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)
stream->writeInt(uniform->registerElement);
}
// Ensure we init the uniform block structure data if we should.
// http://anglebug.com/1637
ensureUniformBlocksInitialized();
stream->writeInt(mD3DUniformBlocks.size());
for (const D3DUniformBlock &uniformBlock : mD3DUniformBlocks)
{
......@@ -1131,7 +1135,7 @@ gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
stream->writeBytes(geometryExe->getFunction(), geometryShaderSize);
}
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */)
......@@ -1174,7 +1178,7 @@ gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum
if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
{
*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
if (mVertexExecutables[executableIndex]->matchesSignature(mCachedVertexSignature))
{
*outExectuable = mVertexExecutables[executableIndex]->shaderExecutable();
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
}
......@@ -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
if (!usesGeometryShader(drawMode))
{
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
gl::PrimitiveType geometryShaderType = GetGeometryShaderTypeFromDrawMode(drawMode);
......@@ -1277,7 +1281,7 @@ gl::Error ProgramD3D::getGeometryExecutableForPrimitiveType(const gl::ContextSta
{
*outExecutable = mGeometryExecutables[geometryShaderType];
}
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(
......@@ -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.
const ShaderD3D *vertexShaderD3D = GetImplAs<ShaderD3D>(mState.getAttachedVertexShader());
......@@ -1657,21 +1665,17 @@ gl::Error ProgramD3D::applyUniforms(GLenum drawMode)
d3dUniform->dirty = false;
}
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
gl::Error ProgramD3D::applyUniformBuffers(const gl::ContextState &data)
{
if (mState.getUniformBlocks().empty())
{
return gl::Error(GL_NO_ERROR);
return gl::NoError();
}
// Lazy init.
if (mD3DUniformBlocks.empty())
{
assignUniformBlockRegisters();
}
ensureUniformBlocksInitialized();
mVertexUBOCache.clear();
mFragmentUBOCache.clear();
......
......@@ -361,7 +361,7 @@ class ProgramD3D : public ProgramImpl
void initAttribLocationsToD3DSemantic();
void reset();
void assignUniformBlockRegisters();
void ensureUniformBlocksInitialized();
void initUniformBlockInfo();
size_t getUniformBlockInfo(const sh::InterfaceBlock &interfaceBlock);
......
......@@ -225,10 +225,11 @@ ANGLE_INSTANTIATE_TEST(ProgramBinaryTest,
class ProgramBinaryES3Test : public ANGLETest
{
protected:
void testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst);
};
// Tests that saving and loading a program perserves uniform block binding info.
TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
void ProgramBinaryES3Test::testBinaryAndUBOBlockIndexes(bool drawWithProgramFirst)
{
// We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0;
......@@ -279,9 +280,12 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
if (drawWithProgramFirst)
{
drawQuad(program.get(), "position", 0.5f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
// Read back the binary.
GLint programLength = 0;
......@@ -308,6 +312,19 @@ TEST_P(ProgramBinaryES3Test, UniformBlockBinding)
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());
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