Implement "rg11b10ufloat-renderable" feature
Implement "rg11b10ufloat-renderable" feature that allows
the RENDER_ATTACHMENT usage on textures with format
"rg11b10ufloat", and also allows textures of that format
to be multisampled.
Bug: dawn:1518
Change-Id: I4109dc0e9d90f4c0803219292edea554927a187a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/102000
Commit-Queue: Takahiro <hogehoge@gachapin.jp>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index 2f0fcb3..d8f8a34 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1386,6 +1386,7 @@
{"value": 7, "name": "texture compression ASTC"},
{"value": 8, "name": "indirect first instance"},
{"value": 9, "name": "shader f16"},
+ {"value": 10, "name": "RG11B10 ufloat renderable"},
{"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]},
{"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]},
{"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]},
diff --git a/src/dawn/native/Features.cpp b/src/dawn/native/Features.cpp
index 4589f1c..c7d00b7 100644
--- a/src/dawn/native/Features.cpp
+++ b/src/dawn/native/Features.cpp
@@ -68,6 +68,11 @@
{"shader-f16", "Supports the \"enable f16;\" directive in WGSL",
"https://bugs.chromium.org/p/dawn/issues/detail?id=1510",
FeatureInfo::FeatureState::Experimental}},
+ {Feature::RG11B10UfloatRenderable,
+ {"rg11b10ufloat-renderable",
+ "Allows the RENDER_ATTACHMENT usage on textures with format \"rg11b10ufloat\", and also "
+ "allows textures of that format to be multisampled.",
+ "https://bugs.chromium.org/p/dawn/issues/detail?id=1518", FeatureInfo::FeatureState::Stable}},
{Feature::DawnInternalUsages,
{"dawn-internal-usages",
"Add internal usages to resources to affect how the texture is allocated, but not "
@@ -119,6 +124,8 @@
return Feature::ChromiumExperimentalDp4a;
case wgpu::FeatureName::ShaderF16:
return Feature::ShaderF16;
+ case wgpu::FeatureName::RG11B10UfloatRenderable:
+ return Feature::RG11B10UfloatRenderable;
}
return Feature::InvalidEnum;
}
@@ -151,6 +158,8 @@
return wgpu::FeatureName::ChromiumExperimentalDp4a;
case Feature::ShaderF16:
return wgpu::FeatureName::ShaderF16;
+ case Feature::RG11B10UfloatRenderable:
+ return wgpu::FeatureName::RG11B10UfloatRenderable;
case Feature::EnumCount:
break;
diff --git a/src/dawn/native/Features.h b/src/dawn/native/Features.h
index 9413da6..4bcb93a 100644
--- a/src/dawn/native/Features.h
+++ b/src/dawn/native/Features.h
@@ -37,6 +37,7 @@
ChromiumExperimentalDp4a,
IndirectFirstInstance,
ShaderF16,
+ RG11B10UfloatRenderable,
// Dawn-specific
DawnInternalUsages,
diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp
index ef9a7d2..fdfe477 100644
--- a/src/dawn/native/Format.cpp
+++ b/src/dawn/native/Format.cpp
@@ -363,7 +363,8 @@
AddColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, true, false, true, true, 4, kAnyFloat, 4, wgpu::TextureFormat::BGRA8Unorm);
AddColorFormat(wgpu::TextureFormat::RGB10A2Unorm, true, false, true, true, 4, kAnyFloat, 4);
- AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, false, false, false, false, 4, kAnyFloat, 3);
+ bool isRG11B10UfloatRenderable = device->HasFeature(Feature::RG11B10UfloatRenderable);
+ AddColorFormat(wgpu::TextureFormat::RG11B10Ufloat, isRG11B10UfloatRenderable, false, isRG11B10UfloatRenderable, false, 4, kAnyFloat, 3);
AddColorFormat(wgpu::TextureFormat::RGB9E5Ufloat, false, false, false, false, 4, kAnyFloat, 3);
// 8 bytes color formats
diff --git a/src/dawn/native/d3d12/AdapterD3D12.cpp b/src/dawn/native/d3d12/AdapterD3D12.cpp
index bcd40fc..842e49e 100644
--- a/src/dawn/native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn/native/d3d12/AdapterD3D12.cpp
@@ -137,6 +137,7 @@
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance);
+ mSupportedFeatures.EnableFeature(Feature::RG11B10UfloatRenderable);
if (GetBackend()->GetFunctions()->IsDXCAvailable()) {
uint64_t dxcVersion = 0;
diff --git a/src/dawn/native/metal/BackendMTL.mm b/src/dawn/native/metal/BackendMTL.mm
index 9d56480..76dbce8 100644
--- a/src/dawn/native/metal/BackendMTL.mm
+++ b/src/dawn/native/metal/BackendMTL.mm
@@ -370,8 +370,8 @@
}
mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance);
-
mSupportedFeatures.EnableFeature(Feature::ShaderF16);
+ mSupportedFeatures.EnableFeature(Feature::RG11B10UfloatRenderable);
return {};
}
diff --git a/src/dawn/native/vulkan/AdapterVk.cpp b/src/dawn/native/vulkan/AdapterVk.cpp
index ab0342b..883f9d3 100644
--- a/src/dawn/native/vulkan/AdapterVk.cpp
+++ b/src/dawn/native/vulkan/AdapterVk.cpp
@@ -181,6 +181,16 @@
mSupportedFeatures.EnableFeature(Feature::DepthClipControl);
}
+ VkFormatProperties properties;
+ mVulkanInstance->GetFunctions().GetPhysicalDeviceFormatProperties(
+ mPhysicalDevice, VK_FORMAT_B10G11R11_UFLOAT_PACK32, &properties);
+
+ if (IsSubset(static_cast<VkFormatFeatureFlags>(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
+ VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT),
+ properties.optimalTilingFeatures)) {
+ mSupportedFeatures.EnableFeature(Feature::RG11B10UfloatRenderable);
+ }
+
#if defined(DAWN_USE_SYNC_FDS)
// TODO(chromium:1258986): Precisely enable the feature by querying the device's format
// features.
diff --git a/src/dawn/tests/end2end/TextureFormatTests.cpp b/src/dawn/tests/end2end/TextureFormatTests.cpp
index c0e9a31..34c841d 100644
--- a/src/dawn/tests/end2end/TextureFormatTests.cpp
+++ b/src/dawn/tests/end2end/TextureFormatTests.cpp
@@ -111,6 +111,83 @@
std::vector<uint16_t> mExpected;
};
+// An expectation for RG11B10Ufloat buffer content that can correctly compare different NaN values
+class ExpectRG11B10Ufloat : public detail::Expectation {
+ public:
+ explicit ExpectRG11B10Ufloat(std::vector<uint32_t> expected) : mExpected(std::move(expected)) {}
+
+ testing::AssertionResult Check(const void* data, size_t size) override {
+ ASSERT(size == sizeof(uint32_t) * mExpected.size());
+
+ const uint32_t* actual = static_cast<const uint32_t*>(data);
+
+ for (size_t i = 0; i < mExpected.size(); ++i) {
+ uint32_t expectedValue = mExpected[i];
+ uint32_t actualValue = actual[i];
+
+ if (!RG11B10UfloatMatch(expectedValue, actualValue)) {
+ testing::AssertionResult result = testing::AssertionFailure()
+ << "Expected data[" << i << "] to be "
+ << expectedValue << ", actual " << actualValue
+ << std::endl;
+ return result;
+ }
+ }
+ return testing::AssertionSuccess();
+ }
+
+ private:
+ bool RG11B10UfloatMatch(uint32_t expected, uint32_t actual) {
+ const uint32_t expectedR = expected & 0x7FF;
+ const uint32_t expectedG = (expected >> 11) & 0x7FF;
+ const uint32_t expectedB = (expected >> 22) & 0x3FF;
+
+ const uint32_t actualR = actual & 0x7FF;
+ const uint32_t actualG = (actual >> 11) & 0x7FF;
+ const uint32_t actualB = (actual >> 22) & 0x3FF;
+
+ return Float11Match(expectedR, actualR) && Float11Match(expectedG, actualG) &&
+ Float10Match(expectedB, actualB);
+ }
+
+ bool Float11Match(uint32_t expected, uint32_t actual) {
+ ASSERT((expected & ~0x7FF) == 0);
+ ASSERT((actual & ~0x7FF) == 0);
+
+ if (IsFloat11NaN(expected)) {
+ return IsFloat11NaN(actual);
+ }
+
+ return expected == actual;
+ }
+
+ bool Float10Match(uint32_t expected, uint32_t actual) {
+ ASSERT((expected & ~0x3FF) == 0);
+ ASSERT((actual & ~0x3FF) == 0);
+
+ if (IsFloat10NaN(expected)) {
+ return IsFloat10NaN(actual);
+ }
+
+ return expected == actual;
+ }
+
+ // The number is NaN if exponent bits are all 1 and mantissa is non-zero
+ bool IsFloat11NaN(uint32_t value) {
+ ASSERT((value & ~0x7FF) == 0);
+
+ return ((value & 0x7C0) == 0x7C0) && ((value & 0x3F) != 0);
+ }
+
+ bool IsFloat10NaN(uint32_t value) {
+ ASSERT((value & ~0x3FF) == 0);
+
+ return ((value & 0x3E0) == 0x3E0) && ((value & 0x1F) != 0);
+ }
+
+ std::vector<uint32_t> mExpected;
+};
+
class TextureFormatTest : public DawnTest {
protected:
// Structure containing all the information that tests need to know about the format.
@@ -436,6 +513,22 @@
DoFormatRenderingTest(formatInfo, uncompressedData, textureData,
new ExpectFloat16(textureData));
}
+
+ // For "rg11b10ufloat-renderable" feature test
+ std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+ if (SupportsFeatures({wgpu::FeatureName::RG11B10UfloatRenderable})) {
+ mIsRG11B10UfloatRenderableSupported = true;
+ return {wgpu::FeatureName::RG11B10UfloatRenderable};
+ } else {
+ mIsRG11B10UfloatRenderableSupported = false;
+ return {};
+ }
+ }
+
+ bool IsRG11B10UfloatRenderableSupported() { return mIsRG11B10UfloatRenderableSupported; }
+
+ private:
+ bool mIsRG11B10UfloatRenderableSupported = false;
};
// Test the R8Unorm format
@@ -740,7 +833,20 @@
DoFloatFormatSamplingTest(
{wgpu::TextureFormat::RG11B10Ufloat, 4, wgpu::TextureComponentType::Float, 4}, textureData,
uncompressedData);
- // This format is not renderable.
+
+ // This format is renderable if "rg11b10ufloat-renderable" feature is enabled
+ if (IsRG11B10UfloatRenderableSupported()) {
+ // TODO(https://crbug.com/swiftshader/147) Rendering INFINITY and NaN isn't handled
+ // correctly by swiftshader
+ if ((IsVulkan() && IsSwiftshader()) || IsANGLE()) {
+ dawn::WarningLog() << "Skip Rendering test because Swiftshader doesn't render INFINITY "
+ "and NaN correctly for RG11B10Ufloat texture format.";
+ } else {
+ DoFormatRenderingTest(
+ {wgpu::TextureFormat::RG11B10Ufloat, 4, wgpu::TextureComponentType::Float, 4},
+ uncompressedData, textureData, new ExpectRG11B10Ufloat(textureData));
+ }
+ }
}
// Test the RGB9E5Ufloat format
diff --git a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
index d40fce4..9708ef4 100644
--- a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
@@ -885,6 +885,29 @@
}
}
+class RG11B10UfloatTextureFormatsValidationTests : public TextureValidationTest {
+ protected:
+ WGPUDevice CreateTestDevice(dawn::native::Adapter dawnAdapter) override {
+ wgpu::DeviceDescriptor descriptor;
+ wgpu::FeatureName requiredFeatures[1] = {wgpu::FeatureName::RG11B10UfloatRenderable};
+ descriptor.requiredFeatures = requiredFeatures;
+ descriptor.requiredFeaturesCount = 1;
+ return dawnAdapter.CreateDevice(&descriptor);
+ }
+};
+
+// Test that RG11B10Ufloat format is valid as render attachment and also it allows
+// multisampling if "rg11b10ufloat-renderable" feature is enabled
+TEST_F(RG11B10UfloatTextureFormatsValidationTests, RenderableFeature) {
+ wgpu::TextureDescriptor descriptor;
+ descriptor.size = {1, 1, 1};
+ descriptor.usage = wgpu::TextureUsage::RenderAttachment;
+
+ descriptor.format = wgpu::TextureFormat::RG11B10Ufloat;
+ descriptor.sampleCount = 4;
+ device.CreateTexture(&descriptor);
+}
+
static void CheckTextureMatchesDescriptor(const wgpu::Texture& tex,
const wgpu::TextureDescriptor& desc) {
EXPECT_EQ(desc.size.width, tex.GetWidth());
diff --git a/src/dawn/wire/SupportedFeatures.cpp b/src/dawn/wire/SupportedFeatures.cpp
index 6358405..59ab14f 100644
--- a/src/dawn/wire/SupportedFeatures.cpp
+++ b/src/dawn/wire/SupportedFeatures.cpp
@@ -37,6 +37,7 @@
case WGPUFeatureName_DawnMultiPlanarFormats:
case WGPUFeatureName_ChromiumExperimentalDp4a:
case WGPUFeatureName_ShaderF16:
+ case WGPUFeatureName_RG11B10UfloatRenderable:
return true;
}