D3D11: implement EXT_clip_control

This implements EXT_clip_control for the D3D11 renderer, so that I can
use a reversed-Z depth buffer with ANGLE.

Tested with
    angle_deqp_gles2_tests.exe --deqp-egl-display-type=angle-d3d11 --deqp-case=dEQP-GLES2.functional.clip_control.*
and
    angle_end2end_tests.exe --gtest_filter=*D3D11*

Bug: angleproject:6554
Change-Id: I1d11cd04a6654c28530b11104470f0cad0009abe
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3218659
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Steven Noonan 2021-10-11 19:26:07 -07:00 коммит произвёл Angle LUCI CQ
Родитель 4b056a17b5
Коммит 01341f9483
6 изменённых файлов: 89 добавлений и 20 удалений

Просмотреть файл

@ -210,3 +210,6 @@ Collabora, Ltd.
LunarG, Inc. LunarG, Inc.
Mark Lobodzinski Mark Lobodzinski
Valve Corporation
Steven Noonan

Просмотреть файл

@ -969,14 +969,17 @@ void OutputHLSL::header(TInfoSinkBase &out,
out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n"; out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
} }
out << " float clipControlOrigin : packoffset(c3.w);\n";
out << " float clipControlZeroToOne : packoffset(c4);\n";
if (mOutputType == SH_HLSL_4_1_OUTPUT) if (mOutputType == SH_HLSL_4_1_OUTPUT)
{ {
mResourcesHLSL->samplerMetadataUniforms(out, 4); mResourcesHLSL->samplerMetadataUniforms(out, 5);
} }
if (mUsesVertexID) if (mUsesVertexID)
{ {
out << " uint dx_VertexID : packoffset(c3.w);\n"; out << " uint dx_VertexID : packoffset(c4.y);\n";
} }
out << "};\n" out << "};\n"
@ -990,8 +993,12 @@ void OutputHLSL::header(TInfoSinkBase &out,
} }
out << "uniform float4 dx_ViewAdjust : register(c1);\n"; out << "uniform float4 dx_ViewAdjust : register(c1);\n";
out << "uniform float2 dx_ViewCoords : register(c2);\n" out << "uniform float2 dx_ViewCoords : register(c2);\n";
"\n";
out << "static const float clipControlOrigin = -1.0f;\n";
out << "static const float clipControlZeroToOne = 0.0f;\n";
out << "\n";
} }
if (mUsesDepthRange) if (mUsesDepthRange)

Просмотреть файл

@ -553,12 +553,19 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps,
} }
else else
{ {
vertexGenerateOutput << " output.dx_Position.y = - gl_Position.y;\n"; vertexGenerateOutput
<< " output.dx_Position.y = clipControlOrigin * gl_Position.y;\n";
} }
vertexGenerateOutput vertexGenerateOutput
<< " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" << " if (clipControlZeroToOne)\n"
<< " output.dx_Position.w = gl_Position.w;\n"; << " {\n"
<< " output.dx_Position.z = gl_Position.z;\n"
<< " } else {\n"
<< " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " }\n";
vertexGenerateOutput << " output.dx_Position.w = gl_Position.w;\n";
} }
else else
{ {
@ -576,14 +583,20 @@ void DynamicHLSL::generateShaderLinkHLSL(const gl::Caps &caps,
} }
else else
{ {
vertexGenerateOutput vertexGenerateOutput << " output.dx_Position.y = clipControlOrigin * (gl_Position.y "
<< " output.dx_Position.y = -(gl_Position.y * dx_ViewAdjust.w + " "* dx_ViewAdjust.w + "
"dx_ViewAdjust.y * gl_Position.w);\n"; "dx_ViewAdjust.y * gl_Position.w);\n";
} }
vertexGenerateOutput vertexGenerateOutput
<< " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" << " if (clipControlZeroToOne)\n"
<< " output.dx_Position.w = gl_Position.w;\n"; << " {\n"
<< " output.dx_Position.z = gl_Position.z;\n"
<< " } else {\n"
<< " output.dx_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
<< " }\n";
vertexGenerateOutput << " output.dx_Position.w = gl_Position.w;\n";
} }
// We don't need to output gl_PointSize if we use are emulating point sprites via instancing. // We don't need to output gl_PointSize if we use are emulating point sprites via instancing.

