| /* |
| * 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. |
| */ |
| |
| #ifdef _WIN32 |
| #undef GL_APICALL |
| #define GL_API __declspec(dllexport) |
| #define GL_APICALL __declspec(dllexport) |
| #endif |
| |
| #define GL_GLEXT_PROTOTYPES |
| #include <GLES2/gl2.h> |
| #include <GLES2/gl2ext.h> |
| #include <GLES3/gl3.h> |
| |
| #include <OpenglCodecCommon/ErrorLog.h> |
| #include <GLcommon/TranslatorIfaces.h> |
| #include "GLESv2Context.h" |
| #include "GLESv2Validate.h" |
| #include "ShaderParser.h" |
| #include "ProgramData.h" |
| #include <GLcommon/TextureUtils.h> |
| #include <GLcommon/FramebufferData.h> |
| |
| #include "ANGLEShaderParser.h" |
| |
| #include <stdio.h> |
| |
| #include <unordered_map> |
| |
| extern "C" { |
| |
| //decleration |
| static void initGLESx(); |
| static void initContext(GLEScontext* ctx,ShareGroupPtr grp); |
| static void deleteGLESContext(GLEScontext* ctx); |
| static void setShareGroup(GLEScontext* ctx,ShareGroupPtr grp); |
| static GLEScontext* createGLESContext(); |
| static __translatorMustCastToProperFunctionPointerType getProcAddress(const char* procName); |
| |
| } |
| |
| /************************************** GLES EXTENSIONS *********************************************************/ |
| typedef std::unordered_map<std::string, __translatorMustCastToProperFunctionPointerType> ProcTableMap; |
| ProcTableMap *s_glesExtensions = NULL; |
| /****************************************************************************************************************/ |
| |
| static EGLiface* s_eglIface = NULL; |
| static GLESiface s_glesIface = { |
| .initGLESx = initGLESx, |
| .createGLESContext = createGLESContext, |
| .initContext = initContext, |
| .deleteGLESContext = deleteGLESContext, |
| .flush = (FUNCPTR_NO_ARGS_RET_VOID)glFlush, |
| .finish = (FUNCPTR_NO_ARGS_RET_VOID)glFinish, |
| .setShareGroup = setShareGroup, |
| .getProcAddress = getProcAddress, |
| .fenceSync = (FUNCPTR_FENCE_SYNC)glFenceSync, |
| .clientWaitSync = (FUNCPTR_CLIENT_WAIT_SYNC)glClientWaitSync, |
| .deleteSync = (FUNCPTR_DELETE_SYNC)glDeleteSync, |
| }; |
| |
| #include <GLcommon/GLESmacros.h> |
| |
| extern "C" { |
| |
| static void initGLESx() { |
| ANGLEShaderParser::globalInitialize(); |
| } |
| |
| static void initContext(GLEScontext* ctx,ShareGroupPtr grp) { |
| if (!ctx->isInitialized()) { |
| ctx->setShareGroup(grp); |
| ctx->init(s_eglIface->eglGetGlLibrary()); |
| glBindTexture(GL_TEXTURE_2D,0); |
| glBindTexture(GL_TEXTURE_CUBE_MAP,0); |
| } |
| } |
| static GLEScontext* createGLESContext() { |
| return new GLESv2Context(); |
| } |
| |
| static void deleteGLESContext(GLEScontext* ctx) { |
| delete ctx; |
| } |
| |
| static void setShareGroup(GLEScontext* ctx,ShareGroupPtr grp) { |
| if(ctx) { |
| ctx->setShareGroup(grp); |
| } |
| } |
| |
| static __translatorMustCastToProperFunctionPointerType getProcAddress(const char* procName) { |
| GET_CTX_RET(NULL) |
| ctx->getGlobalLock(); |
| static bool proc_table_initialized = false; |
| if (!proc_table_initialized) { |
| proc_table_initialized = true; |
| if (!s_glesExtensions) |
| s_glesExtensions = new ProcTableMap(); |
| else |
| s_glesExtensions->clear(); |
| (*s_glesExtensions)["glEGLImageTargetTexture2DOES"] = (__translatorMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES; |
| (*s_glesExtensions)["glEGLImageTargetRenderbufferStorageOES"]=(__translatorMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES; |
| } |
| __translatorMustCastToProperFunctionPointerType ret=NULL; |
| ProcTableMap::iterator val = s_glesExtensions->find(procName); |
| if (val!=s_glesExtensions->end()) |
| ret = val->second; |
| ctx->releaseGlobalLock(); |
| |
| return ret; |
| } |
| |
| GL_APICALL GLESiface* GL_APIENTRY __translator_getIfaces(EGLiface* eglIface); |
| |
| GLESiface* __translator_getIfaces(EGLiface* eglIface) { |
| s_eglIface = eglIface; |
| return & s_glesIface; |
| } |
| |
| } // extern "C" |
| |
| static void s_attachShader(GLEScontext* ctx, GLuint program, GLuint shader, |
| ShaderParser* shaderParser) { |
| if (ctx && program && shader && shaderParser) { |
| shaderParser->attachProgram(program); |
| } |
| } |
| |
| static void s_detachShader(GLEScontext* ctx, GLuint program, GLuint shader) { |
| if (ctx && shader && ctx->shareGroup().get()) { |
| auto shaderData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| if (!shaderData) return; |
| ShaderParser* shaderParser = (ShaderParser*)shaderData; |
| shaderParser->detachProgram(program); |
| if (shaderParser->getDeleteStatus() |
| && !shaderParser->hasAttachedPrograms()) { |
| ctx->shareGroup()->deleteName(NamedObjectType::SHADER_OR_PROGRAM, shader); |
| } |
| } |
| } |
| |
| static ObjectLocalName TextureLocalName(GLenum target,unsigned int tex) { |
| GET_CTX_RET(0); |
| return (tex!=0? tex : ctx->getDefaultTextureName(target)); |
| } |
| |
| static TextureData* getTextureData(ObjectLocalName tex) { |
| GET_CTX_RET(NULL); |
| TextureData *texData = NULL; |
| auto objData = |
| ctx->shareGroup()->getObjectData(NamedObjectType::TEXTURE, tex); |
| if(!objData){ |
| texData = new TextureData(); |
| ctx->shareGroup()->setObjectData(NamedObjectType::TEXTURE, tex, |
| ObjectDataPtr(texData)); |
| } else { |
| texData = (TextureData*)objData; |
| } |
| return texData; |
| } |
| |
| static TextureData* getTextureTargetData(GLenum target){ |
| GET_CTX_RET(NULL); |
| unsigned int tex = ctx->getBindedTexture(target); |
| return getTextureData(TextureLocalName(target,tex)); |
| } |
| |
| GL_APICALL void GL_APIENTRY glActiveTexture(GLenum texture){ |
| GET_CTX_V2(); |
| SET_ERROR_IF (!GLESv2Validate::textureEnum(texture,ctx->getMaxCombinedTexUnits()),GL_INVALID_ENUM); |
| ctx->setActiveTexture(texture); |
| ctx->dispatcher().glActiveTexture(texture); |
| } |
| |
| GL_APICALL void GL_APIENTRY glAttachShader(GLuint program, GLuint shader){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE); |
| |
| auto programData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| auto shaderData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!shaderData || !programData ,GL_INVALID_OPERATION); |
| SET_ERROR_IF(!(shaderData->getDataType() ==SHADER_DATA) || |
| !(programData->getDataType()==PROGRAM_DATA) ,GL_INVALID_OPERATION); |
| |
| GLenum shaderType = ((ShaderParser*)shaderData)->getType(); |
| ProgramData* pData = (ProgramData*)programData; |
| SET_ERROR_IF((pData->getAttachedShader(shaderType)!=0), GL_INVALID_OPERATION); |
| pData->attachShader(shader,shaderType); |
| s_attachShader(ctx, program, shader, (ShaderParser*)shaderData); |
| ctx->dispatcher().glAttachShader(globalProgramName,globalShaderName); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const GLchar* name){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::attribName(name),GL_INVALID_OPERATION); |
| SET_ERROR_IF(!GLESv2Validate::attribIndex(index),GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| |
| ctx->dispatcher().glBindAttribLocation(globalProgramName,index,name); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::bufferTarget(target),GL_INVALID_ENUM); |
| //if buffer wasn't generated before,generate one |
| if (buffer && ctx->shareGroup().get() && |
| !ctx->shareGroup()->isObject(NamedObjectType::VERTEXBUFFER, buffer)) { |
| ctx->shareGroup()->genName(NamedObjectType::VERTEXBUFFER, buffer); |
| ctx->shareGroup()->setObjectData(NamedObjectType::VERTEXBUFFER, buffer, |
| ObjectDataPtr(new GLESbuffer())); |
| } |
| ctx->bindBuffer(target,buffer); |
| if (buffer) { |
| GLESbuffer* vbo = |
| (GLESbuffer*)ctx->shareGroup() |
| ->getObjectData(NamedObjectType::VERTEXBUFFER, buffer); |
| vbo->setBinded(); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::framebufferTarget(target),GL_INVALID_ENUM); |
| |
| GLuint globalFrameBufferName = framebuffer; |
| if(framebuffer && ctx->shareGroup().get()){ |
| globalFrameBufferName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::FRAMEBUFFER, framebuffer); |
| //if framebuffer wasn't generated before,generate one |
| if(!globalFrameBufferName){ |
| ctx->shareGroup()->genName(NamedObjectType::FRAMEBUFFER, |
| framebuffer); |
| ctx->shareGroup()->setObjectData( |
| NamedObjectType::FRAMEBUFFER, framebuffer, |
| ObjectDataPtr(new FramebufferData(framebuffer))); |
| globalFrameBufferName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::FRAMEBUFFER, framebuffer); |
| } |
| } |
| ctx->dispatcher().glBindFramebufferEXT(target,globalFrameBufferName); |
| |
| // update framebuffer binding state |
| ctx->setFramebufferBinding(framebuffer); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::renderbufferTarget(target),GL_INVALID_ENUM); |
| |
| GLuint globalRenderBufferName = renderbuffer; |
| if(renderbuffer && ctx->shareGroup().get()){ |
| globalRenderBufferName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::RENDERBUFFER, renderbuffer); |
| //if renderbuffer wasn't generated before,generate one |
| if(!globalRenderBufferName){ |
| ctx->shareGroup()->genName(NamedObjectType::RENDERBUFFER, |
| renderbuffer); |
| ctx->shareGroup()->setObjectData( |
| NamedObjectType::RENDERBUFFER, renderbuffer, |
| ObjectDataPtr(new RenderbufferData())); |
| globalRenderBufferName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::RENDERBUFFER, renderbuffer); |
| } |
| } |
| ctx->dispatcher().glBindRenderbufferEXT(target,globalRenderBufferName); |
| |
| // update renderbuffer binding state |
| ctx->setRenderbufferBinding(renderbuffer); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBindTexture(GLenum target, GLuint texture){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::textureTarget(target),GL_INVALID_ENUM) |
| |
| //for handling default texture (0) |
| ObjectLocalName localTexName = TextureLocalName(target,texture); |
| GLuint globalTextureName = localTexName; |
| if(ctx->shareGroup().get()){ |
| globalTextureName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::TEXTURE, localTexName); |
| //if texture wasn't generated before,generate one |
| if(!globalTextureName){ |
| ctx->shareGroup()->genName(NamedObjectType::TEXTURE, localTexName); |
| globalTextureName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::TEXTURE, localTexName); |
| } |
| |
| TextureData* texData = getTextureData(localTexName); |
| if (texData->target==0) |
| texData->target = target; |
| //if texture was already bound to another target |
| SET_ERROR_IF(ctx->GLTextureTargetToLocal(texData->target) != ctx->GLTextureTargetToLocal(target), GL_INVALID_OPERATION); |
| texData->wasBound = true; |
| } |
| |
| ctx->setBindedTexture(target,texture); |
| ctx->dispatcher().glBindTexture(target,globalTextureName); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha){ |
| GET_CTX(); |
| ctx->dispatcher().glBlendColor(red,green,blue,alpha); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBlendEquation( GLenum mode ){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::blendEquationMode(mode),GL_INVALID_ENUM) |
| ctx->dispatcher().glBlendEquation(mode); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::blendEquationMode(modeRGB) && GLESv2Validate::blendEquationMode(modeAlpha)),GL_INVALID_ENUM); |
| ctx->dispatcher().glBlendEquationSeparate(modeRGB,modeAlpha); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::blendSrc(sfactor) || !GLESv2Validate::blendDst(dfactor),GL_INVALID_ENUM) |
| ctx->dispatcher().glBlendFunc(sfactor,dfactor); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha){ |
| GET_CTX(); |
| SET_ERROR_IF( |
| !(GLESv2Validate::blendSrc(srcRGB) && GLESv2Validate::blendDst(dstRGB) && GLESv2Validate::blendSrc(srcAlpha) && GLESv2Validate::blendDst(dstAlpha)),GL_INVALID_ENUM); |
| ctx->dispatcher().glBlendFuncSeparate(srcRGB,dstRGB,srcAlpha,dstAlpha); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::bufferTarget(target),GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validate::bufferUsage(usage),GL_INVALID_ENUM); |
| SET_ERROR_IF(!ctx->isBindedBuffer(target),GL_INVALID_OPERATION); |
| ctx->setBufferData(target,size,data,usage); |
| } |
| |
| GL_APICALL void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data){ |
| GET_CTX(); |
| SET_ERROR_IF(!ctx->isBindedBuffer(target),GL_INVALID_OPERATION); |
| SET_ERROR_IF(!GLESv2Validate::bufferTarget(target),GL_INVALID_ENUM); |
| SET_ERROR_IF(!ctx->setBufferSubData(target,offset,size,data),GL_INVALID_VALUE); |
| } |
| |
| |
| GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target){ |
| GET_CTX_RET(GL_FRAMEBUFFER_COMPLETE); |
| RET_AND_SET_ERROR_IF(!GLESv2Validate::framebufferTarget(target),GL_INVALID_ENUM,GL_FRAMEBUFFER_COMPLETE); |
| ctx->drawValidate(); |
| return ctx->dispatcher().glCheckFramebufferStatusEXT(target); |
| } |
| |
| GL_APICALL void GL_APIENTRY glClear(GLbitfield mask){ |
| GET_CTX(); |
| GLbitfield allowed_bits = GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT; |
| GLbitfield has_disallowed_bits = (mask & ~allowed_bits); |
| SET_ERROR_IF(has_disallowed_bits, GL_INVALID_VALUE); |
| ctx->drawValidate(); |
| |
| ctx->dispatcher().glClear(mask); |
| } |
| GL_APICALL void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha){ |
| GET_CTX(); |
| ctx->dispatcher().glClearColor(red,green,blue,alpha); |
| } |
| GL_APICALL void GL_APIENTRY glClearDepthf(GLclampf depth){ |
| GET_CTX(); |
| ctx->dispatcher().glClearDepth(depth); |
| } |
| GL_APICALL void GL_APIENTRY glClearStencil(GLint s){ |
| GET_CTX(); |
| ctx->dispatcher().glClearStencil(s); |
| } |
| GL_APICALL void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha){ |
| GET_CTX(); |
| ctx->dispatcher().glColorMask(red,green,blue,alpha); |
| } |
| |
| GL_APICALL void GL_APIENTRY glCompileShader(GLuint shader){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(objData->getDataType()!= SHADER_DATA,GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| SET_ERROR_IF(sp->getDeleteStatus(), GL_INVALID_VALUE); |
| if (sp->validShader()) { |
| ctx->dispatcher().glCompileShader(globalShaderName); |
| |
| GLsizei infoLogLength=0; |
| GLchar* infoLog; |
| ctx->dispatcher().glGetShaderiv(globalShaderName,GL_INFO_LOG_LENGTH,&infoLogLength); |
| infoLog = new GLchar[infoLogLength+1]; |
| ctx->dispatcher().glGetShaderInfoLog(globalShaderName,infoLogLength,NULL,infoLog); |
| if (infoLogLength == 0) { |
| infoLog[0] = 0; |
| } |
| sp->setInfoLog(infoLog); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data) |
| { |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::textureTargetEx(target),GL_INVALID_ENUM); |
| SET_ERROR_IF(level < 0 || imageSize < 0, GL_INVALID_VALUE); |
| |
| doCompressedTexImage2D(ctx, target, level, internalformat, |
| width, height, border, |
| imageSize, data, (void*)glTexImage2D); |
| } |
| |
| GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::textureTargetEx(target),GL_INVALID_ENUM); |
| SET_ERROR_IF(!data,GL_INVALID_OPERATION); |
| ctx->dispatcher().glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data); |
| } |
| |
| void s_glInitTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border){ |
| GET_CTX(); |
| |
| if (ctx->shareGroup().get() && level == 0){ |
| TextureData *texData = getTextureTargetData(target); |
| if(texData) { |
| texData->width = width; |
| texData->height = height; |
| texData->border = border; |
| texData->internalFormat = internalformat; |
| texData->target = target; |
| |
| if (texData->sourceEGLImage != 0) { |
| // |
| // This texture was a target of EGLImage, |
| // but now it is re-defined so we need to |
| // re-generate global texture name for it. |
| // |
| unsigned int tex = ctx->getBindedTexture(target); |
| ctx->shareGroup()->genName(NamedObjectType::TEXTURE, tex, |
| false); |
| unsigned int globalTextureName = |
| ctx->shareGroup()->getGlobalName( |
| NamedObjectType::TEXTURE, tex); |
| ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, |
| globalTextureName); |
| texData->sourceEGLImage = 0; |
| } |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::pixelFrmt(ctx,internalformat) && GLESv2Validate::textureTargetEx(target)),GL_INVALID_ENUM); |
| SET_ERROR_IF((GLESv2Validate::textureIsCubeMap(target) && width != height), GL_INVALID_VALUE); |
| SET_ERROR_IF(border != 0,GL_INVALID_VALUE); |
| s_glInitTexImage2D(target,level,internalformat,width,height,border); |
| ctx->dispatcher().glCopyTexImage2D(target,level,internalformat,x,y,width,height,border); |
| } |
| |
| GL_APICALL void GL_APIENTRY glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::textureTargetEx(target),GL_INVALID_ENUM); |
| ctx->dispatcher().glCopyTexSubImage2D(target,level,xoffset,yoffset,x,y,width,height); |
| } |
| |
| GL_APICALL GLuint GL_APIENTRY glCreateProgram(void){ |
| GET_CTX_RET(0); |
| if(ctx->shareGroup().get()) { |
| ProgramData* programInfo = new ProgramData(); |
| const GLuint localProgramName = |
| ctx->shareGroup()->genName(ShaderProgramType::PROGRAM, 0, true); |
| ctx->shareGroup()->setObjectData(NamedObjectType::SHADER_OR_PROGRAM, |
| localProgramName, |
| ObjectDataPtr(programInfo)); |
| return localProgramName; |
| } |
| return 0; |
| } |
| |
| GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type){ |
| GET_CTX_V2_RET(0); |
| RET_AND_SET_ERROR_IF(!GLESv2Validate::shaderType(type),GL_INVALID_ENUM,0); |
| if(ctx->shareGroup().get()) { |
| ShaderProgramType shaderProgramType; |
| if (type == GL_VERTEX_SHADER) { |
| shaderProgramType = ShaderProgramType::VERTEX_SHADER; |
| } else { |
| shaderProgramType = ShaderProgramType::FRAGMENT_SHADER; |
| } |
| const GLuint localShaderName = ctx->shareGroup()->genName( |
| shaderProgramType, 0, true); |
| ShaderParser* sp = new ShaderParser(type); |
| ctx->shareGroup()->setObjectData(NamedObjectType::SHADER_OR_PROGRAM, |
| localShaderName, ObjectDataPtr(sp)); |
| return localShaderName; |
| } |
| return 0; |
| } |
| |
| GL_APICALL void GL_APIENTRY glCullFace(GLenum mode){ |
| GET_CTX(); |
| ctx->dispatcher().glCullFace(mode); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteBuffers(GLsizei n, const GLuint* buffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i < n; i++){ |
| ctx->shareGroup()->deleteName(NamedObjectType::VERTEXBUFFER, |
| buffers[i]); |
| ctx->unbindBuffer(buffers[i]); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n < 0, GL_INVALID_VALUE); |
| if (ctx->shareGroup().get()) { |
| for (int i = 0; i < n; i++) { |
| ctx->shareGroup()->deleteName(NamedObjectType::FRAMEBUFFER, |
| framebuffers[i]); |
| } |
| } |
| } |
| |
| static void s_detachFromFramebuffer(NamedObjectType bufferType, |
| GLuint texture) { |
| GET_CTX(); |
| GLuint fbName = ctx->getFramebufferBinding(); |
| if (!fbName) return; |
| auto fbObj = ctx->shareGroup()->getObjectData( |
| NamedObjectType::FRAMEBUFFER, fbName); |
| if (fbObj == NULL) return; |
| FramebufferData *fbData = (FramebufferData *)fbObj; |
| GLenum target; |
| const GLenum kAttachments[] = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}; |
| const size_t sizen = sizeof(kAttachments)/sizeof(GLenum); |
| for (size_t i = 0; i < sizen; ++i ) { |
| GLuint name = fbData->getAttachment(kAttachments[i], &target, NULL); |
| if (name != texture) continue; |
| if (NamedObjectType::TEXTURE == bufferType && |
| GLESv2Validate::textureTargetEx(target)) { |
| glFramebufferTexture2D(GL_FRAMEBUFFER, kAttachments[i], target, 0, 0); |
| } else if (NamedObjectType::RENDERBUFFER == bufferType && |
| GLESv2Validate::renderbufferTarget(target)) { |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, kAttachments[i], target, 0); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i < n; i++){ |
| ctx->shareGroup()->deleteName(NamedObjectType::RENDERBUFFER, |
| renderbuffers[i]); |
| s_detachFromFramebuffer(NamedObjectType::RENDERBUFFER, |
| renderbuffers[i]); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteTextures(GLsizei n, const GLuint* textures){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i < n; i++){ |
| if (textures[i]!=0) { |
| if (ctx->getBindedTexture(GL_TEXTURE_2D) == textures[i]) |
| ctx->setBindedTexture(GL_TEXTURE_2D,0); |
| if (ctx->getBindedTexture(GL_TEXTURE_CUBE_MAP) == textures[i]) |
| ctx->setBindedTexture(GL_TEXTURE_CUBE_MAP,0); |
| s_detachFromFramebuffer(NamedObjectType::TEXTURE, textures[i]); |
| ctx->shareGroup()->deleteName(NamedObjectType::TEXTURE, |
| textures[i]); |
| } |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteProgram(GLuint program){ |
| GET_CTX(); |
| if(program && ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!globalProgramName, GL_INVALID_VALUE); |
| |
| auto programData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!(programData->getDataType()==PROGRAM_DATA), |
| GL_INVALID_OPERATION); |
| ProgramData* pData = (ProgramData*)programData; |
| if (pData && pData->isInUse()) { |
| pData->setDeleteStatus(true); |
| return; |
| } |
| s_detachShader(ctx, program, pData->getAttachedVertexShader()); |
| s_detachShader(ctx, program, pData->getAttachedFragmentShader()); |
| |
| ctx->shareGroup()->deleteName(NamedObjectType::SHADER_OR_PROGRAM, program); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteShader(GLuint shader){ |
| GET_CTX(); |
| if(shader && ctx->shareGroup().get()) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!globalShaderName, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData ,GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType()!=SHADER_DATA,GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| SET_ERROR_IF(sp->getDeleteStatus(), GL_INVALID_VALUE); |
| if (sp->hasAttachedPrograms()) { |
| sp->setDeleteStatus(true); |
| } else { |
| ctx->shareGroup()->deleteName(NamedObjectType::SHADER_OR_PROGRAM, shader); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDepthFunc(GLenum func){ |
| GET_CTX(); |
| ctx->dispatcher().glDepthFunc(func); |
| } |
| GL_APICALL void GL_APIENTRY glDepthMask(GLboolean flag){ |
| GET_CTX(); |
| ctx->dispatcher().glDepthMask(flag); |
| } |
| GL_APICALL void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar){ |
| GET_CTX(); |
| ctx->dispatcher().glDepthRange(zNear,zFar); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDetachShader(GLuint program, GLuint shader){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE); |
| |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData,GL_INVALID_OPERATION); |
| SET_ERROR_IF(!(objData->getDataType()==PROGRAM_DATA) ,GL_INVALID_OPERATION); |
| |
| ProgramData* programData = (ProgramData*)objData; |
| SET_ERROR_IF(!programData->isAttached(shader),GL_INVALID_OPERATION); |
| programData->detachShader(shader); |
| |
| s_detachShader(ctx, program, shader); |
| |
| ctx->dispatcher().glDetachShader(globalProgramName,globalShaderName); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glDisable(GLenum cap){ |
| GET_CTX(); |
| ctx->dispatcher().glDisable(cap); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDisableVertexAttribArray(GLuint index){ |
| GET_CTX(); |
| SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE); |
| ctx->enableArr(index,false); |
| ctx->dispatcher().glDisableVertexAttribArray(index); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDrawArrays(GLenum mode, GLint first, GLsizei count){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(count < 0,GL_INVALID_VALUE) |
| SET_ERROR_IF(!GLESv2Validate::drawMode(mode),GL_INVALID_ENUM); |
| |
| ctx->drawValidate(); |
| |
| GLESConversionArrays tmpArrs; |
| ctx->setupArraysPointers(tmpArrs,first,count,0,NULL,true); |
| |
| if (ctx->needAtt0PreDrawValidation()) { |
| ctx->validateAtt0PreDraw(count); |
| } |
| |
| //Enable texture generation for GL_POINTS and gl_PointSize shader variable |
| //GLES2 assumes this is enabled by default, we need to set this state for GL |
| if (mode==GL_POINTS) { |
| ctx->dispatcher().glEnable(GL_POINT_SPRITE); |
| ctx->dispatcher().glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); |
| } |
| |
| ctx->dispatcher().glDrawArrays(mode,first,count); |
| |
| if (mode==GL_POINTS) { |
| ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); |
| ctx->dispatcher().glDisable(GL_POINT_SPRITE); |
| } |
| |
| ctx->validateAtt0PostDraw(); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* elementsIndices){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(count < 0,GL_INVALID_VALUE) |
| SET_ERROR_IF(!(GLESv2Validate::drawMode(mode) && GLESv2Validate::drawType(type)),GL_INVALID_ENUM); |
| |
| ctx->drawValidate(); |
| |
| const GLvoid* indices = elementsIndices; |
| if(ctx->isBindedBuffer(GL_ELEMENT_ARRAY_BUFFER)) { // if vbo is binded take the indices from the vbo |
| const unsigned char* buf = static_cast<unsigned char *>(ctx->getBindedBuffer(GL_ELEMENT_ARRAY_BUFFER)); |
| indices = buf + SafeUIntFromPointer(elementsIndices); |
| } |
| |
| GLESConversionArrays tmpArrs; |
| ctx->setupArraysPointers(tmpArrs,0,count,type,indices,false); |
| |
| if (ctx->needAtt0PreDrawValidation()) { |
| const unsigned int maxIndex = ctx->findMaxIndex(count, type, indices); |
| ctx->validateAtt0PreDraw(maxIndex); |
| } |
| |
| //See glDrawArrays |
| if (mode==GL_POINTS) { |
| ctx->dispatcher().glEnable(GL_POINT_SPRITE); |
| ctx->dispatcher().glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); |
| } |
| |
| ctx->dispatcher().glDrawElements(mode,count,type,indices); |
| |
| if (mode==GL_POINTS) { |
| ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); |
| ctx->dispatcher().glDisable(GL_POINT_SPRITE); |
| } |
| |
| ctx->validateAtt0PostDraw(); |
| } |
| |
| GL_APICALL void GL_APIENTRY glEnable(GLenum cap){ |
| GET_CTX(); |
| ctx->dispatcher().glEnable(cap); |
| } |
| |
| GL_APICALL void GL_APIENTRY glEnableVertexAttribArray(GLuint index){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE); |
| ctx->enableArr(index,true); |
| ctx->dispatcher().glEnableVertexAttribArray(index); |
| } |
| |
| GL_APICALL void GL_APIENTRY glFinish(void){ |
| GET_CTX(); |
| ctx->dispatcher().glFinish(); |
| } |
| GL_APICALL void GL_APIENTRY glFlush(void){ |
| GET_CTX(); |
| ctx->dispatcher().glFlush(); |
| } |
| |
| |
| GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::framebufferTarget(target) && |
| GLESv2Validate::renderbufferTarget(renderbuffertarget) && |
| GLESv2Validate::framebufferAttachment(attachment)),GL_INVALID_ENUM); |
| SET_ERROR_IF(!ctx->shareGroup().get(), GL_INVALID_OPERATION); |
| |
| GLuint globalRenderbufferName = 0; |
| ObjectDataPtr obj; |
| |
| // generate the renderbuffer object if not yet exist |
| if(renderbuffer) { |
| if (!ctx->shareGroup()->isObject(NamedObjectType::RENDERBUFFER, |
| renderbuffer)) { |
| ctx->shareGroup()->genName(NamedObjectType::RENDERBUFFER, |
| renderbuffer); |
| obj = ObjectDataPtr(new RenderbufferData()); |
| ctx->shareGroup()->setObjectData(NamedObjectType::RENDERBUFFER, |
| renderbuffer, obj); |
| } |
| else { |
| obj = ctx->shareGroup()->getObjectDataPtr( |
| NamedObjectType::RENDERBUFFER, renderbuffer); |
| } |
| |
| globalRenderbufferName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::RENDERBUFFER, renderbuffer); |
| } |
| |
| // Update the the current framebuffer object attachment state |
| GLuint fbName = ctx->getFramebufferBinding(); |
| auto fbObj = ctx->shareGroup()->getObjectData( |
| NamedObjectType::FRAMEBUFFER, fbName); |
| if (fbObj != NULL) { |
| FramebufferData *fbData = (FramebufferData *)fbObj; |
| fbData->setAttachment(attachment, renderbuffertarget, renderbuffer, obj); |
| } |
| |
| if (renderbuffer && obj.get() != NULL) { |
| RenderbufferData *rbData = (RenderbufferData *)obj.get(); |
| if (rbData->eglImageGlobalTexObject) { |
| // |
| // This renderbuffer object is an eglImage target |
| // attach the eglimage's texture instead the renderbuffer. |
| // |
| ctx->dispatcher().glFramebufferTexture2DEXT(target, |
| attachment, |
| GL_TEXTURE_2D, |
| rbData->eglImageGlobalTexObject->getGlobalName(), |
| 0); |
| return; |
| } |
| } |
| |
| ctx->dispatcher().glFramebufferRenderbufferEXT(target,attachment,renderbuffertarget,globalRenderbufferName); |
| } |
| |
| GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::framebufferTarget(target) && |
| GLESv2Validate::textureTargetEx(textarget) && |
| GLESv2Validate::framebufferAttachment(attachment)),GL_INVALID_ENUM); |
| SET_ERROR_IF(level != 0, GL_INVALID_VALUE); |
| SET_ERROR_IF(!ctx->shareGroup().get(), GL_INVALID_OPERATION); |
| |
| GLuint globalTextureName = 0; |
| |
| if(texture) { |
| if (!ctx->shareGroup()->isObject(NamedObjectType::TEXTURE, texture)) { |
| ctx->shareGroup()->genName(NamedObjectType::TEXTURE, texture); |
| } |
| ObjectLocalName texname = TextureLocalName(textarget,texture); |
| globalTextureName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::TEXTURE, texname); |
| } |
| |
| ctx->dispatcher().glFramebufferTexture2DEXT(target,attachment,textarget,globalTextureName,level); |
| |
| // Update the the current framebuffer object attachment state |
| GLuint fbName = ctx->getFramebufferBinding(); |
| auto fbObj = ctx->shareGroup()->getObjectData( |
| NamedObjectType::FRAMEBUFFER, fbName); |
| if (fbObj) { |
| FramebufferData *fbData = (FramebufferData *)fbObj; |
| fbData->setAttachment(attachment, textarget, |
| texture, ObjectDataPtr()); |
| } |
| } |
| |
| |
| GL_APICALL void GL_APIENTRY glFrontFace(GLenum mode){ |
| GET_CTX(); |
| ctx->dispatcher().glFrontFace(mode); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGenBuffers(GLsizei n, GLuint* buffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i<n ;i++) { |
| buffers[i] = ctx->shareGroup()->genName( |
| NamedObjectType::VERTEXBUFFER, 0, true); |
| //generating vbo object related to this buffer name |
| ctx->shareGroup()->setObjectData(NamedObjectType::VERTEXBUFFER, |
| buffers[i], |
| ObjectDataPtr(new GLESbuffer())); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGenerateMipmap(GLenum target){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESvalidate::textureTarget(target), GL_INVALID_ENUM); |
| if (ctx->shareGroup().get()) { |
| TextureData *texData = getTextureTargetData(target); |
| if (texData) { |
| unsigned int width = texData->width; |
| unsigned int height = texData->height; |
| // set error code if either the width or height is not a power of two. |
| SET_ERROR_IF(width == 0 || height == 0 || |
| (width & (width - 1)) != 0 || (height & (height - 1)) != 0, |
| GL_INVALID_OPERATION); |
| } |
| } |
| ctx->dispatcher().glGenerateMipmapEXT(target); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint* framebuffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i<n ;i++) { |
| framebuffers[i] = ctx->shareGroup()->genName( |
| NamedObjectType::FRAMEBUFFER, 0, true); |
| ctx->shareGroup()->setObjectData( |
| NamedObjectType::FRAMEBUFFER, framebuffers[i], |
| ObjectDataPtr(new FramebufferData(framebuffers[i]))); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint* renderbuffers){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i<n ;i++) { |
| renderbuffers[i] = ctx->shareGroup()->genName( |
| NamedObjectType::RENDERBUFFER, 0, true); |
| ctx->shareGroup()->setObjectData( |
| NamedObjectType::RENDERBUFFER, renderbuffers[i], |
| ObjectDataPtr(new RenderbufferData())); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGenTextures(GLsizei n, GLuint* textures){ |
| GET_CTX(); |
| SET_ERROR_IF(n<0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()) { |
| for(int i=0; i<n ;i++) { |
| textures[i] = ctx->shareGroup()->genName(NamedObjectType::TEXTURE, |
| 0, true); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ctx->dispatcher().glGetActiveAttrib(globalProgramName,index,bufsize,length,size,type,name); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ctx->dispatcher().glGetActiveUniform(globalProgramName,index,bufsize,length,size,type,name); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| ctx->dispatcher().glGetAttachedShaders(globalProgramName,maxcount,count,shaders); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| GLint numShaders=0; |
| ctx->dispatcher().glGetProgramiv(globalProgramName,GL_ATTACHED_SHADERS,&numShaders); |
| for(int i=0 ; i < maxcount && i<numShaders ;i++){ |
| shaders[i] = ctx->shareGroup()->getLocalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shaders[i]); |
| } |
| } |
| } |
| |
| GL_APICALL int GL_APIENTRY glGetAttribLocation(GLuint program, const GLchar* name){ |
| GET_CTX_RET(-1); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| RET_AND_SET_ERROR_IF(globalProgramName == 0, GL_INVALID_VALUE, -1); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| RET_AND_SET_ERROR_IF(objData->getDataType() != PROGRAM_DATA, |
| GL_INVALID_OPERATION, -1); |
| ProgramData* pData = (ProgramData*)objData; |
| RET_AND_SET_ERROR_IF(pData->getLinkStatus() != GL_TRUE, |
| GL_INVALID_OPERATION, -1); |
| return ctx->dispatcher().glGetAttribLocation(globalProgramName, name); |
| } |
| return -1; |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params){ |
| GET_CTX(); |
| |
| if (ctx->glGetBooleanv(pname,params)) |
| { |
| return; |
| } |
| |
| switch(pname) |
| { |
| case GL_SHADER_COMPILER: |
| case GL_SHADER_BINARY_FORMATS: |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| case GL_MAX_VERTEX_UNIFORM_VECTORS: |
| case GL_MAX_VARYING_VECTORS: |
| case GL_MAX_FRAGMENT_UNIFORM_VECTORS: |
| if(ctx->getCaps()->GL_ARB_ES2_COMPATIBILITY) |
| ctx->dispatcher().glGetBooleanv(pname,params); |
| else |
| { |
| GLint iparam; |
| glGetIntegerv(pname,&iparam); |
| *params = (iparam != 0); |
| } |
| break; |
| |
| default: |
| ctx->dispatcher().glGetBooleanv(pname,params); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::bufferTarget(target) && GLESv2Validate::bufferParam(pname)),GL_INVALID_ENUM); |
| SET_ERROR_IF(!ctx->isBindedBuffer(target),GL_INVALID_OPERATION); |
| switch(pname) { |
| case GL_BUFFER_SIZE: |
| ctx->getBufferSize(target,params); |
| break; |
| case GL_BUFFER_USAGE: |
| ctx->getBufferUsage(target,params); |
| break; |
| } |
| } |
| |
| |
| GL_APICALL GLenum GL_APIENTRY glGetError(void){ |
| GET_CTX_RET(GL_NO_ERROR) |
| GLenum err = ctx->getGLerror(); |
| if(err != GL_NO_ERROR) { |
| ctx->setGLerror(GL_NO_ERROR); |
| return err; |
| } |
| return ctx->dispatcher().glGetError(); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetFloatv(GLenum pname, GLfloat* params){ |
| GET_CTX(); |
| |
| if (ctx->glGetFloatv(pname,params)) { |
| return; |
| } |
| |
| GLint i; |
| |
| switch (pname) { |
| case GL_CURRENT_PROGRAM: |
| case GL_FRAMEBUFFER_BINDING: |
| case GL_RENDERBUFFER_BINDING: |
| glGetIntegerv(pname,&i); |
| *params = (GLfloat)i; |
| break; |
| case GL_NUM_COMPRESSED_TEXTURE_FORMATS: |
| *params = (GLfloat)getCompressedFormats(NULL); |
| break; |
| case GL_COMPRESSED_TEXTURE_FORMATS: |
| { |
| int nparams = getCompressedFormats(NULL); |
| if (nparams>0) { |
| int * iparams = new int[nparams]; |
| getCompressedFormats(iparams); |
| for (int i=0; i<nparams; i++) params[i] = (GLfloat)iparams[i]; |
| delete [] iparams; |
| } |
| } |
| break; |
| |
| case GL_SHADER_COMPILER: |
| case GL_SHADER_BINARY_FORMATS: |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| case GL_MAX_VERTEX_UNIFORM_VECTORS: |
| case GL_MAX_VARYING_VECTORS: |
| case GL_MAX_FRAGMENT_UNIFORM_VECTORS: |
| if(ctx->getCaps()->GL_ARB_ES2_COMPATIBILITY) |
| ctx->dispatcher().glGetFloatv(pname,params); |
| else |
| { |
| glGetIntegerv(pname,&i); |
| *params = (GLfloat)i; |
| } |
| break; |
| |
| case GL_STENCIL_BACK_VALUE_MASK: |
| case GL_STENCIL_BACK_WRITEMASK: |
| case GL_STENCIL_VALUE_MASK: |
| case GL_STENCIL_WRITEMASK: |
| { |
| GLint myint = 0; |
| glGetIntegerv(pname, &myint); |
| // Two casts are used: since mask is unsigned integer, |
| // the first cast converts to unsigned integer; |
| // the second cast converts to float. |
| *params = (GLfloat)((GLuint)(myint)); |
| } |
| break; |
| |
| default: |
| ctx->dispatcher().glGetFloatv(pname,params); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetIntegerv(GLenum pname, GLint* params){ |
| int destroyCtx = 0; |
| GET_CTX(); |
| |
| if (!ctx) { |
| ctx = createGLESContext(); |
| if (ctx) |
| destroyCtx = 1; |
| } |
| if (ctx->glGetIntegerv(pname,params)) |
| { |
| if (destroyCtx) |
| deleteGLESContext(ctx); |
| return; |
| } |
| |
| bool es2 = ctx->getCaps()->GL_ARB_ES2_COMPATIBILITY; |
| GLint i; |
| |
| switch (pname) { |
| case GL_CURRENT_PROGRAM: |
| if (ctx->shareGroup().get()) { |
| ctx->dispatcher().glGetIntegerv(pname,&i); |
| *params = ctx->shareGroup()->getLocalName(NamedObjectType::SHADER_OR_PROGRAM, |
| i); |
| } |
| break; |
| case GL_FRAMEBUFFER_BINDING: |
| if (ctx->shareGroup().get()) { |
| ctx->dispatcher().glGetIntegerv(pname,&i); |
| *params = ctx->shareGroup()->getLocalName( |
| NamedObjectType::FRAMEBUFFER, i); |
| } |
| break; |
| case GL_RENDERBUFFER_BINDING: |
| if (ctx->shareGroup().get()) { |
| ctx->dispatcher().glGetIntegerv(pname,&i); |
| *params = ctx->shareGroup()->getLocalName( |
| NamedObjectType::RENDERBUFFER, i); |
| } |
| break; |
| |
| case GL_NUM_COMPRESSED_TEXTURE_FORMATS: |
| *params = getCompressedFormats(NULL); |
| break; |
| case GL_COMPRESSED_TEXTURE_FORMATS: |
| getCompressedFormats(params); |
| break; |
| |
| case GL_SHADER_COMPILER: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| else |
| *params = 1; |
| break; |
| |
| case GL_SHADER_BINARY_FORMATS: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| break; |
| |
| case GL_NUM_SHADER_BINARY_FORMATS: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| else |
| *params = 0; |
| break; |
| |
| case GL_MAX_VERTEX_UNIFORM_VECTORS: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| else |
| *params = 128; |
| break; |
| |
| case GL_MAX_VARYING_VECTORS: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| else |
| *params = 8; |
| break; |
| |
| case GL_MAX_FRAGMENT_UNIFORM_VECTORS: |
| if(es2) |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| else |
| *params = 16; |
| break; |
| |
| case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| break; |
| default: |
| ctx->dispatcher().glGetIntegerv(pname,params); |
| } |
| if (destroyCtx) |
| deleteGLESContext(ctx); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::framebufferTarget(target) && |
| GLESv2Validate::framebufferAttachment(attachment) && |
| GLESv2Validate::framebufferAttachmentParams(pname)),GL_INVALID_ENUM); |
| |
| // |
| // Take the attachment attribute from our state - if available |
| // |
| GLuint fbName = ctx->getFramebufferBinding(); |
| SET_ERROR_IF (!fbName, GL_INVALID_OPERATION); |
| if (fbName) { |
| auto fbObj = ctx->shareGroup()->getObjectData( |
| NamedObjectType::FRAMEBUFFER, fbName); |
| if (fbObj != NULL) { |
| FramebufferData *fbData = (FramebufferData *)fbObj; |
| GLenum target; |
| GLuint name = fbData->getAttachment(attachment, &target, NULL); |
| if (!name) { |
| SET_ERROR_IF(pname != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE && |
| pname != GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, GL_INVALID_ENUM); |
| } |
| if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) { |
| if (target == GL_TEXTURE_2D) { |
| *params = GL_TEXTURE; |
| return; |
| } |
| else if (target == GL_RENDERBUFFER) { |
| *params = GL_RENDERBUFFER; |
| return; |
| } else { |
| *params = GL_NONE; |
| } |
| } |
| else if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) { |
| *params = name; |
| return; |
| } |
| } |
| } |
| |
| ctx->dispatcher().glGetFramebufferAttachmentParameterivEXT(target,attachment,pname,params); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::renderbufferTarget(target) && GLESv2Validate::renderbufferParams(pname)),GL_INVALID_ENUM); |
| |
| // |
| // If this is a renderbuffer which is eglimage's target, we |
| // should query the underlying eglimage's texture object instead. |
| // |
| GLuint rb = ctx->getRenderbufferBinding(); |
| if (rb) { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::RENDERBUFFER, rb); |
| RenderbufferData *rbData = (RenderbufferData *)objData; |
| if (rbData && rbData->eglImageGlobalTexObject) { |
| GLenum texPname; |
| switch(pname) { |
| case GL_RENDERBUFFER_WIDTH: |
| texPname = GL_TEXTURE_WIDTH; |
| break; |
| case GL_RENDERBUFFER_HEIGHT: |
| texPname = GL_TEXTURE_HEIGHT; |
| break; |
| case GL_RENDERBUFFER_INTERNAL_FORMAT: |
| texPname = GL_TEXTURE_INTERNAL_FORMAT; |
| break; |
| case GL_RENDERBUFFER_RED_SIZE: |
| texPname = GL_TEXTURE_RED_SIZE; |
| break; |
| case GL_RENDERBUFFER_GREEN_SIZE: |
| texPname = GL_TEXTURE_GREEN_SIZE; |
| break; |
| case GL_RENDERBUFFER_BLUE_SIZE: |
| texPname = GL_TEXTURE_BLUE_SIZE; |
| break; |
| case GL_RENDERBUFFER_ALPHA_SIZE: |
| texPname = GL_TEXTURE_ALPHA_SIZE; |
| break; |
| case GL_RENDERBUFFER_DEPTH_SIZE: |
| texPname = GL_TEXTURE_DEPTH_SIZE; |
| break; |
| case GL_RENDERBUFFER_STENCIL_SIZE: |
| default: |
| *params = 0; //XXX |
| return; |
| break; |
| } |
| |
| GLint prevTex; |
| ctx->dispatcher().glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTex); |
| ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, |
| rbData->eglImageGlobalTexObject->getGlobalName()); |
| ctx->dispatcher().glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, |
| texPname, |
| params); |
| ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, prevTex); |
| return; |
| } |
| } |
| |
| ctx->dispatcher().glGetRenderbufferParameterivEXT(target,pname,params); |
| } |
| |
| |
| GL_APICALL void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::programParam(pname),GL_INVALID_ENUM); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| switch(pname) { |
| case GL_DELETE_STATUS: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != PROGRAM_DATA, |
| GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| params[0] = programData->getDeleteStatus() ? GL_TRUE : GL_FALSE; |
| } |
| break; |
| case GL_LINK_STATUS: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != PROGRAM_DATA, |
| GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| params[0] = programData->getLinkStatus(); |
| } |
| break; |
| //validate status should not return GL_TRUE if link failed |
| case GL_VALIDATE_STATUS: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != PROGRAM_DATA, |
| GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| if (programData->getLinkStatus() == GL_TRUE) |
| ctx->dispatcher().glGetProgramiv(globalProgramName, pname, |
| params); |
| else |
| params[0] = GL_FALSE; |
| } |
| break; |
| case GL_INFO_LOG_LENGTH: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != PROGRAM_DATA, |
| GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| GLint logLength = strlen(programData->getInfoLog()); |
| params[0] = (logLength > 0) ? logLength + 1 : 0; |
| } |
| break; |
| default: |
| ctx->dispatcher().glGetProgramiv(globalProgramName,pname,params); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData ,GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| |
| if (bufsize==0) { |
| if (length) { |
| *length = 0; |
| } |
| return; |
| } |
| |
| GLsizei logLength; |
| logLength = strlen(programData->getInfoLog()); |
| |
| GLsizei returnLength=0; |
| if (infolog) { |
| returnLength = bufsize-1 < logLength ? bufsize-1 : logLength; |
| strncpy(infolog,programData->getInfoLog(),returnLength+1); |
| infolog[returnLength] = '\0'; |
| } |
| if (length) { |
| *length = returnLength; |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| if (pname == GL_DELETE_STATUS) { |
| SET_ERROR_IF(globalShaderName == 0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData ,GL_INVALID_VALUE); |
| SET_ERROR_IF(objData->getDataType()!=SHADER_DATA,GL_INVALID_VALUE); |
| ShaderParser* sp = (ShaderParser*)objData; |
| params[0] = (sp->getDeleteStatus()) ? GL_TRUE : GL_FALSE; |
| return; |
| } |
| SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE); |
| switch(pname) { |
| case GL_INFO_LOG_LENGTH: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != SHADER_DATA, |
| GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| GLint logLength = strlen(sp->getInfoLog()); |
| params[0] = (logLength > 0) ? logLength + 1 : 0; |
| } |
| break; |
| case GL_SHADER_SOURCE_LENGTH: |
| { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != SHADER_DATA, |
| GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| GLint srcLength = sp->getOriginalSrc().length(); |
| params[0] = (srcLength > 0) ? srcLength + 1 : 0; |
| } |
| break; |
| default: |
| ctx->dispatcher().glGetShaderiv(globalShaderName,pname,params); |
| } |
| } |
| } |
| |
| |
| GL_APICALL void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData ,GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType()!=SHADER_DATA,GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| |
| if (bufsize==0) { |
| if (length) { |
| *length = 0; |
| } |
| return; |
| } |
| |
| GLsizei logLength; |
| logLength = strlen(sp->getInfoLog()); |
| |
| GLsizei returnLength=0; |
| if (infolog) { |
| returnLength = bufsize-1 <logLength ? bufsize-1 : logLength; |
| strncpy(infolog,sp->getInfoLog(),returnLength+1); |
| infolog[returnLength] = '\0'; |
| } |
| if (length) { |
| *length = returnLength; |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(!(GLESv2Validate::shaderType(shadertype) && GLESv2Validate::precisionType(precisiontype)),GL_INVALID_ENUM); |
| |
| switch (precisiontype) { |
| case GL_LOW_INT: |
| case GL_MEDIUM_INT: |
| case GL_HIGH_INT: |
| range[0] = range[1] = 16; |
| *precision = 0; |
| break; |
| |
| case GL_LOW_FLOAT: |
| case GL_MEDIUM_FLOAT: |
| case GL_HIGH_FLOAT: |
| if(ctx->dispatcher().glGetShaderPrecisionFormat != NULL) { |
| ctx->dispatcher().glGetShaderPrecisionFormat(shadertype,precisiontype,range,precision); |
| } else { |
| range[0] = range[1] = 127; |
| *precision = 24; |
| } |
| break; |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName == 0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != SHADER_DATA, |
| GL_INVALID_OPERATION); |
| const std::string& src = |
| ((ShaderParser*)objData)->getOriginalSrc(); |
| int srcLength = static_cast<int>(src.size()); |
| |
| int returnLength = bufsize < srcLength ? bufsize - 1 : srcLength; |
| if (returnLength) { |
| strncpy(source, src.c_str(), returnLength); |
| source[returnLength] = '\0'; |
| } |
| |
| if (length) |
| *length = returnLength; |
| } |
| } |
| |
| |
| GL_APICALL const GLubyte* GL_APIENTRY glGetString(GLenum name){ |
| GET_CTX_RET(NULL) |
| static const GLubyte SHADING[] = "OpenGL ES GLSL ES 1.0.17"; |
| switch(name) { |
| case GL_VENDOR: |
| return (const GLubyte*)ctx->getVendorString(); |
| case GL_RENDERER: |
| return (const GLubyte*)ctx->getRendererString(); |
| case GL_VERSION: |
| return (const GLubyte*)ctx->getVersionString(); |
| case GL_SHADING_LANGUAGE_VERSION: |
| return SHADING; |
| case GL_EXTENSIONS: |
| return (const GLubyte*)ctx->getExtensionString(); |
| default: |
| RET_AND_SET_ERROR_IF(true,GL_INVALID_ENUM,NULL); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glGetTexParameterfv(target,pname,params); |
| |
| } |
| GL_APICALL void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glGetTexParameteriv(target,pname,params); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params){ |
| GET_CTX(); |
| SET_ERROR_IF(location < 0,GL_INVALID_OPERATION); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ProgramData* pData = (ProgramData *)objData; |
| SET_ERROR_IF(pData->getLinkStatus() != GL_TRUE,GL_INVALID_OPERATION); |
| ctx->dispatcher().glGetUniformfv(globalProgramName,location,params); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(location < 0,GL_INVALID_OPERATION); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ProgramData* pData = (ProgramData *)objData; |
| SET_ERROR_IF(pData->getLinkStatus() != GL_TRUE,GL_INVALID_OPERATION); |
| ctx->dispatcher().glGetUniformiv(globalProgramName,location,params); |
| } |
| } |
| |
| GL_APICALL int GL_APIENTRY glGetUniformLocation(GLuint program, const GLchar* name){ |
| GET_CTX_RET(-1); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| RET_AND_SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE,-1); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| RET_AND_SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION,-1); |
| ProgramData* pData = (ProgramData *)objData; |
| RET_AND_SET_ERROR_IF(pData->getLinkStatus() != GL_TRUE,GL_INVALID_OPERATION,-1); |
| return ctx->dispatcher().glGetUniformLocation(globalProgramName,name); |
| } |
| return -1; |
| } |
| |
| static bool s_invalidVertexAttribIndex(GLuint index) { |
| GLint param=0; |
| glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, ¶m); |
| return (param < 0 || index >= (GLuint)param); |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(s_invalidVertexAttribIndex(index), GL_INVALID_VALUE); |
| const GLESpointer* p = ctx->getPointer(index); |
| if(p) { |
| switch(pname){ |
| case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: |
| *params = 0; |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_ENABLED: |
| *params = p->isEnable(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_SIZE: |
| *params = p->getSize(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_STRIDE: |
| *params = p->getStride(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_TYPE: |
| *params = p->getType(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: |
| *params = p->isNormalize(); |
| break; |
| case GL_CURRENT_VERTEX_ATTRIB: |
| if(index == 0) |
| { |
| const float* att0 = ctx->getAtt0(); |
| for(int i=0; i<4; i++) |
| params[i] = att0[i]; |
| } |
| else |
| ctx->dispatcher().glGetVertexAttribfv(index,pname,params); |
| break; |
| default: |
| ctx->setGLerror(GL_INVALID_ENUM); |
| } |
| } else { |
| ctx->setGLerror(GL_INVALID_VALUE); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(s_invalidVertexAttribIndex(index), GL_INVALID_VALUE); |
| const GLESpointer* p = ctx->getPointer(index); |
| if(p) { |
| switch(pname){ |
| case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: |
| *params = 0; |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_ENABLED: |
| *params = p->isEnable(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_SIZE: |
| *params = p->getSize(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_STRIDE: |
| *params = p->getStride(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_TYPE: |
| *params = p->getType(); |
| break; |
| case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: |
| *params = p->isNormalize(); |
| break; |
| case GL_CURRENT_VERTEX_ATTRIB: |
| if(index == 0) |
| { |
| const float* att0 = ctx->getAtt0(); |
| for(int i=0; i<4; i++) |
| params[i] = (GLint)att0[i]; |
| } |
| else |
| ctx->dispatcher().glGetVertexAttribiv(index,pname,params); |
| break; |
| default: |
| ctx->setGLerror(GL_INVALID_ENUM); |
| } |
| } else { |
| ctx->setGLerror(GL_INVALID_VALUE); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer){ |
| GET_CTX(); |
| SET_ERROR_IF(pname != GL_VERTEX_ATTRIB_ARRAY_POINTER,GL_INVALID_ENUM); |
| SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE); |
| |
| const GLESpointer* p = ctx->getPointer(index); |
| if(p) { |
| *pointer = const_cast<void *>( p->getBufferData()); |
| } else { |
| ctx->setGLerror(GL_INVALID_VALUE); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glHint(GLenum target, GLenum mode){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::hintTargetMode(target,mode),GL_INVALID_ENUM); |
| ctx->dispatcher().glHint(target,mode); |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsEnabled(GLenum cap){ |
| GET_CTX_RET(GL_FALSE); |
| RET_AND_SET_ERROR_IF(!GLESv2Validate::capability(cap),GL_INVALID_ENUM,GL_FALSE); |
| return ctx->dispatcher().glIsEnabled(cap); |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsBuffer(GLuint buffer){ |
| GET_CTX_RET(GL_FALSE) |
| if(buffer && ctx->shareGroup().get()) { |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::VERTEXBUFFER, buffer); |
| return objData ? ((GLESbuffer*)objData)->wasBinded() |
| : GL_FALSE; |
| } |
| return GL_FALSE; |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer){ |
| GET_CTX_RET(GL_FALSE) |
| if(framebuffer && ctx->shareGroup().get()){ |
| return (ctx->shareGroup()->isObject(NamedObjectType::FRAMEBUFFER, |
| framebuffer) && |
| ctx->getFramebufferBinding() == framebuffer) |
| ? GL_TRUE |
| : GL_FALSE; |
| } |
| return GL_FALSE; |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer){ |
| GET_CTX_RET(GL_FALSE) |
| if(renderbuffer && ctx->shareGroup().get()){ |
| return (ctx->shareGroup()->isObject(NamedObjectType::RENDERBUFFER, |
| renderbuffer) && |
| ctx->getRenderbufferBinding() == renderbuffer) |
| ? GL_TRUE |
| : GL_FALSE; |
| } |
| return GL_FALSE; |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsTexture(GLuint texture){ |
| GET_CTX_RET(GL_FALSE) |
| if (texture==0) |
| return GL_FALSE; |
| TextureData* tex = getTextureData(texture); |
| return tex ? tex->wasBound : GL_FALSE; |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsProgram(GLuint program){ |
| GET_CTX_RET(GL_FALSE) |
| if (program && ctx->shareGroup().get() && |
| ctx->shareGroup()->isObject(NamedObjectType::SHADER_OR_PROGRAM, program)) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| return ctx->dispatcher().glIsProgram(globalProgramName); |
| } |
| return GL_FALSE; |
| } |
| |
| GL_APICALL GLboolean GL_APIENTRY glIsShader(GLuint shader){ |
| GET_CTX_RET(GL_FALSE) |
| if (shader && ctx->shareGroup().get() && |
| ctx->shareGroup()->isObject(NamedObjectType::SHADER_OR_PROGRAM, shader)) { |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| return ctx->dispatcher().glIsShader(globalShaderName); |
| } |
| return GL_FALSE; |
| } |
| |
| GL_APICALL void GL_APIENTRY glLineWidth(GLfloat width){ |
| GET_CTX(); |
| ctx->dispatcher().glLineWidth(width); |
| } |
| |
| GL_APICALL void GL_APIENTRY glLinkProgram(GLuint program){ |
| GET_CTX(); |
| GLint linkStatus = GL_FALSE; |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA, GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| GLint fragmentShader = programData->getAttachedFragmentShader(); |
| GLint vertexShader = programData->getAttachedVertexShader(); |
| if (vertexShader != 0 && fragmentShader!=0) { |
| /* validating that the fragment & vertex shaders were compiled successfuly*/ |
| GLint fCompileStatus = GL_FALSE; |
| GLint vCompileStatus = GL_FALSE; |
| GLuint fragmentShaderGlobal = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, fragmentShader); |
| GLuint vertexShaderGlobal = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, vertexShader); |
| ctx->dispatcher().glGetShaderiv(fragmentShaderGlobal,GL_COMPILE_STATUS,&fCompileStatus); |
| ctx->dispatcher().glGetShaderiv(vertexShaderGlobal,GL_COMPILE_STATUS,&vCompileStatus); |
| |
| if(fCompileStatus != 0 && vCompileStatus != 0){ |
| ctx->dispatcher().glLinkProgram(globalProgramName); |
| ctx->dispatcher().glGetProgramiv(globalProgramName,GL_LINK_STATUS,&linkStatus); |
| } |
| } |
| programData->setLinkStatus(linkStatus); |
| |
| GLsizei infoLogLength=0; |
| GLchar* infoLog; |
| ctx->dispatcher().glGetProgramiv(globalProgramName,GL_INFO_LOG_LENGTH,&infoLogLength); |
| infoLog = new GLchar[infoLogLength+1]; |
| ctx->dispatcher().glGetProgramInfoLog(globalProgramName,infoLogLength,NULL,infoLog); |
| programData->setInfoLog(infoLog); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glPixelStorei(GLenum pname, GLint param){ |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::pixelStoreParam(pname),GL_INVALID_ENUM); |
| SET_ERROR_IF(!((param==1)||(param==2)||(param==4)||(param==8)), GL_INVALID_VALUE); |
| ctx->setUnpackAlignment(param); |
| ctx->dispatcher().glPixelStorei(pname,param); |
| } |
| |
| GL_APICALL void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units){ |
| GET_CTX(); |
| ctx->dispatcher().glPolygonOffset(factor,units); |
| } |
| |
| GL_APICALL void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::readPixelFrmt(format) && GLESv2Validate::pixelType(ctx,type)),GL_INVALID_ENUM); |
| SET_ERROR_IF((width < 0 || height < 0),GL_INVALID_VALUE); |
| SET_ERROR_IF(!(GLESv2Validate::pixelOp(format,type)),GL_INVALID_OPERATION); |
| SET_ERROR_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION); |
| ctx->dispatcher().glReadPixels(x,y,width,height,format,type,pixels); |
| } |
| |
| |
| GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void){ |
| // this function doesn't work on Mac OS with MacOSX10.9sdk |
| #ifndef __APPLE__ |
| |
| /* Use this function with mesa will cause potential bug. Specifically, |
| * calling this function between glCompileShader() and glLinkProgram() will |
| * release resources that would be potentially used by glLinkProgram, |
| * resulting in a segmentation fault. |
| */ |
| const char* env = ::getenv("ANDROID_GL_LIB"); |
| if (env && !strcmp(env, "mesa")) { |
| return; |
| } |
| |
| GET_CTX(); |
| |
| if(ctx->dispatcher().glReleaseShaderCompiler != NULL) |
| { |
| ctx->dispatcher().glReleaseShaderCompiler(); |
| } |
| #endif // !__APPLE__ |
| } |
| |
| GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height){ |
| GET_CTX(); |
| GLenum internal = internalformat; |
| switch (internalformat) { |
| case GL_RGB565: |
| internal = GL_RGB; |
| break; |
| case GL_RGB5_A1: |
| internal = GL_RGBA; |
| break; |
| default: |
| internal = internalformat; |
| break; |
| } |
| |
| // Get current bounded renderbuffer |
| // raise INVALID_OPERATIOn if no renderbuffer is bounded |
| GLuint rb = ctx->getRenderbufferBinding(); |
| SET_ERROR_IF(rb == 0,GL_INVALID_OPERATION); |
| auto objData = |
| ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, rb); |
| RenderbufferData *rbData = (RenderbufferData *)objData; |
| SET_ERROR_IF(!rbData,GL_INVALID_OPERATION); |
| |
| // |
| // if the renderbuffer was an eglImage target, release |
| // its underlying texture. |
| // |
| rbData->eglImageGlobalTexObject.reset(); |
| |
| ctx->dispatcher().glRenderbufferStorageEXT(target,internal,width,height); |
| } |
| |
| GL_APICALL void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert){ |
| GET_CTX(); |
| ctx->dispatcher().glSampleCoverage(value,invert); |
| } |
| |
| GL_APICALL void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height){ |
| GET_CTX(); |
| ctx->dispatcher().glScissor(x,y,width,height); |
| } |
| |
| GL_APICALL void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length){ |
| GET_CTX(); |
| |
| SET_ERROR_IF( (ctx->dispatcher().glShaderBinary == NULL), GL_INVALID_OPERATION); |
| |
| if(ctx->shareGroup().get()){ |
| for(int i=0; i < n ; i++){ |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shaders[i]); |
| SET_ERROR_IF(globalShaderName == 0,GL_INVALID_VALUE); |
| ctx->dispatcher().glShaderBinary(1,&globalShaderName,binaryformat,binary,length); |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length){ |
| GET_CTX_V2(); |
| SET_ERROR_IF(count < 0,GL_INVALID_VALUE); |
| if(ctx->shareGroup().get()){ |
| const GLuint globalShaderName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(globalShaderName == 0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, shader); |
| SET_ERROR_IF(!objData, GL_INVALID_OPERATION); |
| SET_ERROR_IF(objData->getDataType() != SHADER_DATA, |
| GL_INVALID_OPERATION); |
| ShaderParser* sp = (ShaderParser*)objData; |
| sp->setSrc(ctx->glslVersion(), count, string, length); |
| ctx->dispatcher().glShaderSource(globalShaderName, 1, sp->parsedLines(), |
| NULL); |
| sp->clear(); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask){ |
| GET_CTX(); |
| ctx->dispatcher().glStencilFunc(func,ref,mask); |
| } |
| GL_APICALL void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask){ |
| GET_CTX(); |
| ctx->dispatcher().glStencilFuncSeparate(face,func,ref,mask); |
| } |
| GL_APICALL void GL_APIENTRY glStencilMask(GLuint mask){ |
| GET_CTX(); |
| ctx->dispatcher().glStencilMask(mask); |
| } |
| |
| GL_APICALL void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask){ |
| GET_CTX(); |
| ctx->dispatcher().glStencilMaskSeparate(face,mask); |
| } |
| |
| GL_APICALL void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass){ |
| GET_CTX(); |
| ctx->dispatcher().glStencilOp(fail,zfail,zpass); |
| } |
| |
| GL_APICALL void GL_APIENTRY glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass){ |
| GET_CTX(); |
| switch (face) { |
| case GL_FRONT: |
| case GL_BACK: |
| case GL_FRONT_AND_BACK: |
| break; |
| default: |
| SET_ERROR_IF(1, GL_INVALID_ENUM); |
| } |
| ctx->dispatcher().glStencilOpSeparate(face, fail,zfail,zpass); |
| } |
| |
| #define GL_RGBA32F 0x8814 |
| #define GL_RGB32F 0x8815 |
| GL_APICALL void GL_APIENTRY glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTargetEx(target) && |
| GLESv2Validate::pixelFrmt(ctx,format)&& |
| GLESv2Validate::pixelType(ctx,type)),GL_INVALID_ENUM); |
| |
| SET_ERROR_IF(!GLESv2Validate::pixelItnlFrmt(ctx,internalformat), GL_INVALID_VALUE); |
| SET_ERROR_IF((GLESv2Validate::textureIsCubeMap(target) && width != height), GL_INVALID_VALUE); |
| SET_ERROR_IF((format == GL_DEPTH_COMPONENT || internalformat == GL_DEPTH_COMPONENT) && |
| (type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT), GL_INVALID_OPERATION); |
| |
| SET_ERROR_IF((type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) && |
| (format != GL_DEPTH_COMPONENT || internalformat != GL_DEPTH_COMPONENT), GL_INVALID_OPERATION); |
| |
| SET_ERROR_IF(!GLESv2Validate::pixelOp(format,type) && internalformat == ((GLint)format),GL_INVALID_OPERATION); |
| SET_ERROR_IF(!GLESv2Validate::pixelSizedFrmt(ctx, internalformat, format, type), GL_INVALID_OPERATION); |
| SET_ERROR_IF(border != 0,GL_INVALID_VALUE); |
| |
| s_glInitTexImage2D(target,level,internalformat,width,height,border); |
| if (type==GL_HALF_FLOAT_OES) |
| type = GL_HALF_FLOAT_NV; |
| if (pixels==NULL && type==GL_UNSIGNED_SHORT_5_5_5_1) |
| type = GL_UNSIGNED_SHORT; |
| if (type == GL_FLOAT) |
| internalformat = (format == GL_RGBA) ? GL_RGBA32F : GL_RGB32F; |
| ctx->dispatcher().glTexImage2D(target,level,internalformat,width,height,border,format,type,pixels); |
| } |
| |
| GL_APICALL void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glTexParameterf(target,pname,param); |
| } |
| GL_APICALL void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glTexParameterfv(target,pname,params); |
| } |
| GL_APICALL void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glTexParameteri(target,pname,param); |
| } |
| GL_APICALL void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTarget(target) && GLESv2Validate::textureParams(pname)),GL_INVALID_ENUM); |
| ctx->dispatcher().glTexParameteriv(target,pname,params); |
| } |
| |
| GL_APICALL void GL_APIENTRY glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels){ |
| GET_CTX(); |
| SET_ERROR_IF(!(GLESv2Validate::textureTargetEx(target)), GL_INVALID_ENUM); |
| // set an error if level < 0 or level > log 2 max |
| SET_ERROR_IF(level < 0 || 1<<level > ctx->getMaxTexSize(), GL_INVALID_VALUE); |
| SET_ERROR_IF(xoffset < 0 || yoffset < 0 || width < 0 || height < 0, GL_INVALID_VALUE); |
| if (ctx->shareGroup().get()) { |
| TextureData *texData = getTextureTargetData(target); |
| if (texData) { |
| SET_ERROR_IF(xoffset + width > (GLint)texData->width || |
| yoffset + height > (GLint)texData->height, |
| GL_INVALID_VALUE); |
| } |
| } |
| SET_ERROR_IF(!(GLESv2Validate::pixelFrmt(ctx,format)&& |
| GLESv2Validate::pixelType(ctx,type)),GL_INVALID_ENUM); |
| SET_ERROR_IF(!GLESv2Validate::pixelOp(format,type),GL_INVALID_OPERATION); |
| SET_ERROR_IF(!pixels,GL_INVALID_OPERATION); |
| if (type==GL_HALF_FLOAT_OES) |
| type = GL_HALF_FLOAT_NV; |
| |
| ctx->dispatcher().glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels); |
| |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform1f(GLint location, GLfloat x){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform1f(location,x); |
| } |
| GL_APICALL void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform1fv(location,count,v); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform1i(GLint location, GLint x){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform1i(location,x); |
| } |
| GL_APICALL void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform1iv(location,count,v); |
| } |
| GL_APICALL void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform2f(location,x,y); |
| } |
| GL_APICALL void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform2fv(location,count,v); |
| } |
| GL_APICALL void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform2i(location,x,y); |
| } |
| GL_APICALL void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform2iv(location,count,v); |
| } |
| GL_APICALL void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform3f(location,x,y,z); |
| } |
| GL_APICALL void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform3fv(location,count,v); |
| } |
| GL_APICALL void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform3i(location,x,y,z); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform3iv(location,count,v); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform4f(location,x,y,z,w); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform4fv(location,count,v); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform4i(location,x,y,z,w); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v){ |
| GET_CTX(); |
| ctx->dispatcher().glUniform4iv(location,count,v); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){ |
| GET_CTX(); |
| SET_ERROR_IF(transpose != GL_FALSE,GL_INVALID_VALUE); |
| ctx->dispatcher().glUniformMatrix2fv(location,count,transpose,value); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){ |
| GET_CTX(); |
| SET_ERROR_IF(transpose != GL_FALSE,GL_INVALID_VALUE); |
| ctx->dispatcher().glUniformMatrix3fv(location,count,transpose,value); |
| } |
| |
| GL_APICALL void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){ |
| GET_CTX(); |
| SET_ERROR_IF(transpose != GL_FALSE,GL_INVALID_VALUE); |
| ctx->dispatcher().glUniformMatrix4fv(location,count,transpose,value); |
| } |
| |
| static void s_unUseCurrentProgram() { |
| GET_CTX(); |
| GLint localCurrentProgram = 0; |
| glGetIntegerv(GL_CURRENT_PROGRAM, &localCurrentProgram); |
| if (!localCurrentProgram) return; |
| |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, localCurrentProgram); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| programData->setInUse(false); |
| if (programData->getDeleteStatus()) { |
| ctx->shareGroup()->deleteName(NamedObjectType::SHADER_OR_PROGRAM, |
| localCurrentProgram); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glUseProgram(GLuint program){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(program!=0 && globalProgramName==0,GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData && (objData->getDataType()!=PROGRAM_DATA),GL_INVALID_OPERATION); |
| |
| s_unUseCurrentProgram(); |
| |
| ProgramData* programData = (ProgramData*)objData; |
| if (programData) programData->setInUse(true); |
| |
| ctx->dispatcher().glUseProgram(globalProgramName); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glValidateProgram(GLuint program){ |
| GET_CTX(); |
| if(ctx->shareGroup().get()) { |
| const GLuint globalProgramName = ctx->shareGroup()->getGlobalName( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(globalProgramName==0, GL_INVALID_VALUE); |
| auto objData = ctx->shareGroup()->getObjectData( |
| NamedObjectType::SHADER_OR_PROGRAM, program); |
| SET_ERROR_IF(objData->getDataType()!=PROGRAM_DATA,GL_INVALID_OPERATION); |
| ProgramData* programData = (ProgramData*)objData; |
| ctx->dispatcher().glValidateProgram(globalProgramName); |
| |
| GLsizei infoLogLength=0; |
| GLchar* infoLog; |
| ctx->dispatcher().glGetProgramiv(globalProgramName,GL_INFO_LOG_LENGTH,&infoLogLength); |
| infoLog = new GLchar[infoLogLength+1]; |
| ctx->dispatcher().glGetProgramInfoLog(globalProgramName,infoLogLength,NULL,infoLog); |
| programData->setInfoLog(infoLog); |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint indx, GLfloat x){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib1f(indx,x); |
| if(indx == 0) |
| ctx->setAttribute0value(x, 0.0, 0.0, 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint indx, const GLfloat* values){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib1fv(indx,values); |
| if(indx == 0) |
| ctx->setAttribute0value(values[0], 0.0, 0.0, 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib2f(indx,x,y); |
| if(indx == 0) |
| ctx->setAttribute0value(x, y, 0.0, 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint indx, const GLfloat* values){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib2fv(indx,values); |
| if(indx == 0) |
| ctx->setAttribute0value(values[0], values[1], 0.0, 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib3f(indx,x,y,z); |
| if(indx == 0) |
| ctx->setAttribute0value(x, y, z, 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint indx, const GLfloat* values){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib3fv(indx,values); |
| if(indx == 0) |
| ctx->setAttribute0value(values[0], values[1], values[2], 1.0); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib4f(indx,x,y,z,w); |
| if(indx == 0) |
| ctx->setAttribute0value(x, y, z, w); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint indx, const GLfloat* values){ |
| GET_CTX_V2(); |
| ctx->dispatcher().glVertexAttrib4fv(indx,values); |
| if(indx == 0) |
| ctx->setAttribute0value(values[0], values[1], values[2], values[3]); |
| } |
| |
| GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr){ |
| GET_CTX(); |
| SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,indx)),GL_INVALID_VALUE); |
| if (type == GL_HALF_FLOAT_OES) type = GL_HALF_FLOAT; |
| ctx->setPointer(indx,size,type,stride,ptr,normalized); |
| } |
| |
| GL_APICALL void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height){ |
| GET_CTX(); |
| ctx->dispatcher().glViewport(x,y,width,height); |
| } |
| |
| GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) |
| { |
| GET_CTX(); |
| SET_ERROR_IF(!GLESv2Validate::textureTargetLimited(target),GL_INVALID_ENUM); |
| unsigned int imagehndl = SafeUIntFromPointer(image); |
| ImagePtr img = s_eglIface->getEGLImage(imagehndl); |
| if (img) { |
| // Create the texture object in the underlying EGL implementation, |
| // flag to the OpenGL layer to skip the image creation and map the |
| // current binded texture object to the existing global object. |
| if (ctx->shareGroup().get()) { |
| ObjectLocalName tex = TextureLocalName(target,ctx->getBindedTexture(target)); |
| // replace mapping and bind the new global object |
| ctx->shareGroup()->replaceGlobalObject(NamedObjectType::TEXTURE, tex, |
| img->globalTexObj); |
| ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, img->globalTexObj->getGlobalName()); |
| TextureData *texData = getTextureTargetData(target); |
| SET_ERROR_IF(texData==NULL,GL_INVALID_OPERATION); |
| texData->width = img->width; |
| texData->height = img->height; |
| texData->border = img->border; |
| texData->internalFormat = img->internalFormat; |
| texData->sourceEGLImage = imagehndl; |
| } |
| } |
| } |
| |
| GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) |
| { |
| GET_CTX(); |
| SET_ERROR_IF(target != GL_RENDERBUFFER_OES,GL_INVALID_ENUM); |
| unsigned int imagehndl = SafeUIntFromPointer(image); |
| ImagePtr img = s_eglIface->getEGLImage(imagehndl); |
| SET_ERROR_IF(!img,GL_INVALID_VALUE); |
| SET_ERROR_IF(!ctx->shareGroup().get(),GL_INVALID_OPERATION); |
| |
| // Get current bounded renderbuffer |
| // raise INVALID_OPERATIOn if no renderbuffer is bounded |
| GLuint rb = ctx->getRenderbufferBinding(); |
| SET_ERROR_IF(rb == 0,GL_INVALID_OPERATION); |
| auto objData = |
| ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, rb); |
| RenderbufferData *rbData = (RenderbufferData *)objData; |
| SET_ERROR_IF(!rbData,GL_INVALID_OPERATION); |
| |
| // |
| // acquire the texture in the renderbufferData that it is an eglImage target |
| // |
| rbData->eglImageGlobalTexObject = img->globalTexObj; |
| |
| // |
| // if the renderbuffer is attached to a framebuffer |
| // change the framebuffer attachment in the undelying OpenGL |
| // to point to the eglImage texture object. |
| // |
| if (rbData->attachedFB) { |
| // update the framebuffer attachment point to the |
| // underlying texture of the img |
| GLuint prevFB = ctx->getFramebufferBinding(); |
| if (prevFB != rbData->attachedFB) { |
| ctx->dispatcher().glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, |
| rbData->attachedFB); |
| } |
| ctx->dispatcher().glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, |
| rbData->attachedPoint, |
| GL_TEXTURE_2D, |
| img->globalTexObj->getGlobalName(), |
| 0); |
| if (prevFB != rbData->attachedFB) { |
| ctx->dispatcher().glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, |
| prevFB); |
| } |
| } |
| } |
| |
| GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags) |
| { |
| GET_CTX_V2_RET(NULL); |
| return ctx->dispatcher().glFenceSync(condition, flags); |
| } |
| |
| GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync wait_on, GLbitfield flags, GLuint64 timeout) |
| { |
| GET_CTX_V2_RET(GL_WAIT_FAILED); |
| return ctx->dispatcher().glClientWaitSync(wait_on, flags, timeout); |
| } |
| |
| GL_APICALL void GL_APIENTRY glWaitSync(GLsync wait_on, GLbitfield flags, GLuint64 timeout) |
| { |
| GET_CTX_V2(); |
| ctx->dispatcher().glWaitSync(wait_on, flags, timeout); |
| } |
| |
| GL_APICALL void GL_APIENTRY glDeleteSync(GLsync to_delete) |
| { |
| GET_CTX_V2(); |
| ctx->dispatcher().glDeleteSync(to_delete); |
| } |