Commit 51f522f1 by Jamie Madill Committed by Commit Bot

D3D11: Fix program binary crash with UBO bindings.

This crash could occur when saving and loading a program with UBO bindings that was never used in a draw operation. The fix is to ensure the D3DLinkedUniforms are properly initialized before we save the program binary. BUG=angleproject:1637 Change-Id: I9691e375d19dc628f34f351ae94b68bd0f2f76b8 Reviewed-on: https://chromium-review.googlesource.com/422665 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org>
parent 09b04a2f
...@@ -1037,6 +1037,10 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) ...@@ -1037,6 +1037,10 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeInt(uniform->registerElement); stream->writeInt(uniform->registerElement);
} }
// Ensure we init the uniform block structure data if we should.
// http://anglebug.com/1637
ensureUniformBlocksInitialized();
stream->writeInt(mD3DUniformBlocks.size()); stream->writeInt(mD3DUniformBlocks.size());
for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks) for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
{ {
...@@ -1131,7 +1135,7 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream) ...@@ -1131,7 +1135,7 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeBytes(geometryExe->getFunction(), geometryShaderSize); stream->writeBytes(geometryExe->getFunction(), geometryShaderSize);
} }
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */) void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */)
...@@ -1174,7 +1178,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum ...@@ -1174,7 +1178,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature)) if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
{ {
*outExectuable = mPixelExecutables[executableIndex]->shaderExecutable(); *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable();
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
} }
...@@ -1218,7 +1222,7 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &i ...@@ -1218,7 +1222,7 @@ gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::InputLayout &i
if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature)) if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature))
{ {
*outExectuable = mVertexExecutables[executableIndex]->shaderExecutable(); *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable();
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
} }
...@@ -1266,7 +1270,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::ContextSta ...@@ -1266,7 +1270,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::ContextSta
// Return a null shader if the current rendering doesn't use a geometry shader // Return a null shader if the current rendering doesn't use a geometry shader
if (!usesGeometryShader(drawMode)) if (!usesGeometryShader(drawMode))
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode); gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
...@@ -1277,7 +1281,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::ContextSta ...@@ -1277,7 +1281,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::ContextSta
{ {
*outExecutable = mGeometryExecutables[geometryShaderType]; *outExecutable = mGeometryExecutables[geometryShaderType];
} }
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL( std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(
...@@ -1588,9 +1592,13 @@ void ProgramD3D::initUniformBlockInfo() ...@@ -1588,9 +1592,13 @@ void ProgramD3D::initUniformBlockInfo()
} }
} }
void ProgramD3D::assignUniformBlockRegisters() void ProgramD3D::ensureUniformBlocksInitialized()
{ {
mD3DUniformBlocks.clear(); // Lazy init.
if (mState.getUniformBlocks().empty() || !mD3DUniformBlocks.empty())
{
return;
}
// Assign registers and update sizes. // Assign registers and update sizes.
const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mState.getAttachedVertexShader()); const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mState.getAttachedVertexShader());
...@@ -1657,21 +1665,17 @@ gl::Error ProgramD3D::applyUniforms(GLenum drawMode) ...@@ -1657,21 +1665,17 @@ gl::Error ProgramD3D::applyUniforms(GLenum drawMode)
d3dUniform->dirty = false; d3dUniform->dirty = false;
} }
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
gl::Error ProgramD3D::applyUniformBuffers(const gl::ContextState &data) gl::Error ProgramD3D::applyUniformBuffers(const gl::ContextState &data)
{ {
if (mState.getUniformBlocks().empty()) if (mState.getUniformBlocks().empty())
{ {
return gl::Error(GL_NO_ERROR); return gl::NoError();
} }
// Lazy init. ensureUniformBlocksInitialized();
if (mD3DUniformBlocks.empty())
{
assignUniformBlockRegisters();
}
mVertexUBOCache.clear(); mVertexUBOCache.clear();
mFragmentUBOCache.clear(); mFragmentUBOCache.clear();
......
...@@ -361,7 +361,7 @@ class ProgramD3D : public ProgramImpl ...@@ -361,7 +361,7 @@ class ProgramD3D : public ProgramImpl
void initAttribLocationsToD3DSemantic(); void initAttribLocationsToD3DSemantic();
void reset(); void reset();
void assignUniformBlockRegisters(); void ensureUniformBlocksInitialized();
void initUniformBlockInfo(); void initUniformBlockInfo();
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock); size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
......
...@@ -225,10 +225,11 @@ ANGLE_INSTANTIATE_TEST(ProgramBinaryTest, ...@@ -225,10 +225,11 @@ ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
class ProgramBinaryES3Test : public ANGLETest class ProgramBinaryES3Test : public ANGLETest
{ {
protected:
void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
}; };
// Tests that saving and loading a program perserves uniform block binding info. void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
{ {
// We can't run the test if no program binary formats are supported. // We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0; GLint binaryFormatCount = 0;
...@@ -279,9 +280,12 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding) ...@@ -279,9 +280,12 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(program.get(), "position", 0.5f); if (drawWithProgramFirst)
ASSERT_GL_NO_ERROR(); {
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
// Read back the binary. // Read back the binary.
GLint programLength = 0; GLint programLength = 0;
...@@ -308,6 +312,19 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding) ...@@ -308,6 +312,19 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
} }
// Tests that saving and loading a program perserves uniform block binding info.
TEST_P(ProgramBinaryES3Test, UniformBlockBindingWithDraw)
{
testBinaryAndUBOBlockIndexes(true);
}
// Same as above, but does not do an initial draw with the program. Covers an ANGLE crash.
// http://anglebug.com/1637
TEST_P(ProgramBinaryES3Test, UniformBlockBindingNoDraw)
{
testBinaryAndUBOBlockIndexes(false);
}
ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES()); ANGLE_INSTANTIATE_TEST(ProgramBinaryES3Test, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
class ProgramBinaryTransformFeedbackTest : public ANGLETest class ProgramBinaryTransformFeedbackTest : public ANGLETest
......
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