Test readback after loadOp value w/ mipmapped depth/stencil textures
There have been some bugs seen with this on some platforms. Bug: dawn:838 Change-Id: I29fa483eee3c299960d2c998fce90d918ac4dc9d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/52560 Commit-Queue: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org>
This commit is contained in:
parent
83d4d4cce1
commit
735d5046b2
|
@ -304,6 +304,7 @@ source_set("dawn_end2end_tests_sources") {
|
|||
"end2end/DeprecatedAPITests.cpp",
|
||||
"end2end/DepthBiasTests.cpp",
|
||||
"end2end/DepthStencilCopyTests.cpp",
|
||||
"end2end/DepthStencilLoadOpTests.cpp",
|
||||
"end2end/DepthStencilSamplingTests.cpp",
|
||||
"end2end/DepthStencilStateTests.cpp",
|
||||
"end2end/DestroyTests.cpp",
|
||||
|
|
|
@ -1144,7 +1144,137 @@ std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
|||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
return EXPECT_BUFFER_FLOAT_RANGE_EQ(expected.data(), readbackBuffer, 0, expected.size());
|
||||
return EXPECT_BUFFER_FLOAT_RANGE_ABOUT_EQ(expected.data(), readbackBuffer, 0, expected.size(),
|
||||
0.00001);
|
||||
}
|
||||
|
||||
std::ostringstream& DawnTestBase::ExpectAttachmentDepthStencilTestData(
|
||||
wgpu::Texture texture,
|
||||
wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
std::vector<float> expectedDepth,
|
||||
uint8_t* expectedStencil) {
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
|
||||
// Make the color attachment that we'll use to read back.
|
||||
wgpu::TextureDescriptor colorTexDesc = {};
|
||||
colorTexDesc.size = {width, height, 1};
|
||||
colorTexDesc.format = wgpu::TextureFormat::R32Uint;
|
||||
colorTexDesc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
||||
wgpu::Texture colorTexture = device.CreateTexture(&colorTexDesc);
|
||||
|
||||
wgpu::Texture depthDataTexture = nullptr;
|
||||
if (expectedDepth.size() > 0) {
|
||||
// Make a sampleable texture to store the depth data. We'll sample this in the
|
||||
// shader to output depth.
|
||||
wgpu::TextureDescriptor depthDataDesc = {};
|
||||
depthDataDesc.size = {width, height, 1};
|
||||
depthDataDesc.format = wgpu::TextureFormat::R32Float;
|
||||
depthDataDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopyDst;
|
||||
depthDataTexture = device.CreateTexture(&depthDataDesc);
|
||||
|
||||
// Upload the depth data.
|
||||
wgpu::ImageCopyTexture imageCopyTexture =
|
||||
utils::CreateImageCopyTexture(depthDataTexture, 0, {0, 0, 0});
|
||||
wgpu::TextureDataLayout textureDataLayout =
|
||||
utils::CreateTextureDataLayout(0, sizeof(float) * width);
|
||||
wgpu::Extent3D copyExtent = {width, height, 1};
|
||||
|
||||
queue.WriteTexture(&imageCopyTexture, expectedDepth.data(),
|
||||
sizeof(float) * expectedDepth.size(), &textureDataLayout, ©Extent);
|
||||
}
|
||||
|
||||
// Pipeline for a full screen quad.
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||
|
||||
pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, R"(
|
||||
[[stage(vertex)]]
|
||||
fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
|
||||
let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>( 3.0, -1.0),
|
||||
vec2<f32>(-1.0, 3.0));
|
||||
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
|
||||
if (depthDataTexture) {
|
||||
// Sample the input texture and write out depth. |result| will only be set to 1 if we
|
||||
// pass the depth test.
|
||||
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
[[group(0), binding(0)]] var texture0 : texture_2d<f32>;
|
||||
|
||||
struct FragmentOut {
|
||||
[[location(0)]] result : u32;
|
||||
[[builtin(frag_depth)]] fragDepth : f32;
|
||||
};
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn main([[builtin(position)]] FragCoord : vec4<f32>) -> FragmentOut {
|
||||
var output : FragmentOut;
|
||||
output.result = 1u;
|
||||
output.fragDepth = textureLoad(texture0, vec2<i32>(FragCoord.xy), 0)[0];
|
||||
return output;
|
||||
})");
|
||||
} else {
|
||||
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
[[stage(fragment)]]
|
||||
fn main() -> [[location(0)]] u32 {
|
||||
return 1u;
|
||||
})");
|
||||
}
|
||||
|
||||
wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(format);
|
||||
if (depthDataTexture) {
|
||||
// Pass the depth test only if the depth is equal.
|
||||
depthStencil->depthCompare = wgpu::CompareFunction::Equal;
|
||||
|
||||
// TODO(jiawei.shao@intel.com): The Intel Mesa Vulkan driver can't set gl_FragDepth unless
|
||||
// depthWriteEnabled == true. This either needs to be fixed in the driver or restricted by
|
||||
// the WebGPU API.
|
||||
depthStencil->depthWriteEnabled = true;
|
||||
}
|
||||
|
||||
if (expectedStencil != nullptr) {
|
||||
// Pass the stencil test only if the stencil is equal.
|
||||
depthStencil->stencilFront.compare = wgpu::CompareFunction::Equal;
|
||||
}
|
||||
|
||||
pipelineDescriptor.cTargets[0].format = colorTexDesc.format;
|
||||
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.baseArrayLayer = arrayLayer;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
|
||||
utils::ComboRenderPassDescriptor passDescriptor({colorTexture.CreateView()},
|
||||
texture.CreateView(&viewDesc));
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
if (expectedStencil != nullptr) {
|
||||
pass.SetStencilReference(*expectedStencil);
|
||||
}
|
||||
pass.SetPipeline(pipeline);
|
||||
if (depthDataTexture) {
|
||||
// Bind the depth data texture.
|
||||
pass.SetBindGroup(0, utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||
{{0, depthDataTexture.CreateView()}}));
|
||||
}
|
||||
pass.Draw(3);
|
||||
pass.EndPass();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
std::vector<uint32_t> colorData(width * height, 1u);
|
||||
return EXPECT_TEXTURE_EQ(colorData.data(), colorTexture, {0, 0}, {width, height});
|
||||
}
|
||||
|
||||
void DawnTestBase::WaitABit() {
|
||||
|
@ -1301,27 +1431,53 @@ namespace detail {
|
|||
// Helper classes to set expectations
|
||||
|
||||
template <typename T>
|
||||
ExpectEq<T>::ExpectEq(T singleValue) {
|
||||
ExpectEq<T>::ExpectEq(T singleValue, T tolerance) : mTolerance(tolerance) {
|
||||
mExpected.push_back(singleValue);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ExpectEq<T>::ExpectEq(const T* values, const unsigned int count) {
|
||||
ExpectEq<T>::ExpectEq(const T* values, const unsigned int count, T tolerance)
|
||||
: mTolerance(tolerance) {
|
||||
mExpected.assign(values, values + count);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult CheckImpl(const T& expected, const T& actual, const T& tolerance) {
|
||||
ASSERT(tolerance == T{});
|
||||
if (expected != actual) {
|
||||
return testing::AssertionFailure() << expected << ", actual " << actual;
|
||||
}
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
template <>
|
||||
testing::AssertionResult CheckImpl<float>(const float& expected,
|
||||
const float& actual,
|
||||
const float& tolerance) {
|
||||
if (abs(expected - actual) > tolerance) {
|
||||
return tolerance == 0.0
|
||||
? testing::AssertionFailure() << expected << ", actual " << actual
|
||||
: testing::AssertionFailure() << "within " << tolerance << " of "
|
||||
<< expected << ", actual " << actual;
|
||||
}
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
testing::AssertionResult ExpectEq<T>::Check(const void* data, size_t size) {
|
||||
DAWN_ASSERT(size == sizeof(T) * mExpected.size());
|
||||
|
||||
const T* actual = static_cast<const T*>(data);
|
||||
|
||||
for (size_t i = 0; i < mExpected.size(); ++i) {
|
||||
if (actual[i] != mExpected[i]) {
|
||||
testing::AssertionResult check = CheckImpl(mExpected[i], actual[i], mTolerance);
|
||||
if (!check) {
|
||||
testing::AssertionResult result = testing::AssertionFailure()
|
||||
<< "Expected data[" << i << "] to be "
|
||||
<< mExpected[i] << ", actual " << actual[i]
|
||||
<< std::endl;
|
||||
<< check.message() << std::endl;
|
||||
|
||||
if (mExpected.size() <= 1024) {
|
||||
result << "Expected:" << std::endl;
|
||||
|
@ -1334,7 +1490,6 @@ namespace detail {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,10 @@
|
|||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count))
|
||||
|
||||
#define EXPECT_BUFFER_FLOAT_RANGE_ABOUT_EQ(expected, buffer, offset, count, tolerance) \
|
||||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||
new ::detail::ExpectEq<float>(expected, count, tolerance))
|
||||
|
||||
// Test a pixel of the mip level 0 of a 2D texture.
|
||||
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
|
||||
AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
|
||||
|
@ -408,6 +412,42 @@ class DawnTestBase {
|
|||
uint32_t mipLevel,
|
||||
const std::vector<float>& expected);
|
||||
|
||||
// Check depth by uploading expected data to a sampled texture, writing it out as a depth
|
||||
// attachment, and then using the "equals" depth test to check the contents are the same.
|
||||
// Check stencil by rendering a full screen quad and using the "equals" stencil test with
|
||||
// a stencil reference value. Note that checking stencil checks that the entire stencil
|
||||
// buffer is equal to the expected stencil value.
|
||||
std::ostringstream& ExpectAttachmentDepthStencilTestData(wgpu::Texture texture,
|
||||
wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
std::vector<float> expectedDepth,
|
||||
uint8_t* expectedStencil);
|
||||
|
||||
std::ostringstream& ExpectAttachmentDepthTestData(wgpu::Texture texture,
|
||||
wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
std::vector<float> expectedDepth) {
|
||||
return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer,
|
||||
mipLevel, std::move(expectedDepth), nullptr);
|
||||
}
|
||||
|
||||
std::ostringstream& ExpectAttachmentStencilTestData(wgpu::Texture texture,
|
||||
wgpu::TextureFormat format,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t arrayLayer,
|
||||
uint32_t mipLevel,
|
||||
uint8_t expectedStencil) {
|
||||
return ExpectAttachmentDepthStencilTestData(texture, format, width, height, arrayLayer,
|
||||
mipLevel, {}, &expectedStencil);
|
||||
}
|
||||
|
||||
void WaitABit();
|
||||
void FlushWire();
|
||||
void WaitForAllOperations();
|
||||
|
@ -630,13 +670,14 @@ namespace detail {
|
|||
template <typename T>
|
||||
class ExpectEq : public Expectation {
|
||||
public:
|
||||
ExpectEq(T singleValue);
|
||||
ExpectEq(const T* values, const unsigned int count);
|
||||
ExpectEq(T singleValue, T tolerance = {});
|
||||
ExpectEq(const T* values, const unsigned int count, T tolerance = {});
|
||||
|
||||
testing::AssertionResult Check(const void* data, size_t size) override;
|
||||
|
||||
private:
|
||||
std::vector<T> mExpected;
|
||||
T mTolerance;
|
||||
};
|
||||
extern template class ExpectEq<uint8_t>;
|
||||
extern template class ExpectEq<int16_t>;
|
||||
|
|
|
@ -182,126 +182,6 @@ class DepthStencilCopyTests : public DawnTest {
|
|||
return dst;
|
||||
}
|
||||
|
||||
// Check depth by uploading expected data to a sampled texture, writing it out as a depth
|
||||
// attachment, and then using the "equals" depth test to check the contents are the same.
|
||||
void ExpectDepthData(wgpu::Texture depthTexture,
|
||||
wgpu::TextureFormat depthFormat,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t mipLevel,
|
||||
std::vector<float> expected) {
|
||||
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
|
||||
|
||||
// Make the color attachment that we'll use to read back.
|
||||
wgpu::TextureDescriptor colorTexDesc = {};
|
||||
colorTexDesc.size = {width, height, 1};
|
||||
colorTexDesc.format = wgpu::TextureFormat::R32Uint;
|
||||
colorTexDesc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc;
|
||||
wgpu::Texture colorTexture = device.CreateTexture(&colorTexDesc);
|
||||
|
||||
// Make a sampleable texture to store the depth data. We'll sample this in the
|
||||
// shader to output depth.
|
||||
wgpu::TextureDescriptor depthDataDesc = {};
|
||||
depthDataDesc.size = {width, height, 1};
|
||||
depthDataDesc.format = wgpu::TextureFormat::R32Float;
|
||||
depthDataDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::CopyDst;
|
||||
wgpu::Texture depthDataTexture = device.CreateTexture(&depthDataDesc);
|
||||
|
||||
// Upload the depth data.
|
||||
uint32_t bytesPerRow = utils::GetMinimumBytesPerRow(wgpu::TextureFormat::R32Float, width);
|
||||
wgpu::BufferDescriptor uploadBufferDesc = {};
|
||||
uploadBufferDesc.size = utils::RequiredBytesInCopy(bytesPerRow, height, depthDataDesc.size,
|
||||
wgpu::TextureFormat::R32Float);
|
||||
uploadBufferDesc.usage = wgpu::BufferUsage::CopySrc;
|
||||
uploadBufferDesc.mappedAtCreation = true;
|
||||
|
||||
// TODO(crbug.com/dawn/822): Use WriteTexture when implemented on OpenGL.
|
||||
wgpu::Buffer uploadBuffer = device.CreateBuffer(&uploadBufferDesc);
|
||||
uint8_t* dst = static_cast<uint8_t*>(uploadBuffer.GetMappedRange());
|
||||
float* src = expected.data();
|
||||
for (uint32_t y = 0; y < height; ++y) {
|
||||
memcpy(dst, src, width * sizeof(float));
|
||||
dst += bytesPerRow;
|
||||
src += width;
|
||||
}
|
||||
uploadBuffer.Unmap();
|
||||
|
||||
wgpu::ImageCopyBuffer bufferCopy =
|
||||
utils::CreateImageCopyBuffer(uploadBuffer, 0, bytesPerRow, height);
|
||||
wgpu::ImageCopyTexture textureCopy =
|
||||
utils::CreateImageCopyTexture(depthDataTexture, 0, {0, 0, 0}, wgpu::TextureAspect::All);
|
||||
commandEncoder.CopyBufferToTexture(&bufferCopy, &textureCopy, &depthDataDesc.size);
|
||||
|
||||
// Pipeline for a full screen quad.
|
||||
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||
|
||||
pipelineDescriptor.vertex.module = utils::CreateShaderModule(device, R"(
|
||||
[[stage(vertex)]]
|
||||
fn main([[builtin(vertex_index)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
|
||||
let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
|
||||
vec2<f32>(-1.0, -1.0),
|
||||
vec2<f32>( 3.0, -1.0),
|
||||
vec2<f32>(-1.0, 3.0));
|
||||
return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
|
||||
})");
|
||||
|
||||
// Sample the input texture and write out depth. |result| will only be set to 1 if we
|
||||
// pass the depth test.
|
||||
pipelineDescriptor.cFragment.module = utils::CreateShaderModule(device, R"(
|
||||
[[group(0), binding(0)]] var texture0 : texture_2d<f32>;
|
||||
|
||||
struct FragmentOut {
|
||||
[[location(0)]] result : u32;
|
||||
[[builtin(frag_depth)]] fragDepth : f32;
|
||||
};
|
||||
|
||||
[[stage(fragment)]]
|
||||
fn main([[builtin(position)]] FragCoord : vec4<f32>) -> FragmentOut {
|
||||
var output : FragmentOut;
|
||||
output.result = 1u;
|
||||
output.fragDepth = textureLoad(texture0, vec2<i32>(FragCoord.xy), 0)[0];
|
||||
return output;
|
||||
})");
|
||||
|
||||
// Pass the depth test only if the depth is equal.
|
||||
pipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList;
|
||||
wgpu::DepthStencilState* depthStencil = pipelineDescriptor.EnableDepthStencil(depthFormat);
|
||||
depthStencil->depthCompare = wgpu::CompareFunction::Equal;
|
||||
pipelineDescriptor.cTargets[0].format = colorTexDesc.format;
|
||||
|
||||
// TODO(crbug.com/dawn/821): The Intel Mesa Vulkan driver can't set gl_FragDepth unless
|
||||
// depthWriteEnabled == true. This either needs to be fixed in the driver or restricted by
|
||||
// the WebGPU API.
|
||||
depthStencil->depthWriteEnabled = true;
|
||||
|
||||
wgpu::TextureViewDescriptor viewDesc = {};
|
||||
viewDesc.baseMipLevel = mipLevel;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
|
||||
utils::ComboRenderPassDescriptor passDescriptor({colorTexture.CreateView()},
|
||||
depthTexture.CreateView(&viewDesc));
|
||||
passDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = wgpu::LoadOp::Load;
|
||||
passDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = wgpu::LoadOp::Load;
|
||||
|
||||
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&pipelineDescriptor);
|
||||
|
||||
// Bind the depth data texture.
|
||||
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
|
||||
{{0, depthDataTexture.CreateView()}});
|
||||
|
||||
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.SetBindGroup(0, bindGroup);
|
||||
pass.Draw(3);
|
||||
pass.EndPass();
|
||||
|
||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
std::vector<uint32_t> colorData(width * height, 1u);
|
||||
EXPECT_TEXTURE_EQ(colorData.data(), colorTexture, {0, 0}, {width, height});
|
||||
}
|
||||
|
||||
wgpu::ShaderModule mVertexModule;
|
||||
};
|
||||
|
||||
|
@ -481,13 +361,14 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepth) {
|
|||
0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::RenderAttachment);
|
||||
|
||||
// Check the depth
|
||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
ExpectAttachmentDepthTestData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth,
|
||||
kHeight, 0, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
}
|
||||
|
||||
// Test copying both aspects in a T2T copy, then copying only depth at a nonzero mip.
|
||||
|
@ -496,13 +377,13 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyNonZeroMipDepth) {
|
|||
0.1f, 0.3f, 1u, 3u, 8, 8, wgpu::TextureUsage::RenderAttachment, 1);
|
||||
|
||||
// Check the depth
|
||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, 4, 4, 1,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
ExpectAttachmentDepthTestData(texture, wgpu::TextureFormat::Depth24PlusStencil8, 4, 4, 0, 1,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
}
|
||||
|
||||
// Test copying both aspects in a T2T copy, then copying stencil, then copying depth
|
||||
|
@ -528,13 +409,14 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyStencilThenDepth) {
|
|||
wgpu::TextureAspect::StencilOnly);
|
||||
|
||||
// Check the depth
|
||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
ExpectAttachmentDepthTestData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth,
|
||||
kHeight, 0, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
}
|
||||
|
||||
// Test copying both aspects in a T2T copy, then copying depth, then copying stencil
|
||||
|
@ -558,13 +440,14 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepthThenStencil) {
|
|||
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
|
||||
|
||||
// Check the depth
|
||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
ExpectAttachmentDepthTestData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth,
|
||||
kHeight, 0, 0,
|
||||
{
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.1, 0.1, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
0.3, 0.3, 0.1, 0.1, //
|
||||
});
|
||||
|
||||
// Check the stencil
|
||||
std::vector<uint8_t> expectedData = {
|
||||
|
@ -674,14 +557,14 @@ TEST_P(DepthStencilCopyTests, ToStencilAspect) {
|
|||
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||
wgpu::TextureAspect::StencilOnly);
|
||||
|
||||
ExpectDepthData(depthStencilTexture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight,
|
||||
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, //
|
||||
});
|
||||
ExpectAttachmentDepthTestData(depthStencilTexture, wgpu::TextureFormat::Depth24PlusStencil8,
|
||||
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, //
|
||||
});
|
||||
}
|
||||
|
||||
DAWN_INSTANTIATE_TEST(DepthStencilCopyTests,
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
// Copyright 2021 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/DawnTest.h"
|
||||
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/WGPUHelpers.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using Format = wgpu::TextureFormat;
|
||||
enum class Check {
|
||||
CopyStencil,
|
||||
StencilTest,
|
||||
CopyDepth,
|
||||
DepthTest,
|
||||
SampleDepth,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, Check check) {
|
||||
switch (check) {
|
||||
case Check::CopyStencil:
|
||||
o << "CopyStencil";
|
||||
break;
|
||||
case Check::StencilTest:
|
||||
o << "StencilTest";
|
||||
break;
|
||||
case Check::CopyDepth:
|
||||
o << "CopyDepth";
|
||||
break;
|
||||
case Check::DepthTest:
|
||||
o << "DepthTest";
|
||||
break;
|
||||
case Check::SampleDepth:
|
||||
o << "SampleDepth";
|
||||
break;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
DAWN_TEST_PARAM_STRUCT(DepthStencilLoadOpTestParams, Format, Check)
|
||||
|
||||
constexpr static uint32_t kRTSize = 16;
|
||||
constexpr uint32_t kMipLevelCount = 2u;
|
||||
constexpr std::array<float, kMipLevelCount> kDepthValues = {0.125f, 0.875f};
|
||||
constexpr std::array<uint8_t, kMipLevelCount> kStencilValues = {7u, 3u};
|
||||
|
||||
class DepthStencilLoadOpTests : public DawnTestWithParams<DepthStencilLoadOpTestParams> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
DawnTestWithParams<DepthStencilLoadOpTestParams>::SetUp();
|
||||
|
||||
// TODO(crbug.com/tint/827): HLSL writer produces invalid code.
|
||||
DAWN_SUPPRESS_TEST_IF(IsD3D12() && HasToggleEnabled("use_tint_generator") &&
|
||||
GetParam().mCheck == Check::SampleDepth);
|
||||
|
||||
// Readback of Depth/Stencil textures not fully supported on GL right now.
|
||||
// Also depends on glTextureView which is not supported on ES.
|
||||
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
|
||||
|
||||
wgpu::TextureDescriptor descriptor;
|
||||
descriptor.size = {kRTSize, kRTSize};
|
||||
descriptor.format = GetParam().mFormat;
|
||||
descriptor.mipLevelCount = kMipLevelCount;
|
||||
descriptor.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::CopySrc |
|
||||
wgpu::TextureUsage::Sampled;
|
||||
|
||||
texture = device.CreateTexture(&descriptor);
|
||||
|
||||
wgpu::TextureViewDescriptor textureViewDesc = {};
|
||||
textureViewDesc.mipLevelCount = 1;
|
||||
|
||||
for (uint32_t mipLevel = 0; mipLevel < kMipLevelCount; ++mipLevel) {
|
||||
textureViewDesc.baseMipLevel = mipLevel;
|
||||
textureViews[mipLevel] = texture.CreateView(&textureViewDesc);
|
||||
|
||||
utils::ComboRenderPassDescriptor renderPassDescriptor({}, textureViews[mipLevel]);
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth =
|
||||
kDepthValues[mipLevel];
|
||||
renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil =
|
||||
kStencilValues[mipLevel];
|
||||
renderPassDescriptors.push_back(renderPassDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckMipLevel(uint32_t mipLevel) {
|
||||
uint32_t mipSize = std::max(kRTSize >> mipLevel, 1u);
|
||||
|
||||
switch (GetParam().mCheck) {
|
||||
case Check::SampleDepth: {
|
||||
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
|
||||
ExpectSampledDepthData(texture, mipSize, mipSize, 0, mipLevel, expectedDepth)
|
||||
<< "sample depth mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
case Check::CopyDepth: {
|
||||
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
|
||||
EXPECT_TEXTURE_EQ(expectedDepth.data(), texture, {0, 0}, {mipSize, mipSize},
|
||||
mipLevel, wgpu::TextureAspect::DepthOnly)
|
||||
<< "copy depth mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
case Check::CopyStencil: {
|
||||
std::vector<uint8_t> expectedStencil(mipSize * mipSize,
|
||||
kStencilValues[mipLevel]);
|
||||
EXPECT_TEXTURE_EQ(expectedStencil.data(), texture, {0, 0}, {mipSize, mipSize},
|
||||
mipLevel, wgpu::TextureAspect::StencilOnly)
|
||||
<< "copy stencil mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
case Check::DepthTest: {
|
||||
std::vector<float> expectedDepth(mipSize * mipSize, kDepthValues[mipLevel]);
|
||||
ExpectAttachmentDepthTestData(texture, GetParam().mFormat, mipSize, mipSize, 0,
|
||||
mipLevel, expectedDepth)
|
||||
<< "depth test mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
|
||||
case Check::StencilTest: {
|
||||
ExpectAttachmentStencilTestData(texture, GetParam().mFormat, mipSize, mipSize,
|
||||
0, mipLevel, kStencilValues[mipLevel])
|
||||
<< "stencil test mip " << mipLevel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wgpu::Texture texture;
|
||||
std::array<wgpu::TextureView, kMipLevelCount> textureViews;
|
||||
// Vector instead of array because there is no default constructor.
|
||||
std::vector<utils::ComboRenderPassDescriptor> renderPassDescriptors;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Check that clearing a mip level works at all.
|
||||
TEST_P(DepthStencilLoadOpTests, ClearMip0) {
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[0]).EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
CheckMipLevel(0u);
|
||||
}
|
||||
|
||||
// Check that clearing a non-zero mip level works at all.
|
||||
TEST_P(DepthStencilLoadOpTests, ClearMip1) {
|
||||
// TODO(crbug.com/dawn/838): Sampling from the non-zero mip does not work.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && GetParam().mCheck == Check::SampleDepth);
|
||||
|
||||
// TODO(crbug.com/dawn/838): Copying from the non-zero mip here sometimes returns uninitialized
|
||||
// data! (from mip 0 of a previous test run).
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && GetParam().mCheck == Check::CopyDepth);
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && GetParam().mCheck == Check::CopyStencil);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[1]).EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
CheckMipLevel(1u);
|
||||
}
|
||||
|
||||
// Clear first mip then the second mip. Check both mip levels.
|
||||
TEST_P(DepthStencilLoadOpTests, ClearBothMip0Then1) {
|
||||
// TODO(crbug.com/dawn/838): Sampling from the non-zero mip does not work.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && GetParam().mCheck == Check::SampleDepth);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[0]).EndPass();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[1]).EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
CheckMipLevel(0u);
|
||||
CheckMipLevel(1u);
|
||||
}
|
||||
|
||||
// Clear second mip then the first mip. Check both mip levels.
|
||||
TEST_P(DepthStencilLoadOpTests, ClearBothMip1Then0) {
|
||||
// TODO(crbug.com/dawn/838): Sampling from the non-zero mip does not work.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsIntel() && GetParam().mCheck == Check::SampleDepth);
|
||||
|
||||
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[1]).EndPass();
|
||||
encoder.BeginRenderPass(&renderPassDescriptors[0]).EndPass();
|
||||
wgpu::CommandBuffer commandBuffer = encoder.Finish();
|
||||
queue.Submit(1, &commandBuffer);
|
||||
|
||||
CheckMipLevel(0u);
|
||||
CheckMipLevel(1u);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
auto GenerateParams() {
|
||||
auto params1 = MakeParamGenerator<DepthStencilLoadOpTestParams>(
|
||||
{D3D12Backend(), D3D12Backend({}, {"use_d3d12_render_pass"}), MetalBackend(),
|
||||
OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
|
||||
{wgpu::TextureFormat::Depth32Float},
|
||||
{Check::CopyDepth, Check::DepthTest, Check::SampleDepth});
|
||||
|
||||
auto params2 = MakeParamGenerator<DepthStencilLoadOpTestParams>(
|
||||
{D3D12Backend(), D3D12Backend({}, {"use_d3d12_render_pass"}), MetalBackend(),
|
||||
OpenGLBackend(), OpenGLESBackend(), VulkanBackend()},
|
||||
{wgpu::TextureFormat::Depth24PlusStencil8},
|
||||
{Check::CopyStencil, Check::StencilTest, Check::DepthTest, Check::SampleDepth});
|
||||
|
||||
std::vector<DepthStencilLoadOpTestParams> allParams;
|
||||
allParams.insert(allParams.end(), params1.begin(), params1.end());
|
||||
allParams.insert(allParams.end(), params2.begin(), params2.end());
|
||||
|
||||
return allParams;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(,
|
||||
DepthStencilLoadOpTests,
|
||||
::testing::ValuesIn(GenerateParams()),
|
||||
DawnTestBase::PrintToStringParamName("DepthStencilLoadOpTests"));
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DepthStencilLoadOpTests);
|
||||
|
||||
} // namespace
|
Loading…
Reference in New Issue