Implement full program binary support for ES3.
Refactor validation to be used in both the OES and ES3 entry points.
BUG=angleproject:600
BUG=angleproject:1101
Change-Id: I2008c4ea04ce07910f03ae0b997f8a77b66203d8
Reviewed-on: https://chromium-review.googlesource.com/316620
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 9347419..4a99c88 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -225,7 +225,8 @@
Program::Data::Data()
: mAttachedFragmentShader(nullptr),
mAttachedVertexShader(nullptr),
- mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS)
+ mTransformFeedbackBufferMode(GL_INTERLEAVED_ATTRIBS),
+ mBinaryRetrieveableHint(false)
{
}
@@ -791,6 +792,18 @@
return length;
}
+void Program::setBinaryRetrievableHint(bool retrievable)
+{
+ // TODO(jmadill) : replace with dirty bits
+ mProgram->setBinaryRetrievableHint(retrievable);
+ mData.mBinaryRetrieveableHint = retrievable;
+}
+
+bool Program::getBinaryRetrievableHint() const
+{
+ return mData.mBinaryRetrieveableHint;
+}
+
void Program::release()
{
mRefCount--;
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index ac06ff2..f538ce4 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -215,6 +215,8 @@
// TODO(jmadill): use unordered/hash map when available
std::map<int, VariableLocation> mOutputVariables;
+
+ bool mBinaryRetrieveableHint;
};
Program(rx::ImplFactory *factory, ResourceManager *manager, GLuint handle);
@@ -237,6 +239,8 @@
Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length);
Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const;
GLint getBinaryLength() const;
+ void setBinaryRetrievableHint(bool retrievable);
+ bool getBinaryRetrievableHint() const;
int getInfoLogLength() const;
void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog) const;
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index a9d54b8..1e68804 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -37,6 +37,7 @@
virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
virtual gl::Error save(gl::BinaryOutputStream *stream) = 0;
+ virtual void setBinaryRetrievableHint(bool retrievable) = 0;
virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) = 0;
virtual GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) = 0;
diff --git a/src/libANGLE/renderer/ProgramImpl_mock.h b/src/libANGLE/renderer/ProgramImpl_mock.h
index dbc1534..0db2330 100644
--- a/src/libANGLE/renderer/ProgramImpl_mock.h
+++ b/src/libANGLE/renderer/ProgramImpl_mock.h
@@ -25,6 +25,7 @@
MOCK_METHOD2(load, LinkResult(gl::InfoLog &, gl::BinaryInputStream *));
MOCK_METHOD1(save, gl::Error(gl::BinaryOutputStream *));
+ MOCK_METHOD1(setBinaryRetrievableHint, void(bool));
MOCK_METHOD2(link, LinkResult(const gl::Data &, gl::InfoLog &));
MOCK_METHOD2(validate, GLboolean(const gl::Caps &, gl::InfoLog *));
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index d6a2a27..7f44d58 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -1104,6 +1104,10 @@
return gl::Error(GL_NO_ERROR);
}
+void ProgramD3D::setBinaryRetrievableHint(bool /* retrievable */)
+{
+}
+
gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
ShaderExecutableD3D **outExecutable)
{
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index b5eea9b..5ea15aa 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -150,8 +150,9 @@
bool usesGeometryShader(GLenum drawMode) const;
bool usesInstancedPointSpriteEmulation() const;
- LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
- gl::Error save(gl::BinaryOutputStream *stream);
+ LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) override;
+ gl::Error save(gl::BinaryOutputStream *stream) override;
+ void setBinaryRetrievableHint(bool retrievable) override;
gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo,
ShaderExecutableD3D **outExectuable);
diff --git a/src/libANGLE/renderer/gl/ProgramGL.cpp b/src/libANGLE/renderer/gl/ProgramGL.cpp
index c4739d1..f5adc3b 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.cpp
+++ b/src/libANGLE/renderer/gl/ProgramGL.cpp
@@ -47,6 +47,11 @@
return gl::Error(GL_INVALID_OPERATION);
}
+void ProgramGL::setBinaryRetrievableHint(bool retrievable)
+{
+ UNIMPLEMENTED();
+}
+
LinkResult ProgramGL::link(const gl::Data &data, gl::InfoLog &infoLog)
{
// Reset the program state, delete the current program if one exists
diff --git a/src/libANGLE/renderer/gl/ProgramGL.h b/src/libANGLE/renderer/gl/ProgramGL.h
index 377ba0f..fa34368 100644
--- a/src/libANGLE/renderer/gl/ProgramGL.h
+++ b/src/libANGLE/renderer/gl/ProgramGL.h
@@ -33,6 +33,7 @@
LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) override;
gl::Error save(gl::BinaryOutputStream *stream) override;
+ void setBinaryRetrievableHint(bool retrievable) override;
LinkResult link(const gl::Data &data, gl::InfoLog &infoLog) override;
GLboolean validate(const gl::Caps &caps, gl::InfoLog *infoLog) override;
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index d5e7fba..baabae8 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2223,4 +2223,49 @@
return true;
}
+
+bool ValidateProgramBinaryBase(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ Program *programObject = GetValidProgram(context, program);
+ if (programObject == nullptr)
+ {
+ return false;
+ }
+
+ const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
+ if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) ==
+ programBinaryFormats.end())
+ {
+ context->recordError(Error(GL_INVALID_ENUM, "Program binary format is not valid."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetProgramBinaryBase(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ Program *programObject = GetValidProgram(context, program);
+ if (programObject == nullptr)
+ {
+ return false;
+ }
+
+ if (!programObject->isLinked())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Program is not linked."));
+ return false;
+ }
+
+ return true;
+}
}
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index 041c725..fb595fd 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -147,6 +147,18 @@
bool ValidateDeleteVertexArraysBase(Context *context, GLsizei n);
bool ValidateGenVertexArraysBase(Context *context, GLsizei n);
+bool ValidateProgramBinaryBase(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinaryBase(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
+
// Error messages shared here for use in testing.
extern const char *g_ExceedsMaxElementErrorMessage;
}
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index dc05584..b9814d5 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -1037,4 +1037,35 @@
return true;
}
+
+bool ValidateProgramBinaryOES(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ if (!context->getExtensions().getProgramBinary)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length);
+}
+
+bool ValidateGetProgramBinaryOES(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ if (!context->getExtensions().getProgramBinary)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION, "Extension not enabled"));
+ return false;
+ }
+
+ return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary);
+}
}
diff --git a/src/libANGLE/validationES2.h b/src/libANGLE/validationES2.h
index 44166af..c81727e 100644
--- a/src/libANGLE/validationES2.h
+++ b/src/libANGLE/validationES2.h
@@ -38,6 +38,18 @@
bool ValidateDeleteVertexArraysOES(Context *context, GLsizei n);
bool ValidateGenVertexArraysOES(Context *context, GLsizei n);
bool ValidateIsVertexArrayOES(Context *context);
+
+bool ValidateProgramBinaryOES(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinaryOES(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
}
#endif // LIBANGLE_VALIDATION_ES2_H_
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 97dac8b..8ffdc20 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -1322,4 +1322,61 @@
return true;
}
+
+bool ValidateProgramBinary(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateProgramBinaryBase(context, program, binaryFormat, binary, length);
+}
+
+bool ValidateGetProgramBinary(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return ValidateGetProgramBinaryBase(context, program, bufSize, length, binaryFormat, binary);
+}
+
+bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value)
+{
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (GetValidProgram(context, program) == nullptr)
+ {
+ return false;
+ }
+
+ switch (pname)
+ {
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ break;
+
+ default:
+ context->recordError(Error(GL_INVALID_ENUM, "Invalid pname: 0x%X", pname));
+ return false;
+ }
+
+ return true;
+}
}
diff --git a/src/libANGLE/validationES3.h b/src/libANGLE/validationES3.h
index c1d7b74..b029b64 100644
--- a/src/libANGLE/validationES3.h
+++ b/src/libANGLE/validationES3.h
@@ -59,6 +59,19 @@
bool ValidateDeleteVertexArrays(Context *context, GLsizei n);
bool ValidateGenVertexArrays(Context *context, GLsizei n);
bool ValidateIsVertexArray(Context *context);
+
+bool ValidateProgramBinary(Context *context,
+ GLuint program,
+ GLenum binaryFormat,
+ const void *binary,
+ GLint length);
+bool ValidateGetProgramBinary(Context *context,
+ GLuint program,
+ GLsizei bufSize,
+ GLsizei *length,
+ GLenum *binaryFormat,
+ void *binary);
+bool ValidateProgramParameter(Context *context, GLuint program, GLenum pname, GLint value);
}
#endif // LIBANGLE_VALIDATION_ES3_H_
diff --git a/src/libGLESv2/entry_points_gles_2_0.cpp b/src/libGLESv2/entry_points_gles_2_0.cpp
index ebd087c..06840d1 100644
--- a/src/libGLESv2/entry_points_gles_2_0.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0.cpp
@@ -2082,6 +2082,7 @@
case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
case GL_TRANSFORM_FEEDBACK_VARYINGS:
case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
context->recordError(Error(GL_INVALID_ENUM));
return;
}
@@ -2134,6 +2135,9 @@
case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
*params = programObject->getTransformFeedbackVaryingMaxLength();
break;
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ *params = programObject->getBinaryRetrievableHint();
+ break;
default:
context->recordError(Error(GL_INVALID_ENUM));
diff --git a/src/libGLESv2/entry_points_gles_2_0_ext.cpp b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
index 1531ad0..91c55be 100644
--- a/src/libGLESv2/entry_points_gles_2_0_ext.cpp
+++ b/src/libGLESv2/entry_points_gles_2_0_ext.cpp
@@ -751,14 +751,14 @@
Context *context = GetValidGlobalContext();
if (context)
{
- Program *programObject = context->getProgram(program);
-
- if (!programObject || !programObject->isLinked())
+ if (!ValidateGetProgramBinaryOES(context, program, bufSize, length, binaryFormat, binary))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length);
if (error.isError())
{
@@ -776,19 +776,13 @@
Context *context = GetValidGlobalContext();
if (context)
{
- const std::vector<GLenum> &programBinaryFormats = context->getCaps().programBinaryFormats;
- if (std::find(programBinaryFormats.begin(), programBinaryFormats.end(), binaryFormat) == programBinaryFormats.end())
+ if (!ValidateProgramBinaryOES(context, program, binaryFormat, binary, length))
{
- context->recordError(Error(GL_INVALID_ENUM));
return;
}
Program *programObject = context->getProgram(program);
- if (!programObject)
- {
- context->recordError(Error(GL_INVALID_OPERATION));
- return;
- }
+ ASSERT(programObject != nullptr);
Error error = programObject->loadBinary(binaryFormat, binary, length);
if (error.isError())
diff --git a/src/libGLESv2/entry_points_gles_3_0.cpp b/src/libGLESv2/entry_points_gles_3_0.cpp
index c08a944..8ef1314 100644
--- a/src/libGLESv2/entry_points_gles_3_0.cpp
+++ b/src/libGLESv2/entry_points_gles_3_0.cpp
@@ -3072,14 +3072,20 @@
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateGetProgramBinary(context, program, bufSize, length, binaryFormat, binary))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // TODO: Pipe through to the OES extension for now, needs proper validation
- return GetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
}
}
@@ -3091,14 +3097,20 @@
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateProgramBinary(context, program, binaryFormat, binary, length))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // TODO: Pipe through to the OES extension for now, needs proper validation
- return ProgramBinaryOES(program, binaryFormat, binary, length);
+ Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ Error error = programObject->loadBinary(binaryFormat, binary, length);
+ if (error.isError())
+ {
+ context->recordError(error);
+ return;
+ }
}
}
@@ -3110,14 +3122,23 @@
Context *context = GetValidGlobalContext();
if (context)
{
- if (context->getClientVersion() < 3)
+ if (!ValidateProgramParameter(context, program, pname, value))
{
- context->recordError(Error(GL_INVALID_OPERATION));
return;
}
- // glProgramParameteri
- UNIMPLEMENTED();
+ gl::Program *programObject = context->getProgram(program);
+ ASSERT(programObject != nullptr);
+
+ switch (pname)
+ {
+ case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
+ programObject->setBinaryRetrievableHint(value != GL_FALSE);
+ break;
+
+ default:
+ UNREACHABLE();
+ }
}
}
diff --git a/src/tests/deqp_support/deqp_gles3_test_expectations.txt b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
index 8ba0858..55303e9 100644
--- a/src/tests/deqp_support/deqp_gles3_test_expectations.txt
+++ b/src/tests/deqp_support/deqp_gles3_test_expectations.txt
@@ -735,7 +735,6 @@
1101 WIN : dEQP-GLES3.functional.state_query.sampler.sampler_texture_max_lod_getsamplerparameteri = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.fbo.framebuffer_attachment_x_size_rbo = FAIL
1101 WIN : dEQP-GLES3.functional.state_query.shader.program_attached_shaders = FAIL
-1101 WIN : dEQP-GLES3.functional.state_query.shader.program_binary = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed16_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.polygon_offset.fixed24_render_with_units = FAIL
1101 WIN : dEQP-GLES3.functional.lifetime.gen.transform_feedback = FAIL