Fix clip space on D3D12 and OpenGL

The range of the Z-coordinate in clipping volume is [-w, w] on OpenGL,
while it is [0, w] on D3D12, Metal and Vulkan.

In this patch, the "fixup_clipspace" flag of SPIRV-Cross is enabled on
OpenGL backend and disabled on D3D12 backend to unify the behaviour of
clip space on all Dawn backends. An end2end test is also added for this
fix.

This patch also fix a bug when clearing depth stencil attachments on
OpenGL backend. Before clearing depth stencil attachments, we should
enable depth stencil writing by properly setting depth and stencil
masks. We do not need to set the depth and stencil masks back because
they will be set again when applying the render pipeline. The newly
added test will fail without this fix when running the test together
with all the end2ends.

BUG=dawn:122
TEST=dawn_end2end_tests

Change-Id: I4f50ce3eb1f16d731ee4cffc12a56e17844b4675
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/5860
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
This commit is contained in:
Jiawei Shao 2019-03-27 00:01:33 +00:00 committed by Commit Bot service account
parent 91e949292f
commit 5490e9aca1
7 changed files with 126 additions and 2 deletions

View File

@ -640,6 +640,7 @@ test("dawn_end2end_tests") {
"src/tests/end2end/BasicTests.cpp", "src/tests/end2end/BasicTests.cpp",
"src/tests/end2end/BindGroupTests.cpp", "src/tests/end2end/BindGroupTests.cpp",
"src/tests/end2end/BufferTests.cpp", "src/tests/end2end/BufferTests.cpp",
"src/tests/end2end/ClipSpaceTests.cpp",
"src/tests/end2end/ColorStateTests.cpp", "src/tests/end2end/ColorStateTests.cpp",
"src/tests/end2end/ComputeCopyStorageBufferTests.cpp", "src/tests/end2end/ComputeCopyStorageBufferTests.cpp",
"src/tests/end2end/CopyTests.cpp", "src/tests/end2end/CopyTests.cpp",

View File

@ -37,7 +37,6 @@ namespace dawn_native { namespace d3d12 {
// If these options are changed, the values in DawnSPIRVCrossHLSLFastFuzzer.cpp need to be // If these options are changed, the values in DawnSPIRVCrossHLSLFastFuzzer.cpp need to be
// updated. // updated.
spirv_cross::CompilerGLSL::Options options_glsl; spirv_cross::CompilerGLSL::Options options_glsl;
options_glsl.vertex.fixup_clipspace = true;
options_glsl.vertex.flip_vert_y = true; options_glsl.vertex.flip_vert_y = true;
compiler.set_common_options(options_glsl); compiler.set_common_options(options_glsl);

View File

@ -106,6 +106,15 @@ namespace dawn_native { namespace opengl {
} }
} }
GLint GetStencilMaskFromStencilFormat(dawn::TextureFormat depthStencilFormat) {
switch (depthStencilFormat) {
case dawn::TextureFormat::D32FloatS8Uint:
return 0xFF;
default:
UNREACHABLE();
}
}
// Push constants are implemented using OpenGL uniforms, however they aren't part of the // Push constants are implemented using OpenGL uniforms, however they aren't part of the
// global OpenGL state but are part of the program state instead. This means that we have to // global OpenGL state but are part of the program state instead. This means that we have to
// reapply push constants on pipeline change. // reapply push constants on pipeline change.
@ -610,6 +619,14 @@ namespace dawn_native { namespace opengl {
(attachmentInfo.depthLoadOp == dawn::LoadOp::Clear); (attachmentInfo.depthLoadOp == dawn::LoadOp::Clear);
bool doStencilClear = TextureFormatHasStencil(attachmentFormat) && bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
(attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear); (attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear);
if (doDepthClear) {
glDepthMask(GL_TRUE);
}
if (doStencilClear) {
glStencilMask(GetStencilMaskFromStencilFormat(attachmentFormat));
}
if (doDepthClear && doStencilClear) { if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth, glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
attachmentInfo.clearStencil); attachmentInfo.clearStencil);

View File

@ -54,6 +54,12 @@ namespace dawn_native { namespace opengl {
// updated. // updated.
spirv_cross::CompilerGLSL::Options options; spirv_cross::CompilerGLSL::Options options;
// The range of Z-coordinate in the clipping volume of OpenGL is [-w, w], while it is [0, w]
// in D3D12, Metal and Vulkan, so we should normalize it in shaders in all backends.
// See the documentation of spirv_cross::CompilerGLSL::Options::vertex::fixup_clipspace for
// more details.
options.vertex.fixup_clipspace = true;
// TODO(cwallez@chromium.org): discover the backing context version and use that. // TODO(cwallez@chromium.org): discover the backing context version and use that.
#if defined(DAWN_PLATFORM_APPLE) #if defined(DAWN_PLATFORM_APPLE)
options.version = 410; options.version = 410;

View File

@ -29,6 +29,7 @@ namespace {
// Using the options that are used by Dawn, they appear in ShaderModuleGL.cpp // Using the options that are used by Dawn, they appear in ShaderModuleGL.cpp
shaderc_spvc::CompileOptions options; shaderc_spvc::CompileOptions options;
options.SetOutputLanguageVersion(440); options.SetOutputLanguageVersion(440);
options.SetFixupClipspace(true);
compiler.CompileSpvToGlsl(input.data(), input.size(), options); compiler.CompileSpvToGlsl(input.data(), input.size(), options);
}); });

View File

@ -30,7 +30,6 @@ namespace {
shaderc_spvc::CompileOptions options; shaderc_spvc::CompileOptions options;
// Using the options that are used by Dawn, they appear in ShaderModuleD3D12.cpp // Using the options that are used by Dawn, they appear in ShaderModuleD3D12.cpp
options.SetFixupClipspace(true);
options.SetFlipVertY(true); options.SetFlipVertY(true);
options.SetShaderModel(51); options.SetShaderModel(51);
compiler.CompileSpvToHlsl(input.data(), input.size(), options); compiler.CompileSpvToHlsl(input.data(), input.size(), options);

View File

@ -0,0 +1,101 @@
// Copyright 2019 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/DawnHelpers.h"
class ClipSpaceTest : public DawnTest {
protected:
dawn::RenderPipeline CreatePipelineForTest() {
utils::ComboRenderPipelineDescriptor pipelineDescriptor(device);
// Draw two triangles:
// 1. The depth value of the top-left one is >= 0.5
// 2. The depth value of the bottom-right one is <= 0.5
const char* vs =
R"(#version 450
const vec3 pos[6] = vec3[6](vec3(-1.0f, -1.0f, 1.0f),
vec3(-1.0f, 1.0f, 0.5f),
vec3( 1.0f, -1.0f, 0.5f),
vec3( 1.0f, -1.0f, 0.5f),
vec3(-1.0f, 1.0f, 0.5f),
vec3( 1.0f, 1.0f, 0.0f));
void main() {
gl_Position = vec4(pos[gl_VertexIndex], 1.0);
})";
pipelineDescriptor.cVertexStage.module =
utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vs);
const char* fs =
"#version 450\n"
"layout(location = 0) out vec4 fragColor;"
"void main() {\n"
" fragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
pipelineDescriptor.cFragmentStage.module =
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, fs);
pipelineDescriptor.cDepthStencilState.depthCompare = dawn::CompareFunction::LessEqual;
pipelineDescriptor.depthStencilState = &pipelineDescriptor.cDepthStencilState;
return device.CreateRenderPipeline(&pipelineDescriptor);
}
dawn::Texture Create2DTextureForTest(dawn::TextureFormat format) {
dawn::TextureDescriptor textureDescriptor;
textureDescriptor.dimension = dawn::TextureDimension::e2D;
textureDescriptor.format = format;
textureDescriptor.usage =
dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;
textureDescriptor.arrayLayerCount = 1;
textureDescriptor.mipLevelCount = 1;
textureDescriptor.sampleCount = 1;
textureDescriptor.size = {kSize, kSize, 1};
return device.CreateTexture(&textureDescriptor);
}
static constexpr uint32_t kSize = 4;
};
// Test that the clip space is correctly configured.
TEST_P(ClipSpaceTest, ClipSpace) {
dawn::Texture colorTexture = Create2DTextureForTest(dawn::TextureFormat::R8G8B8A8Unorm);
dawn::Texture depthStencilTexture = Create2DTextureForTest(dawn::TextureFormat::D32FloatS8Uint);
utils::ComboRenderPassDescriptor renderPassDescriptor(
{colorTexture.CreateDefaultTextureView()}, depthStencilTexture.CreateDefaultTextureView());
renderPassDescriptor.cColorAttachmentsInfoPtr[0]->clearColor = {0.0, 1.0, 0.0, 1.0};
renderPassDescriptor.cColorAttachmentsInfoPtr[0]->loadOp = dawn::LoadOp::Clear;
// Clear the depth stencil attachment to 0.5f, so only the bottom-right triangle should be
// drawn.
renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.5f;
renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
dawn::CommandEncoder commandEncoder = device.CreateCommandEncoder();
dawn::RenderPassEncoder renderPass = commandEncoder.BeginRenderPass(&renderPassDescriptor);
renderPass.SetPipeline(CreatePipelineForTest());
renderPass.Draw(6, 1, 0, 0);
renderPass.EndPass();
dawn::CommandBuffer commandBuffer = commandEncoder.Finish();
dawn::Queue queue = device.CreateQueue();
queue.Submit(1, &commandBuffer);
EXPECT_PIXEL_RGBA8_EQ(RGBA8(255, 0, 0, 255), colorTexture, kSize - 1, kSize - 1);
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), colorTexture, 0, 0);
}
DAWN_INSTANTIATE_TEST(ClipSpaceTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);