From 971a6233c2a459eb8f9a5f088c17dfb0cd70ee75 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Tue, 17 Mar 2020 10:28:07 +0000 Subject: [PATCH] Validate the declaration of storage texture format in shader This patch adds the validation on the storage texture format declared in shaders when we create a rendering or compute pipeline with read-only or write-only storage textures. This patch also fixes a typo in the TextureValidationTest. BUG=dawn:267 TEST=dawn_unittests Change-Id: Id302b4b7803d7e03b57c61de1290cc71ba940e2c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/16940 Commit-Queue: Jiawei Shao Reviewed-by: Kai Ninomiya --- BUILD.gn | 2 + dawn.json | 3 +- src/dawn_native/BindGroupLayout.cpp | 33 ++- src/dawn_native/BindGroupLayout.h | 4 + src/dawn_native/PipelineLayout.cpp | 4 + src/dawn_native/ShaderModule.cpp | 93 ++++++++- src/dawn_native/ShaderModule.h | 1 + src/tests/end2end/StorageTextureTests.cpp | 2 + src/tests/end2end/TextureFormatTests.cpp | 17 +- .../StorageTextureValidationTests.cpp | 188 +++++++++++++++++- .../validation/TextureValidationTests.cpp | 37 +--- src/utils/CMakeLists.txt | 2 + src/utils/TextureFormatUtils.cpp | 89 +++++++++ src/utils/TextureFormatUtils.h | 58 ++++++ 14 files changed, 483 insertions(+), 50 deletions(-) create mode 100644 src/utils/TextureFormatUtils.cpp create mode 100644 src/utils/TextureFormatUtils.h diff --git a/BUILD.gn b/BUILD.gn index d653c1cacf..9f0cee477e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -751,6 +751,8 @@ static_library("dawn_utils") { "src/utils/SystemUtils.h", "src/utils/TerribleCommandBuffer.cpp", "src/utils/TerribleCommandBuffer.h", + "src/utils/TextureFormatUtils.cpp", + "src/utils/TextureFormatUtils.h", "src/utils/Timer.h", "src/utils/WGPUHelpers.cpp", "src/utils/WGPUHelpers.h", diff --git a/dawn.json b/dawn.json index bec9c9ea0a..aad0a35d22 100644 --- a/dawn.json +++ b/dawn.json @@ -94,7 +94,8 @@ {"name": "has dynamic offset", "type": "bool", "default": "false"}, {"name": "multisampled", "type": "bool", "default": "false"}, {"name": "texture dimension", "type": "texture view dimension", "default": "undefined"}, - {"name": "texture component type", "type": "texture component type", "default": "float"} + {"name": "texture component type", "type": "texture component type", "default": "float"}, + {"name": "storage texture format", "type": "texture format", "default": "undefined"} ] }, "bind group layout descriptor": { diff --git a/src/dawn_native/BindGroupLayout.cpp b/src/dawn_native/BindGroupLayout.cpp index 9039789510..622ed02c85 100644 --- a/src/dawn_native/BindGroupLayout.cpp +++ b/src/dawn_native/BindGroupLayout.cpp @@ -58,7 +58,35 @@ namespace dawn_native { return {}; } - MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase*, + MaybeError ValidateStorageTextureFormat(DeviceBase* device, + wgpu::BindingType bindingType, + wgpu::TextureFormat storageTextureFormat) { + switch (bindingType) { + case wgpu::BindingType::ReadonlyStorageTexture: + case wgpu::BindingType::WriteonlyStorageTexture: { + DAWN_TRY(ValidateTextureFormat(storageTextureFormat)); + + const Format& format = device->GetValidInternalFormat(storageTextureFormat); + if (!format.supportsStorageUsage) { + return DAWN_VALIDATION_ERROR("The storage texture format is not supported"); + } + } break; + + case wgpu::BindingType::StorageBuffer: + case wgpu::BindingType::UniformBuffer: + case wgpu::BindingType::ReadonlyStorageBuffer: + case wgpu::BindingType::Sampler: + case wgpu::BindingType::SampledTexture: + break; + default: + UNREACHABLE(); + break; + } + + return {}; + } + + MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device, const BindGroupLayoutDescriptor* descriptor) { if (descriptor->nextInChain != nullptr) { return DAWN_VALIDATION_ERROR("nextInChain must be nullptr"); @@ -87,6 +115,9 @@ namespace dawn_native { DAWN_TRY( ValidateBindingTypeWithShaderStageVisibility(binding.type, binding.visibility)); + DAWN_TRY( + ValidateStorageTextureFormat(device, binding.type, binding.storageTextureFormat)); + switch (binding.type) { case wgpu::BindingType::UniformBuffer: if (binding.hasDynamicOffset) { diff --git a/src/dawn_native/BindGroupLayout.h b/src/dawn_native/BindGroupLayout.h index 24bae3964b..7455b58cbe 100644 --- a/src/dawn_native/BindGroupLayout.h +++ b/src/dawn_native/BindGroupLayout.h @@ -36,6 +36,10 @@ namespace dawn_native { wgpu::BindingType bindingType, wgpu::ShaderStage shaderStageVisibility); + MaybeError ValidateStorageTextureFormat(DeviceBase* device, + wgpu::BindingType bindingType, + wgpu::TextureFormat storageTextureFormat); + class BindGroupLayoutBase : public CachedObject { public: BindGroupLayoutBase(DeviceBase* device, const BindGroupLayoutDescriptor* descriptor); diff --git a/src/dawn_native/PipelineLayout.cpp b/src/dawn_native/PipelineLayout.cpp index 6f22685871..f72bbdaa9c 100644 --- a/src/dawn_native/PipelineLayout.cpp +++ b/src/dawn_native/PipelineLayout.cpp @@ -160,6 +160,9 @@ namespace dawn_native { DAWN_TRY(ValidateBindingTypeWithShaderStageVisibility( bindingInfo.type, StageBit(module->GetExecutionModel()))); + DAWN_TRY(ValidateStorageTextureFormat(device, bindingInfo.type, + bindingInfo.storageTextureFormat)); + bindingSlot.visibility = GetShaderStageVisibilityWithBindingType(bindingInfo.type); @@ -169,6 +172,7 @@ namespace dawn_native { bindingSlot.textureDimension = bindingInfo.textureDimension; bindingSlot.textureComponentType = Format::FormatTypeToTextureComponentType(bindingInfo.textureComponentType); + bindingSlot.storageTextureFormat = bindingInfo.storageTextureFormat; if (usedBindings[group][binding]) { if (bindingSlot == bindingData[group][usedBindingsMap[group][binding]]) { diff --git a/src/dawn_native/ShaderModule.cpp b/src/dawn_native/ShaderModule.cpp index a6a12c56ee..0a12a8f101 100644 --- a/src/dawn_native/ShaderModule.cpp +++ b/src/dawn_native/ShaderModule.cpp @@ -113,6 +113,9 @@ namespace dawn_native { return wgpu::BindingType::Sampler; case shaderc_spvc_binding_type_sampled_texture: return wgpu::BindingType::SampledTexture; + + // TODO(jiawei.shao@intel.com): add convertion to read-only and write-only storage + // textures when they are supported as shaderc_spvc binding types. case shaderc_spvc_binding_type_storage_texture: return wgpu::BindingType::StorageTexture; } @@ -134,6 +137,77 @@ namespace dawn_native { "Attempted to convert invalid spvc execution model to SingleShaderStage"); } } + + wgpu::TextureFormat ToWGPUTextureFormat(spv::ImageFormat format) { + switch (format) { + case spv::ImageFormatR8: + return wgpu::TextureFormat::R8Unorm; + case spv::ImageFormatR8Snorm: + return wgpu::TextureFormat::R8Snorm; + case spv::ImageFormatR8ui: + return wgpu::TextureFormat::R8Uint; + case spv::ImageFormatR8i: + return wgpu::TextureFormat::R8Sint; + case spv::ImageFormatR16ui: + return wgpu::TextureFormat::R16Uint; + case spv::ImageFormatR16i: + return wgpu::TextureFormat::R16Sint; + case spv::ImageFormatR16f: + return wgpu::TextureFormat::R16Float; + case spv::ImageFormatRg8: + return wgpu::TextureFormat::RG8Unorm; + case spv::ImageFormatRg8Snorm: + return wgpu::TextureFormat::RG8Snorm; + case spv::ImageFormatRg8ui: + return wgpu::TextureFormat::RG8Uint; + case spv::ImageFormatRg8i: + return wgpu::TextureFormat::RG8Sint; + case spv::ImageFormatR32f: + return wgpu::TextureFormat::R32Float; + case spv::ImageFormatR32ui: + return wgpu::TextureFormat::R32Uint; + case spv::ImageFormatR32i: + return wgpu::TextureFormat::R32Sint; + case spv::ImageFormatRg16ui: + return wgpu::TextureFormat::RG16Uint; + case spv::ImageFormatRg16i: + return wgpu::TextureFormat::RG16Sint; + case spv::ImageFormatRg16f: + return wgpu::TextureFormat::RG16Float; + case spv::ImageFormatRgba8: + return wgpu::TextureFormat::RGBA8Unorm; + case spv::ImageFormatRgba8Snorm: + return wgpu::TextureFormat::RGBA8Snorm; + case spv::ImageFormatRgba8ui: + return wgpu::TextureFormat::RGBA8Uint; + case spv::ImageFormatRgba8i: + return wgpu::TextureFormat::RGBA8Sint; + case spv::ImageFormatRgb10A2: + return wgpu::TextureFormat::RGB10A2Unorm; + case spv::ImageFormatR11fG11fB10f: + return wgpu::TextureFormat::RG11B10Float; + case spv::ImageFormatRg32f: + return wgpu::TextureFormat::RG32Float; + case spv::ImageFormatRg32ui: + return wgpu::TextureFormat::RG32Uint; + case spv::ImageFormatRg32i: + return wgpu::TextureFormat::RG32Sint; + case spv::ImageFormatRgba16ui: + return wgpu::TextureFormat::RGBA16Uint; + case spv::ImageFormatRgba16i: + return wgpu::TextureFormat::RGBA16Sint; + case spv::ImageFormatRgba16f: + return wgpu::TextureFormat::RGBA16Float; + case spv::ImageFormatRgba32f: + return wgpu::TextureFormat::RGBA32Float; + case spv::ImageFormatRgba32ui: + return wgpu::TextureFormat::RGBA32Uint; + case spv::ImageFormatRgba32i: + return wgpu::TextureFormat::RGBA32Sint; + default: + return wgpu::TextureFormat::Undefined; + } + } } // anonymous namespace MaybeError ValidateShaderModuleDescriptor(DeviceBase*, @@ -173,7 +247,7 @@ namespace dawn_native { } return {}; - } + } // namespace // ShaderModuleBase @@ -251,6 +325,7 @@ namespace dawn_native { return {}; }; + // TODO(jiawei.shao@intel.com): extract binding information about storage textures. std::vector resource_bindings; DAWN_TRY(CheckSpvcSuccess(mSpvcContext.GetBindingInfo( shaderc_spvc_shader_resource_uniform_buffers, @@ -415,6 +490,22 @@ namespace dawn_native { } else { info->type = wgpu::BindingType::StorageTexture; } + + spirv_cross::SPIRType::ImageType imageType = + compiler.get_type(info->base_type_id).image; + wgpu::TextureFormat storageTextureFormat = + ToWGPUTextureFormat(imageType.format); + if (storageTextureFormat == wgpu::TextureFormat::Undefined) { + return DAWN_VALIDATION_ERROR( + "Invalid image format declaration on storage image"); + } + const Format& format = + GetDevice()->GetValidInternalFormat(storageTextureFormat); + if (!format.supportsStorageUsage) { + return DAWN_VALIDATION_ERROR( + "The storage texture format is not supported"); + } + info->storageTextureFormat = storageTextureFormat; } break; default: info->type = bindingType; diff --git a/src/dawn_native/ShaderModule.h b/src/dawn_native/ShaderModule.h index 096d528ee1..20f67a17e4 100644 --- a/src/dawn_native/ShaderModule.h +++ b/src/dawn_native/ShaderModule.h @@ -58,6 +58,7 @@ namespace dawn_native { Format::Type textureComponentType = Format::Type::Float; bool multisampled = false; bool used = false; + wgpu::TextureFormat storageTextureFormat = wgpu::TextureFormat::Undefined; }; using ModuleBindingInfo = std::array, kMaxBindGroups>; diff --git a/src/tests/end2end/StorageTextureTests.cpp b/src/tests/end2end/StorageTextureTests.cpp index 3886098b1c..b351db7d54 100644 --- a/src/tests/end2end/StorageTextureTests.cpp +++ b/src/tests/end2end/StorageTextureTests.cpp @@ -25,6 +25,7 @@ TEST_P(StorageTextureTests, BindGroupLayoutWithStorageTextureBindingType) { { wgpu::BindGroupLayoutBinding binding = {0, wgpu::ShaderStage::Compute, wgpu::BindingType::ReadonlyStorageTexture}; + binding.storageTextureFormat = wgpu::TextureFormat::R32Float; wgpu::BindGroupLayoutDescriptor descriptor; descriptor.bindingCount = 1; descriptor.bindings = &binding; @@ -36,6 +37,7 @@ TEST_P(StorageTextureTests, BindGroupLayoutWithStorageTextureBindingType) { { wgpu::BindGroupLayoutBinding binding = {0, wgpu::ShaderStage::Compute, wgpu::BindingType::WriteonlyStorageTexture}; + binding.storageTextureFormat = wgpu::TextureFormat::R32Float; wgpu::BindGroupLayoutDescriptor descriptor; descriptor.bindingCount = 1; descriptor.bindings = &binding; diff --git a/src/tests/end2end/TextureFormatTests.cpp b/src/tests/end2end/TextureFormatTests.cpp index a31d38fe9e..61f80e3065 100644 --- a/src/tests/end2end/TextureFormatTests.cpp +++ b/src/tests/end2end/TextureFormatTests.cpp @@ -17,6 +17,7 @@ #include "common/Assert.h" #include "common/Math.h" #include "utils/ComboRenderPipelineDescriptor.h" +#include "utils/TextureFormatUtils.h" #include "utils/WGPUHelpers.h" #include @@ -185,21 +186,7 @@ class TextureFormatTest : public DawnTest { })"); // Compute the prefix needed for GLSL types that handle our texture's data. - const char* prefix = nullptr; - switch (sampleFormatInfo.type) { - case wgpu::TextureComponentType::Float: - prefix = ""; - break; - case wgpu::TextureComponentType::Sint: - prefix = "i"; - break; - case wgpu::TextureComponentType::Uint: - prefix = "u"; - break; - default: - UNREACHABLE(); - break; - } + const char* prefix = utils::GetColorTextureComponentTypePrefix(sampleFormatInfo.format); std::ostringstream fsSource; fsSource << "#version 450\n"; diff --git a/src/tests/unittests/validation/StorageTextureValidationTests.cpp b/src/tests/unittests/validation/StorageTextureValidationTests.cpp index 0bcfddbfe5..30e9e65b6f 100644 --- a/src/tests/unittests/validation/StorageTextureValidationTests.cpp +++ b/src/tests/unittests/validation/StorageTextureValidationTests.cpp @@ -12,19 +12,132 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "common/Assert.h" #include "tests/unittests/validation/ValidationTest.h" #include "utils/ComboRenderPipelineDescriptor.h" +#include "utils/TextureFormatUtils.h" #include "utils/WGPUHelpers.h" class StorageTextureValidationTests : public ValidationTest { protected: - wgpu::ShaderModule mDefaultVSModule = + static const char* GetGLSLImageFormatQualifier(wgpu::TextureFormat textureFormat) { + switch (textureFormat) { + case wgpu::TextureFormat::R8Unorm: + return "r8"; + case wgpu::TextureFormat::R8Snorm: + return "r8_snorm"; + case wgpu::TextureFormat::R8Uint: + return "r8ui"; + case wgpu::TextureFormat::R8Sint: + return "r8i"; + case wgpu::TextureFormat::R16Uint: + return "r16ui"; + case wgpu::TextureFormat::R16Sint: + return "r16i"; + case wgpu::TextureFormat::R16Float: + return "r16f"; + case wgpu::TextureFormat::RG8Unorm: + return "rg8"; + case wgpu::TextureFormat::RG8Snorm: + return "rg8_snorm"; + case wgpu::TextureFormat::RG8Uint: + return "rg8ui"; + case wgpu::TextureFormat::RG8Sint: + return "rg8i"; + case wgpu::TextureFormat::R32Float: + return "r32f"; + case wgpu::TextureFormat::R32Uint: + return "r32ui"; + case wgpu::TextureFormat::R32Sint: + return "r32i"; + case wgpu::TextureFormat::RG16Uint: + return "rg16ui"; + case wgpu::TextureFormat::RG16Sint: + return "rg16i"; + case wgpu::TextureFormat::RG16Float: + return "rg16f"; + case wgpu::TextureFormat::RGBA8Unorm: + return "rgba8"; + case wgpu::TextureFormat::RGBA8Snorm: + return "rgba8_snorm"; + case wgpu::TextureFormat::RGBA8Uint: + return "rgba8ui"; + case wgpu::TextureFormat::RGBA8Sint: + return "rgba8i"; + case wgpu::TextureFormat::RGB10A2Unorm: + return "rgb10_a2"; + case wgpu::TextureFormat::RG11B10Float: + return "r11f_g11f_b10f"; + case wgpu::TextureFormat::RG32Float: + return "rg32f"; + case wgpu::TextureFormat::RG32Uint: + return "rg32ui"; + case wgpu::TextureFormat::RG32Sint: + return "rg32i"; + case wgpu::TextureFormat::RGBA16Uint: + return "rgba16ui"; + case wgpu::TextureFormat::RGBA16Sint: + return "rgba16i"; + case wgpu::TextureFormat::RGBA16Float: + return "rgba16f"; + case wgpu::TextureFormat::RGBA32Float: + return "rgba32f"; + case wgpu::TextureFormat::RGBA32Uint: + return "rgba32ui"; + case wgpu::TextureFormat::RGBA32Sint: + return "rgba32i"; + default: + UNREACHABLE(); + return ""; + } + } + + static std::string CreateComputeShaderWithStorageTexture( + wgpu::BindingType storageTextureBindingType, + wgpu::TextureFormat textureFormat) { + const char* glslImageFormatQualifier = GetGLSLImageFormatQualifier(textureFormat); + const char* textureComponentTypePrefix = + utils::GetColorTextureComponentTypePrefix(textureFormat); + return CreateComputeShaderWithStorageTexture( + storageTextureBindingType, glslImageFormatQualifier, textureComponentTypePrefix); + } + + static std::string CreateComputeShaderWithStorageTexture( + wgpu::BindingType storageTextureBindingType, + const char* glslImageFormatQualifier, + const char* textureComponentTypePrefix) { + const char* memoryQualifier = ""; + switch (storageTextureBindingType) { + case wgpu::BindingType::ReadonlyStorageTexture: + memoryQualifier = "readonly"; + break; + case wgpu::BindingType::WriteonlyStorageTexture: + memoryQualifier = "writeonly"; + break; + default: + UNREACHABLE(); + break; + } + + std::ostringstream ostream; + ostream << "#version 450\n" + "layout (set = 0, binding = 0, " + << glslImageFormatQualifier << ") uniform " << memoryQualifier << " " + << textureComponentTypePrefix + << "image2D image0;\n" + "void main() {\n" + "}\n"; + + return ostream.str(); + } + + const wgpu::ShaderModule mDefaultVSModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"( #version 450 void main() { gl_Position = vec4(0.f, 0.f, 0.f, 1.f); })"); - wgpu::ShaderModule mDefaultFSModule = + const wgpu::ShaderModule mDefaultFSModule = utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( #version 450 layout(location = 0) out vec4 fragColor; @@ -227,6 +340,7 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutWithStorageTextureBindingTy for (const auto& testSpec : kTestSpecs) { wgpu::BindGroupLayoutBinding binding = {0, testSpec.stage, testSpec.type}; + binding.storageTextureFormat = wgpu::TextureFormat::R32Uint; wgpu::BindGroupLayoutDescriptor descriptor; descriptor.bindingCount = 1; descriptor.bindings = &binding; @@ -238,3 +352,73 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutWithStorageTextureBindingTy } } } + +// Validate it is an error to declare a read-only or write-only storage texture in shaders with any +// format that doesn't support TextureUsage::Storage texture usages. +TEST_F(StorageTextureValidationTests, StorageTextureFormatInShaders) { + // Not include RGBA8UnormSrgb, BGRA8Unorm, BGRA8UnormSrgb because they are not related to any + // SPIR-V Image Formats. + constexpr std::array kWGPUTextureFormatSupportedAsSPIRVImageFormats = { + wgpu::TextureFormat::R32Uint, wgpu::TextureFormat::R32Sint, + wgpu::TextureFormat::R32Float, wgpu::TextureFormat::RGBA8Unorm, + wgpu::TextureFormat::RGBA8Snorm, wgpu::TextureFormat::RGBA8Uint, + wgpu::TextureFormat::RGBA8Sint, wgpu::TextureFormat::RG32Uint, + wgpu::TextureFormat::RG32Sint, wgpu::TextureFormat::RG32Float, + wgpu::TextureFormat::RGBA16Uint, wgpu::TextureFormat::RGBA16Sint, + wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RGBA32Uint, + wgpu::TextureFormat::RGBA32Sint, wgpu::TextureFormat::RGBA32Float, + wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, + wgpu::TextureFormat::R8Uint, wgpu::TextureFormat::R8Sint, + wgpu::TextureFormat::R16Uint, wgpu::TextureFormat::R16Sint, + wgpu::TextureFormat::R16Float, wgpu::TextureFormat::RG8Unorm, + wgpu::TextureFormat::RG8Snorm, wgpu::TextureFormat::RG8Uint, + wgpu::TextureFormat::RG8Sint, wgpu::TextureFormat::RG16Uint, + wgpu::TextureFormat::RG16Sint, wgpu::TextureFormat::RG16Float, + wgpu::TextureFormat::RGB10A2Unorm, wgpu::TextureFormat::RG11B10Float}; + + constexpr std::array kStorageTextureBindingTypes = { + wgpu::BindingType::ReadonlyStorageTexture, wgpu::BindingType::WriteonlyStorageTexture}; + + for (wgpu::BindingType storageTextureBindingType : kStorageTextureBindingTypes) { + for (wgpu::TextureFormat format : kWGPUTextureFormatSupportedAsSPIRVImageFormats) { + std::string computeShader = + CreateComputeShaderWithStorageTexture(storageTextureBindingType, format); + if (utils::TextureFormatSupportsStorageTexture(format)) { + utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, + computeShader.c_str()); + } else { + ASSERT_DEVICE_ERROR(utils::CreateShaderModule( + device, utils::SingleShaderStage::Compute, computeShader.c_str())); + } + } + } +} + +// Verify that declaring a storage texture format that is not supported in WebGPU causes validation +// error. +TEST_F(StorageTextureValidationTests, UnsupportedSPIRVStorageTextureFormat) { + struct TextureFormatInfo { + const char* name; + const char* componentTypePrefix; + }; + + constexpr std::array kUnsupportedTextureFormats = {{{"rgba16", ""}, + {"rg16", ""}, + {"r16", ""}, + {"rgba16_snorm", ""}, + {"rg16_snorm", ""}, + {"r16_snorm", ""}, + {"rgb10_a2ui", "u"}}}; + + constexpr std::array kStorageTextureBindingTypes = { + wgpu::BindingType::ReadonlyStorageTexture, wgpu::BindingType::WriteonlyStorageTexture}; + + for (wgpu::BindingType bindingType : kStorageTextureBindingTypes) { + for (const TextureFormatInfo& formatInfo : kUnsupportedTextureFormats) { + std::string computeShader = CreateComputeShaderWithStorageTexture( + bindingType, formatInfo.name, formatInfo.componentTypePrefix); + ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, + computeShader.c_str())); + } + } +} diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp index 4a996fc4fc..a75c5cfdd7 100644 --- a/src/tests/unittests/validation/TextureValidationTests.cpp +++ b/src/tests/unittests/validation/TextureValidationTests.cpp @@ -16,6 +16,7 @@ #include "common/Constants.h" #include "utils/ComboRenderPipelineDescriptor.h" +#include "utils/TextureFormatUtils.h" #include "utils/WGPUHelpers.h" namespace { @@ -345,37 +346,13 @@ TEST_F(TextureValidationTest, TextureFormatNotSupportTextureUsageStorage) { descriptor.size = {1, 1, 1}; descriptor.usage = wgpu::TextureUsage::Storage; - wgpu::TextureFormat kSupportedFormatsWithStorageUsage[] = { - wgpu::TextureFormat::R32Uint, wgpu::TextureFormat::R32Sint, - wgpu::TextureFormat::R32Uint, wgpu::TextureFormat::RGBA8Unorm, - wgpu::TextureFormat::RGBA8Snorm, wgpu::TextureFormat::RGBA8Uint, - wgpu::TextureFormat::RGBA8Sint, wgpu::TextureFormat::RG32Uint, - wgpu::TextureFormat::RG32Sint, wgpu::TextureFormat::RG32Float, - wgpu::TextureFormat::RGBA16Uint, wgpu::TextureFormat::RGBA16Sint, - wgpu::TextureFormat::RGBA16Float, wgpu::TextureFormat::RGBA32Uint, - wgpu::TextureFormat::RGBA32Sint, wgpu::TextureFormat::RGBA32Float}; - for (wgpu::TextureFormat format : kSupportedFormatsWithStorageUsage) { + for (wgpu::TextureFormat format : utils::kAllTextureFormats) { descriptor.format = format; - device.CreateTexture(&descriptor); - } - - wgpu::TextureFormat kUnsupportedFormatsWithStorageUsage[] = { - wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, - wgpu::TextureFormat::R8Uint, wgpu::TextureFormat::R8Sint, - wgpu::TextureFormat::R16Uint, wgpu::TextureFormat::R16Sint, - wgpu::TextureFormat::R16Float, wgpu::TextureFormat::RG8Unorm, - wgpu::TextureFormat::RG8Snorm, wgpu::TextureFormat::RG8Uint, - wgpu::TextureFormat::RG8Sint, wgpu::TextureFormat::RG16Uint, - wgpu::TextureFormat::RG16Sint, wgpu::TextureFormat::RG16Float, - wgpu::TextureFormat::RGBA8UnormSrgb, wgpu::TextureFormat::BGRA8Unorm, - wgpu::TextureFormat::BGRA8UnormSrgb, wgpu::TextureFormat::RGB10A2Unorm, - wgpu::TextureFormat::RG11B10Float, - - wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8, - wgpu::TextureFormat::Depth32Float}; - for (wgpu::TextureFormat format : kUnsupportedFormatsWithStorageUsage) { - descriptor.format = format; - ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); + if (utils::TextureFormatSupportsStorageTexture(format)) { + device.CreateTexture(&descriptor); + } else { + ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); + } } } diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 06ec98c92c..3a959401a2 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -26,6 +26,8 @@ target_sources(dawn_utils PRIVATE "SystemUtils.h" "TerribleCommandBuffer.cpp" "TerribleCommandBuffer.h" + "TextureFormatUtils.cpp" + "TextureFormatUtils.h" "Timer.h" "WGPUHelpers.cpp" "WGPUHelpers.h" diff --git a/src/utils/TextureFormatUtils.cpp b/src/utils/TextureFormatUtils.cpp new file mode 100644 index 0000000000..634417cd12 --- /dev/null +++ b/src/utils/TextureFormatUtils.cpp @@ -0,0 +1,89 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "TextureFormatUtils.h" + +namespace utils { + const char* GetColorTextureComponentTypePrefix(wgpu::TextureFormat textureFormat) { + switch (textureFormat) { + case wgpu::TextureFormat::R8Unorm: + case wgpu::TextureFormat::R8Snorm: + case wgpu::TextureFormat::R16Float: + case wgpu::TextureFormat::RG8Unorm: + case wgpu::TextureFormat::RG8Snorm: + case wgpu::TextureFormat::R32Float: + case wgpu::TextureFormat::RG16Float: + case wgpu::TextureFormat::RGBA8Unorm: + case wgpu::TextureFormat::RGBA8Snorm: + case wgpu::TextureFormat::RGB10A2Unorm: + case wgpu::TextureFormat::RG11B10Float: + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RGBA16Float: + case wgpu::TextureFormat::RGBA32Float: + case wgpu::TextureFormat::BGRA8Unorm: + case wgpu::TextureFormat::BGRA8UnormSrgb: + case wgpu::TextureFormat::RGBA8UnormSrgb: + return ""; + + case wgpu::TextureFormat::R8Uint: + case wgpu::TextureFormat::R16Uint: + case wgpu::TextureFormat::RG8Uint: + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::RG16Uint: + case wgpu::TextureFormat::RGBA8Uint: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RGBA16Uint: + case wgpu::TextureFormat::RGBA32Uint: + return "u"; + + case wgpu::TextureFormat::R8Sint: + case wgpu::TextureFormat::R16Sint: + case wgpu::TextureFormat::RG8Sint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::RG16Sint: + case wgpu::TextureFormat::RGBA8Sint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::RGBA16Sint: + case wgpu::TextureFormat::RGBA32Sint: + return "i"; + default: + UNREACHABLE(); + return ""; + } + } + + bool TextureFormatSupportsStorageTexture(wgpu::TextureFormat format) { + switch (format) { + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::R32Float: + case wgpu::TextureFormat::RGBA8Unorm: + case wgpu::TextureFormat::RGBA8Snorm: + case wgpu::TextureFormat::RGBA8Uint: + case wgpu::TextureFormat::RGBA8Sint: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RGBA16Uint: + case wgpu::TextureFormat::RGBA16Sint: + case wgpu::TextureFormat::RGBA16Float: + case wgpu::TextureFormat::RGBA32Uint: + case wgpu::TextureFormat::RGBA32Sint: + case wgpu::TextureFormat::RGBA32Float: + return true; + default: + return false; + } + } +} // namespace utils diff --git a/src/utils/TextureFormatUtils.h b/src/utils/TextureFormatUtils.h new file mode 100644 index 0000000000..bbd5f0c184 --- /dev/null +++ b/src/utils/TextureFormatUtils.h @@ -0,0 +1,58 @@ +// Copyright 2020 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef UTILS_TEXTURE_FORMAT_UTILS_H_ +#define UTILS_TEXTURE_FORMAT_UTILS_H_ + +#include + +#include + +#include "common/Assert.h" + +namespace utils { + static constexpr std::array kAllTextureFormats = { + wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::R8Snorm, + wgpu::TextureFormat::R8Uint, wgpu::TextureFormat::R8Sint, + wgpu::TextureFormat::R16Uint, wgpu::TextureFormat::R16Sint, + wgpu::TextureFormat::R16Float, wgpu::TextureFormat::RG8Unorm, + wgpu::TextureFormat::RG8Snorm, wgpu::TextureFormat::RG8Uint, + wgpu::TextureFormat::RG8Sint, wgpu::TextureFormat::R32Float, + wgpu::TextureFormat::R32Uint, wgpu::TextureFormat::R32Sint, + wgpu::TextureFormat::RG16Uint, wgpu::TextureFormat::RG16Sint, + wgpu::TextureFormat::RG16Float, wgpu::TextureFormat::RGBA8Unorm, + wgpu::TextureFormat::RGBA8UnormSrgb, wgpu::TextureFormat::RGBA8Snorm, + wgpu::TextureFormat::RGBA8Uint, wgpu::TextureFormat::RGBA8Sint, + wgpu::TextureFormat::BGRA8Unorm, wgpu::TextureFormat::BGRA8UnormSrgb, + wgpu::TextureFormat::RGB10A2Unorm, wgpu::TextureFormat::RG11B10Float, + wgpu::TextureFormat::RG32Float, wgpu::TextureFormat::RG32Uint, + wgpu::TextureFormat::RG32Sint, wgpu::TextureFormat::RGBA16Uint, + wgpu::TextureFormat::RGBA16Sint, wgpu::TextureFormat::RGBA16Float, + wgpu::TextureFormat::RGBA32Float, wgpu::TextureFormat::RGBA32Uint, + wgpu::TextureFormat::RGBA32Sint, wgpu::TextureFormat::Depth32Float, + wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8, + wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb, + wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb, + wgpu::TextureFormat::BC3RGBAUnorm, wgpu::TextureFormat::BC3RGBAUnormSrgb, + wgpu::TextureFormat::BC4RUnorm, wgpu::TextureFormat::BC4RSnorm, + wgpu::TextureFormat::BC5RGUnorm, wgpu::TextureFormat::BC5RGSnorm, + wgpu::TextureFormat::BC6HRGBUfloat, wgpu::TextureFormat::BC6HRGBSfloat, + wgpu::TextureFormat::BC7RGBAUnorm, wgpu::TextureFormat::BC7RGBAUnormSrgb, + }; + + const char* GetColorTextureComponentTypePrefix(wgpu::TextureFormat textureFormat); + bool TextureFormatSupportsStorageTexture(wgpu::TextureFormat format); +} // namespace utils + +#endif