dawn-cmake/src/tests/end2end/DepthStencilSamplingTests.cpp
Stephen White 6f5151f657 Enable D* end-to-end tests on OpenGL ES backend.
This is mostly the set of tests which are enabled on Desktop GL,
with the exception of tests which use glTextureView() (unsupported
on GLES).

BUG=dawn:580

Change-Id: I1dbefa394298f7dd31d65e920f1f4efeaebe90ec
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/34520
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
2020-12-01 21:52:37 +00:00

774 lines
33 KiB
C++

// Copyright 2020 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 "common/Assert.h"
#include "tests/DawnTest.h"
#include "utils/ComboRenderPipelineDescriptor.h"
#include "utils/WGPUHelpers.h"
namespace {
constexpr wgpu::TextureFormat kDepthFormats[] = {
wgpu::TextureFormat::Depth32Float,
wgpu::TextureFormat::Depth24Plus,
wgpu::TextureFormat::Depth24PlusStencil8,
};
constexpr wgpu::TextureFormat kStencilFormats[] = {
wgpu::TextureFormat::Depth24PlusStencil8,
};
constexpr wgpu::CompareFunction kCompareFunctions[] = {
wgpu::CompareFunction::Never, wgpu::CompareFunction::Less,
wgpu::CompareFunction::LessEqual, wgpu::CompareFunction::Greater,
wgpu::CompareFunction::GreaterEqual, wgpu::CompareFunction::Equal,
wgpu::CompareFunction::NotEqual, wgpu::CompareFunction::Always,
};
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
constexpr float kCompareRefs[] = {-0.1, 0.4, 1.2};
// Test 0, below the ref, equal to, above the ref, and 1.
const std::vector<float> kNormalizedTextureValues = {0.0, 0.3, 0.4, 0.5, 1.0};
// Test the limits, and some values in between.
const std::vector<uint8_t> kStencilValues = {uint8_t(0), uint8_t(1), uint8_t(38), uint8_t(255),
uint8_t(256)};
} // anonymous namespace
class DepthStencilSamplingTest : public DawnTest {
protected:
enum class TestAspect {
Depth,
Stencil,
};
void SetUp() override {
DawnTest::SetUp();
wgpu::BufferDescriptor uniformBufferDesc;
uniformBufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst;
uniformBufferDesc.size = sizeof(float);
mUniformBuffer = device.CreateBuffer(&uniformBufferDesc);
}
wgpu::RenderPipeline CreateSamplingRenderPipeline(std::vector<TestAspect> aspects,
uint32_t componentIndex) {
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0;
}
)");
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
std::ostringstream shaderSource;
std::ostringstream shaderBody;
shaderSource << R"(
#version 450
layout(set = 0, binding = 0) uniform sampler samp;
)";
uint32_t index = 0;
for (TestAspect aspect : aspects) {
switch (aspect) {
case TestAspect::Depth:
shaderSource << "layout(set = 0, binding = " << 1 + index
<< ") uniform texture2D tex" << index << ";\n";
shaderSource << "layout(location = " << index << ") out float result" << index
<< ";\n";
shaderBody << "result" << index << " = texture(sampler2D(tex" << index
<< ", samp), vec2(0.5, 0.5))[" << componentIndex << "];\n";
pipelineDescriptor.cColorStates[index].format = wgpu::TextureFormat::R32Float;
break;
case TestAspect::Stencil:
shaderSource << "layout(set = 0, binding = " << 1 + index
<< ") uniform utexture2D tex" << index << ";\n";
shaderSource << "layout(location = " << index << ") out uint result" << index
<< ";\n";
shaderBody << "result" << index << " = texelFetch(usampler2D(tex" << index
<< ", samp), ivec2(0, 0), 0)[" << componentIndex << "];\n";
pipelineDescriptor.cColorStates[index].format = wgpu::TextureFormat::R8Uint;
break;
}
index++;
}
shaderSource << "void main() { " << shaderBody.str() << " }";
wgpu::ShaderModule fsModule = utils::CreateShaderModule(
device, utils::SingleShaderStage::Fragment, shaderSource.str().c_str());
pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.cFragmentStage.module = fsModule;
pipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
pipelineDescriptor.colorStateCount = static_cast<uint32_t>(aspects.size());
return device.CreateRenderPipeline(&pipelineDescriptor);
}
wgpu::ComputePipeline CreateSamplingComputePipeline(std::vector<TestAspect> aspects,
uint32_t componentIndex) {
std::ostringstream shaderSource;
std::ostringstream shaderBody;
shaderSource << R"(
#version 450
layout(set = 0, binding = 0) uniform sampler samp;
)";
uint32_t index = 0;
for (TestAspect aspect : aspects) {
switch (aspect) {
case TestAspect::Depth:
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index
<< ") uniform texture2D tex" << index << ";\n";
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index + 1
<< ") writeonly buffer Result" << index << " {\n"
<< " float result" << index << ";\n"
<< "};\n";
shaderBody << "result" << index << " = texture(sampler2D(tex" << index
<< ", samp), vec2(0.5, 0.5))[" << componentIndex << "];\n";
break;
case TestAspect::Stencil:
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index
<< ") uniform utexture2D tex" << index << ";\n";
shaderSource << "layout(set = 0, binding = " << 1 + 2 * index + 1
<< ") writeonly buffer Result" << index << " {\n"
<< " uint result" << index << ";\n"
<< "};\n";
shaderBody << "result" << index << " = texelFetch(usampler2D(tex" << index
<< ", samp), ivec2(0, 0), 0)[" << componentIndex << "];\n";
break;
}
index++;
}
shaderSource << "void main() { " << shaderBody.str() << " }";
wgpu::ShaderModule csModule = utils::CreateShaderModule(
device, utils::SingleShaderStage::Compute, shaderSource.str().c_str());
wgpu::ComputePipelineDescriptor pipelineDescriptor;
pipelineDescriptor.computeStage.module = csModule;
pipelineDescriptor.computeStage.entryPoint = "main";
return device.CreateComputePipeline(&pipelineDescriptor);
}
wgpu::RenderPipeline CreateComparisonRenderPipeline() {
wgpu::ShaderModule vsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Vertex, R"(
#version 450
void main() {
gl_Position = vec4(0.f, 0.f, 0.f, 1.f);
gl_PointSize = 1.0;
}
)");
wgpu::ShaderModule fsModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"(
#version 450
layout(set = 0, binding = 0) uniform samplerShadow samp;
layout(set = 0, binding = 1) uniform texture2D tex;
layout(set = 0, binding = 2) uniform Uniforms {
float compareRef;
};
layout(location = 0) out float samplerResult;
void main() {
samplerResult = texture(sampler2DShadow(tex, samp), vec3(0.5, 0.5, compareRef));
}
)");
// TODO(dawn:367): Cannot use GetBindGroupLayout for comparison samplers without shader
// reflection data.
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture, false, 0,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison},
{2, wgpu::ShaderStage::Fragment, wgpu::BindingType::UniformBuffer}});
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
pipelineDescriptor.vertexStage.module = vsModule;
pipelineDescriptor.cFragmentStage.module = fsModule;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
pipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList;
pipelineDescriptor.cColorStates[0].format = wgpu::TextureFormat::R32Float;
return device.CreateRenderPipeline(&pipelineDescriptor);
}
wgpu::ComputePipeline CreateComparisonComputePipeline() {
wgpu::ShaderModule csModule =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
layout(set = 0, binding = 0) uniform samplerShadow samp;
layout(set = 0, binding = 1) uniform texture2D tex;
layout(set = 0, binding = 2) uniform Uniforms {
float compareRef;
};
layout(set = 0, binding = 3) writeonly buffer SamplerResult {
float samplerResult;
};
void main() {
samplerResult = texture(sampler2DShadow(tex, samp), vec3(0.5, 0.5, compareRef));
}
)");
// TODO(dawn:367): Cannot use GetBindGroupLayout without shader reflection data.
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Compute, wgpu::BindingType::ComparisonSampler},
{1, wgpu::ShaderStage::Compute, wgpu::BindingType::SampledTexture, false, 0,
wgpu::TextureViewDimension::e2D, wgpu::TextureComponentType::DepthComparison},
{2, wgpu::ShaderStage::Compute, wgpu::BindingType::UniformBuffer},
{3, wgpu::ShaderStage::Compute, wgpu::BindingType::StorageBuffer}});
wgpu::ComputePipelineDescriptor pipelineDescriptor;
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
pipelineDescriptor.computeStage.module = csModule;
pipelineDescriptor.computeStage.entryPoint = "main";
return device.CreateComputePipeline(&pipelineDescriptor);
}
wgpu::Texture CreateInputTexture(wgpu::TextureFormat format) {
wgpu::TextureDescriptor inputTextureDesc;
inputTextureDesc.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::OutputAttachment;
inputTextureDesc.size = {1, 1, 1};
inputTextureDesc.format = format;
return device.CreateTexture(&inputTextureDesc);
}
wgpu::Texture CreateOutputTexture(wgpu::TextureFormat format) {
wgpu::TextureDescriptor outputTextureDesc;
outputTextureDesc.usage =
wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
outputTextureDesc.size = {1, 1, 1};
outputTextureDesc.format = format;
return device.CreateTexture(&outputTextureDesc);
}
wgpu::Buffer CreateOutputBuffer() {
wgpu::BufferDescriptor outputBufferDesc;
outputBufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
outputBufferDesc.size = sizeof(float); // Large enough for both float and uint8_t
return device.CreateBuffer(&outputBufferDesc);
}
void UpdateInputDepth(wgpu::CommandEncoder commandEncoder,
wgpu::Texture texture,
float depthValue) {
utils::ComboRenderPassDescriptor passDescriptor({}, texture.CreateView());
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = depthValue;
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.EndPass();
}
void UpdateInputStencil(wgpu::CommandEncoder commandEncoder,
wgpu::Texture texture,
uint8_t stencilValue) {
utils::ComboRenderPassDescriptor passDescriptor({}, texture.CreateView());
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = stencilValue;
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.EndPass();
}
template <typename T>
void DoSamplingTest(TestAspect aspect,
wgpu::RenderPipeline pipeline,
wgpu::TextureFormat format,
std::vector<T> textureValues,
std::vector<T> expectedValues) {
ASSERT(textureValues.size() == expectedValues.size());
wgpu::SamplerDescriptor samplerDesc;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::Texture outputTexture;
wgpu::Texture inputTexture = CreateInputTexture(format);
wgpu::TextureViewDescriptor inputViewDesc = {};
switch (aspect) {
case TestAspect::Depth:
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
outputTexture = CreateOutputTexture(wgpu::TextureFormat::R32Float);
break;
case TestAspect::Stencil:
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
outputTexture = CreateOutputTexture(wgpu::TextureFormat::R8Uint);
break;
}
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, sampler},
{1, inputTexture.CreateView(&inputViewDesc)},
});
for (size_t i = 0; i < textureValues.size(); ++i) {
// Set the input depth texture to the provided texture value
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
switch (aspect) {
case TestAspect::Depth:
UpdateInputDepth(commandEncoder, inputTexture, textureValues[i]);
break;
case TestAspect::Stencil:
UpdateInputStencil(commandEncoder, inputTexture, textureValues[i]);
break;
}
// Render into the output texture
{
utils::ComboRenderPassDescriptor passDescriptor({outputTexture.CreateView()});
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
EXPECT_TEXTURE_EQ(expectedValues[i], outputTexture, 0, 0);
}
}
template <typename T>
void DoSamplingTest(TestAspect aspect,
wgpu::ComputePipeline pipeline,
wgpu::TextureFormat format,
std::vector<T> textureValues,
std::vector<T> expectedValues) {
ASSERT(textureValues.size() == expectedValues.size());
wgpu::SamplerDescriptor samplerDesc;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::Texture inputTexture = CreateInputTexture(format);
wgpu::TextureViewDescriptor inputViewDesc = {};
switch (aspect) {
case TestAspect::Depth:
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
break;
case TestAspect::Stencil:
inputViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
break;
}
wgpu::Buffer outputBuffer = CreateOutputBuffer();
wgpu::BindGroup bindGroup = utils::MakeBindGroup(
device, pipeline.GetBindGroupLayout(0),
{{0, sampler}, {1, inputTexture.CreateView(&inputViewDesc)}, {2, outputBuffer}});
for (size_t i = 0; i < textureValues.size(); ++i) {
// Set the input depth texture to the provided texture value
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
switch (aspect) {
case TestAspect::Depth:
UpdateInputDepth(commandEncoder, inputTexture, textureValues[i]);
break;
case TestAspect::Stencil:
UpdateInputStencil(commandEncoder, inputTexture, textureValues[i]);
break;
}
// Sample into the output buffer
{
wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
uint32_t expectedValueU32 = 0;
memcpy(&expectedValueU32, &expectedValues[i], std::min(sizeof(T), sizeof(uint32_t)));
EXPECT_BUFFER_U32_EQ(expectedValueU32, outputBuffer, 0);
}
}
template <typename T>
void DoSamplingTest(TestAspect aspect,
wgpu::RenderPipeline pipeline,
wgpu::TextureFormat format,
std::vector<T> textureValues) {
DoSamplingTest(aspect, pipeline, format, textureValues, textureValues);
}
template <typename T>
void DoSamplingTest(TestAspect aspect,
wgpu::ComputePipeline pipeline,
wgpu::TextureFormat format,
std::vector<T> textureValues) {
DoSamplingTest(aspect, pipeline, format, textureValues, textureValues);
}
static bool CompareFunctionPasses(float compareRef,
wgpu::CompareFunction compare,
float textureValue) {
switch (compare) {
case wgpu::CompareFunction::Never:
return false;
case wgpu::CompareFunction::Less:
return compareRef < textureValue;
case wgpu::CompareFunction::LessEqual:
return compareRef <= textureValue;
case wgpu::CompareFunction::Greater:
return compareRef > textureValue;
case wgpu::CompareFunction::GreaterEqual:
return compareRef >= textureValue;
case wgpu::CompareFunction::Equal:
return compareRef == textureValue;
case wgpu::CompareFunction::NotEqual:
return compareRef != textureValue;
case wgpu::CompareFunction::Always:
return true;
default:
return false;
}
}
void DoDepthCompareRefTest(wgpu::RenderPipeline pipeline,
wgpu::TextureFormat format,
float compareRef,
wgpu::CompareFunction compare,
std::vector<float> textureValues) {
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
wgpu::SamplerDescriptor samplerDesc;
samplerDesc.compare = compare;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::Texture inputTexture = CreateInputTexture(format);
wgpu::TextureViewDescriptor inputViewDesc = {};
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, sampler},
{1, inputTexture.CreateView(&inputViewDesc)},
{2, mUniformBuffer},
});
wgpu::Texture outputTexture = CreateOutputTexture(wgpu::TextureFormat::R32Float);
for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
UpdateInputDepth(commandEncoder, inputTexture, textureValue);
// Render into the output texture
{
utils::ComboRenderPassDescriptor passDescriptor({outputTexture.CreateView()});
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
EXPECT_TEXTURE_EQ(CompareFunctionPasses(compareRef, compare, textureValue) ? 1.f : 0.f,
outputTexture, 0, 0);
}
}
void DoDepthCompareRefTest(wgpu::ComputePipeline pipeline,
wgpu::TextureFormat format,
float compareRef,
wgpu::CompareFunction compare,
std::vector<float> textureValues) {
queue.WriteBuffer(mUniformBuffer, 0, &compareRef, sizeof(float));
wgpu::SamplerDescriptor samplerDesc;
samplerDesc.compare = compare;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::Texture inputTexture = CreateInputTexture(format);
wgpu::TextureViewDescriptor inputViewDesc = {};
inputViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
wgpu::Buffer outputBuffer = CreateOutputBuffer();
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampler},
{1, inputTexture.CreateView(&inputViewDesc)},
{2, mUniformBuffer},
{3, outputBuffer}});
for (float textureValue : textureValues) {
// Set the input depth texture to the provided texture value
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
UpdateInputDepth(commandEncoder, inputTexture, textureValue);
// Sample into the output buffer
{
wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
float float0 = 0.f;
float float1 = 1.f;
float* expected =
CompareFunctionPasses(compareRef, compare, textureValue) ? &float1 : &float0;
EXPECT_BUFFER_U32_EQ(*reinterpret_cast<uint32_t*>(expected), outputBuffer, 0);
}
}
private:
wgpu::Buffer mUniformBuffer;
};
// Test that sampling a depth texture with a render/compute pipeline works
TEST_P(DepthStencilSamplingTest, SampleDepth) {
for (wgpu::TextureFormat format : kDepthFormats) {
// Test 0, between [0, 1], and 1.
DoSamplingTest(TestAspect::Depth, CreateSamplingRenderPipeline({TestAspect::Depth}, 0),
format, kNormalizedTextureValues);
DoSamplingTest(TestAspect::Depth, CreateSamplingComputePipeline({TestAspect::Depth}, 0),
format, kNormalizedTextureValues);
}
}
// Test that sampling a stencil texture with a render/compute pipeline works
TEST_P(DepthStencilSamplingTest, SampleStencil) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
DAWN_SKIP_TEST_IF(IsOpenGLES());
for (wgpu::TextureFormat format : kStencilFormats) {
DoSamplingTest(TestAspect::Stencil, CreateSamplingRenderPipeline({TestAspect::Stencil}, 0),
format, kStencilValues);
DoSamplingTest(TestAspect::Stencil, CreateSamplingComputePipeline({TestAspect::Stencil}, 0),
format, kStencilValues);
}
}
// Test that sampling a depth/stencil texture at components 1, 2, and 3 yield 0, 0, and 1
// respectively
TEST_P(DepthStencilSamplingTest, SampleExtraComponents) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
DAWN_SKIP_TEST_IF(IsOpenGLES());
// TODO(enga): In Metal, color textures' unspecified default components values
// are (0, 0, 0, 1). Depth/stencil textures are undefined! Figure out what
// to do here.
// See Section 6.10 of the Metal Shading Language Specification
DAWN_SKIP_TEST_IF(IsMetal());
float expectedDepth[4] = {0, 0, 0, 1};
uint8_t expectedStencil[4] = {0, 0, 0, 1};
for (uint32_t component : {1, 2, 3}) {
DoSamplingTest<float>(
TestAspect::Depth, CreateSamplingRenderPipeline({TestAspect::Depth}, component),
wgpu::TextureFormat::Depth24PlusStencil8, {0.2f}, {expectedDepth[component]});
DoSamplingTest<float>(
TestAspect::Depth, CreateSamplingComputePipeline({TestAspect::Depth}, component),
wgpu::TextureFormat::Depth24PlusStencil8, {0.2f}, {expectedDepth[component]});
DoSamplingTest<uint8_t>(
TestAspect::Stencil, CreateSamplingRenderPipeline({TestAspect::Stencil}, component),
wgpu::TextureFormat::Depth24PlusStencil8, {uint8_t(37)}, {expectedStencil[component]});
DoSamplingTest<uint8_t>(
TestAspect::Stencil, CreateSamplingComputePipeline({TestAspect::Stencil}, component),
wgpu::TextureFormat::Depth24PlusStencil8, {uint8_t(37)}, {expectedStencil[component]});
}
}
// Test sampling both depth and stencil with a render/compute pipeline works.
TEST_P(DepthStencilSamplingTest, SampleDepthAndStencilRender) {
// TODO(crbug.com/dawn/593): This test requires glTextureView, which is unsupported on GLES.
DAWN_SKIP_TEST_IF(IsOpenGLES());
wgpu::SamplerDescriptor samplerDesc;
wgpu::Sampler sampler = device.CreateSampler(&samplerDesc);
wgpu::Texture inputTexture = CreateInputTexture(wgpu::TextureFormat::Depth24PlusStencil8);
wgpu::TextureViewDescriptor depthViewDesc = {};
depthViewDesc.aspect = wgpu::TextureAspect::DepthOnly;
wgpu::TextureViewDescriptor stencilViewDesc = {};
stencilViewDesc.aspect = wgpu::TextureAspect::StencilOnly;
// With render pipeline
{
wgpu::RenderPipeline pipeline =
CreateSamplingRenderPipeline({TestAspect::Depth, TestAspect::Stencil}, 0);
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{
{0, sampler},
{1, inputTexture.CreateView(&depthViewDesc)},
{2, inputTexture.CreateView(&stencilViewDesc)},
});
wgpu::Texture depthOutput = CreateOutputTexture(wgpu::TextureFormat::R32Float);
wgpu::Texture stencilOutput = CreateOutputTexture(wgpu::TextureFormat::R8Uint);
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
// Initialize both depth and stencil aspects.
utils::ComboRenderPassDescriptor passDescriptor({}, inputTexture.CreateView());
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.43f;
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = 31;
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.EndPass();
// Render into the output textures
{
utils::ComboRenderPassDescriptor passDescriptor(
{depthOutput.CreateView(), stencilOutput.CreateView()});
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
EXPECT_TEXTURE_EQ(passDescriptor.cDepthStencilAttachmentInfo.clearDepth, depthOutput, 0, 0);
EXPECT_TEXTURE_EQ(uint8_t(passDescriptor.cDepthStencilAttachmentInfo.clearStencil),
stencilOutput, 0, 0);
}
// With compute pipeline
{
wgpu::ComputePipeline pipeline =
CreateSamplingComputePipeline({TestAspect::Depth, TestAspect::Stencil}, 0);
wgpu::Buffer depthOutput = CreateOutputBuffer();
wgpu::Buffer stencilOutput = CreateOutputBuffer();
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampler},
{1, inputTexture.CreateView(&depthViewDesc)},
{2, depthOutput},
{3, inputTexture.CreateView(&stencilViewDesc)},
{4, stencilOutput}});
wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder();
// Initialize both depth and stencil aspects.
utils::ComboRenderPassDescriptor passDescriptor({}, inputTexture.CreateView());
passDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.43f;
passDescriptor.cDepthStencilAttachmentInfo.clearStencil = 31;
wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor);
pass.EndPass();
// Sample into the output buffers
{
wgpu::ComputePassEncoder pass = commandEncoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1);
pass.EndPass();
}
wgpu::CommandBuffer commands = commandEncoder.Finish();
queue.Submit(1, &commands);
uint32_t expectedValueU32 = 0;
memcpy(&expectedValueU32, &passDescriptor.cDepthStencilAttachmentInfo.clearDepth,
sizeof(float));
EXPECT_BUFFER_U32_EQ(expectedValueU32, depthOutput, 0);
expectedValueU32 = 0;
memcpy(&expectedValueU32, &passDescriptor.cDepthStencilAttachmentInfo.clearStencil,
sizeof(uint8_t));
EXPECT_BUFFER_U32_EQ(expectedValueU32, stencilOutput, 0);
}
}
// Test that sampling in a render pipeline with all of the compare functions works.
TEST_P(DepthStencilSamplingTest, CompareFunctionsRender) {
// Initialization via renderPass loadOp doesn't work on Mac Intel.
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
wgpu::RenderPipeline pipeline = CreateComparisonRenderPipeline();
for (wgpu::TextureFormat format : kDepthFormats) {
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
for (float compareRef : kCompareRefs) {
// Test 0, below the ref, equal to, above the ref, and 1.
for (wgpu::CompareFunction f : kCompareFunctions) {
DoDepthCompareRefTest(pipeline, format, compareRef, f, kNormalizedTextureValues);
}
}
}
}
// Test that sampling in a render pipeline with all of the compare functions works.
TEST_P(DepthStencilSamplingTest, CompareFunctionsCompute) {
// Initialization via renderPass loadOp doesn't work on Mac Intel.
DAWN_SKIP_TEST_IF(IsMetal() && IsIntel());
wgpu::ComputePipeline pipeline = CreateComparisonComputePipeline();
for (wgpu::TextureFormat format : kDepthFormats) {
// Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs.
for (float compareRef : kCompareRefs) {
// Test 0, below the ref, equal to, above the ref, and 1.
for (wgpu::CompareFunction f : kCompareFunctions) {
DoDepthCompareRefTest(pipeline, format, compareRef, f, kNormalizedTextureValues);
}
}
}
}
DAWN_INSTANTIATE_TEST(DepthStencilSamplingTest,
D3D12Backend(),
MetalBackend(),
OpenGLBackend(),
OpenGLESBackend(),
VulkanBackend());