Просмотреть файл

@ -589,6 +589,13 @@ void ShaderConstants11::onImageChange(gl::ShaderType shaderType,
} }
} }
void ShaderConstants11::onClipControlChange(bool lowerLeft, bool zeroToOne)
{
mVertex.clipControlOrigin = lowerLeft ? -1.0f : 1.0f;
mVertex.clipControlZeroToOne = zeroToOne ? 1.0f : 0.0f;
mShaderConstantsDirty.set(gl::ShaderType::Vertex);
}
angle::Result ShaderConstants11::updateBuffer(const gl::Context *context, angle::Result ShaderConstants11::updateBuffer(const gl::Context *context,
Renderer11 *renderer, Renderer11 *renderer,
gl::ShaderType shaderType, gl::ShaderType shaderType,
@ -848,12 +855,12 @@ void StateManager11::updateStencilSizeIfChanged(bool depthStencilInitialized,
void StateManager11::checkPresentPath(const gl::Context *context) void StateManager11::checkPresentPath(const gl::Context *context)
{ {
if (!mRenderer->presentPathFastEnabled())
return;
const auto *framebuffer = context->getState().getDrawFramebuffer(); const auto *framebuffer = context->getState().getDrawFramebuffer();
const auto *firstColorAttachment = framebuffer->getFirstColorAttachment(); const auto *firstColorAttachment = framebuffer->getFirstColorAttachment();
const bool presentPathFastActive = UsePresentPathFast(mRenderer, firstColorAttachment); const bool clipSpaceOriginUpperLeft =
context->getState().getClipSpaceOrigin() == gl::ClipSpaceOrigin::UpperLeft;
const bool presentPathFastActive =
UsePresentPathFast(mRenderer, firstColorAttachment) || clipSpaceOriginUpperLeft;
const int colorBufferHeight = firstColorAttachment ? firstColorAttachment->getSize().height : 0; const int colorBufferHeight = firstColorAttachment ? firstColorAttachment->getSize().height : 0;
@ -1205,6 +1212,22 @@ void StateManager11::syncState(const gl::Context *context, const gl::State::Dirt
case gl::State::DIRTY_BIT_PROVOKING_VERTEX: case gl::State::DIRTY_BIT_PROVOKING_VERTEX:
invalidateShaders(); invalidateShaders();
break; break;
case gl::State::DIRTY_BIT_EXTENDED:
{
gl::State::ExtendedDirtyBits extendedDirtyBits =
state.getAndResetExtendedDirtyBits();
for (size_t extendedDirtyBit : extendedDirtyBits)
{
switch (extendedDirtyBit)
{
case gl::State::EXTENDED_DIRTY_BIT_CLIP_CONTROL:
checkPresentPath(context);
break;
}
}
break;
}
default: default:
break; break;
} }
@ -1429,6 +1452,10 @@ void StateManager11::syncViewport(const gl::Context *context)
dxMinViewportBoundsY = 0; dxMinViewportBoundsY = 0;
} }
bool clipSpaceOriginLowerLeft = glState.getClipSpaceOrigin() == gl::ClipSpaceOrigin::LowerLeft;
mShaderConstants.onClipControlChange(clipSpaceOriginLowerLeft,
glState.isClipControlDepthZeroToOne());
const auto &viewport = glState.getViewport(); const auto &viewport = glState.getViewport();
int dxViewportTopLeftX = 0; int dxViewportTopLeftX = 0;
@ -1447,7 +1474,7 @@ void StateManager11::syncViewport(const gl::Context *context)
D3D11_VIEWPORT dxViewport; D3D11_VIEWPORT dxViewport;
dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX); dxViewport.TopLeftX = static_cast<float>(dxViewportTopLeftX);
if (mCurPresentPathFastEnabled) if (mCurPresentPathFastEnabled && clipSpaceOriginLowerLeft)
{ {
// When present path fast is active and we're rendering to framebuffer 0, we must invert // When present path fast is active and we're rendering to framebuffer 0, we must invert
// the viewport in Y-axis. // the viewport in Y-axis.

Просмотреть файл

@ -53,6 +53,7 @@ class ShaderConstants11 : angle::NonCopyable
void onImageChange(gl::ShaderType shaderType, void onImageChange(gl::ShaderType shaderType,
unsigned int imageIndex, unsigned int imageIndex,
const gl::ImageUnit &imageUnit); const gl::ImageUnit &imageUnit);
void onClipControlChange(bool lowerLeft, bool zeroToOne);
angle::Result updateBuffer(const gl::Context *context, angle::Result updateBuffer(const gl::Context *context,
Renderer11 *renderer, Renderer11 *renderer,
@ -69,7 +70,10 @@ class ShaderConstants11 : angle::NonCopyable
viewCoords{.0f}, viewCoords{.0f},
viewScale{.0f}, viewScale{.0f},
multiviewWriteToViewportIndex{.0f}, multiviewWriteToViewportIndex{.0f},
firstVertex{0} clipControlOrigin{-1.0f},
clipControlZeroToOne{.0f},
firstVertex{0},
padding{.0f, .0f}
{} {}
float depthRange[4]; float depthRange[4];
@ -81,8 +85,19 @@ class ShaderConstants11 : angle::NonCopyable
// whenever a multi-view draw framebuffer is made active. // whenever a multi-view draw framebuffer is made active.
float multiviewWriteToViewportIndex; float multiviewWriteToViewportIndex;
// EXT_clip_control
// Multiplied with Y coordinate: -1.0 for GL_LOWER_LEFT_EXT, 1.0f for GL_UPPER_LEFT_EXT
float clipControlOrigin;
// 0.0 for GL_NEGATIVE_ONE_TO_ONE_EXT, 1.0 for GL_ZERO_TO_ONE_EXT
float clipControlZeroToOne;
uint32_t firstVertex; uint32_t firstVertex;
// Added here to manually pad the struct to 16 byte boundary
float padding[2];
}; };
static_assert(sizeof(Vertex) % 16u == 0,
"D3D11 constant buffers must be multiples of 16 bytes");
struct Pixel struct Pixel
{ {
@ -91,8 +106,8 @@ class ShaderConstants11 : angle::NonCopyable
viewCoords{.0f}, viewCoords{.0f},
depthFront{.0f}, depthFront{.0f},
viewScale{.0f}, viewScale{.0f},
multiviewWriteToViewportIndex(0), multiviewWriteToViewportIndex{.0f},
padding(0) padding{.0f}
{} {}
float depthRange[4]; float depthRange[4];
@ -107,6 +122,7 @@ class ShaderConstants11 : angle::NonCopyable
// Added here to manually pad the struct. // Added here to manually pad the struct.
float padding; float padding;
}; };
static_assert(sizeof(Pixel) % 16u == 0, "D3D11 constant buffers must be multiples of 16 bytes");
struct Compute struct Compute
{ {

Просмотреть файл

@ -1666,6 +1666,9 @@ void GenerateCaps(ID3D11Device *device,
extensions->readStencilNV = false; extensions->readStencilNV = false;
extensions->depthBufferFloat2NV = false; extensions->depthBufferFloat2NV = false;
// GL_EXT_clip_control
extensions->clipControlEXT = (renderer11DeviceCaps.featureLevel >= D3D_FEATURE_LEVEL_9_3);
// D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing. // D3D11 Feature Level 10_0+ uses SV_IsFrontFace in HLSL to emulate gl_FrontFacing.
// D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't // D3D11 Feature Level 9_3 doesn't support SV_IsFrontFace, and has no equivalent, so can't
// support gl_FrontFacing. // support gl_FrontFacing.