+
+void GL2Encoder::s_glGenVertexArrays(void* self, GLsizei n, GLuint* arrays) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ SET_ERROR_IF(n < 0, GL_INVALID_VALUE);
+
+ ctx->m_glGenVertexArrays_enc(self, n, arrays);
+ for (int i = 0; i < n; i++) {
+ ALOGV("%s: gen vao %u", __FUNCTION__, arrays[i]);
+ }
+ state->addVertexArrayObjects(n, arrays);
+}
+
+void GL2Encoder::s_glDeleteVertexArrays(void* self, GLsizei n, const GLuint* arrays) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ SET_ERROR_IF(n < 0, GL_INVALID_VALUE);
+
+ ctx->m_glDeleteVertexArrays_enc(self, n, arrays);
+ for (int i = 0; i < n; i++) {
+ ALOGV("%s: delete vao %u", __FUNCTION__, arrays[i]);
+ }
+ state->removeVertexArrayObjects(n, arrays);
+}
+
+void GL2Encoder::s_glBindVertexArray(void* self, GLuint array) {
+ ALOGV("%s: call. array=%u\n", __FUNCTION__, array);
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ SET_ERROR_IF(!state->isVertexArrayObject(array), GL_INVALID_OPERATION);
+ ctx->m_glBindVertexArray_enc(self, array);
+ state->setVertexArrayObject(array);
+}
+
+void* GL2Encoder::s_glMapBufferRange(void* self, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ // begin validation (lots)
+
+ RET_AND_SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM, NULL);
+
+ GLuint boundBuffer = ctx->m_state->getBuffer(target);
+
+ RET_AND_SET_ERROR_IF(boundBuffer == 0, GL_INVALID_OPERATION, NULL);
+
+ BufferData* buf = ctx->m_shared->getBufferData(boundBuffer);
+ RET_AND_SET_ERROR_IF(!buf, GL_INVALID_VALUE, NULL);
+
+ GLsizeiptr bufferDataSize = buf->m_size;
+
+ RET_AND_SET_ERROR_IF(offset < 0, GL_INVALID_VALUE, NULL);
+ RET_AND_SET_ERROR_IF(length < 0, GL_INVALID_VALUE, NULL);
+ RET_AND_SET_ERROR_IF(offset + length > bufferDataSize, GL_INVALID_VALUE, NULL);
+ RET_AND_SET_ERROR_IF(access & ~GLESv2Validation::allBufferMapAccessFlags, GL_INVALID_VALUE, NULL);
+
+ RET_AND_SET_ERROR_IF(buf->m_mapped, GL_INVALID_OPERATION, NULL);
+ RET_AND_SET_ERROR_IF(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)), GL_INVALID_OPERATION, NULL);
+ RET_AND_SET_ERROR_IF(
+ (access & GL_MAP_READ_BIT) &&
+ ((access & GL_MAP_INVALIDATE_RANGE_BIT) ||
+ (access & GL_MAP_INVALIDATE_BUFFER_BIT) ||
+ (access & GL_MAP_UNSYNCHRONIZED_BIT) ||
+ (access & GL_MAP_FLUSH_EXPLICIT_BIT)), GL_INVALID_OPERATION, NULL);
+
+ // end validation; actually do stuff now
+
+ buf->m_mapped = true;
+ buf->m_mappedAccess = access;
+ buf->m_mappedOffset = offset;
+ buf->m_mappedLength = length;
+
+ char* todo = (char*)buf->m_fixedBuffer.ptr() + offset;
+ ctx->glMapBufferRangeAEMU(
+ ctx, target,
+ offset, length,
+ access,
+ todo);
+
+ return todo;
+}
+
+GLboolean GL2Encoder::s_glUnmapBuffer(void* self, GLenum target) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ RET_AND_SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM, GL_FALSE);
+
+ GLuint boundBuffer = ctx->m_state->getBuffer(target);
+
+ RET_AND_SET_ERROR_IF(boundBuffer == 0, GL_INVALID_OPERATION, GL_FALSE);
+
+ BufferData* buf = ctx->m_shared->getBufferData(boundBuffer);
+ RET_AND_SET_ERROR_IF(!buf, GL_INVALID_VALUE, GL_FALSE);
+ RET_AND_SET_ERROR_IF(!buf->m_mapped, GL_INVALID_OPERATION, GL_FALSE);
+
+ GLboolean host_res = GL_TRUE;
+
+ ctx->glUnmapBufferAEMU(
+ ctx, target,
+ buf->m_mappedOffset,
+ buf->m_mappedLength,
+ buf->m_mappedAccess,
+ (void*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset),
+ &host_res);
+
+ buf->m_mapped = false;
+ buf->m_mappedAccess = 0;
+ buf->m_mappedOffset = 0;
+ buf->m_mappedLength = 0;
+
+ return host_res;
+}
+
+void GL2Encoder::s_glFlushMappedBufferRange(void* self, GLenum target, GLintptr offset, GLsizeiptr length) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+
+ GLuint boundBuffer = ctx->m_state->getBuffer(target);
+ SET_ERROR_IF(!boundBuffer, GL_INVALID_OPERATION);
+
+ BufferData* buf = ctx->m_shared->getBufferData(boundBuffer);
+ SET_ERROR_IF(!buf, GL_INVALID_VALUE);
+ SET_ERROR_IF(!buf->m_mapped, GL_INVALID_OPERATION);
+ SET_ERROR_IF(!(buf->m_mappedAccess & GL_MAP_FLUSH_EXPLICIT_BIT), GL_INVALID_OPERATION);
+
+ SET_ERROR_IF(offset < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(length < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(offset + length > buf->m_mappedLength, GL_INVALID_VALUE);
+
+ GLintptr totalOffset = buf->m_mappedOffset + offset;
+ ctx->glFlushMappedBufferRangeAEMU(
+ ctx, target,
+ totalOffset,
+ length,
+ buf->m_mappedAccess,
+ (void*)((char*)buf->m_fixedBuffer.ptr() + totalOffset));
+}
+
+void GL2Encoder::s_glCompressedTexImage2D(void* self, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM);
+ // Filter compressed formats support.
+ SET_ERROR_IF(!GLESv2Validation::supportedCompressedFormat(ctx, internalformat), GL_INVALID_ENUM);
+ // Verify level <= log2(GL_MAX_TEXTURE_SIZE).
+ GLint max_texture_size;
+ GLint max_cube_map_texture_size;
+ ctx->glGetIntegerv(ctx, GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ ctx->glGetIntegerv(ctx, GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_cube_map_texture_size);
+ SET_ERROR_IF(level < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_cube_map_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(width > max_texture_size, GL_INVALID_VALUE);
+ SET_ERROR_IF(height > max_texture_size, GL_INVALID_VALUE);
+ SET_ERROR_IF(border, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+ SET_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (imageSize > ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ // TODO: Fix:
+ // If |imageSize| is inconsistent with compressed dimensions.
+ // SET_ERROR_IF(GLESv2Validation::compressedTexImageSize(internalformat, width, height, 1) != imageSize, GL_INVALID_VALUE);
+
+ GLenum stateTarget = target;
+ if (target == GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
+ target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y ||
+ target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z ||
+ target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X ||
+ target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y ||
+ target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
+ stateTarget = GL_TEXTURE_CUBE_MAP;
+ state->setBoundTextureInternalFormat(stateTarget, (GLint)internalformat);
+ state->setBoundTextureDims(stateTarget, level, width, height, 1);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glCompressedTexImage2DOffsetAEMU(
+ ctx, target, level, internalformat,
+ width, height, border,
+ imageSize, (uintptr_t)data);
+ } else {
+ ctx->m_glCompressedTexImage2D_enc(
+ ctx, target, level, internalformat,
+ width, height, border,
+ imageSize, data);
+ }
+}
+
+void GL2Encoder::s_glCompressedTexSubImage2D(void* self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM);
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+ GLint max_texture_size;
+ GLint max_cube_map_texture_size;
+ ctx->glGetIntegerv(ctx, GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ ctx->glGetIntegerv(ctx, GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_cube_map_texture_size);
+ SET_ERROR_IF(level < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_cube_map_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (imageSize > ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(xoffset < 0 || yoffset < 0, GL_INVALID_VALUE);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glCompressedTexSubImage2DOffsetAEMU(
+ ctx, target, level,
+ xoffset, yoffset,
+ width, height, format,
+ imageSize, (uintptr_t)data);
+ } else {
+ ctx->m_glCompressedTexSubImage2D_enc(
+ ctx, target, level,
+ xoffset, yoffset,
+ width, height, format,
+ imageSize, data);
+ }
+}
+
+void GL2Encoder::s_glBindBufferRange(void* self, GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+
+ // Only works with certain targets
+ SET_ERROR_IF(
+ !(target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_SHADER_STORAGE_BUFFER ||
+ target == GL_TRANSFORM_FEEDBACK_BUFFER ||
+ target == GL_UNIFORM_BUFFER),
+ GL_INVALID_ENUM);
+
+ // Can't exceed range
+ SET_ERROR_IF(index < 0 ||
+ index >= state->getMaxIndexedBufferBindings(target),
+ GL_INVALID_VALUE);
+ SET_ERROR_IF(buffer && size <= 0, GL_INVALID_VALUE);
+ SET_ERROR_IF((target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_TRANSFORM_FEEDBACK_BUFFER) &&
+ (size % 4 || offset % 4),
+ GL_INVALID_VALUE);
+
+ GLint ssbo_offset_align, ubo_offset_align;
+ ctx->s_glGetIntegerv(ctx, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &ssbo_offset_align);
+ ctx->s_glGetIntegerv(ctx, GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &ubo_offset_align);
+ SET_ERROR_IF(target == GL_SHADER_STORAGE_BUFFER &&
+ offset % ssbo_offset_align,
+ GL_INVALID_VALUE);
+ SET_ERROR_IF(target == GL_UNIFORM_BUFFER &&
+ offset % ubo_offset_align,
+ GL_INVALID_VALUE);
+
+ state->bindBuffer(target, buffer);
+ state->bindIndexedBuffer(target, index, buffer, offset, size, 0, 0);
+ ctx->m_glBindBufferRange_enc(self, target, index, buffer, offset, size);
+}
+
+void GL2Encoder::s_glBindBufferBase(void* self, GLenum target, GLuint index, GLuint buffer) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+
+ // Only works with certain targets
+ SET_ERROR_IF(
+ !(target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_SHADER_STORAGE_BUFFER ||
+ target == GL_TRANSFORM_FEEDBACK_BUFFER ||
+ target == GL_UNIFORM_BUFFER),
+ GL_INVALID_ENUM);
+ // Can't exceed range
+ SET_ERROR_IF(index < 0 ||
+ index >= state->getMaxIndexedBufferBindings(target),
+ GL_INVALID_VALUE);
+
+ state->bindBuffer(target, buffer);
+ BufferData* buf = ctx->getBufferDataById(buffer);
+ state->bindIndexedBuffer(target, index, buffer, 0, buf ? buf->m_size : 0, 0, 0);
+ ctx->m_glBindBufferBase_enc(self, target, index, buffer);
+}
+
+void GL2Encoder::s_glCopyBufferSubData(void *self , GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, readtarget), GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, writetarget), GL_INVALID_ENUM);
+ SET_ERROR_IF((readtarget == GL_ATOMIC_COUNTER_BUFFER ||
+ readtarget == GL_DISPATCH_INDIRECT_BUFFER ||
+ readtarget == GL_DRAW_INDIRECT_BUFFER ||
+ readtarget == GL_SHADER_STORAGE_BUFFER), GL_INVALID_ENUM);
+ SET_ERROR_IF((writetarget == GL_ATOMIC_COUNTER_BUFFER ||
+ writetarget == GL_DISPATCH_INDIRECT_BUFFER ||
+ writetarget == GL_DRAW_INDIRECT_BUFFER ||
+ writetarget == GL_SHADER_STORAGE_BUFFER), GL_INVALID_ENUM);
+ SET_ERROR_IF(!ctx->boundBuffer(readtarget), GL_INVALID_OPERATION);
+ SET_ERROR_IF(!ctx->boundBuffer(writetarget), GL_INVALID_OPERATION);
+ SET_ERROR_IF(ctx->isBufferTargetMapped(readtarget), GL_INVALID_OPERATION);
+ SET_ERROR_IF(ctx->isBufferTargetMapped(writetarget), GL_INVALID_OPERATION);
+ SET_ERROR_IF(readoffset < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(writeoffset < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(size < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(
+ ctx->getBufferData(readtarget) &&
+ (readoffset + size > ctx->getBufferData(readtarget)->m_size),
+ GL_INVALID_VALUE);
+ SET_ERROR_IF(
+ ctx->getBufferData(writetarget) &&
+ (writeoffset + size > ctx->getBufferData(writetarget)->m_size),
+ GL_INVALID_VALUE);
+ SET_ERROR_IF(readtarget == writetarget &&
+ !((writeoffset >= readoffset + size) ||
+ (readoffset >= writeoffset + size)),
+ GL_INVALID_VALUE);
+
+ ctx->m_glCopyBufferSubData_enc(self, readtarget, writetarget, readoffset, writeoffset, size);
+}
+
+void GL2Encoder::s_glGetBufferParameteriv(void* self, GLenum target, GLenum pname, GLint* params) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+ SET_ERROR_IF(
+ target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_DISPATCH_INDIRECT_BUFFER ||
+ target == GL_DRAW_INDIRECT_BUFFER ||
+ target == GL_SHADER_STORAGE_BUFFER,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::bufferParam(ctx, pname), GL_INVALID_ENUM);
+ SET_ERROR_IF(!ctx->boundBuffer(target), GL_INVALID_OPERATION);
+ SET_ERROR_IF(pname == GL_BUFFER_MAP_LENGTH ||
+ pname == GL_BUFFER_MAP_OFFSET,
+ GL_INVALID_OPERATION);
+
+ if (!params) return;
+
+ BufferData* buf = ctx->getBufferData(target);
+
+ switch (pname) {
+ case GL_BUFFER_ACCESS_FLAGS:
+ *params = buf ? buf->m_mappedAccess : 0;
+ break;
+ case GL_BUFFER_MAPPED:
+ *params = buf ? (buf->m_mapped ? GL_TRUE : GL_FALSE) : GL_FALSE;
+ break;
+ case GL_BUFFER_SIZE:
+ *params = buf ? buf->m_size : 0;
+ break;
+ case GL_BUFFER_USAGE:
+ *params = buf ? buf->m_usage : GL_STATIC_DRAW;
+ break;
+ default:
+ break;
+ }
+}
+
+void GL2Encoder::s_glGetBufferParameteri64v(void* self, GLenum target, GLenum pname, GLint64* params) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+ SET_ERROR_IF(
+ target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_DISPATCH_INDIRECT_BUFFER ||
+ target == GL_DRAW_INDIRECT_BUFFER ||
+ target == GL_SHADER_STORAGE_BUFFER,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::bufferParam(ctx, pname), GL_INVALID_ENUM);
+ SET_ERROR_IF(!ctx->boundBuffer(target), GL_INVALID_OPERATION);
+ SET_ERROR_IF(pname == GL_BUFFER_ACCESS_FLAGS ||
+ pname == GL_BUFFER_MAPPED ||
+ pname == GL_BUFFER_USAGE,
+ GL_INVALID_OPERATION);
+
+ if (!params) return;
+
+ BufferData* buf = ctx->getBufferData(target);
+
+ switch (pname) {
+ case GL_BUFFER_MAP_LENGTH:
+ *params = buf ? buf->m_mappedLength : 0;
+ break;
+ case GL_BUFFER_MAP_OFFSET:
+ *params = buf ? buf->m_mappedOffset : 0;
+ break;
+ case GL_BUFFER_SIZE:
+ *params = buf ? buf->m_size : 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void GL2Encoder::s_glGetBufferPointerv(void* self, GLenum target, GLenum pname, GLvoid** params) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM);
+ SET_ERROR_IF(
+ target == GL_ATOMIC_COUNTER_BUFFER ||
+ target == GL_DISPATCH_INDIRECT_BUFFER ||
+ target == GL_DRAW_INDIRECT_BUFFER ||
+ target == GL_SHADER_STORAGE_BUFFER,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(pname != GL_BUFFER_MAP_POINTER, GL_INVALID_ENUM);
+ SET_ERROR_IF(!ctx->boundBuffer(target), GL_INVALID_OPERATION);
+ if (!params) return;
+
+ BufferData* buf = ctx->getBufferData(target);
+
+ if (!buf || !buf->m_mapped) { *params = NULL; return; }
+
+ *params = (GLvoid*)((char*)buf->m_fixedBuffer.ptr() + buf->m_mappedOffset);
+}
+
+static const char* const kNameDelimiter = ";";
+
+static std::string packVarNames(GLsizei count, const char** names, GLint* err_out) {
+
+#define VALIDATE(cond, err) if (cond) { *err_out = err; return packed; } \
+
+ std::string packed;
+ // validate the array of char[]'s
+ const char* currName;
+ for (GLsizei i = 0; i < count; i++) {
+ currName = names[i];
+ VALIDATE(!currName, GL_INVALID_OPERATION);
+ // check if has reasonable size
+ size_t len = strlen(currName);
+ VALIDATE(!len, GL_INVALID_OPERATION);
+ // check for our delimiter, which if present
+ // in the name, means an invalid name anyway.
+ VALIDATE(strstr(currName, kNameDelimiter),
+ GL_INVALID_OPERATION);
+ packed += currName;
+ packed += ";";
+ }
+
+ *err_out = GL_NO_ERROR;
+ return packed;
+}
+
+void GL2Encoder::s_glGetUniformIndices(void* self, GLuint program, GLsizei uniformCount, const GLchar ** uniformNames, GLuint* uniformIndices) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ if (!uniformCount) return;
+
+ GLint err = GL_NO_ERROR;
+ std::string packed = packVarNames(uniformCount, (const char**)uniformNames, &err);
+ SET_ERROR_IF(err != GL_NO_ERROR, GL_INVALID_OPERATION);
+
+ bool needLocationWAR = ctx->m_shared->needUniformLocationWAR(program);
+ std::vector<int> arrIndices;
+ for (size_t i = 0; i < uniformCount; i++) {
+ int err;
+ arrIndices.push_back(sArrIndexOfUniformExpr(uniformNames[i], &err));
+ if (err) {
+ ALOGE("%s: invalid uniform name %s!", __FUNCTION__, uniformNames[i]);
+ return;
+ }
+ }
+
+ ctx->glGetUniformIndicesAEMU(ctx, program, uniformCount, (const GLchar*)&packed[0], packed.size() + 1, uniformIndices);
+
+ for (int i = 0; i < uniformCount; i++) {
+ if (uniformIndices[i] >= 0 && needLocationWAR) {
+ uniformIndices[i] =
+ ctx->m_shared->locationWARHostToApp(program, uniformIndices[i], arrIndices[i]);
+ }
+ }
+}
+
+void GL2Encoder::s_glUniform1ui(void* self, GLint location, GLuint v0) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ GLSharedGroupPtr shared = ctx->m_shared;
+
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform1ui_enc(self, hostLoc, v0);
+
+ GLenum target;
+ if (shared->setSamplerUniform(state->currentProgram(), location, v0, &target)) {
+ GLenum origActiveTexture = state->getActiveTextureUnit();
+ if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + v0, target)) {
+ ctx->m_glActiveTexture_enc(self, origActiveTexture);
+ }
+ state->setActiveTextureUnit(origActiveTexture);
+ }
+}
+
+void GL2Encoder::s_glUniform2ui(void* self, GLint location, GLuint v0, GLuint v1) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform2ui_enc(self, hostLoc, v0, v1);
+}
+
+void GL2Encoder::s_glUniform3ui(void* self, GLint location, GLuint v0, GLuint v1, GLuint v2) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform3ui_enc(self, hostLoc, v0, v1, v2);
+}
+
+void GL2Encoder::s_glUniform4ui(void* self, GLint location, GLint v0, GLuint v1, GLuint v2, GLuint v3) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform4ui_enc(self, hostLoc, v0, v1, v2, v3);
+}
+
+void GL2Encoder::s_glUniform1uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform1uiv_enc(self, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glUniform2uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform2uiv_enc(self, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glUniform3uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform3uiv_enc(self, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glUniform4uiv(void* self, GLint location, GLsizei count, const GLuint *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniform4uiv_enc(self, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glUniformMatrix2x3fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix2x3fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUniformMatrix3x2fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix3x2fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUniformMatrix2x4fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix2x4fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUniformMatrix4x2fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix4x2fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUniformMatrix3x4fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix3x4fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUniformMatrix4x3fv(void* self, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+ ctx->m_glUniformMatrix4x3fv_enc(self, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glGetUniformuiv(void* self, GLuint program, GLint location, GLuint* params) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ SET_ERROR_IF(!ctx->m_shared->isShaderOrProgramObject(program), GL_INVALID_VALUE);
+ SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_OPERATION);
+ SET_ERROR_IF(!ctx->m_shared->isProgramInitialized(program), GL_INVALID_OPERATION);
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,hostLoc)==0, GL_INVALID_OPERATION);
+ ctx->m_glGetUniformuiv_enc(self, program, hostLoc, params);
+}
+
+void GL2Encoder::s_glGetActiveUniformBlockiv(void* self, GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ // refresh client state's # active uniforms in this block
+ if (pname == GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) {
+ // TODO if worth it: cache uniform count and other params,
+ // invalidate on program relinking.
+ GLint numActiveUniforms;
+ ctx->m_glGetActiveUniformBlockiv_enc(ctx,
+ program, uniformBlockIndex,
+ GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+ &numActiveUniforms);
+ ctx->m_state->setNumActiveUniformsInUniformBlock(
+ program, uniformBlockIndex, numActiveUniforms);
+ }
+
+ ctx->m_glGetActiveUniformBlockiv_enc(ctx,
+ program, uniformBlockIndex,
+ pname, params);
+}
+
+void GL2Encoder::s_glGetVertexAttribIiv(void* self, GLuint index, GLenum pname, GLint* params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state);
+ GLint maxIndex;
+ ctx->glGetIntegerv(self, GL_MAX_VERTEX_ATTRIBS, &maxIndex);
+ SET_ERROR_IF(!(index < maxIndex), GL_INVALID_VALUE);
+
+ if (!ctx->m_state->getVertexAttribParameter<GLint>(index, pname, params)) {
+ ctx->m_glGetVertexAttribIiv_enc(self, index, pname, params);
+ }
+}
+
+void GL2Encoder::s_glGetVertexAttribIuiv(void* self, GLuint index, GLenum pname, GLuint* params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state);
+ GLint maxIndex;
+ ctx->glGetIntegerv(self, GL_MAX_VERTEX_ATTRIBS, &maxIndex);
+ SET_ERROR_IF(!(index < maxIndex), GL_INVALID_VALUE);
+
+ if (!ctx->m_state->getVertexAttribParameter<GLuint>(index, pname, params)) {
+ ctx->m_glGetVertexAttribIuiv_enc(self, index, pname, params);
+ }
+}
+
+void GL2Encoder::s_glVertexAttribIPointer(void* self, GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state != NULL);
+ SET_ERROR_IF(!isValidVertexAttribIndex(self, index), GL_INVALID_VALUE);
+ SET_ERROR_IF((size < 1 || size > 4), GL_INVALID_VALUE);
+ SET_ERROR_IF(
+ !(type == GL_BYTE ||
+ type == GL_UNSIGNED_BYTE ||
+ type == GL_SHORT ||
+ type == GL_UNSIGNED_SHORT ||
+ type == GL_INT ||
+ type == GL_UNSIGNED_INT),
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(stride < 0, GL_INVALID_VALUE);
+
+ ctx->m_state->setVertexAttribBinding(index, index);
+ ctx->m_state->setVertexAttribFormat(index, size, type, false, 0, true);
+ GLsizei effectiveStride = stride;
+ if (stride == 0) {
+ effectiveStride = glSizeof(type) * size;
+ }
+ ctx->m_state->bindIndexedBuffer(0, index, ctx->m_state->currentArrayVbo(), (uintptr_t)pointer, 0, stride, effectiveStride);
+
+ if (ctx->m_state->currentArrayVbo() != 0) {
+ ctx->glVertexAttribIPointerOffsetAEMU(ctx, index, size, type, stride, (uintptr_t)pointer);
+ } else {
+ SET_ERROR_IF(ctx->m_state->currentVertexArrayObject() != 0 && pointer, GL_INVALID_OPERATION);
+ // wait for client-array handler
+ }
+}
+
+void GL2Encoder::s_glVertexAttribDivisor(void* self, GLuint index, GLuint divisor) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state != NULL);
+ SET_ERROR_IF(!isValidVertexAttribIndex(self, index), GL_INVALID_VALUE);
+ ctx->m_state->setVertexAttribBinding(index, index);
+ ctx->m_state->setVertexBindingDivisor(index, divisor);
+ ctx->m_glVertexAttribDivisor_enc(ctx, index, divisor);
+}
+
+void GL2Encoder::s_glRenderbufferStorageMultisample(void* self,
+ GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(target != GL_RENDERBUFFER, GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::rboFormat(ctx, internalformat), GL_INVALID_ENUM);
+
+ GLint max_samples;
+ ctx->s_glGetInternalformativ(ctx, target, internalformat, GL_SAMPLES, 1, &max_samples);
+ SET_ERROR_IF(samples > max_samples, GL_INVALID_OPERATION);
+
+ state->setBoundRenderbufferFormat(internalformat);
+ state->setBoundRenderbufferSamples(samples);
+ ctx->m_glRenderbufferStorageMultisample_enc(
+ self, target, samples, internalformat, width, height);
+}
+
+void GL2Encoder::s_glDrawBuffers(void* self, GLsizei n, const GLenum* bufs) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ SET_ERROR_IF(!ctx->m_state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) && n > 1, GL_INVALID_OPERATION);
+ SET_ERROR_IF(n < 0 || n > ctx->m_state->getMaxDrawBuffers(), GL_INVALID_VALUE);
+ for (int i = 0; i < n; i++) {
+ SET_ERROR_IF(
+ bufs[i] != GL_NONE &&
+ bufs[i] != GL_BACK &&
+ glUtilsColorAttachmentIndex(bufs[i]) == -1,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(
+ !ctx->m_state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ glUtilsColorAttachmentIndex(bufs[i]) != -1,
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ ctx->m_state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ ((glUtilsColorAttachmentIndex(bufs[i]) != -1 &&
+ glUtilsColorAttachmentIndex(bufs[i]) != i) ||
+ (glUtilsColorAttachmentIndex(bufs[i]) == -1 &&
+ bufs[i] != GL_NONE)),
+ GL_INVALID_OPERATION);
+ }
+
+ ctx->m_glDrawBuffers_enc(ctx, n, bufs);
+}
+
+void GL2Encoder::s_glReadBuffer(void* self, GLenum src) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ SET_ERROR_IF(
+ glUtilsColorAttachmentIndex(src) != -1 &&
+ (glUtilsColorAttachmentIndex(src) >=
+ ctx->m_state->getMaxColorAttachments()),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ src != GL_NONE &&
+ src != GL_BACK &&
+ src > GL_COLOR_ATTACHMENT0 &&
+ src < GL_DEPTH_ATTACHMENT &&
+ (src - GL_COLOR_ATTACHMENT0) >
+ ctx->m_state->getMaxColorAttachments(),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ src != GL_NONE &&
+ src != GL_BACK &&
+ glUtilsColorAttachmentIndex(src) == -1,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(
+ !ctx->m_state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ src != GL_NONE &&
+ src != GL_BACK,
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ ctx->m_state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ src != GL_NONE &&
+ glUtilsColorAttachmentIndex(src) == -1,
+ GL_INVALID_OPERATION);
+
+ ctx->m_glReadBuffer_enc(ctx, src);
+}
+
+void GL2Encoder::s_glFramebufferTextureLayer(void* self, GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::framebufferTarget(ctx, target), GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::framebufferAttachment(ctx, attachment), GL_INVALID_ENUM);
+ GLenum lastBoundTarget = state->queryTexLastBoundTarget(texture);
+ SET_ERROR_IF(lastBoundTarget != GL_TEXTURE_2D_ARRAY &&
+ lastBoundTarget != GL_TEXTURE_3D,
+ GL_INVALID_OPERATION);
+ state->attachTextureObject(target, attachment, texture);
+
+ GLint max3DTextureSize;
+ ctx->glGetIntegerv(ctx, GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize);
+ SET_ERROR_IF(
+ layer >= max3DTextureSize,
+ GL_INVALID_VALUE);
+
+ ctx->m_glFramebufferTextureLayer_enc(self, target, attachment, texture, level, layer);
+}
+
+void GL2Encoder::s_glTexStorage2D(void* self, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(
+ target != GL_TEXTURE_2D &&
+ target != GL_TEXTURE_CUBE_MAP,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelInternalFormat(internalformat), GL_INVALID_ENUM);
+ SET_ERROR_IF(!state->getBoundTexture(target), GL_INVALID_OPERATION);
+ SET_ERROR_IF(levels < 1 || width < 1 || height < 1, GL_INVALID_VALUE);
+ SET_ERROR_IF(levels > ilog2((uint32_t)std::max(width, height)) + 1,
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(state->isBoundTextureImmutableFormat(target), GL_INVALID_OPERATION);
+
+ state->setBoundTextureInternalFormat(target, internalformat);
+ state->setBoundTextureDims(target, -1, width, height, 1);
+ state->setBoundTextureImmutableFormat(target);
+ ctx->m_glTexStorage2D_enc(ctx, target, levels, internalformat, width, height);
+}
+
+void GL2Encoder::s_glTransformFeedbackVaryings(void* self, GLuint program, GLsizei count, const char** varyings, GLenum bufferMode) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_VALUE);
+
+ GLint maxCount = 0;
+ ctx->glGetIntegerv(ctx, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxCount);
+
+ SET_ERROR_IF(
+ bufferMode == GL_SEPARATE_ATTRIBS &&
+ maxCount < count,
+ GL_INVALID_VALUE);
+ SET_ERROR_IF(
+ bufferMode != GL_INTERLEAVED_ATTRIBS &&
+ bufferMode != GL_SEPARATE_ATTRIBS,
+ GL_INVALID_ENUM);
+
+ if (!count) return;
+
+ GLint err = GL_NO_ERROR;
+ std::string packed = packVarNames(count, varyings, &err);
+ SET_ERROR_IF(err != GL_NO_ERROR, GL_INVALID_OPERATION);
+
+ ctx->glTransformFeedbackVaryingsAEMU(ctx, program, count, (const char*)&packed[0], packed.size() + 1, bufferMode);
+}
+
+void GL2Encoder::s_glBeginTransformFeedback(void* self, GLenum primitiveMode) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ ctx->m_glBeginTransformFeedback_enc(ctx, primitiveMode);
+ state->setTransformFeedbackActiveUnpaused(true);
+}
+
+void GL2Encoder::s_glEndTransformFeedback(void* self) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ ctx->m_glEndTransformFeedback_enc(ctx);
+ state->setTransformFeedbackActiveUnpaused(false);
+}
+
+void GL2Encoder::s_glPauseTransformFeedback(void* self) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ ctx->m_glPauseTransformFeedback_enc(ctx);
+ state->setTransformFeedbackActiveUnpaused(false);
+}
+
+void GL2Encoder::s_glResumeTransformFeedback(void* self) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ ctx->m_glResumeTransformFeedback_enc(ctx);
+ state->setTransformFeedbackActiveUnpaused(true);
+}
+
+void GL2Encoder::s_glTexImage3D(void* self, GLenum target, GLint level, GLint internalFormat,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(target != GL_TEXTURE_3D &&
+ target != GL_TEXTURE_2D_ARRAY,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelType(ctx, type), GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelFormat(ctx, format), GL_INVALID_ENUM);
+
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+
+ GLint max_texture_size;
+ GLint max_3d_texture_size;
+ ctx->glGetIntegerv(ctx, GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ ctx->glGetIntegerv(ctx, GL_MAX_3D_TEXTURE_SIZE, &max_3d_texture_size);
+ SET_ERROR_IF(level < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_3d_texture_size), GL_INVALID_VALUE);
+
+ SET_ERROR_IF(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(width > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(height > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(depth > GL_MAX_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(width > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(height > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(depth > GL_MAX_3D_TEXTURE_SIZE, GL_INVALID_VALUE);
+ SET_ERROR_IF(border != 0, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits and is evenly divisible by the type.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (ctx->m_state->pboNeededDataSize(width, height, depth, format, type, 0) >
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size %
+ glSizeof(type)),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(state->isBoundTextureImmutableFormat(target), GL_INVALID_OPERATION);
+
+ state->setBoundTextureInternalFormat(target, internalFormat);
+ state->setBoundTextureFormat(target, format);
+ state->setBoundTextureType(target, type);
+ state->setBoundTextureDims(target, level, width, height, depth);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glTexImage3DOffsetAEMU(
+ ctx, target, level, internalFormat,
+ width, height, depth,
+ border, format, type, (uintptr_t)data);
+ } else {
+ ctx->m_glTexImage3D_enc(ctx,
+ target, level, internalFormat,
+ width, height, depth,
+ border, format, type, data);
+ }
+}
+
+void GL2Encoder::s_glTexSubImage3D(void* self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(target != GL_TEXTURE_3D &&
+ target != GL_TEXTURE_2D_ARRAY,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelType(ctx, type), GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelFormat(ctx, format), GL_INVALID_ENUM);
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+ GLint max_texture_size;
+ GLint max_3d_texture_size;
+ ctx->glGetIntegerv(ctx, GL_MAX_TEXTURE_SIZE, &max_texture_size);
+ ctx->glGetIntegerv(ctx, GL_MAX_3D_TEXTURE_SIZE, &max_3d_texture_size);
+ SET_ERROR_IF(level < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(level > ilog2(max_3d_texture_size), GL_INVALID_VALUE);
+ SET_ERROR_IF(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(xoffset < 0 || yoffset < 0 || zoffset < 0, GL_INVALID_VALUE);
+ GLuint tex = state->getBoundTexture(target);
+ GLsizei neededWidth = xoffset + width;
+ GLsizei neededHeight = yoffset + height;
+ GLsizei neededDepth = zoffset + depth;
+
+ SET_ERROR_IF(tex &&
+ (neededWidth > state->queryTexWidth(level, tex) ||
+ neededHeight > state->queryTexHeight(level, tex) ||
+ neededDepth > state->queryTexDepth(level, tex)),
+ GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits and is evenly divisible by the type.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (ctx->m_state->pboNeededDataSize(width, height, depth, format, type, 0) >
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size %
+ glSizeof(type)),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(!ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) && !data, GL_INVALID_OPERATION);
+ SET_ERROR_IF(xoffset < 0 || yoffset < 0 || zoffset < 0, GL_INVALID_VALUE);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glTexSubImage3DOffsetAEMU(ctx,
+ target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, type, (uintptr_t)data);
+ } else {
+ ctx->m_glTexSubImage3D_enc(ctx,
+ target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, type, data);
+ }
+}
+
+void GL2Encoder::s_glCompressedTexImage3D(void* self, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ // Filter compressed formats support.
+ SET_ERROR_IF(!GLESv2Validation::supportedCompressedFormat(ctx, internalformat), GL_INVALID_ENUM);
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+ SET_ERROR_IF(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(border, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (imageSize > ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ // TODO: Fix:
+ // If |imageSize| is too small for compressed dimensions.
+ // SET_ERROR_IF(GLESv2Validation::compressedTexImageSize(internalformat, width, height, depth) > imageSize, GL_INVALID_VALUE);
+ state->setBoundTextureInternalFormat(target, (GLint)internalformat);
+ state->setBoundTextureDims(target, level, width, height, depth);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glCompressedTexImage3DOffsetAEMU(
+ ctx, target, level, internalformat,
+ width, height, depth, border,
+ imageSize, (uintptr_t)data);
+ } else {
+ ctx->m_glCompressedTexImage3D_enc(
+ ctx, target, level, internalformat,
+ width, height, depth, border,
+ imageSize, data);
+ }
+}
+
+void GL2Encoder::s_glCompressedTexSubImage3D(void* self, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM);
+ // If unpack buffer is nonzero, verify unmapped state.
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_UNPACK_BUFFER), GL_INVALID_OPERATION);
+ SET_ERROR_IF(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE);
+ // If unpack buffer is nonzero, verify buffer data fits.
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER) &&
+ (imageSize > ctx->getBufferData(GL_PIXEL_UNPACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(xoffset < 0 || yoffset < 0 || zoffset < 0, GL_INVALID_VALUE);
+
+ if (ctx->boundBuffer(GL_PIXEL_UNPACK_BUFFER)) {
+ ctx->glCompressedTexSubImage3DOffsetAEMU(
+ ctx, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, imageSize, (uintptr_t)data);
+ } else {
+ ctx->m_glCompressedTexSubImage3D_enc(
+ ctx, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, imageSize, data);
+
+ }
+}
+
+void GL2Encoder::s_glTexStorage3D(void* self, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) {
+ GL2Encoder* ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ SET_ERROR_IF(target != GL_TEXTURE_3D &&
+ target != GL_TEXTURE_2D_ARRAY,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelInternalFormat(internalformat), GL_INVALID_ENUM);
+ SET_ERROR_IF(!state->getBoundTexture(target), GL_INVALID_OPERATION);
+ SET_ERROR_IF(levels < 1 || width < 1 || height < 1, GL_INVALID_VALUE);
+ SET_ERROR_IF(target == GL_TEXTURE_3D && (levels > ilog2((uint32_t)std::max(width, std::max(height, depth))) + 1),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(target == GL_TEXTURE_2D_ARRAY && (levels > ilog2((uint32_t)std::max(width, height)) + 1),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(state->isBoundTextureImmutableFormat(target), GL_INVALID_OPERATION);
+
+ state->setBoundTextureInternalFormat(target, internalformat);
+ state->setBoundTextureDims(target, -1, width, height, depth);
+ state->setBoundTextureImmutableFormat(target);
+ ctx->m_glTexStorage3D_enc(ctx, target, levels, internalformat, width, height, depth);
+ state->setBoundTextureImmutableFormat(target);
+}
+
+void GL2Encoder::s_glDrawArraysInstanced(void* self, GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state != NULL);
+ SET_ERROR_IF(!isValidDrawMode(mode), GL_INVALID_ENUM);
+ SET_ERROR_IF(count < 0, GL_INVALID_VALUE);
+
+ bool has_client_vertex_arrays = false;
+ bool has_indirect_arrays = false;
+ ctx->getVBOUsage(&has_client_vertex_arrays,
+ &has_indirect_arrays);
+
+ if (has_client_vertex_arrays ||
+ (!has_client_vertex_arrays &&
+ !has_indirect_arrays)) {
+ ctx->sendVertexAttributes(first, count, true, primcount);
+ ctx->m_glDrawArraysInstanced_enc(ctx, mode, 0, count, primcount);
+ } else {
+ ctx->sendVertexAttributes(0, count, false, primcount);
+ ctx->m_glDrawArraysInstanced_enc(ctx, mode, first, count, primcount);
+ }
+ ctx->m_stream->flush();
+}
+
+void GL2Encoder::s_glDrawElementsInstanced(void* self, GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount)
+{
+
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state != NULL);
+ SET_ERROR_IF(!isValidDrawMode(mode), GL_INVALID_ENUM);
+ SET_ERROR_IF(count < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(!(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT), GL_INVALID_ENUM);
+ SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION);
+
+ bool has_client_vertex_arrays = false;
+ bool has_indirect_arrays = false;
+ int nLocations = ctx->m_state->nLocations();
+ GLintptr offset = 0;
+
+ ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
+
+ if (!has_client_vertex_arrays && !has_indirect_arrays) {
+ // ALOGW("glDrawElements: no vertex arrays / buffers bound to the command\n");
+ GLenum status = ctx->m_glCheckFramebufferStatus_enc(self, GL_FRAMEBUFFER);
+ SET_ERROR_IF(status != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ BufferData* buf = NULL;
+ int minIndex = 0, maxIndex = 0;
+
+ // For validation/immediate index array purposes,
+ // we need the min/max vertex index of the index array.
+ // If the VBO != 0, this may not be the first time we have
+ // used this particular index buffer. getBufferIndexRange
+ // can more quickly get min/max vertex index by
+ // caching previous results.
+ if (ctx->m_state->currentIndexVbo() != 0) {
+ buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+ offset = (GLintptr)indices;
+ indices = (void*)((GLintptr)buf->m_fixedBuffer.ptr() + (GLintptr)indices);
+ ctx->getBufferIndexRange(buf,
+ indices,
+ type,
+ (size_t)count,
+ (size_t)offset,
+ &minIndex, &maxIndex);
+ } else {
+ // In this case, the |indices| field holds a real
+ // array, so calculate the indices now. They will
+ // also be needed to know how much data to
+ // transfer to host.
+ ctx->calcIndexRange(indices,
+ type,
+ count,
+ &minIndex,
+ &maxIndex);
+ }
+
+ bool adjustIndices = true;
+ if (ctx->m_state->currentIndexVbo() != 0) {
+ if (!has_client_vertex_arrays) {
+ ctx->sendVertexAttributes(0, maxIndex + 1, false, primcount);
+ ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
+ ctx->glDrawElementsInstancedOffsetAEMU(ctx, mode, count, type, offset, primcount);
+ ctx->flushDrawCall();
+ adjustIndices = false;
+ } else {
+ BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+ ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+ if (adjustIndices) {
+ void *adjustedIndices =
+ ctx->recenterIndices(indices,
+ type,
+ count,
+ minIndex);
+
+ if (has_indirect_arrays || 1) {
+ ctx->sendVertexAttributes(minIndex, maxIndex - minIndex + 1, true, primcount);
+ ctx->glDrawElementsInstancedDataAEMU(ctx, mode, count, type, adjustedIndices, primcount, count * glSizeof(type));
+ ctx->m_stream->flush();
+ // XXX - OPTIMIZATION (see the other else branch) should be implemented
+ if(!has_indirect_arrays) {
+ //ALOGD("unoptimized drawelements !!!\n");
+ }
+ } else {
+ // we are all direct arrays and immidate mode index array -
+ // rebuild the arrays and the index array;
+ ALOGE("glDrawElements: direct index & direct buffer data - will be implemented in later versions;\n");
+ }
+ }
+}
+
+void GL2Encoder::s_glDrawRangeElements(void* self, GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void* indices)
+{
+
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ assert(ctx->m_state != NULL);
+ SET_ERROR_IF(!isValidDrawMode(mode), GL_INVALID_ENUM);
+ SET_ERROR_IF(end < start, GL_INVALID_VALUE);
+ SET_ERROR_IF(count < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(!(type == GL_UNSIGNED_BYTE || type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT), GL_INVALID_ENUM);
+ SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION);
+
+ bool has_client_vertex_arrays = false;
+ bool has_indirect_arrays = false;
+ int nLocations = ctx->m_state->nLocations();
+ GLintptr offset = 0;
+
+ ctx->getVBOUsage(&has_client_vertex_arrays, &has_indirect_arrays);
+
+ if (!has_client_vertex_arrays && !has_indirect_arrays) {
+ // ALOGW("glDrawElements: no vertex arrays / buffers bound to the command\n");
+ GLenum status = ctx->m_glCheckFramebufferStatus_enc(self, GL_FRAMEBUFFER);
+ SET_ERROR_IF(status != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ BufferData* buf = NULL;
+ int minIndex = 0, maxIndex = 0;
+
+ // For validation/immediate index array purposes,
+ // we need the min/max vertex index of the index array.
+ // If the VBO != 0, this may not be the first time we have
+ // used this particular index buffer. getBufferIndexRange
+ // can more quickly get min/max vertex index by
+ // caching previous results.
+ if (ctx->m_state->currentIndexVbo() != 0) {
+ buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+ offset = (GLintptr)indices;
+ indices = (void*)((GLintptr)buf->m_fixedBuffer.ptr() + (GLintptr)indices);
+ ctx->getBufferIndexRange(buf,
+ indices,
+ type,
+ (size_t)count,
+ (size_t)offset,
+ &minIndex, &maxIndex);
+ } else {
+ // In this case, the |indices| field holds a real
+ // array, so calculate the indices now. They will
+ // also be needed to know how much data to
+ // transfer to host.
+ ctx->calcIndexRange(indices,
+ type,
+ count,
+ &minIndex,
+ &maxIndex);
+ }
+
+ bool adjustIndices = true;
+ if (ctx->m_state->currentIndexVbo() != 0) {
+ if (!has_client_vertex_arrays) {
+ ctx->sendVertexAttributes(0, maxIndex + 1, false);
+ ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo());
+ ctx->glDrawElementsOffset(ctx, mode, count, type, offset);
+ ctx->flushDrawCall();
+ adjustIndices = false;
+ } else {
+ BufferData * buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo());
+ ctx->m_glBindBuffer_enc(self, GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+ if (adjustIndices) {
+ void *adjustedIndices =
+ ctx->recenterIndices(indices,
+ type,
+ count,
+ minIndex);
+
+ if (has_indirect_arrays || 1) {
+ ctx->sendVertexAttributes(minIndex, maxIndex - minIndex + 1, true);
+ ctx->glDrawElementsData(ctx, mode, count, type, adjustedIndices, count * glSizeof(type));
+ ctx->m_stream->flush();
+ // XXX - OPTIMIZATION (see the other else branch) should be implemented
+ if(!has_indirect_arrays) {
+ //ALOGD("unoptimized drawelements !!!\n");
+ }
+ } else {
+ // we are all direct arrays and immidate mode index array -
+ // rebuild the arrays and the index array;
+ ALOGE("glDrawElements: direct index & direct buffer data - will be implemented in later versions;\n");
+ }
+ }
+}
+
+// struct GLStringKey {
+// GLenum name;
+// GLuint index;
+// };
+//
+// struct GLStringKeyCompare {
+// bool operator() (const GLStringKey& a,
+// const GLStringKey& b) const {
+// if (a.name != b.name) return a.name < b.name;
+// if (a.index != b.index) return a.index < b.index;
+// return false;
+// }
+// };
+//
+// typedef std::map<GLStringKey, std::string, GLStringKeyCompare> GLStringStore;
+//
+// static GLStringStore sGLStringStore;
+// bool sGLStringStoreInitialized = false;
+
+const GLubyte* GL2Encoder::s_glGetStringi(void* self, GLenum name, GLuint index) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ GLubyte *retval = (GLubyte *) "";
+
+ RET_AND_SET_ERROR_IF(
+ name != GL_VENDOR &&
+ name != GL_RENDERER &&
+ name != GL_VERSION &&
+ name != GL_EXTENSIONS,
+ GL_INVALID_ENUM,
+ retval);
+
+ RET_AND_SET_ERROR_IF(
+ name == GL_VENDOR ||
+ name == GL_RENDERER ||
+ name == GL_VERSION ||
+ name == GL_EXTENSIONS &&
+ index != 0,
+ GL_INVALID_VALUE,
+ retval);
+
+ switch (name) {
+ case GL_VENDOR:
+ retval = gVendorString;
+ break;
+ case GL_RENDERER:
+ retval = gRendererString;
+ break;
+ case GL_VERSION:
+ retval = gVersionString;
+ break;
+ case GL_EXTENSIONS:
+ retval = gExtensionsString;
+ break;
+ }
+
+ return retval;
+}
+
+void GL2Encoder::s_glGetProgramBinary(void* self, GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(!ctx->m_shared->isProgram(program), GL_INVALID_OPERATION);
+
+ GLint linkStatus = 0;
+ ctx->glGetProgramiv(self, program, GL_LINK_STATUS, &linkStatus);
+ GLint properLength = 0;
+ ctx->glGetProgramiv(self, program, GL_PROGRAM_BINARY_LENGTH, &properLength);
+
+ SET_ERROR_IF(!linkStatus, GL_INVALID_OPERATION);
+ SET_ERROR_IF(bufSize < properLength, GL_INVALID_OPERATION);
+
+ ctx->m_glGetProgramBinary_enc(ctx, program, bufSize, length, binaryFormat, binary);
+}
+
+void GL2Encoder::s_glReadPixels(void* self, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(!GLESv2Validation::readPixelsFormat(format), GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::readPixelsType(type), GL_INVALID_ENUM);
+ SET_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE);
+ SET_ERROR_IF(ctx->isBufferTargetMapped(GL_PIXEL_PACK_BUFFER), GL_INVALID_OPERATION);
+ SET_ERROR_IF(ctx->boundBuffer(GL_PIXEL_PACK_BUFFER) &&
+ ctx->getBufferData(GL_PIXEL_PACK_BUFFER) &&
+ (ctx->m_state->pboNeededDataSize(width, height, 1, format, type, 1) >
+ ctx->getBufferData(GL_PIXEL_PACK_BUFFER)->m_size),
+ GL_INVALID_OPERATION);
+ /*
+GL_INVALID_OPERATION is generated if the readbuffer of the currently bound framebuffer is a fixed point normalized surface and format and type are neither GL_RGBA and GL_UNSIGNED_BYTE, respectively, nor the format/type pair returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+
+GL_INVALID_OPERATION is generated if the readbuffer of the currently bound framebuffer is a floating point surface and format and type are neither GL_RGBA and GL_FLOAT, respectively, nor the format/type pair returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+
+GL_INVALID_OPERATION is generated if the readbuffer of the currently bound framebuffer is a signed integer surface and format and type are neither GL_RGBA_INTEGER and GL_INT, respectively, nor the format/type pair returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+
+GL_INVALID_OPERATION is generated if the readbuffer of the currently bound framebuffer is an unsigned integer surface and format and type are neither GL_RGBA_INTEGER and GL_UNSIGNED_INT, respectively, nor the format/type pair returned by querying GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE.
+*/
+
+ FboFormatInfo fbo_format_info;
+ ctx->m_state->getBoundFramebufferFormat(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, &fbo_format_info);
+ SET_ERROR_IF(
+ fbo_format_info.type == FBO_ATTACHMENT_TEXTURE &&
+ !GLESv2Validation::readPixelsFboFormatMatch(
+ format, type, fbo_format_info.tex_type),
+ GL_INVALID_OPERATION);
+
+ if (ctx->boundBuffer(GL_PIXEL_PACK_BUFFER)) {
+ ctx->glReadPixelsOffsetAEMU(
+ ctx, x, y, width, height,
+ format, type, (uintptr_t)pixels);
+ } else {
+ ctx->m_glReadPixels_enc(
+ ctx, x, y, width, height,
+ format, type, pixels);
+ }
+}
+
+// Track enabled state for some things like:
+// - Primitive restart
+void GL2Encoder::s_glEnable(void* self, GLenum what) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ switch (what) {
+ case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+ ctx->m_primitiveRestartEnabled = true;
+ break;
+ }
+
+ ctx->m_glEnable_enc(ctx, what);
+}
+
+void GL2Encoder::s_glDisable(void* self, GLenum what) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ switch (what) {
+ case GL_PRIMITIVE_RESTART_FIXED_INDEX:
+ ctx->m_primitiveRestartEnabled = false;
+ break;
+ }
+
+ ctx->m_glDisable_enc(ctx, what);
+}
+
+void GL2Encoder::s_glClearBufferiv(void* self, GLenum buffer, GLint drawBuffer, const GLint * value) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(buffer == GL_DEPTH || buffer == GL_DEPTH_STENCIL, GL_INVALID_ENUM);
+
+ ctx->m_glClearBufferiv_enc(ctx, buffer, drawBuffer, value);
+}
+
+void GL2Encoder::s_glClearBufferuiv(void* self, GLenum buffer, GLint drawBuffer, const GLuint * value) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(buffer == GL_DEPTH || buffer == GL_STENCIL || buffer == GL_DEPTH_STENCIL, GL_INVALID_ENUM);
+
+ ctx->m_glClearBufferuiv_enc(ctx, buffer, drawBuffer, value);
+}
+
+void GL2Encoder::s_glClearBufferfv(void* self, GLenum buffer, GLint drawBuffer, const GLfloat * value) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(buffer == GL_STENCIL || buffer == GL_DEPTH_STENCIL, GL_INVALID_ENUM);
+
+ ctx->m_glClearBufferfv_enc(ctx, buffer, drawBuffer, value);
+}
+
+void GL2Encoder::s_glBlitFramebuffer(void* self, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ GLClientState* state = ctx->m_state;
+
+ bool validateColor = mask | GL_COLOR_BUFFER_BIT;
+ bool validateDepth = mask | GL_DEPTH_BUFFER_BIT;
+ bool validateStencil = mask | GL_STENCIL_BUFFER_BIT;
+
+ FboFormatInfo read_fbo_format_info;
+ FboFormatInfo draw_fbo_format_info;
+ if (validateColor) {
+ state->getBoundFramebufferFormat(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, &read_fbo_format_info);
+ state->getBoundFramebufferFormat(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, &draw_fbo_format_info);
+
+ if (read_fbo_format_info.type == FBO_ATTACHMENT_TEXTURE &&
+ draw_fbo_format_info.type == FBO_ATTACHMENT_TEXTURE) {
+ SET_ERROR_IF(
+ state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ !GLESv2Validation::blitFramebufferFormat(
+ read_fbo_format_info.tex_type,
+ draw_fbo_format_info.tex_type),
+ GL_INVALID_OPERATION);
+ }
+ }
+
+ if (validateDepth) {
+ state->getBoundFramebufferFormat(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, &read_fbo_format_info);
+ state->getBoundFramebufferFormat(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, &draw_fbo_format_info);
+
+ if (read_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ draw_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER) {
+ SET_ERROR_IF(
+ state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ !GLESv2Validation::blitFramebufferFormat(
+ read_fbo_format_info.rb_format,
+ draw_fbo_format_info.rb_format),
+ GL_INVALID_OPERATION);
+ }
+ }
+
+ if (validateStencil) {
+ state->getBoundFramebufferFormat(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, &read_fbo_format_info);
+ state->getBoundFramebufferFormat(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, &draw_fbo_format_info);
+
+ if (read_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ draw_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER) {
+ SET_ERROR_IF(
+ state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ !GLESv2Validation::blitFramebufferFormat(
+ read_fbo_format_info.rb_format,
+ draw_fbo_format_info.rb_format),
+ GL_INVALID_OPERATION);
+ }
+ }
+
+ state->getBoundFramebufferFormat(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, &draw_fbo_format_info);
+ SET_ERROR_IF(
+ draw_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ draw_fbo_format_info.rb_multisamples > 0,
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ draw_fbo_format_info.type == FBO_ATTACHMENT_TEXTURE &&
+ draw_fbo_format_info.tex_multisamples > 0,
+ GL_INVALID_OPERATION);
+
+ state->getBoundFramebufferFormat(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, &read_fbo_format_info);
+ SET_ERROR_IF(
+ read_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ read_fbo_format_info.rb_multisamples > 0 &&
+ draw_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ state->boundFramebuffer(GL_READ_FRAMEBUFFER) &&
+ state->boundFramebuffer(GL_DRAW_FRAMEBUFFER) &&
+ (read_fbo_format_info.rb_format !=
+ draw_fbo_format_info.rb_format),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(
+ read_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ read_fbo_format_info.rb_multisamples > 0 &&
+ draw_fbo_format_info.type == FBO_ATTACHMENT_RENDERBUFFER &&
+ (srcX0 != dstX0 || srcY0 != dstY0 ||
+ srcX1 != dstX1 || srcY1 != dstY1),
+ GL_INVALID_OPERATION);
+
+ ctx->m_glBlitFramebuffer_enc(ctx,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+}
+
+void GL2Encoder::s_glGetInternalformativ(void* self, GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ SET_ERROR_IF(pname != GL_NUM_SAMPLE_COUNTS &&
+ pname != GL_SAMPLES,
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(target != GL_RENDERBUFFER, GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::unsizedFormat(internalformat) &&
+ !GLESv2Validation::colorRenderableFormat(internalformat) &&
+ !GLESv2Validation::depthRenderableFormat(internalformat) &&
+ !GLESv2Validation::stencilRenderableFormat(internalformat),
+ GL_INVALID_ENUM);
+ SET_ERROR_IF(bufSize < 0, GL_INVALID_VALUE);
+
+ if (bufSize < 1) return;
+
+ // Desktop OpenGL can allow a mindboggling # samples per pixel (such as 64).
+ // Limit to 4 (spec minimum) to keep dEQP tests from timing out.
+ switch (pname) {
+ case GL_NUM_SAMPLE_COUNTS:
+ *params = 3;
+ break;
+ case GL_SAMPLES:
+ params[0] = 4;
+ if (bufSize > 1) params[1] = 2;
+ if (bufSize > 2) params[2] = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void GL2Encoder::s_glGenerateMipmap(void* self, GLenum target) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(target != GL_TEXTURE_2D &&
+ target != GL_TEXTURE_3D &&
+ target != GL_TEXTURE_CUBE_MAP,
+ GL_INVALID_ENUM);
+
+ GLuint tex = state->getBoundTexture(target);
+ GLenum internalformat = state->queryTexInternalFormat(tex);
+ GLenum format = state->queryTexFormat(tex);
+
+ SET_ERROR_IF(tex && GLESv2Validation::isCompressedFormat(internalformat),
+ GL_INVALID_OPERATION);
+ SET_ERROR_IF(tex &&
+ !GLESv2Validation::unsizedFormat(internalformat) &&
+ (!GLESv2Validation::colorRenderableFormat(internalformat) ||
+ !GLESv2Validation::filterableTexFormat(internalformat)),
+ GL_INVALID_OPERATION);
+
+ ctx->m_glGenerateMipmap_enc(ctx, target);
+}
+
+void GL2Encoder::s_glBindSampler(void* self, GLuint unit, GLuint sampler) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ GLint maxCombinedUnits;
+ ctx->glGetIntegerv(ctx, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedUnits);
+ SET_ERROR_IF(unit >= maxCombinedUnits, GL_INVALID_VALUE);
+
+ ctx->m_glBindSampler_enc(ctx, unit, sampler);
+}
+
+void GL2Encoder::s_glDeleteSync(void* self, GLsync sync) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ if (!sync) return;
+
+ ctx->m_glDeleteSync_enc(ctx, sync);
+}
+
+#define LIMIT_CASE(target, lim) \
+ case target: \
+ ctx->glGetIntegerv(ctx, lim, &limit); \
+ SET_ERROR_IF(index >= limit, GL_INVALID_VALUE); \
+ break; \
+
+void GL2Encoder::s_glGetIntegeri_v(void* self, GLenum target, GLuint index, GLint* params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ GLint limit;
+
+ switch (target) {
+ LIMIT_CASE(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
+ LIMIT_CASE(GL_UNIFORM_BUFFER_BINDING, GL_MAX_UNIFORM_BUFFER_BINDINGS)
+ LIMIT_CASE(GL_ATOMIC_COUNTER_BUFFER_BINDING, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS)
+ LIMIT_CASE(GL_SHADER_STORAGE_BUFFER_BINDING, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS)
+ default:
+ break;
+ }
+
+ ctx->m_glGetIntegeri_v_enc(self, target, index, params);
+}
+
+void GL2Encoder::s_glGetInteger64i_v(void* self, GLenum target, GLuint index, GLint64* params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+
+ GLint limit;
+
+ switch (target) {
+ LIMIT_CASE(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
+ LIMIT_CASE(GL_UNIFORM_BUFFER_BINDING, GL_MAX_UNIFORM_BUFFER_BINDINGS)
+ LIMIT_CASE(GL_ATOMIC_COUNTER_BUFFER_BINDING, GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS)
+ LIMIT_CASE(GL_SHADER_STORAGE_BUFFER_BINDING, GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS)
+ default:
+ break;
+ }
+
+ ctx->m_glGetInteger64i_v_enc(self, target, index, params);
+}
+
+void GL2Encoder::s_glGetShaderiv(void* self, GLuint shader, GLenum pname, GLint* params) {
+ GL2Encoder *ctx = (GL2Encoder *)self;
+ ctx->m_glGetShaderiv_enc(self, shader, pname, params);
+ if (pname == GL_SHADER_SOURCE_LENGTH) {
+ ShaderData* shaderData = ctx->m_shared->getShaderData(shader);
+ if (shaderData) {
+ int totalLen = 0;
+ for (int i = 0; i < shaderData->sources.size(); i++) {
+ totalLen += shaderData->sources[i].size();
+ }
+ if (totalLen != 0) {
+ *params = totalLen + 1; // account for null terminator
+ }
+ }
+ }
+}
+
+GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei count, const char** strings) {
+
+ GLint* length = NULL;
+ GL2Encoder* ctx = (GL2Encoder*)self;
+
+ int len = glUtilsCalcShaderSourceLen((char**)strings, length, count);
+ char *str = new char[len + 1];
+ glUtilsPackStrings(str, (char**)strings, (GLint*)length, count);
+
+ // Do GLSharedGroup and location WorkARound-specific initialization
+ // Phase 1: create a ShaderData and initialize with replaceSamplerExternalWith2D()
+ uint32_t spDataId = ctx->m_shared->addNewShaderProgramData();
+ ShaderProgramData* spData = ctx->m_shared->getShaderProgramDataById(spDataId);
+ ShaderData* sData = spData->shaderData;
+
+ if (!replaceSamplerExternalWith2D(str, sData)) {
+ delete [] str;
+ ctx->setError(GL_OUT_OF_MEMORY);
+ ctx->m_shared->deleteShaderProgramDataById(spDataId);
+ return -1;
+ }
+
+ GLuint res = ctx->glCreateShaderProgramvAEMU(ctx, type, count, str, len + 1);
+ delete [] str;
+
+ // Phase 2: do glLinkProgram-related initialization for locationWorkARound
+ GLint linkStatus = 0;
+ ctx->glGetProgramiv(self, res, GL_LINK_STATUS ,&linkStatus);
+ if (!linkStatus) {
+ ctx->m_shared->deleteShaderProgramDataById(spDataId);
+ return -1;
+ }
+
+ ctx->m_shared->associateGLShaderProgram(res, spDataId);
+
+ GLint numUniforms = 0;
+ ctx->glGetProgramiv(ctx, res, GL_ACTIVE_UNIFORMS, &numUniforms);
+ ctx->m_shared->initShaderProgramData(res, numUniforms);
+
+ GLint maxLength=0;
+ ctx->glGetProgramiv(self, res, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+
+ GLint size; GLenum uniformType; GLchar* name = new GLchar[maxLength + 1];
+
+ for (GLint i = 0; i < numUniforms; ++i) {
+ ctx->glGetActiveUniform(self, res, i, maxLength, NULL, &size, &uniformType, name);
+ GLint location = ctx->m_glGetUniformLocation_enc(self, res, name);
+ ctx->m_shared->setShaderProgramIndexInfo(res, i, location, size, uniformType, name);
+ }
+
+ ctx->m_shared->setupShaderProgramLocationShiftWAR(res);
+
+ delete [] name;
+
+ return res;
+}
+
+void GL2Encoder::s_glProgramUniform1f(void* self, GLuint program, GLint location, GLfloat v0)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1f_enc(self, program, hostLoc, v0);
+}
+
+void GL2Encoder::s_glProgramUniform1fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1fv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform1i(void* self, GLuint program, GLint location, GLint v0)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1ui_enc(self, program, hostLoc, v0);
+
+ GLClientState* state = ctx->m_state;
+ GLSharedGroupPtr shared = ctx->m_shared;
+ GLenum target;
+
+ if (shared->setSamplerUniform(program, location, v0, &target)) {
+ GLenum origActiveTexture = state->getActiveTextureUnit();
+ if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + v0, target)) {
+ ctx->m_glActiveTexture_enc(self, origActiveTexture);
+ }
+ state->setActiveTextureUnit(origActiveTexture);
+ }
+}
+
+void GL2Encoder::s_glProgramUniform1iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1iv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform1ui(void* self, GLuint program, GLint location, GLuint v0)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1ui_enc(self, program, hostLoc, v0);
+
+ GLClientState* state = ctx->m_state;
+ GLSharedGroupPtr shared = ctx->m_shared;
+ GLenum target;
+
+ if (shared->setSamplerUniform(program, location, v0, &target)) {
+ GLenum origActiveTexture = state->getActiveTextureUnit();
+ if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + v0, target)) {
+ ctx->m_glActiveTexture_enc(self, origActiveTexture);
+ }
+ state->setActiveTextureUnit(origActiveTexture);
+ }
+}
+
+void GL2Encoder::s_glProgramUniform1uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform1uiv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform2f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2f_enc(self, program, hostLoc, v0, v1);
+}
+
+void GL2Encoder::s_glProgramUniform2fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2fv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform2i(void* self, GLuint program, GLint location, GLint v0, GLint v1)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2i_enc(self, program, hostLoc, v0, v1);
+}
+
+void GL2Encoder::s_glProgramUniform2iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2iv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform2ui(void* self, GLuint program, GLint location, GLint v0, GLuint v1)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2ui_enc(self, program, hostLoc, v0, v1);
+}
+
+void GL2Encoder::s_glProgramUniform2uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform2uiv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform3f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3f_enc(self, program, hostLoc, v0, v1, v2);
+}
+
+void GL2Encoder::s_glProgramUniform3fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3fv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform3i(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3i_enc(self, program, hostLoc, v0, v1, v2);
+}
+
+void GL2Encoder::s_glProgramUniform3iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3iv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform3ui(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLuint v2)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3ui_enc(self, program, hostLoc, v0, v1, v2);
+}
+
+void GL2Encoder::s_glProgramUniform3uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform3uiv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform4f(void* self, GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4f_enc(self, program, hostLoc, v0, v1, v2, v3);
+}
+
+void GL2Encoder::s_glProgramUniform4fv(void* self, GLuint program, GLint location, GLsizei count, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4fv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform4i(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4i_enc(self, program, hostLoc, v0, v1, v2, v3);
+}
+
+void GL2Encoder::s_glProgramUniform4iv(void* self, GLuint program, GLint location, GLsizei count, const GLint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4iv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniform4ui(void* self, GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLuint v3)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4ui_enc(self, program, hostLoc, v0, v1, v2, v3);
+}
+
+void GL2Encoder::s_glProgramUniform4uiv(void* self, GLuint program, GLint location, GLsizei count, const GLuint *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniform4uiv_enc(self, program, hostLoc, count, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix2fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix2x3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix2x3fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix2x4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix2x4fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix3fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix3x2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix3x2fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix3x4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix3x4fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix4fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix4fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix4x2fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix4x2fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glProgramUniformMatrix4x3fv(void* self, GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
+ ctx->m_glProgramUniformMatrix4x3fv_enc(self, program, hostLoc, count, transpose, value);
+}
+
+void GL2Encoder::s_glUseProgramStages(void *self, GLuint pipeline, GLbitfield stages, GLuint program)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+ GLSharedGroupPtr shared = ctx->m_shared;
+
+ SET_ERROR_IF(!pipeline, GL_INVALID_OPERATION);
+ SET_ERROR_IF(program && !shared->isShaderOrProgramObject(program), GL_INVALID_VALUE);
+ SET_ERROR_IF(program && !shared->isProgram(program), GL_INVALID_OPERATION);
+
+ ctx->m_glUseProgramStages_enc(self, pipeline, stages, program);
+ state->associateProgramWithPipeline(program, pipeline);
+
+ // There is an active non-separable shader program in effect; no need to update external/2D bindings.
+ if (state->currentProgram()) {
+ return;
+ }
+
+ // Otherwise, update host texture 2D bindings.
+ ctx->updateHostTexture2DBindingsFromProgramData(program);
+}
+
+void GL2Encoder::s_glBindProgramPipeline(void* self, GLuint pipeline)
+{
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ ctx->m_glBindProgramPipeline_enc(self, pipeline);
+
+ // There is an active non-separable shader program in effect; no need to update external/2D bindings.
+ if (!pipeline || state->currentProgram()) {
+ return;
+ }
+
+ GLClientState::ProgramPipelineIterator it = state->programPipelineBegin();
+ for (; it != state->programPipelineEnd(); ++it) {
+ if (it->second == pipeline) {
+ ctx->updateHostTexture2DBindingsFromProgramData(it->first);
+ }
+ }
+}
+
+void GL2Encoder::s_glVertexAttribFormat(void* self, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ state->setVertexAttribFormat(attribindex, size, type, normalized, relativeoffset, false);
+ ctx->m_glVertexAttribFormat_enc(ctx, attribindex, size, type, normalized, relativeoffset);
+}
+
+void GL2Encoder::s_glVertexAttribIFormat(void* self, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ state->setVertexAttribFormat(attribindex, size, type, GL_FALSE, relativeoffset, true);
+ ctx->m_glVertexAttribIFormat_enc(ctx, attribindex, size, type, relativeoffset);
+}
+
+void GL2Encoder::s_glVertexBindingDivisor(void* self, GLuint bindingindex, GLuint divisor) {
+
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ state->setVertexBindingDivisor(bindingindex, divisor);
+ ctx->m_glVertexBindingDivisor_enc(ctx, bindingindex, divisor);
+}
+
+void GL2Encoder::s_glVertexAttribBinding(void* self, GLuint attribindex, GLuint bindingindex) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ state->setVertexAttribBinding(attribindex, bindingindex);
+ ctx->m_glVertexAttribBinding_enc(ctx, attribindex, bindingindex);
+}
+
+void GL2Encoder::s_glBindVertexBuffer(void* self, GLuint bindingindex, GLuint buffer, GLintptr offset, GLintptr stride) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ state->bindIndexedBuffer(0, bindingindex, buffer, offset, 0, stride, stride);
+ ctx->m_glBindVertexBuffer_enc(ctx, bindingindex, buffer, offset, stride);
+}
+
+void GL2Encoder::s_glDrawArraysIndirect(void* self, GLenum mode, const void* indirect) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+
+ if (ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER)) {
+ ctx->glDrawArraysIndirectOffsetAEMU(ctx, mode, (uintptr_t)indirect);
+ } else {
+ GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWARRAYS);
+ ctx->glDrawArraysIndirectDataAEMU(ctx, mode, indirect, indirectStructSize);
+ }
+}
+
+void GL2Encoder::s_glDrawElementsIndirect(void* self, GLenum mode, GLenum type, const void* indirect) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+
+ SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION);
+ if (ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER)) {
+ ctx->glDrawElementsIndirectOffsetAEMU(ctx, mode, type, (uintptr_t)indirect);
+ } else {
+ GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWELEMENTS);
+ ctx->glDrawElementsIndirectDataAEMU(ctx, mode, type, indirect, indirectStructSize);
+ }
+
+}
+
+void GL2Encoder::s_glTexStorage2DMultisample(void* self, GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) {
+ GL2Encoder *ctx = (GL2Encoder*)self;
+ GLClientState* state = ctx->m_state;
+
+ SET_ERROR_IF(target != GL_TEXTURE_2D_MULTISAMPLE, GL_INVALID_ENUM);
+ SET_ERROR_IF(!GLESv2Validation::pixelInternalFormat(internalformat), GL_INVALID_ENUM);
+ SET_ERROR_IF(!state->getBoundTexture(target), GL_INVALID_OPERATION);
+ SET_ERROR_IF(width < 1 || height < 1, GL_INVALID_VALUE);
+ SET_ERROR_IF(state->isBoundTextureImmutableFormat(target), GL_INVALID_OPERATION);
+
+ state->setBoundTextureInternalFormat(target, internalformat);
+ state->setBoundTextureDims(target, 0, width, height, 1);
+ state->setBoundTextureImmutableFormat(target);
+ state->setBoundTextureSamples(target, samples);
+
+ ctx->m_glTexStorage2DMultisample_enc(ctx, target, samples, internalformat, width, height, fixedsamplelocations);
+}
+