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
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)
{
mUniformHLSL->samplerMetadataUniforms(out, "c4");
......@@ -631,6 +638,13 @@ void OutputHLSL::header(TInfoSinkBase &out, const BuiltInFunctionEmulator *built
out << " float2 dx_ViewCoords : packoffset(c2);\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)
{
mUniformHLSL->samplerMetadataUniforms(out, "c4");
......
......@@ -396,6 +396,11 @@ void DynamicHLSL::generateVaryingLinkHLSL(const VaryingPacking &varyingPacking,
<< builtins.glViewportIndex.str() << ";\n";
}
if (builtins.glLayer.enabled)
{
hlslStream << " nointerpolation uint gl_Layer : " << builtins.glLayer.str() << ";\n";
}
std::string varyingSemantic =
GetVaryingSemantic(mRenderer->getMajorShaderModel(), programUsesPointSize);
......@@ -948,12 +953,27 @@ std::string DynamicHLSL::generateGeometryShaderPreamble(const VaryingPacking &va
<< "#endif // ANGLE_POINT_SPRITE_SHADER\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"
<< "void selectView(inout GS_OUTPUT output, GS_INPUT input)\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";
}
......@@ -1022,18 +1042,34 @@ std::string DynamicHLSL::generateGeometryShaderHLSL(gl::PrimitiveType primitiveT
break;
}
if (pointSprites)
if (pointSprites || hasANGLEMultiviewEnabled)
{
shaderStream << "#define ANGLE_POINT_SPRITE_SHADER\n"
"\n"
"uniform float4 dx_ViewCoords : register(c1);\n";
shaderStream << "cbuffer DriverConstants : register(b0)\n"
"{\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"
"{\n"
" float2( 0.5f, -0.5f),\n"
......@@ -1313,12 +1349,20 @@ void BuiltinVaryingsD3D::updateBuiltins(ShaderType shaderType,
if (shaderType == SHADER_PIXEL && metadata.hasANGLEMultiviewEnabled())
{
builtins->glViewIDOVR.enableSystem("SV_ViewportArrayIndex");
builtins->glViewIDOVR.enable(userSemantic, reservedSemanticIndex++);
}
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->glLayer.enableSystem("SV_RenderTargetArrayIndex");
}
// Special case: do not include PSIZE semantic in HLSL 3 pixel shaders
......
......@@ -78,6 +78,7 @@ struct BuiltinInfo
BuiltinVarying glPointSize;
BuiltinVarying glViewIDOVR;
BuiltinVarying glViewportIndex;
BuiltinVarying glLayer;
};
inline std::string GetVaryingSemantic(int majorShaderModel, bool programUsesPointSize)
......
......@@ -743,6 +743,24 @@ void StateManager11::handleMultiviewDrawFramebufferChange(const gl::Context *con
mInternalDirtyBits.set(DIRTY_BIT_VIEWPORT_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,
......@@ -1038,13 +1056,11 @@ void StateManager11::syncViewport(const gl::Context *context)
mPixelConstants.viewScale[0] = 1.0f;
mPixelConstants.viewScale[1] = mCurPresentPathFastEnabled ? 1.0f : -1.0f;
mPixelConstants.viewScale[2] = 1.0f;
mPixelConstants.viewScale[3] = 1.0f;
// Updates to the multiviewWriteToViewportIndex member are to be handled whenever the draw
// framebuffer's layout is changed.
mVertexConstants.viewScale[0] = mPixelConstants.viewScale[0];
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)
......
......@@ -29,22 +29,56 @@ struct Renderer11DeviceCaps;
struct dx_VertexConstants11
{
dx_VertexConstants11()
: depthRange{.0f},
viewAdjust{.0f},
viewCoords{.0f},
viewScale{.0f},
multiviewWriteToViewportIndex{.0f},
padding{.0f}
{
}
float depthRange[4];
float viewAdjust[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
{
dx_PixelConstants11()
: depthRange{.0f},
viewCoords{.0f},
depthFront{.0f},
viewScale{.0f},
multiviewWriteToViewportIndex{.0f},
padding{.0f}
{
}
float depthRange[4];
float viewCoords[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
{
dx_ComputeConstants11() : numWorkGroups{0u}, padding{0u} {}
unsigned int numWorkGroups[3];
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