Fix rectangular mipmap textures used as color attachments.

ValidateOrSetAttachmentSize() was asserting that
textureSize.width >> attachment->GetBaseMipLevel() is nonzero.
This is not true for rectangular textures, where the smaller dimension
may hit the lower bound and must be be clamped at 1.

Fixed by calling GetMipLevelVirtualSize() which performs the clamp.

Added a test which exercises rectangular mipmapped textures as color
attachments. This required a few fixes to the test harness, which had
the same bug as that fixed in the code (assumes (width >> size) > 0).

Bug: dawn:535
Change-Id: Idde3b68feb14d8a241803d09a094b059d9935d91
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/29261
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Stephen White <senorblanco@chromium.org>
This commit is contained in:
Stephen White 2020-10-02 16:15:40 +00:00 committed by Commit Bot service account
parent 16ebcf601d
commit ed3a93f690
2 changed files with 47 additions and 19 deletions

View File

@ -186,16 +186,15 @@ namespace dawn_native {
MaybeError ValidateOrSetAttachmentSize(const TextureViewBase* attachment, MaybeError ValidateOrSetAttachmentSize(const TextureViewBase* attachment,
uint32_t* width, uint32_t* width,
uint32_t* height) { uint32_t* height) {
const Extent3D& textureSize = attachment->GetTexture()->GetSize(); const Extent3D& attachmentSize =
const uint32_t attachmentWidth = textureSize.width >> attachment->GetBaseMipLevel(); attachment->GetTexture()->GetMipLevelVirtualSize(attachment->GetBaseMipLevel());
const uint32_t attachmentHeight = textureSize.height >> attachment->GetBaseMipLevel();
if (*width == 0) { if (*width == 0) {
DAWN_ASSERT(*height == 0); DAWN_ASSERT(*height == 0);
*width = attachmentWidth; *width = attachmentSize.width;
*height = attachmentHeight; *height = attachmentSize.height;
DAWN_ASSERT(*width != 0 && *height != 0); DAWN_ASSERT(*width != 0 && *height != 0);
} else if (*width != attachmentWidth || *height != attachmentHeight) { } else if (*width != attachmentSize.width || *height != attachmentSize.height) {
return DAWN_VALIDATION_ERROR("Attachment size mismatch"); return DAWN_VALIDATION_ERROR("Attachment size mismatch");
} }

View File

@ -453,14 +453,14 @@ class TextureViewRenderingTest : public DawnTest {
uint32_t layerCount, uint32_t layerCount,
uint32_t levelCount, uint32_t levelCount,
uint32_t textureViewBaseLayer, uint32_t textureViewBaseLayer,
uint32_t textureViewBaseLevel) { uint32_t textureViewBaseLevel,
uint32_t textureWidthLevel0,
uint32_t textureHeightLevel0) {
ASSERT(dimension == wgpu::TextureViewDimension::e2D || ASSERT(dimension == wgpu::TextureViewDimension::e2D ||
dimension == wgpu::TextureViewDimension::e2DArray); dimension == wgpu::TextureViewDimension::e2DArray);
ASSERT_LT(textureViewBaseLayer, layerCount); ASSERT_LT(textureViewBaseLayer, layerCount);
ASSERT_LT(textureViewBaseLevel, levelCount); ASSERT_LT(textureViewBaseLevel, levelCount);
const uint32_t textureWidthLevel0 = 1 << levelCount;
const uint32_t textureHeightLevel0 = 1 << levelCount;
constexpr wgpu::TextureUsage kUsage = constexpr wgpu::TextureUsage kUsage =
wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc; wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
wgpu::Texture texture = Create2DTexture(device, textureWidthLevel0, textureHeightLevel0, wgpu::Texture texture = Create2DTexture(device, textureWidthLevel0, textureHeightLevel0,
@ -511,8 +511,8 @@ class TextureViewRenderingTest : public DawnTest {
queue.Submit(1, &commands); queue.Submit(1, &commands);
// Check if the right pixels (Green) have been written into the right part of the texture. // Check if the right pixels (Green) have been written into the right part of the texture.
uint32_t textureViewWidth = textureWidthLevel0 >> textureViewBaseLevel; uint32_t textureViewWidth = std::max(1u, textureWidthLevel0 >> textureViewBaseLevel);
uint32_t textureViewHeight = textureHeightLevel0 >> textureViewBaseLevel; uint32_t textureViewHeight = std::max(1u, textureHeightLevel0 >> textureViewBaseLevel);
uint32_t bytesPerRow = uint32_t bytesPerRow =
Align(kBytesPerTexel * textureWidthLevel0, kTextureBytesPerRowAlignment); Align(kBytesPerTexel * textureWidthLevel0, kTextureBytesPerRowAlignment);
uint32_t expectedDataSize = uint32_t expectedDataSize =
@ -534,14 +534,43 @@ TEST_P(TextureViewRenderingTest, Texture2DViewOnALevelOf2DTextureAsColorAttachme
{ {
constexpr uint32_t kBaseLevel = 0; constexpr uint32_t kBaseLevel = 0;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
// Rendering into the last level // Rendering into the last level
{ {
constexpr uint32_t kBaseLevel = kMipLevels - 1; constexpr uint32_t kBaseLevel = kMipLevels - 1;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
}
}
// Test rendering into a 2D texture view created on a mipmap level of a rectangular 2D texture.
TEST_P(TextureViewRenderingTest, Texture2DViewOnALevelOfRectangular2DTextureAsColorAttachment) {
constexpr uint32_t kLayers = 1;
constexpr uint32_t kMipLevels = 4;
constexpr uint32_t kBaseLayer = 0;
// Rendering into the first level
{
constexpr uint32_t kBaseLevel = 0;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel, 1 << kMipLevels,
1 << (kMipLevels - 2));
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel, 1 << (kMipLevels - 2),
1 << kMipLevels);
}
// Rendering into the last level
{
constexpr uint32_t kBaseLevel = kMipLevels - 1;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel, 1 << kMipLevels,
1 << (kMipLevels - 2));
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel, 1 << (kMipLevels - 2),
1 << kMipLevels);
} }
} }
@ -555,14 +584,14 @@ TEST_P(TextureViewRenderingTest, Texture2DViewOnALayerOf2DArrayTextureAsColorAtt
{ {
constexpr uint32_t kBaseLayer = 0; constexpr uint32_t kBaseLayer = 0;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
// Rendering into the last layer // Rendering into the last layer
{ {
constexpr uint32_t kBaseLayer = kLayers - 1; constexpr uint32_t kBaseLayer = kLayers - 1;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2D, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
} }
@ -576,14 +605,14 @@ TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALevelOf2DTextureAsColorAtt
{ {
constexpr uint32_t kBaseLevel = 0; constexpr uint32_t kBaseLevel = 0;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
// Rendering into the last level // Rendering into the last level
{ {
constexpr uint32_t kBaseLevel = kMipLevels - 1; constexpr uint32_t kBaseLevel = kMipLevels - 1;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
} }
@ -597,14 +626,14 @@ TEST_P(TextureViewRenderingTest, Texture2DArrayViewOnALayerOf2DArrayTextureAsCol
{ {
constexpr uint32_t kBaseLayer = 0; constexpr uint32_t kBaseLayer = 0;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
// Rendering into the last layer // Rendering into the last layer
{ {
constexpr uint32_t kBaseLayer = kLayers - 1; constexpr uint32_t kBaseLayer = kLayers - 1;
TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels, TextureLayerAsColorAttachmentTest(wgpu::TextureViewDimension::e2DArray, kLayers, kMipLevels,
kBaseLayer, kBaseLevel); kBaseLayer, kBaseLevel, 1 << kMipLevels, 1 << kMipLevels);
} }
} }