Add texture intrinsics to the IntrinsicTable

Automatically implements verification of texture intrinsic overloads.

Bug: tint:449
Change-Id: I74858902ddcc02337641dd422b800378215b0c7a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40507
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2021-02-08 22:59:44 +00:00 committed by Commit Bot service account
parent 59d24735d0
commit 06d8db2bcb
2 changed files with 478 additions and 210 deletions

View File

@ -23,7 +23,11 @@
#include "src/block_allocator.h"
#include "src/program_builder.h"
#include "src/semantic/intrinsic.h"
#include "src/type/depth_texture_type.h"
#include "src/type/f32_type.h"
#include "src/type/multisampled_texture_type.h"
#include "src/type/sampled_texture_type.h"
#include "src/type/storage_texture_type.h"
namespace tint {
namespace {
@ -164,6 +168,18 @@ class OpenTypeBuilder : public Builder {
OpenType open_type_;
};
/// VoidBuilder is a Matcher / Builder for void types.
class VoidBuilder : public Builder {
public:
bool Match(MatchState&, type::Type* ty) const override {
return ty->Is<type::Void>();
}
type::Type* Build(BuildState& state) const override {
return state.ty_mgr.Get<type::Void>();
}
std::string str() const override { return "void"; }
};
/// BoolBuilder is a Matcher / Builder for boolean types.
class BoolBuilder : public Builder {
public:
@ -298,7 +314,7 @@ class VecBuilder : public Builder {
protected:
const uint32_t size_;
Builder* element_builder_;
Builder* const element_builder_;
};
/// OpenSizeVecBuilder is a Matcher / Builder for matrix types of an open number
@ -399,6 +415,173 @@ class ArrayBuilder : public Builder {
Builder* const element_builder_;
};
/// SampledTextureBuilder is a Matcher / Builder for sampled texture types.
class SampledTextureBuilder : public Builder {
public:
explicit SampledTextureBuilder(type::TextureDimension dimensions,
Builder* type_builder)
: dimensions_(dimensions), type_builder_(type_builder) {}
bool Match(MatchState& state, type::Type* ty) const override {
if (auto* tex = ty->As<type::SampledTexture>()) {
if (tex->dim() == dimensions_) {
return type_builder_->Match(state, tex->type());
}
}
return false;
}
type::Type* Build(BuildState& state) const override {
auto* type = type_builder_->Build(state);
return state.ty_mgr.Get<type::SampledTexture>(dimensions_, type);
}
std::string str() const override {
std::stringstream ss;
ss << "texture_" << dimensions_ << "<" << type_builder_->str() << ">";
return ss.str();
}
private:
type::TextureDimension const dimensions_;
Builder* const type_builder_;
};
/// MultisampledTextureBuilder is a Matcher / Builder for multisampled texture
/// types.
class MultisampledTextureBuilder : public Builder {
public:
explicit MultisampledTextureBuilder(type::TextureDimension dimensions,
Builder* type_builder)
: dimensions_(dimensions), type_builder_(type_builder) {}
bool Match(MatchState& state, type::Type* ty) const override {
if (auto* tex = ty->As<type::MultisampledTexture>()) {
if (tex->dim() == dimensions_) {
return type_builder_->Match(state, tex->type());
}
}
return false;
}
type::Type* Build(BuildState& state) const override {
auto* type = type_builder_->Build(state);
return state.ty_mgr.Get<type::MultisampledTexture>(dimensions_, type);
}
std::string str() const override {
std::stringstream ss;
ss << "texture_multisampled_" << dimensions_ << "<" << type_builder_->str()
<< ">";
return ss.str();
}
private:
type::TextureDimension const dimensions_;
Builder* const type_builder_;
};
/// DepthTextureBuilder is a Matcher / Builder for depth texture types.
class DepthTextureBuilder : public Builder {
public:
explicit DepthTextureBuilder(type::TextureDimension dimensions)
: dimensions_(dimensions) {}
bool Match(MatchState&, type::Type* ty) const override {
if (auto* tex = ty->As<type::DepthTexture>()) {
return tex->dim() == dimensions_;
}
return false;
}
type::Type* Build(BuildState& state) const override {
return state.ty_mgr.Get<type::DepthTexture>(dimensions_);
}
std::string str() const override {
std::stringstream ss;
ss << "texture_depth_" << dimensions_;
return ss.str();
}
private:
type::TextureDimension const dimensions_;
};
/// StorageTextureBuilder is a Matcher / Builder for storage texture types of
/// the given texel and channel formats.
class StorageTextureBuilder : public Builder {
public:
explicit StorageTextureBuilder(
type::TextureDimension dimensions,
OpenNumber texel_format, // a.k.a "image format"
OpenType channel_format) // a.k.a "storage subtype"
: dimensions_(dimensions),
texel_format_(texel_format),
channel_format_(channel_format) {}
bool Match(MatchState& state, type::Type* ty) const override {
if (auto* tex = ty->As<type::StorageTexture>()) {
if (MatchOpenNumber(state, texel_format_,
static_cast<uint32_t>(tex->image_format()))) {
if (MatchOpenType(state, channel_format_, tex->type())) {
return tex->dim() == dimensions_;
}
}
}
return false;
}
type::Type* Build(BuildState& state) const override {
auto texel_format =
static_cast<type::ImageFormat>(state.open_numbers.at(texel_format_));
auto* channel_format = state.open_types.at(channel_format_);
return state.ty_mgr.Get<type::StorageTexture>(dimensions_, texel_format,
channel_format);
}
std::string str() const override {
std::stringstream ss;
ss << "texture_storage_" << dimensions_ << "<F>";
return ss.str();
}
private:
type::TextureDimension const dimensions_;
OpenNumber const texel_format_;
OpenType const channel_format_;
};
/// SamplerBuilder is a Matcher / Builder for sampler types of the given kind.
class SamplerBuilder : public Builder {
public:
explicit SamplerBuilder(type::SamplerKind kind) : kind_(kind) {}
bool Match(MatchState&, type::Type* ty) const override {
if (auto* sampler = ty->As<type::Sampler>()) {
return sampler->kind() == kind_;
}
return false;
}
type::Type* Build(BuildState& state) const override {
return state.ty_mgr.Get<type::Sampler>(kind_);
}
std::string str() const override {
switch (kind_) {
case type::SamplerKind::kSampler:
return "sampler";
case type::SamplerKind::kComparisonSampler:
return "sampler_comparison";
}
return "sampler";
}
private:
type::SamplerKind const kind_;
};
/// Impl is the private implementation of the IntrinsicTable interface.
class Impl : public IntrinsicTable {
public:
@ -409,6 +592,18 @@ class Impl : public IntrinsicTable {
semantic::IntrinsicType type,
const std::vector<type::Type*>& args) const override;
/// Holds the information about a single overload parameter used for matching
struct Parameter {
Parameter(
Builder* m) // NOLINT - implicit constructor required for Register()
: matcher(m) {}
Parameter(semantic::Parameter::Usage u, Builder* m)
: matcher(m), usage(u) {}
Builder* const matcher;
semantic::Parameter::Usage const usage = semantic::Parameter::Usage::kNone;
};
/// A single overload definition.
struct Overload {
/// @returns a human readable string representation of the overload
@ -425,7 +620,7 @@ class Impl : public IntrinsicTable {
semantic::IntrinsicType type;
Builder* return_type;
std::vector<Builder*> parameters;
std::vector<Parameter> parameters;
std::unordered_map<OpenType, Matcher*> open_type_matchers;
};
@ -435,6 +630,7 @@ class Impl : public IntrinsicTable {
/// Commonly used Matcher / Builders
struct {
VoidBuilder void_;
BoolBuilder bool_;
F32Builder f32;
I32Builder i32;
@ -450,34 +646,32 @@ class Impl : public IntrinsicTable {
/// @returns a Matcher / Builder that matches a pointer with the given element
/// type
PtrBuilder* ptr(Builder* element_builder) {
Builder* ptr(Builder* element_builder) {
return matcher_allocator_.Create<PtrBuilder>(element_builder);
}
/// @returns a Matcher / Builder that matches a vector of size OpenNumber::N
/// with the given element type
OpenSizeVecBuilder* vecN(Builder* element_builder) {
Builder* vecN(Builder* element_builder) {
return matcher_allocator_.Create<OpenSizeVecBuilder>(OpenNumber::N,
element_builder);
}
/// @returns a Matcher / Builder that matches a vector of the given size and
/// element type
VecBuilder* vec(uint32_t size, Builder* element_builder) {
Builder* vec(uint32_t size, Builder* element_builder) {
return matcher_allocator_.Create<VecBuilder>(size, element_builder);
}
/// @returns a Matcher / Builder that matches a runtime sized array with the
/// given element type
ArrayBuilder* array(Builder* element_builder) {
Builder* array(Builder* element_builder) {
return matcher_allocator_.Create<ArrayBuilder>(element_builder);
}
/// @returns a Matcher / Builder that matches a matrix with the given size and
/// element type
OpenSizeMatBuilder* mat(OpenNumber columns,
OpenNumber rows,
Builder* element_builder) {
Builder* mat(OpenNumber columns, OpenNumber rows, Builder* element_builder) {
return matcher_allocator_.Create<OpenSizeMatBuilder>(columns, rows,
element_builder);
}
@ -489,12 +683,46 @@ class Impl : public IntrinsicTable {
return mat(OpenNumber::N, OpenNumber::N, std::forward<T>(in));
}
/// @returns a Matcher / Builder that matches a sampled texture with the given
/// dimensions and type
Builder* sampled_texture(type::TextureDimension dimensions, Builder* type) {
return matcher_allocator_.Create<SampledTextureBuilder>(dimensions, type);
}
/// @returns a Matcher / Builder that matches a multisampled texture with the
/// given dimensions and type
Builder* multisampled_texture(type::TextureDimension dimensions,
Builder* type) {
return matcher_allocator_.Create<MultisampledTextureBuilder>(dimensions,
type);
}
/// @returns a Matcher / Builder that matches a depth texture with the
/// given dimensions
Builder* depth_texture(type::TextureDimension dimensions) {
return matcher_allocator_.Create<DepthTextureBuilder>(dimensions);
}
/// @returns a Matcher / Builder that matches a storage texture of the given
/// format with the given dimensions
Builder* storage_texture(type::TextureDimension dimensions,
OpenNumber texel_format,
OpenType channel_format) {
return matcher_allocator_.Create<StorageTextureBuilder>(
dimensions, texel_format, channel_format);
}
/// @returns a Matcher / Builder that matches a sampler type
Builder* sampler(type::SamplerKind kind) {
return matcher_allocator_.Create<SamplerBuilder>(kind);
}
/// Registers an overload with the given intrinsic type, return type Matcher /
/// Builder, and parameter Matcher / Builders.
/// This overload of Register does not constrain any OpenTypes.
void Register(semantic::IntrinsicType type,
Builder* return_type,
std::vector<Builder*> parameters) {
std::vector<Parameter> parameters) {
Overload overload{type, return_type, std::move(parameters), {}};
overloads_.emplace_back(overload);
}
@ -505,7 +733,7 @@ class Impl : public IntrinsicTable {
/// open_type_matcher.
void Register(semantic::IntrinsicType type,
Builder* return_type,
std::vector<Builder*> parameters,
std::vector<Parameter> parameters,
std::pair<OpenType, Matcher*> open_type_matcher) {
Overload overload{
type, return_type, std::move(parameters), {open_type_matcher}};
@ -515,9 +743,12 @@ class Impl : public IntrinsicTable {
Impl::Impl() {
using I = semantic::IntrinsicType;
using Dim = type::TextureDimension;
auto* void_ = &matchers_.void_; // void
auto* bool_ = &matchers_.bool_; // bool
auto* f32 = &matchers_.f32; // f32
auto* i32 = &matchers_.i32; // i32
auto* u32 = &matchers_.u32; // u32
auto* iu32 = &matchers_.iu32; // i32 or u32
auto* fiu32 = &matchers_.fiu32; // f32, i32 or u32
@ -527,6 +758,9 @@ Impl::Impl() {
auto* vec2_f32 = vec(2, f32); // vec2<f32>
auto* vec3_f32 = vec(3, f32); // vec3<f32>
auto* vec4_f32 = vec(4, f32); // vec4<f32>
auto* vec4_T = vec(4, T); // vec4<T>
auto* vec2_i32 = vec(2, i32); // vec2<i32>
auto* vec3_i32 = vec(3, i32); // vec3<i32>
auto* vecN_f32 = vecN(f32); // vecN<f32>
auto* vecN_T = vecN(T); // vecN<T>
auto* vecN_bool = vecN(bool_); // vecN<bool>
@ -773,6 +1007,200 @@ Impl::Impl() {
Register(I::kTanh, vecN_f32, {vecN_f32} ); // NOLINT
Register(I::kTrunc, f32, {f32} ); // NOLINT
Register(I::kTrunc, vecN_f32, {vecN_f32} ); // NOLINT
// clang-format on
auto* tex_1d_f32 = sampled_texture(Dim::k1d, f32);
auto* tex_1d_T = sampled_texture(Dim::k1d, T);
auto* tex_1d_array_f32 = sampled_texture(Dim::k1dArray, f32);
auto* tex_1d_array_T = sampled_texture(Dim::k1dArray, T);
auto* tex_2d_f32 = sampled_texture(Dim::k2d, f32);
auto* tex_2d_T = sampled_texture(Dim::k2d, T);
auto* tex_2d_array_f32 = sampled_texture(Dim::k2dArray, f32);
auto* tex_2d_array_T = sampled_texture(Dim::k2dArray, T);
auto* tex_3d_f32 = sampled_texture(Dim::k3d, f32);
auto* tex_3d_T = sampled_texture(Dim::k3d, T);
auto* tex_cube_f32 = sampled_texture(Dim::kCube, f32);
auto* tex_cube_T = sampled_texture(Dim::kCube, T);
auto* tex_cube_array_f32 = sampled_texture(Dim::kCubeArray, f32);
auto* tex_cube_array_T = sampled_texture(Dim::kCubeArray, T);
auto* tex_ms_2d_T = multisampled_texture(Dim::k2d, T);
auto* tex_ms_2d_array_T = multisampled_texture(Dim::k2dArray, T);
auto* tex_depth_2d = depth_texture(Dim::k2d);
auto* tex_depth_2d_array = depth_texture(Dim::k2dArray);
auto* tex_depth_cube = depth_texture(Dim::kCube);
auto* tex_depth_cube_array = depth_texture(Dim::kCubeArray);
auto* tex_storage_1d_FT =
storage_texture(Dim::k1d, OpenNumber::F, OpenType::T);
auto* tex_storage_1d_array_FT =
storage_texture(Dim::k1dArray, OpenNumber::F, OpenType::T);
auto* tex_storage_2d_FT =
storage_texture(Dim::k2d, OpenNumber::F, OpenType::T);
auto* tex_storage_2d_array_FT =
storage_texture(Dim::k2dArray, OpenNumber::F, OpenType::T);
auto* tex_storage_3d_FT =
storage_texture(Dim::k3d, OpenNumber::F, OpenType::T);
auto* sampler = this->sampler(type::SamplerKind::kSampler);
auto* sampler_comparison =
this->sampler(type::SamplerKind::kComparisonSampler);
auto t = semantic::Parameter::Usage::kTexture;
auto s = semantic::Parameter::Usage::kSampler;
auto coords = semantic::Parameter::Usage::kCoords;
auto array_index = semantic::Parameter::Usage::kArrayIndex;
auto ddx = semantic::Parameter::Usage::kDdx;
auto ddy = semantic::Parameter::Usage::kDdy;
auto depth_ref = semantic::Parameter::Usage::kDepthRef;
auto bias = semantic::Parameter::Usage::kBias;
auto level = semantic::Parameter::Usage::kLevel;
auto offset = semantic::Parameter::Usage::kOffset;
auto value = semantic::Parameter::Usage::kValue;
auto sample_index = semantic::Parameter::Usage::kSampleIndex;
// clang-format off
// name return type parameter types
Register(I::kTextureDimensions, i32, {{t, tex_1d_T}, }); // NOLINT
Register(I::kTextureDimensions, i32, {{t, tex_1d_array_T}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_2d_T}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_2d_T}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_2d_array_T}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_2d_array_T}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_3d_T}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_3d_T}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_cube_T}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_cube_T}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_cube_array_T}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_cube_array_T}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_ms_2d_T}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_ms_2d_array_T}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_depth_2d}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_depth_2d}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_depth_2d_array}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_depth_2d_array}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_depth_cube}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_depth_cube}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_depth_cube_array}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_depth_cube_array}, {level, i32}, }); // NOLINT
Register(I::kTextureDimensions, i32, {{t, tex_storage_1d_FT}, }); // NOLINT
Register(I::kTextureDimensions, i32, {{t, tex_storage_1d_array_FT}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_storage_2d_FT}, }); // NOLINT
Register(I::kTextureDimensions, vec2_i32, {{t, tex_storage_2d_array_FT}, }); // NOLINT
Register(I::kTextureDimensions, vec3_i32, {{t, tex_storage_3d_FT}, }); // NOLINT
Register(I::kTextureNumLayers, i32, {{t, tex_1d_array_T}, });
Register(I::kTextureNumLayers, i32, {{t, tex_2d_array_T}, });
Register(I::kTextureNumLayers, i32, {{t, tex_cube_array_T}, });
Register(I::kTextureNumLayers, i32, {{t, tex_ms_2d_array_T}, });
Register(I::kTextureNumLayers, i32, {{t, tex_depth_2d_array}, });
Register(I::kTextureNumLayers, i32, {{t, tex_depth_cube_array}, });
Register(I::kTextureNumLayers, i32, {{t, tex_storage_1d_array_FT}, });
Register(I::kTextureNumLayers, i32, {{t, tex_storage_2d_array_FT}, });
Register(I::kTextureNumLevels, i32, {{t, tex_2d_T}, });
Register(I::kTextureNumLevels, i32, {{t, tex_2d_array_T}, });
Register(I::kTextureNumLevels, i32, {{t, tex_3d_T}, });
Register(I::kTextureNumLevels, i32, {{t, tex_cube_T}, });
Register(I::kTextureNumLevels, i32, {{t, tex_cube_array_T}, });
Register(I::kTextureNumLevels, i32, {{t, tex_depth_2d}, });
Register(I::kTextureNumLevels, i32, {{t, tex_depth_2d_array}, });
Register(I::kTextureNumLevels, i32, {{t, tex_depth_cube}, });
Register(I::kTextureNumLevels, i32, {{t, tex_depth_cube_array}, });
Register(I::kTextureNumSamples, i32, {{t, tex_ms_2d_T}, });
Register(I::kTextureNumSamples, i32, {{t, tex_ms_2d_array_T}, });
Register(I::kTextureSample, vec4_f32, {{t, tex_1d_f32}, {s, sampler}, {coords, f32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_1d_array_f32}, {s, sampler}, {coords, f32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {offset, vec3_i32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_cube_f32}, {s, sampler}, {coords, vec3_f32}, }); // NOLINT
Register(I::kTextureSample, vec4_f32, {{t, tex_cube_array_f32}, {s, sampler}, {coords, vec3_f32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_2d}, {s, sampler}, {coords, vec2_f32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_2d}, {s, sampler}, {coords, vec2_f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_2d_array}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_2d_array}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_cube}, {s, sampler}, {coords, vec3_f32}, }); // NOLINT
Register(I::kTextureSample, f32, {{t, tex_depth_cube_array}, {s, sampler}, {coords, vec3_f32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {bias, f32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {bias, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {bias, f32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {bias, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {bias, f32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {bias, f32}, {offset, vec3_i32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_cube_f32}, {s, sampler}, {coords, vec3_f32}, {bias, f32}, }); // NOLINT
Register(I::kTextureSampleBias, vec4_f32, {{t, tex_cube_array_f32}, {s, sampler}, {coords, vec3_f32}, {array_index, i32}, {bias, f32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_2d}, {s, sampler_comparison}, {coords, vec2_f32}, {depth_ref, f32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_2d}, {s, sampler_comparison}, {coords, vec2_f32}, {depth_ref, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_2d_array}, {s, sampler_comparison}, {coords, vec2_f32}, {array_index, i32}, {depth_ref, f32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_2d_array}, {s, sampler_comparison}, {coords, vec2_f32}, {array_index, i32}, {depth_ref, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_cube}, {s, sampler_comparison}, {coords, vec3_f32}, {depth_ref, f32}, }); // NOLINT
Register(I::kTextureSampleCompare, f32, {{t, tex_depth_cube_array}, {s, sampler_comparison}, {coords, vec3_f32}, {array_index, i32}, {depth_ref, f32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {ddx, vec2_f32}, {ddy, vec2_f32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {ddx, vec2_f32}, {ddy, vec2_f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {ddx, vec2_f32}, {ddy, vec2_f32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {ddx, vec2_f32}, {ddy, vec2_f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {ddx, vec3_f32}, {ddy, vec3_f32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {ddx, vec3_f32}, {ddy, vec3_f32}, {offset, vec3_i32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_cube_f32}, {s, sampler}, {coords, vec3_f32}, {ddx, vec3_f32}, {ddy, vec3_f32}, }); // NOLINT
Register(I::kTextureSampleGrad, vec4_f32, {{t, tex_cube_array_f32}, {s, sampler}, {coords, vec3_f32}, {array_index, i32}, {ddx, vec3_f32}, {ddy, vec3_f32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {level, f32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_2d_f32}, {s, sampler}, {coords, vec2_f32}, {level, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {level, f32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_2d_array_f32}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {level, f32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {level, f32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_3d_f32}, {s, sampler}, {coords, vec3_f32}, {level, f32}, {offset, vec3_i32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_cube_f32}, {s, sampler}, {coords, vec3_f32}, {level, f32}, }); // NOLINT
Register(I::kTextureSampleLevel, vec4_f32, {{t, tex_cube_array_f32}, {s, sampler}, {coords, vec3_f32}, {array_index, i32}, {level, f32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_2d}, {s, sampler}, {coords, vec2_f32}, {level, i32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_2d}, {s, sampler}, {coords, vec2_f32}, {level, i32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_2d_array}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {level, i32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_2d_array}, {s, sampler}, {coords, vec2_f32}, {array_index, i32}, {level, i32}, {offset, vec2_i32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube}, {s, sampler}, {coords, vec3_f32}, {level, i32}, }); // NOLINT
Register(I::kTextureSampleLevel, f32, {{t, tex_depth_cube_array},{s, sampler}, {coords, vec3_f32}, {array_index, i32}, {level, i32}, }); // NOLINT
// TODO(bclayton): Check for [[access(write)]]
Register(I::kTextureStore, void_, {{t, tex_storage_1d_FT}, {coords, i32}, {value, vec4_T}, }); // NOLINT
Register(I::kTextureStore, void_, {{t, tex_storage_1d_array_FT},{coords, i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
Register(I::kTextureStore, void_, {{t, tex_storage_2d_FT}, {coords, vec2_i32}, {value, vec4_T}, }); // NOLINT
Register(I::kTextureStore, void_, {{t, tex_storage_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, {value, vec4_T}, }); // NOLINT
Register(I::kTextureStore, void_, {{t, tex_storage_3d_FT}, {coords, vec3_i32}, {value, vec4_T}, }); // NOLINT
// TODO(bclayton): Check for [[access(read)]]
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_T}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_3d_T}, {coords, vec3_i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_ms_2d_T}, {coords, vec2_i32}, {sample_index, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_ms_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, {sample_index, i32}, }); // NOLINT
Register(I::kTextureLoad, f32, {{t, tex_depth_2d}, {coords, vec2_i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, f32, {{t, tex_depth_2d_array}, {coords, vec2_i32}, {array_index, i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_1d_FT}, {coords, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_1d_array_FT},{coords, i32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_2d_FT}, {coords, vec2_i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_2d_array_FT},{coords, vec2_i32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_storage_3d_FT}, {coords, vec3_i32}, }); // NOLINT
// TODO(bclayton): Update the rest of tint to reflect the spec changes made in
// https://github.com/gpuweb/gpuweb/pull/1301:
// Overloads added in https://github.com/gpuweb/gpuweb/pull/1301
Register(I::kTextureLoad, vec4_T, {{t, tex_1d_T}, {coords, i32}, {level, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_1d_array_T}, {coords, i32}, {array_index, i32}, {level, i32}, }); // NOLINT
// Overloads removed in https://github.com/gpuweb/gpuweb/pull/1301
Register(I::kTextureLoad, vec4_T, {{t, tex_1d_T}, {coords, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_1d_array_T}, {coords, i32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_T}, {coords, vec2_i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_2d_array_T}, {coords, vec2_i32}, {array_index, i32}, }); // NOLINT
Register(I::kTextureLoad, vec4_T, {{t, tex_3d_T}, {coords, vec3_i32}, }); // NOLINT
Register(I::kTextureLoad, f32, {{t, tex_depth_2d}, {coords, vec2_i32}, }); // NOLINT
Register(I::kTextureLoad, f32, {{t, tex_depth_2d_array}, {coords, vec2_i32}, {array_index, i32}, }); // NOLINT
// clang-format on
}
@ -782,12 +1210,15 @@ std::string Impl::Overload::str() const {
ss << type << "(";
{
bool first = true;
for (auto* param : parameters) {
for (auto param : parameters) {
if (!first) {
ss << ", ";
}
first = false;
ss << param->str();
if (param.usage != semantic::Parameter::Usage::kNone) {
ss << semantic::str(param.usage) << " : ";
}
ss << param.matcher->str();
}
}
ss << ") -> ";
@ -840,6 +1271,36 @@ std::string TypeName(type::Type* ty) {
return "mat" + std::to_string(mat->columns()) + "x" +
std::to_string(mat->rows()) + "<" + TypeName(mat->type()) + ">";
}
if (auto* tex = ty->As<type::SampledTexture>()) {
std::stringstream ss;
ss << "texture_" << tex->dim() << "<" << TypeName(tex->type()) << ">";
return ss.str();
}
if (auto* tex = ty->As<type::MultisampledTexture>()) {
std::stringstream ss;
ss << "texture_multisampled_" << tex->dim() << "<" << TypeName(tex->type())
<< ">";
return ss.str();
}
if (auto* tex = ty->As<type::DepthTexture>()) {
std::stringstream ss;
ss << "texture_depth_" << tex->dim();
return ss.str();
}
if (auto* tex = ty->As<type::StorageTexture>()) {
std::stringstream ss;
ss << "texture_storage_" << tex->dim() << "<" << tex->image_format() << ">";
return ss.str();
}
if (auto* sampler = ty->As<type::Sampler>()) {
switch (sampler->kind()) {
case type::SamplerKind::kSampler:
return "sampler";
case type::SamplerKind::kComparisonSampler:
return "sampler_comparison";
}
return "sampler";
}
return ty->type_name();
}
@ -925,7 +1386,7 @@ semantic::Intrinsic* Impl::Overload::Match(ProgramBuilder& builder,
for (size_t i = 0; i < count; i++) {
assert(args[i]);
auto* arg_ty = args[i]->UnwrapAll();
if (!parameters[i]->Match(matcher_state, arg_ty)) {
if (!parameters[i].matcher->Match(matcher_state, arg_ty)) {
matched = false;
continue;
}
@ -976,8 +1437,9 @@ semantic::Intrinsic* Impl::Overload::Match(ProgramBuilder& builder,
semantic::Parameters params;
params.reserve(parameters.size());
for (size_t i = 0; i < args.size(); i++) {
auto* ty = parameters[i]->Build(builder_state);
params.emplace_back(semantic::Parameter{ty});
auto& parameter = parameters[i];
auto* ty = parameter.matcher->Build(builder_state);
params.emplace_back(semantic::Parameter{ty, parameter.usage});
}
return builder.create<semantic::Intrinsic>(intrinsic, ret, params);

View File

@ -460,206 +460,12 @@ bool TypeDeterminer::DetermineCall(ast::CallExpression* call) {
bool TypeDeterminer::DetermineIntrinsicCall(
ast::CallExpression* call,
semantic::IntrinsicType intrinsic_type) {
using Parameter = semantic::Parameter;
using Parameters = semantic::Parameters;
using Usage = Parameter::Usage;
std::vector<type::Type*> arg_tys;
arg_tys.reserve(call->params().size());
for (auto* expr : call->params()) {
arg_tys.emplace_back(TypeOf(expr));
}
std::string name = semantic::str(intrinsic_type);
// TODO(bclayton): Add these to the IntrinsicTable
if (semantic::IsTextureIntrinsic(intrinsic_type)) {
Parameters params;
auto& ty = builder_->ty;
auto* texture = arg_tys[0]->UnwrapAll()->As<type::Texture>();
if (!texture) {
set_error(call->source(), "invalid first argument for " + name);
return false;
}
bool is_array = type::IsTextureArray(texture->dim());
bool is_multisampled = texture->Is<type::MultisampledTexture>();
switch (intrinsic_type) {
case IntrinsicType::kTextureDimensions:
params.emplace_back(Parameter{texture, Usage::kTexture});
if (arg_tys.size() > params.size()) {
params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
}
break;
case IntrinsicType::kTextureNumLayers:
case IntrinsicType::kTextureNumLevels:
case IntrinsicType::kTextureNumSamples:
params.emplace_back(Parameter{texture, Usage::kTexture});
break;
case IntrinsicType::kTextureLoad:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
if (arg_tys.size() > params.size()) {
if (is_multisampled) {
params.emplace_back(Parameter{ty.i32(), Usage::kSampleIndex});
} else {
params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
}
}
break;
case IntrinsicType::kTextureSample:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
if (arg_tys.size() > params.size()) {
params.emplace_back(
Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleBias:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
params.emplace_back(Parameter{ty.f32(), Usage::kBias});
if (arg_tys.size() > params.size()) {
params.emplace_back(
Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleLevel:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
params.emplace_back(Parameter{ty.i32(), Usage::kLevel});
if (arg_tys.size() > params.size()) {
params.emplace_back(
Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleCompare:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
params.emplace_back(Parameter{ty.f32(), Usage::kDepthRef});
if (arg_tys.size() > params.size()) {
params.emplace_back(
Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureSampleGrad:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kSampler});
params.emplace_back(Parameter{arg_tys[2], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
params.emplace_back(Parameter{arg_tys[params.size()], Usage::kDdx});
params.emplace_back(Parameter{arg_tys[params.size()], Usage::kDdy});
if (arg_tys.size() > params.size()) {
params.emplace_back(
Parameter{arg_tys[params.size()], Usage::kOffset});
}
break;
case IntrinsicType::kTextureStore:
params.emplace_back(Parameter{texture, Usage::kTexture});
params.emplace_back(Parameter{arg_tys[1], Usage::kCoords});
if (is_array) {
params.emplace_back(Parameter{ty.i32(), Usage::kArrayIndex});
}
params.emplace_back(Parameter{arg_tys[params.size()], Usage::kValue});
break;
default:
set_error(call->source(),
"Internal compiler error: Unreachable intrinsic " + name);
return false;
}
if (arg_tys.size() != params.size()) {
set_error(call->source(), "incorrect number of arguments for " + name +
", got " + std::to_string(arg_tys.size()) +
" and expected " +
std::to_string(params.size()));
return false;
}
// Set the function return type
type::Type* return_type = nullptr;
switch (intrinsic_type) {
case IntrinsicType::kTextureDimensions: {
auto* i32 = builder_->create<type::I32>();
switch (texture->dim()) {
default:
set_error(call->source(), "invalid texture dimensions");
break;
case type::TextureDimension::k1d:
case type::TextureDimension::k1dArray:
return_type = i32;
break;
case type::TextureDimension::k2d:
case type::TextureDimension::k2dArray:
return_type = builder_->create<type::Vector>(i32, 2);
break;
case type::TextureDimension::k3d:
case type::TextureDimension::kCube:
case type::TextureDimension::kCubeArray:
return_type = builder_->create<type::Vector>(i32, 3);
break;
}
break;
}
case IntrinsicType::kTextureNumLayers:
case IntrinsicType::kTextureNumLevels:
case IntrinsicType::kTextureNumSamples:
return_type = builder_->create<type::I32>();
break;
case IntrinsicType::kTextureStore:
return_type = builder_->create<type::Void>();
break;
default: {
if (texture->Is<type::DepthTexture>()) {
return_type = builder_->create<type::F32>();
} else {
type::Type* type = nullptr;
if (auto* storage = texture->As<type::StorageTexture>()) {
type = storage->type();
} else if (auto* sampled = texture->As<type::SampledTexture>()) {
type = sampled->type();
} else if (auto* msampled =
texture->As<type::MultisampledTexture>()) {
type = msampled->type();
} else {
set_error(call->source(),
"unknown texture type for texture sampling");
return false;
}
return_type = builder_->create<type::Vector>(type, 4);
}
}
}
auto* intrinsic = builder_->create<semantic::Intrinsic>(
intrinsic_type, return_type, params);
builder_->Sem().Add(call, builder_->create<semantic::Call>(intrinsic));
return true;
}
auto result = intrinsic_table_->Lookup(*builder_, intrinsic_type, arg_tys);
if (!result.intrinsic) {
// Intrinsic lookup failed.