Commit 72b4e1e5 by Martin Radev Committed by Commit Bot

D3D11: Add support for multiview layered rendering

A branch is added in the geometry shader to select either the viewport, or texture layer which is being rendered to based on the value of a uniform in the driver constant buffer. Using this approach there is no need for separate programs for side-by-side and layered rendering. BUG=angleproject:2062 TEST=angle_end2end_tests Change-Id: I66701164ff02a851c13695d5409f8ad350534e69 Reviewed-on: https://chromium-review.googlesource.com/645547 Commit-Queue: Martin Radev <mradev@nvidia.com> Reviewed-by: 's avatarOlli Etuaho <oetuaho@nvidia.com>
parent b5c5fb1b
...@@ -518,6 +518,13 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -518,6 +518,13 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << " float2 dx_ViewScale : packoffset(c3);\n"; out << " float2 dx_ViewScale : packoffset(c3);\n";
} }
if (mHasMultiviewExtensionEnabled)
{
// We have to add a value which we can use to keep track of which multi-view code
// path is to be selected in the GS.
out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
}
if (mOutputType == SH_HLSL_4_1_OUTPUT) if (mOutputType == SH_HLSL_4_1_OUTPUT)
{ {
mUniformHLSL->samplerMetadataUniforms(out, "c4"); mUniformHLSL->samplerMetadataUniforms(out, "c4");
...@@ -631,6 +638,13 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built ...@@ -631,6 +638,13 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << " float2 dx_ViewCoords : packoffset(c2);\n"; out << " float2 dx_ViewCoords : packoffset(c2);\n";
out << " float2 dx_ViewScale : packoffset(c3);\n"; out << " float2 dx_ViewScale : packoffset(c3);\n";
if (mHasMultiviewExtensionEnabled)
{
// We have to add a value which we can use to keep track of which multi-view code
// path is to be selected in the GS.
out << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
}
if (mOutputType == SH_HLSL_4_1_OUTPUT) if (mOutputType == SH_HLSL_4_1_OUTPUT)
{ {
mUniformHLSL->samplerMetadataUniforms(out, "c4"); mUniformHLSL->samplerMetadataUniforms(out, "c4");
......
...@@ -396,6 +396,11 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking, ...@@ -396,6 +396,11 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking,
<< builtins.glViewportIndex.str() << ";\n"; << builtins.glViewportIndex.str() << ";\n";
} }
if (builtins.glLayer.enabled)
{
hlslStream << " nointerpolation uint gl_Layer : " << builtins.glLayer.str() << ";\n";
}
std::string varyingSemantic = std::string varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize); GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize);
...@@ -948,12 +953,27 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va ...@@ -948,12 +953,27 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va
<< "#endif // ANGLE_POINT_SPRITE_SHADER\n" << "#endif // ANGLE_POINT_SPRITE_SHADER\n"
<< "}\n"; << "}\n";
if (builtinsD3D[SHADER_GEOMETRY].glViewportIndex.enabled && hasANGLEMultiviewEnabled) if (hasANGLEMultiviewEnabled)
{ {
ASSERT(builtinsD3D[SHADER_GEOMETRY].glViewportIndex.enabled &&
builtinsD3D[SHADER_GEOMETRY].glLayer.enabled);
// According to the HLSL reference, using SV_RenderTargetArrayIndex is only valid if the
// render target is an array resource. Because of this we do not write to gl_Layer if we are
// taking the side-by-side code path. We still select the viewport index in the layered code
// path as that is always valid. See:
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb509647(v=vs.85).aspx
preambleStream << "\n" preambleStream << "\n"
<< "void selectView(inout GS_OUTPUT output, GS_INPUT input)\n" << "void selectView(inout GS_OUTPUT output, GS_INPUT input)\n"
<< "{\n" << "{\n"
<< " output.gl_ViewportIndex = input.gl_ViewID_OVR;\n" << " output.gl_ViewID_OVR = input.gl_ViewID_OVR;\n"
<< " if (multiviewSelectViewportIndex)\n"
<< " {\n"
<< " output.gl_ViewportIndex = input.gl_ViewID_OVR;\n"
<< " } else {\n"
<< " output.gl_ViewportIndex = 0;\n"
<< " output.gl_Layer = input.gl_ViewID_OVR;\n"
<< " }\n"
<< "}\n"; << "}\n";
} }
...@@ -1022,18 +1042,34 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT ...@@ -1022,18 +1042,34 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT
break; break;
} }
if (pointSprites) if (pointSprites || hasANGLEMultiviewEnabled)
{ {
shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n" shaderStream << "cbuffer DriverConstants : register(b0)\n"
"\n" "{\n";
"uniform float4 dx_ViewCoords : register(c1);\n";
if (useViewScale) if (pointSprites)
{ {
shaderStream << "uniform float2 dx_ViewScale : register(c3);\n"; shaderStream << " float4 dx_ViewCoords : packoffset(c1);\n";
if (useViewScale)
{
shaderStream << " float2 dx_ViewScale : packoffset(c3);\n";
}
} }
shaderStream << "\n" if (hasANGLEMultiviewEnabled)
{
// We have to add a value which we can use to keep track of which multi-view code path
// is to be selected in the GS.
shaderStream << " float multiviewSelectViewportIndex : packoffset(c3.z);\n";
}
shaderStream << "};\n\n";
}
if (pointSprites)
{
shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n"
"\n"
"static float2 pointSpriteCorners[] = \n" "static float2 pointSpriteCorners[] = \n"
"{\n" "{\n"
" float2( 0.5f, -0.5f),\n" " float2( 0.5f, -0.5f),\n"
...@@ -1313,12 +1349,20 @@ void BuiltinVaryingsD3D::updateBuiltins(ShaderType shaderType, ...@@ -1313,12 +1349,20 @@ void BuiltinVaryingsD3D::updateBuiltins(ShaderType shaderType,
if (shaderType == SHADER_PIXEL && metadata.hasANGLEMultiviewEnabled()) if (shaderType == SHADER_PIXEL && metadata.hasANGLEMultiviewEnabled())
{ {
builtins->glViewIDOVR.enableSystem("SV_ViewportArrayIndex"); builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++);
} }
if (shaderType == SHADER_GEOMETRY && metadata.hasANGLEMultiviewEnabled()) if (shaderType == SHADER_GEOMETRY && metadata.hasANGLEMultiviewEnabled())
{ {
// Although it is possible to retrieve gl_ViewID_OVR from the value of
// SV_ViewportArrayIndex or SV_RenderTargetArrayIndex based on the multi-view state in the
// driver constant buffer, it is easier and cleaner to pass it as a varying.
builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++);
// gl_Layer and gl_ViewportIndex are necessary so that we can write to either based on the
// multiview state in the driver constant buffer.
builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex"); builtins->glViewportIndex.enableSystem("SV_ViewportArrayIndex");
builtins->glLayer.enableSystem("SV_RenderTargetArrayIndex");
} }
// Special case: do not include PSIZE semantic in HLSL 3 pixel shaders // Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
......
...@@ -78,6 +78,7 @@ struct BuiltinInfo ...@@ -78,6 +78,7 @@ struct BuiltinInfo
BuiltinVarying glPointSize; BuiltinVarying glPointSize;
BuiltinVarying glViewIDOVR; BuiltinVarying glViewIDOVR;
BuiltinVarying glViewportIndex; BuiltinVarying glViewportIndex;
BuiltinVarying glLayer;
}; };
inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize) inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
......
...@@ -743,6 +743,24 @@ void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *con ...@@ -743,6 +743,24 @@ void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *con
mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE); mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_STATE);
mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE); mInternalDirtyBits.set(DIRTY_BIT_SCISSOR_STATE);
} }
switch (drawFramebuffer->getMultiviewLayout())
{
case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE:
mVertexConstants.multiviewWriteToViewportIndex = 1.0f;
mPixelConstants.multiviewWriteToViewportIndex = 1.0f;
break;
case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE:
// Because the base view index is applied as an offset to the 2D texture array when the
// RTV is created, we just have to pass a boolean to select which code path is to be
// used.
mVertexConstants.multiviewWriteToViewportIndex = 0.0f;
mPixelConstants.multiviewWriteToViewportIndex = 0.0f;
break;
default:
// There is no need to update the value in the constant buffer if the active framebuffer
// object does not have a multiview layout.
break;
}
} }
gl::Error StateManager11::syncBlendState(const gl::Context *context, gl::Error StateManager11::syncBlendState(const gl::Context *context,
...@@ -1038,13 +1056,11 @@ void StateManager11::syncViewport(const gl::Context *context) ...@@ -1038,13 +1056,11 @@ void StateManager11::syncViewport(const gl::Context *context)
mPixelConstants.viewScale[0] = 1.0f; mPixelConstants.viewScale[0] = 1.0f;
mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f; mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f;
mPixelConstants.viewScale[2] = 1.0f; // Updates to the multiviewWriteToViewportIndex member are to be handled whenever the draw
mPixelConstants.viewScale[3] = 1.0f; // framebuffer's layout is changed.
mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0]; mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0];
mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1]; mVertexConstants.viewScale[1] = mPixelConstants.viewScale[1];
mVertexConstants.viewScale[2] = mPixelConstants.viewScale[2];
mVertexConstants.viewScale[3] = mPixelConstants.viewScale[3];
} }
void StateManager11::invalidateRenderTarget(const gl::Context *context) void StateManager11::invalidateRenderTarget(const gl::Context *context)
......
...@@ -29,22 +29,56 @@ struct Renderer11DeviceCaps; ...@@ -29,22 +29,56 @@ struct Renderer11DeviceCaps;
struct dx_VertexConstants11 struct dx_VertexConstants11
{ {
dx_VertexConstants11()
: depthRange{.0f},
viewAdjust{.0f},
viewCoords{.0f},
viewScale{.0f},
multiviewWriteToViewportIndex{.0f},
padding{.0f}
{
}
float depthRange[4]; float depthRange[4];
float viewAdjust[4]; float viewAdjust[4];
float viewCoords[4]; float viewCoords[4];
float viewScale[4]; float viewScale[2];
// multiviewWriteToViewportIndex is used to select either the side-by-side or layered code-path
// in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated whenever a
// multi-view draw framebuffer is made active.
float multiviewWriteToViewportIndex;
// Added here to manually pad the struct.
float padding;
}; };
struct dx_PixelConstants11 struct dx_PixelConstants11
{ {
dx_PixelConstants11()
: depthRange{.0f},
viewCoords{.0f},
depthFront{.0f},
viewScale{.0f},
multiviewWriteToViewportIndex{.0f},
padding{.0f}
{
}
float depthRange[4]; float depthRange[4];
float viewCoords[4]; float viewCoords[4];
float depthFront[4]; float depthFront[4];
float viewScale[4]; float viewScale[2];
// multiviewWriteToViewportIndex is used to select either the side-by-side or layered code-path
// in the GS. It's value, if set, is either 0.0f or 1.0f. The value is updated whenever a
// multi-view draw framebuffer is made active.
float multiviewWriteToViewportIndex;
// Added here to manually pad the struct.
float padding;
}; };
struct dx_ComputeConstants11 struct dx_ComputeConstants11
{ {
dx_ComputeConstants11() : numWorkGroups{0u}, padding{0u} {}
unsigned int numWorkGroups[3]; unsigned int numWorkGroups[3];
unsigned int padding; // This just pads the struct to 16 bytes unsigned int padding; // This just pads the struct to 16 bytes
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment