OSDN Git Service

[WIP] ES 3.1 guestside changes
[android-x86/device-generic-goldfish-opengl.git] / system / GLESv2_enc / GL2Encoder.cpp
index 7d4f746..6dec27b 100755 (executable)
@@ -66,6 +66,7 @@ GL2Encoder::GL2Encoder(IOStream *stream, ChecksumCalculator *protocol)
     m_max_renderBufferSize = 0;
     m_max_textureSize = 0;
     m_max_3d_textureSize = 0;
+    m_max_vertexAttribStride = 0;
     m_compressedTextureFormats = NULL;
 
     m_ssbo_offset_align = 0;
@@ -261,13 +262,19 @@ GL2Encoder::GL2Encoder(IOStream *stream, ChecksumCalculator *protocol)
 
     OVERRIDE(glBindSampler);
 
-    OVERRIDE(glDeleteSync);
+    OVERRIDE_CUSTOM(glFenceSync);
+    OVERRIDE_CUSTOM(glClientWaitSync);
+    OVERRIDE_CUSTOM(glWaitSync);
+    OVERRIDE_CUSTOM(glDeleteSync);
+    OVERRIDE_CUSTOM(glIsSync);
+    OVERRIDE_CUSTOM(glGetSynciv);
 
     OVERRIDE(glGetIntegeri_v);
     OVERRIDE(glGetInteger64i_v);
 
     OVERRIDE(glGetShaderiv);
 
+    OVERRIDE(glActiveShaderProgram);
     OVERRIDE_CUSTOM(glCreateShaderProgramv);
     OVERRIDE(glProgramUniform1f);
     OVERRIDE(glProgramUniform1fv);
@@ -303,9 +310,16 @@ GL2Encoder::GL2Encoder(IOStream *stream, ChecksumCalculator *protocol)
     OVERRIDE(glProgramUniformMatrix4x2fv);
     OVERRIDE(glProgramUniformMatrix4x3fv);
 
+    OVERRIDE(glProgramParameteri);
     OVERRIDE(glUseProgramStages);
     OVERRIDE(glBindProgramPipeline);
 
+    OVERRIDE(glGetProgramResourceiv);
+    OVERRIDE(glGetProgramResourceIndex);
+    OVERRIDE(glGetProgramResourceLocation);
+    OVERRIDE(glGetProgramResourceName);
+    OVERRIDE(glGetProgramPipelineInfoLog);
+
     OVERRIDE(glVertexAttribFormat);
     OVERRIDE(glVertexAttribIFormat);
     OVERRIDE(glVertexBindingDivisor);
@@ -386,6 +400,7 @@ void GL2Encoder::s_glBindBuffer(void *self, GLenum target, GLuint id)
     GL2Encoder *ctx = (GL2Encoder *) self;
     assert(ctx->m_state != NULL);
     ctx->m_state->bindBuffer(target, id);
+    ctx->m_state->addBuffer(id);
     // TODO set error state if needed;
     ctx->m_glBindBuffer_enc(self, target, id);
 }
@@ -417,6 +432,15 @@ void GL2Encoder::s_glBufferSubData(void * self, GLenum target, GLintptr offset,
     ctx->m_glBufferSubData_enc(self, target, offset, size, data);
 }
 
+void GL2Encoder::s_glGenBuffers(void* self, GLsizei n, GLuint* buffers) {
+    GL2Encoder *ctx = (GL2Encoder *) self;
+    SET_ERROR_IF(n<0, GL_INVALID_VALUE);
+    ctx->m_glGenBuffers_enc(self, n, buffers);
+    for (int i = 0; i < n; i++) {
+        ctx->m_state->addBuffer(buffers[i]);
+    }
+}
+
 void GL2Encoder::s_glDeleteBuffers(void * self, GLsizei n, const GLuint * buffers)
 {
     GL2Encoder *ctx = (GL2Encoder *) self;
@@ -426,6 +450,7 @@ void GL2Encoder::s_glDeleteBuffers(void * self, GLsizei n, const GLuint * buffer
         // use it anymore after this :)
         ctx->m_shared->deleteBufferData(buffers[i]);
         ctx->m_state->unBindBuffer(buffers[i]);
+        ctx->m_state->removeBuffer(buffers[i]);
         ctx->m_glDeleteBuffers_enc(self,1,&buffers[i]);
     }
 }
@@ -526,6 +551,14 @@ void GL2Encoder::s_glGetIntegerv(void *self, GLenum param, GLint *ptr)
             ctx->m_state->setMaxVertexAttribs(*ptr);
         }
         break;
