Commit 61d5325e by Jamie Madill Committed by Commit Bot

D3D9: Improve varying packing failure mode.

D3D9 has a special limitation on varying packing, where each variable takes up a full register width, and cannot share space with other packed varyings. A bug was counting registers incorrectly on D3D9. Fix this by introducing a new limitation exposed to the ANGLE front-end via the gl::Limitations structure. Now varying packing will fail correctly in the ANGLE linking front-end with a more descriptive error message, as such: "Could not pack varying blah" "Note: Additional non-conformant packing restrictions are enforced on D3D9." Also change the packing so that input built-in variables are counted towards varying limits (e.g. gl_PointSize), except for gl_Position. On D3D9 we don't pack gl_PointSize, since it is used in a special extra PSIZE register. Also update some tests to be more robust. Bug: chromium:804799 Change-Id: I9027266a8b66a28626f038f259bff42ebf09dcd2 Reviewed-on: https://chromium-review.googlesource.com/889898 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 191a84a8
...@@ -253,7 +253,8 @@ Limitations::Limitations() ...@@ -253,7 +253,8 @@ Limitations::Limitations()
attributeZeroRequiresZeroDivisorInEXT(false), attributeZeroRequiresZeroDivisorInEXT(false),
noSeparateStencilRefsAndMasks(false), noSeparateStencilRefsAndMasks(false),
shadersRequireIndexedLoopValidation(false), shadersRequireIndexedLoopValidation(false),
noSimultaneousConstantColorAndAlphaBlendFunc(false) noSimultaneousConstantColorAndAlphaBlendFunc(false),
noFlexibleVaryingPacking(false)
{ {
} }
......
...@@ -410,6 +410,9 @@ struct Limitations ...@@ -410,6 +410,9 @@ struct Limitations
// Renderer doesn't support Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA // Renderer doesn't support Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA
// and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR blend functions. // and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR blend functions.
bool noSimultaneousConstantColorAndAlphaBlendFunc; bool noSimultaneousConstantColorAndAlphaBlendFunc;
// D3D9 does not support flexible varying register packing.
bool noFlexibleVaryingPacking;
}; };
struct TypePrecision struct TypePrecision
......
...@@ -986,8 +986,16 @@ Error Program::link(const gl::Context *context) ...@@ -986,8 +986,16 @@ Error Program::link(const gl::Context *context)
// Map the varyings to the register file // Map the varyings to the register file
// In WebGL, we use a slightly different handling for packing variables. // In WebGL, we use a slightly different handling for packing variables.
auto packMode = data.getExtensions().webglCompatibility ? PackMode::WEBGL_STRICT gl::PackMode packMode = PackMode::ANGLE_RELAXED;
: PackMode::ANGLE_RELAXED; if (data.getLimitations().noFlexibleVaryingPacking)
{
// D3D9 pack mode is strictly more strict than WebGL, so takes priority.
packMode = PackMode::ANGLE_NON_CONFORMANT_D3D9;
}
else if (data.getExtensions().webglCompatibility)
{
packMode = PackMode::WEBGL_STRICT;
}
ProgramLinkedResources resources = { ProgramLinkedResources resources = {
{data.getCaps().maxVaryingVectors, packMode}, {data.getCaps().maxVaryingVectors, packMode},
......
...@@ -69,7 +69,7 @@ VaryingPacking::~VaryingPacking() = default; ...@@ -69,7 +69,7 @@ VaryingPacking::~VaryingPacking() = default;
// Returns false if unsuccessful. // Returns false if unsuccessful.
bool VaryingPacking::packVarying(const PackedVarying &packedVarying) bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
{ {
const auto &varying = *packedVarying.varying; const sh::ShaderVariable &varying = *packedVarying.varying;
// "Non - square matrices of type matCxR consume the same space as a square matrix of type matN // "Non - square matrices of type matCxR consume the same space as a square matrix of type matN
// where N is the greater of C and R." // where N is the greater of C and R."
...@@ -80,9 +80,16 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying) ...@@ -80,9 +80,16 @@ bool VaryingPacking::packVarying(const PackedVarying &packedVarying)
unsigned int varyingRows = gl::VariableRowCount(transposedType); unsigned int varyingRows = gl::VariableRowCount(transposedType);
unsigned int varyingColumns = gl::VariableColumnCount(transposedType); unsigned int varyingColumns = gl::VariableColumnCount(transposedType);
// Special pack mode for D3D9. Each varying takes a full register, no sharing.
// TODO(jmadill): Implement more sophisticated component packing in D3D9.
if (mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
{
varyingColumns = 4;
}
// "Variables of type mat2 occupies 2 complete rows." // "Variables of type mat2 occupies 2 complete rows."
// For non-WebGL contexts, we allow mat2 to occupy only two columns per row. // For non-WebGL contexts, we allow mat2 to occupy only two columns per row.
if (mPackMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2) else if (mPackMode == PackMode::WEBGL_STRICT && varying.type == GL_FLOAT_MAT2)
{ {
varyingColumns = 4; varyingColumns = 4;
} }
...@@ -286,29 +293,40 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog, ...@@ -286,29 +293,40 @@ bool VaryingPacking::collectAndPackUserVaryings(gl::InfoLog &infoLog,
// Only pack statically used varyings that have a matched input or output, plus special // Only pack statically used varyings that have a matched input or output, plus special
// builtins. // builtins.
if (((input && output) || (output && output->isBuiltIn())) && output->staticUse) if ((input && output && output->staticUse) ||
(input && input->isBuiltIn() && input->staticUse) ||
(output && output->isBuiltIn() && output->staticUse))
{ {
// Will get the vertex shader interpolation by default. const sh::Varying *varying = output ? output : input;
auto interpolation = ref.second.get()->interpolation;
// Note that we lose the vertex shader static use information here. The data for the // Don't count gl_Position. Also don't count gl_PointSize for D3D9.
// variable is taken from the fragment shader. if (varying->name != "gl_Position" &&
if (output->isStruct()) !(varying->name == "gl_PointSize" &&
mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9))
{ {
ASSERT(!output->isArray()); // Will get the vertex shader interpolation by default.
for (const auto &field : output->fields) auto interpolation = ref.second.get()->interpolation;
// Note that we lose the vertex shader static use information here. The data for the
// variable is taken from the fragment shader.
if (varying->isStruct())
{
ASSERT(!varying->isArray());
for (const auto &field : varying->fields)
{
ASSERT(!field.isStruct() && !field.isArray());
mPackedVaryings.push_back(
PackedVarying(field, interpolation, varying->name));
uniqueFullNames.insert(mPackedVaryings.back().fullName());
}
}
else
{ {
ASSERT(!field.isStruct() && !field.isArray()); mPackedVaryings.push_back(PackedVarying(*varying, interpolation));
mPackedVaryings.push_back(PackedVarying(field, interpolation, output->name));
uniqueFullNames.insert(mPackedVaryings.back().fullName()); uniqueFullNames.insert(mPackedVaryings.back().fullName());
} }
continue;
} }
else
{
mPackedVaryings.push_back(PackedVarying(*output, interpolation));
uniqueFullNames.insert(mPackedVaryings.back().fullName());
}
continue;
} }
// Keep Transform FB varyings in the merged list always. // Keep Transform FB varyings in the merged list always.
...@@ -383,6 +401,14 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -383,6 +401,14 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
if (!packVarying(packedVarying)) if (!packVarying(packedVarying))
{ {
infoLog << "Could not pack varying " << packedVarying.fullName(); infoLog << "Could not pack varying " << packedVarying.fullName();
// TODO(jmadill): Implement more sophisticated component packing in D3D9.
if (mPackMode == PackMode::ANGLE_NON_CONFORMANT_D3D9)
{
infoLog << "Note: Additional non-conformant packing restrictions are enforced on "
"D3D9.";
}
return false; return false;
} }
} }
...@@ -400,19 +426,4 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog, ...@@ -400,19 +426,4 @@ bool VaryingPacking::packUserVaryings(gl::InfoLog &infoLog,
return true; return true;
} }
unsigned int VaryingPacking::getRegisterCount() const
{
unsigned int count = 0;
for (const Register &reg : mRegisterMap)
{
if (reg.data[0] || reg.data[1] || reg.data[2] || reg.data[3])
{
++count;
}
}
return count;
}
} // namespace rx } // namespace rx
...@@ -141,6 +141,9 @@ enum class PackMode ...@@ -141,6 +141,9 @@ enum class PackMode
// We allow mat2 to take a 2x2 chunk. // We allow mat2 to take a 2x2 chunk.
ANGLE_RELAXED, ANGLE_RELAXED,
// Each varying takes a separate register. No register sharing.
ANGLE_NON_CONFORMANT_D3D9,
}; };
class VaryingPacking final : angle::NonCopyable class VaryingPacking final : angle::NonCopyable
...@@ -175,8 +178,6 @@ class VaryingPacking final : angle::NonCopyable ...@@ -175,8 +178,6 @@ class VaryingPacking final : angle::NonCopyable
{ {
return static_cast<unsigned int>(mRegisterList.size()); return static_cast<unsigned int>(mRegisterList.size());
} }
unsigned int getRegisterCount() const;
size_t getRegisterMapSize() const { return mRegisterMap.size(); }
private: private:
bool packVarying(const PackedVarying &packedVarying); bool packVarying(const PackedVarying &packedVarying);
......
...@@ -1729,16 +1729,6 @@ gl::LinkResult ProgramD3D::link(const gl::Context *context, ...@@ -1729,16 +1729,6 @@ gl::LinkResult ProgramD3D::link(const gl::Context *context,
} }
} }
// TODO(jmadill): Implement more sophisticated component packing in D3D9.
// We can fail here because we use one semantic per GLSL varying. D3D11 can pack varyings
// intelligently, but D3D9 assumes one semantic per register.
if (mRenderer->getRendererClass() == RENDERER_D3D9 &&
resources.varyingPacking.getMaxSemanticIndex() > data.getCaps().maxVaryingVectors)
{
infoLog << "Cannot pack these varyings on D3D9.";
return false;
}
ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D); ProgramD3DMetadata metadata(mRenderer, vertexShaderD3D, fragmentShaderD3D);
BuiltinVaryingsD3D builtins(metadata, resources.varyingPacking); BuiltinVaryingsD3D builtins(metadata, resources.varyingPacking);
......
...@@ -292,6 +292,15 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples) ...@@ -292,6 +292,15 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples)
namespace d3d9_gl namespace d3d9_gl
{ {
unsigned int GetReservedVaryingVectors()
{
// We reserve two registers for "dx_Position" and "gl_Position". The spec says they
// don't count towards the varying limit, so we must make space for them. We also
// reserve the last register since it can only pass a PSIZE, and not any arbitrary
// varying.
return 3;
}
unsigned int GetReservedVertexUniformVectors() unsigned int GetReservedVertexUniformVectors()
{ {
return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange. return 3; // dx_ViewCoords, dx_ViewAdjust and dx_DepthRange.
...@@ -472,9 +481,9 @@ void GenerateCaps(IDirect3D9 *d3d9, ...@@ -472,9 +481,9 @@ void GenerateCaps(IDirect3D9 *d3d9,
caps->maxVertexUniformBlocks = 0; caps->maxVertexUniformBlocks = 0;
// SM3 only supports 11 output variables, with a special 12th register for PSIZE. // SM3 only supports 12 output variables, but the special 12th register is only for PSIZE.
const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9; const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM3 = 12 - GetReservedVaryingVectors();
const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7; const unsigned int MAX_VERTEX_OUTPUT_VECTORS_SM2 = 10 - GetReservedVaryingVectors();
caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3 caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
: MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4; : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4;
...@@ -615,6 +624,10 @@ void GenerateCaps(IDirect3D9 *d3d9, ...@@ -615,6 +624,10 @@ void GenerateCaps(IDirect3D9 *d3d9,
// D3D9 cannot support constant color and alpha blend funcs together // D3D9 cannot support constant color and alpha blend funcs together
limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true; limitations->noSimultaneousConstantColorAndAlphaBlendFunc = true;
// D3D9 cannot support packing more than one variable to a single varying.
// TODO(jmadill): Implement more sophisticated component packing in D3D9.
limitations->noFlexibleVaryingPacking = true;
} }
} }
......
...@@ -48,6 +48,8 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples); ...@@ -48,6 +48,8 @@ D3DMULTISAMPLE_TYPE GetMultisampleType(GLuint samples);
namespace d3d9_gl namespace d3d9_gl
{ {
unsigned int GetReservedVaryingVectors();
unsigned int GetReservedVertexUniformVectors(); unsigned int GetReservedVertexUniformVectors();
unsigned int GetReservedFragmentUniformVectors(); unsigned int GetReservedFragmentUniformVectors();
......
...@@ -1297,29 +1297,62 @@ TEST_P(GLSLTest, MaxVaryingVec4) ...@@ -1297,29 +1297,62 @@ TEST_P(GLSLTest, MaxVaryingVec4)
VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, false, false, true); VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings, 0, false, false, false, true);
} }
TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusTwoSpecialVariables) // Verify we can pack registers with one builtin varying.
TEST_P(GLSLTest, MaxVaryingVec4_OneBuiltin)
{ {
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
// Generate shader code that uses gl_FragCoord and gl_PointCoord, two special fragment shader variables. // Generate shader code that uses gl_FragCoord.
VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, false, true); VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 1, 0, true, false, false, true);
} }
TEST_P(GLSLTest, MaxMinusTwoVaryingVec4PlusThreeSpecialVariables) // Verify we can pack registers with two builtin varyings.
TEST_P(GLSLTest, MaxVaryingVec4_TwoBuiltins)
{ {
// TODO(geofflang): Figure out why this fails on OpenGL AMD (http://anglebug.com/1291) GLint maxVaryings = 0;
if (IsAMD() && getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE) glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
{
std::cout << "Test disabled on OpenGL." << std::endl; // Generate shader code that uses gl_FragCoord and gl_PointCoord.
return; VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, false, true);
} }
// Verify we can pack registers with three builtin varyings.
TEST_P(GLSLTest, MaxVaryingVec4_ThreeBuiltins)
{
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
// Generate shader code that uses gl_FragCoord, gl_PointCoord and gl_PointSize. // Generate shader code that uses gl_FragCoord, gl_PointCoord and gl_PointSize.
VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 2, 0, true, true, true, true); VaryingTestBase(0, 0, 0, 0, 0, 0, maxVaryings - 3, 0, true, true, true, true);
}
// This covers a problematic case in D3D9 - we are limited by the number of available semantics,
// rather than total register use.
TEST_P(GLSLTest, MaxVaryingsSpecialCases)
{
ANGLE_SKIP_TEST_IF(!IsD3D9());
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(maxVaryings, 0, 0, 0, 0, 0, 0, 0, true, false, false, false);
VaryingTestBase(maxVaryings - 1, 0, 0, 0, 0, 0, 0, 0, true, true, false, false);
VaryingTestBase(maxVaryings - 2, 0, 0, 0, 0, 0, 0, 0, true, true, false, true);
// Special case for gl_PointSize: we get it for free on D3D9.
VaryingTestBase(maxVaryings - 2, 0, 0, 0, 0, 0, 0, 0, true, true, true, true);
}
// This covers a problematic case in D3D9 - we are limited by the number of available semantics,
// rather than total register use.
TEST_P(GLSLTest, MaxMinusTwoVaryingVec2PlusOneSpecialVariable)
{
GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
// Generate shader code that uses gl_FragCoord.
VaryingTestBase(0, 0, maxVaryings, 0, 0, 0, 0, 0, true, false, false, !IsD3D9());
} }
TEST_P(GLSLTest, MaxVaryingVec3) TEST_P(GLSLTest, MaxVaryingVec3)
...@@ -1338,45 +1371,27 @@ TEST_P(GLSLTest, MaxVaryingVec3Array) ...@@ -1338,45 +1371,27 @@ TEST_P(GLSLTest, MaxVaryingVec3Array)
VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true); VaryingTestBase(0, 0, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true);
} }
// Disabled because of a failure in D3D9 // Only fails on D3D9 because of packing limitations.
TEST_P(GLSLTest, MaxVaryingVec3AndOneFloat) TEST_P(GLSLTest, MaxVaryingVec3AndOneFloat)
{ {
if (IsD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(1, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, true); VaryingTestBase(1, 0, 0, 0, maxVaryings, 0, 0, 0, false, false, false, !IsD3D9());
} }
// Disabled because of a failure in D3D9 // Only fails on D3D9 because of packing limitations.
TEST_P(GLSLTest, MaxVaryingVec3ArrayAndOneFloatArray) TEST_P(GLSLTest, MaxVaryingVec3ArrayAndOneFloatArray)
{ {
if (IsD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 1, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, true); VaryingTestBase(0, 1, 0, 0, 0, maxVaryings / 2, 0, 0, false, false, false, !IsD3D9());
} }
// Disabled because of a failure in D3D9 // Only fails on D3D9 because of packing limitations.
TEST_P(GLSLTest, TwiceMaxVaryingVec2) TEST_P(GLSLTest, TwiceMaxVaryingVec2)
{ {
if (IsD3D9())
{
std::cout << "Test disabled on D3D9." << std::endl;
return;
}
if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE) if (getPlatformRenderer() == EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE)
{ {
// TODO(geofflang): Figure out why this fails on NVIDIA's GLES driver // TODO(geofflang): Figure out why this fails on NVIDIA's GLES driver
...@@ -1397,7 +1412,7 @@ TEST_P(GLSLTest, TwiceMaxVaryingVec2) ...@@ -1397,7 +1412,7 @@ TEST_P(GLSLTest, TwiceMaxVaryingVec2)
GLint maxVaryings = 0; GLint maxVaryings = 0;
glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings); glGetIntegerv(GL_MAX_VARYING_VECTORS, &maxVaryings);
VaryingTestBase(0, 0, 2 * maxVaryings, 0, 0, 0, 0, 0, false, false, false, true); VaryingTestBase(0, 0, 2 * maxVaryings, 0, 0, 0, 0, 0, false, false, false, !IsD3D9());
} }
// Disabled because of a failure in D3D9 // Disabled because of a failure in D3D9
......
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