Fix Norm16 formats being available without the extension.
This changes SharedTextureMemoryTests to request the extension, but also
skip over creating the backing SharedTextureMemory if the format isn't
supported.
Bug: dawn:1982
Change-Id: I1d1955b2f40bc62dd99f6c9d738e8c6f4efc943d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/161685
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp
index 3718433..5ec9cc4 100644
--- a/src/dawn/native/Format.cpp
+++ b/src/dawn/native/Format.cpp
@@ -480,13 +480,13 @@
AddColorFormat(wgpu::TextureFormat::RGBA32Float, Cap::Renderable | Cap::StorageW, ByteSize(16), sampleTypeFor32BitFloatFormats, ComponentCount(4), RenderTargetPixelByteCost(16), RenderTargetComponentAlignment(4));
// Norm16 color formats
- auto norm16Capabilities = device->HasFeature(Feature::Norm16TextureFormats) ? Cap::Renderable | Cap::Multisample | Cap::Resolve : Cap::None;
- AddColorFormat(wgpu::TextureFormat::R16Unorm, norm16Capabilities, ByteSize(2), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
- AddColorFormat(wgpu::TextureFormat::RG16Unorm, norm16Capabilities, ByteSize(4), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(2));
- AddColorFormat(wgpu::TextureFormat::RGBA16Unorm, norm16Capabilities, ByteSize(8), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(2));
- AddColorFormat(wgpu::TextureFormat::R16Snorm, norm16Capabilities, ByteSize(2), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
- AddColorFormat(wgpu::TextureFormat::RG16Snorm, norm16Capabilities, ByteSize(4), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(2));
- AddColorFormat(wgpu::TextureFormat::RGBA16Snorm, norm16Capabilities, ByteSize(8), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(2));
+ auto norm16Supported = device->HasFeature(Feature::Norm16TextureFormats) ? Format::supported : RequiresFeature{wgpu::FeatureName::Norm16TextureFormats};
+ AddConditionalColorFormat(wgpu::TextureFormat::R16Unorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(2), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
+ AddConditionalColorFormat(wgpu::TextureFormat::RG16Unorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(4), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(2));
+ AddConditionalColorFormat(wgpu::TextureFormat::RGBA16Unorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(8), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(2));
+ AddConditionalColorFormat(wgpu::TextureFormat::R16Snorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(2), kAnyFloat, ComponentCount(1), RenderTargetPixelByteCost(2), RenderTargetComponentAlignment(2));
+ AddConditionalColorFormat(wgpu::TextureFormat::RG16Snorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(4), kAnyFloat, ComponentCount(2), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(2));
+ AddConditionalColorFormat(wgpu::TextureFormat::RGBA16Snorm, norm16Supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(8), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(2));
// Depth-stencil formats
AddStencilFormat(wgpu::TextureFormat::Stencil8, Format::supported);
diff --git a/src/dawn/tests/end2end/SharedTextureMemoryTests.cpp b/src/dawn/tests/end2end/SharedTextureMemoryTests.cpp
index 5d6dd99..77dbf8e 100644
--- a/src/dawn/tests/end2end/SharedTextureMemoryTests.cpp
+++ b/src/dawn/tests/end2end/SharedTextureMemoryTests.cpp
@@ -40,7 +40,7 @@
}
std::vector<wgpu::FeatureName> SharedTextureMemoryTests::GetRequiredFeatures() {
- auto features = GetParam().mBackend->RequiredFeatures();
+ auto features = GetParam().mBackend->RequiredFeatures(GetAdapter().Get());
if (!SupportsFeatures(features)) {
return {};
}
@@ -49,6 +49,7 @@
wgpu::FeatureName::MultiPlanarFormatExtendedUsages,
wgpu::FeatureName::MultiPlanarRenderTargets,
wgpu::FeatureName::TransientAttachments,
+ wgpu::FeatureName::Norm16TextureFormats,
};
for (auto feature : kOptionalFeatures) {
if (SupportsFeatures({feature})) {
@@ -62,7 +63,8 @@
void SharedTextureMemoryTests::SetUp() {
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
DawnTestWithParams<SharedTextureMemoryTestParams>::SetUp();
- DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures(GetParam().mBackend->RequiredFeatures()));
+ DAWN_TEST_UNSUPPORTED_IF(
+ !SupportsFeatures(GetParam().mBackend->RequiredFeatures(GetAdapter().Get())));
}
std::vector<wgpu::SharedTextureMemory> SharedTextureMemoryTestBackend::CreateSharedTextureMemories(
@@ -305,6 +307,7 @@
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kYellow, colorTarget, br, {1, 1});
break;
case wgpu::TextureFormat::RG16Float:
+ case wgpu::TextureFormat::RG16Unorm:
case wgpu::TextureFormat::RG8Unorm:
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kGreen, colorTarget, tl, {1, 1});
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kRed, colorTarget, bl, {1, 1});
@@ -312,6 +315,7 @@
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kYellow, colorTarget, br, {1, 1});
break;
case wgpu::TextureFormat::R16Float:
+ case wgpu::TextureFormat::R16Unorm:
case wgpu::TextureFormat::R8Unorm:
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kBlack, colorTarget, tl, {1, 1});
EXPECT_TEXTURE_EQ(deviceObj, &utils::RGBA8::kRed, colorTarget, bl, {1, 1});
diff --git a/src/dawn/tests/end2end/SharedTextureMemoryTests.h b/src/dawn/tests/end2end/SharedTextureMemoryTests.h
index 340e75e..c46d628 100644
--- a/src/dawn/tests/end2end/SharedTextureMemoryTests.h
+++ b/src/dawn/tests/end2end/SharedTextureMemoryTests.h
@@ -43,10 +43,10 @@
virtual std::string Name() const = 0;
// The required features for testing this backend.
- virtual std::vector<wgpu::FeatureName> RequiredFeatures() const = 0;
+ virtual std::vector<wgpu::FeatureName> RequiredFeatures(const wgpu::Adapter& device) const = 0;
// Create one basic shared texture memory. It should support most operations.
- virtual wgpu::SharedTextureMemory CreateSharedTextureMemory(wgpu::Device& device) = 0;
+ virtual wgpu::SharedTextureMemory CreateSharedTextureMemory(const wgpu::Device& device) = 0;
// Create a variety of valid SharedTextureMemory for testing, one on each device.
// Backends should return all interesting types of shared texture memory here, including
diff --git a/src/dawn/tests/end2end/SharedTextureMemoryTests_apple.mm b/src/dawn/tests/end2end/SharedTextureMemoryTests_apple.mm
index 51caf7c..25c375e 100644
--- a/src/dawn/tests/end2end/SharedTextureMemoryTests_apple.mm
+++ b/src/dawn/tests/end2end/SharedTextureMemoryTests_apple.mm
@@ -53,15 +53,20 @@
std::string Name() const override { return "IOSurface"; }
- std::vector<wgpu::FeatureName> RequiredFeatures() const override {
- return {wgpu::FeatureName::SharedTextureMemoryIOSurface,
- wgpu::FeatureName::SharedFenceMTLSharedEvent,
- wgpu::FeatureName::DawnMultiPlanarFormats,
- wgpu::FeatureName::MultiPlanarFormatNv12a};
+ std::vector<wgpu::FeatureName> RequiredFeatures(const wgpu::Adapter& device) const override {
+ std::vector<wgpu::FeatureName> features = {wgpu::FeatureName::SharedTextureMemoryIOSurface,
+ wgpu::FeatureName::SharedFenceMTLSharedEvent,
+ wgpu::FeatureName::DawnMultiPlanarFormats};
+
+ if (device.HasFeature(wgpu::FeatureName::MultiPlanarFormatNv12a)) {
+ features.push_back(wgpu::FeatureName::MultiPlanarFormatNv12a);
+ }
+
+ return features;
}
// Create one basic shared texture memory. It should support most operations.
- wgpu::SharedTextureMemory CreateSharedTextureMemory(wgpu::Device& device) override {
+ wgpu::SharedTextureMemory CreateSharedTextureMemory(const wgpu::Device& device) override {
auto dict = AcquireCFRef(CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
@@ -82,30 +87,39 @@
std::vector<std::vector<wgpu::SharedTextureMemory>> CreatePerDeviceSharedTextureMemories(
const std::vector<wgpu::Device>& devices) override {
std::vector<std::vector<wgpu::SharedTextureMemory>> memories;
- for (auto [format, bytesPerElement] : {
- std::make_pair(kCVPixelFormatType_64RGBAHalf, 8),
- std::make_pair(kCVPixelFormatType_TwoComponent16Half, 4),
- std::make_pair(kCVPixelFormatType_OneComponent16Half, 2),
- std::make_pair(kCVPixelFormatType_TwoComponent16, 4),
- std::make_pair(kCVPixelFormatType_OneComponent16, 2),
- std::make_pair(kCVPixelFormatType_ARGB2101010LEPacked, 4),
- std::make_pair(kCVPixelFormatType_32RGBA, 4),
- std::make_pair(kCVPixelFormatType_32BGRA, 4),
- std::make_pair(kCVPixelFormatType_TwoComponent8, 2),
- std::make_pair(kCVPixelFormatType_OneComponent8, 1),
- // Below bytes per element isn't correct.
- std::make_pair(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, 4),
- std::make_pair(kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar, 4),
- // TODO(dawn:551): Add R10X6BG10X6Biplanar420Unorm support.
- }) {
+
+ struct IOSurfaceFormat {
+ uint32_t format;
+ uint32_t bytesPerElement;
+ wgpu::FeatureName requiredFeature = wgpu::FeatureName::Undefined;
+ };
+ const std::array<IOSurfaceFormat, 12> kFormats{{
+ {kCVPixelFormatType_64RGBAHalf, 8},
+ {kCVPixelFormatType_TwoComponent16Half, 4},
+ {kCVPixelFormatType_OneComponent16Half, 2},
+ {kCVPixelFormatType_TwoComponent16, 4, wgpu::FeatureName::Norm16TextureFormats},
+ {kCVPixelFormatType_OneComponent16, 2, wgpu::FeatureName::Norm16TextureFormats},
+ {kCVPixelFormatType_ARGB2101010LEPacked, 4},
+ {kCVPixelFormatType_32RGBA, 4},
+ {kCVPixelFormatType_32BGRA, 4},
+ {kCVPixelFormatType_TwoComponent8, 2},
+ {kCVPixelFormatType_OneComponent8, 1},
+ // Below bytes per element isn't correct.
+ {kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, 4},
+ {kCVPixelFormatType_420YpCbCr8VideoRange_8A_TriPlanar, 4,
+ wgpu::FeatureName::MultiPlanarFormatNv12a},
+ // TODO(dawn:551): Add R10X6BG10X6Biplanar420Unorm support.
+ }};
+
+ for (auto f : kFormats) {
for (uint32_t size : {4, 64}) {
auto dict = AcquireCFRef(CFDictionaryCreateMutable(
kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks));
AddIntegerValue(dict.Get(), kIOSurfaceWidth, size);
AddIntegerValue(dict.Get(), kIOSurfaceHeight, size);
- AddIntegerValue(dict.Get(), kIOSurfacePixelFormat, format);
- AddIntegerValue(dict.Get(), kIOSurfaceBytesPerElement, bytesPerElement);
+ AddIntegerValue(dict.Get(), kIOSurfacePixelFormat, f.format);
+ AddIntegerValue(dict.Get(), kIOSurfaceBytesPerElement, f.bytesPerElement);
wgpu::SharedTextureMemoryIOSurfaceDescriptor ioSurfaceDesc;
ioSurfaceDesc.ioSurface = IOSurfaceCreate(dict.Get());
@@ -113,7 +127,7 @@
// Internally, the CV enums are defined as their fourcc values. Cast to that and use
// it as the label. The fourcc value is a four-character name that can be
// interpreted as a 32-bit integer enum ('ABGR', 'r011', etc.)
- std::string label = std::string(reinterpret_cast<char*>(&format), 4) + " " +
+ std::string label = std::string(reinterpret_cast<char*>(&f.format), 4) + " " +
std::to_string(size) + "x" + std::to_string(size);
wgpu::SharedTextureMemoryDescriptor desc;
desc.label = label.c_str();
@@ -121,9 +135,17 @@
std::vector<wgpu::SharedTextureMemory> perDeviceMemories;
for (auto& device : devices) {
+ if (f.requiredFeature != wgpu::FeatureName::Undefined &&
+ !device.HasFeature(f.requiredFeature)) {
+ continue;
+ }
+
perDeviceMemories.push_back(device.ImportSharedTextureMemory(&desc));
}
- memories.push_back(std::move(perDeviceMemories));
+
+ if (!perDeviceMemories.empty()) {
+ memories.push_back(std::move(perDeviceMemories));
+ }
}
}
diff --git a/src/dawn/tests/end2end/SharedTextureMemoryTests_win.cpp b/src/dawn/tests/end2end/SharedTextureMemoryTests_win.cpp
index 7c73eaf..051d53a 100644
--- a/src/dawn/tests/end2end/SharedTextureMemoryTests_win.cpp
+++ b/src/dawn/tests/end2end/SharedTextureMemoryTests_win.cpp
@@ -77,7 +77,7 @@
bool UseSameDevice() const override { return mMode == Mode::D3D11Texture2D; }
bool SupportsConcurrentRead() const override { return !mUseKeyedMutex; }
- std::vector<wgpu::FeatureName> RequiredFeatures() const override {
+ std::vector<wgpu::FeatureName> RequiredFeatures(const wgpu::Adapter& adapter) const override {
switch (mMode) {
case Mode::D3D11Texture2D: {
return {wgpu::FeatureName::SharedTextureMemoryD3D11Texture2D,
@@ -121,7 +121,7 @@
}
// Create one basic shared texture memory. It should support most operations.
- wgpu::SharedTextureMemory CreateSharedTextureMemory(wgpu::Device& device) override {
+ wgpu::SharedTextureMemory CreateSharedTextureMemory(const wgpu::Device& device) override {
ComPtr<ID3D11Device> d3d11Device = MakeD3D11Device(device);
// Create a DX11 texture with data then wrap it in a shared handle.
@@ -200,18 +200,28 @@
}
}
- std::vector<DXGI_FORMAT> formats = {
- DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R16G16_FLOAT,
- DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R8G8B8A8_UNORM,
- DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM,
- DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8_UNORM,
+ struct D3DFormat {
+ DXGI_FORMAT format;
+ wgpu::FeatureName requiredFeature = wgpu::FeatureName::Undefined;
};
+ std::vector<D3DFormat> formats = {{
+ {DXGI_FORMAT_R16G16B16A16_FLOAT},
+ {DXGI_FORMAT_R16G16_FLOAT},
+ {DXGI_FORMAT_R16_FLOAT},
+ {DXGI_FORMAT_R8G8B8A8_UNORM},
+ {DXGI_FORMAT_B8G8R8A8_UNORM},
+ {DXGI_FORMAT_R10G10B10A2_UNORM},
+ {DXGI_FORMAT_R16G16_UNORM, wgpu::FeatureName::Norm16TextureFormats},
+ {DXGI_FORMAT_R16_UNORM, wgpu::FeatureName::Norm16TextureFormats},
+ {DXGI_FORMAT_R8G8_UNORM},
+ {DXGI_FORMAT_R8_UNORM},
+ }};
if (supportsNV12Sharing) {
- formats.push_back(DXGI_FORMAT_NV12);
+ formats.push_back({DXGI_FORMAT_NV12});
}
- for (DXGI_FORMAT format : formats) {
+ for (auto f : formats) {
for (uint32_t size : {4, 64}) {
// Create a DX11 texture with data then wrap it in a shared handle.
D3D11_TEXTURE2D_DESC d3dDescriptor;
@@ -219,7 +229,7 @@
d3dDescriptor.Height = size;
d3dDescriptor.MipLevels = 1;
d3dDescriptor.ArraySize = 1;
- d3dDescriptor.Format = format;
+ d3dDescriptor.Format = f.format;
d3dDescriptor.SampleDesc.Count = 1;
d3dDescriptor.SampleDesc.Quality = 0;
d3dDescriptor.Usage = D3D11_USAGE_DEFAULT;
@@ -233,6 +243,7 @@
ComPtr<ID3D11Texture2D> d3d11Texture;
HRESULT hr = d3d11Device->CreateTexture2D(&d3dDescriptor, nullptr, &d3d11Texture);
+ std::vector<wgpu::SharedTextureMemory> perDeviceMemories;
switch (mMode) {
case Mode::D3D11Texture2D: {
native::d3d11::SharedTextureMemoryD3D11Texture2DDescriptor texture2DDesc;
@@ -241,11 +252,14 @@
wgpu::SharedTextureMemoryDescriptor desc;
desc.nextInChain = &texture2DDesc;
- std::vector<wgpu::SharedTextureMemory> perDeviceMemories;
for (auto& device : devices) {
+ if (f.requiredFeature != wgpu::FeatureName::Undefined &&
+ !device.HasFeature(f.requiredFeature)) {
+ continue;
+ }
+
perDeviceMemories.push_back(device.ImportSharedTextureMemory(&desc));
}
- memories.push_back(std::move(perDeviceMemories));
break;
}
case Mode::DXGISharedHandle: {
@@ -262,22 +276,28 @@
wgpu::SharedTextureMemoryDXGISharedHandleDescriptor sharedHandleDesc;
sharedHandleDesc.handle = sharedHandle;
- std::string label = LabelName(format, size);
+ std::string label = LabelName(f.format, size);
wgpu::SharedTextureMemoryDescriptor desc;
desc.nextInChain = &sharedHandleDesc;
desc.label = label.c_str();
- std::vector<wgpu::SharedTextureMemory> perDeviceMemories;
for (auto& device : devices) {
+ if (f.requiredFeature != wgpu::FeatureName::Undefined &&
+ !device.HasFeature(f.requiredFeature)) {
+ continue;
+ }
+
perDeviceMemories.push_back(device.ImportSharedTextureMemory(&desc));
}
- memories.push_back(std::move(perDeviceMemories));
::CloseHandle(sharedHandle);
break;
}
}
+ if (!perDeviceMemories.empty()) {
+ memories.push_back(std::move(perDeviceMemories));
+ }
}
}
return memories;
diff --git a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
index 8d8827a..c16cf8f 100644
--- a/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/TextureValidationTests.cpp
@@ -971,6 +971,32 @@
device.CreateTexture(&descriptor);
}
+// Test that the Norm16 formats are not available even for just TextureBinding when the optional
+// feature is not specified.
+TEST_F(TextureValidationTest, Norm16NotAvailableWithoutExtension) {
+ wgpu::TextureDescriptor descriptor;
+ descriptor.size = {1, 1, 1};
+ descriptor.usage = wgpu::TextureUsage::TextureBinding;
+
+ descriptor.format = wgpu::TextureFormat::R16Unorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+
+ descriptor.format = wgpu::TextureFormat::RG16Unorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+
+ descriptor.format = wgpu::TextureFormat::RGBA16Unorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+
+ descriptor.format = wgpu::TextureFormat::R16Snorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+
+ descriptor.format = wgpu::TextureFormat::RG16Snorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+
+ descriptor.format = wgpu::TextureFormat::RGBA16Snorm;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+}
+
static void CheckTextureMatchesDescriptor(const wgpu::Texture& tex,
const wgpu::TextureDescriptor& desc) {
EXPECT_EQ(desc.size.width, tex.GetWidth());