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/DeprecatedAPITests.cpp",
|
||||||
"end2end/DepthBiasTests.cpp",
|
"end2end/DepthBiasTests.cpp",
|
||||||
"end2end/DepthStencilCopyTests.cpp",
|
"end2end/DepthStencilCopyTests.cpp",
|
||||||
|
"end2end/DepthStencilLoadOpTests.cpp",
|
||||||
"end2end/DepthStencilSamplingTests.cpp",
|
"end2end/DepthStencilSamplingTests.cpp",
|
||||||
"end2end/DepthStencilStateTests.cpp",
|
"end2end/DepthStencilStateTests.cpp",
|
||||||
"end2end/DestroyTests.cpp",
|
"end2end/DestroyTests.cpp",
|
||||||
|
|
|
@ -1144,7 +1144,137 @@ std::ostringstream& DawnTestBase::ExpectSampledDepthData(wgpu::Texture texture,
|
||||||
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
wgpu::CommandBuffer commands = commandEncoder.Finish();
|
||||||
queue.Submit(1, &commands);
|
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() {
|
void DawnTestBase::WaitABit() {
|
||||||
|
@ -1301,27 +1431,53 @@ namespace detail {
|
||||||
// Helper classes to set expectations
|
// Helper classes to set expectations
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ExpectEq<T>::ExpectEq(T singleValue) {
|
ExpectEq<T>::ExpectEq(T singleValue, T tolerance) : mTolerance(tolerance) {
|
||||||
mExpected.push_back(singleValue);
|
mExpected.push_back(singleValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
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>
|
template <typename T>
|
||||||
testing::AssertionResult ExpectEq<T>::Check(const void* data, size_t size) {
|
testing::AssertionResult ExpectEq<T>::Check(const void* data, size_t size) {
|
||||||
DAWN_ASSERT(size == sizeof(T) * mExpected.size());
|
DAWN_ASSERT(size == sizeof(T) * mExpected.size());
|
||||||
|
|
||||||
const T* actual = static_cast<const T*>(data);
|
const T* actual = static_cast<const T*>(data);
|
||||||
|
|
||||||
for (size_t i = 0; i < mExpected.size(); ++i) {
|
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()
|
testing::AssertionResult result = testing::AssertionFailure()
|
||||||
<< "Expected data[" << i << "] to be "
|
<< "Expected data[" << i << "] to be "
|
||||||
<< mExpected[i] << ", actual " << actual[i]
|
<< check.message() << std::endl;
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
if (mExpected.size() <= 1024) {
|
if (mExpected.size() <= 1024) {
|
||||||
result << "Expected:" << std::endl;
|
result << "Expected:" << std::endl;
|
||||||
|
@ -1334,7 +1490,6 @@ namespace detail {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return testing::AssertionSuccess();
|
return testing::AssertionSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,10 @@
|
||||||
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
EXPECT_BUFFER(buffer, offset, sizeof(float) * (count), \
|
||||||
new ::detail::ExpectEq<float>(expected, 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.
|
// Test a pixel of the mip level 0 of a 2D texture.
|
||||||
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
|
#define EXPECT_PIXEL_RGBA8_EQ(expected, texture, x, y) \
|
||||||
AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
|
AddTextureExpectation(__FILE__, __LINE__, expected, texture, {x, y})
|
||||||
|
@ -408,6 +412,42 @@ class DawnTestBase {
|
||||||
uint32_t mipLevel,
|
uint32_t mipLevel,
|
||||||
const std::vector<float>& expected);
|
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 WaitABit();
|
||||||
void FlushWire();
|
void FlushWire();
|
||||||
void WaitForAllOperations();
|
void WaitForAllOperations();
|
||||||
|
@ -630,13 +670,14 @@ namespace detail {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ExpectEq : public Expectation {
|
class ExpectEq : public Expectation {
|
||||||
public:
|
public:
|
||||||
ExpectEq(T singleValue);
|
ExpectEq(T singleValue, T tolerance = {});
|
||||||
ExpectEq(const T* values, const unsigned int count);
|
ExpectEq(const T* values, const unsigned int count, T tolerance = {});
|
||||||
|
|
||||||
testing::AssertionResult Check(const void* data, size_t size) override;
|
testing::AssertionResult Check(const void* data, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<T> mExpected;
|
std::vector<T> mExpected;
|
||||||
|
T mTolerance;
|
||||||
};
|
};
|
||||||
extern template class ExpectEq<uint8_t>;
|
extern template class ExpectEq<uint8_t>;
|
||||||
extern template class ExpectEq<int16_t>;
|
extern template class ExpectEq<int16_t>;
|
||||||
|
|
|
@ -182,126 +182,6 @@ class DepthStencilCopyTests : public DawnTest {
|
||||||
return dst;
|
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;
|
wgpu::ShaderModule mVertexModule;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -481,13 +361,14 @@ TEST_P(DepthStencilCopyTests, T2TBothAspectsThenCopyDepth) {
|
||||||
0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::RenderAttachment);
|
0.1f, 0.3f, 1u, 3u, kWidth, kHeight, wgpu::TextureUsage::RenderAttachment);
|
||||||
|
|
||||||
// Check the depth
|
// Check the depth
|
||||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
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.1, 0.1, 0.1, 0.1, //
|
||||||
0.3, 0.3, 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, //
|
||||||
});
|
0.3, 0.3, 0.1, 0.1, //
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test copying both aspects in a T2T copy, then copying only depth at a nonzero mip.
|
// 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);
|
0.1f, 0.3f, 1u, 3u, 8, 8, wgpu::TextureUsage::RenderAttachment, 1);
|
||||||
|
|
||||||
// Check the depth
|
// Check the depth
|
||||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, 4, 4, 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.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, //
|
||||||
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
|
// 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);
|
wgpu::TextureAspect::StencilOnly);
|
||||||
|
|
||||||
// Check the depth
|
// Check the depth
|
||||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
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.1, 0.1, 0.1, 0.1, //
|
||||||
0.3, 0.3, 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, //
|
||||||
});
|
0.3, 0.3, 0.1, 0.1, //
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test copying both aspects in a T2T copy, then copying depth, then copying stencil
|
// 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);
|
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
|
||||||
|
|
||||||
// Check the depth
|
// Check the depth
|
||||||
ExpectDepthData(texture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight, 0,
|
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.1, 0.1, 0.1, 0.1, //
|
||||||
0.3, 0.3, 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, //
|
||||||
});
|
0.3, 0.3, 0.1, 0.1, //
|
||||||
|
});
|
||||||
|
|
||||||
// Check the stencil
|
// Check the stencil
|
||||||
std::vector<uint8_t> expectedData = {
|
std::vector<uint8_t> expectedData = {
|
||||||
|
@ -674,14 +557,14 @@ TEST_P(DepthStencilCopyTests, ToStencilAspect) {
|
||||||
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
|
EXPECT_TEXTURE_EQ(expectedStencilData.data(), depthStencilTexture, {0, 0}, {kWidth, kHeight}, 0,
|
||||||
wgpu::TextureAspect::StencilOnly);
|
wgpu::TextureAspect::StencilOnly);
|
||||||
|
|
||||||
ExpectDepthData(depthStencilTexture, wgpu::TextureFormat::Depth24PlusStencil8, kWidth, kHeight,
|
ExpectAttachmentDepthTestData(depthStencilTexture, wgpu::TextureFormat::Depth24PlusStencil8,
|
||||||
0,
|
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, //
|
||||||
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,
|
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