From d086c147d031106abecfc354a61893da6bc99161 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Tue, 16 Feb 2021 15:10:23 +0000 Subject: [PATCH] Add support fo extracting information about Storage Textures BUG=tint:489 Change-Id: I28e4b0e568aea463971e9d2f5a04f04e942e2564 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41600 Auto-Submit: Ryan Harrison Commit-Queue: dan sinclair Reviewed-by: Ben Clayton Reviewed-by: dan sinclair --- src/inspector/inspector.cc | 51 +++++++- src/inspector/inspector.h | 28 +++- src/inspector/inspector_test.cc | 206 ++++++++++++++++++++++++++++++ src/semantic/function.h | 8 +- src/semantic/sem_function.cc | 32 ++++- src/writer/hlsl/generator_impl.cc | 2 +- src/writer/msl/generator_impl.cc | 6 +- 7 files changed, 322 insertions(+), 11 deletions(-) diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc index e41d2b3b12..95f856554f 100644 --- a/src/inspector/inspector.cc +++ b/src/inspector/inspector.cc @@ -332,6 +332,18 @@ std::vector Inspector::GetMultisampledTextureResourceBindings( return GetSampledTextureResourceBindingsImpl(entry_point, true); } +std::vector +Inspector::GetReadOnlyStorageTextureResourceBindings( + const std::string& entry_point) { + return GetStorageTextureResourceBindingsImpl(entry_point, true); +} + +std::vector +Inspector::GetWriteOnlyStorageTextureResourceBindings( + const std::string& entry_point) { + return GetStorageTextureResourceBindingsImpl(entry_point, false); +} + ast::Function* Inspector::FindEntryPointByName(const std::string& name) { auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name)); if (!func) { @@ -357,7 +369,7 @@ std::vector Inspector::GetStorageBufferResourceBindingsImpl( auto* func_sem = program_->Sem().Get(func); std::vector result; - for (auto& rsv : func_sem->ReferencedStoragebufferVariables()) { + for (auto& rsv : func_sem->ReferencedStorageBufferVariables()) { auto* var = rsv.first; auto* decl = var->Declaration(); auto binding_info = rsv.second; @@ -477,5 +489,42 @@ std::vector Inspector::GetSampledTextureResourceBindingsImpl( return result; } +std::vector Inspector::GetStorageTextureResourceBindingsImpl( + const std::string& entry_point, + bool read_only) { + auto* func = FindEntryPointByName(entry_point); + if (!func) { + return {}; + } + + auto* func_sem = program_->Sem().Get(func); + std::vector result; + for (auto& ref : func_sem->ReferencedStorageTextureVariables()) { + auto* var = ref.first; + auto* decl = var->Declaration(); + auto binding_info = ref.second; + + auto* ac_type = decl->type()->As(); + if (ac_type == nullptr) { + continue; + } + + if (read_only != ac_type->IsReadOnly()) { + continue; + } + + ResourceBinding entry; + entry.resource_type = + read_only ? ResourceBinding::ResourceType::kReadOnlyStorageTexture + : ResourceBinding::ResourceType::kWriteOnlyStorageTexture; + entry.bind_group = binding_info.group->value(); + entry.binding = binding_info.binding->value(); + + result.push_back(entry); + } + + return result; +} + } // namespace inspector } // namespace tint diff --git a/src/inspector/inspector.h b/src/inspector/inspector.h index 8e09e3ffe6..38e59a1434 100644 --- a/src/inspector/inspector.h +++ b/src/inspector/inspector.h @@ -63,7 +63,9 @@ struct ResourceBinding { kSampler, kComparisonSampler, kSampledTexture, - kMulitsampledTexture + kMulitsampledTexture, + kReadOnlyStorageTexture, + kWriteOnlyStorageTexture, }; /// Type of resource that is bound. @@ -146,6 +148,16 @@ class Inspector { std::vector GetMultisampledTextureResourceBindings( const std::string& entry_point); + /// @param entry_point name of the entry point to get information about. + /// @returns vector of all of the bindings for read-only storage textures. + std::vector GetReadOnlyStorageTextureResourceBindings( + const std::string& entry_point); + + /// @param entry_point name of the entry point to get information about. + /// @returns vector of all of the bindings for write-only storage textures. + std::vector GetWriteOnlyStorageTextureResourceBindings( + const std::string& entry_point); + private: const Program* program_; std::string error_; @@ -156,9 +168,9 @@ class Inspector { ast::Function* FindEntryPointByName(const std::string& name); /// @param entry_point name of the entry point to get information about. - /// @param read_only get only read only if true, otherwise get everything - /// else. - /// @returns vector of all of the bindings for the request storage buffers. + /// @param read_only if true get only read-only bindings, if false get + /// write-only bindings. + /// @returns vector of all of the bindings for the requested storage buffers. std::vector GetStorageBufferResourceBindingsImpl( const std::string& entry_point, bool read_only); @@ -170,6 +182,14 @@ class Inspector { std::vector GetSampledTextureResourceBindingsImpl( const std::string& entry_point, bool multisampled_only); + + /// @param entry_point name of the entry point to get information about. + /// @param read_only if true get only read-only bindings, otherwise get + /// write-only bindings. + /// @returns vector of all of the bindings for the requested storage textures. + std::vector GetStorageTextureResourceBindingsImpl( + const std::string& entry_point, + bool read_only); }; } // namespace inspector diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc index 982e12e30b..f52e688eaf 100644 --- a/src/inspector/inspector_test.cc +++ b/src/inspector/inspector_test.cc @@ -601,6 +601,85 @@ class InspectorHelper : public ProgramBuilder { return nullptr; } + /// Generates appropriate types for a StorageTexture + /// @param dim the texture dimension of the storage texture + /// @param format the image format of the storage texture + /// @returns the storage texture type and subtype + std::tuple MakeStorageTextureTypes( + type::TextureDimension dim, + type::ImageFormat format) { + type::Type* subtype = type::StorageTexture::SubtypeFor(format, Types()); + return {create(dim, format, subtype), subtype}; + } + + /// Generates appropriate types for a Read-Only StorageTexture + /// @param dim the texture dimension of the storage texture + /// @param format the image format of the storage texture + /// @param read_only should the access type be read only, otherwise write only + /// @returns the storage texture type, subtype & access control type + std::tuple + MakeStorageTextureTypes(type::TextureDimension dim, + type::ImageFormat format, + bool read_only) { + type::StorageTexture* texture_type; + type::Type* subtype; + std::tie(texture_type, subtype) = MakeStorageTextureTypes(dim, format); + auto* access_control = + create(read_only ? ast::AccessControl::kReadOnly + : ast::AccessControl::kWriteOnly, + texture_type); + return {texture_type, subtype, access_control}; + } + + /// Generates appropriate types for a Write-Only StorageTexture + /// @param dim the texture dimension of the storage texture + /// @param format the image format of the storage texture + /// @returns the storage texture type, subtype & access control type + std::tuple + MakeWriteOnlyStorageTextureTypes(type::TextureDimension dim, + type::ImageFormat format) { + type::StorageTexture* texture_type; + type::Type* subtype; + std::tie(texture_type, subtype) = MakeStorageTextureTypes(dim, format); + auto* access_control = create( + ast::AccessControl::kWriteOnly, texture_type); + return {texture_type, subtype, access_control}; + } + + /// Adds a storage texture variable to the program + /// @param name the name of the variable + /// @param type the type to use + /// @param group the binding/group to use for the sampled texture + /// @param binding the binding number to use for the sampled texture + void AddStorageTexture(const std::string& name, + type::Type* type, + uint32_t group, + uint32_t binding) { + AddBinding(name, type, ast::StorageClass::kUniformConstant, group, binding); + } + + /// Generates a function that references a storage texture variable. + /// @param func_name name of the function created + /// @param st_name name of the storage texture to use + /// @param dim_type type expected by textureDimensons to return + /// @param decorations the function decorations + /// @returns a function that references all of the values specified + ast::Function* MakeStorageTextureBodyFunction( + const std::string& func_name, + const std::string& st_name, + type::Type* dim_type, + ast::FunctionDecorationList decorations) { + ast::StatementList stmts; + + stmts.emplace_back(create( + Var("dim", ast::StorageClass::kFunction, dim_type))); + stmts.emplace_back(create( + Expr("dim"), Call("textureDimensions", st_name))); + stmts.emplace_back(create()); + + return Func(func_name, ast::VariableList(), ty.void_(), stmts, decorations); + } + Inspector& Build() { if (inspector_) { return *inspector_; @@ -694,6 +773,13 @@ class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam class InspectorGetMultisampledTextureResourceBindingsTestWithParam : public InspectorHelper, public testing::TestWithParam {}; +class InspectorGetStorageTextureResourceBindingsTest : public InspectorHelper, + public testing::Test {}; +typedef std::tuple + GetStorageTextureTestParams; +class InspectorGetStorageTextureResourceBindingsTestWithParam + : public InspectorHelper, + public testing::TestWithParam {}; TEST_F(InspectorGetEntryPointTest, NoFunctions) { Inspector& inspector = Build(); @@ -2417,6 +2503,126 @@ INSTANTIATE_TEST_SUITE_P( inspector::ResourceBinding::TextureDimension::k2dArray, inspector::ResourceBinding::SampledKind::kUInt})); +TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) { + MakeEmptyBodyFunction( + "ep", ast::FunctionDecorationList{ + create(ast::PipelineStage::kVertex), + }); + + Inspector& inspector = Build(); + + auto result = inspector.GetReadOnlyStorageTextureResourceBindings("ep"); + ASSERT_FALSE(inspector.has_error()) << inspector.error(); + EXPECT_EQ(0u, result.size()); + + result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep"); + ASSERT_FALSE(inspector.has_error()) << inspector.error(); + EXPECT_EQ(0u, result.size()); +} + +TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) { + bool read_only; + type::TextureDimension dim; + type::ImageFormat format; + std::tie(read_only, dim, format) = GetParam(); + + type::StorageTexture* st_type; + type::Type* st_subtype; + type::AccessControl* ac; + std::tie(st_type, st_subtype, ac) = + MakeStorageTextureTypes(dim, format, read_only); + AddStorageTexture("st_var", ac, 0, 0); + + type::Type* dim_type = nullptr; + switch (dim) { + case type::TextureDimension::k1d: + case type::TextureDimension::k1dArray: + dim_type = ty.i32(); + break; + case type::TextureDimension::k2d: + case type::TextureDimension::k2dArray: + dim_type = ty.vec2(); + break; + case type::TextureDimension::k3d: + dim_type = ty.vec3(); + break; + default: + break; + } + + ASSERT_FALSE(dim_type == nullptr); + + MakeStorageTextureBodyFunction( + "ep", "st_var", dim_type, + ast::FunctionDecorationList{ + create(ast::PipelineStage::kVertex)}); + + Inspector& inspector = Build(); + + auto result = + read_only ? inspector.GetReadOnlyStorageTextureResourceBindings("ep") + : inspector.GetWriteOnlyStorageTextureResourceBindings("ep"); + ASSERT_FALSE(inspector.has_error()) << inspector.error(); + ASSERT_EQ(1u, result.size()); + + EXPECT_EQ(read_only ? ResourceBinding::ResourceType::kReadOnlyStorageTexture + : ResourceBinding::ResourceType::kWriteOnlyStorageTexture, + result[0].resource_type); + EXPECT_EQ(0u, result[0].bind_group); + EXPECT_EQ(0u, result[0].binding); + + result = read_only + ? inspector.GetWriteOnlyStorageTextureResourceBindings("ep") + : inspector.GetReadOnlyStorageTextureResourceBindings("ep"); + ASSERT_FALSE(inspector.has_error()) << inspector.error(); + ASSERT_EQ(0u, result.size()); +} + +INSTANTIATE_TEST_SUITE_P( + InspectorGetStorageTextureResourceBindingsTest, + InspectorGetStorageTextureResourceBindingsTestWithParam, + testing::Combine(testing::Bool(), + testing::Values(type::TextureDimension::k1d, + type::TextureDimension::k1dArray, + type::TextureDimension::k2d, + type::TextureDimension::k2dArray, + type::TextureDimension::k3d), + testing::Values(type::ImageFormat::kR8Uint, + type::ImageFormat::kR16Uint, + type::ImageFormat::kRg8Uint, + type::ImageFormat::kR32Uint, + type::ImageFormat::kRg16Uint, + type::ImageFormat::kRgba8Uint, + type::ImageFormat::kRg32Uint, + type::ImageFormat::kRgba16Uint, + type::ImageFormat::kRgba32Uint, + type::ImageFormat::kR8Sint, + type::ImageFormat::kR16Sint, + type::ImageFormat::kRg8Sint, + type::ImageFormat::kR32Sint, + type::ImageFormat::kRg16Sint, + type::ImageFormat::kRgba8Sint, + type::ImageFormat::kRg32Sint, + type::ImageFormat::kRgba16Sint, + type::ImageFormat::kRgba32Sint, + type::ImageFormat::kR8Unorm, + type::ImageFormat::kRg8Unorm, + type::ImageFormat::kRgba8Unorm, + type::ImageFormat::kRgba8UnormSrgb, + type::ImageFormat::kBgra8Unorm, + type::ImageFormat::kBgra8UnormSrgb, + type::ImageFormat::kRgb10A2Unorm, + type::ImageFormat::kR8Snorm, + type::ImageFormat::kRg8Snorm, + type::ImageFormat::kRgba8Snorm, + type::ImageFormat::kR16Float, + type::ImageFormat::kR32Float, + type::ImageFormat::kRg16Float, + type::ImageFormat::kRg11B10Float, + type::ImageFormat::kRg32Float, + type::ImageFormat::kRgba16Float, + type::ImageFormat::kRgba32Float))); + } // namespace } // namespace inspector } // namespace tint diff --git a/src/semantic/function.h b/src/semantic/function.h index 652e14d162..9dc200f762 100644 --- a/src/semantic/function.h +++ b/src/semantic/function.h @@ -95,7 +95,7 @@ class Function : public Castable { /// must be decorated with both binding and group decorations. /// @returns the referenced storagebuffers const std::vector> - ReferencedStoragebufferVariables() const; + ReferencedStorageBufferVariables() const; /// Retrieves any referenced regular Sampler variables. Note, the /// variables must be decorated with both binding and group decorations. @@ -121,6 +121,12 @@ class Function : public Castable { const std::vector> ReferencedMultisampledTextureVariables() const; + /// Retrieves any referenced storage texture variables. Note, the variables + /// must be decorated with both binding and group decorations. + /// @returns the referenced storage textures + const std::vector> + ReferencedStorageTextureVariables() const; + /// Retrieves any locally referenced builtin variables /// @returns the pairs. const std::vector> diff --git a/src/semantic/sem_function.cc b/src/semantic/sem_function.cc index 2ebf820dc0..98620751d1 100644 --- a/src/semantic/sem_function.cc +++ b/src/semantic/sem_function.cc @@ -24,6 +24,7 @@ #include "src/semantic/variable.h" #include "src/type/multisampled_texture_type.h" #include "src/type/sampled_texture_type.h" +#include "src/type/storage_texture_type.h" #include "src/type/texture_type.h" TINT_INSTANTIATE_CLASS_ID(tint::semantic::Function); @@ -98,7 +99,7 @@ Function::ReferencedUniformVariables() const { } const std::vector> -Function::ReferencedStoragebufferVariables() const { +Function::ReferencedStorageBufferVariables() const { std::vector> ret; for (auto* var : ReferencedModuleVariables()) { @@ -159,6 +160,35 @@ Function::ReferencedMultisampledTextureVariables() const { return ReferencedSampledTextureVariablesImpl(true); } +const std::vector> +Function::ReferencedStorageTextureVariables() const { + std::vector> ret; + + for (auto* var : ReferencedModuleVariables()) { + auto* unwrapped_type = var->Declaration()->type()->UnwrapIfNeeded(); + auto* storage_texture = unwrapped_type->As(); + if (storage_texture == nullptr) { + continue; + } + + ast::BindingDecoration* binding = nullptr; + ast::GroupDecoration* group = nullptr; + for (auto* deco : var->Declaration()->decorations()) { + if (auto* b = deco->As()) { + binding = b; + } else if (auto* s = deco->As()) { + group = s; + } + } + if (binding == nullptr || group == nullptr) { + continue; + } + + ret.push_back({var, BindingInfo{binding, group}}); + } + return ret; +} + const std::vector> Function::LocalReferencedBuiltinVariables() const { std::vector> ret; diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc index b170fbd300..f1d34e01ce 100644 --- a/src/writer/hlsl/generator_impl.cc +++ b/src/writer/hlsl/generator_impl.cc @@ -1626,7 +1626,7 @@ bool GeneratorImpl::EmitEntryPointData( } bool emitted_storagebuffer = false; - for (auto data : func_sem->ReferencedStoragebufferVariables()) { + for (auto data : func_sem->ReferencedStorageBufferVariables()) { auto* var = data.first; auto* decl = var->Declaration(); auto* binding = data.second.binding; diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc index 5421a649c8..7fb68032b1 100644 --- a/src/writer/msl/generator_impl.cc +++ b/src/writer/msl/generator_impl.cc @@ -546,7 +546,7 @@ bool GeneratorImpl::EmitCall(ast::CallExpression* expr) { out_ << program_->Symbols().NameFor(var->Declaration()->symbol()); } - for (const auto& data : func_sem->ReferencedStoragebufferVariables()) { + for (const auto& data : func_sem->ReferencedStorageBufferVariables()) { auto* var = data.first; if (!first) { out_ << ", "; @@ -1384,7 +1384,7 @@ bool GeneratorImpl::EmitFunctionInternal(ast::Function* func, out_ << "& " << program_->Symbols().NameFor(var->Declaration()->symbol()); } - for (const auto& data : func_sem->ReferencedStoragebufferVariables()) { + for (const auto& data : func_sem->ReferencedStorageBufferVariables()) { auto* var = data.first; if (!first) { out_ << ", "; @@ -1551,7 +1551,7 @@ bool GeneratorImpl::EmitEntryPointFunction(ast::Function* func) { << " [[buffer(" << binding->value() << ")]]"; } - for (auto data : func_sem->ReferencedStoragebufferVariables()) { + for (auto data : func_sem->ReferencedStorageBufferVariables()) { if (!first) { out_ << ", "; }