Safe glGetBoolean/Integer/Float queries
bug: 63454254
Test: N-CTS dEQP GLES2/3/EGL 100% pass
Change-Id: I47de6426d216bf6c83a634b89870ad5ad9ad4dae
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 11be3c7..39e4cda 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -285,6 +285,8 @@
OVERRIDE(glGetIntegeri_v);
OVERRIDE(glGetInteger64i_v);
+ OVERRIDE(glGetInteger64v);
+ OVERRIDE(glGetBooleani_v);
OVERRIDE(glGetShaderiv);
@@ -356,12 +358,112 @@
GL2Encoder *ctx = (GL2Encoder *)self;
GLenum err = ctx->getError();
if(err != GL_NO_ERROR) {
+ ctx->m_glGetError_enc(ctx); // also clear host error
ctx->setError(GL_NO_ERROR);
return err;
}
return ctx->m_glGetError_enc(self);
+}
+class GL2Encoder::ErrorUpdater {
+public:
+ ErrorUpdater(GL2Encoder* ctx) :
+ mCtx(ctx),
+ guest_error(ctx->getError()),
+ host_error(ctx->m_glGetError_enc(ctx)) {
+ // Preserve any existing GL error in the guest:
+ // OpenGL ES 3.0.5 spec:
+ // The command enum GetError( void ); is used to obtain error information.
+ // Each detectable error is assigned a numeric code. When an error is
+ // detected, a flag is set and the code is recorded. Further errors, if
+ // they occur, do not affect this recorded code. When GetError is called,
+ // the code is returned and the flag is cleared, so that a further error
+ // will again record its code. If a call to GetError returns NO_ERROR, then
+ // there has been no detectable error since the last call to GetError (or
+ // since the GL was initialized).
+ if (guest_error == GL_NO_ERROR) {
+ guest_error = host_error;
+ }
+ }
+
+ GLenum getHostErrorAndUpdate() {
+ host_error = mCtx->m_glGetError_enc(mCtx);
+ if (guest_error == GL_NO_ERROR) {
+ guest_error = host_error;
+ }
+ return host_error;
+ }
+
+ void updateGuestErrorState() {
+ mCtx->setError(guest_error);
+ }
+
+private:
+ GL2Encoder* mCtx;
+ GLenum guest_error;
+ GLenum host_error;
+};
+
+template<class T>
+class GL2Encoder::ScopedQueryUpdate {
+public:
+ ScopedQueryUpdate(GL2Encoder* ctx, uint32_t bytes, T* target) :
+ mCtx(ctx),
+ mBuf(bytes, 0),
+ mTarget(target),
+ mErrorUpdater(ctx) {
+ }
+ T* hostStagingBuffer() {
+ return (T*)&mBuf[0];
+ }
+ ~ScopedQueryUpdate() {
+ GLint hostError = mErrorUpdater.getHostErrorAndUpdate();
+ if (hostError == GL_NO_ERROR) {
+ memcpy(mTarget, &mBuf[0], mBuf.size());
+ }
+ mErrorUpdater.updateGuestErrorState();
+ }
+private:
+ GL2Encoder* mCtx;
+ std::vector<char> mBuf;
+ T* mTarget;
+ ErrorUpdater mErrorUpdater;
+};
+
+void GL2Encoder::safe_glGetBooleanv(GLenum param, GLboolean* val) {
+ ScopedQueryUpdate<GLboolean> query(this, glUtilsParamSize(param) * sizeof(GLboolean), val);
+ m_glGetBooleanv_enc(this, param, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetFloatv(GLenum param, GLfloat* val) {
+ ScopedQueryUpdate<GLfloat> query(this, glUtilsParamSize(param) * sizeof(GLfloat), val);
+ m_glGetFloatv_enc(this, param, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetIntegerv(GLenum param, GLint* val) {
+ ScopedQueryUpdate<GLint> query(this, glUtilsParamSize(param) * sizeof(GLint), val);
+ m_glGetIntegerv_enc(this, param, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetInteger64v(GLenum param, GLint64* val) {
+ ScopedQueryUpdate<GLint64> query(this, glUtilsParamSize(param) * sizeof(GLint64), val);
+ m_glGetInteger64v_enc(this, param, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetIntegeri_v(GLenum param, GLuint index, GLint* val) {
+ ScopedQueryUpdate<GLint> query(this, sizeof(GLint), val);
+ m_glGetIntegeri_v_enc(this, param, index, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetInteger64i_v(GLenum param, GLuint index, GLint64* val) {
+ ScopedQueryUpdate<GLint64> query(this, sizeof(GLint64), val);
+ m_glGetInteger64i_v_enc(this, param, index, query.hostStagingBuffer());
+}
+
+void GL2Encoder::safe_glGetBooleani_v(GLenum param, GLuint index, GLboolean* val) {
+ ScopedQueryUpdate<GLboolean> query(this, sizeof(GLboolean), val);
+ m_glGetBooleani_v_enc(this, param, index, query.hostStagingBuffer());
}
void GL2Encoder::s_glFlush(void *self)
@@ -553,7 +655,7 @@
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
case GL_MAX_TEXTURE_IMAGE_UNITS:
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
*ptr = MIN(*ptr, GLClientState::MAX_TEXTURE_UNITS);
break;
@@ -566,7 +668,7 @@
case GL_MAX_VERTEX_ATTRIBS:
if (!ctx->m_state->getClientStateParameter<GLint>(param, ptr)) {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_state->setMaxVertexAttribs(*ptr);
}
break;
@@ -574,7 +676,7 @@
if (ctx->m_max_vertexAttribStride != 0) {
*ptr = ctx->m_max_vertexAttribStride;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_max_vertexAttribStride = *ptr;
}
break;
@@ -582,7 +684,7 @@
if (ctx->m_max_cubeMapTextureSize != 0) {
*ptr = ctx->m_max_cubeMapTextureSize;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_max_cubeMapTextureSize = *ptr;
}
break;
@@ -590,7 +692,7 @@
if (ctx->m_max_renderBufferSize != 0) {
*ptr = ctx->m_max_renderBufferSize;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_max_renderBufferSize = *ptr;
}
break;
@@ -598,7 +700,7 @@
if (ctx->m_max_textureSize != 0) {
*ptr = ctx->m_max_textureSize;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_max_textureSize = *ptr;
}
break;
@@ -606,7 +708,7 @@
if (ctx->m_max_3d_textureSize != 0) {
*ptr = ctx->m_max_3d_textureSize;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_max_3d_textureSize = *ptr;
}
break;
@@ -614,7 +716,7 @@
if (ctx->m_ssbo_offset_align != 0) {
*ptr = ctx->m_ssbo_offset_align;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_ssbo_offset_align = *ptr;
}
break;
@@ -622,7 +724,7 @@
if (ctx->m_ubo_offset_align != 0) {
*ptr = ctx->m_ubo_offset_align;
} else {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
ctx->m_ubo_offset_align = *ptr;
}
break;
@@ -639,13 +741,13 @@
case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
case GL_MAX_UNIFORM_BUFFER_BINDINGS:
SET_ERROR_IF(ctx->majorVersion() < 3, GL_INVALID_ENUM);
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
break;
case GL_MAX_COLOR_ATTACHMENTS:
case GL_MAX_DRAW_BUFFERS:
SET_ERROR_IF(ctx->majorVersion() < 3 &&
!ctx->hasExtension("GL_EXT_draw_buffers"), GL_INVALID_ENUM);
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
break;
// Not allowed in ES 3.0.
case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
@@ -654,11 +756,11 @@
SET_ERROR_IF(ctx->majorVersion() < 3 ||
(ctx->majorVersion() == 3 &&
ctx->minorVersion() == 0), GL_INVALID_ENUM);
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
break;
default:
if (!ctx->m_state->getClientStateParameter<GLint>(param, ptr)) {
- ctx->m_glGetIntegerv_enc(self, param, ptr);
+ ctx->safe_glGetIntegerv(param, ptr);
}
break;
}
@@ -693,7 +795,7 @@
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
case GL_MAX_TEXTURE_IMAGE_UNITS:
- ctx->m_glGetFloatv_enc(self, param, ptr);
+ ctx->safe_glGetFloatv(param, ptr);
*ptr = MIN(*ptr, (GLfloat)GLClientState::MAX_TEXTURE_UNITS);
break;
@@ -706,7 +808,7 @@
default:
if (!ctx->m_state->getClientStateParameter<GLfloat>(param, ptr)) {
- ctx->m_glGetFloatv_enc(self, param, ptr);
+ ctx->safe_glGetFloatv(param, ptr);
}
break;
}
@@ -748,7 +850,7 @@
default:
if (!ctx->m_state->getClientStateParameter<GLboolean>(param, ptr)) {
- ctx->m_glGetBooleanv_enc(self, param, ptr);
+ ctx->safe_glGetBooleanv(param, ptr);
}
*ptr = (*ptr != 0) ? GL_TRUE : GL_FALSE;
break;
@@ -1335,7 +1437,7 @@
ctx->m_glLinkProgram_enc(self, program);
GLint linkStatus = 0;
- ctx->glGetProgramiv(self,program,GL_LINK_STATUS,&linkStatus);
+ ctx->glGetProgramiv(self, program, GL_LINK_STATUS, &linkStatus);
if (!linkStatus) {
return;
}
@@ -4162,7 +4264,7 @@
break;
}
- ctx->m_glGetIntegeri_v_enc(self, target, index, params);
+ ctx->safe_glGetIntegeri_v(target, index, params);
}
void GL2Encoder::s_glGetInteger64i_v(void* self, GLenum target, GLuint index, GLint64* params) {
@@ -4211,7 +4313,17 @@
break;
}
- ctx->m_glGetInteger64i_v_enc(self, target, index, params);
+ ctx->safe_glGetInteger64i_v(target, index, params);
+}
+
+void GL2Encoder::s_glGetInteger64v(void* self, GLenum param, GLint64* val) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ ctx->safe_glGetInteger64v(param, val);
+}
+
+void GL2Encoder::s_glGetBooleani_v(void* self, GLenum param, GLuint index, GLboolean* val) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ ctx->safe_glGetBooleani_v(param, index, val);
}
void GL2Encoder::s_glGetShaderiv(void* self, GLuint shader, GLenum pname, GLint* params) {
@@ -4282,7 +4394,7 @@
ctx->m_shared->associateGLShaderProgram(res, spDataId);
GLint numUniforms = 0;
- ctx->glGetProgramiv(ctx, res, GL_ACTIVE_UNIFORMS, &numUniforms);
+ ctx->glGetProgramiv(self, res, GL_ACTIVE_UNIFORMS, &numUniforms);
ctx->m_shared->initShaderProgramData(res, numUniforms);
GLint maxLength=0;