aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLingfeng Yang <lfy@google.com>2020-09-16 18:55:01 -0700
committerLingfeng Yang <lfy@google.com>2020-09-16 20:33:43 -0700
commit62054e92be714b2f17aeea2f9347cfa0139f30c2 (patch)
tree1c4ce3b72962dae0e04430668ba24b2db4ffff86
parente8f712f5d1edd931aa919d6b3857ff1c33891ccf (diff)
downloaddevice_generic_goldfish-opengl-62054e92be714b2f17aeea2f9347cfa0139f30c2.tar.gz
device_generic_goldfish-opengl-62054e92be714b2f17aeea2f9347cfa0139f30c2.tar.bz2
device_generic_goldfish-opengl-62054e92be714b2f17aeea2f9347cfa0139f30c2.zip
Don't try to do robust buffer access checks on non-linked attrib indices
There's no danger from allowing out of bounds access there if the shader program does nothing with it. Don't upload client arrays in that case either. Change-Id: Ic356a75d28fcf880608f3d44ca123bba18913c65
-rw-r--r--shared/OpenglCodecCommon/GLClientState.cpp7
-rw-r--r--shared/OpenglCodecCommon/GLClientState.h6
-rwxr-xr-xshared/OpenglCodecCommon/GLSharedGroup.cpp62
-rwxr-xr-xshared/OpenglCodecCommon/GLSharedGroup.h11
-rw-r--r--shared/OpenglCodecCommon/StateTrackingSupport.h8
-rw-r--r--shared/OpenglCodecCommon/glUtils.cpp94
-rw-r--r--shared/OpenglCodecCommon/glUtils.h1
-rwxr-xr-xsystem/GLESv2_enc/GL2Encoder.cpp73
8 files changed, 239 insertions, 23 deletions
diff --git a/shared/OpenglCodecCommon/GLClientState.cpp b/shared/OpenglCodecCommon/GLClientState.cpp
index 039b7632..67758316 100644
--- a/shared/OpenglCodecCommon/GLClientState.cpp
+++ b/shared/OpenglCodecCommon/GLClientState.cpp
@@ -2406,6 +2406,13 @@ void GLClientState::validateUniform(bool isFloat, bool isUnsigned, GLint columns
}
}
+bool GLClientState::isAttribIndexUsedByProgram(int index) {
+ auto info = currentAttribValidationInfo.get_const(index);
+ if (!info) return false;
+ if (!info->validInProgram) return false;
+ return true;
+}
+
void GLClientState::addFreshFramebuffer(GLuint name) {
FboProps props;
props.name = name;
diff --git a/shared/OpenglCodecCommon/GLClientState.h b/shared/OpenglCodecCommon/GLClientState.h
index c98190c8..6beeb962 100644
--- a/shared/OpenglCodecCommon/GLClientState.h
+++ b/shared/OpenglCodecCommon/GLClientState.h
@@ -541,12 +541,14 @@ public:
int getMaxColorAttachments() const;
int getMaxDrawBuffers() const;
- // Uniform validation info
+ // Uniform/attribute validation info
UniformValidationInfo currentUniformValidationInfo;
- // TODO: Program uniform validation info
+ AttribValidationInfo currentAttribValidationInfo;;
// Uniform validation api
void validateUniform(bool isFloat, bool isUnsigned, GLint columns, GLint rows, GLint location, GLsizei count, GLenum* err);
+ // Attrib validation
+ bool isAttribIndexUsedByProgram(int attribIndex);
private:
void init();
diff --git a/shared/OpenglCodecCommon/GLSharedGroup.cpp b/shared/OpenglCodecCommon/GLSharedGroup.cpp
index 848dfdbb..e2ed36cb 100755
--- a/shared/OpenglCodecCommon/GLSharedGroup.cpp
+++ b/shared/OpenglCodecCommon/GLSharedGroup.cpp
@@ -40,6 +40,7 @@ ProgramData::ProgramData() : m_numIndexes(0),
m_numAttributes(0),
m_initialized(false) {
m_Indexes = NULL;
+ m_attribIndexes = NULL;
m_refcount = 1;
m_linkStatus = 0;
m_activeUniformBlockCount = 0;
@@ -52,8 +53,10 @@ void ProgramData::initProgramData(GLuint numIndexes, GLuint numAttributes) {
m_numAttributes = numAttributes;
delete [] m_Indexes;
+ delete [] m_attribIndexes;
m_Indexes = new IndexInfo[numIndexes];
+ m_attribIndexes = new AttribInfo[m_numAttributes];
}
bool ProgramData::isInitialized() {
@@ -63,6 +66,7 @@ bool ProgramData::isInitialized() {
ProgramData::~ProgramData() {
delete [] m_Indexes;
+ delete [] m_attribIndexes;
m_Indexes = NULL;
}
@@ -80,6 +84,16 @@ void ProgramData::setIndexInfo(
m_Indexes[index].samplerValue = 0;
}
+void ProgramData::setAttribInfo(
+ GLuint index, GLint attribLoc, GLint size, GLenum type) {
+
+ if (index >= m_numAttributes) return;
+
+ m_attribIndexes[index].attribLoc = attribLoc;
+ m_attribIndexes[index].size = size;
+ m_attribIndexes[index].type = type;
+}
+
void ProgramData::setIndexFlags(GLuint index, GLuint flags) {
if (index >= m_numIndexes) return;
@@ -228,6 +242,27 @@ UniformValidationInfo ProgramData::compileValidationInfo(bool* error) const {
return res;
}
+AttribValidationInfo ProgramData::compileAttribValidationInfo(bool* error) const {
+ AttribValidationInfo res;
+ if (!m_attribIndexes) {
+ *error = true;
+ return res;
+ }
+
+ for (GLuint i = 0; i < m_numAttributes; ++i) {
+ if (m_attribIndexes[i].attribLoc < 0) continue;
+
+ AttribIndexInfo info = {
+ .validInProgram = true,
+ };
+
+ for (GLuint j = 0; j < getAttributeCountOfType(m_attribIndexes[i].type) * m_attribIndexes[i].size ; ++j) {
+ res.add(m_attribIndexes[i].attribLoc + j, info);
+ }
+ }
+
+ return res;
+}
/***** GLSharedGroup ****/
GLSharedGroup::GLSharedGroup() { }
@@ -521,6 +556,19 @@ void GLSharedGroup::setProgramIndexInfo(
}
}
+void GLSharedGroup::setProgramAttribInfo(
+ GLuint program, GLuint index, GLint attribLoc,
+ GLint size, GLenum type, const char* name) {
+
+ android::AutoMutex _lock(m_lock);
+
+ ProgramData* pData = getProgramDataLocked(program);
+
+ if (pData) {
+ pData->setAttribInfo(index,attribLoc,size,type);
+ }
+}
+
GLenum GLSharedGroup::getProgramUniformType(GLuint program, GLint location) {
android::AutoMutex _lock(m_lock);
@@ -801,6 +849,20 @@ UniformValidationInfo GLSharedGroup::getUniformValidationInfo(GLuint program) {
return pData->compileValidationInfo(&error);
}
+AttribValidationInfo GLSharedGroup::getAttribValidationInfo(GLuint program) {
+ AttribValidationInfo res;
+
+ android::AutoMutex _lock(m_lock);
+
+ ProgramData* pData =
+ getProgramDataLocked(program);
+
+ if (!pData) return res;
+
+ bool error; (void)error;
+ return pData->compileAttribValidationInfo(&error);
+}
+
void GLSharedGroup::setProgramLinkStatus(GLuint program, GLint linkStatus) {
android::AutoMutex _lock(m_lock);
ProgramData* pData =
diff --git a/shared/OpenglCodecCommon/GLSharedGroup.h b/shared/OpenglCodecCommon/GLSharedGroup.h
index b423951b..807a0065 100755
--- a/shared/OpenglCodecCommon/GLSharedGroup.h
+++ b/shared/OpenglCodecCommon/GLSharedGroup.h
@@ -76,9 +76,16 @@ private:
GLint samplerValue; // only set for sampler uniforms
} IndexInfo;
+ typedef struct _AttribInfo {
+ GLint attribLoc;
+ GLint size;
+ GLenum type;
+ } AttribInfo;
+
GLuint m_numIndexes;
GLuint m_numAttributes;
IndexInfo* m_Indexes;
+ AttribInfo* m_attribIndexes;
bool m_initialized;
std::vector<GLuint> m_shaders;
@@ -100,6 +107,7 @@ public:
bool isInitialized();
virtual ~ProgramData();
void setIndexInfo(GLuint index, GLint base, GLint size, GLenum type);
+ void setAttribInfo(GLuint index, GLint base, GLint size, GLenum type);
void setIndexFlags(GLuint index, GLuint flags);
GLuint getIndexForLocation(GLint location);
GLenum getTypeForLocation(GLint location);
@@ -120,6 +128,7 @@ public:
}
UniformValidationInfo compileValidationInfo(bool* error) const;
+ AttribValidationInfo compileAttribValidationInfo(bool* error) const;
void setLinkStatus(GLint status) { m_linkStatus = status; }
GLint getLinkStatus() { return m_linkStatus; }
@@ -210,6 +219,7 @@ public:
void deleteProgramData(GLuint program);
void deleteProgramDataLocked(GLuint program);
void setProgramIndexInfo(GLuint program, GLuint index, GLint base, GLint size, GLenum type, const char* name);
+ void setProgramAttribInfo(GLuint program, GLuint index, GLint attribLoc, GLint size, GLenum type, const char* name);
GLenum getProgramUniformType(GLuint program, GLint location);
GLint getNextSamplerUniform(GLuint program, GLint index, GLint* val, GLenum* target) const;
bool setSamplerUniform(GLuint program, GLint appLoc, GLint val, GLenum* target);
@@ -233,6 +243,7 @@ public:
// Validation info
UniformValidationInfo getUniformValidationInfo(GLuint program);
+ AttribValidationInfo getAttribValidationInfo(GLuint program);
void setProgramLinkStatus(GLuint program, GLint linkStatus);
GLint getProgramLinkStatus(GLuint program);
diff --git a/shared/OpenglCodecCommon/StateTrackingSupport.h b/shared/OpenglCodecCommon/StateTrackingSupport.h
index c6715c4e..b742c131 100644
--- a/shared/OpenglCodecCommon/StateTrackingSupport.h
+++ b/shared/OpenglCodecCommon/StateTrackingSupport.h
@@ -74,7 +74,8 @@ private:
Storage mStorage;
};
-// A structure for fast validation of uniform uploads and other uniform related api calls.
+// Structures for fast validation of uniforms/attribs.
+
struct UniformLocationInfo {
bool valid = false;
uint32_t columns;
@@ -86,7 +87,12 @@ struct UniformLocationInfo {
bool isBool;
};
+struct AttribIndexInfo {
+ bool validInProgram = false;
+};
+
using UniformValidationInfo = android::base::HybridComponentManager<1000, uint32_t, UniformLocationInfo>;
+using AttribValidationInfo = android::base::HybridComponentManager<16, uint32_t, AttribIndexInfo>;
using LastQueryTargetInfo = android::base::HybridComponentManager<1000, uint32_t, uint32_t>;
diff --git a/shared/OpenglCodecCommon/glUtils.cpp b/shared/OpenglCodecCommon/glUtils.cpp
index de621393..a6b0b7c8 100644
--- a/shared/OpenglCodecCommon/glUtils.cpp
+++ b/shared/OpenglCodecCommon/glUtils.cpp
@@ -287,6 +287,100 @@ uint32_t getRowsOfType(GLenum type) {
}
}
+uint32_t getAttributeCountOfType(GLenum type) {
+ switch (type) {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE:
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ case GL_HALF_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_UNSIGNED_INT:
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_FIXED:
+ case GL_BOOL:
+ return 1;
+#ifdef GL_DOUBLE
+ case GL_DOUBLE:
+ case GL_DOUBLE_VEC2:
+ case GL_DOUBLE_VEC3:
+ case GL_DOUBLE_VEC4:
+ return 1;
+ case GL_DOUBLE_MAT2:
+ case GL_DOUBLE_MAT2x3:
+ case GL_DOUBLE_MAT2x4:
+ return 4;
+ case GL_DOUBLE_MAT3:
+ case GL_DOUBLE_MAT3x2:
+ case GL_DOUBLE_MAT3x4:
+ return 6;
+ case GL_DOUBLE_MAT4:
+ case GL_DOUBLE_MAT4x2:
+ case GL_DOUBLE_MAT4x3:
+ return 8;
+#endif
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_BOOL_VEC2:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_BOOL_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ return 1;
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ return 2;
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ return 3;
+ case GL_FLOAT_MAT4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ return 4;
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_ATOMIC_COUNTER:
+ default:
+ return 1;
+ }
+}
+
size_t glSizeof(GLenum type)
{
size_t retval = 0;
diff --git a/shared/OpenglCodecCommon/glUtils.h b/shared/OpenglCodecCommon/glUtils.h
index 489ac188..09081c2f 100644
--- a/shared/OpenglCodecCommon/glUtils.h
+++ b/shared/OpenglCodecCommon/glUtils.h
@@ -63,6 +63,7 @@ typedef enum {
bool isBoolType(GLenum type);
uint32_t getColumnsOfType(GLenum type);
uint32_t getRowsOfType(GLenum type);
+ uint32_t getAttributeCountOfType(GLenum type);
size_t glSizeof(GLenum type);
size_t glUtilsParamSize(GLenum param);
void glUtilsPackPointerData(unsigned char *dst, unsigned char *str,
diff --git a/system/GLESv2_enc/GL2Encoder.cpp b/system/GLESv2_enc/GL2Encoder.cpp
index 919fdef1..cca18a98 100755
--- a/system/GLESv2_enc/GL2Encoder.cpp
+++ b/system/GLESv2_enc/GL2Encoder.cpp
@@ -1319,20 +1319,24 @@ void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClient
}
if (state.elementSize == 0) {
// The vertex attribute array is uninitialized. Abandon it.
- ALOGE("a vertex attribute array is uninitialized. Skipping corresponding vertex attribute.");
this->m_glDisableVertexAttribArray_enc(this, i);
continue;
}
m_glEnableVertexAttribArray_enc(this, i);
if (datalen && (!offset || !((unsigned char*)offset + firstIndex))) {
- ALOGD("%s: bad offset / len!!!!!", __FUNCTION__);
continue;
}
+
+ unsigned char* data = (unsigned char*)offset + firstIndex;
+ if (!m_state->isAttribIndexUsedByProgram(i)) {
+ continue;
+ }
+
if (state.isInt) {
- this->glVertexAttribIPointerDataAEMU(this, i, state.size, state.type, stride, (unsigned char *)offset + firstIndex, datalen);
+ this->glVertexAttribIPointerDataAEMU(this, i, state.size, state.type, stride, data, datalen);
} else {
- this->glVertexAttribPointerData(this, i, state.size, state.type, state.normalized, stride, (unsigned char *)offset + firstIndex, datalen);
+ this->glVertexAttribPointerData(this, i, state.size, state.type, state.normalized, stride, data, datalen);
}
} else {
const BufferData* buf = m_shared->getBufferData(bufferObject);
@@ -1347,20 +1351,24 @@ void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClient
if (buf && firstIndex >= 0 && firstIndex + bufLen <= buf->m_size) {
if (hasClientArrays) {
m_glEnableVertexAttribArray_enc(this, i);
- if (state.isInt) {
- this->glVertexAttribIPointerOffsetAEMU(this, i, state.size, state.type, stride, offset + firstIndex);
- } else {
- this->glVertexAttribPointerOffset(this, i, state.size, state.type, state.normalized, stride, offset + firstIndex);
+ if (firstIndex) {
+ if (state.isInt) {
+ this->glVertexAttribIPointerOffsetAEMU(this, i, state.size, state.type, stride, offset + firstIndex);
+ } else {
+ this->glVertexAttribPointerOffset(this, i, state.size, state.type, state.normalized, stride, offset + firstIndex);
+ }
}
}
} else {
- ALOGE("a vertex attribute index out of boundary is detected. Skipping corresponding vertex attribute. buf=%p", buf);
- if (buf) {
- ALOGE("Out of bounds vertex attribute info: "
- "clientArray? %d attribute %d vbo %u allocedBufferSize %u bufferDataSpecified? %d wantedStart %u wantedEnd %u",
- hasClientArrays, i, bufferObject, (unsigned int)buf->m_size, buf != NULL, firstIndex, firstIndex + bufLen);
+ if (m_state->isAttribIndexUsedByProgram(i)) {
+ ALOGE("a vertex attribute index out of boundary is detected. Skipping corresponding vertex attribute. buf=%p", buf);
+ if (buf) {
+ ALOGE("Out of bounds vertex attribute info: "
+ "clientArray? %d attribute %d vbo %u allocedBufferSize %u bufferDataSpecified? %d wantedStart %u wantedEnd %u",
+ hasClientArrays, i, bufferObject, (unsigned int)buf->m_size, buf != NULL, firstIndex, firstIndex + bufLen);
+ }
+ m_glDisableVertexAttribArray_enc(this, i);
}
- m_glDisableVertexAttribArray_enc(this, i);
}
}
} else {
@@ -1909,11 +1917,14 @@ void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
//get the length of the longest uniform name
GLint maxLength=0;
+ GLint maxAttribLength=0;
ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLength);
GLint size;
GLenum type;
- GLchar *name = new GLchar[maxLength+1];
+ size_t bufLen = maxLength > maxAttribLength ? maxLength : maxAttribLength;
+ GLchar *name = new GLchar[bufLen + 1];
GLint location;
//for each active uniform, get its size and starting location.
for (GLint i=0 ; i<numUniforms ; ++i)
@@ -1923,6 +1934,12 @@ void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
ctx->m_shared->setProgramIndexInfo(program, i, location, size, type, name);
}
+ for (GLint i = 0; i < numAttributes; ++i) {
+ ctx->m_glGetActiveAttrib_enc(self, program, i, maxAttribLength, NULL, &size, &type, name);
+ location = ctx->m_glGetAttribLocation_enc(self, program, name);
+ ctx->m_shared->setProgramAttribInfo(program, i, location, size, type, name);
+ }
+
if (ctx->majorVersion() > 2) {
GLint numBlocks;
ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_UNIFORM_BLOCKS, &numBlocks);
@@ -2219,6 +2236,7 @@ void GL2Encoder::s_glUseProgram(void *self, GLuint program)
if (program) {
ctx->m_state->currentUniformValidationInfo = ctx->m_shared->getUniformValidationInfo(program);
+ ctx->m_state->currentAttribValidationInfo = ctx->m_shared->getAttribValidationInfo(program);
}
}
@@ -5321,7 +5339,7 @@ void GL2Encoder::s_glActiveShaderProgram(void* self, GLuint pipeline, GLuint pro
}
}
-GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei count, const char** strings) {
+GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum shaderType, GLsizei count, const char** strings) {
GLint* length = NULL;
GL2Encoder* ctx = (GL2Encoder*)self;
@@ -5342,7 +5360,7 @@ GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei cou
return -1;
}
- GLuint res = ctx->glCreateShaderProgramvAEMU(ctx, type, count, str, len + 1);
+ GLuint res = ctx->glCreateShaderProgramvAEMU(ctx, shaderType, count, str, len + 1);
delete [] str;
// Phase 2: do glLinkProgram-related initialization for locationWorkARound
@@ -5363,14 +5381,23 @@ GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei cou
ctx->m_shared->initShaderProgramData(res, numUniforms, numAttributes);
GLint maxLength=0;
+ GLint maxAttribLength=0;
ctx->m_glGetProgramiv_enc(self, res, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+ ctx->m_glGetProgramiv_enc(self, res, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLength);
- GLint size; GLenum uniformType; GLchar* name = new GLchar[maxLength + 1];
+ size_t bufLen = maxLength > maxAttribLength ? maxLength : maxAttribLength;
+ GLint size; GLenum type; GLchar *name = new GLchar[bufLen + 1];
for (GLint i = 0; i < numUniforms; ++i) {
- ctx->m_glGetActiveUniform_enc(self, res, i, maxLength, NULL, &size, &uniformType, name);
+ ctx->m_glGetActiveUniform_enc(self, res, i, maxLength, NULL, &size, &type, name);
GLint location = ctx->m_glGetUniformLocation_enc(self, res, name);
- ctx->m_shared->setShaderProgramIndexInfo(res, i, location, size, uniformType, name);
+ ctx->m_shared->setShaderProgramIndexInfo(res, i, location, size, type, name);
+ }
+
+ for (GLint i = 0; i < numAttributes; ++i) {
+ ctx->m_glGetActiveAttrib_enc(self, res, i, maxAttribLength, NULL, &size, &type, name);
+ GLint location = ctx->m_glGetAttribLocation_enc(self, res, name);
+ ctx->m_shared->setProgramAttribInfo(res, i, location, size, type, name);
}
GLint numBlocks;
@@ -5636,6 +5663,11 @@ void GL2Encoder::s_glUseProgramStages(void *self, GLuint pipeline, GLbitfield st
// Otherwise, update host texture 2D bindings.
ctx->updateHostTexture2DBindingsFromProgramData(program);
+
+ if (program) {
+ ctx->m_state->currentUniformValidationInfo = ctx->m_shared->getUniformValidationInfo(program);
+ ctx->m_state->currentAttribValidationInfo = ctx->m_shared->getAttribValidationInfo(program);
+ }
}
void GL2Encoder::s_glBindProgramPipeline(void* self, GLuint pipeline)
@@ -6208,6 +6240,7 @@ void GL2Encoder::s_glBindAttribLocation(void *self , GLuint program, GLuint inde
SET_ERROR_IF(index > maxVertexAttribs, GL_INVALID_VALUE);
SET_ERROR_IF(name && !strncmp("gl_", name, 3), GL_INVALID_OPERATION);
+ fprintf(stderr, "%s: bind attrib %u name %s\n", __func__, index, name);
ctx->m_glBindAttribLocation_enc(ctx, program, index, name);
}