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:
parent
a2a57b9b52
commit
dd96f830f9
|
@ -215,12 +215,37 @@ class DepthStencilCopyTests : public DawnTestWithParams<DepthStencilCopyTestPara
|
|||
return dst;
|
||||
}
|
||||
|
||||
uint32_t BufferSizeForTextureCopy(
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t depth,
|
||||
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm) {
|
||||
uint32_t bytesPerPixel = utils::GetTexelBlockSizeInBytes(format);
|
||||
uint32_t BufferSizeForTextureCopy(uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t depth,
|
||||
wgpu::TextureFormat format = wgpu::TextureFormat::RGBA8Unorm,
|
||||
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);
|
||||
return (bytesPerRow * (height - 1) + width * bytesPerPixel) * depth;
|
||||
}
|
||||
|
@ -431,331 +456,462 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepthThenStencil) {
|
|||
wgpu::TextureAspect::StencilOnly);
|
||||
}
|
||||
|
||||
class DepthCopyTests : public DepthStencilCopyTests {};
|
||||
class DepthCopyTests : public DepthStencilCopyTests {
|
||||
public:
|
||||
void DoCopyFromDepthTest(uint32_t bufferCopyOffset,
|
||||
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
|
||||
// Invalid format and type combination in glReadPixels
|
||||
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
||||
(IsOpenGL() || IsOpenGLES()));
|
||||
|
||||
// TODO(crbug.com/dawn/1291): These tests are failing on GLES (both native and ANGLE)
|
||||
// when using Tint/GLSL.
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
||||
|
||||
uint32_t mipLevelCount = testLevel + 1;
|
||||
wgpu::Texture texture = CreateTexture(
|
||||
textureWidth, textureHeight,
|
||||
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
|
||||
|
||||
InitializeDepthStencilTextureRegion(texture, 0.f, initDepth, 0, 0, testLevel);
|
||||
|
||||
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, ©Size);
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
if (GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm) {
|
||||
uint16_t expected = FloatToUnorm<uint16_t>(initDepth);
|
||||
std::vector<uint16_t> expectedData = {
|
||||
0, 0, 0, 0, //
|
||||
0, 0, 0, 0, //
|
||||
expected, expected, 0, 0, //
|
||||
expected, expected, 0, 0, //
|
||||
};
|
||||
|
||||
for (uint32_t y = 0; y < copyHeight; ++y) {
|
||||
EXPECT_BUFFER_U16_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
|
||||
bufferCopyOffset + y * kBytesPerRow, copyWidth);
|
||||
}
|
||||
|
||||
} else {
|
||||
std::vector<float> expectedData = {
|
||||
0.0, 0.0, 0.0, 0.0, //
|
||||
0.0, 0.0, 0.0, 0.0, //
|
||||
initDepth, initDepth, 0.0, 0.0, //
|
||||
initDepth, initDepth, 0.0, 0.0, //
|
||||
};
|
||||
|
||||
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) {
|
||||
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
||||
// Invalid format and type combination in glReadPixels
|
||||
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
||||
(IsOpenGL() || IsOpenGLES()));
|
||||
|
||||
// TODO(crbug.com/dawn/1291): These tests are failing on GLES (both native and ANGLE)
|
||||
// when using Tint/GLSL.
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
wgpu::Texture texture = CreateTexture(
|
||||
kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
|
||||
// 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;
|
||||
InitializeDepthStencilTextureRegion(texture, 0.f, kInitDepth, 0, 0);
|
||||
|
||||
// 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(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
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(), texture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::DepthOnly);
|
||||
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_P(DepthCopyTests, FromNonZeroMipDepthAspect) {
|
||||
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
||||
// Invalid format and type combination in glReadPixels
|
||||
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
||||
(IsOpenGL() || IsOpenGLES()));
|
||||
|
||||
// TODO(crbug.com/dawn/1291): These tests are failing on GLES (both native and ANGLE)
|
||||
// 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);
|
||||
}
|
||||
constexpr float kInitDepth = 0.2f;
|
||||
constexpr uint32_t kBufferCopyOffset = 0;
|
||||
constexpr uint32_t kWidth = 9;
|
||||
constexpr uint32_t kHeight = 9;
|
||||
constexpr uint32_t kTestLevel = 1;
|
||||
DoCopyFromDepthTest(kBufferCopyOffset, kInitDepth, kWidth, kHeight, kTestLevel);
|
||||
}
|
||||
|
||||
class DepthCopyFromBufferTests : public DepthStencilCopyTests {};
|
||||
class DepthCopyFromBufferTests : public DepthStencilCopyTests {
|
||||
public:
|
||||
void DoTest(uint32_t bufferCopyOffset, bool hasRenderAttachmentUsage) {
|
||||
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
||||
// Invalid format and type combination in glReadPixels
|
||||
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
||||
(IsOpenGL() || IsOpenGLES()));
|
||||
|
||||
constexpr uint32_t kWidth = 8;
|
||||
constexpr uint32_t kHeight = 1;
|
||||
|
||||
wgpu::TextureUsage textureUsage = 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;
|
||||
descriptor.size = bufferCopyOffset +
|
||||
BufferSizeForTextureCopy(kWidth, kHeight, 1, GetParam().mTextureFormat);
|
||||
descriptor.usage = wgpu::BufferUsage::CopySrc;
|
||||
descriptor.mappedAtCreation = true;
|
||||
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
|
||||
|
||||
constexpr uint32_t kBytesPerRow = kTextureBytesPerRowAlignment;
|
||||
wgpu::ImageCopyBuffer imageCopyBuffer =
|
||||
utils::CreateImageCopyBuffer(srcBuffer, bufferCopyOffset, kBytesPerRow, kHeight);
|
||||
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
||||
destTexture, 0, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
|
||||
wgpu::Extent3D extent = {kWidth, kHeight, 1};
|
||||
|
||||
constexpr float kInitDepth = 0.2f;
|
||||
|
||||
// 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, expected, expected, 0, 0, expected, expected,
|
||||
};
|
||||
size_t expectedSize = expectedData.size() * sizeof(uint16_t);
|
||||
memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
|
||||
expectedSize);
|
||||
srcBuffer.Unmap();
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::DepthOnly);
|
||||
} else {
|
||||
std::vector<float> expectedData = {
|
||||
0.0, 0.0, kInitDepth, kInitDepth, 0.0, 0.0, kInitDepth, kInitDepth,
|
||||
};
|
||||
size_t expectedSize = expectedData.size() * sizeof(float);
|
||||
|
||||
memcpy(srcBuffer.GetMappedRange(bufferCopyOffset, expectedSize), expectedData.data(),
|
||||
expectedSize);
|
||||
srcBuffer.Unmap();
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::DepthOnly);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Test copying the depth-only aspect from a buffer.
|
||||
TEST_P(DepthCopyFromBufferTests, BufferToDepthAspect) {
|
||||
// TODO(crbug.com/dawn/1237): Depth16Unorm test failed on OpenGL and OpenGLES which says
|
||||
// Invalid format and type combination in glReadPixels
|
||||
DAWN_TEST_UNSUPPORTED_IF(GetParam().mTextureFormat == wgpu::TextureFormat::Depth16Unorm &&
|
||||
(IsOpenGL() || IsOpenGLES()));
|
||||
constexpr uint32_t kBufferCopyOffset = 0;
|
||||
constexpr bool kIsRenderable = false;
|
||||
DoTest(kBufferCopyOffset, kIsRenderable);
|
||||
}
|
||||
|
||||
constexpr uint32_t kWidth = 8;
|
||||
constexpr uint32_t kHeight = 1;
|
||||
|
||||
wgpu::Texture destTexture =
|
||||
CreateTexture(kWidth, kHeight, wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
wgpu::BufferDescriptor descriptor;
|
||||
descriptor.size = BufferSizeForTextureCopy(kWidth, kHeight, 1, GetParam().mTextureFormat);
|
||||
descriptor.usage = wgpu::BufferUsage::CopySrc;
|
||||
descriptor.mappedAtCreation = true;
|
||||
wgpu::Buffer srcBuffer = device.CreateBuffer(&descriptor);
|
||||
|
||||
wgpu::ImageCopyBuffer imageCopyBuffer =
|
||||
utils::CreateImageCopyBuffer(srcBuffer, 0, 256, kHeight);
|
||||
wgpu::ImageCopyTexture imageCopyTexture =
|
||||
utils::CreateImageCopyTexture(destTexture, 0, {0, 0, 0}, wgpu::TextureAspect::DepthOnly);
|
||||
wgpu::Extent3D extent = {kWidth, kHeight, 1};
|
||||
|
||||
constexpr float kInitDepth = 0.2f;
|
||||
|
||||
// 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, expected, expected, 0, 0, expected, expected,
|
||||
};
|
||||
size_t expectedSize = expectedData.size() * sizeof(uint16_t);
|
||||
|
||||
memcpy(srcBuffer.GetMappedRange(0, expectedSize), expectedData.data(), expectedSize);
|
||||
srcBuffer.Unmap();
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::DepthOnly);
|
||||
} else {
|
||||
std::vector<float> expectedData = {
|
||||
0.0, 0.0, kInitDepth, kInitDepth, 0.0, 0.0, kInitDepth, kInitDepth,
|
||||
};
|
||||
size_t expectedSize = expectedData.size() * sizeof(float);
|
||||
|
||||
memcpy(srcBuffer.GetMappedRange(0, expectedSize), expectedData.data(), expectedSize);
|
||||
srcBuffer.Unmap();
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, &extent);
|
||||
wgpu::CommandBuffer commands = encoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_TEXTURE_EQ(expectedData.data(), destTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::DepthOnly);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
class StencilCopyTests : public DepthStencilCopyTests {};
|
||||
// Test copying the depth-only aspect from a buffer at a non-zero offset.
|
||||
TEST_P(DepthCopyFromBufferTests, BufferToRenderableDepthAspectAtNonZeroOffset) {
|
||||
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());
|
||||
|
||||
// TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
|
||||
// stencil.
|
||||
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
||||
|
||||
uint32_t mipLevelCount = testLevel + 1;
|
||||
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
|
||||
textureWidth, textureHeight,
|
||||
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc, mipLevelCount);
|
||||
|
||||
InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 1u, testLevel);
|
||||
|
||||
std::vector<uint8_t> expectedData = {
|
||||
0u, 0u, 0u, 0u, //
|
||||
0u, 0u, 0u, 0u, //
|
||||
1u, 1u, 0u, 0u, //
|
||||
1u, 1u, 0u, 0u, //
|
||||
};
|
||||
|
||||
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::Buffer destinationBuffer = device.CreateBuffer(&bufferDescriptor);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
wgpu::ImageCopyTexture imageCopyTexture = utils::CreateImageCopyTexture(
|
||||
depthStencilTexture, testLevel, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
|
||||
wgpu::ImageCopyBuffer imageCopyBuffer = utils::CreateImageCopyBuffer(
|
||||
destinationBuffer, bufferCopyOffset, kBytesPerRow, copyHeight);
|
||||
encoder.CopyTextureToBuffer(&imageCopyTexture, &imageCopyBuffer, ©Size);
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
for (uint32_t y = 0; y < copyHeight; ++y) {
|
||||
EXPECT_BUFFER_U8_RANGE_EQ(expectedData.data() + copyWidth * y, destinationBuffer,
|
||||
bufferCopyOffset + y * kBytesPerRow, copyWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void DoCopyToStencilTest(uint32_t bufferCopyOffset) {
|
||||
// Copies to a single aspect are unsupported on OpenGL.
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
||||
|
||||
// TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work
|
||||
// on some Intel drivers.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
|
||||
|
||||
// TODO(crbug.com/dawn/1273): Fails on Win11 with D3D12 debug layer and full validation
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
|
||||
|
||||
// Create a stencil texture
|
||||
constexpr uint32_t kWidth = 4;
|
||||
constexpr uint32_t kHeight = 4;
|
||||
const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat);
|
||||
|
||||
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
|
||||
kWidth, kHeight,
|
||||
wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
|
||||
wgpu::TextureUsage::CopyDst);
|
||||
|
||||
if (hasDepth) {
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
|
||||
// Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth.
|
||||
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
||||
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthClearValue = 0.7;
|
||||
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
pass.End();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> stencilData = {
|
||||
1u, 2u, 3u, 4u, //
|
||||
5u, 6u, 7u, 8u, //
|
||||
9u, 10u, 11u, 12u, //
|
||||
13u, 14u, 15u, 16u, //
|
||||
};
|
||||
|
||||
// After copying stencil data in, we will decrement stencil values in the bottom left
|
||||
// of the screen. This is the expected result.
|
||||
std::vector<uint8_t> expectedStencilData = {
|
||||
1u, 2u, 3u, 4u, //
|
||||
5u, 6u, 7u, 8u, //
|
||||
8u, 9u, 11u, 12u, //
|
||||
12u, 13u, 15u, 16u, //
|
||||
};
|
||||
|
||||
// Upload the stencil data.
|
||||
{
|
||||
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::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);
|
||||
wgpu::Extent3D copySize = {kWidth, kHeight, 1};
|
||||
commandEncoder.CopyBufferToTexture(&imageCopyBuffer, &imageCopyTexture, ©Size);
|
||||
wgpu::CommandBuffer commandBuffer = commandEncoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
}
|
||||
|
||||
// Decrement the stencil value in a render pass to ensure the data is visible to the
|
||||
// pipeline.
|
||||
{
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
// Create a render pipline which decrements the stencil value for passing fragments.
|
||||
// A quad is drawn in the bottom left.
|
||||
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
|
||||
renderPipelineDesc.vertex.module = mVertexModule;
|
||||
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
@fragment fn main() {
|
||||
})");
|
||||
renderPipelineDesc.cFragment.targetCount = 0;
|
||||
wgpu::DepthStencilState* depthStencil =
|
||||
renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat);
|
||||
depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
|
||||
if (!hasDepth) {
|
||||
depthStencil->depthWriteEnabled = false;
|
||||
depthStencil->depthCompare = wgpu::CompareFunction::Always;
|
||||
}
|
||||
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
|
||||
|
||||
// Create a render pass which loads the stencil. We want to load the values we
|
||||
// copied in. Also load the canary depth values so they're not lost.
|
||||
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
||||
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
||||
|
||||
// Draw the quad in the bottom left (two triangles).
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.Draw(6);
|
||||
pass.End();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
}
|
||||
|
||||
// Copy back the stencil data and check it is correct.
|
||||
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0},
|
||||
{kWidth, kHeight}, 0, wgpu::TextureAspect::StencilOnly);
|
||||
|
||||
if (hasDepth) {
|
||||
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth,
|
||||
kHeight, 0, 0,
|
||||
{
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
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) {
|
||||
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
|
||||
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/dawn/667): Work around the fact that some platforms are unable to read
|
||||
// stencil.
|
||||
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_depth_stencil_read"));
|
||||
// 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;
|
||||
|
||||
wgpu::Texture depthStencilTexture = CreateDepthStencilTexture(
|
||||
kWidth, kHeight, wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc);
|
||||
|
||||
InitializeDepthStencilTextureRegion(depthStencilTexture, 0.f, 0.3f, 0u, 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}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::StencilOnly);
|
||||
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) {
|
||||
// TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work
|
||||
// on some Intel drivers.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
|
||||
|
||||
// TODO(crbug.com/dawn/1497): glReadPixels: GL error: HIGH: Invalid format and type combination.
|
||||
DAWN_SUPPRESS_TEST_IF(IsANGLE());
|
||||
|
||||
// TODO(crbug.com/dawn/667): Work around some platforms' inability to read back stencil.
|
||||
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);
|
||||
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 buffer
|
||||
// Test copying to the stencil-aspect of a texture
|
||||
TEST_P(StencilCopyTests, ToStencilAspect) {
|
||||
// Copies to a single aspect are unsupported on OpenGL.
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGL());
|
||||
DAWN_TEST_UNSUPPORTED_IF(IsOpenGLES());
|
||||
constexpr uint32_t kBufferCopyOffset = 0;
|
||||
DoCopyToStencilTest(kBufferCopyOffset);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/dawn/704): Readback after clear via stencil copy does not work
|
||||
// on some Intel drivers.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel());
|
||||
// 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());
|
||||
|
||||
// TODO(crbug.com/dawn/1273): Fails on Win11 with D3D12 debug layer and full validation
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsBackendValidationEnabled());
|
||||
|
||||
// Create a stencil texture
|
||||
constexpr uint32_t kWidth = 4;
|
||||
constexpr uint32_t kHeight = 4;
|
||||
const bool hasDepth = !utils::IsStencilOnlyFormat(GetParam().mTextureFormat);
|
||||
|
||||
wgpu::Texture depthStencilTexture =
|
||||
CreateDepthStencilTexture(kWidth, kHeight,
|
||||
wgpu::TextureUsage::RenderAttachment |
|
||||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst);
|
||||
|
||||
if (hasDepth) {
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
|
||||
// Clear depth to 0.7, so we can check that the stencil copy doesn't mutate the depth.
|
||||
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
||||
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthClearValue = 0.7;
|
||||
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
pass.End();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> stencilData = {
|
||||
1u, 2u, 3u, 4u, //
|
||||
5u, 6u, 7u, 8u, //
|
||||
9u, 10u, 11u, 12u, //
|
||||
13u, 14u, 15u, 16u, //
|
||||
};
|
||||
|
||||
// After copying stencil data in, we will decrement stencil values in the bottom left
|
||||
// of the screen. This is the expected result.
|
||||
std::vector<uint8_t> expectedStencilData = {
|
||||
1u, 2u, 3u, 4u, //
|
||||
5u, 6u, 7u, 8u, //
|
||||
8u, 9u, 11u, 12u, //
|
||||
12u, 13u, 15u, 16u, //
|
||||
};
|
||||
|
||||
// Upload the stencil data.
|
||||
wgpu::TextureDataLayout stencilDataLayout = {};
|
||||
stencilDataLayout.bytesPerRow = kWidth * sizeof(uint8_t);
|
||||
|
||||
wgpu::ImageCopyTexture stencilDataCopyTexture = utils::CreateImageCopyTexture(
|
||||
depthStencilTexture, 0, {0, 0, 0}, wgpu::TextureAspect::StencilOnly);
|
||||
|
||||
wgpu::Extent3D writeSize = {kWidth, kHeight, 1};
|
||||
queue.WriteTexture(&stencilDataCopyTexture, stencilData.data(),
|
||||
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();
|
||||
// Create a render pipline which decrements the stencil value for passing fragments.
|
||||
// A quad is drawn in the bottom left.
|
||||
utils::ComboRenderPipelineDescriptor renderPipelineDesc;
|
||||
renderPipelineDesc.vertex.module = mVertexModule;
|
||||
renderPipelineDesc.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
@fragment fn main() {
|
||||
})");
|
||||
renderPipelineDesc.cFragment.targetCount = 0;
|
||||
wgpu::DepthStencilState* depthStencil =
|
||||
renderPipelineDesc.EnableDepthStencil(GetParam().mTextureFormat);
|
||||
depthStencil->stencilFront.passOp = wgpu::StencilOperation::DecrementClamp;
|
||||
if (!hasDepth) {
|
||||
depthStencil->depthWriteEnabled = false;
|
||||
depthStencil->depthCompare = wgpu::CompareFunction::Always;
|
||||
}
|
||||
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&renderPipelineDesc);
|
||||
|
||||
// Create a render pass which loads the stencil. We want to load the values we
|
||||
// copied in. Also load the canary depth values so they're not lost.
|
||||
utils::ComboRenderPassDescriptor passDescriptor({}, depthStencilTexture.CreateView());
|
||||
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.UnsetDepthStencilLoadStoreOpsForFormat(GetParam().mTextureFormat);
|
||||
|
||||
// Draw the quad in the bottom left (two triangles).
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.Draw(6);
|
||||
pass.End();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
}
|
||||
|
||||
// Copy back the stencil data and check it is correct.
|
||||
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::StencilOnly);
|
||||
|
||||
if (hasDepth) {
|
||||
ExpectAttachmentDepthTestData(depthStencilTexture, GetParam().mTextureFormat, kWidth,
|
||||
kHeight, 0, 0,
|
||||
{
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
0.7, 0.7, 0.7, 0.7, //
|
||||
});
|
||||
constexpr std::array<uint32_t, 2> kBufferCopyOffsets = {8, 512};
|
||||
for (uint32_t offset : kBufferCopyOffsets) {
|
||||
DoCopyToStencilTest(offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue