Enable multisample and resolve for Snorm formats in TextureFormatsTier1
Add support for multisample and resolve capability on R8Snorm/RG8Snorm/RGBA8Snorm texture formats,
conditional on the texture-formats-tier1 feature being enabled. This commit also includes new unit
and end-to-end tests to confirm correct functionality of Snorm formats with multisample and resolve
under this feature.
Bug: 421941589
Change-Id: I98ab6a66d5b233c30c9aca9fd1d696e7a120c5ac
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/247255
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp
index d67a594..f399b5e 100644
--- a/src/dawn/native/Format.cpp
+++ b/src/dawn/native/Format.cpp
@@ -499,19 +499,23 @@
auto r8unormSupportsStorage = device->HasFeature(Feature::R8UnormStorage) ? Cap::StorageROrW : Cap::None;
auto r8snormSupportsRender = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Renderable : Cap::None;
auto r8snormSupportsBlend = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Blendable : Cap::None;
+ auto r8snormSupportsMultisample = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Multisample : Cap::None;
+ auto r8snormSupportsResolve = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Resolve : Cap::None;
AddColorFormat(wgpu::TextureFormat::R8Unorm, Cap::Renderable | Cap::Multisample | Cap::Resolve | r8unormSupportsStorage | Cap::Blendable, ByteSize(1), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(1), RenderTargetComponentAlignment(1));
- AddColorFormat(wgpu::TextureFormat::R8Snorm, r8snormSupportsRender | r8snormSupportsBlend, ByteSize(1), kAnyFloat, ComponentCount(1),RenderTargetPixelByteCost(1), RenderTargetComponentAlignment(1));
+ AddColorFormat(wgpu::TextureFormat::R8Snorm, r8snormSupportsRender | r8snormSupportsBlend | r8snormSupportsMultisample | r8snormSupportsResolve, ByteSize(1), kAnyFloat, ComponentCount(1),RenderTargetPixelByteCost(1), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::R8Uint, Cap::Renderable | intMultisampleCaps, ByteSize(1), SampleTypeBit::Uint, ComponentCount(1), RenderTargetPixelByteCost(1), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::R8Sint, Cap::Renderable | intMultisampleCaps, ByteSize(1), SampleTypeBit::Sint, ComponentCount(1), RenderTargetPixelByteCost(1), RenderTargetComponentAlignment(1));
// 2 bytes color formats
auto rg8snormSupportsRender = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Renderable : Cap::None;
auto rg8snormSupportsBlend = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Blendable : Cap::None;
+ auto rg8snormSupportsMultisample = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Multisample : Cap::None;
+ auto rg8snormSupportsResolve = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Resolve : Cap::None;
AddColorFormat(wgpu::TextureFormat::R16Uint, Cap::Renderable | intMultisampleCaps, ByteSize(2), SampleTypeBit::Uint, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
AddColorFormat(wgpu::TextureFormat::R16Sint, Cap::Renderable | intMultisampleCaps, ByteSize(2), SampleTypeBit::Sint, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
AddColorFormat(wgpu::TextureFormat::R16Float, Cap::Renderable | Cap::Multisample | Cap::Resolve | Cap::Blendable, ByteSize(2), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
AddColorFormat(wgpu::TextureFormat::RG8Unorm, Cap::Renderable | Cap::Multisample | Cap::Resolve | Cap::Blendable, ByteSize(2), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(1));
- AddColorFormat(wgpu::TextureFormat::RG8Snorm, rg8snormSupportsRender | rg8snormSupportsBlend, ByteSize(2), kAnyFloat, ComponentCount(2),RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
+ AddColorFormat(wgpu::TextureFormat::RG8Snorm, rg8snormSupportsRender | rg8snormSupportsBlend | rg8snormSupportsMultisample | rg8snormSupportsResolve, ByteSize(2), kAnyFloat, ComponentCount(2),RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
AddColorFormat(wgpu::TextureFormat::RG8Uint, Cap::Renderable | intMultisampleCaps, ByteSize(2), SampleTypeBit::Uint, ComponentCount(2), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::RG8Sint, Cap::Renderable | intMultisampleCaps, ByteSize(2), SampleTypeBit::Sint, ComponentCount(2), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(1));
@@ -523,6 +527,8 @@
auto r32FloatMultisampleCaps = device->IsCompatibilityMode() ? Cap::None : Cap::Multisample;
auto rgba8snormSupportsRender = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Renderable : Cap::None;
auto rgba8snormSupportsBlend = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Blendable : Cap::None;
+ auto rgba8snormSupportsMultisample = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Multisample : Cap::None;
+ auto rgba8snormSupportsResolve = device->HasFeature(Feature::TextureFormatsTier1) ? Cap::Resolve : Cap::None;
AddColorFormat(wgpu::TextureFormat::R32Uint, Cap::Renderable | Cap::StorageROrW | Cap::StorageRW | supportsPLS, ByteSize(4), SampleTypeBit::Uint, ComponentCount(1), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(4));
AddColorFormat(wgpu::TextureFormat::R32Sint, Cap::Renderable | Cap::StorageROrW | Cap::StorageRW | supportsPLS, ByteSize(4), SampleTypeBit::Sint, ComponentCount(1), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(4));
@@ -532,7 +538,7 @@
AddColorFormat(wgpu::TextureFormat::RG16Float, Cap::Renderable | Cap::Multisample | Cap::Resolve | Cap::Blendable, ByteSize(4), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(2));
AddColorFormat(wgpu::TextureFormat::RGBA8Unorm, Cap::Renderable | Cap::StorageROrW | Cap::Multisample | Cap::Resolve | Cap::Blendable, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::RGBA8UnormSrgb, Cap::Renderable | Cap::Multisample | Cap::Resolve | Cap::Blendable, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(1), wgpu::TextureFormat::RGBA8Unorm);
- AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, Cap::StorageROrW | rgba8snormSupportsRender | rgba8snormSupportsBlend, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(4));
+ AddColorFormat(wgpu::TextureFormat::RGBA8Snorm, Cap::StorageROrW | rgba8snormSupportsRender | rgba8snormSupportsBlend | rgba8snormSupportsMultisample | rgba8snormSupportsResolve, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(4));
AddColorFormat(wgpu::TextureFormat::RGBA8Uint, Cap::Renderable | Cap::StorageROrW | intMultisampleCaps, ByteSize(4), SampleTypeBit::Uint, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::RGBA8Sint, Cap::Renderable | Cap::StorageROrW | intMultisampleCaps, ByteSize(4), SampleTypeBit::Sint, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(1));
diff --git a/src/dawn/tests/end2end/TextureFormatsTier1Tests.cpp b/src/dawn/tests/end2end/TextureFormatsTier1Tests.cpp
index 36dd014..38c9f95 100644
--- a/src/dawn/tests/end2end/TextureFormatsTier1Tests.cpp
+++ b/src/dawn/tests/end2end/TextureFormatsTier1Tests.cpp
@@ -111,9 +111,7 @@
utils::ComboRenderPipelineDescriptor pipelineDesc;
pipelineDesc.vertex.module = shaderModule;
- pipelineDesc.vertex.entryPoint = "vs_main";
pipelineDesc.cFragment.module = shaderModule;
- pipelineDesc.cFragment.entryPoint = "fs_main";
pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
pipelineDesc.cFragment.targetCount = 1;
@@ -212,9 +210,7 @@
utils::ComboRenderPipelineDescriptor pipelineDesc;
pipelineDesc.vertex.module = shaderModule;
- pipelineDesc.vertex.entryPoint = "vs_main";
pipelineDesc.cFragment.module = shaderModule;
- pipelineDesc.cFragment.entryPoint = "fs_main";
pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
pipelineDesc.cFragment.targetCount = 1;
@@ -312,5 +308,116 @@
VulkanBackend(),
OpenGLBackend());
+class MultisampleResolveSnormFormatsTest : public TextureFormatsTier1Test {
+ protected:
+ static constexpr uint32_t kSize = 16;
+ static constexpr uint32_t kMultisampleCount = 4;
+ static constexpr uint32_t kSingleSampleCount = 1;
+ void RunMultisampleResolveTest(wgpu::TextureFormat format,
+ const std::vector<float>& expectedDrawColorFloats) {
+ DAWN_TEST_UNSUPPORTED_IF(!device.HasFeature(wgpu::FeatureName::TextureFormatsTier1));
+ std::string fsCode = GenerateFragmentShader(expectedDrawColorFloats);
+
+ wgpu::TextureDescriptor multisampleColorDesc;
+ multisampleColorDesc.usage = wgpu::TextureUsage::RenderAttachment;
+ multisampleColorDesc.dimension = wgpu::TextureDimension::e2D;
+ multisampleColorDesc.size = {kSize, kSize, 1};
+ multisampleColorDesc.format = format;
+ multisampleColorDesc.sampleCount = kMultisampleCount;
+
+ wgpu::Texture multisampleColorTexture = device.CreateTexture(&multisampleColorDesc);
+ wgpu::TextureView multisampleColorView = multisampleColorTexture.CreateView();
+
+ wgpu::TextureDescriptor resolveTargetDesc;
+ resolveTargetDesc.usage =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
+ resolveTargetDesc.dimension = wgpu::TextureDimension::e2D;
+ resolveTargetDesc.size = {kSize, kSize, 1};
+ resolveTargetDesc.format = format;
+ resolveTargetDesc.sampleCount = kSingleSampleCount;
+
+ wgpu::Texture resolveTargetTexture = device.CreateTexture(&resolveTargetDesc);
+ wgpu::TextureView resolveTargetView = resolveTargetTexture.CreateView();
+
+ std::string combinedShaderCode = GetFullScreenQuadVS() + fsCode;
+ wgpu::ShaderModule shaderModule =
+ utils::CreateShaderModule(device, combinedShaderCode.c_str());
+
+ utils::ComboRenderPipelineDescriptor pipelineDesc;
+ pipelineDesc.vertex.module = shaderModule;
+ pipelineDesc.cFragment.module = shaderModule;
+ pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
+ pipelineDesc.cFragment.targetCount = 1;
+ pipelineDesc.cTargets[0].format = format;
+ pipelineDesc.multisample.count = kMultisampleCount;
+
+ pipelineDesc.cTargets[0].writeMask = wgpu::ColorWriteMask::All;
+
+ wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDesc);
+
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ utils::ComboRenderPassDescriptor renderPass;
+ renderPass.cColorAttachments[0].view = multisampleColorView;
+ renderPass.cColorAttachments[0].resolveTarget = resolveTargetView;
+ renderPass.cColorAttachments[0].loadOp = wgpu::LoadOp::Clear;
+ renderPass.cColorAttachments[0].storeOp = wgpu::StoreOp::Store;
+ renderPass.cColorAttachments[0].clearValue = {0.0f, 0.0f, 0.0f, 0.0f};
+ renderPass.colorAttachmentCount = 1;
+
+ wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+ pass.SetPipeline(pipeline);
+ pass.Draw(3);
+ pass.End();
+
+ wgpu::CommandBuffer commands = encoder.Finish();
+ queue.Submit(1, &commands);
+
+ uint32_t componentCount = utils::GetTextureComponentCount(format);
+
+ std::vector<int8_t> expectedLowerBounds;
+ std::vector<int8_t> expectedUpperBounds;
+
+ for (uint32_t i = 0; i < componentCount; ++i) {
+ float floatComponent = expectedDrawColorFloats[i];
+ int8_t lowerSnormExpectation = ConvertFloatToSnorm8(floatComponent * 127.0f - 0.6f);
+ int8_t upperSnormExpectation = ConvertFloatToSnorm8(floatComponent * 127.0f + 0.6f);
+
+ expectedLowerBounds.push_back(lowerSnormExpectation);
+ expectedUpperBounds.push_back(upperSnormExpectation);
+ }
+
+ EXPECT_TEXTURE_SNORM_BETWEEN(expectedLowerBounds, expectedUpperBounds, resolveTargetTexture,
+ {0, 0}, {1, 1}, format);
+ }
+};
+
+// Test that r8snorm format has multisample and resolve capability
+// if 'texture-formats-tier1' is enabled.
+TEST_P(MultisampleResolveSnormFormatsTest, R8SnormMultisampleResolve) {
+ std::vector<float> expectedDrawColor = {1.0f, 0.0f, 0.0f, 1.0f};
+ RunMultisampleResolveTest(wgpu::TextureFormat::R8Snorm, expectedDrawColor);
+}
+
+// Test that rg8snorm format has multisample and resolve capability
+// if 'texture-formats-tier1' is enabled.
+TEST_P(MultisampleResolveSnormFormatsTest, RG8SnormMultisampleResolve) {
+ std::vector<float> expectedDrawColor = {1.0f, -0.5f, 0.0f, 1.0f};
+ RunMultisampleResolveTest(wgpu::TextureFormat::RG8Snorm, expectedDrawColor);
+}
+
+// Test that rgba8snorm format has multisample and resolve capability
+// if 'texture-formats-tier1' is enabled.
+TEST_P(MultisampleResolveSnormFormatsTest, RGBA8SnormMultisampleResolve) {
+ std::vector<float> expectedDrawColor = {1.0f, -0.5f, -1.0f, 0.5f};
+ RunMultisampleResolveTest(wgpu::TextureFormat::RGBA8Snorm, expectedDrawColor);
+}
+
+DAWN_INSTANTIATE_TEST(MultisampleResolveSnormFormatsTest,
+ D3D11Backend(),
+ D3D12Backend(),
+ MetalBackend(),
+ VulkanBackend(),
+ OpenGLBackend());
+
} // anonymous namespace
} // namespace dawn
diff --git a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
index 95ef147..6dba385 100644
--- a/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp
@@ -737,6 +737,41 @@
AssertBeginRenderPassError(&renderPass);
}
+class TextureFormatsTier1RenderPassTest : public RenderPassDescriptorValidationTest {
+ protected:
+ std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+ return {wgpu::FeatureName::TextureFormatsTier1};
+ }
+};
+
+// Tests that R8Snorm, RG8Snorm, and RGBA8Snorm color attachments support multisampling and resolve
+// targets when TextureFormatsTier1 is enabled.
+TEST_F(TextureFormatsTier1RenderPassTest, MultisampledColorWithResolveTarget) {
+ const std::array kTestFormats = {wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::RG8Snorm,
+ wgpu::TextureFormat::RGBA8Snorm};
+ for (const auto format : kTestFormats) {
+ static constexpr uint32_t kArrayLayers = 1;
+ static constexpr uint32_t kLevelCount = 1;
+ static constexpr uint32_t kSize = 32;
+ static constexpr uint32_t kMultiSampleCount = 4;
+ static constexpr uint32_t kSingleSampleCount = 1;
+ wgpu::TextureFormat kColorFormat = format;
+
+ wgpu::Texture colorTexture =
+ CreateTexture(device, wgpu::TextureDimension::e2D, kColorFormat, kSize, kSize,
+ kArrayLayers, kLevelCount, kMultiSampleCount);
+ wgpu::Texture resolveTargetTexture =
+ CreateTexture(device, wgpu::TextureDimension::e2D, kColorFormat, kSize, kSize,
+ kArrayLayers, kLevelCount, kSingleSampleCount);
+ wgpu::TextureView colorTextureView = colorTexture.CreateView();
+ wgpu::TextureView resolveTargetTextureView = resolveTargetTexture.CreateView();
+
+ utils::ComboRenderPassDescriptor renderPass({colorTextureView});
+ renderPass.cColorAttachments[0].resolveTarget = resolveTargetTextureView;
+ AssertBeginRenderPassSuccess(&renderPass);
+ }
+}
+
// drawCount must not exceed maxDrawCount
TEST_F(RenderPassDescriptorValidationTest, MaxDrawCount) {
constexpr wgpu::TextureFormat kColorFormat = wgpu::TextureFormat::RGBA8Unorm;
diff --git a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
index bb81171..00d062e 100644
--- a/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/RenderPipelineValidationTests.cpp
@@ -3610,5 +3610,20 @@
}
}
+// Tests that R8Snorm, RG8Snorm, and RGBA8Snorm must support multisampling
+// when the TextureFormatsTier1 feature is enabled.
+TEST_F(TextureFormatsTier1PipelineTest, SNORMFormatsMultisampleSupportWithTier1) {
+ const std::array kTestFormats = {wgpu::TextureFormat::R8Snorm, wgpu::TextureFormat::RG8Snorm,
+ wgpu::TextureFormat::RGBA8Snorm};
+ for (const auto format : kTestFormats) {
+ utils::ComboRenderPipelineDescriptor descriptor;
+ descriptor.vertex.module = vsModule;
+ descriptor.cFragment.module = fsModule;
+ descriptor.cTargets[0].format = format;
+ descriptor.multisample.count = 4;
+ device.CreateRenderPipeline(&descriptor);
+ }
+}
+
} // anonymous namespace
} // namespace dawn