mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-19 21:13:30 +00:00
This is blocking the Tint roll which adds validation that textureSampleCompare cannot be used in the compute stage. Simply disabling this test for now since WGSL discussions seem to indicate there may be a builtin added with a different name and semantics. Change-Id: Iaecf5865c9fb38aea3231c3ae823d783a665984d Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/53320 Reviewed-by: Austin Eng <enga@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
749 lines
32 KiB
C++
749 lines
32 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)};
|
|
|
|
} // 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, R"(
|
|
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
|
|
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
|
})");
|
|
|
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
|
|
|
std::ostringstream shaderSource;
|
|
std::ostringstream shaderOutputStruct;
|
|
std::ostringstream shaderBody;
|
|
|
|
uint32_t index = 0;
|
|
for (TestAspect aspect : aspects) {
|
|
switch (aspect) {
|
|
case TestAspect::Depth:
|
|
shaderSource << "[[group(0), binding(" << index << ")]] var tex" << index
|
|
<< " : texture_2d<f32>;\n";
|
|
|
|
shaderOutputStruct << " [[location(" << index << ")]] result" << index
|
|
<< " : f32;\n";
|
|
|
|
shaderBody << "\n output.result" << index << " = textureLoad(tex" << index
|
|
<< ", vec2<i32>(0, 0), 0)[" << componentIndex << "];\n";
|
|
pipelineDescriptor.cTargets[index].format = wgpu::TextureFormat::R32Float;
|
|
break;
|
|
case TestAspect::Stencil:
|
|
shaderSource << "[[group(0), binding(" << index << ")]] var tex" << index
|
|
<< " : texture_2d<u32>;\n";
|
|
|
|
shaderOutputStruct << " [[location(" << index << ")]] result" << index
|
|
<< " : u32;\n";
|
|
|
|
shaderBody << "\n output.result" << index << " = textureLoad(tex" << index
|
|
<< ", vec2<i32>(0, 0), 0)[" << componentIndex << "];\n";
|
|
pipelineDescriptor.cTargets[index].format = wgpu::TextureFormat::R8Uint;
|
|
break;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
shaderSource << "struct FragOutputs {\n" << shaderOutputStruct.str() << "};\n";
|
|
shaderSource << "[[stage(fragment)]] fn main() -> FragOutputs {\n";
|
|
shaderSource << " var output : FragOutputs;\n"
|
|
<< shaderBody.str() << " return output;\n}";
|
|
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, shaderSource.str().c_str());
|
|
pipelineDescriptor.vertex.module = vsModule;
|
|
pipelineDescriptor.cFragment.module = fsModule;
|
|
pipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::PointList;
|
|
pipelineDescriptor.cFragment.targetCount = 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"(
|
|
[[block]] struct DepthResult {
|
|
value : f32;
|
|
};
|
|
[[block]] struct StencilResult {
|
|
value : u32;
|
|
};)";
|
|
shaderSource << "\n";
|
|
|
|
uint32_t index = 0;
|
|
for (TestAspect aspect : aspects) {
|
|
switch (aspect) {
|
|
case TestAspect::Depth:
|
|
shaderSource << "[[group(0), binding(" << 2 * index << ")]] var tex" << index
|
|
<< " : texture_2d<f32>;\n";
|
|
|
|
shaderSource << "[[group(0), binding(" << 2 * index + 1
|
|
<< ")]] var<storage> result" << index
|
|
<< " : [[access(read_write)]] DepthResult;\n";
|
|
|
|
shaderBody << "\nresult" << index << ".value = textureLoad(tex" << index
|
|
<< ", vec2<i32>(0, 0), 0)[" << componentIndex << "];";
|
|
break;
|
|
case TestAspect::Stencil:
|
|
shaderSource << "[[group(0), binding(" << 2 * index << ")]] var tex" << index
|
|
<< " : texture_2d<u32>;\n";
|
|
|
|
shaderSource << "[[group(0), binding(" << 2 * index + 1
|
|
<< ")]] var<storage> result" << index
|
|
<< " : [[access(read_write)]] StencilResult;\n";
|
|
|
|
shaderBody << "\nresult" << index << ".value = textureLoad(tex" << index
|
|
<< ", vec2<i32>(0, 0), 0)[" << componentIndex << "];";
|
|
break;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
shaderSource << "[[stage(compute)]] fn main() { " << shaderBody.str() << "\n}";
|
|
|
|
wgpu::ShaderModule csModule = utils::CreateShaderModule(device, 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, R"(
|
|
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
|
|
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
|
|
})");
|
|
|
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
|
|
[[group(0), binding(0)]] var samp : sampler_comparison;
|
|
[[group(0), binding(1)]] var tex : texture_depth_2d;
|
|
[[block]] struct Uniforms {
|
|
compareRef : f32;
|
|
};
|
|
[[group(0), binding(2)]] var<uniform> uniforms : Uniforms;
|
|
|
|
[[stage(fragment)]] fn main() -> [[location(0)]] f32 {
|
|
return textureSampleCompare(tex, samp, vec2<f32>(0.5, 0.5), uniforms.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::SamplerBindingType::Comparison},
|
|
{1, wgpu::ShaderStage::Fragment, wgpu::TextureSampleType::Depth},
|
|
{2, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Uniform}});
|
|
|
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
|
pipelineDescriptor.vertex.module = vsModule;
|
|
pipelineDescriptor.cFragment.module = fsModule;
|
|
pipelineDescriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
|
|
pipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::PointList;
|
|
pipelineDescriptor.cTargets[0].format = wgpu::TextureFormat::R32Float;
|
|
|
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
|
}
|
|
|
|
wgpu::ComputePipeline CreateComparisonComputePipeline() {
|
|
wgpu::ShaderModule csModule = utils::CreateShaderModule(device, R"(
|
|
[[group(0), binding(0)]] var samp : sampler_comparison;
|
|
[[group(0), binding(1)]] var tex : texture_depth_2d;
|
|
[[block]] struct Uniforms {
|
|
compareRef : f32;
|
|
};
|
|
[[group(0), binding(2)]] var<uniform> uniforms : Uniforms;
|
|
|
|
[[block]] struct SamplerResult {
|
|
value : f32;
|
|
};
|
|
[[group(0), binding(3)]] var<storage> samplerResult : [[access(read_write)]] SamplerResult;
|
|
|
|
[[stage(compute)]] fn main() {
|
|
samplerResult.value = textureSampleCompare(tex, samp, vec2<f32>(0.5, 0.5), uniforms.compareRef);
|
|
})");
|
|
|
|
// TODO(dawn:367): Cannot use GetBindGroupLayout without shader reflection data.
|
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
|
device, {{0, wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Comparison},
|
|
{1, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Depth},
|
|
{2, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Uniform},
|
|
{3, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Storage}});
|
|
|
|
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::RenderAttachment;
|
|
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::RenderAttachment | 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::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, 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::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, inputTexture.CreateView(&inputViewDesc)}, {1, 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_TEST_UNSUPPORTED_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_TEST_UNSUPPORTED_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_SUPPRESS_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_TEST_UNSUPPORTED_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, inputTexture.CreateView(&depthViewDesc)},
|
|
{1, 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, inputTexture.CreateView(&depthViewDesc)},
|
|
{1, depthOutput},
|
|
{2, inputTexture.CreateView(&stencilViewDesc)},
|
|
{3, 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_SUPPRESS_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.
|
|
// WGSL disallows |textureSampleCompare| in compute stages.
|
|
TEST_P(DepthStencilSamplingTest, DISABLED_CompareFunctionsCompute) {
|
|
// Initialization via renderPass loadOp doesn't work on Mac Intel.
|
|
DAWN_SUPPRESS_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());
|