+    case GL_MAX_VERTEX_ATTRIB_STRIDE:
+        if (ctx->m_max_vertexAttribStride != 0) {
+            *ptr = ctx->m_max_vertexAttribStride;
+        } else {
+            ctx->m_glGetIntegerv_enc(self, param, ptr);
+            ctx->m_max_vertexAttribStride = *ptr;
+        }
+        break;
     case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
         if (ctx->m_max_cubeMapTextureSize != 0) {
             *ptr = ctx->m_max_cubeMapTextureSize;
@@ -577,6 +610,9 @@ void GL2Encoder::s_glGetIntegerv(void *self, GLenum param, GLint *ptr)
     // Desktop OpenGL can allow a mindboggling # samples per pixel (such as 64).
     // Limit to 4 (spec minimum) to keep dEQP tests from timing out.
     case GL_MAX_SAMPLES:
+    case GL_MAX_COLOR_TEXTURE_SAMPLES:
+    case GL_MAX_INTEGER_SAMPLES:
+    case GL_MAX_DEPTH_TEXTURE_SAMPLES:
         *ptr = 4;
         break;
     default:
@@ -913,10 +949,10 @@ void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClient
                 // The following expression actually means bufLen = stride*count;
                 // But the last element doesn't have to fill up the whole stride.
                 // So it becomes the current form.
-                unsigned int bufLen = effectiveStride * (count - 1) + state.elementSize;
+                unsigned int bufLen = effectiveStride * (count ? (count - 1) : 0) + state.elementSize;
                 if (divisor && primcount) {
                     int actual_count = std::max(1, (int)((primcount + divisor - 1) / divisor));
-                    bufLen = effectiveStride * (actual_count - 1) + state.elementSize;
+                    bufLen = effectiveStride * (actual_count ? (actual_count - 1) : 0) + state.elementSize;
                 }
                 if (buf && firstIndex >= 0 && firstIndex + bufLen <= buf->m_size) {
                     if (hasClientArrays) {
@@ -929,10 +965,12 @@ void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClient
                     }
                 } else {
                     ALOGE("a vertex attribute index out of boundary is detected. Skipping corresponding vertex attribute. buf=%p", 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, buf->m_size, buf != NULL, firstIndex, firstIndex + bufLen);
-                    // m_glDisableVertexAttribArray_enc(this, i);
+                    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, buf->m_size, buf != NULL, firstIndex, firstIndex + bufLen);
+                    }
+                    m_glDisableVertexAttribArray_enc(this, i);
                 }
             }
         } else {
@@ -1000,7 +1038,7 @@ void GL2Encoder::s_glDrawArrays(void *self, GLenum mode, GLint first, GLsizei co
         ctx->sendVertexAttributes(0, count, false);
         ctx->m_glDrawArrays_enc(ctx, mode, first, count);
     }
-    ctx->m_stream->flush();
+    // ctx->m_stream->flush();
 }
 
 
