diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn index 66e3355d73..4e2ebeda7e 100644 --- a/src/tests/BUILD.gn +++ b/src/tests/BUILD.gn @@ -255,7 +255,6 @@ source_set("dawn_end2end_tests_sources") { "end2end/BufferTests.cpp", "end2end/ClipSpaceTests.cpp", "end2end/ColorStateTests.cpp", - "end2end/ComparisonSamplerTests.cpp", "end2end/CompressedTextureFormatTests.cpp", "end2end/ComputeCopyStorageBufferTests.cpp", "end2end/ComputeIndirectTests.cpp", @@ -265,6 +264,7 @@ source_set("dawn_end2end_tests_sources") { "end2end/CullingTests.cpp", "end2end/DebugMarkerTests.cpp", "end2end/DeprecatedAPITests.cpp", + "end2end/DepthSamplingTests.cpp", "end2end/DepthStencilStateTests.cpp", "end2end/DestroyTests.cpp", "end2end/DeviceLostTests.cpp", diff --git a/src/tests/end2end/ComparisonSamplerTests.cpp b/src/tests/end2end/ComparisonSamplerTests.cpp deleted file mode 100644 index a7cca15e55..0000000000 --- a/src/tests/end2end/ComparisonSamplerTests.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// 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::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, - }; - -} // anonymous namespace - -class ComparisonSamplerTest : public DawnTest { - protected: - void TestSetUp() override { - DawnTest::TestSetUp(); - - 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 vec4 samplerResult; - - void main() { - samplerResult = vec4(texture(sampler2DShadow(tex, samp), vec3(0.5, 0.5, compareRef))); - } - )"); - - wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( - device, {{0, wgpu::ShaderStage::Fragment, wgpu::BindingType::ComparisonSampler}, - {1, wgpu::ShaderStage::Fragment, wgpu::BindingType::SampledTexture}, - {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; - - mRenderPipeline = device.CreateRenderPipeline(&pipelineDescriptor); - - wgpu::BufferDescriptor uniformBufferDesc; - uniformBufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst; - uniformBufferDesc.size = sizeof(float); - mUniformBuffer = device.CreateBuffer(&uniformBufferDesc); - - wgpu::BufferDescriptor textureUploadDesc; - textureUploadDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; - textureUploadDesc.size = sizeof(float); - mTextureUploadBuffer = device.CreateBuffer(&textureUploadDesc); - - wgpu::TextureDescriptor inputTextureDesc; - inputTextureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled | - wgpu::TextureUsage::OutputAttachment; - inputTextureDesc.size = {1, 1, 1}; - inputTextureDesc.format = wgpu::TextureFormat::Depth32Float; - mInputTexture = device.CreateTexture(&inputTextureDesc); - - wgpu::TextureDescriptor outputTextureDesc; - outputTextureDesc.usage = - wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc; - outputTextureDesc.size = {1, 1, 1}; - outputTextureDesc.format = wgpu::TextureFormat::RGBA8Unorm; - mOutputTexture = device.CreateTexture(&outputTextureDesc); - } - - void DoCompareRefTest(float compareRef, - wgpu::CompareFunction compare, - std::vector textureValues) { - mUniformBuffer.SetSubData(0, sizeof(float), &compareRef); - - wgpu::SamplerDescriptor samplerDesc; - samplerDesc.compare = compare; - wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); - - wgpu::BindGroup bindGroup = - utils::MakeBindGroup(device, mRenderPipeline.GetBindGroupLayout(0), - { - {0, sampler}, - {1, mInputTexture.CreateView()}, - {2, mUniformBuffer}, - }); - - for (float textureValue : textureValues) { - bool success = false; - switch (compare) { - case wgpu::CompareFunction::Never: - success = false; - break; - case wgpu::CompareFunction::Less: - success = compareRef < textureValue; - break; - case wgpu::CompareFunction::LessEqual: - success = compareRef <= textureValue; - break; - case wgpu::CompareFunction::Greater: - success = compareRef > textureValue; - break; - case wgpu::CompareFunction::GreaterEqual: - success = compareRef >= textureValue; - break; - case wgpu::CompareFunction::Equal: - success = compareRef == textureValue; - break; - case wgpu::CompareFunction::NotEqual: - success = compareRef != textureValue; - break; - case wgpu::CompareFunction::Always: - success = true; - break; - default: - UNREACHABLE(); - break; - } - - // Set the input depth texture to the provided texture value - mTextureUploadBuffer.SetSubData(0, sizeof(float), &textureValue); - - wgpu::BufferCopyView bufferCopyView = {}; - bufferCopyView.buffer = mTextureUploadBuffer; - bufferCopyView.offset = 0; - bufferCopyView.bytesPerRow = kTextureBytesPerRowAlignment; - - wgpu::TextureCopyView textureCopyView; - textureCopyView.texture = mInputTexture; - textureCopyView.origin = {0, 0, 0}; - - wgpu::Extent3D copySize = {1, 1, 1}; - - wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); - commandEncoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); - - // Render into the output texture - { - utils::ComboRenderPassDescriptor passDescriptor({mOutputTexture.CreateView()}); - wgpu::RenderPassEncoder pass = commandEncoder.BeginRenderPass(&passDescriptor); - pass.SetPipeline(mRenderPipeline); - pass.SetBindGroup(0, bindGroup); - pass.Draw(3); - pass.EndPass(); - } - - wgpu::CommandBuffer commands = commandEncoder.Finish(); - queue.Submit(1, &commands); - - EXPECT_PIXEL_RGBA8_EQ(success ? RGBA8(255, 255, 255, 255) : RGBA8(0, 0, 0, 0), - mOutputTexture, 0, 0); - } - } - - private: - wgpu::RenderPipeline mRenderPipeline; - wgpu::Buffer mUniformBuffer; - wgpu::Buffer mTextureUploadBuffer; - wgpu::Texture mInputTexture; - wgpu::Texture mOutputTexture; -}; - -// Test that sampling with all of the compare functions works. -TEST_P(ComparisonSamplerTest, CompareFunctions) { - // Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs. - for (float compareRef : {-0.1, 0.4, 1.2}) { - // Test 0, below the ref, equal to, above the ref, and 1. - for (wgpu::CompareFunction f : kCompareFunctions) { - DoCompareRefTest(compareRef, f, {0.0, 0.3, 0.4, 0.5, 1.0}); - } - } -} - -// Test that sampling with all of the compare functions works, when the texture contents -// are outside the 0-1 range. -TEST_P(ComparisonSamplerTest, CompareFunctionsUnnormalizedContents) { - // TODO(enga): Copies to depth textures are clamped. Unless we reinterpret - // contents as R32F. - DAWN_SKIP_TEST_IF(IsOpenGL()); - - // Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs. - for (float compareRef : {-0.1, 0.4, 1.2}) { - // Test negative, and above 1. - for (wgpu::CompareFunction f : kCompareFunctions) { - DoCompareRefTest(compareRef, f, {-0.2, 1.3}); - } - } -} - -// TODO(crbug.com/dawn/367): Does not work on D3D12 because we need to reinterpret the texture view -// as R32Float to sample it. See tables here: -// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/hardware-support-for-direct3d-12-1-formats -DAWN_INSTANTIATE_TEST(ComparisonSamplerTest, MetalBackend(), OpenGLBackend(), VulkanBackend()); diff --git a/src/tests/end2end/DepthSamplingTests.cpp b/src/tests/end2end/DepthSamplingTests.cpp new file mode 100644 index 0000000000..491f7c2c4b --- /dev/null +++ b/src/tests/end2end/DepthSamplingTests.cpp @@ -0,0 +1,511 @@ +// 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::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 kNormalizedTextureValues = {0.0, 0.3, 0.4, 0.5, 1.0}; + const std::vector kNonNormalizedTextureValues = {-0.2, -0.1, 1.2, 1.3}; + +} // anonymous namespace + +class DepthSamplingTest : public DawnTest { + protected: + void TestSetUp() override { + DawnTest::TestSetUp(); + + wgpu::BufferDescriptor uniformBufferDesc; + uniformBufferDesc.usage = wgpu::BufferUsage::Uniform | wgpu::BufferUsage::CopyDst; + uniformBufferDesc.size = sizeof(float); + mUniformBuffer = device.CreateBuffer(&uniformBufferDesc); + + wgpu::BufferDescriptor textureUploadDesc; + textureUploadDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; + textureUploadDesc.size = sizeof(float); + mTextureUploadBuffer = device.CreateBuffer(&textureUploadDesc); + + wgpu::TextureDescriptor inputTextureDesc; + inputTextureDesc.usage = wgpu::TextureUsage::CopyDst | wgpu::TextureUsage::Sampled | + wgpu::TextureUsage::OutputAttachment; + inputTextureDesc.size = {1, 1, 1}; + inputTextureDesc.format = wgpu::TextureFormat::Depth32Float; + mInputTexture = device.CreateTexture(&inputTextureDesc); + + wgpu::TextureDescriptor outputTextureDesc; + outputTextureDesc.usage = + wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc; + outputTextureDesc.size = {1, 1, 1}; + outputTextureDesc.format = wgpu::TextureFormat::R32Float; + mOutputTexture = device.CreateTexture(&outputTextureDesc); + + wgpu::BufferDescriptor outputBufferDesc; + outputBufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc; + outputBufferDesc.size = sizeof(float); + mOutputBuffer = device.CreateBuffer(&outputBufferDesc); + } + + wgpu::RenderPipeline CreateSamplingRenderPipeline() { + 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 sampler samp; + layout(set = 0, binding = 1) uniform texture2D tex; + + layout(location = 0) out float samplerResult; + + void main() { + samplerResult = texture(sampler2D(tex, samp), vec2(0.5, 0.5)).r; + } + )"); + + utils::ComboRenderPipelineDescriptor pipelineDescriptor(device); + pipelineDescriptor.vertexStage.module = vsModule; + pipelineDescriptor.cFragmentStage.module = fsModule; + pipelineDescriptor.primitiveTopology = wgpu::PrimitiveTopology::PointList; + pipelineDescriptor.cColorStates[0].format = wgpu::TextureFormat::R32Float; + + return device.CreateRenderPipeline(&pipelineDescriptor); + } + + wgpu::ComputePipeline CreateSamplingComputePipeline() { + wgpu::ShaderModule csModule = + utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"( + #version 450 + layout(set = 0, binding = 0) uniform sampler samp; + layout(set = 0, binding = 1) uniform texture2D tex; + layout(set = 0, binding = 2) writeonly buffer SamplerResult { + float samplerResult; + }; + + void main() { + samplerResult = texture(sampler2D(tex, samp), vec2(0.5, 0.5)).r; + } + )"); + + 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}, + {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}, + {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); + } + + void UpdateInputTexture(wgpu::CommandEncoder commandEncoder, float textureValue) { + mTextureUploadBuffer.SetSubData(0, sizeof(float), &textureValue); + + wgpu::BufferCopyView bufferCopyView = {}; + bufferCopyView.buffer = mTextureUploadBuffer; + bufferCopyView.offset = 0; + bufferCopyView.bytesPerRow = kTextureBytesPerRowAlignment; + + wgpu::TextureCopyView textureCopyView; + textureCopyView.texture = mInputTexture; + textureCopyView.origin = {0, 0, 0}; + + wgpu::Extent3D copySize = {1, 1, 1}; + + commandEncoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); + } + + void DoSamplingTest(wgpu::RenderPipeline pipeline, std::vector textureValues) { + wgpu::SamplerDescriptor samplerDesc; + wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); + + wgpu::BindGroup bindGroup = + utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + { + {0, sampler}, + {1, mInputTexture.CreateView()}, + }); + + for (float textureValue : textureValues) { + // Set the input depth texture to the provided texture value + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + UpdateInputTexture(commandEncoder, textureValue); + + // Render into the output texture + { + utils::ComboRenderPassDescriptor passDescriptor({mOutputTexture.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_PIXEL_FLOAT_EQ(textureValue, mOutputTexture, 0, 0); + } + } + + void DoSamplingTest(wgpu::ComputePipeline pipeline, std::vector textureValues) { + wgpu::SamplerDescriptor samplerDesc; + wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); + + wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + { + {0, sampler}, + {1, mInputTexture.CreateView()}, + {2, mOutputBuffer} + }); + + for (float textureValue : textureValues) { + // Set the input depth texture to the provided texture value + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + UpdateInputTexture(commandEncoder, 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); + + EXPECT_BUFFER_U32_EQ(*reinterpret_cast(&textureValue), mOutputBuffer, 0); + } + } + + 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 DoCompareRefTest(wgpu::RenderPipeline pipeline, + float compareRef, + wgpu::CompareFunction compare, + std::vector textureValues) { + mUniformBuffer.SetSubData(0, sizeof(float), &compareRef); + + wgpu::SamplerDescriptor samplerDesc; + samplerDesc.compare = compare; + wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); + + wgpu::BindGroup bindGroup = + utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + { + {0, sampler}, + {1, mInputTexture.CreateView()}, + {2, mUniformBuffer}, + }); + + for (float textureValue : textureValues) { + // Set the input depth texture to the provided texture value + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + UpdateInputTexture(commandEncoder, textureValue); + + // Render into the output texture + { + utils::ComboRenderPassDescriptor passDescriptor({mOutputTexture.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_PIXEL_FLOAT_EQ( + CompareFunctionPasses(compareRef, compare, textureValue) ? 1.0 : 0.0, + mOutputTexture, 0, 0); + } + } + + void DoCompareRefTest(wgpu::ComputePipeline pipeline, + float compareRef, + wgpu::CompareFunction compare, + std::vector textureValues) { + mUniformBuffer.SetSubData(0, sizeof(float), &compareRef); + + wgpu::SamplerDescriptor samplerDesc; + samplerDesc.compare = compare; + wgpu::Sampler sampler = device.CreateSampler(&samplerDesc); + + wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0), + { + {0, sampler}, + {1, mInputTexture.CreateView()}, + {2, mUniformBuffer}, + {3, mOutputBuffer} + }); + + for (float textureValue : textureValues) { + // Set the input depth texture to the provided texture value + wgpu::CommandEncoder commandEncoder = device.CreateCommandEncoder(); + UpdateInputTexture(commandEncoder, 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(expected), mOutputBuffer, 0); + } + } + + private: + wgpu::Buffer mUniformBuffer; + wgpu::Buffer mTextureUploadBuffer; + wgpu::Texture mInputTexture; + wgpu::Texture mOutputTexture; + wgpu::Buffer mOutputBuffer; +}; + +// Test that sampling a depth texture with a render pipeline works +TEST_P(DepthSamplingTest, SampleRender) { + // Test 0, between [0, 1], and 1. + DoSamplingTest(CreateSamplingRenderPipeline(), kNormalizedTextureValues); +} + +// Test that sampling a depth texture with a compute pipeline works +TEST_P(DepthSamplingTest, SampleCompute) { + // Test 0, between [0, 1], and 1. + DoSamplingTest(CreateSamplingComputePipeline(), kNormalizedTextureValues); +} + +// Test that sampling a depth texture with a render pipeline works, +// when the texture contents are outside the 0-1 range. +TEST_P(DepthSamplingTest, SampleNonNormalizedContentsRender) { + // TODO(enga): Sampling depth textures is clamped. Unless we reinterpret + // contents as R32F. + DAWN_SKIP_TEST_IF(IsOpenGL()); + + // Test values not between [0, 1] + DoSamplingTest(CreateSamplingRenderPipeline(), kNonNormalizedTextureValues); +} + +// Test that sampling a depth texture with a render pipeline works, +// when the texture contents are outside the 0-1 range. +TEST_P(DepthSamplingTest, SampleNonNormalizedContentsCompute) { + // TODO(enga): Sampling depth textures is clamped. Unless we reinterpret + // contents as R32F. + DAWN_SKIP_TEST_IF(IsOpenGL()); + + // Test values not between [0, 1] + DoSamplingTest(CreateSamplingComputePipeline(), kNonNormalizedTextureValues); +} + +// Test that sampling in a render pipeline with all of the compare functions works. +TEST_P(DepthSamplingTest, CompareFunctionsRender) { + wgpu::RenderPipeline pipeline = CreateComparisonRenderPipeline(); + + // 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) { + DoCompareRefTest(pipeline, compareRef, f, kNormalizedTextureValues); + } + } +} + +// Test that sampling in a render pipeline with all of the compare functions works. +TEST_P(DepthSamplingTest, CompareFunctionsCompute) { + // Comparison is always 0 on Mac Intel when using compute. + DAWN_SKIP_TEST_IF(IsMetal() && IsIntel()); + + wgpu::ComputePipeline pipeline = CreateComparisonComputePipeline(); + + // 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) { + DoCompareRefTest(pipeline, compareRef, f, kNormalizedTextureValues); + } + } +} + +// Test that sampling in a render pipeline with all of the compare functions works, +// when the texture contents are outside the 0-1 range. +TEST_P(DepthSamplingTest, CompareFunctionsNonNormalizedContentsRender) { + // TODO(enga): Sampling depth textures is clamped. Unless we reinterpret + // contents as R32F. + DAWN_SKIP_TEST_IF(IsOpenGL()); + wgpu::RenderPipeline pipeline = CreateComparisonRenderPipeline(); + + // Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs. + for (float compareRef : kCompareRefs) { + // Test negative, and above 1. + for (wgpu::CompareFunction f : kCompareFunctions) { + DoCompareRefTest(pipeline, compareRef, f, kNonNormalizedTextureValues); + } + } +} + +// Test that sampling in a compute pipeline with all of the compare functions works, +// when the texture contents are outside the 0-1 range. +TEST_P(DepthSamplingTest, CompareFunctionsNonNormalizedContentsCompute) { + // Comparison is always 0 on Mac Intel when using compute. + DAWN_SKIP_TEST_IF(IsMetal() && IsIntel()); + + // TODO(enga): Sampling depth textures is clamped. Unless we reinterpret + // contents as R32F. + DAWN_SKIP_TEST_IF(IsOpenGL()); + wgpu::ComputePipeline pipeline = CreateComparisonComputePipeline(); + + // Test a "normal" ref value between 0 and 1; as well as negative and > 1 refs. + for (float compareRef : kCompareRefs) { + // Test negative, and above 1. + for (wgpu::CompareFunction f : kCompareFunctions) { + DoCompareRefTest(pipeline, compareRef, f, kNormalizedTextureValues); + } + } +} + +// TODO(crbug.com/dawn/367): Does not work on D3D12 because we need to reinterpret the texture view +// as R32Float to sample it. See tables here: +// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/hardware-support-for-direct3d-12-1-formats +DAWN_INSTANTIATE_TEST(DepthSamplingTest, MetalBackend(), OpenGLBackend(), VulkanBackend());