Commit 65a0be92 by Geoff Lang Committed by Commit Bot

Implement program binary in ProgramGL.

BUG=angleproject:882 Change-Id: I8d57c185066e9fc0c1b8def09bc48d80ad97d328 Reviewed-on: https://chromium-review.googlesource.com/303901Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent aab7e868
......@@ -961,6 +961,11 @@ void FunctionsGL::initializeProcsDesktopGL()
AssignGLExtensionEntryPoint(extensions, "GL_ARB_transform_feedback3", loadProcAddress("glEndQueryIndexed"), &endQueryIndexed);
AssignGLExtensionEntryPoint(extensions, "GL_ARB_transform_feedback3", loadProcAddress("glGetQueryIndexediv"), &getQueryIndexediv);
// GL_ARB_get_program_binary
AssignGLExtensionEntryPoint(extensions, "GL_ARB_get_program_binary", loadProcAddress("glGetProgramBinary"), &getProgramBinary);
AssignGLExtensionEntryPoint(extensions, "GL_ARB_get_program_binary", loadProcAddress("glProgramBinary"), &programBinary);
AssignGLExtensionEntryPoint(extensions, "GL_ARB_get_program_binary", loadProcAddress("glProgramParameteri"), &programParameteri);
// 1.0
if (isAtLeastGL(gl::Version(1, 0)))
{
......@@ -1791,6 +1796,10 @@ void FunctionsGL::initializeProcsGLES()
AssignGLExtensionEntryPoint(extensions, "GL_OES_EGL_image", loadProcAddress("glEGLImageTargetRenderbufferStorageOES"), &eglImageTargetRenderbufferStorageOES);
AssignGLExtensionEntryPoint(extensions, "GL_OES_EGL_image", loadProcAddress("glEGLImageTargetTexture2DOES"), &eglImageTargetTexture2DOES);
// GL_OES_get_program_binary
AssignGLExtensionEntryPoint(extensions, "GL_OES_get_program_binary", loadProcAddress("glGetProgramBinaryOES"), &getProgramBinary);
AssignGLExtensionEntryPoint(extensions, "GL_OES_get_program_binary", loadProcAddress("glProgramBinaryOES"), &programBinary);
// 2.0
if (isAtLeastGLES(gl::Version(2, 0)))
{
......
......@@ -43,25 +43,58 @@ ProgramGL::~ProgramGL()
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 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
&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 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
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 @@ LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
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::setUniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformB
}
}
void ProgramGL::reset()
{
mUniformRealLocationMap.clear();
mUniformBlockRealLocationMap.clear();
mSamplerBindings.clear();
mUniformIndexToSamplerIndex.clear();
}
GLuint ProgramGL::getProgramID() const
{
return mProgramID;
......@@ -433,4 +381,102 @@ bool ProgramGL::getUniformBlockMemberInfo(const std::string &memberUniformName,
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
......@@ -72,7 +72,9 @@ class ProgramGL : public ProgramImpl
const std::vector<SamplerBindingGL> &getAppliedSamplerUniforms() const;
private:
void reset();
void preLink();
bool checkLinkStatus(gl::InfoLog &infoLog);
void postLink();
// Helper function, makes it simpler to type.
GLint uniLoc(GLint glLocation) const { return mUniformRealLocationMap[glLocation]; }
......
......@@ -289,6 +289,24 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
// Doesn't impact supported version
}
if (functions->isAtLeastGL(gl::Version(4, 1)) ||
functions->hasGLExtension("GL_ARB_get_program_binary") ||
functions->isAtLeastGLES(gl::Version(3, 0)) ||
functions->hasGLExtension("GL_OES_get_program_binary"))
{
// Able to support the GL_PROGRAM_BINARY_ANGLE format as long as another program binary
// format is available.
GLint numBinaryFormats = QuerySingleGLInt(functions, GL_NUM_PROGRAM_BINARY_FORMATS_OES);
if (numBinaryFormats > 0)
{
caps->programBinaryFormats.push_back(GL_PROGRAM_BINARY_ANGLE);
}
}
else
{
// Doesn't impact supported version
}
// glGetShaderPrecisionFormat is not available until desktop GL version 4.1 or GL_ARB_ES2_compatibility exists
if (functions->isAtLeastGL(gl::Version(4, 1)) || functions->hasGLExtension("GL_ARB_ES2_compatibility") ||
functions->isAtLeastGLES(gl::Version(2, 0)))
......@@ -581,6 +599,7 @@ void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsM
extensions->setTextureExtensionSupport(*textureCapsMap);
extensions->elementIndexUint = functions->standard == STANDARD_GL_DESKTOP ||
functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_OES_element_index_uint");
extensions->getProgramBinary = caps->programBinaryFormats.size() > 0;
extensions->readFormatBGRA = functions->isAtLeastGL(gl::Version(1, 2)) || functions->hasGLExtension("GL_EXT_bgra") ||
functions->hasGLESExtension("GL_EXT_read_format_bgra");
extensions->mapBuffer = functions->isAtLeastGL(gl::Version(1, 5)) ||
......
......@@ -405,7 +405,6 @@
1323 LINUX : dEQP-GLES3.functional.fbo.depth.depth_write_clamp.depth32f_stencil8 = FAIL
1323 LINUX : dEQP-GLES3.functional.implementation_limits.max_fragment_uniform_components = FAIL
1323 LINUX : dEQP-GLES3.functional.implementation_limits.max_vertex_uniform_components = FAIL
1323 LINUX : dEQP-GLES3.functional.negative_api.shader.program_binary = FAIL
1323 LINUX : dEQP-GLES3.functional.negative_api.state.get_integeri_v = FAIL
1323 LINUX : dEQP-GLES3.functional.rasterization.fbo.rbo_multisample_max.primitives.points = FAIL
1323 LINUX : dEQP-GLES3.functional.shaders.builtin_functions.precision.refract.highp_fragment.scalar = FAIL
......
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