@@ -1082,7 +1120,7 @@ void GL2Encoder::s_glDrawElements(void *self, GLenum mode, GLsizei count, GLenum
             ctx->sendVertexAttributes(minIndex, maxIndex - minIndex + 1, true);
             ctx->glDrawElementsData(ctx, mode, count, type, adjustedIndices,
                                     count * glSizeof(type));
-            ctx->m_stream->flush();
+            // ctx->m_stream->flush();
             // XXX - OPTIMIZATION (see the other else branch) should be implemented
             if(!has_indirect_arrays) {
                 //ALOGD("unoptimized drawelements !!!\n");
@@ -1243,6 +1281,7 @@ void GL2Encoder::s_glFinish(void *self)
 
 void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
 {
+    ALOGD("%s: link %u\n", __FUNCTION__, program);
     GL2Encoder *ctx = (GL2Encoder *)self;
     bool isProgram = ctx->m_shared->isProgram(program);
     SET_ERROR_IF(!isProgram && !ctx->m_shared->isShader(program), GL_INVALID_VALUE);
@@ -1252,8 +1291,9 @@ void GL2Encoder::s_glLinkProgram(void * self, GLuint program)
 
     GLint linkStatus = 0;
     ctx->glGetProgramiv(self,program,GL_LINK_STATUS,&linkStatus);
-    if (!linkStatus)
+    if (!linkStatus) {
         return;
+    }
 
     //get number of active uniforms in the program
     GLint numUniforms=0;
@@ -1320,6 +1360,7 @@ GLuint GL2Encoder::s_glCreateProgram(void * self)
 
 GLuint GL2Encoder::s_glCreateShader(void *self, GLenum shaderType)
 {
+    ALOGD("%s: create shader of type 0x%x\n", __FUNCTION__, shaderType);
     GL2Encoder *ctx = (GL2Encoder*)self;
     RET_AND_SET_ERROR_IF(!GLESv2Validation::shaderType(ctx, shaderType), GL_INVALID_ENUM, 0);
     GLuint shader = ctx->m_glCreateShader_enc(self, shaderType);
@@ -1387,6 +1428,7 @@ void GL2Encoder::s_glDeleteShader(void *self, GLenum shader)
 
 void GL2Encoder::s_glAttachShader(void *self, GLuint program, GLuint shader)
 {
+    ALOGD("%s: attach shader %u to %u\n", __FUNCTION__, shader, program);
     GL2Encoder *ctx = (GL2Encoder*)self;
     ctx->m_glAttachShader_enc(self, program, shader);
     ctx->m_shared->attachShader(program, shader);
@@ -1495,6 +1537,7 @@ void GL2Encoder::s_glUseProgram(void *self, GLuint program)
 
     ctx->m_glUseProgram_enc(self, program);
     ctx->m_state->setCurrentProgram(program);
+    ctx->m_state->setCurrentShaderProgram(program);
 
     ctx->updateHostTexture2DBindingsFromProgramData(program);
 }
@@ -1502,14 +1545,14 @@ void GL2Encoder::s_glUseProgram(void *self, GLuint program)
 void GL2Encoder::s_glUniform1f(void *self , GLint location, GLfloat x)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform1f_enc(self, hostLoc, x);
 }
 
 void GL2Encoder::s_glUniform1fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform1fv_enc(self, hostLoc, count, v);
 }
 
@@ -1519,11 +1562,11 @@ void GL2Encoder::s_glUniform1i(void *self , GLint location, GLint x)
     GLClientState* state = ctx->m_state;
     GLSharedGroupPtr shared = ctx->m_shared;
 
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform1i_enc(self, hostLoc, x);
 
     GLenum target;
-    if (shared->setSamplerUniform(state->currentProgram(), location, x, &target)) {
+    if (shared->setSamplerUniform(state->currentShaderProgram(), location, x, &target)) {
         GLenum origActiveTexture = state->getActiveTextureUnit();
         if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + x, target)) {
             ctx->m_glActiveTexture_enc(self, origActiveTexture);
@@ -1535,112 +1578,112 @@ void GL2Encoder::s_glUniform1i(void *self , GLint location, GLint x)
 void GL2Encoder::s_glUniform1iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform1iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform2f(void *self , GLint location, GLfloat x, GLfloat y)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform2f_enc(self, hostLoc, x, y);
 }
 
 void GL2Encoder::s_glUniform2fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform2fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform2i(void *self , GLint location, GLint x, GLint y)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform2i_enc(self, hostLoc, x, y);
 }
 
 void GL2Encoder::s_glUniform2iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform2iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform3f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform3f_enc(self, hostLoc, x, y, z);
 }
 
 void GL2Encoder::s_glUniform3fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform3fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform3i(void *self , GLint location, GLint x, GLint y, GLint z)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform3i_enc(self, hostLoc, x, y, z);
 }
 
 void GL2Encoder::s_glUniform3iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform3iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform4f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform4f_enc(self, hostLoc, x, y, z, w);
 }
 
 void GL2Encoder::s_glUniform4fv(void *self , GLint location, GLsizei count, const GLfloat* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform4fv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniform4i(void *self , GLint location, GLint x, GLint y, GLint z, GLint w)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform4i_enc(self, hostLoc, x, y, z, w);
 }
 
 void GL2Encoder::s_glUniform4iv(void *self , GLint location, GLsizei count, const GLint* v)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform4iv_enc(self, hostLoc, count, v);
 }
 
 void GL2Encoder::s_glUniformMatrix2fv(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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniformMatrix2fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix3fv(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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniformMatrix3fv_enc(self, hostLoc, count, transpose, value);
 }
 
 void GL2Encoder::s_glUniformMatrix4fv(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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniformMatrix4fv_enc(self, hostLoc, count, transpose, value);
 }
 
@@ -2336,6 +2379,7 @@ GLenum GL2Encoder::s_glCheckFramebufferStatus(void* self, GLenum target) {
         // double check with underlying opengl to avoid craziness.
         GLenum host_checkstatus = ctx->m_glCheckFramebufferStatus_enc(self, target);
         state->setCheckFramebufferStatus(target, host_checkstatus);
+        if (host_checkstatus == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) return GL_FRAMEBUFFER_COMPLETE;
         return host_checkstatus;
     }
 }
