Add validation rules for 3D texture view

3D texture view's baseArrayLayer must be 0, and its arrayLayerCount
must be 1. In addition, 2D/2DArray/Cube/CubeArray (and 1D) views
upon 3D textures are not allowed.

Other behaviors for 3D texture views like default values are similar
to 2D/2DArray views.

This change also adds a test for aspect test against color format for
completeness, in addition to the existing depth/stencil formats.

Bug: dawn:558
Change-Id: I4f5d095b85c9b81e6f41497f1c8a54b569c210bb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/39600
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
This commit is contained in:
Yunchao He 2021-02-01 19:55:58 +00:00 committed by Commit Bot service account
parent fbaa306056
commit a32954a4d2
2 changed files with 186 additions and 11 deletions

View File

@ -63,6 +63,7 @@ namespace dawn_native {
uint32_t textureViewArrayLayer) { uint32_t textureViewArrayLayer) {
switch (textureViewDimension) { switch (textureViewDimension) {
case wgpu::TextureViewDimension::e2D: case wgpu::TextureViewDimension::e2D:
case wgpu::TextureViewDimension::e3D:
return textureViewArrayLayer == 1u; return textureViewArrayLayer == 1u;
case wgpu::TextureViewDimension::e2DArray: case wgpu::TextureViewDimension::e2DArray:
return true; return true;
@ -72,7 +73,6 @@ namespace dawn_native {
return textureViewArrayLayer % 6 == 0; return textureViewArrayLayer % 6 == 0;
case wgpu::TextureViewDimension::e1D: case wgpu::TextureViewDimension::e1D:
case wgpu::TextureViewDimension::e3D:
case wgpu::TextureViewDimension::Undefined: case wgpu::TextureViewDimension::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
@ -87,10 +87,10 @@ namespace dawn_native {
return textureSize.width == textureSize.height; return textureSize.width == textureSize.height;
case wgpu::TextureViewDimension::e2D: case wgpu::TextureViewDimension::e2D:
case wgpu::TextureViewDimension::e2DArray: case wgpu::TextureViewDimension::e2DArray:
case wgpu::TextureViewDimension::e3D:
return true; return true;
case wgpu::TextureViewDimension::e1D: case wgpu::TextureViewDimension::e1D:
case wgpu::TextureViewDimension::e3D:
case wgpu::TextureViewDimension::Undefined: case wgpu::TextureViewDimension::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
@ -287,9 +287,8 @@ namespace dawn_native {
} }
DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension)); DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
if (descriptor->dimension == wgpu::TextureViewDimension::e1D || if (descriptor->dimension == wgpu::TextureViewDimension::e1D) {
descriptor->dimension == wgpu::TextureViewDimension::e3D) { return DAWN_VALIDATION_ERROR("1D texture views aren't supported (yet).");
return DAWN_VALIDATION_ERROR("Texture view dimension must be 2D compatible.");
} }
DAWN_TRY(ValidateTextureFormat(descriptor->format)); DAWN_TRY(ValidateTextureFormat(descriptor->format));
@ -440,8 +439,11 @@ namespace dawn_native {
} }
uint32_t TextureBase::GetArrayLayers() const { uint32_t TextureBase::GetArrayLayers() const {
ASSERT(!IsError()); ASSERT(!IsError());
// TODO(cwallez@chromium.org): Update for 1D / 3D textures when they are supported. // TODO(cwallez@chromium.org): Update for 1D textures when they are supported.
ASSERT(mDimension == wgpu::TextureDimension::e2D); ASSERT(mDimension != wgpu::TextureDimension::e1D);
if (mDimension == wgpu::TextureDimension::e3D) {
return 1;
}
return mSize.depth; return mSize.depth;
} }
uint32_t TextureBase::GetNumMipLevels() const { uint32_t TextureBase::GetNumMipLevels() const {

View File

@ -20,6 +20,7 @@ namespace {
constexpr uint32_t kWidth = 32u; constexpr uint32_t kWidth = 32u;
constexpr uint32_t kHeight = 32u; constexpr uint32_t kHeight = 32u;
constexpr uint32_t kDepth = 6u;
constexpr uint32_t kDefaultMipLevels = 6u; constexpr uint32_t kDefaultMipLevels = 6u;
constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm; constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
@ -42,6 +43,17 @@ namespace {
return device.CreateTexture(&descriptor); return device.CreateTexture(&descriptor);
} }
wgpu::Texture Create3DTexture(wgpu::Device& device) {
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e3D;
descriptor.size = {kWidth, kHeight, kDepth};
descriptor.sampleCount = 1;
descriptor.format = kDefaultTextureFormat;
descriptor.mipLevelCount = kDefaultMipLevels;
descriptor.usage = wgpu::TextureUsage::Sampled;
return device.CreateTexture(&descriptor);
}
wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) { wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) {
wgpu::TextureViewDescriptor descriptor; wgpu::TextureViewDescriptor descriptor;
descriptor.format = kDefaultTextureFormat; descriptor.format = kDefaultTextureFormat;
@ -82,6 +94,14 @@ namespace {
texture.CreateView(&descriptor); texture.CreateView(&descriptor);
} }
// It is an error to create a 3D texture view on a 2D texture.
{
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e3D;
descriptor.arrayLayerCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// baseMipLevel == k && mipLevelCount == 0 means to use levels k..end. // baseMipLevel == k && mipLevelCount == 0 means to use levels k..end.
{ {
wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor; wgpu::TextureViewDescriptor descriptor = base2DTextureViewDescriptor;
@ -139,6 +159,14 @@ namespace {
texture.CreateView(&descriptor); texture.CreateView(&descriptor);
} }
// It is an error to create a 3D texture view on a 2D array texture.
{
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
descriptor.dimension = wgpu::TextureViewDimension::e3D;
descriptor.arrayLayerCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end. // baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end.
{ {
wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor; wgpu::TextureViewDescriptor descriptor = base2DArrayTextureViewDescriptor;
@ -172,10 +200,94 @@ namespace {
} }
} }
// Test creating texture view on a 3D texture
TEST_F(TextureViewValidationTest, CreateTextureViewOnTexture3D) {
wgpu::Texture texture = Create3DTexture(device);
wgpu::TextureViewDescriptor base3DTextureViewDescriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e3D);
// It is OK to create a 3D texture view on a 3D texture.
{
wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor;
texture.CreateView(&descriptor);
}
// It is an error to create a 2D/2DArray/Cube/CubeArray texture view on a 3D texture.
{
wgpu::TextureViewDimension invalidDimensions[] = {
wgpu::TextureViewDimension::e2D,
wgpu::TextureViewDimension::e2DArray,
wgpu::TextureViewDimension::Cube,
wgpu::TextureViewDimension::CubeArray,
};
for (wgpu::TextureViewDimension dimension : invalidDimensions) {
wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor;
descriptor.dimension = dimension;
if (dimension == wgpu::TextureViewDimension::Cube ||
dimension == wgpu::TextureViewDimension::CubeArray) {
descriptor.arrayLayerCount = 6;
}
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// baseMipLevel == k && mipLevelCount == 0 means to use levels k..end.
{
wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor;
descriptor.mipLevelCount = 0;
descriptor.baseMipLevel = 0;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels - 1;
texture.CreateView(&descriptor);
descriptor.baseMipLevel = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// It is an error to make the mip level out of range.
{
wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor;
descriptor.baseMipLevel = 0;
descriptor.mipLevelCount = kDefaultMipLevels + 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = 1;
descriptor.mipLevelCount = kDefaultMipLevels;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels - 1;
descriptor.mipLevelCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseMipLevel = kDefaultMipLevels;
descriptor.mipLevelCount = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
// baseArrayLayer == k && arrayLayerCount == 0 means to use layers k..end. But
// baseArrayLayer must be 0, and arrayLayerCount must be 1 at most for 3D texture view.
{
wgpu::TextureViewDescriptor descriptor = base3DTextureViewDescriptor;
descriptor.arrayLayerCount = 0;
descriptor.baseArrayLayer = 0;
texture.CreateView(&descriptor);
descriptor.baseArrayLayer = 1;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.baseArrayLayer = 0;
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.arrayLayerCount = kDepth;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Using the "none" ("default") values validates the same as explicitly // Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to. // specifying the values they're supposed to default to.
// Variant for a texture with more than 1 array layer. // Variant for a 2D texture with more than 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsArray) { TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults2DArray) {
constexpr uint32_t kDefaultArrayLayers = 6; constexpr uint32_t kDefaultArrayLayers = 6;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
@ -215,8 +327,8 @@ namespace {
// Using the "none" ("default") values validates the same as explicitly // Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to. // specifying the values they're supposed to default to.
// Variant for a texture with only 1 array layer. // Variant for a 2D texture with only 1 array layer.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaultsNonArray) { TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults2DNonArray) {
constexpr uint32_t kDefaultArrayLayers = 1; constexpr uint32_t kDefaultArrayLayers = 1;
wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers); wgpu::Texture texture = Create2DArrayTexture(device, kDefaultArrayLayers);
@ -257,6 +369,51 @@ namespace {
} }
} }
// Using the "none" ("default") values validates the same as explicitly
// specifying the values they're supposed to default to.
// Variant for a 3D texture.
TEST_F(TextureViewValidationTest, TextureViewDescriptorDefaults3D) {
wgpu::Texture texture = Create3DTexture(device);
{ texture.CreateView(); }
{
wgpu::TextureViewDescriptor descriptor;
descriptor.format = wgpu::TextureFormat::Undefined;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
texture.CreateView(&descriptor);
descriptor.format = wgpu::TextureFormat::R8Unorm;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.dimension = wgpu::TextureViewDimension::Undefined;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e3D;
texture.CreateView(&descriptor);
descriptor.dimension = wgpu::TextureViewDimension::e2DArray;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
descriptor.dimension = wgpu::TextureViewDimension::e2D;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.arrayLayerCount = 0;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 1;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = 2;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
{
wgpu::TextureViewDescriptor descriptor;
descriptor.mipLevelCount = kDefaultMipLevels;
texture.CreateView(&descriptor);
descriptor.arrayLayerCount = kDepth;
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
}
// Test creating cube map texture view // Test creating cube map texture view
TEST_F(TextureViewValidationTest, CreateCubeMapTextureView) { TEST_F(TextureViewValidationTest, CreateCubeMapTextureView) {
constexpr uint32_t kDefaultArrayLayers = 16; constexpr uint32_t kDefaultArrayLayers = 16;
@ -381,6 +538,22 @@ namespace {
viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly; viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly;
texture.CreateView(&viewDescriptor); texture.CreateView(&viewDescriptor);
} }
// Can select: All from RGBA8Unorm
{
descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
wgpu::Texture texture = device.CreateTexture(&descriptor);
wgpu::TextureViewDescriptor viewDescriptor = {};
viewDescriptor.aspect = wgpu::TextureAspect::All;
texture.CreateView(&viewDescriptor);
viewDescriptor.aspect = wgpu::TextureAspect::DepthOnly;
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
viewDescriptor.aspect = wgpu::TextureAspect::StencilOnly;
ASSERT_DEVICE_ERROR(texture.CreateView(&viewDescriptor));
}
} }
} // anonymous namespace } // anonymous namespace