Implement program binary in ProgramGL.
BUG=angleproject:882
Change-Id: I8d57c185066e9fc0c1b8def09bc48d80ad97d328
Reviewed-on: https://chromium-review.googlesource.com/303901
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index 6a2bc44..f5d3a48 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -43,25 +43,58 @@
LinkResult ProgramGL::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
{
- UNIMPLEMENTED();
- return LinkResult(false, gl::Error(GL_INVALID_OPERATION));
+ preLink();
+
+ // Read the binary format, size and blob
+ GLenum binaryFormat = stream->readInt<GLenum>();
+ GLint binaryLength = stream->readInt<GLint>();
+ const uint8_t *binary = stream->data() + stream->offset();
+ stream->skip(binaryLength);
+
+ // Load the binary
+ mFunctions->programBinary(mProgramID, binaryFormat, binary, binaryLength);
+
+ // Verify that the program linked
+ if (!checkLinkStatus(infoLog))
+ {
+ return LinkResult(false, gl::Error(GL_NO_ERROR));
+ }
+
+ postLink();
+
+ return LinkResult(true, gl::Error(GL_NO_ERROR));
}
gl::Error ProgramGL::save(gl::BinaryOutputStream *stream)
{
- UNIMPLEMENTED();
- return gl::Error(GL_INVALID_OPERATION);
+ GLint binaryLength = 0;
+ mFunctions->getProgramiv(mProgramID, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
+
+ std::vector<uint8_t> binary(binaryLength);
+ GLenum binaryFormat = GL_NONE;
+ mFunctions->getProgramBinary(mProgramID, binaryLength, &binaryLength, &binaryFormat,
+ &binary[0]);
+
+ stream->writeInt(binaryFormat);
+ stream->writeInt(binaryLength);
+ stream->writeBytes(&binary[0], binaryLength);
+
+ return gl::Error(GL_NO_ERROR);
}
void ProgramGL::setBinaryRetrievableHint(bool retrievable)
{
- UNIMPLEMENTED();
+ // glProgramParameteri isn't always available on ES backends.
+ if (mFunctions->programParameteri)
+ {
+ mFunctions->programParameteri(mProgramID, GL_PROGRAM_BINARY_RETRIEVABLE_HINT,
+ retrievable ? GL_TRUE : GL_FALSE);
+ }
}
LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
{
- // Reset the program state, delete the current program if one exists
- reset();
+ preLink();
// Set the transform feedback state
std::vector<const GLchar *> transformFeedbackVaryings;
@@ -86,11 +119,8 @@
&transformFeedbackVaryings[0], mData.getTransformFeedbackBufferMode());
}
- const gl::Shader *vertexShader = mData.getAttachedVertexShader();
- const gl::Shader *fragmentShader = mData.getAttachedFragmentShader();
-
- const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(vertexShader);
- const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(fragmentShader);
+ const ShaderGL *vertexShaderGL = GetImplAs<ShaderGL>(mData.getAttachedVertexShader());
+ const ShaderGL *fragmentShaderGL = GetImplAs<ShaderGL>(mData.getAttachedFragmentShader());
// Attach the shaders
mFunctions->attachShader(mProgramID, vertexShaderGL->getShaderID());
@@ -115,38 +145,8 @@
mFunctions->detachShader(mProgramID, fragmentShaderGL->getShaderID());
// Verify the link
- GLint linkStatus = GL_FALSE;
- mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
- if (linkStatus == GL_FALSE)
+ if (!checkLinkStatus(infoLog))
{
- // Linking failed, put the error into the info log
- GLint infoLogLength = 0;
- mFunctions->getProgramiv(mProgramID, GL_INFO_LOG_LENGTH, &infoLogLength);
-
- std::string warning;
-
- // Info log length includes the null terminator, so 1 means that the info log is an empty
- // string.
- if (infoLogLength > 1)
- {
- std::vector<char> buf(infoLogLength);
- mFunctions->getProgramInfoLog(mProgramID, infoLogLength, nullptr, &buf[0]);
-
- mFunctions->deleteProgram(mProgramID);
- mProgramID = 0;
-
- infoLog << buf.data();
-
- warning = FormatString("Program link failed unexpectedly: %s", buf.data());
- }
- else
- {
- warning = "Program link failed unexpectedly with no info log.";
- }
- ANGLEPlatformCurrent()->logWarning(warning.c_str());
- TRACE("\n%s", warning.c_str());
-
- // TODO, return GL_OUT_OF_MEMORY or just fail the link? This is an unexpected case
return LinkResult(false, gl::Error(GL_NO_ERROR));
}
@@ -155,51 +155,7 @@
mStateManager->forceUseProgram(mProgramID);
}
- // Query the uniform information
- ASSERT(mUniformRealLocationMap.empty());
- const auto &uniformLocations = mData.getUniformLocations();
- const auto &uniforms = mData.getUniforms();
- mUniformRealLocationMap.resize(uniformLocations.size(), GL_INVALID_INDEX);
- for (size_t uniformLocation = 0; uniformLocation < uniformLocations.size(); uniformLocation++)
- {
- const auto &entry = uniformLocations[uniformLocation];
- if (!entry.used)
- {
- continue;
- }
-
- // From the spec:
- // "Locations for sequential array indices are not required to be sequential."
- const gl::LinkedUniform &uniform = uniforms[entry.index];
- std::stringstream fullNameStr;
- fullNameStr << uniform.name;
- if (uniform.isArray())
- {
- fullNameStr << "[" << entry.element << "]";
- }
- const std::string &fullName = fullNameStr.str();
-
- GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
- mUniformRealLocationMap[uniformLocation] = realLocation;
- }
-
- mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX);
-
- for (size_t uniformId = 0; uniformId < uniforms.size(); ++uniformId)
- {
- const gl::LinkedUniform &linkedUniform = uniforms[uniformId];
-
- if (!linkedUniform.isSampler() || !linkedUniform.staticUse)
- continue;
-
- mUniformIndexToSamplerIndex[uniformId] = mSamplerBindings.size();
-
- // If uniform is a sampler type, insert it into the mSamplerBindings array
- SamplerBindingGL samplerBinding;
- samplerBinding.textureType = gl::SamplerTypeToTextureType(linkedUniform.type);
- samplerBinding.boundTextureUnits.resize(linkedUniform.elementCount(), 0);
- mSamplerBindings.push_back(samplerBinding);
- }
+ postLink();
return LinkResult(true, gl::Error(GL_NO_ERROR));
}
@@ -369,14 +325,6 @@
}
}
-void ProgramGL::reset()
-{
- mUniformRealLocationMap.clear();
- mUniformBlockRealLocationMap.clear();
- mSamplerBindings.clear();
- mUniformIndexToSamplerIndex.clear();
-}
-
GLuint ProgramGL::getProgramID() const
{
return mProgramID;
@@ -433,4 +381,102 @@
return true;
}
+void ProgramGL::preLink()
+{
+ // Reset the program state
+ mUniformRealLocationMap.clear();
+ mUniformBlockRealLocationMap.clear();
+ mSamplerBindings.clear();
+ mUniformIndexToSamplerIndex.clear();
+}
+
+bool ProgramGL::checkLinkStatus(gl::InfoLog &infoLog)
+{
+ GLint linkStatus = GL_FALSE;
+ mFunctions->getProgramiv(mProgramID, GL_LINK_STATUS, &linkStatus);
+ if (linkStatus == GL_FALSE)
+ {
+ // Linking failed, put the error into the info log
+ GLint infoLogLength = 0;
+ mFunctions->getProgramiv(mProgramID, GL_INFO_LOG_LENGTH, &infoLogLength);
+
+ std::string warning;
+
+ // Info log length includes the null terminator, so 1 means that the info log is an empty
+ // string.
+ if (infoLogLength > 1)
+ {
+ std::vector<char> buf(infoLogLength);
+ mFunctions->getProgramInfoLog(mProgramID, infoLogLength, nullptr, &buf[0]);
+
+ mFunctions->deleteProgram(mProgramID);
+ mProgramID = 0;
+
+ infoLog << buf.data();
+
+ warning = FormatString("Program link failed unexpectedly: %s", buf.data());
+ }
+ else
+ {
+ warning = "Program link failed unexpectedly with no info log.";
+ }
+ ANGLEPlatformCurrent()->logWarning(warning.c_str());
+ TRACE("\n%s", warning.c_str());
+
+ // TODO, return GL_OUT_OF_MEMORY or just fail the link? This is an unexpected case
+ return false;
+ }
+
+ return true;
+}
+
+void ProgramGL::postLink()
+{
+ // Query the uniform information
+ ASSERT(mUniformRealLocationMap.empty());
+ const auto &uniformLocations = mData.getUniformLocations();
+ const auto &uniforms = mData.getUniforms();
+ mUniformRealLocationMap.resize(uniformLocations.size(), GL_INVALID_INDEX);
+ for (size_t uniformLocation = 0; uniformLocation < uniformLocations.size(); uniformLocation++)
+ {
+ const auto &entry = uniformLocations[uniformLocation];
+ if (!entry.used)
+ {
+ continue;
+ }
+
+ // From the spec:
+ // "Locations for sequential array indices are not required to be sequential."
+ const gl::LinkedUniform &uniform = uniforms[entry.index];
+ std::stringstream fullNameStr;
+ fullNameStr << uniform.name;
+ if (uniform.isArray())
+ {
+ fullNameStr << "[" << entry.element << "]";
+ }
+ const std::string &fullName = fullNameStr.str();
+
+ GLint realLocation = mFunctions->getUniformLocation(mProgramID, fullName.c_str());
+ mUniformRealLocationMap[uniformLocation] = realLocation;
+ }
+
+ mUniformIndexToSamplerIndex.resize(mData.getUniforms().size(), GL_INVALID_INDEX);
+
+ for (size_t uniformId = 0; uniformId < uniforms.size(); ++uniformId)
+ {
+ const gl::LinkedUniform &linkedUniform = uniforms[uniformId];
+
+ if (!linkedUniform.isSampler() || !linkedUniform.staticUse)
+ continue;
+
+ mUniformIndexToSamplerIndex[uniformId] = mSamplerBindings.size();
+
+ // If uniform is a sampler type, insert it into the mSamplerBindings array
+ SamplerBindingGL samplerBinding;
+ samplerBinding.textureType = gl::SamplerTypeToTextureType(linkedUniform.type);
+ samplerBinding.boundTextureUnits.resize(linkedUniform.elementCount(), 0);
+ mSamplerBindings.push_back(samplerBinding);
+ }
+}
+
} // namespace rx