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>
diff --git a/src/intrinsic_table.cc b/src/intrinsic_table.cc
index d550eec..044c239 100644
--- a/src/intrinsic_table.cc
+++ b/src/intrinsic_table.cc
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/// Commonly used Matcher / Builders
struct {
+ VoidBuilder void_;
BoolBuilder bool_;
F32Builder f32;
I32Builder i32;
@@ -450,34 +646,32 @@
/// @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 @@
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 @@
/// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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::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);
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index 0353b66..3b4b7f5 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -460,206 +460,12 @@
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.