Add support for creating 1D textures.
However there are a lot more things to implement for full support:
- Copies from/to buffers.
- Copies from/to other textures.
- WriteTexture
- Lazy initialization (if needed)
- Anything using views and 1D textures in shaders
So they are currently marked as unsafe API.
Bug: dawn:814
Change-Id: I3f1aac87bd5bc27f710d58e525938c1226d093d8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64542
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn_native/BindGroupLayout.cpp b/src/dawn_native/BindGroupLayout.cpp
index cea3a06..8cd4a4d 100644
--- a/src/dawn_native/BindGroupLayout.cpp
+++ b/src/dawn_native/BindGroupLayout.cpp
@@ -90,11 +90,13 @@
allowedStages &= ~wgpu::ShaderStage::Vertex;
}
}
+
if (entry.sampler.type != wgpu::SamplerBindingType::Undefined) {
bindingMemberCount++;
bindingType = BindingInfoType::Sampler;
DAWN_TRY(ValidateSamplerBindingType(entry.sampler.type));
}
+
if (entry.texture.sampleType != wgpu::TextureSampleType::Undefined) {
bindingMemberCount++;
bindingType = BindingInfoType::Texture;
@@ -113,6 +115,7 @@
"View dimension (%s) for a multisampled texture bindings was not %s.",
viewDimension, wgpu::TextureViewDimension::e2D);
}
+
if (entry.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
bindingMemberCount++;
bindingType = BindingInfoType::StorageTexture;
diff --git a/src/dawn_native/CommandValidation.cpp b/src/dawn_native/CommandValidation.cpp
index e7a0feb..1e307e5 100644
--- a/src/dawn_native/CommandValidation.cpp
+++ b/src/dawn_native/CommandValidation.cpp
@@ -267,6 +267,13 @@
const Extent3D& copySize) {
const TextureBase* texture = textureCopy.texture;
DAWN_TRY(device->ValidateObject(texture));
+
+ // TODO(https://crbug.com/dawn/814): Disallow 1D texture copies until they are implemented.
+ DAWN_INVALID_IF(texture->GetDimension() == wgpu::TextureDimension::e1D,
+ "%s is used in a copy and has dimension %s. Copies with %s aren't "
+ "implemented (yet) and are disallowed. See https://crbug.com/dawn/814.",
+ texture, wgpu::TextureDimension::e1D, wgpu::TextureDimension::e1D);
+
DAWN_INVALID_IF(textureCopy.mipLevel >= texture->GetNumMipLevels(),
"MipLevel (%u) is greater than the number of mip levels (%u) in %s.",
textureCopy.mipLevel, texture->GetNumMipLevels(), texture);
diff --git a/src/dawn_native/Texture.cpp b/src/dawn_native/Texture.cpp
index 092f7a1..999d550 100644
--- a/src/dawn_native/Texture.cpp
+++ b/src/dawn_native/Texture.cpp
@@ -181,6 +181,9 @@
const CombinedLimits& limits = device->GetLimits();
Extent3D maxExtent;
switch (descriptor->dimension) {
+ case wgpu::TextureDimension::e1D:
+ maxExtent = {limits.v1.maxTextureDimension1D, 1, 1};
+ break;
case wgpu::TextureDimension::e2D:
maxExtent = {limits.v1.maxTextureDimension2D, limits.v1.maxTextureDimension2D,
limits.v1.maxTextureArrayLayers};
@@ -189,9 +192,6 @@
maxExtent = {limits.v1.maxTextureDimension3D, limits.v1.maxTextureDimension3D,
limits.v1.maxTextureDimension3D};
break;
- case wgpu::TextureDimension::e1D:
- default:
- UNREACHABLE();
}
DAWN_INVALID_IF(descriptor->size.width > maxExtent.width ||
descriptor->size.height > maxExtent.height ||
@@ -199,18 +199,33 @@
"Texture size (%s) exceeded maximum texture size (%s).",
&descriptor->size, &maxExtent);
- uint32_t maxMippedDimension = descriptor->size.width;
- if (descriptor->dimension != wgpu::TextureDimension::e1D) {
- maxMippedDimension = std::max(maxMippedDimension, descriptor->size.height);
+ switch (descriptor->dimension) {
+ case wgpu::TextureDimension::e1D:
+ DAWN_INVALID_IF(
+ descriptor->mipLevelCount != 1,
+ "Texture mip level count (%u) is more than 1 when its dimension is %s.",
+ descriptor->mipLevelCount, wgpu::TextureDimension::e1D);
+ break;
+ case wgpu::TextureDimension::e2D: {
+ uint32_t maxMippedDimension =
+ std::max(descriptor->size.width, descriptor->size.height);
+ DAWN_INVALID_IF(
+ Log2(maxMippedDimension) + 1 < descriptor->mipLevelCount,
+ "Texture mip level count (%u) exceeds the maximum (%u) for its size (%s).",
+ descriptor->mipLevelCount, Log2(maxMippedDimension) + 1, &descriptor->size);
+ break;
+ }
+ case wgpu::TextureDimension::e3D: {
+ uint32_t maxMippedDimension = std::max(
+ descriptor->size.width,
+ std::max(descriptor->size.height, descriptor->size.depthOrArrayLayers));
+ DAWN_INVALID_IF(
+ Log2(maxMippedDimension) + 1 < descriptor->mipLevelCount,
+ "Texture mip level count (%u) exceeds the maximum (%u) for its size (%s).",
+ descriptor->mipLevelCount, Log2(maxMippedDimension) + 1, &descriptor->size);
+ break;
+ }
}
- if (descriptor->dimension == wgpu::TextureDimension::e3D) {
- maxMippedDimension =
- std::max(maxMippedDimension, descriptor->size.depthOrArrayLayers);
- }
- DAWN_INVALID_IF(
- Log2(maxMippedDimension) + 1 < descriptor->mipLevelCount,
- "Texture mip level count (%u) exceeds the maximum (%u) for its size (%s).",
- descriptor->mipLevelCount, Log2(maxMippedDimension) + 1, &descriptor->size);
if (format->isCompressed) {
const TexelBlockInfo& blockInfo =
@@ -271,13 +286,18 @@
const DawnTextureInternalUsageDescriptor* internalUsageDesc = nullptr;
FindInChain(descriptor->nextInChain, &internalUsageDesc);
- DAWN_INVALID_IF(descriptor->dimension == wgpu::TextureDimension::e1D,
- "1D textures aren't supported (yet).");
-
DAWN_INVALID_IF(
internalUsageDesc != nullptr && !device->IsFeatureEnabled(Feature::DawnInternalUsages),
"The dawn-internal-usages feature is not enabled");
+ // Support for 1D textures is not complete so they are currently unsafe to use.
+ DAWN_INVALID_IF(
+ device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs) &&
+ descriptor->dimension == wgpu::TextureDimension::e1D,
+ "Texture with dimension %s are disallowed because they are partially implemented. See "
+ "https://crbug.com/dawn/814",
+ wgpu::TextureDimension::e1D);
+
const Format* format;
DAWN_TRY_ASSIGN(format, device->GetInternalFormat(descriptor->format));
@@ -526,8 +546,6 @@
}
uint32_t TextureBase::GetArrayLayers() const {
ASSERT(!IsError());
- // TODO(crbug.com/dawn/814): Update for 1D textures when they are supported.
- ASSERT(mDimension != wgpu::TextureDimension::e1D);
if (mDimension == wgpu::TextureDimension::e3D) {
return 1;
}
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index 85ceabc..d958daf 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -101,13 +101,12 @@
D3D12_RESOURCE_DIMENSION D3D12TextureDimension(wgpu::TextureDimension dimension) {
switch (dimension) {
+ case wgpu::TextureDimension::e1D:
+ return D3D12_RESOURCE_DIMENSION_TEXTURE1D;
case wgpu::TextureDimension::e2D:
return D3D12_RESOURCE_DIMENSION_TEXTURE2D;
case wgpu::TextureDimension::e3D:
return D3D12_RESOURCE_DIMENSION_TEXTURE3D;
-
- case wgpu::TextureDimension::e1D:
- UNREACHABLE();
}
}
diff --git a/src/dawn_native/metal/TextureMTL.mm b/src/dawn_native/metal/TextureMTL.mm
index a3e9745..5230423 100644
--- a/src/dawn_native/metal/TextureMTL.mm
+++ b/src/dawn_native/metal/TextureMTL.mm
@@ -423,7 +423,6 @@
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
mtlDesc.width = GetWidth();
- mtlDesc.height = GetHeight();
mtlDesc.sampleCount = GetSampleCount();
// Metal only allows format reinterpretation to happen on swizzle pattern or conversion
// between linear space and sRGB. For example, creating bgra8Unorm texture view on
@@ -438,9 +437,17 @@
// Choose the correct MTLTextureType and paper over differences in how the array layer count
// is specified.
switch (GetDimension()) {
- case wgpu::TextureDimension::e2D:
+ case wgpu::TextureDimension::e1D:
+ mtlDesc.arrayLength = 1;
mtlDesc.depth = 1;
+ ASSERT(mtlDesc.sampleCount == 1);
+ mtlDesc.textureType = MTLTextureType1D;
+ break;
+
+ case wgpu::TextureDimension::e2D:
+ mtlDesc.height = GetHeight();
mtlDesc.arrayLength = GetArrayLayers();
+ mtlDesc.depth = 1;
if (mtlDesc.arrayLength > 1) {
ASSERT(mtlDesc.sampleCount == 1);
mtlDesc.textureType = MTLTextureType2DArray;
@@ -451,14 +458,12 @@
}
break;
case wgpu::TextureDimension::e3D:
+ mtlDesc.height = GetHeight();
mtlDesc.depth = GetDepth();
mtlDesc.arrayLength = 1;
ASSERT(mtlDesc.sampleCount == 1);
mtlDesc.textureType = MTLTextureType3D;
break;
-
- case wgpu::TextureDimension::e1D:
- UNREACHABLE();
}
return mtlDescRef;
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 83982e8..8d08f9e 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -196,6 +196,12 @@
// Fill in the image type, and paper over differences in how the array layer count is
// specified between WebGPU and Vulkan.
switch (texture.GetDimension()) {
+ case wgpu::TextureDimension::e1D:
+ info->imageType = VK_IMAGE_TYPE_1D;
+ info->extent = {size.width, 1, 1};
+ info->arrayLayers = 1;
+ break;
+
case wgpu::TextureDimension::e2D:
info->imageType = VK_IMAGE_TYPE_2D;
info->extent = {size.width, size.height, 1};
@@ -207,9 +213,6 @@
info->extent = {size.width, size.height, size.depthOrArrayLayers};
info->arrayLayers = 1;
break;
-
- case wgpu::TextureDimension::e1D:
- UNREACHABLE();
}
}
diff --git a/src/tests/unittests/validation/TextureValidationTests.cpp b/src/tests/unittests/validation/TextureValidationTests.cpp
index 1835cd5..e81cd0b 100644
--- a/src/tests/unittests/validation/TextureValidationTests.cpp
+++ b/src/tests/unittests/validation/TextureValidationTests.cpp
@@ -291,6 +291,22 @@
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
}
+
+ // 1D textures can only have a single mip level.
+ {
+ wgpu::TextureDescriptor descriptor = defaultDescriptor;
+ descriptor.dimension = wgpu::TextureDimension::e1D;
+ descriptor.size.width = 32;
+ descriptor.size.height = 1;
+
+ // Having a single mip level is allowed.
+ descriptor.mipLevelCount = 1;
+ device.CreateTexture(&descriptor);
+
+ // Having more than 1 is an error.
+ descriptor.mipLevelCount = 2;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+ }
}
// Test the validation of array layer count
@@ -321,6 +337,51 @@
}
}
+ // Test the validation of 1D texture size
+ TEST_F(TextureValidationTest, 1DTextureSize) {
+ wgpu::Limits supportedLimits = GetSupportedLimits().limits;
+
+ wgpu::TextureDescriptor defaultDescriptor;
+ defaultDescriptor.size = {4, 1, 1};
+ defaultDescriptor.dimension = wgpu::TextureDimension::e1D;
+ defaultDescriptor.usage = wgpu::TextureUsage::CopySrc;
+ defaultDescriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+
+ // Width must be in [1, kMaxTextureDimension1D]
+ {
+ wgpu::TextureDescriptor desc = defaultDescriptor;
+ desc.size.width = 0;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+ desc.size.width = 1;
+ device.CreateTexture(&desc);
+
+ desc.size.width = supportedLimits.maxTextureDimension1D;
+ device.CreateTexture(&desc);
+ desc.size.width = supportedLimits.maxTextureDimension1D + 1u;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+ }
+
+ // Height must be 1
+ {
+ wgpu::TextureDescriptor desc = defaultDescriptor;
+ desc.size.height = 2;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+
+ desc.size.height = 0;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+ }
+
+ // DepthOrArrayLayers must be 1
+ {
+ wgpu::TextureDescriptor desc = defaultDescriptor;
+ desc.size.depthOrArrayLayers = 2;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+
+ desc.size.depthOrArrayLayers = 0;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+ }
+ }
+
// Test the validation of 2D texture size
TEST_F(TextureValidationTest, 2DTextureSize) {
wgpu::TextureDescriptor defaultDescriptor = CreateDefaultTextureDescriptor();
@@ -427,8 +488,8 @@
}
}
- // Test that depth/stencil formats are invalid for 3D texture
- TEST_F(TextureValidationTest, DepthStencilFormatsFor3D) {
+ // Test that depth/stencil formats are invalid for 1D and 3D texture
+ TEST_F(TextureValidationTest, DepthStencilFormatsFor1DAnd3D) {
wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
wgpu::TextureFormat depthStencilFormats[] = {
@@ -638,8 +699,6 @@
}
}
- // TODO(jiawei.shao@intel.com): add tests to verify we cannot create 1D or 3D textures with
- // compressed texture formats.
class CompressedTextureFormatsValidationTests : public TextureValidationTest {
protected:
WGPUDevice CreateTestDevice() override {
@@ -649,6 +708,15 @@
wgpu::FeatureName::TextureCompressionASTC};
descriptor.requiredFeatures = requiredFeatures;
descriptor.requiredFeaturesCount = 3;
+
+ // TODO(dawn:814): Remove when 1D texture support is complete.
+ const char* kDisallowUnsafeApis = "disallow_unsafe_apis";
+ wgpu::DawnTogglesDeviceDescriptor togglesDesc;
+ togglesDesc.forceDisabledToggles = &kDisallowUnsafeApis;
+ togglesDesc.forceDisabledTogglesCount = 1;
+
+ descriptor.nextInChain = &togglesDesc;
+
return adapter.CreateDevice(&descriptor);
}
@@ -718,6 +786,24 @@
}
}
+ // Test that it is not allowed to create a 1D texture in compressed formats.
+ TEST_F(CompressedTextureFormatsValidationTests, 1DTexture) {
+ for (wgpu::TextureFormat format : utils::kCompressedFormats) {
+ wgpu::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
+ descriptor.format = format;
+ // Unfortunately we can't use the block height here otherwise validation for the max
+ // texture 1D size will trigger. We check the error message below to make sure the
+ // correct code path is covered.
+ descriptor.size.height = 1;
+ descriptor.size.depthOrArrayLayers = 1;
+ descriptor.dimension = wgpu::TextureDimension::e1D;
+ ASSERT_DEVICE_ERROR(
+ device.CreateTexture(&descriptor),
+ testing::HasSubstr(
+ "The dimension (TextureDimension::e1D) of a texture with a compressed format"));
+ }
+ }
+
// Test that it is not allowed to create a 3D texture in compressed formats.
TEST_F(CompressedTextureFormatsValidationTests, 3DTexture) {
for (wgpu::TextureFormat format : utils::kCompressedFormats) {
diff --git a/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp b/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
index e1ab1ae..b115a5d 100644
--- a/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
+++ b/src/tests/unittests/validation/UnsafeAPIValidationTests.cpp
@@ -32,6 +32,23 @@
}
};
+// Check that 1D textures are disallowed as part of unsafe APIs.
+// TODO(dawn:814): Remove when 1D texture support is complete.
+TEST_F(UnsafeAPIValidationTest, 1DTextures) {
+ wgpu::TextureDescriptor desc;
+ desc.size = {1, 1, 1};
+ desc.format = wgpu::TextureFormat::RGBA8Unorm;
+ desc.usage = wgpu::TextureUsage::CopyDst;
+
+ // Control case: 2D textures are allowed.
+ desc.dimension = wgpu::TextureDimension::e2D;
+ device.CreateTexture(&desc);
+
+ // Error case: 1D textures are disallowed.
+ desc.dimension = wgpu::TextureDimension::e1D;
+ ASSERT_DEVICE_ERROR(device.CreateTexture(&desc));
+}
+
// Check that pipeline overridable constants are disallowed as part of unsafe APIs.
// TODO(dawn:1041) Remove when implementation for all backend is added
TEST_F(UnsafeAPIValidationTest, PipelineOverridableConstants) {