Test non-zero buffer copy offset in DepthStencilCopyTests

This patch adds the tests on the buffer-texture copies with depth
stencil textures when buffer copy offset is not zero.

Note that the tests about texture-buffer copies with depth stencil
textures are temporarily skipped on D3D12 backends as there is still a
bug on the texture-to-buffer copies with depth stencil textures on some
D3D12 platforms. We will fix this issue in the next patch.

Bug: dawn:727
Test: dawn_end2end_tests
Change-Id: I1d92cca80945ad77506db5441c396ce3eea00cca
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97180
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao 2022-07-27 00:57:55 +00:00 committed by Dawn LUCI CQ
parent a2a57b9b52
commit dd96f830f9
1 changed files with 449 additions and 293 deletions

View File

@ -215,12 +215,37 @@ class DepthStencilCopyTests : public DawnTestWithParams<DepthStencilCopyTestPara
return dst; return dst;
} }
uint32_t BufferSizeForTextureCopy( uint32_t BufferSizeForTextureCopy(uint32_t width,
uint32_t width,
uint32_t height, uint32_t height,
uint32_t depth, uint32_t depth,
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm) { wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm,
uint32_t bytesPerPixel = utils::GetTexelBlockSizeInBytes(format); wgpu::TextureAspect aspect = wgpu::TextureAspect::All) {
uint32_t bytesPerPixel = 0;
switch (format) {
case wgpu::TextureFormat::Depth24PlusStencil8: {
ASSERT(aspect == wgpu::TextureAspect::StencilOnly);
bytesPerPixel = 1;
break;
}
case wgpu::TextureFormat::Depth32FloatStencil8: {
switch (aspect) {
case wgpu::TextureAspect::DepthOnly:
bytesPerPixel = 4;
break;
case wgpu::TextureAspect::StencilOnly:
bytesPerPixel = 1;
break;
default:
UNREACHABLE();
break;
}
break;
}
default:
bytesPerPixel = utils::GetTexelBlockSizeInBytes(format);
break;
}
uint32_t bytesPerRow = Align(width * bytesPerPixel, kTextureBytesPerRowAlignment); uint32_t bytesPerRow = Align(width * bytesPerPixel, kTextureBytesPerRowAlignment);
return (bytesPerRow * (height - 1) + width * bytesPerPixel) * depth; return (bytesPerRow * (height - 1) + width * bytesPerPixel) * depth;
} }
@ -431,10 +456,13 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepthThenStencil) {
wgpu::TextureAspect::StencilOnly); wgpu::TextureAspect::StencilOnly);
} }
class DepthCopyTests : public DepthStencilCopyTests {}; class DepthCopyTests : public DepthStencilCopyTests {
public:
// Test copying the depth-only aspect into a buffer. void DoCopyFromDepthTest(uint32_t bufferCopyOffset,
TEST_P(DepthCopyTests, FromDepthAspect) { float initDepth,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t testLevel) {
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says // TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
// Invalid format and type combination in glReadPixels // Invalid format and type combination in glReadPixels
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm && DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
@ -444,82 +472,104 @@ TEST_P(DepthCopyTests, FromDepthAspect) {
// when using Tint/GLSL. // when using Tint/GLSL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES()); DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
constexpr uint32_t kWidth = 4; uint32_t mipLevelCount = testLevel + 1;
constexpr uint32_t kHeight = 4;
wgpu::Texture texture = CreateTexture( wgpu::Texture texture = CreateTexture(
kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc); textureWidth, textureHeight,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
constexpr float kInitDepth = 0.2f; InitializeDepthStencilTextureRegion(texture, 0.f, initDepth, 0, 0, testLevel);
InitializeDepthStencilTextureRegion(texture, 0.f, kInitDepth, 0, 0);
uint32_t copyWidth = textureWidth >> testLevel;
uint32_t copyHeight = textureHeight >> testLevel;
wgpu::Extent3D copySize = {copyWidth, copyHeight, 1};
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
wgpu::BufferDescriptor bufferDescriptor = {};
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
bufferDescriptor.size =
bufferCopyOffset + BufferSizeForTextureCopy(copyWidth, copyHeight, 1,
GetParam().mTextureFormat,
wgpu::TextureAspect::DepthOnly);
wgpu::Buffer destinationBuffer = device.CreateBuffer(&bufferDescriptor);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
texture, testLevel, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
destinationBuffer, bufferCopyOffset, kBytesPerRow, copyHeight);
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
// This expectation is the test as it performs the CopyTextureToBuffer.
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) { if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
uint16_t expected = FloatToUnorm<uint16_t>(kInitDepth); uint16_t expected = FloatToUnorm<uint16_t>(initDepth);
std::vector<uint16_t> expectedData = { std::vector<uint16_t> expectedData = {
0, 0, 0, 0, // 0, 0, 0, 0, //
0, 0, 0, 0, // 0, 0, 0, 0, //
expected, expected, 0, 0, // expected, expected, 0, 0, //
expected, expected, 0, 0, // expected, expected, 0, 0, //
}; };
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
wgpu::TextureAspect::DepthOnly); for (uint32_t y = 0; y < copyHeight; ++y) {
EXPECT_BUFFER_U16_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
bufferCopyOffset + y * kBytesPerRow, copyWidth);
}
} else { } else {
std::vector<float> expectedData = { std::vector<float> expectedData = {
0.0, 0.0, 0.0, 0.0, // 0.0, 0.0, 0.0, 0.0, //
0.0, 0.0, 0.0, 0.0, // 0.0, 0.0, 0.0, 0.0, //
kInitDepth, kInitDepth, 0.0, 0.0, // initDepth, initDepth, 0.0, 0.0, //
kInitDepth, kInitDepth, 0.0, 0.0, // initDepth, initDepth, 0.0, 0.0, //
}; };
EXPECT_TEXTURE_EQ(expectedData.data(), texture, {0, 0}, {kWidth, kHeight}, 0,
wgpu::TextureAspect::DepthOnly); for (uint32_t y = 0; y < copyHeight; ++y) {
EXPECT_BUFFER_FLOAT_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
bufferCopyOffset + y * kBytesPerRow, copyWidth);
}
}
}
};
// Test copying the depth-only aspect into a buffer.
TEST_P(DepthCopyTests, FromDepthAspect) {
constexpr float kInitDepth = 0.2f;
constexpr uint32_t kBufferCopyOffset = 0;
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
constexpr uint32_t kTestLevel = 0;
DoCopyFromDepthTest(kBufferCopyOffset, kInitDepth, kWidth, kHeight, kTestLevel);
}
// Test copying the depth-only aspect into a buffer at a non-zero offset.
TEST_P(DepthCopyTests, FromDepthAspectToBufferAtNonZeroOffset) {
// TODO(crbug.com/dawn/727): currently this test fails on many D3D12 drivers as there is a bug
// in the implementation of texture-to-buffer copies with depth stencil textures on D3D12.
DAWN_SUPPRESS_TEST_IF(IsD3D12());
constexpr float kInitDepth = 0.2f;
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
constexpr uint32_t kTestLevel = 0;
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {4u, 512u};
for (uint32_t offset : kBufferCopyOffsets) {
DoCopyFromDepthTest(offset, kInitDepth, kWidth, kHeight, kTestLevel);
} }
} }
// Test copying the non-zero mip, depth-only aspect into a buffer. // Test copying the non-zero mip, depth-only aspect into a buffer.
TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) { TEST_P(DepthCopyTests, FromNonZeroMipDepthAspect) {
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says constexpr float kInitDepth = 0.2f;
// Invalid format and type combination in glReadPixels constexpr uint32_t kBufferCopyOffset = 0;
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm && constexpr uint32_t kWidth = 9;
(IsOpenGL() || IsOpenGLES())); constexpr uint32_t kHeight = 9;
constexpr uint32_t kTestLevel = 1;
// TODO(crbug.com/dawn/1291): These tests are failing on GLES (both native and ANGLE) DoCopyFromDepthTest(kBufferCopyOffset, kInitDepth, kWidth, kHeight, kTestLevel);
// when using Tint/GLSL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
wgpu::Texture depthTexture = CreateDepthTexture(
9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);
constexpr float kInitDepth = 0.4f;
InitializeDepthStencilTextureRegion(depthTexture, 0.f, kInitDepth, 0, 0, /*mipLevel*/ 1);
// This expectation is the test as it performs the CopyTextureToBuffer.
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
uint16_t expected = FloatToUnorm<uint16_t>(kInitDepth);
std::vector<uint16_t> expectedData = {
0, 0, 0, 0, //
0, 0, 0, 0, //
expected, expected, 0, 0, //
expected, expected, 0, 0, //
};
EXPECT_TEXTURE_EQ(expectedData.data(), depthTexture, {0, 0}, {4, 4}, 1,
wgpu::TextureAspect::DepthOnly);
} else {
std::vector<float> expectedData = {
0.0, 0.0, 0.0, 0.0, //
0.0, 0.0, 0.0, 0.0, //
kInitDepth, kInitDepth, 0.0, 0.0, //
kInitDepth, kInitDepth, 0.0, 0.0, //
};
EXPECT_TEXTURE_EQ(expectedData.data(), depthTexture, {0, 0}, {4, 4}, 1,
wgpu::TextureAspect::DepthOnly);
}
} }
class DepthCopyFromBufferTests : public DepthStencilCopyTests {}; class DepthCopyFromBufferTests : public DepthStencilCopyTests {
public:
// Test copying the depth-only aspect from a buffer. void DoTest(uint32_t bufferCopyOffset, bool hasRenderAttachmentUsage) {
TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says // TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
// Invalid format and type combination in glReadPixels // Invalid format and type combination in glReadPixels
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm && DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
@ -528,19 +578,27 @@ TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
constexpr uint32_t kWidth = 8; constexpr uint32_t kWidth = 8;
constexpr uint32_t kHeight = 1; constexpr uint32_t kHeight = 1;
wgpu::Texture destTexture = wgpu::TextureUsage textureUsage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc;
CreateTexture(kWidth, kHeight, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc); // On D3D12 backend the resource flag D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL is set only
// when wgpu::TextureUsage::RenderAttachment is set on the creation of a depth stencil
// texture.
if (hasRenderAttachmentUsage) {
textureUsage |= wgpu::TextureUsage::RenderAttachment;
}
wgpu::Texture destTexture = CreateTexture(kWidth, kHeight, textureUsage);
wgpu::BufferDescriptor descriptor; wgpu::BufferDescriptor descriptor;
descriptor.size = BufferSizeForTextureCopy(kWidth, kHeight, 1, GetParam().mTextureFormat); descriptor.size = bufferCopyOffset +
BufferSizeForTextureCopy(kWidth, kHeight, 1, GetParam().mTextureFormat);
descriptor.usage = wgpu::BufferUsage::CopySrc; descriptor.usage = wgpu::BufferUsage::CopySrc;
descriptor.mappedAtCreation = true; descriptor.mappedAtCreation = true;
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor); wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
wgpu::ImageCopyBuffer imageCopyBuffer = wgpu::ImageCopyBuffer imageCopyBuffer =
utils::CreateImageCopyBuffer(srcBuffer, 0, 256, kHeight); utils::CreateImageCopyBuffer(srcBuffer, bufferCopyOffset, kBytesPerRow, kHeight);
wgpu::ImageCopyTexture imageCopyTexture = wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
utils::CreateImageCopyTexture(destTexture, 0, {0, 0, 0}, wgpu::TextureAspect::DepthOnly); destTexture, 0, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
wgpu::Extent3D extent = {kWidth, kHeight, 1}; wgpu::Extent3D extent = {kWidth, kHeight, 1};
constexpr float kInitDepth = 0.2f; constexpr float kInitDepth = 0.2f;
@ -552,8 +610,8 @@ TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
0, 0, expected, expected, 0, 0, expected, expected, 0, 0, expected, expected, 0, 0, expected, expected,
}; };
size_t expectedSize = expectedData.size() * sizeof(uint16_t); size_t expectedSize = expectedData.size() * sizeof(uint16_t);
memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
memcpy(srcBuffer.GetMappedRange(0, expectedSize), expectedData.data(), expectedSize); expectedSize);
srcBuffer.Unmap(); srcBuffer.Unmap();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -569,7 +627,8 @@ TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
}; };
size_t expectedSize = expectedData.size() * sizeof(float); size_t expectedSize = expectedData.size() * sizeof(float);
memcpy(srcBuffer.GetMappedRange(0, expectedSize), expectedData.data(), expectedSize); memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
expectedSize);
srcBuffer.Unmap(); srcBuffer.Unmap();
wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
@ -580,68 +639,96 @@ TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0, EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
wgpu::TextureAspect::DepthOnly); wgpu::TextureAspect::DepthOnly);
} }
}
};
// Test copying the depth-only aspect from a buffer.
TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
constexpr uint32_t kBufferCopyOffset = 0;
constexpr bool kIsRenderable = false;
DoTest(kBufferCopyOffset, kIsRenderable);
} }
class StencilCopyTests : public DepthStencilCopyTests {}; // Test copying the depth-only aspect from a buffer at a non-zero offset.
TEST_P(DepthCopyFromBufferTests, BufferToNonRenderableDepthAspectAtNonZeroOffset) {
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
constexpr bool kIsRenderable = false;
for (uint32_t offset : kBufferCopyOffsets) {
DoTest(offset, kIsRenderable);
}
}
// Test copying the stencil-only aspect into a buffer. // Test copying the depth-only aspect from a buffer at a non-zero offset.
TEST_P(StencilCopyTests, FromStencilAspect) { TEST_P(DepthCopyFromBufferTests, BufferToRenderableDepthAspectAtNonZeroOffset) {
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination. constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
// TODO(crbug.com/dawn/727): currently this test fails on many D3D12 drivers as there is a bug
// in the implementation of texture-to-buffer copies with depth stencil textures on D3D12.
DAWN_SUPPRESS_TEST_IF(IsD3D12());
constexpr bool kIsRenderable = true;
for (uint32_t offset : kBufferCopyOffsets) {
DoTest(offset, kIsRenderable);
}
}
class StencilCopyTests : public DepthStencilCopyTests {
public:
void DoCopyFromStencilTest(uint32_t bufferCopyOffset,
uint32_t textureWidth,
uint32_t textureHeight,
uint32_t testLevel) {
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type
// combination.
DAWN_SUPPRESS_TEST_IF(IsANGLE()); DAWN_SUPPRESS_TEST_IF(IsANGLE());
// TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read // TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
// stencil. // stencil.
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read")); DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
constexpr uint32_t kWidth = 4; uint32_t mipLevelCount = testLevel + 1;
constexpr uint32_t kHeight = 4;
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture( wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc); textureWidth, textureHeight,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u); InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u, testLevel);
// This expectation is the test as it performs the CopyTextureToBuffer.
std::vector<uint8_t> expectedData = { std::vector<uint8_t> expectedData = {
0u, 0u, 0u, 0u, // 0u, 0u, 0u, 0u, //
0u, 0u, 0u, 0u, // 0u, 0u, 0u, 0u, //
1u, 1u, 0u, 0u, // 1u, 1u, 0u, 0u, //
1u, 1u, 0u, 0u, // 1u, 1u, 0u, 0u, //
}; };
EXPECT_TEXTURE_EQ(expectedData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
uint32_t copyWidth = textureWidth >> testLevel;
uint32_t copyHeight = textureHeight >> testLevel;
ASSERT_EQ(expectedData.size(), copyWidth * copyHeight);
wgpu::Extent3D copySize = {copyWidth, copyHeight, 1};
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
wgpu::BufferDescriptor bufferDescriptor = {};
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
bufferDescriptor.size =
bufferCopyOffset + BufferSizeForTextureCopy(copyWidth, copyHeight, 1,
GetParam().mTextureFormat,
wgpu::TextureAspect::StencilOnly); wgpu::TextureAspect::StencilOnly);
} wgpu::Buffer destinationBuffer = device.CreateBuffer(&bufferDescriptor);
// Test copying the non-zero mip, stencil-only aspect into a buffer. wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
TEST_P(StencilCopyTests, FromNonZeroMipStencilAspect) { wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
// TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work depthStencilTexture, testLevel, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
// on some Intel drivers. wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel()); destinationBuffer, bufferCopyOffset, kBytesPerRow, copyHeight);
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, &copySize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
queue.Submit(1, &commandBuffer);
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination. for (uint32_t y = 0; y < copyHeight; ++y) {
DAWN_SUPPRESS_TEST_IF(IsANGLE()); EXPECT_BUFFER_U8_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
bufferCopyOffset + y * kBytesPerRow, copyWidth);
}
}
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil. void DoCopyToStencilTest(uint32_t bufferCopyOffset) {
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
9, 9, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, 2);
InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u, 1u);
// This expectation is the test as it performs the CopyTextureToBuffer.
std::vector<uint8_t> expectedData = {
0u, 0u, 0u, 0u, //
0u, 0u, 0u, 0u, //
1u, 1u, 0u, 0u, //
1u, 1u, 0u, 0u, //
};
EXPECT_TEXTURE_EQ(expectedData.data(), depthStencilTexture, {0, 0}, {4, 4}, 1,
wgpu::TextureAspect::StencilOnly);
}
// Test copying to the stencil-aspect of a buffer
TEST_P(StencilCopyTests, ToStencilAspect) {
// Copies to a single aspect are unsupported on OpenGL. // Copies to a single aspect are unsupported on OpenGL.
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL()); DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES()); DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
@ -658,10 +745,10 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
constexpr uint32_t kHeight = 4; constexpr uint32_t kHeight = 4;
const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat); const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat);
wgpu::Texture depthStencilTexture = wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
CreateDepthStencilTexture(kWidth, kHeight, kWidth, kHeight,
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst); wgpu::TextureUsage::CopyDst);
if (hasDepth) { if (hasDepth) {
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
@ -695,17 +782,34 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
}; };
// Upload the stencil data. // Upload the stencil data.
wgpu::TextureDataLayout stencilDataLayout = {}; {
stencilDataLayout.bytesPerRow = kWidth * sizeof(uint8_t); wgpu::BufferDescriptor descriptor;
descriptor.size = bufferCopyOffset + BufferSizeForTextureCopy(
kWidth, kHeight, 1, GetParam().mTextureFormat,
wgpu::TextureAspect::StencilOnly);
descriptor.usage = wgpu::BufferUsage::CopySrc;
descriptor.mappedAtCreation = true;
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
uint8_t* mappedPtr = static_cast<uint8_t*>(srcBuffer.GetMappedRange(bufferCopyOffset));
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
for (uint32_t y = 0; y < kHeight; ++y) {
memcpy(mappedPtr + y * kBytesPerRow, stencilData.data() + y * kWidth, kWidth);
}
srcBuffer.Unmap();
wgpu::ImageCopyTexture stencilDataCopyTexture = utils::CreateImageCopyTexture( wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
wgpu::ImageCopyBuffer imageCopyBuffer =
utils::CreateImageCopyBuffer(srcBuffer, bufferCopyOffset, kBytesPerRow, kHeight);
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
depthStencilTexture, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly); depthStencilTexture, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
wgpu::Extent3D copySize = {kWidth, kHeight, 1};
commandEncoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &copySize);
wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
queue.Submit(1, &commandBuffer);
}
wgpu::Extent3D writeSize = {kWidth, kHeight, 1}; // Decrement the stencil value in a render pass to ensure the data is visible to the
queue.WriteTexture(&stencilDataCopyTexture, stencilData.data(), // pipeline.
stencilData.size() * sizeof(uint8_t), &stencilDataLayout, &writeSize);
// Decrement the stencil value in a render pass to ensure the data is visible to the pipeline.
{ {
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
// Create a render pipline which decrements the stencil value for passing fragments. // Create a render pipline which decrements the stencil value for passing fragments.
@ -744,8 +848,8 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
} }
// Copy back the stencil data and check it is correct. // Copy back the stencil data and check it is correct.
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0, EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0},
wgpu::TextureAspect::StencilOnly); {kWidth, kHeight}, 0, wgpu::TextureAspect::StencilOnly);
if (hasDepth) { if (hasDepth) {
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth, ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth,
@ -757,6 +861,58 @@ TEST_P(StencilCopyTests, ToStencilAspect) {
0.7, 0.7, 0.7, 0.7, // 0.7, 0.7, 0.7, 0.7, //
}); });
} }
}
};
// Test copying the stencil-only aspect into a buffer.
TEST_P(StencilCopyTests, FromStencilAspect) {
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
constexpr uint32_t kTestLevel = 0;
constexpr uint32_t kBufferCopyOffset = 0;
DoCopyFromStencilTest(kBufferCopyOffset, kWidth, kHeight, kTestLevel);
}
// Test copying the stencil-only aspect into a buffer at a non-zero offset
TEST_P(StencilCopyTests, FromStencilAspectAtNonZeroOffset) {
// TODO(crbug.com/dawn/727): currently this test fails on many D3D12 drivers as there is a bug
// in the implementation of texture-to-buffer copies with depth stencil textures on D3D12.
DAWN_SUPPRESS_TEST_IF(IsD3D12());
constexpr uint32_t kWidth = 4;
constexpr uint32_t kHeight = 4;
constexpr uint32_t kTestLevel = 0;
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {4u, 512u};
for (uint32_t offset : kBufferCopyOffsets) {
DoCopyFromStencilTest(offset, kWidth, kHeight, kTestLevel);
}
}
// Test copying the non-zero mip, stencil-only aspect into a buffer.
TEST_P(StencilCopyTests, FromNonZeroMipStencilAspect) {
constexpr uint32_t kWidth = 9;
constexpr uint32_t kHeight = 9;
constexpr uint32_t kTestLevel = 1;
constexpr uint32_t kBufferCopyOffset = 0;
DoCopyFromStencilTest(kBufferCopyOffset, kWidth, kHeight, kTestLevel);
}
// Test copying to the stencil-aspect of a texture
TEST_P(StencilCopyTests, ToStencilAspect) {
constexpr uint32_t kBufferCopyOffset = 0;
DoCopyToStencilTest(kBufferCopyOffset);
}
// Test copying to the stencil-aspect of a texture at non-zero offset
TEST_P(StencilCopyTests, ToStencilAspectAtNonZeroOffset) {
// TODO(crbug.com/dawn/727): currently this test fails on many D3D12 drivers as there is a bug
// in the implementation of texture-to-buffer copies with depth stencil textures on D3D12.
DAWN_SUPPRESS_TEST_IF(IsD3D12());
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
for (uint32_t offset : kBufferCopyOffsets) {
DoCopyToStencilTest(offset);
}
} }
DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests, DAWN_INSTANTIATE_TEST_P(DepthStencilCopyTests,