| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "GL2Encoder.h" |
| #include "GLESv2Validation.h" |
| #include "GLESTextureUtils.h" |
| |
| #include <string> |
| #include <map> |
| |
| #include <assert.h> |
| #include <ctype.h> |
| |
| #include <GLES2/gl2.h> |
| #include <GLES2/gl2ext.h> |
| #include <GLES2/gl2platform.h> |
| |
| #include <GLES3/gl3.h> |
| #include <GLES3/gl31.h> |
| |
| #ifndef MIN |
| #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
| #endif |
| |
| static GLubyte *gVendorString= (GLubyte *) "Android"; |
| static GLubyte *gRendererString= (GLubyte *) "Android HW-GLES 3.0"; |
| static GLubyte *gVersionString= (GLubyte *) "OpenGL ES 3.0"; |
| static GLubyte *gExtensionsString= (GLubyte *) "GL_OES_EGL_image_external "; |
| |
| #define SET_ERROR_IF(condition, err) if((condition)) { \ |
| ALOGE("%s:%s:%d GL error 0x%x condition [%s]\n", __FILE__, __FUNCTION__, __LINE__, err, #condition); \ |
| ctx->setError(err); \ |
| return; \ |
| } |
| |
| #define SET_ERROR_WITH_MESSAGE_IF(condition, err, generator, genargs) if ((condition)) { \ |
| std::string msg = generator genargs; \ |
| ALOGE("%s:%s:%d GL error 0x%x\n" \ |
| "Info: %s\n", __FILE__, __FUNCTION__, __LINE__, err, msg.c_str()); \ |
| ctx->setError(err); \ |
| return; \ |
| } \ |
| |
| #define RET_AND_SET_ERROR_IF(condition, err, ret) if((condition)) { \ |
| ALOGE("%s:%s:%d GL error 0x%x\n", __FILE__, __FUNCTION__, __LINE__, err); \ |
| ctx->setError(err); \ |
| return ret; \ |
| } \ |
| |
| #define RET_AND_SET_ERROR_WITH_MESSAGE_IF(condition, err, ret, generator, genargs) if((condition)) { \ |
| std::string msg = generator genargs; \ |
| ALOGE("%s:%s:%d GL error 0x%x\n" \ |
| "Info: %s\n", __FILE__, __FUNCTION__, __LINE__, err, msg.c_str()); \ |
| ctx->setError(err); \ |
| return ret; \ |
| } \ |
| |
| GL2Encoder::GL2Encoder(IOStream *stream, ChecksumCalculator *protocol) |
| : gl2_encoder_context_t(stream, protocol) |
| { |
| m_currMajorVersion = 2; |
| m_currMinorVersion = 0; |
| m_hasAsyncUnmapBuffer = false; |
| m_hasSyncBufferData = false; |
| m_initialized = false; |
| m_noHostError = false; |
| m_state = NULL; |
| m_error = GL_NO_ERROR; |
| |
| m_num_compressedTextureFormats = 0; |
| m_max_combinedTextureImageUnits = 0; |
| m_max_vertexTextureImageUnits = 0; |
| m_max_array_texture_layers = 0; |
| m_max_textureImageUnits = 0; |
| m_max_cubeMapTextureSize = 0; |
| m_max_renderBufferSize = 0; |
| m_max_textureSize = 0; |
| m_max_3d_textureSize = 0; |
| m_max_vertexAttribStride = 0; |
| |
| m_max_transformFeedbackSeparateAttribs = 0; |
| m_max_uniformBufferBindings = 0; |
| m_max_colorAttachments = 0; |
| m_max_drawBuffers = 0; |
| |
| m_max_atomicCounterBufferBindings = 0; |
| m_max_shaderStorageBufferBindings = 0; |
| m_max_vertexAttribBindings = 0; |
| |
| m_textureBufferOffsetAlign = 0; |
| |
| m_compressedTextureFormats = NULL; |
| |
| m_ssbo_offset_align = 0; |
| m_ubo_offset_align = 0; |
| |
| m_drawCallFlushInterval = 800; |
| m_drawCallFlushCount = 0; |
| m_primitiveRestartEnabled = false; |
| m_primitiveRestartIndex = 0; |
| |
| // overrides |
| #define OVERRIDE(name) m_##name##_enc = this-> name ; this-> name = &s_##name |
| #define OVERRIDE_CUSTOM(name) this-> name = &s_##name |
| #define OVERRIDEWITH(name, target) do { \ |
| m_##target##_enc = this-> target; \ |
| this-> target = &s_##name; \ |
| } while(0) |
| #define OVERRIDEOES(name) OVERRIDEWITH(name, name##OES) |
| |
| OVERRIDE(glFlush); |
| OVERRIDE(glPixelStorei); |
| OVERRIDE(glGetString); |
| OVERRIDE(glBindBuffer); |
| OVERRIDE(glBufferData); |
| OVERRIDE(glBufferSubData); |
| OVERRIDE(glDeleteBuffers); |
| OVERRIDE(glDrawArrays); |
| OVERRIDE(glDrawElements); |
| OVERRIDE(glDrawArraysNullAEMU); |
| OVERRIDE(glDrawElementsNullAEMU); |
| OVERRIDE(glGetIntegerv); |
| OVERRIDE(glGetFloatv); |
| OVERRIDE(glGetBooleanv); |
| OVERRIDE(glVertexAttribPointer); |
| OVERRIDE(glEnableVertexAttribArray); |
| OVERRIDE(glDisableVertexAttribArray); |
| OVERRIDE(glGetVertexAttribiv); |
| OVERRIDE(glGetVertexAttribfv); |
| OVERRIDE(glGetVertexAttribPointerv); |
| |
| this->glShaderBinary = &s_glShaderBinary; |
| this->glShaderSource = &s_glShaderSource; |
| this->glFinish = &s_glFinish; |
| |
| OVERRIDE(glGetError); |
| OVERRIDE(glLinkProgram); |
| OVERRIDE(glDeleteProgram); |
| OVERRIDE(glGetUniformiv); |
| OVERRIDE(glGetUniformfv); |
| OVERRIDE(glCreateProgram); |
| OVERRIDE(glCreateShader); |
| OVERRIDE(glDeleteShader); |
| OVERRIDE(glAttachShader); |
| OVERRIDE(glDetachShader); |
| OVERRIDE(glGetAttachedShaders); |
| OVERRIDE(glGetShaderSource); |
| OVERRIDE(glGetShaderInfoLog); |
| OVERRIDE(glGetProgramInfoLog); |
| |
| OVERRIDE(glGetUniformLocation); |
| OVERRIDE(glUseProgram); |
| |
| OVERRIDE(glUniform1f); |
| OVERRIDE(glUniform1fv); |
| OVERRIDE(glUniform1i); |
| OVERRIDE(glUniform1iv); |
| OVERRIDE(glUniform2f); |
| OVERRIDE(glUniform2fv); |
| OVERRIDE(glUniform2i); |
| OVERRIDE(glUniform2iv); |
| OVERRIDE(glUniform3f); |
| OVERRIDE(glUniform3fv); |
| OVERRIDE(glUniform3i); |
| OVERRIDE(glUniform3iv); |
| OVERRIDE(glUniform4f); |
| OVERRIDE(glUniform4fv); |
| OVERRIDE(glUniform4i); |
| OVERRIDE(glUniform4iv); |
| OVERRIDE(glUniformMatrix2fv); |
| OVERRIDE(glUniformMatrix3fv); |
| OVERRIDE(glUniformMatrix4fv); |
| |
| OVERRIDE(glActiveTexture); |
| OVERRIDE(glBindTexture); |
| OVERRIDE(glDeleteTextures); |
| OVERRIDE(glGetTexParameterfv); |
| OVERRIDE(glGetTexParameteriv); |
| OVERRIDE(glTexParameterf); |
| OVERRIDE(glTexParameterfv); |
| OVERRIDE(glTexParameteri); |
| OVERRIDE(glTexParameteriv); |
| OVERRIDE(glTexImage2D); |
| OVERRIDE(glTexSubImage2D); |
| OVERRIDE(glCopyTexImage2D); |
| OVERRIDE(glTexBufferOES); |
| OVERRIDE(glTexBufferRangeOES); |
| OVERRIDE(glTexBufferEXT); |
| OVERRIDE(glTexBufferRangeEXT); |
| |
| OVERRIDE(glEnableiEXT); |
| OVERRIDE(glDisableiEXT); |
| OVERRIDE(glBlendEquationiEXT); |
| OVERRIDE(glBlendEquationSeparateiEXT); |
| OVERRIDE(glBlendFunciEXT); |
| OVERRIDE(glBlendFuncSeparateiEXT); |
| OVERRIDE(glColorMaskiEXT); |
| OVERRIDE(glIsEnablediEXT); |
| |
| OVERRIDE(glGenRenderbuffers); |
| OVERRIDE(glDeleteRenderbuffers); |
| OVERRIDE(glBindRenderbuffer); |
| OVERRIDE(glRenderbufferStorage); |
| OVERRIDE(glFramebufferRenderbuffer); |
| |
| OVERRIDE(glGenFramebuffers); |
| OVERRIDE(glDeleteFramebuffers); |
| OVERRIDE(glBindFramebuffer); |
| OVERRIDE(glFramebufferParameteri); |
| OVERRIDE(glFramebufferTexture2D); |
| OVERRIDE(glFramebufferTexture3DOES); |
| OVERRIDE(glGetFramebufferAttachmentParameteriv); |
| |
| OVERRIDE(glCheckFramebufferStatus); |
| |
| OVERRIDE(glGenVertexArrays); |
| OVERRIDE(glDeleteVertexArrays); |
| OVERRIDE(glBindVertexArray); |
| OVERRIDEOES(glGenVertexArrays); |
| OVERRIDEOES(glDeleteVertexArrays); |
| OVERRIDEOES(glBindVertexArray); |
| |
| OVERRIDE_CUSTOM(glMapBufferOES); |
| OVERRIDE_CUSTOM(glUnmapBufferOES); |
| OVERRIDE_CUSTOM(glMapBufferRange); |
| OVERRIDE_CUSTOM(glUnmapBuffer); |
| OVERRIDE_CUSTOM(glFlushMappedBufferRange); |
| |
| OVERRIDE(glCompressedTexImage2D); |
| OVERRIDE(glCompressedTexSubImage2D); |
| |
| OVERRIDE(glBindBufferRange); |
| OVERRIDE(glBindBufferBase); |
| |
| OVERRIDE(glCopyBufferSubData); |
| |
| OVERRIDE(glGetBufferParameteriv); |
| OVERRIDE(glGetBufferParameteri64v); |
| OVERRIDE(glGetBufferPointerv); |
| |
| OVERRIDE_CUSTOM(glGetUniformIndices); |
| |
| OVERRIDE(glUniform1ui); |
| OVERRIDE(glUniform2ui); |
| OVERRIDE(glUniform3ui); |
| OVERRIDE(glUniform4ui); |
| OVERRIDE(glUniform1uiv); |
| OVERRIDE(glUniform2uiv); |
| OVERRIDE(glUniform3uiv); |
| OVERRIDE(glUniform4uiv); |
| OVERRIDE(glUniformMatrix2x3fv); |
| OVERRIDE(glUniformMatrix3x2fv); |
| OVERRIDE(glUniformMatrix2x4fv); |
| OVERRIDE(glUniformMatrix4x2fv); |
| OVERRIDE(glUniformMatrix3x4fv); |
| OVERRIDE(glUniformMatrix4x3fv); |
| |
| OVERRIDE(glGetUniformuiv); |
| OVERRIDE(glGetActiveUniformBlockiv); |
| |
| OVERRIDE(glGetVertexAttribIiv); |
| OVERRIDE(glGetVertexAttribIuiv); |
| |
| OVERRIDE_CUSTOM(glVertexAttribIPointer); |
| |
| OVERRIDE(glVertexAttribDivisor); |
| |
| OVERRIDE(glRenderbufferStorageMultisample); |
| OVERRIDE(glDrawBuffers); |
| OVERRIDE(glReadBuffer); |
| OVERRIDE(glFramebufferTextureLayer); |
| OVERRIDE(glTexStorage2D); |
| |
| OVERRIDE_CUSTOM(glTransformFeedbackVaryings); |
| OVERRIDE(glBeginTransformFeedback); |
| OVERRIDE(glEndTransformFeedback); |
| OVERRIDE(glPauseTransformFeedback); |
| OVERRIDE(glResumeTransformFeedback); |
| |
| OVERRIDE(glTexImage3D); |
| OVERRIDE(glTexSubImage3D); |
| OVERRIDE(glTexStorage3D); |
| OVERRIDE(glCompressedTexImage3D); |
| OVERRIDE(glCompressedTexSubImage3D); |
| |
| OVERRIDE(glDrawArraysInstanced); |
| OVERRIDE_CUSTOM(glDrawElementsInstanced); |
| OVERRIDE_CUSTOM(glDrawRangeElements); |
| |
| OVERRIDE_CUSTOM(glGetStringi); |
| OVERRIDE(glGetProgramBinary); |
| OVERRIDE(glReadPixels); |
| |
| OVERRIDE(glEnable); |
| OVERRIDE(glDisable); |
| OVERRIDE(glClearBufferiv); |
| OVERRIDE(glClearBufferuiv); |
| OVERRIDE(glClearBufferfv); |
| OVERRIDE(glBlitFramebuffer); |
| OVERRIDE_CUSTOM(glGetInternalformativ); |
| |
| OVERRIDE(glGenerateMipmap); |
| |
| OVERRIDE(glBindSampler); |
| OVERRIDE(glDeleteSamplers); |
| |
| 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(glGetInteger64v); |
| OVERRIDE(glGetBooleani_v); |
| |
| OVERRIDE(glGetShaderiv); |
| |
| OVERRIDE(glActiveShaderProgram); |
| OVERRIDE_CUSTOM(glCreateShaderProgramv); |
| OVERRIDE(glProgramUniform1f); |
| OVERRIDE(glProgramUniform1fv); |
| OVERRIDE(glProgramUniform1i); |
| OVERRIDE(glProgramUniform1iv); |
| OVERRIDE(glProgramUniform1ui); |
| OVERRIDE(glProgramUniform1uiv); |
| OVERRIDE(glProgramUniform2f); |
| OVERRIDE(glProgramUniform2fv); |
| OVERRIDE(glProgramUniform2i); |
| OVERRIDE(glProgramUniform2iv); |
| OVERRIDE(glProgramUniform2ui); |
| OVERRIDE(glProgramUniform2uiv); |
| OVERRIDE(glProgramUniform3f); |
| OVERRIDE(glProgramUniform3fv); |
| OVERRIDE(glProgramUniform3i); |
| OVERRIDE(glProgramUniform3iv); |
| OVERRIDE(glProgramUniform3ui); |
| OVERRIDE(glProgramUniform3uiv); |
| OVERRIDE(glProgramUniform4f); |
| OVERRIDE(glProgramUniform4fv); |
| OVERRIDE(glProgramUniform4i); |
| OVERRIDE(glProgramUniform4iv); |
| OVERRIDE(glProgramUniform4ui); |
| OVERRIDE(glProgramUniform4uiv); |
| OVERRIDE(glProgramUniformMatrix2fv); |
| OVERRIDE(glProgramUniformMatrix2x3fv); |
| OVERRIDE(glProgramUniformMatrix2x4fv); |
| OVERRIDE(glProgramUniformMatrix3fv); |
| OVERRIDE(glProgramUniformMatrix3x2fv); |
| OVERRIDE(glProgramUniformMatrix3x4fv); |
| OVERRIDE(glProgramUniformMatrix4fv); |
| 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); |
| OVERRIDE(glVertexAttribBinding); |
| OVERRIDE(glBindVertexBuffer); |
| |
| OVERRIDE_CUSTOM(glDrawArraysIndirect); |
| OVERRIDE_CUSTOM(glDrawElementsIndirect); |
| |
| OVERRIDE(glTexStorage2DMultisample); |
| |
| OVERRIDE_CUSTOM(glGetGraphicsResetStatusEXT); |
| OVERRIDE_CUSTOM(glReadnPixelsEXT); |
| OVERRIDE_CUSTOM(glGetnUniformfvEXT); |
| OVERRIDE_CUSTOM(glGetnUniformivEXT); |
| |
| OVERRIDE(glInvalidateFramebuffer); |
| OVERRIDE(glInvalidateSubFramebuffer); |
| |
| OVERRIDE(glDispatchCompute); |
| OVERRIDE(glDispatchComputeIndirect); |
| |
| OVERRIDE(glGenTransformFeedbacks); |
| OVERRIDE(glDeleteTransformFeedbacks); |
| OVERRIDE(glGenSamplers); |
| OVERRIDE(glGenQueries); |
| OVERRIDE(glDeleteQueries); |
| |
| OVERRIDE(glBindTransformFeedback); |
| OVERRIDE(glBeginQuery); |
| OVERRIDE(glEndQuery); |
| |
| OVERRIDE(glClear); |
| OVERRIDE(glClearBufferfi); |
| OVERRIDE(glCopyTexSubImage2D); |
| OVERRIDE(glCopyTexSubImage3D); |
| OVERRIDE(glCompileShader); |
| OVERRIDE(glValidateProgram); |
| OVERRIDE(glProgramBinary); |
| |
| OVERRIDE(glGetSamplerParameterfv); |
| OVERRIDE(glGetSamplerParameteriv); |
| OVERRIDE(glSamplerParameterf); |
| OVERRIDE(glSamplerParameteri); |
| OVERRIDE(glSamplerParameterfv); |
| OVERRIDE(glSamplerParameteriv); |
| |
| OVERRIDE(glGetAttribLocation); |
| |
| OVERRIDE(glBindAttribLocation); |
| OVERRIDE(glUniformBlockBinding); |
| OVERRIDE(glGetTransformFeedbackVarying); |
| OVERRIDE(glScissor); |
| OVERRIDE(glDepthFunc); |
| OVERRIDE(glViewport); |
| OVERRIDE(glStencilFunc); |
| OVERRIDE(glStencilFuncSeparate); |
| OVERRIDE(glStencilOp); |
| OVERRIDE(glStencilOpSeparate); |
| OVERRIDE(glStencilMaskSeparate); |
| OVERRIDE(glBlendEquation); |
| OVERRIDE(glBlendEquationSeparate); |
| OVERRIDE(glBlendFunc); |
| OVERRIDE(glBlendFuncSeparate); |
| OVERRIDE(glCullFace); |
| OVERRIDE(glFrontFace); |
| OVERRIDE(glLineWidth); |
| OVERRIDE(glVertexAttrib1f); |
| OVERRIDE(glVertexAttrib2f); |
| OVERRIDE(glVertexAttrib3f); |
| OVERRIDE(glVertexAttrib4f); |
| OVERRIDE(glVertexAttrib1fv); |
| OVERRIDE(glVertexAttrib2fv); |
| OVERRIDE(glVertexAttrib3fv); |
| OVERRIDE(glVertexAttrib4fv); |
| OVERRIDE(glVertexAttribI4i); |
| OVERRIDE(glVertexAttribI4ui); |
| OVERRIDE(glVertexAttribI4iv); |
| OVERRIDE(glVertexAttribI4uiv); |
| |
| OVERRIDE(glGetShaderPrecisionFormat); |
| OVERRIDE(glGetProgramiv); |
| OVERRIDE(glGetActiveUniform); |
| OVERRIDE(glGetActiveUniformsiv); |
| OVERRIDE(glGetActiveUniformBlockName); |
| OVERRIDE(glGetActiveAttrib); |
| OVERRIDE(glGetRenderbufferParameteriv); |
| OVERRIDE(glGetQueryiv); |
| OVERRIDE(glGetQueryObjectuiv); |
| OVERRIDE(glIsEnabled); |
| OVERRIDE(glHint); |
| |
| OVERRIDE(glGetFragDataLocation); |
| |
| OVERRIDE(glStencilMask); |
| OVERRIDE(glClearStencil); |
| } |
| |
| GL2Encoder::~GL2Encoder() |
| { |
| delete m_compressedTextureFormats; |
| } |
| |
| GLenum GL2Encoder::s_glGetError(void * self) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| GLenum err = ctx->getError(); |
| if(err != GL_NO_ERROR) { |
| if (!ctx->m_noHostError) { |
| ctx->m_glGetError_enc(ctx); // also clear host error |
| } |
| ctx->setError(GL_NO_ERROR); |
| return err; |
| } |
| |
| if (ctx->m_noHostError) { |
| return GL_NO_ERROR; |
| } else { |
| return ctx->m_glGetError_enc(self); |
| } |
| } |
| |
| class GL2Encoder::ErrorUpdater { |
| public: |
| ErrorUpdater(GL2Encoder* ctx) : |
| mCtx(ctx), |
| guest_error(ctx->getError()), |
| host_error(ctx->m_glGetError_enc(ctx)) { |
| if (ctx->m_noHostError) { |
| host_error = GL_NO_ERROR; |
| } |
| // Preserve any existing GL error in the guest: |
| // OpenGL ES 3.0.5 spec: |
| // The command enum GetError( void ); is used to obtain error information. |
| // Each detectable error is assigned a numeric code. When an error is |
| // detected, a flag is set and the code is recorded. Further errors, if |
| // they occur, do not affect this recorded code. When GetError is called, |
| // the code is returned and the flag is cleared, so that a further error |
| // will again record its code. If a call to GetError returns NO_ERROR, then |
| // there has been no detectable error since the last call to GetError (or |
| // since the GL was initialized). |
| if (guest_error == GL_NO_ERROR) { |
| guest_error = host_error; |
| } |
| } |
| |
| GLenum getHostErrorAndUpdate() { |
| host_error = mCtx->m_glGetError_enc(mCtx); |
| if (guest_error == GL_NO_ERROR) { |
| guest_error = host_error; |
| } |
| return host_error; |
| } |
| |
| void updateGuestErrorState() { |
| mCtx->setError(guest_error); |
| } |
| |
| private: |
| GL2Encoder* mCtx; |
| GLenum guest_error; |
| GLenum host_error; |
| }; |
| |
| template<class T> |
| class GL2Encoder::ScopedQueryUpdate { |
| public: |
| ScopedQueryUpdate(GL2Encoder* ctx, uint32_t bytes, T* target) : |
| mCtx(ctx), |
| mBuf(bytes, 0), |
| mTarget(target), |
| mErrorUpdater(ctx) { |
| } |
| T* hostStagingBuffer() { |
| return (T*)&mBuf[0]; |
| } |
| ~ScopedQueryUpdate() { |
| GLint hostError = mErrorUpdater.getHostErrorAndUpdate(); |
| if (hostError == GL_NO_ERROR && mTarget) { |
| memcpy(mTarget, &mBuf[0], mBuf.size()); |
| } |
| mErrorUpdater.updateGuestErrorState(); |
| } |
| private: |
| GL2Encoder* mCtx; |
| std::vector<char> mBuf; |
| T* mTarget; |
| ErrorUpdater mErrorUpdater; |
| }; |
| |
| void GL2Encoder::safe_glGetBooleanv(GLenum param, GLboolean* val) { |
| ScopedQueryUpdate<GLboolean> query(this, glUtilsParamSize(param) * sizeof(GLboolean), val); |
| m_glGetBooleanv_enc(this, param, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetFloatv(GLenum param, GLfloat* val) { |
| ScopedQueryUpdate<GLfloat> query(this, glUtilsParamSize(param) * sizeof(GLfloat), val); |
| m_glGetFloatv_enc(this, param, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetIntegerv(GLenum param, GLint* val) { |
| ScopedQueryUpdate<GLint> query(this, glUtilsParamSize(param) * sizeof(GLint), val); |
| m_glGetIntegerv_enc(this, param, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetInteger64v(GLenum param, GLint64* val) { |
| ScopedQueryUpdate<GLint64> query(this, glUtilsParamSize(param) * sizeof(GLint64), val); |
| m_glGetInteger64v_enc(this, param, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetIntegeri_v(GLenum param, GLuint index, GLint* val) { |
| ScopedQueryUpdate<GLint> query(this, sizeof(GLint), val); |
| m_glGetIntegeri_v_enc(this, param, index, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetInteger64i_v(GLenum param, GLuint index, GLint64* val) { |
| ScopedQueryUpdate<GLint64> query(this, sizeof(GLint64), val); |
| m_glGetInteger64i_v_enc(this, param, index, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::safe_glGetBooleani_v(GLenum param, GLuint index, GLboolean* val) { |
| ScopedQueryUpdate<GLboolean> query(this, sizeof(GLboolean), val); |
| m_glGetBooleani_v_enc(this, param, index, query.hostStagingBuffer()); |
| } |
| |
| void GL2Encoder::s_glFlush(void *self) |
| { |
| GL2Encoder *ctx = (GL2Encoder *) self; |
| ctx->m_glFlush_enc(self); |
| ctx->m_stream->flush(); |
| } |
| |
| const GLubyte *GL2Encoder::s_glGetString(void *self, GLenum name) |
| { |
| 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); |
| 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_glPixelStorei(void *self, GLenum param, GLint value) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| SET_ERROR_IF(!GLESv2Validation::pixelStoreParam(ctx, param), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::pixelStoreValue(param, value), GL_INVALID_VALUE); |
| ctx->m_glPixelStorei_enc(ctx, param, value); |
| assert(ctx->m_state != NULL); |
| ctx->m_state->setPixelStore(param, value); |
| } |
| void GL2Encoder::s_glBindBuffer(void *self, GLenum target, GLuint id) |
| { |
| GL2Encoder *ctx = (GL2Encoder *) self; |
| assert(ctx->m_state != NULL); |
| SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM); |
| |
| bool nop = ctx->m_state->isNonIndexedBindNoOp(target, id); |
| |
| if (nop) return; |
| |
| ctx->m_state->bindBuffer(target, id); |
| ctx->m_state->addBuffer(id); |
| ctx->m_glBindBuffer_enc(ctx, target, id); |
| ctx->m_state->setLastEncodedBufferBind(target, id); |
| } |
| |
| void GL2Encoder::doBindBufferEncodeCached(GLenum target, GLuint id) { |
| bool encode = id != m_state->getLastEncodedBufferBind(target); |
| |
| if (encode) { |
| m_glBindBuffer_enc(this, target, id); |
| } |
| |
| m_state->setLastEncodedBufferBind(target, id); |
| } |
| |
| void GL2Encoder::s_glBufferData(void * self, GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) |
| { |
| GL2Encoder *ctx = (GL2Encoder *) self; |
| SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM); |
| GLuint bufferId = ctx->m_state->getBuffer(target); |
| SET_ERROR_IF(bufferId==0, GL_INVALID_OPERATION); |
| SET_ERROR_IF(size<0, GL_INVALID_VALUE); |
| SET_ERROR_IF(!GLESv2Validation::bufferUsage(ctx, usage), GL_INVALID_ENUM); |
| |
| ctx->m_shared->updateBufferData(bufferId, size, data); |
| ctx->m_shared->setBufferUsage(bufferId, usage); |
| if (ctx->m_hasSyncBufferData) { |
| ctx->glBufferDataSyncAEMU(self, target, size, data, usage); |
| } else { |
| ctx->m_glBufferData_enc(self, target, size, data, usage); |
| } |
| } |
| |
| void GL2Encoder::s_glBufferSubData(void * self, GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) |
| { |
| GL2Encoder *ctx = (GL2Encoder *) self; |
| SET_ERROR_IF(!GLESv2Validation::bufferTarget(ctx, target), GL_INVALID_ENUM); |
| GLuint bufferId = ctx->m_state->getBuffer(target); |
| SET_ERROR_IF(bufferId==0, GL_INVALID_OPERATION); |
| SET_ERROR_IF(ctx->isBufferTargetMapped(target), GL_INVALID_OPERATION); |
| |
| GLenum res = ctx->m_shared->subUpdateBufferData(bufferId, offset, size, data); |
| SET_ERROR_IF(res, res); |
| |
| 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; |
| SET_ERROR_IF(n<0, GL_INVALID_VALUE); |
| for (int i=0; i<n; i++) { |
| // Technically if the buffer is mapped, we should unmap it, but we won't |
| // 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]); |
| } |
| } |
| |
| #define VALIDATE_VERTEX_ATTRIB_INDEX(index) \ |
| SET_ERROR_IF(index >= CODEC_MAX_VERTEX_ATTRIBUTES, GL_INVALID_VALUE); \ |
| |
| void GL2Encoder::s_glVertexAttribPointer(void *self, GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid * ptr) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| assert(ctx->m_state != NULL); |
| VALIDATE_VERTEX_ATTRIB_INDEX(indx); |
| SET_ERROR_IF((size < 1 || size > 4), GL_INVALID_VALUE); |
| SET_ERROR_IF(!GLESv2Validation::vertexAttribType(ctx, type), GL_INVALID_ENUM); |
| SET_ERROR_IF(stride < 0, GL_INVALID_VALUE); |
| SET_ERROR_IF((type == GL_INT_2_10_10_10_REV || |
| type == GL_UNSIGNED_INT_2_10_10_10_REV) && |
| size != 4, |
| GL_INVALID_OPERATION); |
| ctx->m_state->setVertexAttribBinding(indx, indx); |
| ctx->m_state->setVertexAttribFormat(indx, size, type, normalized, 0, false); |
| |
| GLsizei effectiveStride = stride; |
| if (stride == 0) { |
| effectiveStride = glSizeof(type) * size; |
| switch (type) { |
| case GL_INT_2_10_10_10_REV: |
| case GL_UNSIGNED_INT_2_10_10_10_REV: |
| effectiveStride /= 4; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| ctx->m_state->bindIndexedBuffer(0, indx, ctx->m_state->currentArrayVbo(), (uintptr_t)ptr, 0, stride, effectiveStride); |
| |
| if (ctx->m_state->currentArrayVbo() != 0) { |
| ctx->glVertexAttribPointerOffset(ctx, indx, size, type, normalized, stride, (uintptr_t)ptr); |
| } else { |
| SET_ERROR_IF(ctx->m_state->currentVertexArrayObject() != 0 && ptr, GL_INVALID_OPERATION); |
| // wait for client-array handler |
| } |
| } |
| |
| void GL2Encoder::s_glGetIntegerv(void *self, GLenum param, GLint *ptr) |
| { |
| GL2Encoder *ctx = (GL2Encoder *) self; |
| GLClientState* state = ctx->m_state; |
| |
| switch (param) { |
| case GL_NUM_EXTENSIONS: |
| *ptr = (int)ctx->m_currExtensionsArray.size(); |
| break; |
| case GL_MAJOR_VERSION: |
| *ptr = ctx->m_deviceMajorVersion; |
| break; |
| case GL_MINOR_VERSION: |
| *ptr = ctx->m_deviceMinorVersion; |
| break; |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| *ptr = 0; |
| break; |
| case GL_SHADER_BINARY_FORMATS: |
| // do nothing |
| break; |
| |
| case GL_COMPRESSED_TEXTURE_FORMATS: { |
| GLint *compressedTextureFormats = ctx->getCompressedTextureFormats(); |
| if (ctx->m_num_compressedTextureFormats > 0 && |
| compressedTextureFormats != NULL) { |
| memcpy(ptr, compressedTextureFormats, |
| ctx->m_num_compressedTextureFormats * sizeof(GLint)); |
| } |
| break; |
| } |
| |
| case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: |
| if (ctx->m_max_combinedTextureImageUnits != 0) { |
| *ptr = ctx->m_max_combinedTextureImageUnits; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_combinedTextureImageUnits = *ptr; |
| } |
| break; |
| case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: |
| if (ctx->m_max_vertexTextureImageUnits != 0) { |
| *ptr = ctx->m_max_vertexTextureImageUnits; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_vertexTextureImageUnits = *ptr; |
| } |
| break; |
| case GL_MAX_ARRAY_TEXTURE_LAYERS: |
| if (ctx->m_max_array_texture_layers != 0) { |
| *ptr = ctx->m_max_array_texture_layers; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_array_texture_layers = *ptr; |
| } |
| break; |
| case GL_MAX_TEXTURE_IMAGE_UNITS: |
| if (ctx->m_max_textureImageUnits != 0) { |
| *ptr = ctx->m_max_textureImageUnits; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_textureImageUnits = *ptr; |
| } |
| break; |
| case GL_TEXTURE_BINDING_2D: |
| if (!state) return; |
| *ptr = state->getBoundTexture(GL_TEXTURE_2D); |
| break; |
| case GL_TEXTURE_BINDING_EXTERNAL_OES: |
| if (!state) return; |
| *ptr = state->getBoundTexture(GL_TEXTURE_EXTERNAL_OES); |
| break; |
| case GL_MAX_VERTEX_ATTRIBS: |
| *ptr = CODEC_MAX_VERTEX_ATTRIBUTES; |
| break; |
| case GL_MAX_VERTEX_ATTRIB_STRIDE: |
| if (ctx->m_max_vertexAttribStride != 0) { |
| *ptr = ctx->m_max_vertexAttribStride; |
| } else { |
| ctx->safe_glGetIntegerv(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; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_cubeMapTextureSize = *ptr; |
| } |
| break; |
| case GL_MAX_RENDERBUFFER_SIZE: |
| if (ctx->m_max_renderBufferSize != 0) { |
| *ptr = ctx->m_max_renderBufferSize; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_renderBufferSize = *ptr; |
| } |
| break; |
| case GL_MAX_TEXTURE_SIZE: |
| if (ctx->m_max_textureSize != 0) { |
| *ptr = ctx->m_max_textureSize; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_textureSize = *ptr; |
| if (ctx->m_max_textureSize > 0) { |
| uint32_t current = 1; |
| while (current < ctx->m_max_textureSize) { |
| ++ctx->m_log2MaxTextureSize; |
| current = current << 1; |
| } |
| } |
| } |
| break; |
| case GL_MAX_3D_TEXTURE_SIZE: |
| if (ctx->m_max_3d_textureSize != 0) { |
| *ptr = ctx->m_max_3d_textureSize; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_3d_textureSize = *ptr; |
| } |
| break; |
| case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: |
| if (ctx->m_ssbo_offset_align != 0) { |
| *ptr = ctx->m_ssbo_offset_align; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_ssbo_offset_align = *ptr; |
| } |
| break; |
| case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: |
| if (ctx->m_ubo_offset_align != 0) { |
| *ptr = ctx->m_ubo_offset_align; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_ubo_offset_align = *ptr; |
| } |
| break; |
| // 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; |
| // Checks for version-incompatible enums. |
| // Not allowed in vanilla ES 2.0. |
| case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: |
| SET_ERROR_IF(ctx->majorVersion() < 3, GL_INVALID_ENUM); |
| if (ctx->m_max_transformFeedbackSeparateAttribs != 0) { |
| *ptr = ctx->m_max_transformFeedbackSeparateAttribs; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_transformFeedbackSeparateAttribs = *ptr; |
| } |
| break; |
| case GL_MAX_UNIFORM_BUFFER_BINDINGS: |
| SET_ERROR_IF(ctx->majorVersion() < 3, GL_INVALID_ENUM); |
| if (ctx->m_max_uniformBufferBindings != 0) { |
| *ptr = ctx->m_max_uniformBufferBindings; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_uniformBufferBindings = *ptr; |
| } |
| break; |
| case GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES: |
| SET_ERROR_IF(!ctx->es32Plus() && !ctx->getExtensions().textureBufferAny(), GL_INVALID_ENUM); |
| if(ctx->m_textureBufferOffsetAlign != 0) { |
| *ptr = ctx->m_textureBufferOffsetAlign; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_textureBufferOffsetAlign = *ptr; |
| } |
| break; |
| case GL_MAX_COLOR_ATTACHMENTS: |
| SET_ERROR_IF(ctx->majorVersion() < 3 && |
| !ctx->hasExtension("GL_EXT_draw_buffers"), GL_INVALID_ENUM); |
| if (ctx->m_max_colorAttachments != 0) { |
| *ptr = ctx->m_max_colorAttachments; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_colorAttachments = *ptr; |
| } |
| break; |
| case GL_MAX_DRAW_BUFFERS: |
| SET_ERROR_IF(ctx->majorVersion() < 3 && |
| !ctx->hasExtension("GL_EXT_draw_buffers"), GL_INVALID_ENUM); |
| if (ctx->m_max_drawBuffers != 0) { |
| *ptr = ctx->m_max_drawBuffers; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_drawBuffers = *ptr; |
| } |
| break; |
| // Not allowed in ES 3.0. |
| case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: |
| SET_ERROR_IF(ctx->majorVersion() < 3 || |
| (ctx->majorVersion() == 3 && |
| ctx->minorVersion() == 0), GL_INVALID_ENUM); |
| if (ctx->m_max_atomicCounterBufferBindings != 0) { |
| *ptr = ctx->m_max_atomicCounterBufferBindings; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_atomicCounterBufferBindings = *ptr; |
| } |
| break; |
| case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: |
| SET_ERROR_IF(ctx->majorVersion() < 3 || |
| (ctx->majorVersion() == 3 && |
| ctx->minorVersion() == 0), GL_INVALID_ENUM); |
| if (ctx->m_max_shaderStorageBufferBindings != 0) { |
| *ptr = ctx->m_max_shaderStorageBufferBindings; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_shaderStorageBufferBindings = *ptr; |
| } |
| break; |
| case GL_MAX_VERTEX_ATTRIB_BINDINGS: |
| SET_ERROR_IF(ctx->majorVersion() < 3 || |
| (ctx->majorVersion() == 3 && |
| ctx->minorVersion() == 0), GL_INVALID_ENUM); |
| if (ctx->m_max_vertexAttribBindings != 0) { |
| *ptr = ctx->m_max_vertexAttribBindings; |
| } else { |
| ctx->safe_glGetIntegerv(param, ptr); |
| ctx->m_max_vertexAttribBindings = *ptr; |
| } |
| break; |
| case GL_RESET_NOTIFICATION_STRATEGY_EXT: |
| // BUG: 121414786 |
| *ptr = GL_LOSE_CONTEXT_ON_RESET_EXT; |
| break; |
| default: |
| if (!state) return; |
| if (!state->getClientStateParameter<GLint>(param, ptr)) { |
| ctx->safe_glGetIntegerv(param, ptr); |
| } |
| break; |
| } |
| } |
| |
| |
| void GL2Encoder::s_glGetFloatv(void *self, GLenum param, GLfloat *ptr) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| GLClientState* state = ctx->m_state; |
| |
| switch (param) { |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| *ptr = 0; |
| break; |
| case GL_SHADER_BINARY_FORMATS: |
| // do nothing |
| break; |
| |
| case GL_COMPRESSED_TEXTURE_FORMATS: { |
| GLint *compressedTextureFormats = ctx->getCompressedTextureFormats(); |
| if (ctx->m_num_compressedTextureFormats > 0 && |
| compressedTextureFormats != NULL) { |
| for (int i = 0; i < ctx->m_num_compressedTextureFormats; i++) { |
| ptr[i] = (GLfloat) compressedTextureFormats[i]; |
| } |
| } |
| break; |
| } |
| |
| case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_VERTEX_ATTRIBS: |
| case GL_MAX_VERTEX_ATTRIB_STRIDE: |
| case GL_MAX_CUBE_MAP_TEXTURE_SIZE: |
| case GL_MAX_RENDERBUFFER_SIZE: |
| case GL_MAX_TEXTURE_SIZE: |
| case GL_MAX_3D_TEXTURE_SIZE: |
| case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: |
| case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: |
| case GL_MAX_SAMPLES: |
| case GL_MAX_COLOR_TEXTURE_SAMPLES: |
| case GL_MAX_INTEGER_SAMPLES: |
| case GL_MAX_DEPTH_TEXTURE_SAMPLES: |
| case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: |
| case GL_MAX_UNIFORM_BUFFER_BINDINGS: |
| case GL_MAX_COLOR_ATTACHMENTS: |
| case GL_MAX_DRAW_BUFFERS: |
| case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: |
| case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: |
| case GL_MAX_VERTEX_ATTRIB_BINDINGS: |
| case GL_TEXTURE_BINDING_2D: |
| case GL_TEXTURE_BINDING_EXTERNAL_OES: { |
| GLint res; |
| s_glGetIntegerv(ctx, param, &res); |
| *ptr = (GLfloat)res; |
| break; |
| } |
| |
| default: |
| if (!state) return; |
| if (!state->getClientStateParameter<GLfloat>(param, ptr)) { |
| ctx->safe_glGetFloatv(param, ptr); |
| } |
| break; |
| } |
| } |
| |
| |
| void GL2Encoder::s_glGetBooleanv(void *self, GLenum param, GLboolean *ptr) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| GLClientState* state = ctx->m_state; |
| |
| switch (param) { |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| *ptr = GL_FALSE; |
| break; |
| case GL_SHADER_BINARY_FORMATS: |
| // do nothing |
| break; |
| |
| case GL_COMPRESSED_TEXTURE_FORMATS: { |
| GLint *compressedTextureFormats = ctx->getCompressedTextureFormats(); |
| if (ctx->m_num_compressedTextureFormats > 0 && |
| compressedTextureFormats != NULL) { |
| for (int i = 0; i < ctx->m_num_compressedTextureFormats; i++) { |
| ptr[i] = compressedTextureFormats[i] != 0 ? GL_TRUE : GL_FALSE; |
| } |
| } |
| break; |
| } |
| |
| case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_TEXTURE_IMAGE_UNITS: |
| case GL_MAX_VERTEX_ATTRIBS: |
| case GL_MAX_VERTEX_ATTRIB_STRIDE: |
| case GL_MAX_CUBE_MAP_TEXTURE_SIZE: |
| case GL_MAX_RENDERBUFFER_SIZE: |
| case GL_MAX_TEXTURE_SIZE: |
| case GL_MAX_3D_TEXTURE_SIZE: |
| case GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT: |
| case GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: |
| case GL_MAX_SAMPLES: |
| case GL_MAX_COLOR_TEXTURE_SAMPLES: |
| case GL_MAX_INTEGER_SAMPLES: |
| case GL_MAX_DEPTH_TEXTURE_SAMPLES: |
| case GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: |
| case GL_MAX_UNIFORM_BUFFER_BINDINGS: |
| case GL_MAX_COLOR_ATTACHMENTS: |
| case GL_MAX_DRAW_BUFFERS: |
| case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: |
| case GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: |
| case GL_MAX_VERTEX_ATTRIB_BINDINGS: |
| case GL_TEXTURE_BINDING_2D: |
| case GL_TEXTURE_BINDING_EXTERNAL_OES: { |
| GLint res; |
| s_glGetIntegerv(ctx, param, &res); |
| *ptr = res == 0 ? GL_FALSE : GL_TRUE; |
| break; |
| } |
| |
| default: |
| if (!state) return; |
| { |
| GLint intVal; |
| if (!state->getClientStateParameter<GLint>(param, &intVal)) { |
| ctx->safe_glGetBooleanv(param, ptr); |
| } else { |
| *ptr = (intVal != 0) ? GL_TRUE : GL_FALSE; |
| } |
| } |
| break; |
| } |
| } |
| |
| |
| void GL2Encoder::s_glEnableVertexAttribArray(void *self, GLuint index) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| assert(ctx->m_state); |
| VALIDATE_VERTEX_ATTRIB_INDEX(index); |
| ctx->m_glEnableVertexAttribArray_enc(ctx, index); |
| ctx->m_state->enable(index, 1); |
| } |
| |
| void GL2Encoder::s_glDisableVertexAttribArray(void *self, GLuint index) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| assert(ctx->m_state); |
| VALIDATE_VERTEX_ATTRIB_INDEX(index); |
| ctx->m_glDisableVertexAttribArray_enc(ctx, index); |
| ctx->m_state->enable(index, 0); |
| } |
| |
| |
| void GL2Encoder::s_glGetVertexAttribiv(void *self, GLuint index, GLenum pname, GLint *params) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| VALIDATE_VERTEX_ATTRIB_INDEX(index); |
| SET_ERROR_IF(!GLESv2Validation::allowedGetVertexAttrib(pname), GL_INVALID_ENUM); |
| |
| if (!ctx->m_state->getVertexAttribParameter<GLint>(index, pname, params)) { |
| ctx->m_glGetVertexAttribiv_enc(self, index, pname, params); |
| } |
| } |
| |
| void GL2Encoder::s_glGetVertexAttribfv(void *self, GLuint index, GLenum pname, GLfloat *params) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| VALIDATE_VERTEX_ATTRIB_INDEX(index); |
| SET_ERROR_IF(!GLESv2Validation::allowedGetVertexAttrib(pname), GL_INVALID_ENUM); |
| |
| if (!ctx->m_state->getVertexAttribParameter<GLfloat>(index, pname, params)) { |
| ctx->m_glGetVertexAttribfv_enc(self, index, pname, params); |
| } |
| } |
| |
| void GL2Encoder::s_glGetVertexAttribPointerv(void *self, GLuint index, GLenum pname, GLvoid **pointer) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| if (ctx->m_state == NULL) return; |
| VALIDATE_VERTEX_ATTRIB_INDEX(index); |
| SET_ERROR_IF(pname != GL_VERTEX_ATTRIB_ARRAY_POINTER, GL_INVALID_ENUM); |
| (void)pname; |
| |
| *pointer = (GLvoid*)(ctx->m_state->getCurrAttributeBindingInfo(index).offset); |
| } |
| |
| void GL2Encoder::calcIndexRange(const void* indices, |
| GLenum type, |
| GLsizei count, |
| int* minIndex_out, |
| int* maxIndex_out) { |
| switch(type) { |
| case GL_BYTE: |
| case GL_UNSIGNED_BYTE: |
| GLUtils::minmaxExcept( |
| (unsigned char *)indices, count, |
| minIndex_out, maxIndex_out, |
| m_primitiveRestartEnabled, GLUtils::primitiveRestartIndex<unsigned char>()); |
| break; |
| case GL_SHORT: |
| case GL_UNSIGNED_SHORT: |
| GLUtils::minmaxExcept( |
| (unsigned short *)indices, count, |
| minIndex_out, maxIndex_out, |
| m_primitiveRestartEnabled, GLUtils::primitiveRestartIndex<unsigned short>()); |
| break; |
| case GL_INT: |
| case GL_UNSIGNED_INT: |
| GLUtils::minmaxExcept( |
| (unsigned int *)indices, count, |
| minIndex_out, maxIndex_out, |
| m_primitiveRestartEnabled, GLUtils::primitiveRestartIndex<unsigned int>()); |
| break; |
| default: |
| ALOGE("unsupported index buffer type %d\n", type); |
| } |
| } |
| |
| void* GL2Encoder::recenterIndices(const void* src, |
| GLenum type, |
| GLsizei count, |
| int minIndex) { |
| |
| void* adjustedIndices = (void*)src; |
| |
| if (minIndex != 0) { |
| m_fixedBuffer.resize(glSizeof(type) * count); |
| adjustedIndices = m_fixedBuffer.data(); |
| switch(type) { |
| case GL_BYTE: |
| case GL_UNSIGNED_BYTE: |
| GLUtils::shiftIndicesExcept( |
| (unsigned char *)src, |
| (unsigned char *)adjustedIndices, |
| count, -minIndex, |
| m_primitiveRestartEnabled, |
| (unsigned char)m_primitiveRestartIndex); |
| break; |
| case GL_SHORT: |
| case GL_UNSIGNED_SHORT: |
| GLUtils::shiftIndicesExcept( |
| (unsigned short *)src, |
| (unsigned short *)adjustedIndices, |
| count, -minIndex, |
| m_primitiveRestartEnabled, |
| (unsigned short)m_primitiveRestartIndex); |
| break; |
| case GL_INT: |
| case GL_UNSIGNED_INT: |
| GLUtils::shiftIndicesExcept( |
| (unsigned int *)src, |
| (unsigned int *)adjustedIndices, |
| count, -minIndex, |
| m_primitiveRestartEnabled, |
| (unsigned int)m_primitiveRestartIndex); |
| break; |
| default: |
| ALOGE("unsupported index buffer type %d\n", type); |
| } |
| } |
| |
| return adjustedIndices; |
| } |
| |
| void GL2Encoder::getBufferIndexRange(BufferData* buf, |
| const void* dataWithOffset, |
| GLenum type, |
| size_t count, |
| size_t offset, |
| int* minIndex_out, |
| int* maxIndex_out) { |
| |
| if (buf->m_indexRangeCache.findRange( |
| type, offset, count, |
| m_primitiveRestartEnabled, |
| minIndex_out, |
| maxIndex_out)) { |
| return; |
| } |
| |
| calcIndexRange(dataWithOffset, type, count, minIndex_out, maxIndex_out); |
| |
| buf->m_indexRangeCache.addRange( |
| type, offset, count, m_primitiveRestartEnabled, |
| *minIndex_out, *maxIndex_out); |
| |
| ALOGV("%s: got range [%u %u] pr? %d", __FUNCTION__, *minIndex_out, *maxIndex_out, m_primitiveRestartEnabled); |
| } |
| |
| // For detecting legacy usage of glVertexAttribPointer |
| void GL2Encoder::getVBOUsage(bool* hasClientArrays, bool* hasVBOs) const { |
| if (hasClientArrays) *hasClientArrays = false; |
| if (hasVBOs) *hasVBOs = false; |
| |
| m_state->getVBOUsage(hasClientArrays, hasVBOs); |
| } |
| |
| void GL2Encoder::sendVertexAttributes(GLint first, GLsizei count, bool hasClientArrays, GLsizei primcount) |
| { |
| assert(m_state); |
| |
| m_state->updateEnableDirtyArrayForDraw(); |
| |
| GLuint lastBoundVbo = m_state->currentArrayVbo(); |
| const GLClientState::VAOState& vaoState = m_state->currentVaoState(); |
| |
| for (int k = 0; k < vaoState.numAttributesNeedingUpdateForDraw; k++) { |
| int i = vaoState.attributesNeedingUpdateForDraw[k]; |
| |
| const GLClientState::VertexAttribState& state = vaoState.attribState[i]; |
| |
| if (state.enabled) { |
| const GLClientState::BufferBinding& curr_binding = m_state->getCurrAttributeBindingInfo(i); |
| GLuint bufferObject = curr_binding.buffer; |
| if (hasClientArrays && lastBoundVbo != bufferObject) { |
| doBindBufferEncodeCached(GL_ARRAY_BUFFER, bufferObject); |
| lastBoundVbo = bufferObject; |
| } |
| |
| int divisor = curr_binding.divisor; |
| int stride = curr_binding.stride; |
| int effectiveStride = curr_binding.effectiveStride; |
| uintptr_t offset = curr_binding.offset; |
| |
| int firstIndex = effectiveStride * first; |
| if (firstIndex && divisor && !primcount) { |
| // If firstIndex != 0 according to effectiveStride * first, |
| // it needs to be adjusted if a divisor has been specified, |
| // even if we are not in glDraw***Instanced. |
| firstIndex = 0; |
| } |
| |
| if (bufferObject == 0) { |
| unsigned int datalen = state.elementSize * count; |
| if (divisor) { |
| ALOGV("%s: divisor for att %d: %d, w/ stride %d (effective stride %d) size %d type 0x%x) datalen %u", |
| __FUNCTION__, i, divisor, state.stride, effectiveStride, state.elementSize, state.type, datalen); |
| int actual_count = std::max(1, (int)((primcount + divisor - 1) / divisor)); |
| datalen = state.elementSize * actual_count; |
| ALOGV("%s: actual datalen %u", __FUNCTION__, datalen); |
| } |
| if (state.elementSize == 0) { |
| // The vertex attribute array is uninitialized. Abandon it. |
| this->m_glDisableVertexAttribArray_enc(this, i); |
| continue; |
| } |
| m_glEnableVertexAttribArray_enc(this, i); |
| |
| if (datalen && (!offset || !((unsigned char*)offset + firstIndex))) { |
| continue; |
| } |
| |
| unsigned char* data = (unsigned char*)offset + firstIndex; |
| if (!m_state->isAttribIndexUsedByProgram(i)) { |
| continue; |
| } |
| |
| if (state.isInt) { |
| this->glVertexAttribIPointerDataAEMU(this, i, state.size, state.type, stride, data, datalen); |
| } else { |
| this->glVertexAttribPointerData(this, i, state.size, state.type, state.normalized, stride, data, datalen); |
| } |
| } else { |
| const BufferData* buf = m_shared->getBufferData(bufferObject); |
| // 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 ? (count - 1) : 0) + state.elementSize; |
| if (divisor) { |
| int actual_count = std::max(1, (int)((primcount + divisor - 1) / divisor)); |
| bufLen = effectiveStride * (actual_count ? (actual_count - 1) : 0) + state.elementSize; |
| } |
| if (buf && firstIndex >= 0 && firstIndex + bufLen <= buf->m_size) { |
| if (hasClientArrays) { |
| m_glEnableVertexAttribArray_enc(this, i); |
| if (firstIndex) { |
| if (state.isInt) { |
| this->glVertexAttribIPointerOffsetAEMU(this, i, state.size, state.type, stride, offset + firstIndex); |
| } else { |
| this->glVertexAttribPointerOffset(this, i, state.size, state.type, state.normalized, stride, offset + firstIndex); |
| } |
| } |
| } |
| } else { |
| if (m_state->isAttribIndexUsedByProgram(i)) { |
| ALOGE("a vertex attribute index out of boundary is detected. Skipping corresponding vertex attribute. buf=%p", buf); |
| if (buf) { |
| ALOGE("Out of bounds vertex attribute info: " |
| "clientArray? %d attribute %d vbo %u allocedBufferSize %u bufferDataSpecified? %d wantedStart %u wantedEnd %u", |
| hasClientArrays, i, bufferObject, (unsigned int)buf->m_size, buf != NULL, firstIndex, firstIndex + bufLen); |
| } |
| m_glDisableVertexAttribArray_enc(this, i); |
| } |
| } |
| } |
| } else { |
| if (hasClientArrays) { |
| this->m_glDisableVertexAttribArray_enc(this, i); |
| } |
| } |
| } |
| |
| if (hasClientArrays && lastBoundVbo != m_state->currentArrayVbo()) { |
| doBindBufferEncodeCached(GL_ARRAY_BUFFER, m_state->currentArrayVbo()); |
| } |
| } |
| |
| void GL2Encoder::flushDrawCall() { |
| if (m_drawCallFlushCount % m_drawCallFlushInterval == 0) { |
| m_stream->flush(); |
| } |
| m_drawCallFlushCount++; |
| } |
| |
| static bool isValidDrawMode(GLenum mode) |
| { |
| bool retval = false; |
| switch (mode) { |
| case GL_POINTS: |
| case GL_LINE_STRIP: |
| case GL_LINE_LOOP: |
| case GL_LINES: |
| case GL_TRIANGLE_STRIP: |
| case GL_TRIANGLE_FAN: |
| case GL_TRIANGLES: |
| retval = true; |
| } |
| return retval; |
| } |
| |
| void GL2Encoder::s_glDrawArrays(void *self, GLenum mode, GLint first, GLsizei count) |
| { |
| 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(ctx->m_state->checkFramebufferCompleteness(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION); |
| |
| 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); |
| ctx->m_glDrawArrays_enc(ctx, mode, 0, count); |
| } else { |
| ctx->m_glDrawArrays_enc(ctx, mode, first, count); |
| } |
| |
| ctx->m_state->postDraw(); |
| } |
| |
| |
| void GL2Encoder::s_glDrawElements(void *self, GLenum mode, 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(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); |
| SET_ERROR_IF(ctx->m_state->checkFramebufferCompleteness(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION); |
| |
| bool has_client_vertex_arrays = false; |
| bool has_indirect_arrays = false; |
| 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->glCheckFramebufferStatus(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 = &buf->m_fixedBuffer[offset]; |
| 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); |
| } |
| |
| if (count == 0) return; |
| |
| bool adjustIndices = true; |
| if (ctx->m_state->currentIndexVbo() != 0) { |
| if (!has_client_vertex_arrays) { |
| ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo()); |
| ctx->glDrawElementsOffset(ctx, mode, count, type, offset); |
| ctx->flushDrawCall(); |
| adjustIndices = false; |
| } else { |
| ctx->doBindBufferEncodeCached(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)); |
| // 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"); |
| } |
| } |
| |
| ctx->m_state->postDraw(); |
| } |
| |
| void GL2Encoder::s_glDrawArraysNullAEMU(void *self, GLenum mode, GLint first, GLsizei count) |
| { |
| 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(ctx->m_state->checkFramebufferCompleteness(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION); |
| |
| 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); |
| ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, 0, count); |
| } else { |
| ctx->m_glDrawArraysNullAEMU_enc(ctx, mode, first, count); |
| } |
| ctx->flushDrawCall(); |
| ctx->m_state->postDraw(); |
| } |
| |
| void GL2Encoder::s_glDrawElementsNullAEMU(void *self, GLenum mode, 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(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); |
| SET_ERROR_IF(ctx->m_state->checkFramebufferCompleteness(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION); |
| |
| bool has_client_vertex_arrays = false; |
| bool has_indirect_arrays = false; |
| GLintptr offset = (GLintptr)indices; |
| |
| 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->glCheckFramebufferStatus(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) { |
| if (!has_client_vertex_arrays && has_indirect_arrays) { |
| // Don't do anything |
| } else { |
| buf = ctx->m_shared->getBufferData(ctx->m_state->currentIndexVbo()); |
| offset = (GLintptr)indices; |
| indices = &buf->m_fixedBuffer[offset]; |
| 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); |
| } |
| |
| if (count == 0) return; |
| |
| bool adjustIndices = true; |
| if (ctx->m_state->currentIndexVbo() != 0) { |
| if (!has_client_vertex_arrays) { |
| ctx->doBindBufferEncodeCached(GL_ELEMENT_ARRAY_BUFFER, ctx->m_state->currentIndexVbo()); |
| ctx->glDrawElementsOffsetNullAEMU(ctx, mode, count, type, offset); |
| ctx->flushDrawCall(); |
| adjustIndices = false; |
| } else { |
| 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->glDrawElementsDataNullAEMU(ctx, mode, count, type, adjustedIndices, |
| count * glSizeof(type)); |
| // 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("glDrawElementsNullAEMU: direct index & direct buffer data - will be implemented in later versions;\n"); |
| } |
| } |
| ctx->m_state->postDraw(); |
| } |
| |
| GLint * GL2Encoder::getCompressedTextureFormats() |
| { |
| if (m_compressedTextureFormats == NULL) { |
| this->glGetIntegerv(this, GL_NUM_COMPRESSED_TEXTURE_FORMATS, |
| &m_num_compressedTextureFormats); |
| if (m_num_compressedTextureFormats > 0) { |
| // get number of texture formats; |
| m_compressedTextureFormats = new GLint[m_num_compressedTextureFormats]; |
| this->glGetCompressedTextureFormats(this, m_num_compressedTextureFormats, m_compressedTextureFormats); |
| } |
| } |
| return m_compressedTextureFormats; |
| } |
| |
| // Replace uses of samplerExternalOES with sampler2D, recording the names of |
| // modified shaders in data. Also remove |
| // #extension GL_OES_EGL_image_external : require |
| // #extension GL_OES_EGL_image_external_essl3 : require |
| // statements. |
| // |
| // This implementation assumes the input has already been pre-processed. If not, |
| // a few cases will be mishandled: |
| // |
| // 1. "mySampler" will be incorrectly recorded as being a samplerExternalOES in |
| // the following code: |
| // #if 1 |
| // uniform sampler2D mySampler; |
| // #else |
| // uniform samplerExternalOES mySampler; |
| // #endif |
| // |
| // 2. Comments that look like sampler declarations will be incorrectly modified |
| // and recorded: |
| // // samplerExternalOES hahaFooledYou |
| // |
| // 3. However, GLSL ES does not have a concatentation operator, so things like |
| // this (valid in C) are invalid and not a problem: |
| // #define SAMPLER(TYPE, NAME) uniform sampler#TYPE NAME |
| // SAMPLER(ExternalOES, mySampler); |
| // |
| |
| static const char STR_SAMPLER_EXTERNAL_OES[] = "samplerExternalOES"; |
| static const char STR_SAMPLER2D_SPACE[] = "sampler2D "; |
| static const char STR_DEFINE[] = "#define"; |
| |
| static std::vector<std::string> getSamplerExternalAliases(char* str) { |
| std::vector<std::string> res; |
| |
| res.push_back(STR_SAMPLER_EXTERNAL_OES); |
| |
| // -- capture #define x samplerExternalOES |
| char* c = str; |
| while ((c = strstr(c, STR_DEFINE))) { |
| // Don't push it if samplerExternalOES is not even there. |
| char* samplerExternalOES_next = strstr(c, STR_SAMPLER_EXTERNAL_OES); |
| if (!samplerExternalOES_next) break; |
| |
| bool prevIdent = false; |
| |
| std::vector<std::string> idents; |
| std::string curr; |
| |
| while (*c != '\0') { |
| |
| if (isspace(*c)) { |
| if (prevIdent) { |
| idents.push_back(curr); |
| curr = ""; |
| } |
| } |
| |
| if (*c == '\n' || idents.size() == 3) break; |
| |
| if (isalpha(*c) || *c == '_') { |
| curr.push_back(*c); |
| prevIdent = true; |
| } |
| |
| ++c; |
| } |
| |
| if (idents.size() != 3) continue; |
| |
| const std::string& defineLhs = idents[1]; |
| const std::string& defineRhs = idents[2]; |
| |
| if (defineRhs == STR_SAMPLER_EXTERNAL_OES) { |
| res.push_back(defineLhs); |
| } |
| |
| if (*c == '\0') break; |
| } |
| |
| return res; |
| } |
| |
| static bool replaceExternalSamplerUniformDefinition(char* str, const std::string& samplerExternalType, ShaderData* data) { |
| // -- replace "samplerExternalOES" with "sampler2D" and record name |
| char* c = str; |
| while ((c = strstr(c, samplerExternalType.c_str()))) { |
| // Make sure "samplerExternalOES" isn't a substring of a larger token |
| if (c == str || !isspace(*(c-1))) { |
| c++; |
| continue; |
| } |
| char* sampler_start = c; |
| c += samplerExternalType.size(); |
| if (!isspace(*c) && *c != '\0' && *c != ';') { |
| continue; |
| } else { |
| // capture sampler name |
| while (isspace(*c) && *c != '\0') { |
| c++; |
| } |
| } |
| |
| if ((!isalpha(*c) && *c != '_') || *c == ';') { |
| // not an identifier, but might have some effect anyway. |
| if (samplerExternalType == STR_SAMPLER_EXTERNAL_OES) { |
| memcpy(sampler_start, STR_SAMPLER2D_SPACE, sizeof(STR_SAMPLER2D_SPACE)-1); |
| } |
| } else { |
| char* name_start = c; |
| do { |
| c++; |
| } while (isalnum(*c) || *c == '_'); |
| |
| size_t len = (size_t)(c - name_start); |
| if (len) { |
| data->samplerExternalNames.push_back( |
| std::string(name_start, len)); |
| } |
| |
| // We only need to perform a string replacement for the original |
| // occurrence of samplerExternalOES if a #define was used. |
| // |
| // The important part was to record the name in |
| // |data->samplerExternalNames|. |
| if (samplerExternalType == STR_SAMPLER_EXTERNAL_OES) { |
| memcpy(sampler_start, STR_SAMPLER2D_SPACE, sizeof(STR_SAMPLER2D_SPACE)-1); |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| static bool replaceSamplerExternalWith2D(char* const str, ShaderData* const data) |
| { |
| static const char STR_HASH_EXTENSION[] = "#extension"; |
| static const char STR_GL_OES_EGL_IMAGE_EXTERNAL[] = "GL_OES_EGL_image_external"; |
| static const char STR_GL_OES_EGL_IMAGE_EXTERNAL_ESSL3[] = "GL_OES_EGL_image_external_essl3"; |
| |
| // -- overwrite all "#extension GL_OES_EGL_image_external : xxx" statements |
| char* c = str; |
| while ((c = strstr(c, STR_HASH_EXTENSION))) { |
| char* start = c; |
| c += sizeof(STR_HASH_EXTENSION)-1; |
| while (isspace(*c) && *c != '\0') { |
| c++; |
| } |
| |
| bool hasBaseImageExternal = |
| !strncmp(c, STR_GL_OES_EGL_IMAGE_EXTERNAL, |
| sizeof(STR_GL_OES_EGL_IMAGE_EXTERNAL) - 1); |
| bool hasEssl3ImageExternal = |
| !strncmp(c, STR_GL_OES_EGL_IMAGE_EXTERNAL_ESSL3, |
| sizeof(STR_GL_OES_EGL_IMAGE_EXTERNAL_ESSL3) - 1); |
| |
| if (hasBaseImageExternal || hasEssl3ImageExternal) |
| { |
| // #extension statements are terminated by end of line |
| c = start; |
| while (*c != '\0' && *c != '\r' && *c != '\n') { |
| *c++ = ' '; |
| } |
| } |
| } |
| |
| std::vector<std::string> samplerExternalAliases = |
| getSamplerExternalAliases(str); |
| |
| for (size_t i = 0; i < samplerExternalAliases.size(); i++) { |
| if (!replaceExternalSamplerUniformDefinition( |
| str, samplerExternalAliases[i], data)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void GL2Encoder::s_glShaderBinary(void *self, GLsizei, const GLuint *, GLenum, const void*, GLsizei) |
| { |
| // Although it is not supported, need to set proper error code. |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(1, GL_INVALID_ENUM); |
| } |
| |
| void GL2Encoder::s_glShaderSource(void *self, GLuint shader, GLsizei count, const GLchar * const *string, const GLint *length) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| ShaderData* shaderData = ctx->m_shared->getShaderData(shader); |
| SET_ERROR_IF(!ctx->m_shared->isShaderOrProgramObject(shader), GL_INVALID_VALUE); |
| SET_ERROR_IF(!shaderData, GL_INVALID_OPERATION); |
| SET_ERROR_IF((count<0), GL_INVALID_VALUE); |
| |
| // Track original sources---they may be translated in the backend |
| std::vector<std::string> orig_sources; |
| if (length) { |
| for (int i = 0; i < count; i++) { |
| // Each element in the length array may contain the length of the corresponding |
| // string (the null character is not counted as part of the string length) or a |
| // value less than 0 to indicate that the string is null terminated. |
| if (length[i] >= 0) { |
| orig_sources.push_back(std::string((const char*)(string[i]), |
| (const char*)(string[i]) + length[i])); |
| } else { |
| orig_sources.push_back(std::string((const char*)(string[i]))); |
| } |
| } |
| } else { |
| for (int i = 0; i < count; i++) { |
| orig_sources.push_back(std::string((const char*)(string[i]))); |
| } |
| } |
| shaderData->sources = orig_sources; |
| |
| int len = glUtilsCalcShaderSourceLen((char**)string, (GLint*)length, count); |
| char *str = new char[len + 1]; |
| glUtilsPackStrings(str, (char**)string, (GLint*)length, count); |
| |
| // TODO: pre-process str before calling replaceSamplerExternalWith2D(). |
| // Perhaps we can borrow Mesa's pre-processor? |
| |
| if (!replaceSamplerExternalWith2D(str, shaderData)) { |
| delete[] str; |
| ctx->setError(GL_OUT_OF_MEMORY); |
| return; |
| } |
| ctx->glShaderString(ctx, shader, str, len + 1); |
| delete[] str; |
| } |
| |
| void GL2Encoder::s_glFinish(void *self) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| ctx->glFinishRoundTrip(self); |
| } |
| |
| void GL2Encoder::s_glLinkProgram(void * self, GLuint program) |
| { |
| GL2Encoder *ctx = (GL2Encoder *)self; |
| bool isProgram = ctx->m_shared->isProgram(program); |
| SET_ERROR_IF(!isProgram && !ctx->m_shared->isShader(program), GL_INVALID_VALUE); |
| SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION); |
| |
| if (program == ctx->m_state->currentProgram() || |
| (!ctx->m_state->currentProgram() && |
| (program == ctx->m_state->currentShaderProgram()))) { |
| SET_ERROR_IF(ctx->m_state->getTransformFeedbackActive(), GL_INVALID_OPERATION); |
| } |
| |
| ctx->m_glLinkProgram_enc(self, program); |
| |
| GLint linkStatus = 0; |
| ctx->m_glGetProgramiv_enc(self, program, GL_LINK_STATUS, &linkStatus); |
| ctx->m_shared->setProgramLinkStatus(program, linkStatus); |
| if (!linkStatus) { |
| return; |
| } |
| |
| // get number of active uniforms and attributes in the program |
| GLint numUniforms=0; |
| GLint numAttributes=0; |
| ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_UNIFORMS, &numUniforms); |
| ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_ATTRIBUTES, &numAttributes); |
| ctx->m_shared->initProgramData(program,numUniforms,numAttributes); |
| |
| //get the length of the longest uniform name |
| GLint maxLength=0; |
| GLint maxAttribLength=0; |
| ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); |
| ctx->m_glGetProgramiv_enc(self, program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLength); |
| |
| GLint size; |
| GLenum type; |
| size_t bufLen = maxLength > maxAttribLength ? maxLength : maxAttribLength; |
| GLchar *name = new GLchar[bufLen + 1]; |
| GLint location; |
| //for each active uniform, get its size and starting location. |
| for (GLint i=0 ; i<numUniforms ; ++i) |
| { |
| ctx->m_glGetActiveUniform_enc(self, program, i, maxLength, NULL, &size, &type, name); |
| location = ctx->m_glGetUniformLocation_enc(self, program, name); |
| ctx->m_shared->setProgramIndexInfo(program, i, location, size, type, name); |
| } |
| |
| for (GLint i = 0; i < numAttributes; ++i) { |
| ctx->m_glGetActiveAttrib_enc(self, program, i, maxAttribLength, NULL, &size, &type, name); |
| location = ctx->m_glGetAttribLocation_enc(self, program, name); |
| ctx->m_shared->setProgramAttribInfo(program, i, location, size, type, name); |
| } |
| |
| if (ctx->majorVersion() > 2) { |
| GLint numBlocks; |
| ctx->m_glGetProgramiv_enc(ctx, program, GL_ACTIVE_UNIFORM_BLOCKS, &numBlocks); |
| ctx->m_shared->setActiveUniformBlockCountForProgram(program, numBlocks); |
| |
| GLint tfVaryingsCount; |
| ctx->m_glGetProgramiv_enc(ctx, program, GL_TRANSFORM_FEEDBACK_VARYINGS, &tfVaryingsCount); |
| ctx->m_shared->setTransformFeedbackVaryingsCountForProgram(program, tfVaryingsCount); |
| } |
| |
| delete[] name; |
| } |
| |
| #define VALIDATE_PROGRAM_NAME(program) \ |
| bool isShaderOrProgramObject = \ |
| ctx->m_shared->isShaderOrProgramObject(program); \ |
| bool isProgram = \ |
| ctx->m_shared->isProgram(program); \ |
| SET_ERROR_IF(!isShaderOrProgramObject, GL_INVALID_VALUE); \ |
| SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION); \ |
| |
| #define VALIDATE_PROGRAM_NAME_RET(program, ret) \ |
| bool isShaderOrProgramObject = \ |
| ctx->m_shared->isShaderOrProgramObject(program); \ |
| bool isProgram = \ |
| ctx->m_shared->isProgram(program); \ |
| RET_AND_SET_ERROR_IF(!isShaderOrProgramObject, GL_INVALID_VALUE, ret); \ |
| RET_AND_SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION, ret); \ |
| |
| #define VALIDATE_SHADER_NAME(shader) \ |
| bool isShaderOrProgramObject = \ |
| ctx->m_shared->isShaderOrProgramObject(shader); \ |
| bool isShader = \ |
| ctx->m_shared->isShader(shader); \ |
| SET_ERROR_IF(!isShaderOrProgramObject, GL_INVALID_VALUE); \ |
| SET_ERROR_IF(!isShader, GL_INVALID_OPERATION); \ |
| |
| void GL2Encoder::s_glDeleteProgram(void *self, GLuint program) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| |
| VALIDATE_PROGRAM_NAME(program); |
| |
| ctx->m_glDeleteProgram_enc(self, program); |
| |
| ctx->m_shared->deleteProgramData(program); |
| } |
| |
| void GL2Encoder::s_glGetUniformiv(void *self, GLuint program, GLint location, GLint* 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); |
| SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,location)==0, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!ctx->m_shared->isProgramUniformLocationValid(program,location), GL_INVALID_OPERATION); |
| ctx->m_glGetUniformiv_enc(self, program, location, params); |
| } |
| void GL2Encoder::s_glGetUniformfv(void *self, GLuint program, GLint location, GLfloat* 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); |
| SET_ERROR_IF(ctx->m_shared->getProgramUniformType(program,location)==0, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!ctx->m_shared->isProgramUniformLocationValid(program,location), GL_INVALID_OPERATION); |
| ctx->m_glGetUniformfv_enc(self, program, location, params); |
| } |
| |
| GLuint GL2Encoder::s_glCreateProgram(void * self) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| GLuint program = ctx->m_glCreateProgram_enc(self); |
| if (program!=0) |
| ctx->m_shared->addProgramData(program); |
| return program; |
| } |
| |
| GLuint GL2Encoder::s_glCreateShader(void *self, GLenum 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); |
| if (shader != 0) { |
| if (!ctx->m_shared->addShaderData(shader, shaderType)) { |
| ctx->m_glDeleteShader_enc(self, shader); |
| return 0; |
| } |
| } |
| return shader; |
| } |
| |
| void GL2Encoder::s_glGetAttachedShaders(void *self, GLuint program, GLsizei maxCount, |
| GLsizei* count, GLuint* shaders) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| VALIDATE_PROGRAM_NAME(program); |
| SET_ERROR_IF(maxCount < 0, GL_INVALID_VALUE); |
| ctx->m_glGetAttachedShaders_enc(self, program, maxCount, count, shaders); |
| } |
| |
| void GL2Encoder::s_glGetShaderSource(void *self, GLuint shader, GLsizei bufsize, |
| GLsizei* length, GLchar* source) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| VALIDATE_SHADER_NAME(shader); |
| SET_ERROR_IF(bufsize < 0, GL_INVALID_VALUE); |
| ctx->m_glGetShaderSource_enc(self, shader, bufsize, length, source); |
| ShaderData* shaderData = ctx->m_shared->getShaderData(shader); |
| if (shaderData) { |
| std::string returned; |
| int curr_len = 0; |
| for (int i = 0; i < shaderData->sources.size(); i++) { |
| if (curr_len + shaderData->sources[i].size() < bufsize - 1) { |
| returned += shaderData->sources[i]; |
| } else { |
| returned += shaderData->sources[i].substr(0, bufsize - 1 - curr_len); |
| break; |
| } |
| } |
| std::string ret = returned.substr(0, bufsize - 1); |
| |
| size_t toCopy = bufsize < (ret.size() + 1) ? bufsize : ret.size() + 1; |
| memcpy(source, ret.c_str(), toCopy); |
| } |
| } |
| |
| void GL2Encoder::s_glGetShaderInfoLog(void *self, GLuint shader, GLsizei bufsize, |
| GLsizei* length, GLchar* infolog) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| VALIDATE_SHADER_NAME(shader); |
| SET_ERROR_IF(bufsize < 0, GL_INVALID_VALUE); |
| ctx->m_glGetShaderInfoLog_enc(self, shader, bufsize, length, infolog); |
| } |
| |
| void GL2Encoder::s_glGetProgramInfoLog(void *self, GLuint program, GLsizei bufsize, |
| GLsizei* length, GLchar* infolog) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| VALIDATE_PROGRAM_NAME(program); |
| SET_ERROR_IF(bufsize < 0, GL_INVALID_VALUE); |
| ctx->m_glGetProgramInfoLog_enc(self, program, bufsize, length, infolog); |
| } |
| |
| void GL2Encoder::s_glDeleteShader(void *self, GLenum shader) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| |
| bool isShaderOrProgramObject = |
| ctx->m_shared->isShaderOrProgramObject(shader); |
| bool isShader = |
| ctx->m_shared->isShader(shader); |
| |
| SET_ERROR_IF(isShaderOrProgramObject && !isShader, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!isShaderOrProgramObject && !isShader, GL_INVALID_VALUE); |
| |
| ctx->m_glDeleteShader_enc(self,shader); |
| ctx->m_shared->unrefShaderData(shader); |
| } |
| |
| void GL2Encoder::s_glAttachShader(void *self, GLuint program, GLuint shader) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| bool programIsShaderOrProgram = ctx->m_shared->isShaderOrProgramObject(program); |
| bool programIsProgram = ctx->m_shared->isProgram(program); |
| bool shaderIsShaderOrProgram = ctx->m_shared->isShaderOrProgramObject(shader); |
| bool shaderIsShader = ctx->m_shared->isShader(shader); |
| |
| SET_ERROR_IF(!programIsShaderOrProgram, GL_INVALID_VALUE); |
| SET_ERROR_IF(!shaderIsShaderOrProgram, GL_INVALID_VALUE); |
| SET_ERROR_IF(!programIsProgram, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!shaderIsShader, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!ctx->m_shared->attachShader(program, shader), GL_INVALID_OPERATION); |
| |
| ctx->m_glAttachShader_enc(self, program, shader); |
| } |
| |
| void GL2Encoder::s_glDetachShader(void *self, GLuint program, GLuint shader) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| |
| bool programIsShaderOrProgram = ctx->m_shared->isShaderOrProgramObject(program); |
| bool programIsProgram = ctx->m_shared->isProgram(program); |
| bool shaderIsShaderOrProgram = ctx->m_shared->isShaderOrProgramObject(shader); |
| bool shaderIsShader = ctx->m_shared->isShader(shader); |
| |
| SET_ERROR_IF(!programIsShaderOrProgram, GL_INVALID_VALUE); |
| SET_ERROR_IF(!shaderIsShaderOrProgram, GL_INVALID_VALUE); |
| SET_ERROR_IF(!programIsProgram, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!shaderIsShader, GL_INVALID_OPERATION); |
| SET_ERROR_IF(!ctx->m_shared->detachShader(program, shader), GL_INVALID_OPERATION); |
| |
| ctx->m_glDetachShader_enc(self, program, shader); |
| } |
| |
| int sArrIndexOfUniformExpr(const char* name, int* err) { |
| *err = 0; |
| int arrIndex = 0; |
| int namelen = strlen(name); |
| if (name[namelen-1] == ']') { |
| const char *brace = strrchr(name,'['); |
| if (!brace || sscanf(brace+1,"%d",&arrIndex) != 1) { |
| *err = 1; return 0; |
| } |
| } |
| return arrIndex; |
| } |
| |
| int GL2Encoder::s_glGetUniformLocation(void *self, GLuint program, const GLchar *name) |
| { |
| if (!name) return -1; |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| |
| bool isShaderOrProgramObject = |
| ctx->m_shared->isShaderOrProgramObject(program); |
| bool isProgram = |
| ctx->m_shared->isProgram(program); |
| |
| RET_AND_SET_ERROR_IF(!isShaderOrProgramObject, GL_INVALID_VALUE, -1); |
| RET_AND_SET_ERROR_IF(!isProgram, GL_INVALID_OPERATION, -1); |
| RET_AND_SET_ERROR_IF(!ctx->m_shared->getProgramLinkStatus(program), GL_INVALID_OPERATION, -1); |
| |
| return ctx->m_glGetUniformLocation_enc(self, program, name); |
| } |
| |
| bool GL2Encoder::updateHostTexture2DBinding(GLenum texUnit, GLenum newTarget) |
| { |
| if (newTarget != GL_TEXTURE_2D && newTarget != GL_TEXTURE_EXTERNAL_OES) |
| return false; |
| |
| m_state->setActiveTextureUnit(texUnit); |
| |
| GLenum oldTarget = m_state->getPriorityEnabledTarget(GL_TEXTURE_2D); |
| if (newTarget != oldTarget) { |
| if (newTarget == GL_TEXTURE_EXTERNAL_OES) { |
| m_state->disableTextureTarget(GL_TEXTURE_2D); |
| m_state->enableTextureTarget(GL_TEXTURE_EXTERNAL_OES); |
| } else { |
| m_state->disableTextureTarget(GL_TEXTURE_EXTERNAL_OES); |
| m_state->enableTextureTarget(GL_TEXTURE_2D); |
| } |
| m_glActiveTexture_enc(this, texUnit); |
| m_glBindTexture_enc(this, GL_TEXTURE_2D, |
| m_state->getBoundTexture(newTarget)); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void GL2Encoder::updateHostTexture2DBindingsFromProgramData(GLuint program) { |
| GL2Encoder *ctx = this; |
| GLClientState* state = ctx->m_state; |
| GLSharedGroupPtr shared = ctx->m_shared; |
| |
| GLenum origActiveTexture = state->getActiveTextureUnit(); |
| GLenum hostActiveTexture = origActiveTexture; |
| GLint samplerIdx = -1; |
| GLint samplerVal; |
| GLenum samplerTarget; |
| while ((samplerIdx = shared->getNextSamplerUniform(program, samplerIdx, &samplerVal, &samplerTarget)) != -1) { |
| if (samplerVal < 0 || samplerVal >= GLClientState::MAX_TEXTURE_UNITS) |
| continue; |
| if (ctx->updateHostTexture2DBinding(GL_TEXTURE0 + samplerVal, |
| samplerTarget)) |
| { |
| hostActiveTexture = GL_TEXTURE0 + samplerVal; |
| } |
| } |
| state->setActiveTextureUnit(origActiveTexture); |
| if (hostActiveTexture != origActiveTexture) { |
| ctx->m_glActiveTexture_enc(ctx, origActiveTexture); |
| } |
| } |
| |
| void GL2Encoder::s_glUseProgram(void *self, GLuint program) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| GLSharedGroupPtr shared = ctx->m_shared; |
| |
| SET_ERROR_IF(program && !shared->isShaderOrProgramObject(program), GL_INVALID_VALUE); |
| SET_ERROR_IF(program && !shared->isProgram(program), GL_INVALID_OPERATION); |
| SET_ERROR_IF(ctx->m_state->getTransformFeedbackActiveUnpaused(), GL_INVALID_OPERATION); |
| |
| ctx->m_glUseProgram_enc(self, program); |
| |
| GLuint currProgram = ctx->m_state->currentProgram(); |
| ctx->m_shared->onUseProgram(currProgram, program); |
| |
| ctx->m_state->setCurrentProgram(program); |
| ctx->m_state->setCurrentShaderProgram(program); |
| ctx->updateHostTexture2DBindingsFromProgramData(program); |
| |
| if (program) { |
| ctx->m_state->currentUniformValidationInfo = ctx->m_shared->getUniformValidationInfo(program); |
| ctx->m_state->currentAttribValidationInfo = ctx->m_shared->getAttribValidationInfo(program); |
| } |
| } |
| |
| void GL2Encoder::s_glUniform1f(void *self , GLint location, GLfloat x) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 1 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform1f_enc(self, location, x); |
| } |
| |
| void GL2Encoder::s_glUniform1fv(void *self , GLint location, GLsizei count, const GLfloat* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 1 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform1fv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform1i(void *self , GLint location, GLint x) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| GLClientState* state = ctx->m_state; |
| GLSharedGroupPtr shared = ctx->m_shared; |
| |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 1 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| |
| ctx->m_glUniform1i_enc(self, location, x); |
| |
| GLenum 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); |
| } |
| state->setActiveTextureUnit(origActiveTexture); |
| } |
| } |
| |
| void GL2Encoder::s_glUniform1iv(void *self , GLint location, GLsizei count, const GLint* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 1 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform1iv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform2f(void *self , GLint location, GLfloat x, GLfloat y) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 2 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform2f_enc(self, location, x, y); |
| } |
| |
| void GL2Encoder::s_glUniform2fv(void *self , GLint location, GLsizei count, const GLfloat* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 2 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform2fv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform2i(void *self , GLint location, GLint x, GLint y) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 2 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform2i_enc(self, location, x, y); |
| } |
| |
| void GL2Encoder::s_glUniform2iv(void *self , GLint location, GLsizei count, const GLint* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 2 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform2iv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform3f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 3 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform3f_enc(self, location, x, y, z); |
| } |
| |
| void GL2Encoder::s_glUniform3fv(void *self , GLint location, GLsizei count, const GLfloat* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 3 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform3fv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform3i(void *self , GLint location, GLint x, GLint y, GLint z) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 3 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform3i_enc(self, location, x, y, z); |
| } |
| |
| void GL2Encoder::s_glUniform3iv(void *self , GLint location, GLsizei count, const GLint* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 3 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform3iv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform4f(void *self , GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 4 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform4f_enc(self, location, x, y, z, w); |
| } |
| |
| void GL2Encoder::s_glUniform4fv(void *self , GLint location, GLsizei count, const GLfloat* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 4 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform4fv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniform4i(void *self , GLint location, GLint x, GLint y, GLint z, GLint w) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 4 /* columns */, 1 /* rows */, location, 1 /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform4i_enc(self, location, x, y, z, w); |
| } |
| |
| void GL2Encoder::s_glUniform4iv(void *self , GLint location, GLsizei count, const GLint* v) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(false /* is float? */, false /* is unsigned? */, 4 /* columns */, 1 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniform4iv_enc(self, location, count, v); |
| } |
| |
| void GL2Encoder::s_glUniformMatrix2fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 2 /* columns */, 2 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniformMatrix2fv_enc(self, location, count, transpose, value); |
| } |
| |
| void GL2Encoder::s_glUniformMatrix3fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 3 /* columns */, 3 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniformMatrix3fv_enc(self, location, count, transpose, value); |
| } |
| |
| void GL2Encoder::s_glUniformMatrix4fv(void *self , GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) |
| { |
| GL2Encoder *ctx = (GL2Encoder*)self; |
| ctx->m_state->validateUniform(true /* is float? */, false /* is unsigned? */, 4 /* columns */, 4 /* rows */, location, count /* count */, ctx->getErrorPtr()); |
| ctx->m_glUniformMatrix4fv_enc(self, location, count, transpose, value); |
| } |
| |
| void GL2Encoder::s_glActiveTexture(void* self, GLenum texture) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| GLClientState* state = ctx->m_state; |
| GLenum err; |
| |
| GLint maxCombinedUnits; |
| ctx->glGetIntegerv(ctx, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedUnits); |
| |
| SET_ERROR_IF(texture - GL_TEXTURE0 > maxCombinedUnits - 1, GL_INVALID_ENUM); |
| SET_ERROR_IF((err = state->setActiveTextureUnit(texture)) != GL_NO_ERROR, err); |
| |
| ctx->m_glActiveTexture_enc(ctx, texture); |
| } |
| |
| void GL2Encoder::s_glBindTexture(void* self, GLenum target, GLuint texture) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| GLClientState* state = ctx->m_state; |
| GLenum err; |
| GLboolean firstUse; |
| |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF((err = state->bindTexture(target, texture, &firstUse)) != GL_NO_ERROR, err); |
| |
| if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) { |
| ctx->m_glBindTexture_enc(ctx, target, texture); |
| return; |
| } |
| |
| GLenum priorityTarget = state->getPriorityEnabledTarget(GL_TEXTURE_2D); |
| |
| if (target == GL_TEXTURE_EXTERNAL_OES && firstUse) { |
| ctx->m_glBindTexture_enc(ctx, GL_TEXTURE_2D, texture); |
| ctx->m_glTexParameteri_enc(ctx, GL_TEXTURE_2D, |
| GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| ctx->m_glTexParameteri_enc(ctx, GL_TEXTURE_2D, |
| GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| ctx->m_glTexParameteri_enc(ctx, GL_TEXTURE_2D, |
| GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| |
| if (target != priorityTarget) { |
| ctx->m_glBindTexture_enc(ctx, GL_TEXTURE_2D, |
| state->getBoundTexture(GL_TEXTURE_2D)); |
| } |
| } |
| |
| if (target == priorityTarget) { |
| ctx->m_glBindTexture_enc(ctx, GL_TEXTURE_2D, texture); |
| } |
| } |
| |
| void GL2Encoder::s_glDeleteTextures(void* self, GLsizei n, const GLuint* textures) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| GLClientState* state = ctx->m_state; |
| |
| state->deleteTextures(n, textures); |
| ctx->m_glDeleteTextures_enc(ctx, n, textures); |
| } |
| |
| void GL2Encoder::s_glGetTexParameterfv(void* self, |
| GLenum target, GLenum pname, GLfloat* params) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParams(ctx, pname), GL_INVALID_ENUM); |
| if (!params) return; |
| |
| if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) { |
| ctx->override2DTextureTarget(target); |
| ctx->m_glGetTexParameterfv_enc(ctx, GL_TEXTURE_2D, pname, params); |
| ctx->restore2DTextureTarget(target); |
| } else { |
| ctx->m_glGetTexParameterfv_enc(ctx, target, pname, params); |
| } |
| } |
| |
| void GL2Encoder::s_glGetTexParameteriv(void* self, |
| GLenum target, GLenum pname, GLint* params) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParams(ctx, pname), GL_INVALID_ENUM); |
| |
| if (!params) return; |
| |
| switch (pname) { |
| case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES: |
| *params = 1; |
| break; |
| |
| default: |
| if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) { |
| ctx->override2DTextureTarget(target); |
| ctx->m_glGetTexParameteriv_enc(ctx, GL_TEXTURE_2D, pname, params); |
| ctx->restore2DTextureTarget(target); |
| } else { |
| ctx->m_glGetTexParameteriv_enc(ctx, target, pname, params); |
| } |
| break; |
| } |
| } |
| |
| static bool isValidTextureExternalParam(GLenum pname, GLenum param) |
| { |
| switch (pname) { |
| case GL_TEXTURE_MIN_FILTER: |
| case GL_TEXTURE_MAG_FILTER: |
| return param == GL_NEAREST || param == GL_LINEAR; |
| |
| case GL_TEXTURE_WRAP_S: |
| case GL_TEXTURE_WRAP_T: |
| return param == GL_CLAMP_TO_EDGE; |
| |
| default: |
| return true; |
| } |
| } |
| |
| void GL2Encoder::s_glTexParameterf(void* self, |
| GLenum target, GLenum pname, GLfloat param) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| |
| SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES && |
| !isValidTextureExternalParam(pname, (GLenum)param)), |
| GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParams(ctx, pname), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParamValue(ctx, pname, (GLint)param, param, (GLenum)param), GL_INVALID_ENUM); |
| |
| if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) { |
| ctx->override2DTextureTarget(target); |
| ctx->m_glTexParameterf_enc(ctx, GL_TEXTURE_2D, pname, param); |
| ctx->restore2DTextureTarget(target); |
| } else { |
| ctx->m_glTexParameterf_enc(ctx, target, pname, param); |
| } |
| } |
| |
| void GL2Encoder::s_glTexParameterfv(void* self, |
| GLenum target, GLenum pname, const GLfloat* params) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| |
| SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES && |
| !isValidTextureExternalParam(pname, (GLenum)params[0])), |
| GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParams(ctx, pname), GL_INVALID_ENUM); |
| SET_ERROR_IF(!params, GL_INVALID_VALUE); |
| GLfloat param = *params; |
| SET_ERROR_IF(!GLESv2Validation::textureParamValue(ctx, pname, (GLint)param, param, (GLenum)param), GL_INVALID_ENUM); |
| |
| if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) { |
| ctx->override2DTextureTarget(target); |
| ctx->m_glTexParameterfv_enc(ctx, GL_TEXTURE_2D, pname, params); |
| ctx->restore2DTextureTarget(target); |
| } else { |
| ctx->m_glTexParameterfv_enc(ctx, target, pname, params); |
| } |
| } |
| |
| void GL2Encoder::s_glTexParameteri(void* self, |
| GLenum target, GLenum pname, GLint param) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| |
| SET_ERROR_IF((target == GL_TEXTURE_EXTERNAL_OES && |
| !isValidTextureExternalParam(pname, (GLenum)param)), |
| GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureTarget(ctx, target), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParams(ctx, pname), GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validation::textureParamValue(ctx, pname, param, (GLfloat)param, (GLenum)param), GL_INVALID_ENUM); |
| |
| if (target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES) { |
| ctx->override2DTextureTarget(target); |
| ctx->m_glTexParameteri_enc(ctx, GL_TEXTURE_2D, pname, param); |
| ctx->restore2DTextureTarget(target); |
| } else { |
| ctx->m_glTexParameteri_enc(ctx, target, pname, param); |
| } |
| } |
| |
| bool GL2Encoder::validateTexBuffer(void* self, GLenum target, GLenum internalFormat, GLuint buffer) { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| RET_AND_SET_ERROR_IF((target != GL_TEXTURE_BUFFER_OES), GL_INVALID_ENUM, false); |
| RET_AND_SET_ERROR_IF(!GLESv2Validation::textureBufferFormat(ctx, internalFormat), GL_INVALID_ENUM, false); |
| RET_AND_SET_ERROR_IF(buffer != 0 && !ctx->getBufferDataById(buffer), GL_INVALID_OPERATION, false); |
| return true; |
| } |
| |
| bool GL2Encoder::validateTexBufferRange(void* self, GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| RET_AND_SET_ERROR_IF((target != GL_TEXTURE_BUFFER_OES), GL_INVALID_ENUM, false); |
| RET_AND_SET_ERROR_IF(!GLESv2Validation::textureBufferFormat(ctx, internalFormat), GL_INVALID_ENUM, false); |
| if (buffer != 0) { |
| BufferData* buf = ctx->getBufferDataById(buffer); |
| RET_AND_SET_ERROR_IF(((!buf) || (buf->m_size < offset+size) || (offset < 0) || (size<0)), GL_INVALID_VALUE, false); |
| } |
| GLint tex_buffer_offset_align = 1; |
| ctx->s_glGetIntegerv(ctx, GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT_OES, &tex_buffer_offset_align); |
| RET_AND_SET_ERROR_IF((offset % tex_buffer_offset_align) != 0, GL_INVALID_VALUE, false); |
| return true; |
| } |
| |
| void GL2Encoder::s_glTexBufferOES(void* self, |
| GLenum target, GLenum internalFormat, GLuint buffer) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().textureBufferOES, GL_INVALID_OPERATION); |
| if(!validateTexBuffer(ctx, target, internalFormat, buffer)) return; |
| GLClientState* state = ctx->m_state; |
| state->setBoundTextureInternalFormat(target, internalFormat); |
| ctx->m_glTexBufferOES_enc(ctx, target, internalFormat, buffer); |
| } |
| |
| |
| void GL2Encoder::s_glTexBufferRangeOES(void* self, |
| GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size) { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().textureBufferOES, GL_INVALID_OPERATION); |
| if(!validateTexBufferRange(ctx, target, internalFormat, buffer, offset, size)) return; |
| GLClientState* state = ctx->m_state; |
| state->setBoundTextureInternalFormat(target, internalFormat); |
| ctx->m_glTexBufferRangeOES_enc(ctx, target, internalFormat, buffer, offset, size); |
| } |
| |
| void GL2Encoder::s_glTexBufferEXT(void* self, |
| GLenum target, GLenum internalFormat, GLuint buffer) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().textureBufferEXT, GL_INVALID_OPERATION); |
| if(!validateTexBuffer(ctx, target, internalFormat, buffer)) return; |
| GLClientState* state = ctx->m_state; |
| state->setBoundTextureInternalFormat(target, internalFormat); |
| ctx->m_glTexBufferEXT_enc(ctx, target, internalFormat, buffer); |
| } |
| |
| |
| void GL2Encoder::s_glTexBufferRangeEXT(void* self, |
| GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size) { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().textureBufferEXT, GL_INVALID_OPERATION); |
| if(!validateTexBufferRange(ctx, target, internalFormat, buffer, offset, size)) return; |
| GLClientState* state = ctx->m_state; |
| state->setBoundTextureInternalFormat(target, internalFormat); |
| ctx->m_glTexBufferRangeEXT_enc(ctx, target, internalFormat, buffer, offset, size); |
| } |
| |
| bool GL2Encoder::validateAllowedEnablei(void* self, GLenum cap, GLuint index) { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| switch(cap) |
| { |
| case GL_BLEND: |
| RET_AND_SET_ERROR_IF(index >= ctx->m_state->getMaxDrawBuffers(), GL_INVALID_VALUE, false); |
| break; |
| default: |
| RET_AND_SET_ERROR_IF(false, GL_INVALID_ENUM, false); |
| } |
| return true; |
| } |
| |
| void GL2Encoder::s_glEnableiEXT(void * self, GLenum cap, GLuint index) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().drawBuffersIndexedEXT, GL_INVALID_OPERATION); |
| if(!validateAllowedEnablei(ctx, cap, index)) return; |
| ctx->m_glEnableiEXT_enc(ctx, cap, index); |
| } |
| |
| void GL2Encoder::s_glDisableiEXT(void* self, GLenum cap, GLuint index) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().drawBuffersIndexedEXT, GL_INVALID_OPERATION); |
| if(!validateAllowedEnablei(ctx, cap, index)) return; |
| ctx->m_glDisableiEXT_enc(ctx, cap, index); |
| } |
| |
| void GL2Encoder::s_glBlendEquationiEXT(void* self, GLuint buf, GLenum mode) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().drawBuffersIndexedEXT, GL_INVALID_OPERATION); |
| SET_ERROR_IF(buf >= ctx->m_state->getMaxDrawBuffers(), GL_INVALID_VALUE); |
| SET_ERROR_IF( |
| !GLESv2Validation::allowedBlendEquation(mode), |
| GL_INVALID_ENUM); |
| ctx->m_glBlendEquationiEXT_enc(ctx, buf, mode); |
| } |
| |
| void GL2Encoder::s_glBlendEquationSeparateiEXT(void* self, GLuint buf, GLenum modeRGB, GLenum modeAlpha) |
| { |
| GL2Encoder* ctx = (GL2Encoder*)self; |
| SET_ERROR_IF(!ctx->getExtensions().drawBuffersIndexedEXT, GL_INVALID_OPERATION); |
|