From 06d8db2bcb80589c2939041da73bd2ea896e9199 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 8 Feb 2021 22:59:44 +0000 Subject: [PATCH] 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 Reviewed-by: dan sinclair --- src/intrinsic_table.cc | 494 +++++++++++++++++++++++++++++++++++++++-- src/type_determiner.cc | 194 ---------------- 2 files changed, 478 insertions(+), 210 deletions(-) diff --git a/src/intrinsic_table.cc b/src/intrinsic_table.cc index d550eec69d..044c2391ef 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 @@ 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::Type* Build(BuildState& state) const override { + return state.ty_mgr.Get(); + } + 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()) { + 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(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()) { + 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(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()) { + return tex->dim() == dimensions_; + } + return false; + } + + type::Type* Build(BuildState& state) const override { + return state.ty_mgr.Get(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()) { + if (MatchOpenNumber(state, texel_format_, + static_cast(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(state.open_numbers.at(texel_format_)); + auto* channel_format = state.open_types.at(channel_format_); + return state.ty_mgr.Get(dimensions_, texel_format, + channel_format); + } + + std::string str() const override { + std::stringstream ss; + ss << "texture_storage_" << dimensions_ << ""; + 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()) { + return sampler->kind() == kind_; + } + return false; + } + + type::Type* Build(BuildState& state) const override { + return state.ty_mgr.Get(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& 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 parameters; + std::vector parameters; std::unordered_map 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(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(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(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(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(columns, rows, element_builder); } @@ -489,12 +683,46 @@ class Impl : public IntrinsicTable { return mat(OpenNumber::N, OpenNumber::N, std::forward(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(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(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(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( + dimensions, texel_format, channel_format); + } + + /// @returns a Matcher / Builder that matches a sampler type + Builder* sampler(type::SamplerKind kind) { + return matcher_allocator_.Create(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 parameters) { + std::vector 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 parameters, + std::vector parameters, std::pair 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 auto* vec3_f32 = vec(3, f32); // vec3 auto* vec4_f32 = vec(4, f32); // vec4 + auto* vec4_T = vec(4, T); // vec4 + auto* vec2_i32 = vec(2, i32); // vec2 + auto* vec3_i32 = vec(3, i32); // vec3 auto* vecN_f32 = vecN(f32); // vecN auto* vecN_T = vecN(T); // vecN auto* vecN_bool = vecN(bool_); // vecN @@ -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()) { + std::stringstream ss; + ss << "texture_" << tex->dim() << "<" << TypeName(tex->type()) << ">"; + return ss.str(); + } + if (auto* tex = ty->As()) { + std::stringstream ss; + ss << "texture_multisampled_" << tex->dim() << "<" << TypeName(tex->type()) + << ">"; + return ss.str(); + } + if (auto* tex = ty->As()) { + std::stringstream ss; + ss << "texture_depth_" << tex->dim(); + return ss.str(); + } + if (auto* tex = ty->As()) { + std::stringstream ss; + ss << "texture_storage_" << tex->dim() << "<" << tex->image_format() << ">"; + return ss.str(); + } + if (auto* sampler = ty->As()) { + 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(intrinsic, ret, params); diff --git a/src/type_determiner.cc b/src/type_determiner.cc index 0353b669c4..3b4b7f5f00 100644 --- a/src/type_determiner.cc +++ b/src/type_determiner.cc @@ -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 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(); - 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(); - 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(); - 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(i32, 2); - break; - case type::TextureDimension::k3d: - case type::TextureDimension::kCube: - case type::TextureDimension::kCubeArray: - return_type = builder_->create(i32, 3); - break; - } - break; - } - case IntrinsicType::kTextureNumLayers: - case IntrinsicType::kTextureNumLevels: - case IntrinsicType::kTextureNumSamples: - return_type = builder_->create(); - break; - case IntrinsicType::kTextureStore: - return_type = builder_->create(); - break; - default: { - if (texture->Is()) { - return_type = builder_->create(); - } else { - type::Type* type = nullptr; - if (auto* storage = texture->As()) { - type = storage->type(); - } else if (auto* sampled = texture->As()) { - type = sampled->type(); - } else if (auto* msampled = - texture->As()) { - type = msampled->type(); - } else { - set_error(call->source(), - "unknown texture type for texture sampling"); - return false; - } - return_type = builder_->create(type, 4); - } - } - } - - auto* intrinsic = builder_->create( - intrinsic_type, return_type, params); - builder_->Sem().Add(call, builder_->create(intrinsic)); - return true; - } - auto result = intrinsic_table_->Lookup(*builder_, intrinsic_type, arg_tys); if (!result.intrinsic) { // Intrinsic lookup failed.