@@ -2435,6 +2479,15 @@ GLboolean GL2Encoder::s_glUnmapBuffer(void* self, GLenum target) {
     RET_AND_SET_ERROR_IF(!buf, GL_INVALID_VALUE, GL_FALSE);
     RET_AND_SET_ERROR_IF(!buf->m_mapped, GL_INVALID_OPERATION, GL_FALSE);
 
+    if (buf->m_mappedAccess & GL_MAP_WRITE_BIT) {
+        // invalide index range cache here
+        if (buf->m_mappedAccess & GL_MAP_INVALIDATE_BUFFER_BIT) {
+            buf->m_indexRangeCache.invalidateRange(0, buf->m_size);
+        } else {
+            buf->m_indexRangeCache.invalidateRange(buf->m_mappedOffset, buf->m_mappedLength);
+        }
+    }
+
     GLboolean host_res = GL_TRUE;
 
     ctx->glUnmapBufferAEMU(
@@ -2472,6 +2525,9 @@ void GL2Encoder::s_glFlushMappedBufferRange(void* self, GLenum target, GLintptr
     SET_ERROR_IF(offset + length > buf->m_mappedLength, GL_INVALID_VALUE);
 
     GLintptr totalOffset = buf->m_mappedOffset + offset;
+
+    buf->m_indexRangeCache.invalidateRange(totalOffset, length);
+
     ctx->glFlushMappedBufferRangeAEMU(
             ctx, target,
             totalOffset,
@@ -2606,6 +2662,7 @@ void GL2Encoder::s_glBindBufferRange(void* self, GLenum target, GLuint index, GL
                  GL_INVALID_VALUE);
 
     state->bindBuffer(target, buffer);
+    ctx->m_state->addBuffer(buffer);
     state->bindIndexedBuffer(target, index, buffer, offset, size, 0, 0);
     ctx->m_glBindBufferRange_enc(self, target, index, buffer, offset, size);
 }
@@ -2629,6 +2686,7 @@ void GL2Encoder::s_glBindBufferBase(void* self, GLenum target, GLuint index, GLu
                  GL_INVALID_VALUE);
 
     state->bindBuffer(target, buffer);
+    ctx->m_state->addBuffer(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);
@@ -2676,16 +2734,24 @@ void GL2Encoder::s_glGetBufferParameteriv(void* self, GLenum target, GLenum pnam
 
     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,
+        target != GL_ARRAY_BUFFER &&
+        target != GL_ELEMENT_ARRAY_BUFFER &&
+        target != GL_COPY_READ_BUFFER &&
+        target != GL_COPY_WRITE_BUFFER &&
+        target != GL_PIXEL_PACK_BUFFER &&
+        target != GL_PIXEL_UNPACK_BUFFER &&
+        target != GL_TRANSFORM_FEEDBACK_BUFFER &&
+        target != GL_UNIFORM_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);
+    SET_ERROR_IF(pname != GL_BUFFER_ACCESS_FLAGS &&
+                 pname != GL_BUFFER_MAPPED &&
+                 pname != GL_BUFFER_SIZE &&
+                 pname != GL_BUFFER_USAGE &&
+                 pname != GL_BUFFER_MAP_LENGTH &&
+                 pname != GL_BUFFER_MAP_OFFSET,
+                 GL_INVALID_ENUM);
 
     if (!params) return;
 
@@ -2704,6 +2770,12 @@ void GL2Encoder::s_glGetBufferParameteriv(void* self, GLenum target, GLenum pnam
         case GL_BUFFER_USAGE:
             *params = buf ? buf->m_usage : GL_STATIC_DRAW;
             break;
+        case GL_BUFFER_MAP_LENGTH:
+            *params = buf ? buf->m_mappedLength : 0;
+            break;
+        case GL_BUFFER_MAP_OFFSET:
+            *params = buf ? buf->m_mappedOffset : 0;
+            break;
         default:
             break;
     }
@@ -2714,32 +2786,48 @@ void GL2Encoder::s_glGetBufferParameteri64v(void* self, GLenum target, GLenum pn
 
     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,
+        target != GL_ARRAY_BUFFER &&
+        target != GL_ELEMENT_ARRAY_BUFFER &&
+        target != GL_COPY_READ_BUFFER &&
+        target != GL_COPY_WRITE_BUFFER &&
+        target != GL_PIXEL_PACK_BUFFER &&
+        target != GL_PIXEL_UNPACK_BUFFER &&
+        target != GL_TRANSFORM_FEEDBACK_BUFFER &&
+        target != GL_UNIFORM_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);
+    SET_ERROR_IF(pname != GL_BUFFER_ACCESS_FLAGS &&
+                 pname != GL_BUFFER_MAPPED &&
+                 pname != GL_BUFFER_SIZE &&
+                 pname != GL_BUFFER_USAGE &&
+                 pname != GL_BUFFER_MAP_LENGTH &&
+                 pname != GL_BUFFER_MAP_OFFSET,
+                 GL_INVALID_ENUM);
 
     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;
         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;
     }
@@ -2827,11 +2915,11 @@ void GL2Encoder::s_glUniform1ui(void* self, GLint location, GLuint v0) {
     GLClientState* state = ctx->m_state;
     GLSharedGroupPtr shared = ctx->m_shared;
 
-    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentProgram(),location);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniform1ui_enc(self, hostLoc, v0);
 
     GLenum target;
-    if (shared->setSamplerUniform(state->currentProgram(), location, v0, &target)) {
+    if (shared->setSamplerUniform(state->currentShaderProgram(), location, v0, &target)) {
         GLenum origActiveTexture = state->getActiveTextureUnit();
         if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + v0, target)) {
             ctx->m_glActiveTexture_enc(self, origActiveTexture);
@@ -2842,79 +2930,79 @@ void GL2Encoder::s_glUniform1ui(void* self, GLint location, GLuint v0) {
 
 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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),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);
+    GLint hostLoc = ctx->m_shared->locationWARAppToHost(ctx->m_state->currentShaderProgram(),location);
     ctx->m_glUniformMatrix4x3fv_enc(self, hostLoc, count, transpose, value);
 }
 
@@ -3866,7 +3954,8 @@ void GL2Encoder::s_glGetInternalformativ(void* self, GLenum target, GLenum inter
     SET_ERROR_IF(pname != GL_NUM_SAMPLE_COUNTS &&
                  pname != GL_SAMPLES,
                  GL_INVALID_ENUM);
-    SET_ERROR_IF(target != GL_RENDERBUFFER, GL_INVALID_ENUM);
+    ALOGD("%s: maj min %d %d", __FUNCTION__, ctx->majorVersion(), ctx->minorVersion());
+    SET_ERROR_IF(!GLESv2Validation::internalFormatTarget(ctx, target), GL_INVALID_ENUM);
     SET_ERROR_IF(!GLESv2Validation::unsizedFormat(internalformat) &&
                  !GLESv2Validation::colorRenderableFormat(internalformat) &&
                  !GLESv2Validation::depthRenderableFormat(internalformat) &&
@@ -3925,22 +4014,52 @@ void GL2Encoder::s_glBindSampler(void* self, GLuint unit, GLuint sampler) {
     ctx->m_glBindSampler_enc(ctx, unit, sampler);
 }
 
+GLsync GL2Encoder::s_glFenceSync(void* self, GLenum condition, GLbitfield flags) {
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    uint64_t syncHandle = ctx->glFenceSyncAEMU(ctx, condition, flags);
+    return (GLsync)(uintptr_t)syncHandle;
+}
+
+GLenum GL2Encoder::s_glClientWaitSync(void* self, GLsync wait_on, GLbitfield flags, GLuint64 timeout) {
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    return ctx->glClientWaitSyncAEMU(ctx, (uint64_t)(uintptr_t)wait_on, flags, timeout);
+}
+
+void GL2Encoder::s_glWaitSync(void* self, GLsync wait_on, GLbitfield flags, GLuint64 timeout) {
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    ctx->glWaitSyncAEMU(ctx, (uint64_t)(uintptr_t)wait_on, flags, timeout);
+}
+
 void GL2Encoder::s_glDeleteSync(void* self, GLsync sync) {
     GL2Encoder *ctx = (GL2Encoder *)self;
 
     if (!sync) return;
 
-    ctx->m_glDeleteSync_enc(ctx, sync);
+    ctx->glDeleteSyncAEMU(ctx, (uint64_t)(uintptr_t)sync);
+}
+
+GLboolean GL2Encoder::s_glIsSync(void* self, GLsync sync) {
+    GL2Encoder *ctx = (GL2Encoder *)self;
+    return ctx->glIsSyncAEMU(ctx, (uint64_t)(uintptr_t)sync);
+}
+
+void GL2Encoder::s_glGetSynciv(void* self, GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values) {
+    GL2Encoder *ctx = (GL2Encoder *)self;
+
+    SET_ERROR_IF(bufSize < 0, GL_INVALID_VALUE);
+
+    return ctx->glGetSyncivAEMU(ctx, (uint64_t)(uintptr_t)sync, pname, bufSize, length, values);
 }
 
 #define LIMIT_CASE(target, lim) \
     case target: \
         ctx->glGetIntegerv(ctx, lim, &limit); \
-        SET_ERROR_IF(index >= limit, GL_INVALID_VALUE); \
+        SET_ERROR_IF(index < 0 || index >= limit, GL_INVALID_VALUE); \
         break; \
 
 void GL2Encoder::s_glGetIntegeri_v(void* self, GLenum target, GLuint index, GLint* params) {
     GL2Encoder *ctx = (GL2Encoder *)self;
+    GLClientState* state = ctx->m_state;
 
     GLint limit;
 
@@ -3953,11 +4072,43 @@ void GL2Encoder::s_glGetIntegeri_v(void* self, GLenum target, GLuint index, GLin
         break;
     }
 
+    const GLClientState::VertexAttribBindingVector& currBindings =
+        state->currentVertexBufferBindings();
+
+    switch (target) {
+    case GL_VERTEX_BINDING_DIVISOR:
+    case GL_VERTEX_BINDING_OFFSET:
+    case GL_VERTEX_BINDING_STRIDE:
+    case GL_VERTEX_BINDING_BUFFER:
+        SET_ERROR_IF(index < 0 || index > currBindings.size(), GL_INVALID_VALUE);
+        break;
+    default:
+        break;
+    }
+
+    switch (target) {
+    case GL_VERTEX_BINDING_DIVISOR:
+        *params = currBindings[index].divisor;
+        return;
+    case GL_VERTEX_BINDING_OFFSET:
+        *params = currBindings[index].offset;
+        return;
+    case GL_VERTEX_BINDING_STRIDE:
+        *params = currBindings[index].effectiveStride;
+        return;
+    case GL_VERTEX_BINDING_BUFFER:
+        *params = currBindings[index].buffer;
+        return;
+    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;
+    GLClientState* state = ctx->m_state;
 
     GLint limit;
 
@@ -3970,6 +4121,37 @@ void GL2Encoder::s_glGetInteger64i_v(void* self, GLenum target, GLuint index, GL
         break;
     }
 
+    const GLClientState::VertexAttribBindingVector& currBindings =
+        state->currentVertexBufferBindings();
+
+    switch (target) {
+    case GL_VERTEX_BINDING_DIVISOR:
+    case GL_VERTEX_BINDING_OFFSET:
+    case GL_VERTEX_BINDING_STRIDE:
+    case GL_VERTEX_BINDING_BUFFER:
+        SET_ERROR_IF(index < 0 || index > currBindings.size(), GL_INVALID_VALUE);
+        break;
+    default:
+        break;
+    }
+
+    switch (target) {
+    case GL_VERTEX_BINDING_DIVISOR:
+        *params = currBindings[index].divisor;
+        return;
+    case GL_VERTEX_BINDING_OFFSET:
+        *params = currBindings[index].offset;
+        return;
+    case GL_VERTEX_BINDING_STRIDE:
+        *params = currBindings[index].effectiveStride;
+        return;
+    case GL_VERTEX_BINDING_BUFFER:
+        *params = currBindings[index].buffer;
+        return;
+    default:
+        break;
+    }
+
     ctx->m_glGetInteger64i_v_enc(self, target, index, params);
 }
 
@@ -3990,14 +4172,33 @@ void GL2Encoder::s_glGetShaderiv(void* self, GLuint shader, GLenum pname, GLint*
     }
 }
 
+void GL2Encoder::s_glActiveShaderProgram(void* self, GLuint pipeline, 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_glActiveShaderProgram_enc(ctx, pipeline, program);
+    if (!state->currentProgram()) {
+        state->setCurrentShaderProgram(program);
+    }
+}
+
 GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei count, const char** strings) {
 
+    ALOGD("%s: entry firststr %s", __FUNCTION__, strings[0]);
+
     GLint* length = NULL;
     GL2Encoder* ctx = (GL2Encoder*)self;
 
     int len = glUtilsCalcShaderSourceLen((char**)strings, length, count);
+    ALOGD("%s: len %d\n", __FUNCTION__, len);
     char *str = new char[len + 1];
     glUtilsPackStrings(str, (char**)strings, (GLint*)length, count);
+    ALOGD("%s: packed %s", __FUNCTION__, str);
    
     // Do GLSharedGroup and location WorkARound-specific initialization 
     // Phase 1: create a ShaderData and initialize with replaceSamplerExternalWith2D()
@@ -4006,6 +4207,7 @@ GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei cou
     ShaderData* sData = spData->shaderData;
 
     if (!replaceSamplerExternalWith2D(str, sData)) {
+        ALOGD("%s: failed to do stuf\n", __FUNCTION__);
         delete [] str;
         ctx->setError(GL_OUT_OF_MEMORY);
         ctx->m_shared->deleteShaderProgramDataById(spDataId);
@@ -4013,12 +4215,14 @@ GLuint GL2Encoder::s_glCreateShaderProgramv(void* self, GLenum type, GLsizei cou
     }
 
     GLuint res = ctx->glCreateShaderProgramvAEMU(ctx, type, count, str, len + 1);
+        ALOGD("%s: return from glcreateshaderprogramv. res %u\n", __FUNCTION__, res);
     delete [] str;
 
     // Phase 2: do glLinkProgram-related initialization for locationWorkARound
     GLint linkStatus = 0;
     ctx->glGetProgramiv(self, res, GL_LINK_STATUS ,&linkStatus);
     if (!linkStatus) {
+        ALOGD("%s: no link status :(\n", __FUNCTION__);
         ctx->m_shared->deleteShaderProgramDataById(spDataId);
         return -1;
     }
@@ -4065,7 +4269,7 @@ void GL2Encoder::s_glProgramUniform1i(void* self, GLuint program, GLint location
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
     GLint hostLoc = ctx->m_shared->locationWARAppToHost(program, location);
-    ctx->m_glProgramUniform1ui_enc(self, program, hostLoc, v0);
+    ctx->m_glProgramUniform1i_enc(self, program, hostLoc, v0);
 
     GLClientState* state = ctx->m_state;
     GLSharedGroupPtr shared = ctx->m_shared;
@@ -4302,6 +4506,11 @@ void GL2Encoder::s_glProgramUniformMatrix4x3fv(void* self, GLuint program, GLint
     ctx->m_glProgramUniformMatrix4x3fv_enc(self, program, hostLoc, count, transpose, value);
 }
 
+void GL2Encoder::s_glProgramParameteri(void* self, GLuint program, GLenum pname, GLint value) {
+    GL2Encoder* ctx = (GL2Encoder*)self;
+    ctx->m_glProgramParameteri_enc(self, program, pname, value);
+}
+
 void GL2Encoder::s_glUseProgramStages(void *self, GLuint pipeline, GLbitfield stages, GLuint program)
 {
     GL2Encoder *ctx = (GL2Encoder*)self;
@@ -4344,10 +4553,89 @@ void GL2Encoder::s_glBindProgramPipeline(void* self, GLuint pipeline)
     }
 }
 
+void GL2Encoder::s_glGetProgramResourceiv(void* self, GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum * props, GLsizei bufSize, GLsizei * length, GLint * params) {
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    SET_ERROR_IF(bufSize < 0, GL_INVALID_VALUE);
+    if (bufSize == 0) {
+        if (length) *length = 0;
+        return;
+    }
+
+    // Avoid modifying |name| if |*length| < bufSize.
+    GLint* intermediate = new GLint[bufSize];
+    GLsizei* myLength = length ? length : new GLsizei;
+    bool needFreeLength = length == NULL;
+
+    ctx->m_glGetProgramResourceiv_enc(self, program, programInterface, index, propCount, props, bufSize, myLength, intermediate);
+    GLsizei writtenInts = *myLength;
+    memcpy(params, intermediate, writtenInts * sizeof(GLint));
+
+    delete [] intermediate;
+    if (needFreeLength)
+        delete myLength;
+}
+
+GLuint GL2Encoder::s_glGetProgramResourceIndex(void* self, GLuint program, GLenum programInterface, const char* name) {
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    return ctx->m_glGetProgramResourceIndex_enc(self, program, programInterface, name);
+}
+
+GLint GL2Encoder::s_glGetProgramResourceLocation(void* self, GLuint program, GLenum programInterface, const char* name) {
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    return ctx->m_glGetProgramResourceLocation_enc(self, program, programInterface, name);
+}
+
+void GL2Encoder::s_glGetProgramResourceName(void* self, GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei* length, char* name) {
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    SET_ERROR_IF(bufSize < 0, GL_INVALID_VALUE);
+    if (bufSize == 0) {
+        if (length) *length = 0;
+        return;
+    }
+
+    // Avoid modifying |name| if |*length| < bufSize.
+    char* intermediate = new char[bufSize];
+    GLsizei* myLength = length ? length : new GLsizei;
+    bool needFreeLength = length == NULL;
+
+    ctx->m_glGetProgramResourceName_enc(self, program, programInterface, index, bufSize, myLength, intermediate);
+    GLsizei writtenStrLen = *myLength;
+    memcpy(name, intermediate, writtenStrLen + 1);
+
+    delete [] intermediate;
+    if (needFreeLength)
+        delete myLength;
+}
+
+void GL2Encoder::s_glGetProgramPipelineInfoLog(void* self, GLuint pipeline, GLsizei bufSize, GLsizei* length, GLchar* infoLog) {
+    GL2Encoder *ctx = (GL2Encoder*)self;
+    SET_ERROR_IF(bufSize < 0, GL_INVALID_VALUE);
+    if (bufSize == 0) {
+        if (length) *length = 0;
+        return;
+    }
+
+    // Avoid modifying |infoLog| if |*length| < bufSize.
+    GLchar* intermediate = new GLchar[bufSize];
+    GLsizei* myLength = length ? length : new GLsizei;
+    bool needFreeLength = length == NULL;
+
+    ctx->m_glGetProgramPipelineInfoLog_enc(self, pipeline, bufSize, myLength, intermediate);
+    GLsizei writtenStrLen = *myLength;
+    memcpy(infoLog, intermediate, writtenStrLen + 1);
+
+    delete [] intermediate;
+    if (needFreeLength)
+        delete myLength;
+}
+
 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;
 
+    SET_ERROR_IF(!isValidVertexAttribIndex(self, attribindex), GL_INVALID_VALUE);
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+
     state->setVertexAttribFormat(attribindex, size, type, normalized, relativeoffset, false);
     ctx->m_glVertexAttribFormat_enc(ctx, attribindex, size, type, normalized, relativeoffset);
 }
@@ -4356,15 +4644,19 @@ void GL2Encoder::s_glVertexAttribIFormat(void* self, GLuint attribindex, GLint s
     GL2Encoder *ctx = (GL2Encoder*)self;
     GLClientState* state = ctx->m_state;
 
+    SET_ERROR_IF(!isValidVertexAttribIndex(self, attribindex), GL_INVALID_VALUE);
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+
     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;
 
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+
     state->setVertexBindingDivisor(bindingindex, divisor);
     ctx->m_glVertexBindingDivisor_enc(ctx, bindingindex, divisor);
 }
@@ -4372,6 +4664,8 @@ void GL2Encoder::s_glVertexBindingDivisor(void* self, GLuint bindingindex, GLuin
 void GL2Encoder::s_glVertexAttribBinding(void* self, GLuint attribindex, GLuint bindingindex) {
     GL2Encoder *ctx = (GL2Encoder*)self;
     GLClientState* state = ctx->m_state;
+    SET_ERROR_IF(!isValidVertexAttribIndex(self, attribindex), GL_INVALID_VALUE);
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
 
     state->setVertexAttribBinding(attribindex, bindingindex);
     ctx->m_glVertexAttribBinding_enc(ctx, attribindex, bindingindex);
@@ -4381,17 +4675,39 @@ void GL2Encoder::s_glBindVertexBuffer(void* self, GLuint bindingindex, GLuint bu
     GL2Encoder *ctx = (GL2Encoder*)self;
     GLClientState* state = ctx->m_state;
 
+    SET_ERROR_IF(offset < 0, GL_INVALID_VALUE);
+
+    GLint maxStride;
+    ctx->glGetIntegerv(ctx, GL_MAX_VERTEX_ATTRIB_STRIDE, &maxStride);
+    SET_ERROR_IF(stride < 0 || stride > maxStride, GL_INVALID_VALUE);
+
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+
     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;
+    GLClientState* state = ctx->m_state;
+
+    bool hasClientArrays = false;
+    ctx->getVBOUsage(&hasClientArrays, NULL);
+
+    SET_ERROR_IF(hasClientArrays, GL_INVALID_OPERATION);
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+    SET_ERROR_IF(!ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER), GL_INVALID_OPERATION);
 
+    GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWARRAYS);
     if (ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER)) {
+        // BufferData* buf = ctx->getBufferData(target);
+        // if (buf) {
+        //     SET_ERROR_IF((GLuint)(uintptr_t)indirect + indirectStructSize > buf->m_size, GL_INVALID_VALUE);
+        // }
         ctx->glDrawArraysIndirectOffsetAEMU(ctx, mode, (uintptr_t)indirect);
     } else {
-        GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWARRAYS);
+        // Client command structs are technically allowed in desktop OpenGL, but not in ES.
+        // This is purely for debug/dev purposes.
         ctx->glDrawArraysIndirectDataAEMU(ctx, mode, indirect, indirectStructSize);
     }
 }
@@ -4399,11 +4715,27 @@ void GL2Encoder::s_glDrawArraysIndirect(void* self, GLenum mode, const void* ind
 void GL2Encoder::s_glDrawElementsIndirect(void* self, GLenum mode, GLenum type, const void* indirect) {
     GL2Encoder *ctx = (GL2Encoder*)self;
 
+    GLClientState* state = ctx->m_state;
+
+    bool hasClientArrays = false;
+    ctx->getVBOUsage(&hasClientArrays, NULL);
+
+    SET_ERROR_IF(hasClientArrays, GL_INVALID_OPERATION);
+    SET_ERROR_IF(!state->currentVertexArrayObject(), GL_INVALID_OPERATION);
+    SET_ERROR_IF(!ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER), GL_INVALID_OPERATION);
+
     SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION);
+
+    GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWELEMENTS);
     if (ctx->boundBuffer(GL_DRAW_INDIRECT_BUFFER)) {
+        // BufferData* buf = ctx->getBufferData(target);
+        // if (buf) {
+        //     SET_ERROR_IF((GLuint)(uintptr_t)indirect + indirectStructSize > buf->m_size, GL_INVALID_VALUE);
+        // }
         ctx->glDrawElementsIndirectOffsetAEMU(ctx, mode, type, (uintptr_t)indirect);
     } else {
-        GLuint indirectStructSize = glUtilsIndirectStructSize(INDIRECT_COMMAND_DRAWELEMENTS);
+        // Client command structs are technically allowed in desktop OpenGL, but not in ES.
+        // This is purely for debug/dev purposes.
         ctx->glDrawElementsIndirectDataAEMU(ctx, mode, type, indirect, indirectStructSize);
     }
 
@@ -4418,6 +4750,9 @@ void GL2Encoder::s_glTexStorage2DMultisample(void* self, GLenum target, GLsizei
     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);
+    GLint max_samples;
+    ctx->s_glGetInternalformativ(ctx, target, internalformat, GL_SAMPLES, 1, &max_samples);
+    SET_ERROR_IF(samples > max_samples, GL_INVALID_OPERATION);
 
     state->setBoundTextureInternalFormat(target, internalformat);
     state->setBoundTextureDims(target, 0, width, height, 1);