From ab1a2b7407d418b115b908a8373124bd5ce02226 Mon Sep 17 00:00:00 2001 From: Jiawei Shao Date: Thu, 17 Feb 2022 00:48:26 +0000 Subject: [PATCH] Add validation on format when creating a multisampled texture This patch adds the validation on the texture format when we create a texture with sample count > 1 according to the latest updates in WebGPU SPEC. Below formats can't be used to create a multisampled texture: - R32Uint, R32Sint, RG32Uint, RG32Sint, RG32Float, RGBA32Uint, RGBA32Uint, RGBA32Sint, RGBA32Float - All compressed formats - RGB9E5UFloat BUG=dawn:1244 TEST=dawn_unittests Change-Id: I71743281ce12158be4b1904732934fad95f39cee Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/80240 Reviewed-by: Brandon Jones Reviewed-by: Austin Eng Commit-Queue: Jiawei Shao --- src/dawn/native/Format.cpp | 91 ++++++++++--------- src/dawn/native/Format.h | 1 + src/dawn/native/Texture.cpp | 5 +- .../validation/TextureValidationTests.cpp | 12 ++- src/dawn/utils/TextureUtils.cpp | 23 +++++ src/dawn/utils/TextureUtils.h | 25 +++++ 6 files changed, 107 insertions(+), 50 deletions(-) diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp index e4eb963f19..403291d1cf 100644 --- a/src/dawn/native/Format.cpp +++ b/src/dawn/native/Format.cpp @@ -158,7 +158,8 @@ namespace dawn::native { auto AddColorFormat = [&AddFormat](wgpu::TextureFormat format, bool renderable, bool supportsStorageUsage, - uint32_t byteSize, SampleTypeBit sampleTypes, uint8_t componentCount, + bool supportsMultisample, uint32_t byteSize, SampleTypeBit sampleTypes, + uint8_t componentCount, wgpu::TextureFormat baseFormat = wgpu::TextureFormat::Undefined) { Format internalFormat; internalFormat.format = format; @@ -166,6 +167,7 @@ namespace dawn::native { internalFormat.isCompressed = false; internalFormat.isSupported = true; internalFormat.supportsStorageUsage = supportsStorageUsage; + internalFormat.supportsMultisample = supportsMultisample; internalFormat.aspects = Aspect::Color; internalFormat.componentCount = componentCount; @@ -213,6 +215,7 @@ namespace dawn::native { internalFormat.isCompressed = false; internalFormat.isSupported = isSupported; internalFormat.supportsStorageUsage = false; + internalFormat.supportsMultisample = true; internalFormat.aspects = Aspect::Depth; internalFormat.componentCount = 1; @@ -242,6 +245,7 @@ namespace dawn::native { internalFormat.isCompressed = false; internalFormat.isSupported = isSupported; internalFormat.supportsStorageUsage = false; + internalFormat.supportsMultisample = true; internalFormat.aspects = Aspect::Stencil; internalFormat.componentCount = 1; internalFormat.baseFormat = baseFormat; @@ -273,6 +277,7 @@ namespace dawn::native { internalFormat.isCompressed = true; internalFormat.isSupported = isSupported; internalFormat.supportsStorageUsage = false; + internalFormat.supportsMultisample = false; internalFormat.aspects = Aspect::Color; internalFormat.componentCount = componentCount; @@ -296,7 +301,8 @@ namespace dawn::native { auto AddMultiAspectFormat = [&AddFormat, &table](wgpu::TextureFormat format, Aspect aspects, wgpu::TextureFormat firstFormat, wgpu::TextureFormat secondFormat, - bool isRenderable, bool isSupported, uint8_t componentCount, + bool isRenderable, bool isSupported, bool supportsMultisample, + uint8_t componentCount, wgpu::TextureFormat baseFormat = wgpu::TextureFormat::Undefined) { Format internalFormat; internalFormat.format = format; @@ -304,6 +310,7 @@ namespace dawn::native { internalFormat.isCompressed = false; internalFormat.isSupported = isSupported; internalFormat.supportsStorageUsage = false; + internalFormat.supportsMultisample = supportsMultisample; internalFormat.aspects = aspects; internalFormat.componentCount = componentCount; @@ -325,51 +332,51 @@ namespace dawn::native { // clang-format off // 1 byte color formats - AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, 1, kAnyFloat, 1); - AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, 1, kAnyFloat, 1); - AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, 1, SampleTypeBit::Uint, 1); - AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, 1, SampleTypeBit::Sint, 1); + AddColorFormat(wgpu::TextureFormat::R8Unorm, true, false, true, 1, kAnyFloat, 1); + AddColorFormat(wgpu::TextureFormat::R8Snorm, false, false, true, 1, kAnyFloat, 1); + AddColorFormat(wgpu::TextureFormat::R8Uint, true, false, true, 1, SampleTypeBit::Uint, 1); + AddColorFormat(wgpu::TextureFormat::R8Sint, true, false, true, 1, SampleTypeBit::Sint, 1); // 2 bytes color formats - AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, 2, SampleTypeBit::Uint, 1); - AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, 2, SampleTypeBit::Sint, 1); - AddColorFormat(wgpu::TextureFormat::R16Float, true, false, 2, kAnyFloat, 1); - AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, 2, kAnyFloat, 2); - AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, 2, kAnyFloat, 2); - AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, 2, SampleTypeBit::Uint, 2); - AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, 2, SampleTypeBit::Sint, 2); + AddColorFormat(wgpu::TextureFormat::R16Uint, true, false, true, 2, SampleTypeBit::Uint, 1); + AddColorFormat(wgpu::TextureFormat::R16Sint, true, false, true, 2, SampleTypeBit::Sint, 1); + AddColorFormat(wgpu::TextureFormat::R16Float, true, false, true, 2, kAnyFloat, 1); + AddColorFormat(wgpu::TextureFormat::RG8Unorm, true, false, true, 2, kAnyFloat, 2); + AddColorFormat(wgpu::TextureFormat::RG8Snorm, false, false, true, 2, kAnyFloat, 2); + AddColorFormat(wgpu::TextureFormat::RG8Uint, true, false, true, 2, SampleTypeBit::Uint, 2); + AddColorFormat(wgpu::TextureFormat::RG8Sint, true, false, true, 2, SampleTypeBit::Sint, 2); // 4 bytes color formats - AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, 4, SampleTypeBit::Uint, 1); - AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, 4, SampleTypeBit::Sint, 1); - AddColorFormat(wgpu::TextureFormat::R32Float, true, true, 4, SampleTypeBit::UnfilterableFloat, 1); - AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, 4, SampleTypeBit::Uint, 2); - AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, 4, SampleTypeBit::Sint, 2); - AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, 4, kAnyFloat, 2); - AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, 4, kAnyFloat, 4); - AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, 4, kAnyFloat, 4, wgpu::TextureFormat::RGBA8Unorm); - AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, 4, kAnyFloat, 4); - AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, 4, SampleTypeBit::Uint, 4); - AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, 4, SampleTypeBit::Sint, 4); - AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, 4, kAnyFloat, 4); - AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, 4, kAnyFloat, 4, wgpu::TextureFormat::BGRA8Unorm); - AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, 4, kAnyFloat, 4); + AddColorFormat(wgpu::TextureFormat::R32Uint, true, true, false, 4, SampleTypeBit::Uint, 1); + AddColorFormat(wgpu::TextureFormat::R32Sint, true, true, false, 4, SampleTypeBit::Sint, 1); + AddColorFormat(wgpu::TextureFormat::R32Float, true, true, true, 4, SampleTypeBit::UnfilterableFloat, 1); + AddColorFormat(wgpu::TextureFormat::RG16Uint, true, false, true, 4, SampleTypeBit::Uint, 2); + AddColorFormat(wgpu::TextureFormat::RG16Sint, true, false, true, 4, SampleTypeBit::Sint, 2); + AddColorFormat(wgpu::TextureFormat::RG16Float, true, false, true, 4, kAnyFloat, 2); + AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, true, true, true, 4, kAnyFloat, 4); + AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, true, false, true, 4, kAnyFloat, 4, wgpu::TextureFormat::RGBA8Unorm); + AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, false, true, true, 4, kAnyFloat, 4); + AddColorFormat(wgpu::TextureFormat::RGBA8Uint, true, true, true, 4, SampleTypeBit::Uint, 4); + AddColorFormat(wgpu::TextureFormat::RGBA8Sint, true, true, true, 4, SampleTypeBit::Sint, 4); + AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, true, false, true, 4, kAnyFloat, 4); + AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, true, 4, kAnyFloat, 4, wgpu::TextureFormat::BGRA8Unorm); + AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, true, 4, kAnyFloat, 4); - AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, 4, kAnyFloat, 3); - AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, 4, kAnyFloat, 3); + AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, true, 4, kAnyFloat, 3); + AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, false, 4, kAnyFloat, 3); // 8 bytes color formats - AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, 8, SampleTypeBit::Uint, 2); - AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, 8, SampleTypeBit::Sint, 2); - AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, 8, SampleTypeBit::UnfilterableFloat, 2); - AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, 8, SampleTypeBit::Uint, 4); - AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, 8, SampleTypeBit::Sint, 4); - AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, 8, kAnyFloat, 4); + AddColorFormat(wgpu::TextureFormat::RG32Uint, true, true, false, 8, SampleTypeBit::Uint, 2); + AddColorFormat(wgpu::TextureFormat::RG32Sint, true, true, false, 8, SampleTypeBit::Sint, 2); + AddColorFormat(wgpu::TextureFormat::RG32Float, true, true, false, 8, SampleTypeBit::UnfilterableFloat, 2); + AddColorFormat(wgpu::TextureFormat::RGBA16Uint, true, true, true, 8, SampleTypeBit::Uint, 4); + AddColorFormat(wgpu::TextureFormat::RGBA16Sint, true, true, true, 8, SampleTypeBit::Sint, 4); + AddColorFormat(wgpu::TextureFormat::RGBA16Float, true, true, true, 8, kAnyFloat, 4); // 16 bytes color formats - AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, 16, SampleTypeBit::Uint, 4); - AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, 16, SampleTypeBit::Sint, 4); - AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, 16, SampleTypeBit::UnfilterableFloat, 4); + AddColorFormat(wgpu::TextureFormat::RGBA32Uint, true, true, false, 16, SampleTypeBit::Uint, 4); + AddColorFormat(wgpu::TextureFormat::RGBA32Sint, true, true, false, 16, SampleTypeBit::Sint, 4); + AddColorFormat(wgpu::TextureFormat::RGBA32Float, true, true, false, 16, SampleTypeBit::UnfilterableFloat, 4); // Depth-stencil formats // TODO(dawn:666): Implement the stencil8 format @@ -380,14 +387,14 @@ namespace dawn::native { // using 0 here to mean "unsized" and adding a backend-specific query for the block size. AddDepthFormat(wgpu::TextureFormat::Depth24Plus, 4, true); AddMultiAspectFormat(wgpu::TextureFormat::Depth24PlusStencil8, - Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true, 2); + Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, true, true, 2); bool isD24S8Supported = device->IsFeatureEnabled(Feature::Depth24UnormStencil8); AddMultiAspectFormat(wgpu::TextureFormat::Depth24UnormStencil8, - Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, isD24S8Supported, 2); + Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Stencil8, true, isD24S8Supported, true, 2); AddDepthFormat(wgpu::TextureFormat::Depth32Float, 4, true); bool isD32S8Supported = device->IsFeatureEnabled(Feature::Depth32FloatStencil8); AddMultiAspectFormat(wgpu::TextureFormat::Depth32FloatStencil8, - Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Stencil8, true, isD32S8Supported, 2); + Aspect::Depth | Aspect::Stencil, wgpu::TextureFormat::Depth32Float, wgpu::TextureFormat::Stencil8, true, isD32S8Supported, true, 2); // BC compressed formats bool isBCFormatSupported = device->IsFeatureEnabled(Feature::TextureCompressionBC); @@ -453,7 +460,7 @@ namespace dawn::native { // multi-planar formats const bool isMultiPlanarFormatSupported = device->IsFeatureEnabled(Feature::MultiPlanarFormats); AddMultiAspectFormat(wgpu::TextureFormat::R8BG8Biplanar420Unorm, Aspect::Plane0 | Aspect::Plane1, - wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported, 3); + wgpu::TextureFormat::R8Unorm, wgpu::TextureFormat::RG8Unorm, false, isMultiPlanarFormatSupported, false, 3); // clang-format on diff --git a/src/dawn/native/Format.h b/src/dawn/native/Format.h index 5d3afc2fb9..228913ca2d 100644 --- a/src/dawn/native/Format.h +++ b/src/dawn/native/Format.h @@ -91,6 +91,7 @@ namespace dawn::native { // A format can be known but not supported because it is part of a disabled extension. bool isSupported; bool supportsStorageUsage; + bool supportsMultisample; Aspect aspects; // Only used for renderable color formats, number of color channels. uint8_t componentCount; diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index ef0ee26beb..5f81a7f39a 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -112,10 +112,7 @@ namespace dawn::native { "The depthOrArrayLayers (%u) of a multisampled texture is not 1.", descriptor->size.depthOrArrayLayers); - // If a format can support multisample, it must be renderable. Because Vulkan - // requires that if the format is not color-renderable or depth/stencil renderable, - // sampleCount must be 1. - DAWN_INVALID_IF(!format->isRenderable, + DAWN_INVALID_IF(!format->supportsMultisample, "The texture format (%s) does not support multisampling.", format->format); diff --git a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp index 0b7f476e8e..3136c769d3 100644 --- a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp +++ b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp @@ -144,15 +144,19 @@ namespace { { wgpu::TextureDescriptor descriptor = defaultDescriptor; descriptor.sampleCount = 4; + descriptor.usage = wgpu::TextureUsage::TextureBinding; - for (wgpu::TextureFormat format : kNonRenderableColorFormats) { - // If a format can support multisample, it must be renderable. + for (wgpu::TextureFormat format : utils::kFormatsInCoreSpec) { descriptor.format = format; - ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); + if (utils::TextureFormatSupportsMultisampling(format)) { + device.CreateTexture(&descriptor); + } else { + ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor)); + } } } - // Currently we do not support multisampled 2D textures with depth>1. + // Currently we do not support multisampled 2D textures with depth > 1. { wgpu::TextureDescriptor descriptor = defaultDescriptor; descriptor.sampleCount = 4; diff --git a/src/dawn/utils/TextureUtils.cpp b/src/dawn/utils/TextureUtils.cpp index 9f5277a9f0..099cad24b8 100644 --- a/src/dawn/utils/TextureUtils.cpp +++ b/src/dawn/utils/TextureUtils.cpp @@ -130,6 +130,29 @@ namespace utils { } } + bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat) { + if (IsBCTextureFormat(textureFormat) || IsETC2TextureFormat(textureFormat) || + IsASTCTextureFormat(textureFormat)) { + return false; + } + + switch (textureFormat) { + case wgpu::TextureFormat::R32Uint: + case wgpu::TextureFormat::R32Sint: + case wgpu::TextureFormat::RG32Uint: + case wgpu::TextureFormat::RG32Sint: + case wgpu::TextureFormat::RG32Float: + case wgpu::TextureFormat::RGBA32Uint: + case wgpu::TextureFormat::RGBA32Sint: + case wgpu::TextureFormat::RGBA32Float: + case wgpu::TextureFormat::RGB9E5Ufloat: + return false; + + default: + return true; + } + } + uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat) { switch (textureFormat) { case wgpu::TextureFormat::R8Unorm: diff --git a/src/dawn/utils/TextureUtils.h b/src/dawn/utils/TextureUtils.h index 092a637d6f..b75903b7e3 100644 --- a/src/dawn/utils/TextureUtils.h +++ b/src/dawn/utils/TextureUtils.h @@ -119,6 +119,29 @@ namespace utils { wgpu::TextureFormat::ASTC12x12Unorm, wgpu::TextureFormat::ASTC12x12UnormSrgb}; + static constexpr std::array kFormatsInCoreSpec = { + 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::RG11B10Ufloat, + wgpu::TextureFormat::RGB9E5Ufloat, 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::Depth16Unorm, wgpu::TextureFormat::Depth32Float, + wgpu::TextureFormat::Depth24Plus, wgpu::TextureFormat::Depth24PlusStencil8, + }; + static constexpr std::array kBCFormats = { wgpu::TextureFormat::BC1RGBAUnorm, wgpu::TextureFormat::BC1RGBAUnormSrgb, wgpu::TextureFormat::BC2RGBAUnorm, wgpu::TextureFormat::BC2RGBAUnormSrgb, @@ -208,6 +231,8 @@ namespace utils { bool IsDepthOnlyFormat(wgpu::TextureFormat textureFormat); + bool TextureFormatSupportsMultisampling(wgpu::TextureFormat textureFormat); + uint32_t GetTexelBlockSizeInBytes(wgpu::TextureFormat textureFormat); uint32_t GetTextureFormatBlockWidth(wgpu::TextureFormat textureFormat); uint32_t GetTextureFormatBlockHeight(wgpu::TextureFormat textureFormat);