blob: 7021eedf66858f6e4744ecc68191ea8e28f5ba9d [file] [log] [blame]
/*
* 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
#define GL_APICALL
#endif // !_WIN32
#define GL_GLEXT_PROTOTYPES
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
#include <GLES3/gl31.h>
#include "aemu/base/system/System.h"
#include "host-common/logging.h"
#include "GLESv2Context.h"
#include "GLESv2Validate.h"
#include "GLcommon/FramebufferData.h"
#include "GLcommon/GLutils.h"
#include "GLcommon/SaveableTexture.h"
#include "GLcommon/TextureData.h"
#include "GLcommon/TextureUtils.h"
#include "GLcommon/TranslatorIfaces.h"
#include "ProgramData.h"
#include "SamplerData.h"
#include "ShaderParser.h"
#include "TransformFeedbackData.h"
#include "host-common/crash_reporter.h"
#include "ANGLEShaderParser.h"
#include <math.h>
#include <stdio.h>
#include <numeric>
#include <unordered_map>
#ifdef _MSC_VER
#include "aemu/base/msvc.h"
#else
#include <sys/time.h>
#endif
#define GLES2_NAMESPACED(f) translator::gles2::f
namespace translator {
namespace gles2 {
GL_API void GL_APIENTRY glFlush( void);
GL_API void GL_APIENTRY glFinish( void);
GL_API GLenum GL_APIENTRY glGetError( void);
} // namespace gles1
} // namespace translator
extern "C" {
//decleration
static void initGLESx(bool isGles2Gles);
static void initContext(GLEScontext* ctx,ShareGroupPtr grp);
static void setMaxGlesVersion(GLESVersion version);
static void deleteGLESContext(GLEScontext* ctx);
static void setShareGroup(GLEScontext* ctx,ShareGroupPtr grp);
static GLEScontext* createGLESContext(void);
static GLEScontext* createGLESxContext(int maj, int min, GlobalNameSpace* globalNameSpace, android::base::Stream* stream);
static __translatorMustCastToProperFunctionPointerType getProcAddressGles2(const char* procName);
static void preSaveTexture();
static void postSaveTexture();
static void saveTexture(SaveableTexture* texture, android::base::Stream* stream,
android::base::SmallVector<unsigned char>* buffer);
static SaveableTexture* createTexture(GlobalNameSpace* globalNameSpace,
SaveableTexture::loader_t&& loader);
static void restoreTexture(SaveableTexture* texture);
static void blitFromCurrentReadBufferANDROID(EGLImage image);
static bool vulkanInteropSupported();
namespace translator {
namespace gles2 {
static GLsync internal_glFenceSync(GLenum condition, GLbitfield flags);
static GLenum internal_glClientWaitSync(GLsync wait_on, GLbitfield flags, GLuint64 timeout);
static void internal_glWaitSync(GLsync wait_on, GLbitfield flags, GLuint64 timeout);
static void internal_glDeleteSync(GLsync to_delete);
static void internal_glGetSynciv(GLsync sync, GLenum pname, GLsizei bufsize, GLsizei *length, GLint *values);
} // namespace translator
} // namespace gles2
}
/************************************** GLES EXTENSIONS *********************************************************/
typedef std::unordered_map<std::string, __translatorMustCastToProperFunctionPointerType> ProcTableMap;
ProcTableMap *s_gles2Extensions = NULL;
/****************************************************************************************************************/
static EGLiface* s_eglIface = NULL;
static GLESiface s_glesIface = {
.initGLESx = initGLESx,
.createGLESContext = createGLESxContext,
.initContext = initContext,
.setMaxGlesVersion = setMaxGlesVersion,
.deleteGLESContext = deleteGLESContext,
.flush = (FUNCPTR_NO_ARGS_RET_VOID)GLES2_NAMESPACED(glFlush),
.finish = (FUNCPTR_NO_ARGS_RET_VOID)GLES2_NAMESPACED(glFinish),
.getError = (FUNCPTR_NO_ARGS_RET_INT)GLES2_NAMESPACED(glGetError),
.setShareGroup = setShareGroup,
.getProcAddress = getProcAddressGles2,
.fenceSync = (FUNCPTR_FENCE_SYNC)translator::gles2::internal_glFenceSync,
.clientWaitSync = (FUNCPTR_CLIENT_WAIT_SYNC)translator::gles2::internal_glClientWaitSync,
.waitSync = (FUNCPTR_WAIT_SYNC)translator::gles2::internal_glWaitSync,
.deleteSync = (FUNCPTR_DELETE_SYNC)translator::gles2::internal_glDeleteSync,
.preSaveTexture = preSaveTexture,
.postSaveTexture = postSaveTexture,
.saveTexture = saveTexture,
.createTexture = createTexture,
.restoreTexture = restoreTexture,
.deleteRbo = deleteRenderbufferGlobal,
.blitFromCurrentReadBufferANDROID = blitFromCurrentReadBufferANDROID,
.vulkanInteropSupported = vulkanInteropSupported,
.getSynciv = (FUNCPTR_GET_SYNC_IV)translator::gles2::internal_glGetSynciv,
};
#include <GLcommon/GLESmacros.h>
namespace translator {
namespace gles2 {
GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image);
GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image);
GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
GL_APICALL void GL_APIENTRY glVertexAttribPointerWithDataSize(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr, GLsizei dataSize);
GL_APICALL void GL_APIENTRY glVertexAttribIPointerWithDataSize(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* ptr, GLsizei dataSize);
GL_APICALL void GL_APIENTRY glTestHostDriverPerformance(GLuint count, uint64_t* duration_us, uint64_t* duration_cpu_us);
GL_APICALL void GL_APIENTRY glDrawArraysNullAEMU(GLenum mode, GLint first, GLsizei count);
GL_APICALL void GL_APIENTRY glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const void* indices);
// Vulkan/GL interop
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_external_objects.txt
// Common between GL_EXT_memory_object and GL_EXT_semaphore
GL_APICALL void GL_APIENTRY glGetUnsignedBytevEXT(GLenum pname, GLubyte* data);
GL_APICALL void GL_APIENTRY glGetUnsignedBytei_vEXT(GLenum target, GLuint index, GLubyte* data);
// GL_EXT_memory_object
GL_APICALL void GL_APIENTRY glImportMemoryFdEXT(GLuint memory, GLuint64 size, GLenum handleType, GLint fd);
GL_APICALL void GL_APIENTRY glImportMemoryWin32HandleEXT(GLuint memory, GLuint64 size, GLenum handleType, void* handle);
GL_APICALL void GL_APIENTRY glDeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObjects);
GL_APICALL GLboolean GL_APIENTRY glIsMemoryObjectEXT(GLuint memoryObject);
GL_APICALL void GL_APIENTRY glCreateMemoryObjectsEXT(GLsizei n, GLuint *memoryObjects);
GL_APICALL void GL_APIENTRY glMemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, const GLint *params);
GL_APICALL void GL_APIENTRY glGetMemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, GLint *params);
GL_APICALL void GL_APIENTRY glTexStorageMem2DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset);
GL_APICALL void GL_APIENTRY glTexStorageMem2DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
GL_APICALL void GL_APIENTRY glTexStorageMem3DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset);
GL_APICALL void GL_APIENTRY glTexStorageMem3DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset);
GL_APICALL void GL_APIENTRY glBufferStorageMemEXT(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset);
GL_APICALL void GL_APIENTRY glTexParameteriHOST(GLenum target, GLenum pname, GLint param);
// GL_OES_texture_buffer
GL_APICALL void GL_APIENTRY glTexBufferOES(GLenum target, GLenum internalformat, GLuint buffer);
GL_APICALL void GL_APIENTRY glTexBufferRangeOES(GLenum target, GLenum internalformat, GLuint buffer,
GLintptr offset, GLsizeiptr size);
// GL_EXT_texture_buffer
GL_APICALL void GL_APIENTRY glTexBufferEXT(GLenum target, GLenum internalformat, GLuint buffer);
GL_APICALL void GL_APIENTRY glTexBufferRangeEXT(GLenum target, GLenum internalformat, GLuint buffer,
GLintptr offset, GLsizeiptr size);
// GL_EXT_draw_buffers_indexed
GL_APICALL void GL_APIENTRY glTexBufferOES(GLenum target, GLenum internalFormat, GLuint buffer);
GL_APICALL void GL_APIENTRY glTexBufferRangeOES(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size);
GL_APICALL void GL_APIENTRY glTexBufferEXT(GLenum target, GLenum internalFormat, GLuint buffer);
GL_APICALL void GL_APIENTRY glTexBufferRangeEXT(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size);
GL_APICALL void GL_APIENTRY glEnableiEXT(GLenum cap, GLuint index);
GL_APICALL void GL_APIENTRY glDisableiEXT(GLenum cap, GLuint index);
GL_APICALL void GL_APIENTRY glBlendEquationiEXT(GLuint index, GLenum mode);
GL_APICALL void GL_APIENTRY glBlendEquationSeparateiEXT(GLuint index, GLenum modeRGB, GLenum modeAlpha);
GL_APICALL void GL_APIENTRY glBlendFunciEXT(GLuint index, GLenum sfactor, GLenum dfactor);
GL_APICALL void GL_APIENTRY glBlendFuncSeparateiEXT(GLuint index, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
GL_APICALL void GL_APIENTRY glColorMaskiEXT(GLuint index, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GL_APICALL GLboolean GL_APIENTRY glIsEnablediEXT(GLenum cap, GLuint index);
// Not included: direct-state-access, 1D function pointers
// GL_EXT_semaphore
GL_APICALL void GL_APIENTRY glImportSemaphoreFdEXT(GLuint semaphore, GLenum handleType, GLint fd);
GL_APICALL void GL_APIENTRY glImportSemaphoreWin32HandleEXT(GLuint semaphore, GLenum handleType, void* handle);
GL_APICALL void GL_APIENTRY glGenSemaphoresEXT(GLsizei n, GLuint *semaphores);
GL_APICALL void GL_APIENTRY glDeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores);
GL_APICALL GLboolean glIsSemaphoreEXT(GLuint semaphore);
GL_APICALL void GL_APIENTRY glSemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, const GLuint64 *params);
GL_APICALL void GL_APIENTRY glGetSemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, GLuint64 *params);
GL_APICALL void GL_APIENTRY glWaitSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts);
GL_APICALL void GL_APIENTRY glSignalSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts);
// Utility to get global names
GL_APICALL GLuint GL_APIENTRY glGetGlobalTexName(GLuint localName);
GL_APICALL void GL_APIENTRY glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels);
GL_APICALL void GL_APIENTRY glDebugMessageControlKHR(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
GL_APICALL void GL_APIENTRY glDebugMessageInsertKHR(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
GL_APICALL void GL_APIENTRY glDebugMessageCallbackKHR(GLDEBUGPROCKHR callback, const void* userdata);
GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLogKHR(GLuint count, GLsizei size, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* log);
GL_APICALL void GL_APIENTRY glPushDebugGroupKHR(GLenum source, GLuint id, GLsizei length, const GLchar* message);
GL_APICALL void GL_APIENTRY glPopDebugGroupKHR(void);
GL_APICALL void GL_APIENTRY glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled);
GL_APICALL void GL_APIENTRY glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf);
GL_APICALL void GL_APIENTRY glDebugMessageCallback(GLDEBUGPROC callback, const void* userdata);
GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLog(GLuint count, GLsizei size, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* log);
GL_APICALL void GL_APIENTRY glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar* message);
GL_APICALL void GL_APIENTRY glPopDebugGroup(void);
} // namespace gles2
} // namespace translator
extern "C" {
static void setMaxGlesVersion(GLESVersion version) {
GLESv2Context::setMaxGlesVersion(version);
}
static void initContext(GLEScontext* ctx,ShareGroupPtr grp) {
setCoreProfile(ctx->isCoreProfile());
GLESv2Context::initGlobal(s_eglIface);
if (!ctx->shareGroup()) {
ctx->setShareGroup(grp);
}
if (!ctx->isInitialized()) {
ctx->init();
translator::gles2::glBindTexture(GL_TEXTURE_2D,0);
translator::gles2::glBindTexture(GL_TEXTURE_CUBE_MAP,0);
}
if (ctx->needRestore()) {
ctx->restore();
}
}
static GLEScontext* createGLESContext() {
return new GLESv2Context(2, 0, nullptr, nullptr, nullptr);
}
static GLEScontext* createGLESxContext(int maj, int min,
GlobalNameSpace* globalNameSpace, android::base::Stream* stream) {
return new GLESv2Context(maj, min, globalNameSpace, stream,
s_eglIface->eglGetGlLibrary());
}
static bool shaderParserInitialized = false;
static bool sDebugPrintShaders = false;
#define SHADER_DEBUG_PRINT(fmt,...) \
if (sDebugPrintShaders) { \
printf("shader_debug: %s: " fmt "\n", __func__, ##__VA_ARGS__); \
} \
static void initGLESx(bool isGles2Gles) {
setGles2Gles(isGles2Gles);
}
static void deleteGLESContext(GLEScontext* ctx) {
delete ctx;
}
static void setShareGroup(GLEScontext* ctx,ShareGroupPtr grp) {
if(ctx) {
ctx->setShareGroup(grp);
}
}
static __translatorMustCastToProperFunctionPointerType getProcAddressGles2(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_gles2Extensions)
s_gles2Extensions = new ProcTableMap();
else
s_gles2Extensions->clear();
(*s_gles2Extensions)["glEGLImageTargetTexture2DOES"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glEGLImageTargetTexture2DOES);
(*s_gles2Extensions)["glEGLImageTargetRenderbufferStorageOES"]=(__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glEGLImageTargetRenderbufferStorageOES);
(*s_gles2Extensions)["glVertexAttribPointerWithDataSize"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glVertexAttribPointerWithDataSize);
(*s_gles2Extensions)["glVertexAttribIPointerWithDataSize"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glVertexAttribIPointerWithDataSize);
(*s_gles2Extensions)["glTestHostDriverPerformance"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTestHostDriverPerformance);
(*s_gles2Extensions)["glDrawArraysNullAEMU"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDrawArraysNullAEMU);
(*s_gles2Extensions)["glDrawElementsNullAEMU"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDrawElementsNullAEMU);
(*s_gles2Extensions)["glGetUnsignedBytevEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetUnsignedBytevEXT);
(*s_gles2Extensions)["glGetUnsignedBytei_vEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetUnsignedBytei_vEXT);
(*s_gles2Extensions)["glImportMemoryFdEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glImportMemoryFdEXT);
(*s_gles2Extensions)["glImportMemoryWin32HandleEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glImportMemoryWin32HandleEXT);
(*s_gles2Extensions)["glDeleteMemoryObjectsEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDeleteMemoryObjectsEXT);
(*s_gles2Extensions)["glIsMemoryObjectEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glIsMemoryObjectEXT);
(*s_gles2Extensions)["glCreateMemoryObjectsEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glCreateMemoryObjectsEXT);
(*s_gles2Extensions)["glMemoryObjectParameterivEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glMemoryObjectParameterivEXT);
(*s_gles2Extensions)["glGetMemoryObjectParameterivEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetMemoryObjectParameterivEXT);
(*s_gles2Extensions)["glTexStorageMem2DEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexStorageMem2DEXT);
(*s_gles2Extensions)["glTexStorageMem2DMultisampleEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexStorageMem2DMultisampleEXT);
(*s_gles2Extensions)["glTexStorageMem3DEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexStorageMem3DEXT);
(*s_gles2Extensions)["glTexStorageMem3DMultisampleEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexStorageMem3DMultisampleEXT);
(*s_gles2Extensions)["glBufferStorageMemEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glBufferStorageMemEXT);
(*s_gles2Extensions)["glTexParameteriHOST"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexParameteriHOST);
(*s_gles2Extensions)["glImportSemaphoreFdEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glImportSemaphoreFdEXT);
(*s_gles2Extensions)["glImportSemaphoreWin32HandleEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glImportSemaphoreWin32HandleEXT);
(*s_gles2Extensions)["glGenSemaphoresEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGenSemaphoresEXT);
(*s_gles2Extensions)["glDeleteSemaphoresEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDeleteSemaphoresEXT);
(*s_gles2Extensions)["glIsSemaphoreEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glIsSemaphoreEXT);
(*s_gles2Extensions)["glSemaphoreParameterui64vEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glSemaphoreParameterui64vEXT);
(*s_gles2Extensions)["glGetSemaphoreParameterui64vEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetSemaphoreParameterui64vEXT);
(*s_gles2Extensions)["glWaitSemaphoreEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glWaitSemaphoreEXT);
(*s_gles2Extensions)["glSignalSemaphoreEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glSignalSemaphoreEXT);
(*s_gles2Extensions)["glGetGlobalTexName"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetGlobalTexName);
(*s_gles2Extensions)["glGetTexImage"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetTexImage);
(*s_gles2Extensions)["glDebugMessageControlKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageControlKHR);
(*s_gles2Extensions)["glDebugMessageInsertKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageInsertKHR);
(*s_gles2Extensions)["glDebugMessageCallbackKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageCallbackKHR);
(*s_gles2Extensions)["glGetDebugMessageLogKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetDebugMessageLogKHR);
(*s_gles2Extensions)["glPushDebugGroupKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glPushDebugGroupKHR);
(*s_gles2Extensions)["glPopDebugGroupKHR"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glPopDebugGroupKHR);
(*s_gles2Extensions)["glDebugMessageControl"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageControl);
(*s_gles2Extensions)["glDebugMessageCallback"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageCallback);
(*s_gles2Extensions)["glDebugMessageInsert"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDebugMessageInsert);
(*s_gles2Extensions)["glGetDebugMessageLog"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glGetDebugMessageLog);
(*s_gles2Extensions)["glPushDebugGroup"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glPushDebugGroup);
(*s_gles2Extensions)["glPopDebugGroup"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glPopDebugGroup);
(*s_gles2Extensions)["glTexBufferOES"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexBufferOES);
(*s_gles2Extensions)["glTexBufferRangeOES"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexBufferRangeOES);
(*s_gles2Extensions)["glTexBufferEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexBufferEXT);
(*s_gles2Extensions)["glTexBufferRangeEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glTexBufferRangeEXT);
(*s_gles2Extensions)["glEnableiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glEnableiEXT);
(*s_gles2Extensions)["glDisableiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glDisableiEXT);
(*s_gles2Extensions)["glBlendEquationiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glBlendEquationiEXT);
(*s_gles2Extensions)["glBlendEquationSeparateiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glBlendEquationSeparateiEXT);
(*s_gles2Extensions)["glBlendFunciEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glBlendFunciEXT);
(*s_gles2Extensions)["glBlendFuncSeparateiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glBlendFuncSeparateiEXT);
(*s_gles2Extensions)["glColorMaskiEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glColorMaskiEXT);
(*s_gles2Extensions)["glIsEnablediEXT"] = (__translatorMustCastToProperFunctionPointerType)GLES2_NAMESPACED(glIsEnablediEXT);
}
__translatorMustCastToProperFunctionPointerType ret=NULL;
ProcTableMap::iterator val = s_gles2Extensions->find(procName);
if (val!=s_gles2Extensions->end())
ret = val->second;
ctx->releaseGlobalLock();
return ret;
}
static void preSaveTexture() {
SaveableTexture::preSave();
}
static void postSaveTexture() {
SaveableTexture::postSave();
}
static void saveTexture(SaveableTexture* texture, android::base::Stream* stream,
SaveableTexture::Buffer* buffer) {
texture->onSave(stream);
}
static SaveableTexture* createTexture(GlobalNameSpace* globalNameSpace,
SaveableTexture::loader_t&& loader) {
return new SaveableTexture(globalNameSpace, std::move(loader));
}
static void restoreTexture(SaveableTexture* texture) {
if (!texture) return;
texture->touch();
}
extern "C" {
GLESiface* static_translator_glesv2_getIfaces(const EGLiface* eglIface);
GLESiface* static_translator_glesv2_getIfaces(const EGLiface* eglIface) {
s_eglIface = (EGLiface*)eglIface;
return & s_glesIface;
}
}
static bool vulkanInteropSupported() {
return GLEScontext::vulkanInteropSupported();
}
static void blitFromCurrentReadBufferANDROID(EGLImage image) {
GET_CTX()
unsigned int imagehndl = SafeUIntFromPointer(image);
ImagePtr img = s_eglIface->getEGLImage(imagehndl);
if (!img ||
!ctx->shareGroup().get()) {
// emugl_crash_reporter(
// "FATAL: blitFromCurrentReadBufferANDROID: "
// "image (%p) or share group (%p) not found",
// img.get(), ctx->shareGroup().get());
return;
}
// Could be a bad snapshot load
if (!img->isNative) {
if (!img->saveableTexture) {
return;
}
}
if (img->globalTexObj) {
img->saveableTexture->makeDirty();
GLuint globalTexObj = img->globalTexObj->getGlobalName();
ctx->blitFromReadBufferToTextureFlipped(
globalTexObj, img->width, img->height,
img->internalFormat, img->format, img->type);
} else if (img->isNative) {
if (!img->width || !img->height || !img->internalFormat) {
fprintf(stderr, "%s: error: Tried to blit to internal image, "
"but we don't know the width, height or internalformat.\n", __func__);
return;
}
ctx->blitFromReadBufferToEGLImage(
img->nativeImage,
img->internalFormat,
img->width, img->height);
}
}
} // 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 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(ctx->getTextureLocalName(target,tex));
}
namespace translator {
namespace gles2 {
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, (ShaderParser*)shaderData, shaderType);
s_attachShader(ctx, program, shader, (ShaderParser*)shaderData);
SHADER_DEBUG_PRINT(
"attach shader %u to program %u", shader, program);
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, ctx->getCaps()->maxVertexAttribs),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);
ProgramData* pData = (ProgramData*)objData;
ctx->dispatcher().glBindAttribLocation(
globalProgramName, index,
pData->getTranslatedName(name).c_str());
pData->bindAttribLocation(name, index);
}
}
GL_APICALL void GL_APIENTRY glBindBuffer(GLenum target, GLuint buffer){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::bufferTarget(ctx, target), GL_INVALID_ENUM);
GLuint globalBufferName = ctx->bindBuffer(target,buffer);
ctx->dispatcher().glBindBuffer(target, globalBufferName);
}
static bool sIsFboTextureTarget(GLenum target) {
switch (target) {
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
case GL_TEXTURE_2D_ARRAY:
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_MULTISAMPLE:
return true;
default:
return false;
}
}
template <class T>
static bool sHasAttachmentWithFormat(const GLESv2Context* ctx,
FramebufferData* fbData,
const T& attachments,
const std::initializer_list<GLenum> formats) {
for (auto attachment : attachments) {
GLenum target;
GLuint name = fbData->getAttachment(attachment, &target, NULL);
if (!name) continue;
if (target == GL_RENDERBUFFER) {
auto objData = ctx->shareGroup()->getObjectData(
NamedObjectType::RENDERBUFFER, name);
if (auto rbData = (RenderbufferData*)objData) {
GLenum rb_internalformat = rbData->internalformat;
for (auto triggerFormat : formats) {
if (rb_internalformat == triggerFormat) {
return true;
}
}
}
} else if (sIsFboTextureTarget(target)) {
if (TextureData* tex = getTextureData(name)) {
GLenum tex_internalformat = tex->internalFormat;
for (auto triggerFormat : formats) {
if (tex_internalformat == triggerFormat) {
return true;
}
}
}
}
}
return false;
}
static void sSetDesktopGLEnable(const GLESv2Context* ctx, bool enable, GLenum cap) {
if (enable)
ctx->dispatcher().glEnable(cap);
else
ctx->dispatcher().glDisable(cap);
}
// Framebuffer format workarounds:
// Desktop OpenGL implicit framebuffer behavior is much more configurable
// than that of OpenGL ES. In OpenGL ES, some implicit operations can happen
// depending on the internal format and attachment combinations of the
// framebuffer object.
static void sUpdateFboEmulation(GLESv2Context* ctx) {
if (ctx->getMajorVersion() < 3 || isGles2Gles()) {
return;
}
std::vector<GLenum> colorAttachments(ctx->getCaps()->maxDrawBuffers);
std::iota(colorAttachments.begin(), colorAttachments.end(), GL_COLOR_ATTACHMENT0);
const auto depthAttachments =
{GL_DEPTH_ATTACHMENT, GL_DEPTH_STENCIL_ATTACHMENT};
GLuint read_fbo = ctx->getFramebufferBinding(GL_READ_FRAMEBUFFER);
GLuint draw_fbo = ctx->getFramebufferBinding(GL_DRAW_FRAMEBUFFER);
bool enableSRGB = false;
bool enableDepth32fClamp = false;
for (auto fbObj : {ctx->getFBOData(read_fbo),
ctx->getFBOData(draw_fbo)}) {
if (fbObj == nullptr) { continue; }
// Enable GL_FRAMEBUFFER_SRGB when any framebuffer has SRGB color attachment.
if (sHasAttachmentWithFormat(ctx, fbObj,
colorAttachments, {GL_SRGB8_ALPHA8}))
enableSRGB = true;
// Enable GL_DEPTH_CLAMP when any fbo's
// GL_DEPTH_ATTACHMENT or GL_DEPTH_STENCIL_ATTACHMENT is of internal format
// GL_DEPTH_COMPONENT32F or GL_DEPTH32F_STENCIL8.
if (sHasAttachmentWithFormat(ctx, fbObj,
depthAttachments, {GL_DEPTH_COMPONENT32F, GL_DEPTH32F_STENCIL8}))
enableDepth32fClamp = true;
// Perform any necessary workarounds for apps that use separate depth/stencil
// attachments.
fbObj->separateDepthStencilWorkaround(ctx);
}
// TODO: GLES3: snapshot those enable value as well?
sSetDesktopGLEnable(ctx, enableSRGB, GL_FRAMEBUFFER_SRGB);
sSetDesktopGLEnable(ctx, enableDepth32fClamp, GL_DEPTH_CLAMP);
}
GL_APICALL void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::framebufferTarget(ctx, target),GL_INVALID_ENUM);
GLuint globalFrameBufferName;
bool isDefaultFBO = !framebuffer;
if (isDefaultFBO) {
globalFrameBufferName = ctx->getDefaultFBOGlobalName();
ctx->dispatcher().glBindFramebuffer(target, globalFrameBufferName);
ctx->setFramebufferBinding(target, 0);
} else {
globalFrameBufferName = framebuffer;
if(framebuffer){
globalFrameBufferName = ctx->getFBOGlobalName(framebuffer);
//if framebuffer wasn't generated before,generate one
if(!globalFrameBufferName){
ctx->genFBOName(framebuffer);
globalFrameBufferName = ctx->getFBOGlobalName(framebuffer);
ctx->setFBOData(framebuffer,
ObjectDataPtr(new FramebufferData(framebuffer,
globalFrameBufferName)));
}
// set that this framebuffer has been bound before
auto fbObj = ctx->getFBOData(framebuffer);
fbObj->setBoundAtLeastOnce();
}
ctx->dispatcher().glBindFramebuffer(target,globalFrameBufferName);
ctx->setFramebufferBinding(target, framebuffer);
}
sUpdateFboEmulation(ctx);
}
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);
RenderbufferData* rboData = new RenderbufferData();
rboData->everBound = true;
ctx->shareGroup()->setObjectData(
NamedObjectType::RENDERBUFFER, renderbuffer,
ObjectDataPtr(rboData));
globalRenderBufferName = ctx->shareGroup()->getGlobalName(
NamedObjectType::RENDERBUFFER, renderbuffer);
} else {
RenderbufferData* rboData = (RenderbufferData*)(ctx->shareGroup()->getObjectDataPtr(
NamedObjectType::RENDERBUFFER, renderbuffer).get());
if (rboData) rboData->everBound = true;
}
}
ctx->dispatcher().glBindRenderbuffer(target,globalRenderBufferName);
// update renderbuffer binding state
ctx->setRenderbufferBinding(renderbuffer);
}
GL_APICALL GLuint GL_APIENTRY glGetGlobalTexName(GLuint localName) {
GET_CTX_V2_RET(0);
GLuint globalTextureName = ctx->shareGroup()->getGlobalName(
NamedObjectType::TEXTURE, localName);
return globalTextureName;
}
GL_APICALL void GL_APIENTRY glBindTexture(GLenum target, GLuint texture){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::textureTarget(ctx, target), GL_INVALID_ENUM);
//for handling default texture (0)
ObjectLocalName localTexName = ctx->getTextureLocalName(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->setTarget(target);
}
//if texture was already bound to another target
if (ctx->GLTextureTargetToLocal(texData->target) != ctx->GLTextureTargetToLocal(target)) {
fprintf(stderr, "%s: Set invalid operation!\n", __func__);
}
SET_ERROR_IF(ctx->GLTextureTargetToLocal(texData->target) != ctx->GLTextureTargetToLocal(target), GL_INVALID_OPERATION);
texData->setGlobalName(globalTextureName);
if (!texData->wasBound) {
texData->resetSaveableTexture();
}
texData->wasBound = true;
}
ctx->setBindedTexture(target,texture);
ctx->dispatcher().glBindTexture(target,globalTextureName);
if (ctx->getMajorVersion() < 3) return;
// OpenGL ES assumes that rendered depth textures shade as (v, 0, 0, 1)
// when coming out of the fragment shader.
// Desktop OpenGL assumes (v, v, v, 1).
// GL_DEPTH_TEXTURE_MODE can be set to GL_RED to follow the OpenGL ES behavior.
if (!ctx->isCoreProfile() && !isGles2Gles()) {
#define GL_DEPTH_TEXTURE_MODE 0x884B
ctx->dispatcher().glTexParameteri(target ,GL_DEPTH_TEXTURE_MODE, GL_RED);
}
}
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_V2();
SET_ERROR_IF(!GLESv2Validate::blendEquationMode(ctx, mode), GL_INVALID_ENUM);
ctx->setBlendEquationSeparate(mode, mode);
ctx->dispatcher().glBlendEquation(mode);
}
GL_APICALL void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::blendEquationMode(ctx, modeRGB) &&
GLESv2Validate::blendEquationMode(ctx, modeAlpha)), GL_INVALID_ENUM);
ctx->setBlendEquationSeparate(modeRGB, modeAlpha);
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->setBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
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->setBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
ctx->dispatcher().glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
}
GL_APICALL void GL_APIENTRY glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::bufferTarget(ctx, target), GL_INVALID_ENUM);
SET_ERROR_IF(!ctx->isBindedBuffer(target),GL_INVALID_OPERATION);
SET_ERROR_IF(!GLESv2Validate::bufferUsage(ctx, usage), GL_INVALID_ENUM);
ctx->setBufferData(target,size,data,usage);
ctx->dispatcher().glBufferData(target, size, data, usage);
}
GL_APICALL void GL_APIENTRY glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::bufferTarget(ctx, target), GL_INVALID_ENUM);
SET_ERROR_IF(!ctx->isBindedBuffer(target),GL_INVALID_OPERATION);
SET_ERROR_IF(!ctx->setBufferSubData(target,offset,size,data),GL_INVALID_VALUE);
ctx->dispatcher().glBufferSubData(target, offset, size, data);
}
GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target){
GET_CTX_V2_RET(GL_FRAMEBUFFER_COMPLETE);
RET_AND_SET_ERROR_IF(!GLESv2Validate::framebufferTarget(ctx, target), GL_INVALID_ENUM, GL_FRAMEBUFFER_COMPLETE);
// We used to issue ctx->drawValidate() here, but it can corrupt the status of
// separately bound draw/read framebuffer objects. So we just don't call it now.
return ctx->dispatcher().glCheckFramebufferStatus(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);
if (ctx->getMajorVersion() < 3)
ctx->drawValidate();
ctx->dispatcher().glClear(mask);
}
GL_APICALL void GL_APIENTRY glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha){
GET_CTX();
ctx->setClearColor(red,green, blue, alpha);
ctx->dispatcher().glClearColor(red,green,blue,alpha);
}
GL_APICALL void GL_APIENTRY glClearDepthf(GLclampf depth){
GET_CTX();
ctx->setClearDepth(depth);
if (isGles2Gles()) {
ctx->dispatcher().glClearDepthf(depth);
} else {
ctx->dispatcher().glClearDepth(depth);
}
}
GL_APICALL void GL_APIENTRY glClearStencil(GLint s){
GET_CTX();
ctx->setClearStencil(s);
ctx->dispatcher().glClearStencil(s);
}
GL_APICALL void GL_APIENTRY glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha){
GET_CTX();
ctx->setColorMask(red, green, blue, alpha);
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);
GLint compileStatus;
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);
ctx->dispatcher().glGetShaderiv(globalShaderName,GL_COMPILE_STATUS,&compileStatus);
sp->setCompileStatus(compileStatus == GL_FALSE ? false : true);
} else {
ctx->dispatcher().glCompileShader(globalShaderName);
sp->setCompileStatus(false);
ctx->dispatcher().glGetShaderiv(globalShaderName,GL_COMPILE_STATUS,&compileStatus);
if (compileStatus != GL_FALSE) {
fprintf(stderr, "%s: Warning: underlying GL compiled invalid shader!\n", __func__);
}
}
}
}
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);
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(ctx, target),GL_INVALID_ENUM);
SET_ERROR_IF(level < 0 || imageSize < 0, GL_INVALID_VALUE);
auto funcPtr = translator::gles2::glTexImage2D;
if (shouldPassthroughCompressedFormat(ctx, internalformat)) {
doCompressedTexImage2DNative(ctx, target, level, internalformat,
width, height, border, imageSize, data);
} else {
doCompressedTexImage2D(ctx, target, level, internalformat,
width, height, border,
imageSize, data, funcPtr);
}
TextureData* texData = getTextureTargetData(target);
if (texData) {
texData->compressed = true;
texData->compressedFormat = internalformat;
if (shouldPassthroughCompressedFormat(ctx, internalformat)) {
texData->internalFormat = internalformat;
}
}
}
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);
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(ctx, target),GL_INVALID_ENUM);
if (ctx->shareGroup().get()) {
TextureData* texData = getTextureTargetData(target);
if (texData) {
if (isEtc2Format(texData->compressedFormat)) {
int encodedDataSize =
etc_get_encoded_data_size(
getEtcFormat(texData->compressedFormat),
width, height);
SET_ERROR_IF(imageSize != encodedDataSize, GL_INVALID_VALUE);
GLsizei lvlWidth = texData->width >> level;
GLsizei lvlHeight = texData->height >> level;
if (texData->width && !lvlWidth) lvlWidth = 1;
if (texData->height && !lvlHeight) lvlHeight = 1;
SET_ERROR_IF((width % 4) && ((xoffset + width) != (GLsizei)lvlWidth), GL_INVALID_OPERATION);
SET_ERROR_IF((height % 4) && ((yoffset + height) != (GLsizei)lvlHeight), GL_INVALID_OPERATION);
SET_ERROR_IF(xoffset % 4, GL_INVALID_OPERATION);
SET_ERROR_IF(yoffset % 4, GL_INVALID_OPERATION);
}
SET_ERROR_IF(format != texData->compressedFormat, GL_INVALID_OPERATION);
}
SET_ERROR_IF(ctx->getMajorVersion() < 3 && !data, GL_INVALID_OPERATION);
if (shouldPassthroughCompressedFormat(ctx, format)) {
doCompressedTexSubImage2DNative(ctx, target, level, xoffset, yoffset,
width, height, format, imageSize, data);
} else {
doCompressedTexImage2D(ctx, target, level, format,
width, height, 0, imageSize, data,
[xoffset, yoffset](GLenum target, GLint level,
GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type,
const GLvoid* data) {
glTexSubImage2D(target, level, xoffset, yoffset,
width, height, format, type, data);
});
}
}
}
void s_glInitTexImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLint border, GLint samples, GLenum* format,
GLenum* type, GLint* internalformat_out) {
GET_CTX();
if (ctx->shareGroup().get()) {
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->hasStorage = true;
texData->setMipmapLevelAtLeast(static_cast<unsigned int>(level));
}
if (texData && level == 0) {
assert(texData->target == GL_TEXTURE_2D ||
texData->target == GL_TEXTURE_2D_MULTISAMPLE ||
texData->target == GL_TEXTURE_CUBE_MAP);
if (GLESv2Validate::isCompressedFormat(internalformat)) {
texData->compressed = true;
texData->compressedFormat = internalformat;
texData->internalFormat = shouldPassthroughCompressedFormat(ctx, internalformat) ? internalformat : decompressedInternalFormat(ctx, internalformat);
} else {
texData->internalFormat = internalformat;
}
if (internalformat_out) {
*internalformat_out = texData->internalFormat;
}
texData->width = width;
texData->height = height;
texData->border = border;
texData->samples = samples;
if (format) texData->format = *format;
if (type) texData->type = *type;
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;
texData->setGlobalName(globalTextureName);
}
texData->resetSaveableTexture();
}
texData->makeDirty();
}
}
void s_glInitTexImage3D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLsizei depth, GLint border,
GLenum format, GLenum type){
GET_CTX();
if (ctx->shareGroup().get()){
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->hasStorage = true;
texData->setMipmapLevelAtLeast(static_cast<unsigned int>(level));
}
if (texData && level == 0) {
texData->width = width;
texData->height = height;
texData->depth = depth;
texData->border = border;
texData->internalFormat = internalformat;
texData->target = target;
texData->format = format;
texData->type = type;
texData->resetSaveableTexture();
}
texData->makeDirty();
}
}
GL_APICALL void GL_APIENTRY glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::pixelFrmt(ctx,internalformat) &&
(GLESv2Validate::textureTarget(ctx, target) ||
GLESv2Validate::textureTargetEx(ctx, target))), GL_INVALID_ENUM);
SET_ERROR_IF((GLESv2Validate::textureIsCubeMap(target) && width != height), GL_INVALID_VALUE);
SET_ERROR_IF(border != 0,GL_INVALID_VALUE);
GLenum format = baseFormatOfInternalFormat((GLint)internalformat);
GLenum type = accurateTypeOfInternalFormat((GLint)internalformat);
s_glInitTexImage2D(
target, level, internalformat, width, height, border, 0,
&format, &type, (GLint*)&internalformat);
TextureData* texData = getTextureTargetData(target);
if (texData && isCoreProfile() &&
isCoreProfileEmulatedFormat(texData->format)) {
GLEScontext::prepareCoreProfileEmulatedTexture(
getTextureTargetData(target),
false, target, format, type,
(GLint*)&internalformat, &format);
ctx->copyTexImageWithEmulation(
texData, false, target, level, internalformat,
0, 0, x, y, width, height, border);
} else {
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_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) ||
GLESv2Validate::textureTargetEx(ctx, target)), GL_INVALID_ENUM);
TextureData* texData = getTextureTargetData(target);
if (texData) {
texData->makeDirty();
}
if (texData && isCoreProfile() &&
isCoreProfileEmulatedFormat(texData->format)) {
ctx->copyTexImageWithEmulation(
texData, true, target, level, 0, xoffset, yoffset, x, y, width, height, 0);
} else {
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(ctx->getMajorVersion(),
ctx->getMinorVersion());
const GLuint localProgramName =
ctx->shareGroup()->genName(ShaderProgramType::PROGRAM, 0, true);
ctx->shareGroup()->setObjectData(NamedObjectType::SHADER_OR_PROGRAM,
localProgramName,
ObjectDataPtr(programInfo));
programInfo->addProgramName(ctx->shareGroup()->getGlobalName(
NamedObjectType::SHADER_OR_PROGRAM, localProgramName));
return localProgramName;
}
return 0;
}
GL_APICALL GLuint GL_APIENTRY glCreateShader(GLenum type){
GET_CTX_V2_RET(0);
// Lazy init so we can catch the caps.
if (!shaderParserInitialized) {
shaderParserInitialized = true;
sDebugPrintShaders =
android::base::getEnvironmentVariable(
"ANDROID_EMUGL_SHADER_PRINT") == "1";
auto& gl = ctx->dispatcher();
auto glesMajorVersion = ctx->getMajorVersion();
auto glesMinorVersion = ctx->getMinorVersion();
#ifdef USE_ANGLE_SHADER_PARSER
ANGLEShaderParser::BuiltinResourcesEditCallback editCallback =
[&gl, glesMajorVersion,
glesMinorVersion](ST_BuiltInResources& res) {
gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &res.MaxVertexAttribs);
gl.glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS,
&res.MaxVertexUniformVectors);
gl.glGetIntegerv(GL_MAX_VARYING_VECTORS,
&res.MaxVaryingVectors);
gl.glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
&res.MaxVertexTextureImageUnits);
gl.glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
&res.MaxCombinedTextureImageUnits);
gl.glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,
&res.MaxTextureImageUnits);
gl.glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
&res.MaxFragmentUniformVectors);
gl.glGetIntegerv(GL_MAX_DRAW_BUFFERS, &res.MaxDrawBuffers);
res.FragmentPrecisionHigh = 1;
GLint tmp;
gl.glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &tmp);
res.MaxVertexOutputVectors = tmp / 4;
gl.glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &tmp);
res.MaxFragmentInputVectors = tmp / 4;
gl.glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET,
&res.MinProgramTexelOffset);
gl.glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET,
&res.MaxProgramTexelOffset);
res.MaxDualSourceDrawBuffers = 1;
res.OES_standard_derivatives = 1;
res.OES_EGL_image_external = 0;
res.EXT_gpu_shader5 = 1;
bool shaderFramebufferFetch =
GLEScontext::shaderFramebufferFetchSupported();
res.EXT_shader_framebuffer_fetch =
shaderFramebufferFetch ? 1 : 0;
// GLES 3.1 constants
gl.glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET,
&res.MaxProgramTextureGatherOffset);
gl.glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET,
&res.MinProgramTextureGatherOffset);
gl.glGetIntegerv(GL_MAX_IMAGE_UNITS, &res.MaxImageUnits);
gl.glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS,
&res.MaxComputeImageUniforms);
gl.glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS,
&res.MaxVertexImageUniforms);
gl.glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS,
&res.MaxFragmentImageUniforms);
gl.glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS,
&res.MaxCombinedImageUniforms);
gl.glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES,
&res.MaxCombinedShaderOutputResources);
gl.glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS,
&res.MaxUniformLocations);
GLint maxComputeWorkGroupCount[3];
GLint maxComputeWorkGroupSize[3];
for (uint32_t i = 0; i < 3; ++i) {
if (gl.glGetIntegeri_v &&
!(glesMajorVersion == 3 && glesMinorVersion == 0)) {
gl.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, i,
&maxComputeWorkGroupCount[i]);
gl.glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, i,
&maxComputeWorkGroupSize[i]);
} else {
maxComputeWorkGroupCount[i] = 65536;
maxComputeWorkGroupSize[i] = 128;
}
res.MaxComputeWorkGroupCount[i] =
maxComputeWorkGroupCount[i];
res.MaxComputeWorkGroupSize[i] = maxComputeWorkGroupSize[i];
}
gl.glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS,
&res.MaxComputeUniformComponents);
gl.glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS,
&res.MaxComputeTextureImageUnits);
gl.glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS,
&res.MaxComputeAtomicCounters);
gl.glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS,
&res.MaxComputeAtomicCounterBuffers);
gl.glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS,
&res.MaxVertexAtomicCounters);
gl.glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS,
&res.MaxFragmentAtomicCounters);
gl.glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS,
&res.MaxCombinedAtomicCounters);
gl.glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
&res.MaxAtomicCounterBindings);
gl.glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS,
&res.MaxVertexAtomicCounterBuffers);
gl.glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS,
&res.MaxFragmentAtomicCounterBuffers);
gl.glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS,
&res.MaxCombinedAtomicCounterBuffers);
gl.glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE,
&res.MaxAtomicCounterBufferSize);
gl.glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
&res.MaxUniformBufferBindings);
gl.glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
&res.MaxShaderStorageBufferBindings);
// Clear GL errors if the underlying GL doesn't have those
// enums.
gl.glGetError();
};
ANGLEShaderParser::globalInitialize(
isGles2Gles(),
editCallback);
#endif
}
RET_AND_SET_ERROR_IF(!GLESv2Validate::shaderType(ctx, type), GL_INVALID_ENUM, 0);
if(ctx->shareGroup().get()) {
ShaderProgramType shaderProgramType;
switch (type) {
case GL_VERTEX_SHADER:
shaderProgramType = ShaderProgramType::VERTEX_SHADER;
break;
case GL_FRAGMENT_SHADER:
shaderProgramType = ShaderProgramType::FRAGMENT_SHADER;
break;
case GL_COMPUTE_SHADER:
shaderProgramType = ShaderProgramType::COMPUTE_SHADER;
break;
default:
shaderProgramType = ShaderProgramType::VERTEX_SHADER;
break;
}
const GLuint localShaderName = ctx->shareGroup()->genName(
shaderProgramType, 0, true);
ShaderParser* sp = new ShaderParser(type, isCoreProfile());
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->setCullFace(mode);
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_V2();
SET_ERROR_IF(n < 0, GL_INVALID_VALUE);
for (int i = 0; i < n; i++) {
if (ctx->getFramebufferBinding(GL_FRAMEBUFFER) == framebuffers[i]) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
else if (ctx->getFramebufferBinding(GL_READ_FRAMEBUFFER) == framebuffers[i]) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
ctx->deleteFBO(framebuffers[i]);
}
}
GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
static void s_detachFromFramebuffer(NamedObjectType bufferType,
GLuint texture,
GLenum target) {
GET_CTX();
GLuint fbName = ctx->getFramebufferBinding(target);
if (!fbName) return;
auto fbObj = ctx->getFBOData(fbName);
if (fbObj == NULL) return;
const GLenum kAttachments[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
GL_COLOR_ATTACHMENT4,
GL_COLOR_ATTACHMENT5,
GL_COLOR_ATTACHMENT6,
GL_COLOR_ATTACHMENT7,
GL_COLOR_ATTACHMENT8,
GL_COLOR_ATTACHMENT9,
GL_COLOR_ATTACHMENT10,
GL_COLOR_ATTACHMENT11,
GL_COLOR_ATTACHMENT12,
GL_COLOR_ATTACHMENT13,
GL_COLOR_ATTACHMENT14,
GL_COLOR_ATTACHMENT15,
GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT,
GL_DEPTH_STENCIL_ATTACHMENT };
const size_t sizen = sizeof(kAttachments)/sizeof(GLenum);
GLenum textarget;
for (size_t i = 0; i < sizen; ++i ) {
GLuint name = fbObj->getAttachment(kAttachments[i], &textarget, NULL);
if (name != texture) continue;
if (NamedObjectType::TEXTURE == bufferType &&
GLESv2Validate::textureTargetEx(ctx, textarget)) {
glFramebufferTexture2D(GL_FRAMEBUFFER, kAttachments[i], textarget, 0, 0);
} else if (NamedObjectType::RENDERBUFFER == bufferType &&
GLESv2Validate::renderbufferTarget(textarget)) {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, kAttachments[i], textarget, 0);
}
// detach
fbObj->setAttachment(
ctx, kAttachments[i], (GLenum)0, 0, nullptr, false);
}
}
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_DRAW_FRAMEBUFFER);
s_detachFromFramebuffer(NamedObjectType::RENDERBUFFER,
renderbuffers[i], GL_READ_FRAMEBUFFER);
}
}
}
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);
if (ctx->getBindedTexture(GL_TEXTURE_2D_ARRAY) == textures[i])
ctx->setBindedTexture(GL_TEXTURE_2D_ARRAY,0);
if (ctx->getBindedTexture(GL_TEXTURE_3D) == textures[i])
ctx->setBindedTexture(GL_TEXTURE_3D,0);
if (ctx->getBindedTexture(GL_TEXTURE_2D_MULTISAMPLE) == textures[i])
ctx->setBindedTexture(GL_TEXTURE_2D_MULTISAMPLE,0);
if (ctx->getBindedTexture(GL_TEXTURE_BUFFER) == textures[i])
ctx->setBindedTexture(GL_TEXTURE_BUFFER,0);
s_detachFromFramebuffer(NamedObjectType::TEXTURE, textures[i], GL_DRAW_FRAMEBUFFER);
s_detachFromFramebuffer(NamedObjectType::TEXTURE, textures[i], GL_READ_FRAMEBUFFER);
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());
s_detachShader(ctx, program, pData->getAttachedComputeShader());
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->setDepthFunc(func);
ctx->dispatcher().glDepthFunc(func);
}
GL_APICALL void GL_APIENTRY glDepthMask(GLboolean flag){
GET_CTX();
ctx->setDepthMask(flag);
ctx->dispatcher().glDepthMask(flag);
}
GL_APICALL void GL_APIENTRY glDepthRangef(GLclampf zNear, GLclampf zFar){
GET_CTX();
ctx->setDepthRangef(zNear, zFar);
if (isGles2Gles()) {
ctx->dispatcher().glDepthRangef(zNear,zFar);
} else {
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();
if (isCoreProfile()) {
switch (cap) {
case GL_TEXTURE_2D:
case GL_POINT_SPRITE_OES:
// always enabled in core
return;
}
}
#ifdef __APPLE__
if (!isGles2Gles()) {
switch (cap) {
case GL_PRIMITIVE_RESTART_FIXED_INDEX:
ctx->setPrimitiveRestartEnabled(false);
ctx->setEnable(cap, false);
return;
}
}
#endif
ctx->setEnable(cap, false);
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);
}
// s_glDrawPre/Post() are for draw calls' fast paths.
static void s_glDrawPre(GLESv2Context* ctx, GLenum mode, GLenum type = 0) {
SHADER_DEBUG_PRINT("draw with program %u", ctx->getCurrentProgram());
if (isGles2Gles()) {
return;
}
if (ctx->getMajorVersion() < 3)
ctx->drawValidate();
//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_VERTEX_PROGRAM_POINT_SIZE);
if (!isCoreProfile()) {
ctx->dispatcher().glEnable(GL_POINT_SPRITE);
}
}
#ifdef __APPLE__
if (ctx->primitiveRestartEnabled() && type) {
ctx->updatePrimitiveRestartIndex(type);
}
#endif
}
static void s_glDrawPost(GLESv2Context* ctx, GLenum mode) {
if (isGles2Gles()) {
return;
}
if (mode == GL_POINTS) {
ctx->dispatcher().glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
if (!isCoreProfile()) {
ctx->dispatcher().glDisable(GL_POINT_SPRITE);
}
}
}
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);
if (ctx->vertexAttributesBufferBacked()) {
s_glDrawPre(ctx, mode);
ctx->dispatcher().glDrawArrays(mode,first,count);
s_glDrawPost(ctx, mode);
} else {
ctx->drawWithEmulations(
GLESv2Context::DrawCallCmd::Arrays,
mode, first, count,
0, nullptr, 0, 0, 0 /* type, indices, primcount, start, end unused */);
}
}
GL_APICALL void GL_APIENTRY glDrawArraysNullAEMU(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);
if (ctx->vertexAttributesBufferBacked()) {
s_glDrawPre(ctx, mode);
// No host driver draw
s_glDrawPost(ctx, mode);
} else {
// TODO: Null draw with emulations
ctx->drawWithEmulations(
GLESv2Context::DrawCallCmd::Arrays,
mode, first, count,
0, nullptr, 0, 0, 0 /* type, indices, primcount, start, end unused */);
}
}
GL_APICALL void GL_APIENTRY glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
GET_CTX_V2();
SET_ERROR_IF(count < 0,GL_INVALID_VALUE)
SET_ERROR_IF(!(GLESv2Validate::drawMode(mode) && GLESv2Validate::drawType(type)),GL_INVALID_ENUM);
if (ctx->isBindedBuffer(GL_ELEMENT_ARRAY_BUFFER) &&
ctx->vertexAttributesBufferBacked()) {
s_glDrawPre(ctx, mode, type);
ctx->dispatcher().glDrawElements(mode, count, type, indices);
s_glDrawPost(ctx, mode);
} else {
ctx->drawWithEmulations(
GLESv2Context::DrawCallCmd::Elements,
mode, 0 /* first (unused) */, count, type, indices,
0, 0, 0 /* primcount, start, end (unused) */);
}
}
GL_APICALL void GL_APIENTRY glDrawElementsNullAEMU(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices) {
GET_CTX_V2();
SET_ERROR_IF(count < 0,GL_INVALID_VALUE)
SET_ERROR_IF(!(GLESv2Validate::drawMode(mode) && GLESv2Validate::drawType(type)),GL_INVALID_ENUM);
if (ctx->isBindedBuffer(GL_ELEMENT_ARRAY_BUFFER) &&
ctx->vertexAttributesBufferBacked()) {
s_glDrawPre(ctx, mode, type);
// No host driver draw
s_glDrawPost(ctx, mode);
} else {
ctx->drawWithEmulations(
GLESv2Context::DrawCallCmd::Elements,
mode, 0 /* first (unused) */, count, type, indices,
0, 0, 0 /* primcount, start, end (unused) */);
}
}
GL_APICALL void GL_APIENTRY glEnable(GLenum cap){
GET_CTX();
if (isCoreProfile()) {
switch (cap) {
case GL_TEXTURE_2D:
case GL_POINT_SPRITE_OES:
return;
}
}
#ifdef __APPLE__
if (!isGles2Gles()) {
switch (cap) {
case GL_PRIMITIVE_RESTART_FIXED_INDEX:
ctx->setPrimitiveRestartEnabled(true);
ctx->setEnable(cap, true);
return;
}
}
#endif
ctx->setEnable(cap, true);
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_V2();
SET_ERROR_IF(!(GLESv2Validate::framebufferTarget(ctx, target) &&
GLESv2Validate::renderbufferTarget(renderbuffertarget) &&
GLESv2Validate::framebufferAttachment(ctx, attachment)), GL_INVALID_ENUM);
SET_ERROR_IF(!ctx->shareGroup().get(), GL_INVALID_OPERATION);
SET_ERROR_IF(ctx->isDefaultFBOBound(target), 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);
RenderbufferData* rboData = new RenderbufferData();
rboData->everBound = true;
obj = ObjectDataPtr(rboData);
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(target);
auto fbObj = ctx->getFBOData(fbName);
if (fbObj != NULL) {
fbObj->setAttachment(
ctx, 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().glFramebufferTexture2D(target,
attachment,
GL_TEXTURE_2D,
rbData->eglImageGlobalTexObject->getGlobalName(),
0);
return;
}
}
ctx->dispatcher().glFramebufferRenderbuffer(target,attachment,renderbuffertarget,globalRenderbufferName);
sUpdateFboEmulation(ctx);
}
GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::framebufferTarget(ctx, target) &&
GLESv2Validate::textureTargetEx(ctx, textarget) &&
GLESv2Validate::framebufferAttachment(ctx, attachment)), GL_INVALID_ENUM);
SET_ERROR_IF(ctx->getMajorVersion() < 3 && level != 0, GL_INVALID_VALUE);
SET_ERROR_IF(!ctx->shareGroup().get(), GL_INVALID_OPERATION);
SET_ERROR_IF(ctx->isDefaultFBOBound(target), GL_INVALID_OPERATION);
SET_ERROR_IF(texture &&
!ctx->shareGroup()->isObject(NamedObjectType::TEXTURE, texture),
GL_INVALID_OPERATION);
GLuint globalTextureName = 0;
if(texture) {
ObjectLocalName texname = ctx->getTextureLocalName(textarget,texture);
globalTextureName = ctx->shareGroup()->getGlobalName(
NamedObjectType::TEXTURE, texname);
TextureData* texData = getTextureData(texname);
if (texData) {
texData->makeDirty();
}
}
ctx->dispatcher().glFramebufferTexture2D(target,attachment,textarget,globalTextureName,level);
// Update the the current framebuffer object attachment state
GLuint fbName = ctx->getFramebufferBinding(target);
auto fbObj = ctx->getFBOData(fbName);
if (fbObj) {
fbObj->setAttachment(
ctx, attachment, textarget, texture, ObjectDataPtr());
}
sUpdateFboEmulation(ctx);
}
GL_APICALL void GL_APIENTRY glFrontFace(GLenum mode){
GET_CTX();
ctx->setFrontFace(mode);
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()));
}
}
}
static int maxMipmapLevel(GLsizei width, GLsizei height) {
// + 0.5 for potential floating point rounding issue
return log2(std::max(width, height) + 0.5);
}
GL_APICALL void GL_APIENTRY glGenerateMipmap(GLenum target){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::textureTarget(ctx, target), GL_INVALID_ENUM);
// Assuming we advertised GL_OES_texture_npot
if (ctx->shareGroup().get()) {
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->setMipmapLevelAtLeast(maxMipmapLevel(texData->width,
texData->height));
}
}
ctx->dispatcher().glGenerateMipmap(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->genFBOName(0, true);
ctx->setFBOData(framebuffers[i],
ObjectDataPtr(
new FramebufferData(
framebuffers[i],
ctx->getFBOGlobalName(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);
}
}
}
static void s_getActiveAttribOrUniform(bool isUniform, GLEScontext* ctx,
ProgramData* pData,
GLuint globalProgramName, GLuint index,
GLsizei bufsize, GLsizei* length,
GLint* size, GLenum* type,
GLchar* name) {
auto& gl = ctx->dispatcher();
GLsizei hostBufSize = 256;
GLsizei hostLen = 0;
GLint hostSize = 0;
GLenum hostType = 0;
gl.glGetProgramiv(
globalProgramName,
isUniform ? GL_ACTIVE_UNIFORM_MAX_LENGTH : GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
(GLint*)&hostBufSize);
std::string hostVarName(hostBufSize + 1, 0);
char watch_val = 0xfe;
hostVarName[0] = watch_val;
if (isUniform) {
gl.glGetActiveUniform(globalProgramName, index, hostBufSize, &hostLen,
&hostSize, &hostType, &hostVarName[0]);
} else {
gl.glGetActiveAttrib(globalProgramName, index, hostBufSize, &hostLen,
&hostSize, &hostType, &hostVarName[0]);
}
// here, something failed on the host side,
// so bail early.
if (hostVarName[0] == watch_val) {
return;
}
// Got a valid string from host GL, but
// we need to return the exact strlen to the GL user.
hostVarName.resize(strlen(hostVarName.c_str()));
// Things seem to have gone right, so translate the name
// and fill out all applicable guest fields.
auto guestVarName = pData->getDetranslatedName(hostVarName);
// Don't overstate how many non-nullterminator characters
// we are returning.
int strlenForGuest = std::min((int)(bufsize - 1), (int)guestVarName.size());
if (length) *length = strlenForGuest;
if (size) *size = hostSize;
if (type) *type = hostType;
// use the guest's bufsize, but don't run over.
if (name) memcpy(name, guestVarName.data(), strlenForGuest + 1);
}
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);
GLint numActiveAttributes = 0;
ctx->dispatcher().glGetProgramiv(
globalProgramName, GL_ACTIVE_ATTRIBUTES, &numActiveAttributes);
SET_ERROR_IF(index >= numActiveAttributes, GL_INVALID_VALUE);
SET_ERROR_IF(bufsize < 0, GL_INVALID_VALUE);
ProgramData* pData = (ProgramData*)objData;
s_getActiveAttribOrUniform(false, ctx, pData,
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);
GLint numActiveUniforms = 0;
ctx->dispatcher().glGetProgramiv(globalProgramName, GL_ACTIVE_UNIFORMS,
&numActiveUniforms);
SET_ERROR_IF(index >= numActiveUniforms, GL_INVALID_VALUE);
SET_ERROR_IF(bufsize < 0, GL_INVALID_VALUE);
ProgramData* pData = (ProgramData*)objData;
s_getActiveAttribOrUniform(true, ctx, pData,
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;
#if !defined(TOLERATE_PROGRAM_LINK_ERROR) || !TOLERATE_PROGRAM_LINK_ERROR
RET_AND_SET_ERROR_IF(!pData->getLinkStatus(), GL_INVALID_OPERATION,
-1);
#endif
int ret = ctx->dispatcher().glGetAttribLocation(
globalProgramName, pData->getTranslatedName(name).c_str());
if (ret != -1) {
pData->linkedAttribLocation(name, ret);
}
return ret;
}
return -1;
}
template <typename T>
using GLStateQueryFunc = void (*)(GLenum pname, T* params);
template <typename T>
using GLStateQueryFuncIndexed = void (*)(GLenum pname, GLuint index, T* params);
static void s_glGetBooleanv_wrapper(GLenum pname, GLboolean* params) {
GET_CTX();
ctx->dispatcher().glGetBooleanv(pname, params);
}
static void s_glGetIntegerv_wrapper(GLenum pname, GLint* params) {
GET_CTX();
ctx->dispatcher().glGetIntegerv(pname, params);
}
static void s_glGetInteger64v_wrapper(GLenum pname, GLint64* params) {
GET_CTX();
ctx->dispatcher().glGetInteger64v(pname, params);
}
static void s_glGetFloatv_wrapper(GLenum pname, GLfloat* params) {
GET_CTX();
ctx->dispatcher().glGetFloatv(pname, params);
}
static void s_glGetIntegeri_v_wrapper(GLenum pname, GLuint index, GLint* data) {
GET_CTX_V2();
ctx->dispatcher().glGetIntegeri_v(pname, index, data);
}
static void s_glGetInteger64i_v_wrapper(GLenum pname, GLuint index, GLint64* data) {
GET_CTX_V2();
ctx->dispatcher().glGetInteger64i_v(pname, index, data);
}
template <class T>
static void s_glStateQueryTv(bool es2, GLenum pname, T* params, GLStateQueryFunc<T> getter) {
T i;
GLint iparams[4];
GET_CTX_V2();
switch (pname) {
case GL_VIEWPORT:
ctx->getViewport(iparams);
params[0] = (T)iparams[0];
params[1] = (T)iparams[1];
params[2] = (T)iparams[2];
params[3] = (T)iparams[3];
break;
case GL_CURRENT_PROGRAM:
if (ctx->shareGroup().get()) {
*params = (T)ctx->getCurrentProgram();
}
break;
case GL_FRAMEBUFFER_BINDING:
case GL_READ_FRAMEBUFFER_BINDING:
getter(pname,&i);
*params = ctx->getFBOLocalName(i);
break;
case GL_RENDERBUFFER_BINDING:
if (ctx->shareGroup().get()) {
getter(pname,&i);
*params = ctx->shareGroup()->getLocalName(
NamedObjectType::RENDERBUFFER, i);
}
break;
case GL_READ_BUFFER:
case GL_DRAW_BUFFER0:
if (ctx->shareGroup().get()) {
getter(pname, &i);
GLenum target = pname == GL_READ_BUFFER ? GL_READ_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER;
if (ctx->isDefaultFBOBound(target) && (GLint)i == GL_COLOR_ATTACHMENT0) {
i = (T)GL_BACK;
}
*params = i;
}
break;
case GL_VERTEX_ARRAY_BINDING:
getter(pname,&i);
*params = ctx->getVAOLocalName(i);
break;
case GL_ARRAY_BUFFER_BINDING:
*params = ctx->getBuffer(GL_ARRAY_BUFFER);
break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
*params = ctx->getBuffer(GL_ELEMENT_ARRAY_BUFFER);
break;
case GL_COPY_READ_BUFFER_BINDING:
*params = ctx->getBuffer(GL_COPY_READ_BUFFER);
break;
case GL_COPY_WRITE_BUFFER_BINDING:
*params = ctx->getBuffer(GL_COPY_WRITE_BUFFER);
break;
case GL_PIXEL_PACK_BUFFER_BINDING:
*params = ctx->getBuffer(GL_PIXEL_PACK_BUFFER);
break;
case GL_PIXEL_UNPACK_BUFFER_BINDING:
*params = ctx->getBuffer(GL_PIXEL_UNPACK_BUFFER);
break;
case GL_TRANSFORM_FEEDBACK_BINDING:
*params = ctx->getTransformFeedbackBinding();
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
*params = ctx->getBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
break;
case GL_UNIFORM_BUFFER_BINDING:
*params = ctx->getBuffer(GL_UNIFORM_BUFFER);
break;
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
*params = ctx->getBuffer(GL_ATOMIC_COUNTER_BUFFER);
break;
case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
*params = ctx->getBuffer(GL_DISPATCH_INDIRECT_BUFFER);
break;
case GL_DRAW_INDIRECT_BUFFER_BINDING:
*params = ctx->getBuffer(GL_DRAW_INDIRECT_BUFFER);
break;
case GL_SHADER_STORAGE_BUFFER_BINDING:
*params = ctx->getBuffer(GL_SHADER_STORAGE_BUFFER);
break;
case GL_TEXTURE_BUFFER_BINDING:
*params = ctx->getBuffer(GL_TEXTURE_BUFFER);
break;
case GL_TEXTURE_BINDING_2D:
*params = ctx->getBindedTexture(GL_TEXTURE_2D);
break;
case GL_TEXTURE_BINDING_CUBE_MAP:
*params = ctx->getBindedTexture(GL_TEXTURE_CUBE_MAP);
break;
case GL_TEXTURE_BINDING_2D_ARRAY:
*params = ctx->getBindedTexture(GL_TEXTURE_2D_ARRAY);
break;
case GL_TEXTURE_BINDING_3D:
*params = ctx->getBindedTexture(GL_TEXTURE_3D);
break;
case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
*params = ctx->getBindedTexture(GL_TEXTURE_2D_MULTISAMPLE);
break;
case GL_TEXTURE_BINDING_BUFFER:
*params = ctx->getBindedTexture(GL_TEXTURE_BUFFER);
break;
case GL_SAMPLER_BINDING:
if (ctx->shareGroup().get()) {
getter(pname,&i);
*params = ctx->shareGroup()->getLocalName(
NamedObjectType::SAMPLER, i);
}
break;
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
*params = (T)getCompressedFormats(2, NULL);
break;
case GL_COMPRESSED_TEXTURE_FORMATS:
{
int nparams = getCompressedFormats(2, NULL);
if (nparams > 0) {
int* iparams = new int[nparams];
getCompressedFormats(2, iparams);
for (int i = 0; i < nparams; i++) {
params[i] = (T)iparams[i];
}
delete [] iparams;
}
}
break;
case GL_SHADER_COMPILER:
if(es2)
getter(pname, params);
else
*params = 1;
break;
case GL_SHADER_BINARY_FORMATS:
if(es2)
getter(pname,params);
break;
case GL_NUM_SHADER_BINARY_FORMATS:
if(es2)
getter(pname,params);
else
*params = 0;
break;
case GL_MAX_VERTEX_UNIFORM_VECTORS:
if(es2)
getter(pname,params);
else
*params = 128;
break;
case GL_MAX_VERTEX_ATTRIBS:
*params = kMaxVertexAttributes;
break;
case GL_MAX_VARYING_VECTORS:
if(es2)
getter(pname,params);
else
*params = 8;
break;
case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
if(es2)
getter(pname,params);
else
*params = 16;
break;
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
getter(pname,params);
break;
case GL_STENCIL_BACK_VALUE_MASK:
case GL_STENCIL_BACK_WRITEMASK:
case GL_STENCIL_VALUE_MASK:
case GL_STENCIL_WRITEMASK:
{
T myT = 0;
getter(pname, &myT);
*params = myT;
}
break;
// Core-profile related fixes
case GL_GENERATE_MIPMAP_HINT:
if (isCoreProfile()) {
*params = ctx->getHint(GL_GENERATE_MIPMAP_HINT);
} else {
getter(pname, params);
}
break;
case GL_RED_BITS:
case GL_GREEN_BITS:
case GL_BLUE_BITS:
case GL_ALPHA_BITS:
case GL_DEPTH_BITS:
case GL_STENCIL_BITS:
if (isCoreProfile()) {
GLuint fboBinding = ctx->getFramebufferBinding(GL_DRAW_FRAMEBUFFER);
*params = (T)ctx->queryCurrFboBits(fboBinding, pname);
} else {
getter(pname, params);
}
break;
case GL_ALIASED_POINT_SIZE_RANGE:
if (isCoreProfile()) {
#ifndef GL_POINT_SIZE_RANGE
#define GL_POINT_SIZE_RANGE 0x0B12
#endif
getter(GL_POINT_SIZE_RANGE, params);
} else {
getter(pname, params);
}
break;
default:
getter(pname,params);
break;
}
}
template <typename T>
static void s_glStateQueryTi_v(GLenum pname, GLuint index, T* params, GLStateQueryFuncIndexed<T> getter) {
GET_CTX_V2();
switch (pname) {
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
*params = ctx->getIndexedBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, index);
break;
case GL_UNIFORM_BUFFER_BINDING:
*params = ctx->getIndexedBuffer(GL_UNIFORM_BUFFER, index);
break;
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
*params = ctx->getIndexedBuffer(GL_ATOMIC_COUNTER_BUFFER, index);
break;
case GL_SHADER_STORAGE_BUFFER_BINDING:
*params = ctx->getIndexedBuffer(GL_SHADER_STORAGE_BUFFER, index);
break;
case GL_IMAGE_BINDING_NAME:
// Need the local name here.
getter(pname, index, params);
*params = ctx->shareGroup()->getLocalName(NamedObjectType::TEXTURE, *params);
break;
default:
getter(pname, index, params);
break;
}
}
GL_APICALL void GL_APIENTRY glGetBooleanv(GLenum pname, GLboolean* params){
GET_CTX_V2();
#define TO_GLBOOL(params, x) \
*params = x ? GL_TRUE : GL_FALSE; \
GLint i = 0;
switch (pname) {
case GL_CURRENT_PROGRAM:
if (ctx->shareGroup().get()) {
s_glGetIntegerv_wrapper(pname,&i);
TO_GLBOOL(params,ctx->shareGroup()->getLocalName(NamedObjectType::SHADER_OR_PROGRAM, i));
}
break;
case GL_FRAMEBUFFER_BINDING:
case GL_READ_FRAMEBUFFER_BINDING:
s_glGetIntegerv_wrapper(pname,&i);
TO_GLBOOL(params,ctx->getFBOLocalName(i));
break;
case GL_RENDERBUFFER_BINDING:
if (ctx->shareGroup().get()) {
s_glGetIntegerv_wrapper(pname,&i);
TO_GLBOOL(params,ctx->shareGroup()->getLocalName(NamedObjectType::RENDERBUFFER, i));
}
break;
case GL_ARRAY_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_ARRAY_BUFFER));
break;
case GL_ELEMENT_ARRAY_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_ELEMENT_ARRAY_BUFFER));
break;
case GL_COPY_READ_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_COPY_READ_BUFFER));
break;
case GL_COPY_WRITE_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_COPY_WRITE_BUFFER));
break;
case GL_PIXEL_PACK_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_PIXEL_PACK_BUFFER));
break;
case GL_PIXEL_UNPACK_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_PIXEL_UNPACK_BUFFER));
break;
case GL_TRANSFORM_FEEDBACK_BINDING:
TO_GLBOOL(params, ctx->getTransformFeedbackBinding());
break;
case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_TRANSFORM_FEEDBACK_BUFFER));
break;
case GL_UNIFORM_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_UNIFORM_BUFFER));
break;
case GL_ATOMIC_COUNTER_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_ATOMIC_COUNTER_BUFFER));
break;
case GL_DISPATCH_INDIRECT_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_DISPATCH_INDIRECT_BUFFER));
break;
case GL_DRAW_INDIRECT_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_DRAW_INDIRECT_BUFFER));
break;
case GL_SHADER_STORAGE_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_SHADER_STORAGE_BUFFER));
break;
case GL_TEXTURE_BUFFER_BINDING:
TO_GLBOOL(params, ctx->getBuffer(GL_TEXTURE_BUFFER));
break;
case GL_TEXTURE_BINDING_2D:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_2D));
break;
case GL_TEXTURE_BINDING_CUBE_MAP:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_CUBE_MAP));
break;
case GL_TEXTURE_BINDING_2D_ARRAY:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_2D_ARRAY));
break;
case GL_TEXTURE_BINDING_3D:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_3D));
break;
case GL_TEXTURE_BINDING_2D_MULTISAMPLE:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_2D_MULTISAMPLE));
break;
case GL_TEXTURE_BINDING_BUFFER:
TO_GLBOOL(params, ctx->getBindedTexture(GL_TEXTURE_BUFFER));
break;
case GL_SAMPLER_BINDING:
if (ctx->shareGroup().get()) {
s_glGetIntegerv_wrapper(pname,&i);
TO_GLBOOL(params,ctx->shareGroup()->getLocalName(NamedObjectType::SAMPLER, i));
}
break;
case GL_VERTEX_ARRAY_BINDING:
s_glGetIntegerv_wrapper(pname,&i);
TO_GLBOOL(params, ctx->getVAOLocalName(i));
break;
case GL_GENERATE_MIPMAP_HINT:
if (isCoreProfile()) {
TO_GLBOOL(params, ctx->getHint(GL_GENERATE_MIPMAP_HINT));
} else {
s_glGetBooleanv_wrapper(pname, params);
}
break;
case GL_RED_BITS:
case GL_GREEN_BITS:
case GL_BLUE_BITS:
case GL_ALPHA_BITS:
case GL_DEPTH_BITS:
case GL_STENCIL_BITS:
if (isCoreProfile()) {
GLuint fboBinding = ctx->getFramebufferBinding(GL_DRAW_FRAMEBUFFER);
TO_GLBOOL(params, ctx->queryCurrFboBits(fboBinding, pname));
} else {
s_glGetBooleanv_wrapper(pname, params);
}
break;
case GL_ALIASED_POINT_SIZE_RANGE:
if (isCoreProfile()) {
#ifndef GL_POINT_SIZE_RANGE
#define GL_POINT_SIZE_RANGE 0x0B12
#endif
s_glGetBooleanv_wrapper(GL_POINT_SIZE_RANGE, params);
} else {
s_glGetBooleanv_wrapper(pname, params);
}
break;
default:
s_glGetBooleanv_wrapper(pname, params);
break;
}
}
GL_APICALL void GL_APIENTRY glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::bufferTarget(ctx, target), GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::bufferParam(ctx, 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();
s_glStateQueryTv<GLfloat>(true, pname, params, s_glGetFloatv_wrapper);
}
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;
}
// For non-int64 glGetIntegerv, the following params have precision issues,
// so just use glGetFloatv straight away:
GLfloat floatVals[4];
switch (pname) {
case GL_DEPTH_RANGE:
case GL_BLEND_COLOR:
case GL_COLOR_CLEAR_VALUE:
case GL_DEPTH_CLEAR_VALUE:
ctx->dispatcher().glGetFloatv(pname, floatVals);
default:
break;
}
int converted_float_params = 0;
switch (pname) {
case GL_DEPTH_RANGE:
converted_float_params = 2;
break;
case GL_BLEND_COLOR:
case GL_COLOR_CLEAR_VALUE:
converted_float_params = 4;
break;
case GL_DEPTH_CLEAR_VALUE:
converted_float_params = 1;
break;
default:
break;
}
if (converted_float_params) {
for (int i = 0; i < converted_float_params; i++) {
params[i] = (GLint)((GLint64)(floatVals[i] * 2147483647.0));
}
return;
}
bool es2 = ctx->getCaps()->GL_ARB_ES2_COMPATIBILITY;
s_glStateQueryTv<GLint>(es2, pname, params, s_glGetIntegerv_wrapper);
if (destroyCtx)
deleteGLESContext(ctx);
}
GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params){
GET_CTX_V2();
//
// Take the attachment attribute from our state - if available
//
GLuint fbName = ctx->getFramebufferBinding(target);
if (fbName) {
auto fbObj = ctx->getFBOData(fbName);
if (fbObj != NULL) {
GLenum target;
GLuint name = fbObj->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;
}
}
}
if (ctx->isDefaultFBOBound(target)) {
SET_ERROR_IF(
attachment == GL_DEPTH_ATTACHMENT ||
attachment == GL_STENCIL_ATTACHMENT ||
attachment == GL_DEPTH_STENCIL_ATTACHMENT ||
(attachment >= GL_COLOR_ATTACHMENT0 &&
attachment <= GL_COLOR_ATTACHMENT15), GL_INVALID_OPERATION);
SET_ERROR_IF(pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, GL_INVALID_ENUM);
if (attachment == GL_BACK)
attachment = GL_COLOR_ATTACHMENT0;
if (attachment == GL_DEPTH)
attachment = GL_DEPTH_ATTACHMENT;
if (attachment == GL_STENCIL)
attachment = GL_STENCIL_ATTACHMENT;
}
ctx->dispatcher().glGetFramebufferAttachmentParameteriv(target,attachment,pname,params);
if (ctx->isDefaultFBOBound(target) && *params == GL_RENDERBUFFER) {
*params = GL_FRAMEBUFFER_DEFAULT;
}
}
GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::renderbufferTarget(target) &&
GLESv2Validate::renderbufferParam(ctx, 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().glGetRenderbufferParameteriv(target,pname,params);
// An uninitialized renderbuffer storage may give a format of GL_RGBA on
// some drivers; GLES2 default is GL_RGBA4.
if (pname == GL_RENDERBUFFER_INTERNAL_FORMAT && *params == GL_RGBA) {
*params = GL_RGBA4;
}
}
GL_APICALL void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::programParam(ctx, 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() ? GL_TRUE : GL_FALSE;
}
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;
params[0] = programData->getValidateStatus() ? GL_TRUE : 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);
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;
switch(pname) {
case GL_DELETE_STATUS:
{
params[0] = (sp->getDeleteStatus()) ? GL_TRUE : GL_FALSE;
}
break;
case GL_INFO_LOG_LENGTH:
{
GLint logLength = strlen(sp->getInfoLog());
params[0] = (logLength > 0) ? logLength + 1 : 0;
}
break;
case GL_SHADER_SOURCE_LENGTH:
{
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(ctx, shadertype) &&
GLESv2Validate::precisionType(precisiontype)),GL_INVALID_ENUM);
switch (precisiontype) {
case GL_LOW_INT:
case GL_MEDIUM_INT:
// range[0] = range[1] = 16;
// *precision = 0;
// break;
case GL_HIGH_INT:
range[0] = 31;
range[1] = 30;
*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_V2_RET(NULL)
static const GLubyte SHADING[] = "OpenGL ES GLSL ES 1.0.17";
static const GLubyte SHADING30[] = "OpenGL ES GLSL ES 3.00";
static const GLubyte SHADING31[] = "OpenGL ES GLSL ES 3.10";
static const GLubyte SHADING32[] = "OpenGL ES GLSL ES 3.20";
switch(name) {
case GL_VENDOR:
return (const GLubyte*)ctx->getVendorString(false /* not gles1 */);
case GL_RENDERER:
return (const GLubyte*)ctx->getRendererString(false /* not gles1 */);
case GL_VERSION:
return (const GLubyte*)ctx->getVersionString(false /* not gles1 */);
case GL_SHADING_LANGUAGE_VERSION:
switch (ctx->getMajorVersion()) {
case 3:
switch (ctx->getMinorVersion()) {
case 0:
return SHADING30;
case 1:
return SHADING31;
case 2:
return SHADING32;
default:
return SHADING31;
}
default:
return SHADING;
}
case GL_EXTENSIONS:
return (const GLubyte*)ctx->getExtensionString(false /* not gles1 */);
default:
RET_AND_SET_ERROR_IF(true,GL_INVALID_ENUM,NULL);
}
}
static bool sShouldEmulateSwizzles(TextureData* texData, GLenum target, GLenum pname) {
return texData && isCoreProfile() && isSwizzleParam(pname) &&
isCoreProfileEmulatedFormat(texData->format);
}
GL_APICALL void GL_APIENTRY glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData* texData = getTextureTargetData(target);
if (sShouldEmulateSwizzles(texData, target, pname)) {
*params = (GLfloat)(texData->getSwizzle(pname));
return;
}
ctx->dispatcher().glGetTexParameterfv(target, pname, params);
}
GL_APICALL void GL_APIENTRY glGetTexParameteriv(GLenum target, GLenum pname, GLint* params){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData* texData = getTextureTargetData(target);
if (sShouldEmulateSwizzles(texData, target, pname)) {
*params = texData->getSwizzle(pname);
return;
}
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;
#if !defined(TOLERATE_PROGRAM_LINK_ERROR) || !TOLERATE_PROGRAM_LINK_ERROR
SET_ERROR_IF(!pData->getLinkStatus(), GL_INVALID_OPERATION);
#endif
ctx->dispatcher().glGetUniformfv(globalProgramName,
pData->getHostUniformLocation(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;
#if !defined(TOLERATE_PROGRAM_LINK_ERROR) || !TOLERATE_PROGRAM_LINK_ERROR
SET_ERROR_IF(!pData->getLinkStatus(), GL_INVALID_OPERATION);
#endif
ctx->dispatcher().glGetUniformiv(globalProgramName,
pData->getHostUniformLocation(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;
#if !defined(TOLERATE_PROGRAM_LINK_ERROR) || !TOLERATE_PROGRAM_LINK_ERROR
RET_AND_SET_ERROR_IF(!pData->getLinkStatus(), GL_INVALID_OPERATION, -1);
#endif
return pData->getGuestUniformLocation(name);
}
return -1;
}
static bool s_invalidVertexAttribIndex(GLuint index) {
GLint param=0;
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &param);
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 = p->getBufferName();
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) {
if (p->getBufferName() == 0) {
// vertex attrib has no buffer, return array data pointer
*pointer = const_cast<GLvoid*>(p->getArrayData());
} else {
// vertex attrib has buffer, return offset
*pointer = reinterpret_cast<GLvoid*>(p->getBufferOffset());
}
} 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);
if (isCoreProfile() &&
target == GL_GENERATE_MIPMAP_HINT) {
ctx->setHint(target, mode);
} else {
ctx->dispatcher().glHint(target,mode);
}
}
GL_APICALL GLboolean GL_APIENTRY glIsEnabled(GLenum cap){
GET_CTX_RET(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){
if (!ctx->isFBO(framebuffer))
return GL_FALSE;
auto fbObj = ctx->getFBOData(framebuffer);
if (!fbObj) return GL_FALSE;
return fbObj->hasBeenBoundAtLeastOnce() ? 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()){
auto obj = ctx->shareGroup()->getObjectDataPtr(
NamedObjectType::RENDERBUFFER, renderbuffer);
if (obj) {
RenderbufferData *rboData = (RenderbufferData *)obj.get();
return rboData->everBound ? 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->setLineWidth(width);
#ifdef __APPLE__
// There is no line width setting on Mac core profile.
// Line width emulation can be done (replace user's
// vertex buffer with thick triangles of our own),
// but just have thin lines on Mac for now.
if (!ctx->isCoreProfile() || isGles2Gles()) {
ctx->dispatcher().glLineWidth(width);
}
#else
ctx->dispatcher().glLineWidth(width);
#endif
}
GL_APICALL void GL_APIENTRY glLinkProgram(GLuint program){
GET_CTX_V2();
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 (ctx->getMajorVersion() >= 3 && ctx->getMinorVersion() >= 1) {
ctx->dispatcher().glLinkProgram(globalProgramName);
ctx->dispatcher().glGetProgramiv(globalProgramName,GL_LINK_STATUS,&linkStatus);
programData->setHostLinkStatus(linkStatus);
} else {
if (vertexShader != 0 && fragmentShader!=0) {
auto fragObjData = ctx->shareGroup()->getObjectData(
NamedObjectType::SHADER_OR_PROGRAM, fragmentShader);
auto vertObjData = ctx->shareGroup()->getObjectData(
NamedObjectType::SHADER_OR_PROGRAM, vertexShader);
ShaderParser* fragSp = (ShaderParser*)fragObjData;
ShaderParser* vertSp = (ShaderParser*)vertObjData;
if(fragSp->getCompileStatus() && vertSp->getCompileStatus()) {
ctx->dispatcher().glLinkProgram(globalProgramName);
ctx->dispatcher().glGetProgramiv(globalProgramName,GL_LINK_STATUS,&linkStatus);
programData->setHostLinkStatus(linkStatus);
if (!programData->validateLink(fragSp, vertSp)) {
programData->setLinkStatus(GL_FALSE);
programData->setErrInfoLog();
return;
}
}
}
}
programData->setLinkStatus(linkStatus);
GLsizei infoLogLength = 0, cLog = 0;
ctx->dispatcher().glGetProgramiv(globalProgramName, GL_INFO_LOG_LENGTH,
&infoLogLength);
std::unique_ptr<GLchar[]> log(new GLchar[infoLogLength + 1]);
ctx->dispatcher().glGetProgramInfoLog(globalProgramName, infoLogLength,
&cLog, log.get());
// Only update when there actually is something to update.
if (cLog > 0) {
programData->setInfoLog(log.release());
}
}
}
GL_APICALL void GL_APIENTRY glPixelStorei(GLenum pname, GLint param){
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::pixelStoreParam(ctx, pname), GL_INVALID_ENUM);
switch (pname) {
case GL_PACK_ALIGNMENT:
case GL_UNPACK_ALIGNMENT:
SET_ERROR_IF(!((param==1)||(param==2)||(param==4)||(param==8)), GL_INVALID_VALUE);
break;
default:
SET_ERROR_IF(param < 0, GL_INVALID_VALUE);
break;
}
ctx->setPixelStorei(pname, param);
ctx->dispatcher().glPixelStorei(pname,param);
}
GL_APICALL void GL_APIENTRY glPolygonOffset(GLfloat factor, GLfloat units){
GET_CTX();
ctx->setPolygonOffset(factor, units);
ctx->dispatcher().glPolygonOffset(factor,units);
}
GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
GL_APICALL void GL_APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
GL_APICALL void GL_APIENTRY glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::pixelOp(format,type)),GL_INVALID_OPERATION);
SET_ERROR_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE, GL_INVALID_FRAMEBUFFER_OPERATION);
if (ctx->isDefaultFBOBound(GL_READ_FRAMEBUFFER) &&
ctx->getDefaultFBOMultisamples()) {
GLint prev_bound_rbo;
GLint prev_bound_draw_fbo;
glGetIntegerv(GL_RENDERBUFFER_BINDING, &prev_bound_rbo);
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &prev_bound_draw_fbo);
GLuint resolve_fbo = 0;
GLuint resolve_rbo = 0;
glGenFramebuffers(1, &resolve_fbo);
glGenRenderbuffers(1, &resolve_rbo);
int fboFormat = ctx->getDefaultFBOColorFormat();
int fboWidth = ctx->getDefaultFBOWidth();
int fboHeight = ctx->getDefaultFBOHeight();
glBindRenderbuffer(GL_RENDERBUFFER, resolve_rbo);
glRenderbufferStorage(GL_RENDERBUFFER, fboFormat, fboWidth, fboHeight);
glBindFramebuffer(GL_FRAMEBUFFER, resolve_fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, resolve_rbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolve_fbo);
bool scissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
if (scissorEnabled) glDisable(GL_SCISSOR_TEST);
glBlitFramebuffer(0, 0, fboWidth, fboHeight, 0, 0, fboWidth, fboHeight,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
if (scissorEnabled) glEnable(GL_SCISSOR_TEST);
glBindFramebuffer(GL_READ_FRAMEBUFFER, resolve_fbo);
ctx->dispatcher().glReadPixels(x,y,width,height,format,type,pixels);
glDeleteRenderbuffers(1, &resolve_rbo);
glDeleteFramebuffers(1, &resolve_fbo);
glBindRenderbuffer(GL_RENDERBUFFER, prev_bound_rbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prev_bound_draw_fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
} else {
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__
}
static GLenum sPrepareRenderbufferStorage(GLenum internalformat, GLsizei width,
GLsizei height, GLint samples, GLint* err) {
GET_CTX_V2_RET(GL_NONE);
GLenum internal = internalformat;
if (!isGles2Gles() && ctx->getMajorVersion() < 3) {
switch (internalformat) {
case GL_RGB565:
internal = GL_RGB;
break;
case GL_RGB5_A1:
internal = GL_RGBA;
break;
default:
break;
}
}
// Get current bounded renderbuffer
// raise INVALID_OPERATIOn if no renderbuffer is bounded
GLuint rb = ctx->getRenderbufferBinding();
if (!rb) { *err = GL_INVALID_OPERATION; return GL_NONE; }
auto objData = ctx->shareGroup()->getObjectData(NamedObjectType::RENDERBUFFER, rb);
RenderbufferData *rbData = (RenderbufferData *)objData;
if (!rbData) { *err = GL_INVALID_OPERATION; return GL_NONE; }
rbData->internalformat = internalformat;
rbData->hostInternalFormat = internal;
rbData->width = width;
rbData->height = height;
rbData->samples = samples;
//
// if the renderbuffer was an eglImage target, release
// its underlying texture.
//
rbData->eglImageGlobalTexObject.reset();
rbData->saveableTexture.reset();
*err = GL_NO_ERROR;
return internal;
}
GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height){
GET_CTX();
GLint err = GL_NO_ERROR;
internalformat = sPrepareRenderbufferStorage(internalformat, width, height, 0, &err);
SET_ERROR_IF(err != GL_NO_ERROR, err);
ctx->dispatcher().glRenderbufferStorage(target,internalformat,width,height);
}
GL_APICALL void GL_APIENTRY glSampleCoverage(GLclampf value, GLboolean invert){
GET_CTX();
ctx->setSampleCoverage(value, invert);
ctx->dispatcher().glSampleCoverage(value,invert);
}
GL_APICALL void GL_APIENTRY glScissor(GLint x, GLint y, GLsizei width, GLsizei height){
GET_CTX();
ctx->setScissor(x, y, width, height);
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(count, string, length);
if (isGles2Gles()) {
if (sDebugPrintShaders) { // save repeated checks
for (GLsizei i = 0; i < count; ++i) {
SHADER_DEBUG_PRINT(
"(GLES->GLES) shader "
"%u source %d of %d: [%s]\n",
shader,
i, count,
string[i]);
}
}
ctx->dispatcher().glShaderSource(globalShaderName, count, string,
length);
} else {
if (sDebugPrintShaders) { // save repeated checks
for (GLsizei i = 0; i < 1; ++i) {
SHADER_DEBUG_PRINT(
"(GLES->GL translated) "
"shader %u source %d of %d: [%s]\n",
shader,
i, count,
sp->parsedLines()[i]);
}
}
ctx->dispatcher().glShaderSource(globalShaderName, 1, sp->parsedLines(),
NULL);
}
}
}
GL_APICALL void GL_APIENTRY glStencilFunc(GLenum func, GLint ref, GLuint mask){
GET_CTX();
ctx->setStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
ctx->dispatcher().glStencilFunc(func,ref,mask);
}
GL_APICALL void GL_APIENTRY glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask){
GET_CTX();
ctx->setStencilFuncSeparate(face, func, ref, mask);
ctx->dispatcher().glStencilFuncSeparate(face,func,ref,mask);
}
GL_APICALL void GL_APIENTRY glStencilMask(GLuint mask){
GET_CTX();
ctx->setStencilMaskSeparate(GL_FRONT_AND_BACK, mask);
ctx->dispatcher().glStencilMask(mask);
}
GL_APICALL void GL_APIENTRY glStencilMaskSeparate(GLenum face, GLuint mask){
GET_CTX();
ctx->setStencilMaskSeparate(face, mask);
ctx->dispatcher().glStencilMaskSeparate(face,mask);
}
GL_APICALL void GL_APIENTRY glStencilOp(GLenum fail, GLenum zfail, GLenum zpass){
GET_CTX();
ctx->setStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
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->setStencilOpSeparate(face, fail, zfail, zpass);
ctx->dispatcher().glStencilOpSeparate(face, fail,zfail,zpass);
}
#define GL_RGBA32F 0x8814
#define GL_RGB32F 0x8815
static void sPrepareTexImage2D(GLenum target, GLsizei level, GLint internalformat,
GLsizei width, GLsizei height, GLint border,
GLenum format, GLenum type, GLint samples, const GLvoid* pixels,
GLenum* type_out,
GLint* internalformat_out,
GLint* err_out) {
GET_CTX_V2();
#define VALIDATE(cond, err) do { if (cond) { *err_out = err; fprintf(stderr, "%s:%d failed validation\n", __FUNCTION__, __LINE__); return; } } while(0) \
bool isCompressedFormat =
GLESv2Validate::isCompressedFormat(internalformat);
if (!isCompressedFormat) {
VALIDATE(!(GLESv2Validate::textureTarget(ctx, target) ||
GLESv2Validate::textureTargetEx(ctx, target)), GL_INVALID_ENUM);
VALIDATE(!GLESv2Validate::pixelFrmt(ctx, format), GL_INVALID_ENUM);
VALIDATE(!GLESv2Validate::pixelType(ctx, type), GL_INVALID_ENUM);
VALIDATE(!GLESv2Validate::pixelItnlFrmt(ctx,internalformat), GL_INVALID_VALUE);
VALIDATE((GLESv2Validate::textureIsCubeMap(target) && width != height), GL_INVALID_VALUE);
VALIDATE(ctx->getMajorVersion() < 3 &&
(format == GL_DEPTH_COMPONENT || internalformat == GL_DEPTH_COMPONENT) &&
(type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT), GL_INVALID_OPERATION);
VALIDATE(ctx->getMajorVersion() < 3 &&
(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) &&
!((format == GL_DEPTH_COMPONENT && internalformat == GL_DEPTH_COMPONENT)
|| (format == GL_LUMINANCE && internalformat == GL_LUMINANCE)), GL_INVALID_OPERATION);
VALIDATE(!GLESv2Validate::pixelOp(format,type),GL_INVALID_OPERATION);
VALIDATE(!GLESv2Validate::pixelSizedFrmt(ctx, internalformat, format, type), GL_INVALID_OPERATION);
}
VALIDATE(border != 0,GL_INVALID_VALUE);
s_glInitTexImage2D(target, level, internalformat, width, height, border, samples,
&format, &type, &internalformat);
if (!isCompressedFormat && ctx->getMajorVersion() < 3 && !isGles2Gles()) {
if (type==GL_HALF_FLOAT_OES && !isGles2Gles())
type = GL_HALF_FLOAT_NV;
if (pixels==NULL && type==GL_UNSIGNED_SHORT_5_5_5_1)
type = GL_UNSIGNED_BYTE;
if (type == GL_FLOAT)
internalformat = (format == GL_RGBA) ? GL_RGBA32F : GL_RGB32F;
}
// Desktop OpenGL doesn't support GL_BGRA_EXT as internal format.
if (!isGles2Gles() && type == GL_UNSIGNED_BYTE && format == GL_BGRA_EXT &&
internalformat == GL_BGRA_EXT) {
internalformat = GL_RGBA;
}
*type_out = type;
*internalformat_out = internalformat;
*err_out = GL_NO_ERROR;
}
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_V2();
// clear previous error
GLint err = ctx->dispatcher().glGetError();
if (err != GL_NO_ERROR) {
fprintf(stderr, "%s: got err pre :( 0x%x internal 0x%x format 0x%x type 0x%x\n", __func__, err, internalformat, format, type);
}
sPrepareTexImage2D(target, level, internalformat, width, height, border, format, type, 0, pixels, &type, &internalformat, &err);
SET_ERROR_IF(err != GL_NO_ERROR, err);
if (isCoreProfile()) {
GLEScontext::prepareCoreProfileEmulatedTexture(
getTextureTargetData(target),
false, target, format, type,
&internalformat, &format);
}
ctx->dispatcher().glTexImage2D(target,level,internalformat,width,height,border,format,type,pixels);
err = ctx->dispatcher().glGetError();
if (err != GL_NO_ERROR) {
fprintf(stderr, "%s: got err :( 0x%x internal 0x%x format 0x%x type 0x%x\n", __func__, err, internalformat, format, type);
ctx->setGLerror(err); \
}
}
static void sEmulateUserTextureSwizzle(TextureData* texData,
GLenum target, GLenum pname, GLint param) {
GET_CTX_V2();
TextureSwizzle emulatedBaseSwizzle =
getSwizzleForEmulatedFormat(texData->format);
GLenum userSwz =
texData->getSwizzle(pname);
GLenum hostEquivalentSwizzle =
swizzleComponentOf(emulatedBaseSwizzle, userSwz);
ctx->dispatcher().glTexParameteri(target, pname, hostEquivalentSwizzle);
}
GL_APICALL void GL_APIENTRY glTexParameterf(GLenum target, GLenum pname, GLfloat param){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->setTexParam(pname, static_cast<GLint>(param));
}
if (sShouldEmulateSwizzles(texData, target, pname)) {
sEmulateUserTextureSwizzle(texData, target, pname, (GLint)param);
} else {
ctx->dispatcher().glTexParameterf(target,pname,param);
}
}
GL_APICALL void GL_APIENTRY glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->setTexParam(pname, static_cast<GLint>(params[0]));
}
if (sShouldEmulateSwizzles(texData, target, pname)) {
sEmulateUserTextureSwizzle(texData, target, pname, (GLint)params[0]);
} else {
ctx->dispatcher().glTexParameterfv(target,pname,params);
}
}
GL_APICALL void GL_APIENTRY glTexParameteri(GLenum target, GLenum pname, GLint param){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->setTexParam(pname, param);
}
if (sShouldEmulateSwizzles(texData, target, pname)) {
sEmulateUserTextureSwizzle(texData, target, pname, param);
} else {
ctx->dispatcher().glTexParameteri(target,pname,param);
}
}
GL_APICALL void GL_APIENTRY glTexParameteriv(GLenum target, GLenum pname, const GLint* params){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) &&
GLESv2Validate::textureParams(ctx, pname)),
GL_INVALID_ENUM);
TextureData *texData = getTextureTargetData(target);
if (texData) {
texData->setTexParam(pname, params[0]);
}
if (sShouldEmulateSwizzles(texData, target, pname)) {
sEmulateUserTextureSwizzle(texData, target, pname, params[0]);
} else {
ctx->dispatcher().glTexParameteriv(target,pname,params);
}
}
GL_APICALL void GL_APIENTRY glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid* pixels){
GET_CTX_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) ||
GLESv2Validate::textureTargetEx(ctx, target)), GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::pixelFrmt(ctx,format), GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::pixelType(ctx,type),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(!(GLESv2Validate::pixelFrmt(ctx,format) &&
GLESv2Validate::pixelType(ctx,type)),GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::pixelOp(format,type),GL_INVALID_OPERATION);
if (isCoreProfile() &&
isCoreProfileEmulatedFormat(format)) {
format = getCoreProfileEmulatedFormat(format);
}
uint8_t* data = (uint8_t*)pixels;
if (ctx->dispatcher().glGetTexImage) {
ctx->dispatcher().glGetTexImage(target,level,format,type,data);
} else {
// Best effort via readPixels, assume gles 3.0 capabilities underneath
GLint prevViewport[4];
GLint prevFbo;
GLint packAlignment;
auto gl = ctx->dispatcher();
gl.glGetIntegerv(GL_VIEWPORT, prevViewport);
gl.glGetIntegerv(GL_PACK_ALIGNMENT, &packAlignment);
gl.glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &prevFbo);
GLint width;
GLint height;
GLint depth;
gl.glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
gl.glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
gl.glGetTexLevelParameteriv(target, level, GL_TEXTURE_DEPTH, &depth);
GLuint fbo;
gl.glGenFramebuffers(1, &fbo);
gl.glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
GLenum attachment = GL_COLOR_ATTACHMENT0;
switch (format) {
case GL_DEPTH_COMPONENT:
attachment = GL_DEPTH_ATTACHMENT;
break;
case GL_DEPTH_STENCIL:
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
break;
}
unsigned int tex = ctx->getBindedTexture(target);
GLuint globalName = ctx->shareGroup()->getGlobalName(
NamedObjectType::TEXTURE, tex);
// Do stuff
switch (target) {
case GL_TEXTURE_2D:
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
gl.glFramebufferTexture2D(
GL_READ_FRAMEBUFFER, attachment, target,
globalName, level);
gl.glReadPixels(0, 0, width, height,
format, type,
data);
gl.glFramebufferTexture2D(
GL_READ_FRAMEBUFFER, attachment, target,
0, level);
break;
case GL_TEXTURE_3D: {
unsigned int layerImgSize = texImageSize(
format, type, packAlignment, width, height);
for (unsigned int d = 0; d < depth; d++) {
gl.glFramebufferTexture3DOES(
GL_READ_FRAMEBUFFER, attachment, target,
globalName, level, d);
gl.glReadPixels(0, 0, width,
height, format,
type, data +
layerImgSize * d);
gl.glFramebufferTexture3DOES(
GL_READ_FRAMEBUFFER, attachment, target,
0, level, d);
}
break;
}
case GL_TEXTURE_2D_ARRAY: {
unsigned int layerImgSize = texImageSize(
format, type, packAlignment, width, height);
for (unsigned int d = 0; d < depth; d++) {
gl.glFramebufferTextureLayer(
GL_READ_FRAMEBUFFER, attachment,
globalName, level, d);
gl.glReadPixels(0, 0, width,
height, format,
type, data +
layerImgSize * d);
gl.glFramebufferTextureLayer(
GL_READ_FRAMEBUFFER, attachment,
0, level, d);
}
break;
}
}
gl.glBindFramebuffer(GL_READ_FRAMEBUFFER, prevFbo);
gl.glDeleteFramebuffers(1, &fbo);
gl.glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);
gl.glGetError();
}
}
GL_APICALL void GL_APIENTRY glDebugMessageControlKHR(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled) {
GET_CTX_V2();
ctx->dispatcher().glDebugMessageControlKHR(source, type, severity, count, ids, enabled);
}
GL_APICALL void GL_APIENTRY glDebugMessageInsertKHR(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf) {
GET_CTX_V2();
ctx->dispatcher().glDebugMessageInsertKHR(source, type, id, severity, length, buf);
}
GL_APICALL void GL_APIENTRY glDebugMessageCallbackKHR(GLDEBUGPROCKHR callback, const void* userdata) {
GET_CTX_V2();
ctx->dispatcher().glDebugMessageCallbackKHR(callback, userdata);
}
GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLogKHR(GLuint count, GLsizei size, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* log) {
GET_CTX_V2_RET(0);
return ctx->dispatcher().glGetDebugMessageLogKHR(count, size, sources, types, ids, severities, lengths, log);
}
GL_APICALL void GL_APIENTRY glPushDebugGroupKHR(GLenum source, GLuint id, GLsizei length, const GLchar* message) {
GET_CTX_V2();
ctx->dispatcher().glPushDebugGroupKHR(source, id, length, message);
}
GL_APICALL void GL_APIENTRY glPopDebugGroupKHR(void) {
GET_CTX_V2();
ctx->dispatcher().glPopDebugGroupKHR();
}
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_V2();
SET_ERROR_IF(!(GLESv2Validate::textureTarget(ctx, target) ||
GLESv2Validate::textureTargetEx(ctx, target)), GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::pixelFrmt(ctx,format), GL_INVALID_ENUM);
SET_ERROR_IF(!GLESv2Validate::pixelType(ctx,type),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);
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 && !ctx->isBindedBuffer(GL_PIXEL_UNPACK_BUFFER),GL_INVALID_OPERATION);
if (type==GL_HALF_FLOAT_OES)
type = GL_HALF_FLOAT_NV;
if (isCoreProfile() &&
isCoreProfileEmulatedFormat(format)) {
format = getCoreProfileEmulatedFormat(format);
}
texData->setMipmapLevelAtLeast(level);
texData->makeDirty();
ctx->dispatcher().glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels);
}
static int s_getHostLocOrSetError(GLESv2Context* ctx, GLint location) {
if (!ctx) return -1;
ProgramData* pData = ctx->getUseProgram();
RET_AND_SET_ERROR_IF(!pData, GL_INVALID_OPERATION, -2);
return pData->getHostUniformLocation(location);
}
static int s_getHostLocOrSetError(GLESv2Context* ctx, GLuint program,
GLint location) {
if (!ctx) return -1;
ProgramData* pData = (ProgramData*)ctx->shareGroup()->getObjectDataPtr(
NamedObjectType::SHADER_OR_PROGRAM, program).get();
RET_AND_SET_ERROR_IF(!pData, GL_INVALID_OPERATION, -2);
return pData->getHostUniformLocation(location);
}
GL_APICALL void GL_APIENTRY glUniform1f(GLint location, GLfloat x){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform1f(hostLoc,x);
}
GL_APICALL void GL_APIENTRY glUniform1fv(GLint location, GLsizei count, const GLfloat* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform1fv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform1i(GLint location, GLint x){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform1i(hostLoc, x);
}
GL_APICALL void GL_APIENTRY glUniform1iv(GLint location, GLsizei count, const GLint* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform1iv(hostLoc, count,v);
}
GL_APICALL void GL_APIENTRY glUniform2f(GLint location, GLfloat x, GLfloat y){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform2f(hostLoc, x, y);
}
GL_APICALL void GL_APIENTRY glUniform2fv(GLint location, GLsizei count, const GLfloat* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform2fv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform2i(GLint location, GLint x, GLint y){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform2i(hostLoc, x, y);
}
GL_APICALL void GL_APIENTRY glUniform2iv(GLint location, GLsizei count, const GLint* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform2iv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform3f(hostLoc,x,y,z);
}
GL_APICALL void GL_APIENTRY glUniform3fv(GLint location, GLsizei count, const GLfloat* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform3fv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform3i(GLint location, GLint x, GLint y, GLint z){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform3i(hostLoc,x,y,z);
}
GL_APICALL void GL_APIENTRY glUniform3iv(GLint location, GLsizei count, const GLint* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform3iv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform4f(hostLoc,x,y,z,w);
}
GL_APICALL void GL_APIENTRY glUniform4fv(GLint location, GLsizei count, const GLfloat* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform4fv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform4i(hostLoc,x,y,z,w);
}
GL_APICALL void GL_APIENTRY glUniform4iv(GLint location, GLsizei count, const GLint* v){
GET_CTX_V2();
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniform4iv(hostLoc,count,v);
}
GL_APICALL void GL_APIENTRY glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){
GET_CTX_V2();
SET_ERROR_IF(ctx->getMajorVersion() < 3 &&
transpose != GL_FALSE,GL_INVALID_VALUE);
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniformMatrix2fv(hostLoc,count,transpose,value);
}
GL_APICALL void GL_APIENTRY glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){
GET_CTX_V2();
SET_ERROR_IF(ctx->getMajorVersion() < 3 &&
transpose != GL_FALSE,GL_INVALID_VALUE);
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniformMatrix3fv(hostLoc,count,transpose,value);
}
GL_APICALL void GL_APIENTRY glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value){
GET_CTX_V2();
SET_ERROR_IF(ctx->getMajorVersion() < 3 &&
transpose != GL_FALSE,GL_INVALID_VALUE);
int hostLoc = s_getHostLocOrSetError(ctx, location);
SET_ERROR_IF(hostLoc < -1, GL_INVALID_OPERATION);
ctx->dispatcher().glUniformMatrix4fv(hostLoc,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()) {
s_detachShader(ctx, localCurrentProgram,
programData->getAttachedVertexShader());
s_detachShader(ctx, localCurrentProgram,
programData->getAttachedFragmentShader());
s_detachShader(ctx, localCurrentProgram,
programData->getAttachedComputeShader());
ctx->shareGroup()->deleteName(NamedObjectType::SHADER_OR_PROGRAM,
localCurrentProgram);
}
}
GL_APICALL void GL_APIENTRY glUseProgram(GLuint program){
GET_CTX_V2();
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()->getObjectDataPtr(
NamedObjectType::SHADER_OR_PROGRAM, program);
SET_ERROR_IF(objData && (objData->getDataType()!=PROGRAM_DATA),GL_INVALID_OPERATION);
s_unUseCurrentProgram();
ProgramData* programData = (ProgramData*)objData.get();
if (programData) programData->setInUse(true);
ctx->setUseProgram(program, objData);
SHADER_DEBUG_PRINT("use program %u", program);
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);
GLint validateStatus;
ctx->dispatcher().glGetProgramiv(globalProgramName, GL_VALIDATE_STATUS,
&validateStatus);
programData->setValidateStatus(static_cast<bool>(validateStatus));
GLsizei infoLogLength = 0, cLength = 0;
ctx->dispatcher().glGetProgramiv(globalProgramName,GL_INFO_LOG_LENGTH,&infoLogLength);
std::unique_ptr<GLchar[]> infoLog(new GLchar[infoLogLength + 1]);
ctx->dispatcher().glGetProgramInfoLog(globalProgramName, infoLogLength,
&cLength, infoLog.get());
if (cLength > 0) {
programData->setInfoLog(infoLog.release());
}
}
}
GL_APICALL void GL_APIENTRY glVertexAttrib1f(GLuint index, GLfloat x){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib1f(index,x);
ctx->setAttribValue(index, 1, &x);
if(index == 0)
ctx->setAttribute0value(x, 0.0, 0.0, 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib1fv(GLuint index, const GLfloat* values){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib1fv(index,values);
ctx->setAttribValue(index, 1, values);
if(index == 0)
ctx->setAttribute0value(values[0], 0.0, 0.0, 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib2f(index,x,y);
GLfloat values[] = {x, y};
ctx->setAttribValue(index, 2, values);
if(index == 0)
ctx->setAttribute0value(x, y, 0.0, 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib2fv(GLuint index, const GLfloat* values){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib2fv(index,values);
ctx->setAttribValue(index, 2, values);
if(index == 0)
ctx->setAttribute0value(values[0], values[1], 0.0, 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib3f(index,x,y,z);
GLfloat values[3] = {x, y, z};
ctx->setAttribValue(index, 3, values);
if(index == 0)
ctx->setAttribute0value(x, y, z, 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib3fv(GLuint index, const GLfloat* values){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib3fv(index,values);
ctx->setAttribValue(index, 3, values);
if(index == 0)
ctx->setAttribute0value(values[0], values[1], values[2], 1.0);
}
GL_APICALL void GL_APIENTRY glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib4f(index,x,y,z,w);
GLfloat values[4] = {x, y, z, z};
ctx->setAttribValue(index, 4, values);
if(index == 0)
ctx->setAttribute0value(x, y, z, w);
}
GL_APICALL void GL_APIENTRY glVertexAttrib4fv(GLuint index, const GLfloat* values){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
ctx->dispatcher().glVertexAttrib4fv(index,values);
ctx->setAttribValue(index, 4, values);
if(index == 0)
ctx->setAttribute0value(values[0], values[1], values[2], values[3]);
}
static void s_glPrepareVertexAttribPointer(GLESv2Context* ctx, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr, GLsizei dataSize, bool isInt) {
ctx->setVertexAttribBindingIndex(index, index);
GLsizei effectiveStride = stride;
if (stride == 0) {
effectiveStride = GLESv2Validate::sizeOfType(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->bindIndexedBuffer(0, index, ctx->getBuffer(GL_ARRAY_BUFFER), (GLintptr)ptr, 0, effectiveStride);
ctx->setVertexAttribFormat(index, size, type, normalized, 0, isInt);
// Still needed to deal with client arrays
ctx->setPointer(index, size, type, stride, ptr, dataSize, normalized, isInt);
}
GL_APICALL void GL_APIENTRY glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr){
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
if (type == GL_HALF_FLOAT_OES) type = GL_HALF_FLOAT;
s_glPrepareVertexAttribPointer(ctx, index, size, type, normalized, stride, ptr, 0, false);
if (ctx->isBindedBuffer(GL_ARRAY_BUFFER)) {
ctx->dispatcher().glVertexAttribPointer(index, size, type, normalized, stride, ptr);
}
}
GL_APICALL void GL_APIENTRY glVertexAttribPointerWithDataSize(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr, GLsizei dataSize) {
GET_CTX_V2();
SET_ERROR_IF((!GLESv2Validate::arrayIndex(ctx,index)),GL_INVALID_VALUE);
if (type == GL_HALF_FLOAT_OES) type = GL_HALF_FLOAT;
s_glPrepareVertexAttribPointer(ctx, index, size, type, normalized, stride, ptr, dataSize, false);
if (ctx->isBindedBuffer(GL_ARRAY_BUFFER)) {
ctx->dispatcher().glVertexAttribPointer(index, size, type, normalized, stride, ptr);
}
}
GL_APICALL void GL_APIENTRY glViewport(GLint x, GLint y, GLsizei width, GLsizei height){
GET_CTX();
ctx->setViewport(x, y, width, height);
ctx->dispatcher().glViewport(x,y,width,height);
}
GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
{
GET_CTX_V2();
SET_ERROR_IF(!GLESv2Validate::textureTargetLimited(target),GL_INVALID_ENUM);
unsigned int imagehndl = SafeUIntFromPointer(image);
ImagePtr img = s_eglIface->getEGLImage(imagehndl);
if (img) {
// For native underlying EGL images, call underlying native
// glEGLImageTargetTexture2DOES and exit, without replacing it with
// another global tex obj ourselves. This will implicitly replace the
// underlying texture that's stored in our global info.
if (img->isNative) {
if (!ctx->dispatcher().glEGLImageTargetTexture2DOES) {
fprintf(stderr, "%s: warning, glEGLImageTargetTexture2DOES not found\n", __func__);
} else {
ctx->dispatcher().glEGLImageTargetTexture2DOES(target, (GLeglImageOES)img->nativeImage);
}
// We need to update our records about this texture.
if (ctx->shareGroup().get()) {
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->format = img->format;
texData->type = img->type;
texData->texStorageLevels = img->texStorageLevels;
texData->sourceEGLImage = imagehndl;
if (img->sync) {
// insert gpu side fence to make sure we are done with any blit ops.
ctx->dispatcher().glWaitSync(img->sync, 0, GL_TIMEOUT_IGNORED);
}
if (!imagehndl) {
fprintf(stderr, "glEGLImageTargetTexture2DOES with empty handle\n");
}
}
return;
}
// Could be from a bad snapshot; in this case, skip.
if (!img->globalTexObj) return;
// 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 = ctx->getTextureLocalName(target,ctx->getBindedTexture(target));
// Replace mapping for this local texture id
// with |img|'s global GL texture id
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->format = img->format;
texData->type = img->type;
texData->texStorageLevels = img->texStorageLevels;
texData->sourceEGLImage = imagehndl;
texData->setGlobalName(img->globalTexObj->getGlobalName());
texData->setSaveableTexture(
SaveableTexturePtr(img->saveableTexture));
if (img->sync) {
// insert gpu side fence to make sure we are done with any blit ops.
ctx->dispatcher().glWaitSync(img->sync, 0, GL_TIMEOUT_IGNORED);
}
if (!imagehndl) {
fprintf(stderr, "glEGLImageTargetTexture2DOES with empty handle\n");
}
}
}
}
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);
if (img->isNative) {
if (!ctx->dispatcher().glEGLImageTargetRenderbufferStorageOES) {
fprintf(stderr, "%s: warning, glEGLImageTargetRenderbufferStorageOES not found\n", __func__);
} else {
ctx->dispatcher().glEGLImageTargetRenderbufferStorageOES(target, (GLeglImageOES)img->nativeImage);
}
return;
}
// 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;
rbData->saveableTexture = img->saveableTexture;
img->saveableTexture->makeDirty();
//
// 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(GL_FRAMEBUFFER_EXT);
if (prevFB != rbData->attachedFB) {
ctx->dispatcher().glBindFramebuffer(GL_FRAMEBUFFER_EXT,
rbData->attachedFB);
}
ctx->dispatcher().glFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
rbData->attachedPoint,
GL_TEXTURE_2D,
img->globalTexObj->getGlobalName(),
0);
if (prevFB != rbData->attachedFB) {
ctx->dispatcher().glBindFramebuffer(GL_FRAMEBUFFER_EXT,
prevFB);
}
}
}
// Extension: Vertex array objects
GL_APICALL void GL_APIENTRY glGenVertexArraysOES(GLsizei n, GLuint* arrays) {
GET_CTX_V2();
SET_ERROR_IF(n < 0,GL_INVALID_VALUE);
for (GLsizei i = 0; i < n; i++) {
arrays[i] = ctx->genVAOName(0, true);
}
ctx->addVertexArrayObjects(n, arrays);
}
GL_APICALL void GL_APIENTRY glBindVertexArrayOES(GLuint array) {
GET_CTX_V2();
if (ctx->setVertexArrayObject(array)) {
// TODO: This could be useful for a glIsVertexArray
// that doesn't use the host GPU, but currently, it doesn't
// really work. VAOs need to be bound first if glIsVertexArray
// is to return true, and for now let's just ask the GPU
// directly.
ctx->setVAOEverBound();
}
ctx->dispatcher().glBindVertexArray(ctx->getVAOGlobalName(array));
}
GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES(GLsizei n, const GLuint * arrays) {
GET_CTX_V2();
SET_ERROR_IF(n < 0,GL_INVALID_VALUE);
ctx->removeVertexArrayObjects(n, arrays);
for (GLsizei i = 0; i < n; i++) {
ctx->deleteVAO(arrays[i]);
}
}
GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array) {
GET_CTX_V2_RET(0);
if (!array) return GL_FALSE;
// TODO: Figure out how to answer this completely in software.
// Currently, state gets weird so we need to ask the GPU directly.
return ctx->dispatcher().glIsVertexArray(ctx->getVAOGlobalName(array));
}
#define EXTERN_PART
#include "GLESv30Imp.cpp"
#include "GLESv31Imp.cpp"
#include "GLESv32Imp.cpp"
namespace glperf {
static GLuint compileShader(GLDispatch* gl,
GLenum shaderType,
const char* src) {
GLuint shader = gl->glCreateShader(shaderType);
gl->glShaderSource(shader, 1, (const GLchar* const*)&src, nullptr);
gl->glCompileShader(shader);
GLint compileStatus;
gl->glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus != GL_TRUE) {
GLsizei infoLogLength = 0;
gl->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<char> infoLog(infoLogLength + 1, 0);
gl->glGetShaderInfoLog(shader, infoLogLength, nullptr, infoLog.data());
fprintf(stderr, "Failed to compile shader. Info log: [%s]\n", infoLog.data());
}
return shader;
}
static GLint compileAndLinkShaderProgram(GLDispatch* gl,
const char* vshaderSrc,
const char* fshaderSrc) {
GLuint vshader = compileShader(gl, GL_VERTEX_SHADER, vshaderSrc);
GLuint fshader = compileShader(gl, GL_FRAGMENT_SHADER, fshaderSrc);
GLuint program = gl->glCreateProgram();
gl->glAttachShader(program, vshader);
gl->glAttachShader(program, fshader);
gl->glLinkProgram(program);
gl->glDeleteShader(vshader);
gl->glDeleteShader(fshader);
GLint linkStatus;
gl->glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
gl->glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
if (linkStatus != GL_TRUE) {
GLsizei infoLogLength = 0;
gl->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
std::vector<char> infoLog(infoLogLength + 1, 0);
gl->glGetProgramInfoLog(program, infoLogLength, nullptr,
infoLog.data());
fprintf(stderr, "Failed to link program. Info log: [%s]\n", infoLog.data());
}
return program;
}
} // namespace glperf
GL_APICALL void GL_APIENTRY
glTestHostDriverPerformance(GLuint count,
uint64_t* duration_us,
uint64_t* duration_cpu_us) {
GET_CTX_V2();
auto gl = &(ctx->dispatcher());
constexpr char vshaderSrcEs[] = R"(#version 300 es
precision highp float;
layout (location = 0) in vec2 pos;
layout (location = 1) in vec3 color;
uniform mat4 transform;
out vec3 color_varying;
void main() {
gl_Position = transform * vec4(pos, 0.0, 1.0);
color_varying = (transform * vec4(color, 1.0)).xyz;
}
)";
constexpr char fshaderSrcEs[] = R"(#version 300 es
precision highp float;
in vec3 color_varying;
out vec4 fragColor;
void main() {
fragColor = vec4(color_varying, 1.0);
}
)";
constexpr char vshaderSrcCore[] = R"(#version 330 core
precision highp float;
layout (location = 0) in vec2 pos;
layout (location = 1) in vec3 color;
uniform mat4 transform;
out vec3 color_varying;
void main() {
gl_Position = transform * vec4(pos, 0.0, 1.0);
color_varying = (transform * vec4(color, 1.0)).xyz;
}
)";
constexpr char fshaderSrcCore[] = R"(#version 330 core
precision highp float;
in vec3 color_varying;
out vec4 fragColor;
void main() {
fragColor = vec4(color_varying, 1.0);
}
)";
GLuint program;
if (isGles2Gles()) {
program = glperf::compileAndLinkShaderProgram(gl, vshaderSrcEs,
fshaderSrcEs);
} else {
program = glperf::compileAndLinkShaderProgram(gl, vshaderSrcCore,
fshaderSrcCore);
}
GLint transformLoc = gl->glGetUniformLocation(program, "transform");
struct VertexAttributes {
float position[2];
float color[3];
};
const VertexAttributes vertexAttrs[] = {
{ { -0.5f, -0.5f,}, { 0.2, 0.1, 0.9, }, },
{ { 0.5f, -0.5f,}, { 0.8, 0.3, 0.1,}, },
{ { 0.0f, 0.5f,}, { 0.1, 0.9, 0.6,}, },
};
GLuint buffer;
gl->glGenBuffers(1, &buffer);
gl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
gl->glBufferData(GL_ARRAY_BUFFER, sizeof(vertexAttrs), vertexAttrs,
GL_STATIC_DRAW);
gl->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE,
sizeof(VertexAttributes), 0);
gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
sizeof(VertexAttributes),
(GLvoid*)offsetof(VertexAttributes, color));
gl->glEnableVertexAttribArray(0);
gl->glEnableVertexAttribArray(1);
gl->glUseProgram(program);
gl->glClearColor(0.2f, 0.2f, 0.3f, 0.0f);
gl->glViewport(0, 0, 1, 1);
float matrix[16] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f,
};
gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
uint32_t drawCount = 0;
auto cpuTimeStart = android::base::cpuTime();
fprintf(stderr, "%s: transform loc %d\n", __func__, transformLoc);
fprintf(stderr, "%s: begin count %d\n", __func__, count);
while (drawCount < count) {
gl->glUniformMatrix4fv(transformLoc, 1, GL_FALSE, matrix);
gl->glBindBuffer(GL_ARRAY_BUFFER, buffer);
gl->glDrawArrays(GL_TRIANGLES, 0, 3);
++drawCount;
}
gl->glFinish();
auto cpuTime = android::base::cpuTime() - cpuTimeStart;
*duration_us = cpuTime.wall_time_us;
*duration_cpu_us = cpuTime.usageUs();
float ms = (*duration_us) / 1000.0f;
float sec = (*duration_us) / 1000000.0f;
printf("Drew %u times in %f ms. Rate: %f Hz\n", count, ms, count / sec);
gl->glBindBuffer(GL_ARRAY_BUFFER, 0);
gl->glUseProgram(0);
gl->glDeleteProgram(program);
gl->glDeleteBuffers(1, &buffer);
}
// Vulkan/GL interop
// https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_external_objects.txt
// Common between GL_EXT_memory_object and GL_EXT_semaphore
GL_APICALL void GL_APIENTRY glGetUnsignedBytevEXT(GLenum pname, GLubyte* data) {
GET_CTX_V2();
if (!ctx->dispatcher().glGetUnsignedBytevEXT) {
return;
}
ctx->dispatcher().glGetUnsignedBytevEXT(pname, data);
}
GL_APICALL void GL_APIENTRY glGetUnsignedBytei_vEXT(GLenum target, GLuint index, GLubyte* data) {
GET_CTX_V2();
if (!ctx->dispatcher().glGetUnsignedBytei_vEXT) {
return;
}
ctx->dispatcher().glGetUnsignedBytei_vEXT(target, index, data);
}
// GL_EXT_memory_object
GL_APICALL void GL_APIENTRY glImportMemoryFdEXT(GLuint memory, GLuint64 size, GLenum handleType, GLint fd) {
GET_CTX_V2();
ctx->dispatcher().glImportMemoryFdEXT(memory, size, handleType, fd);
}
GL_APICALL void GL_APIENTRY glImportMemoryWin32HandleEXT(GLuint memory, GLuint64 size, GLenum handleType, void* handle) {
GET_CTX_V2();
ctx->dispatcher().glImportMemoryWin32HandleEXT(memory, size, handleType, handle);
}
GL_APICALL void GL_APIENTRY glDeleteMemoryObjectsEXT(GLsizei n, const GLuint *memoryObjects) {
GET_CTX_V2();
ctx->dispatcher().glDeleteMemoryObjectsEXT(n, memoryObjects);
}
GL_APICALL GLboolean GL_APIENTRY glIsMemoryObjectEXT(GLuint memoryObject) {
GET_CTX_V2_RET(GL_FALSE);
return ctx->dispatcher().glIsMemoryObjectEXT(memoryObject);
}
GL_APICALL void GL_APIENTRY glCreateMemoryObjectsEXT(GLsizei n, GLuint *memoryObjects) {
GET_CTX_V2();
ctx->dispatcher().glCreateMemoryObjectsEXT(n, memoryObjects);
}
GL_APICALL void GL_APIENTRY glMemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, const GLint *params) {
GET_CTX_V2();
ctx->dispatcher().glMemoryObjectParameterivEXT(memoryObject, pname, params);
}
GL_APICALL void GL_APIENTRY glGetMemoryObjectParameterivEXT(GLuint memoryObject, GLenum pname, GLint *params) {
GET_CTX_V2();
ctx->dispatcher().glGetMemoryObjectParameterivEXT(memoryObject, pname, params);
}
GL_APICALL void GL_APIENTRY glTexStorageMem2DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLuint memory, GLuint64 offset) {
GET_CTX_V2();
GLint err = GL_NO_ERROR;
GLenum format, type;
GLESv2Validate::getCompatibleFormatTypeForInternalFormat(internalFormat, &format, &type);
sPrepareTexImage2D(target, 0, (GLint)internalFormat, width, height, 0, format, type, 0, NULL, &type, (GLint*)&internalFormat, &err);
SET_ERROR_IF(err != GL_NO_ERROR, err);
TextureData *texData = getTextureTargetData(target);
texData->texStorageLevels = levels;
ctx->dispatcher().glTexStorageMem2DEXT(target, levels, internalFormat, width, height, memory, offset);
}
GL_APICALL void GL_APIENTRY glTexStorageMem2DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
GET_CTX_V2();
ctx->dispatcher().glTexStorageMem2DMultisampleEXT(target, samples, internalFormat, width, height, fixedSampleLocations, memory, offset);
}
GL_APICALL void GL_APIENTRY glTexStorageMem3DEXT(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLuint memory, GLuint64 offset) {
GET_CTX_V2();
ctx->dispatcher().glTexStorageMem3DEXT(target, levels, internalFormat, width, height, depth, memory, offset);
}
GL_APICALL void GL_APIENTRY glTexStorageMem3DMultisampleEXT(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations, GLuint memory, GLuint64 offset) {
GET_CTX_V2();
ctx->dispatcher().glTexStorageMem3DMultisampleEXT(target, samples, internalFormat, width, height, depth, fixedSampleLocations, memory, offset);
}
GL_APICALL void GL_APIENTRY glBufferStorageMemEXT(GLenum target, GLsizeiptr size, GLuint memory, GLuint64 offset) {
GET_CTX_V2();
ctx->dispatcher().glBufferStorageMemEXT(target, size, memory, offset);
}
GL_APICALL void GL_APIENTRY glTexParameteriHOST(GLenum target, GLenum pname, GLint param) {
GET_CTX_V2();
ctx->dispatcher().glTexParameteri(target, pname, param);
}
// Not included: direct-state-access, 1D function pointers
// GL_EXT_semaphore
GL_APICALL void GL_APIENTRY glImportSemaphoreFdEXT(GLuint semaphore, GLenum handleType, GLint fd) {
GET_CTX_V2();
ctx->dispatcher().glImportSemaphoreFdEXT(semaphore, handleType, fd);
}
GL_APICALL void GL_APIENTRY glImportSemaphoreWin32HandleEXT(GLuint semaphore, GLenum handleType, void* handle) {
GET_CTX_V2();
ctx->dispatcher().glImportSemaphoreWin32HandleEXT(semaphore, handleType, handle);
}
GL_APICALL void GL_APIENTRY glGenSemaphoresEXT(GLsizei n, GLuint *semaphores) {
GET_CTX_V2();
ctx->dispatcher().glGenSemaphoresEXT(n, semaphores);
}
GL_APICALL void GL_APIENTRY glDeleteSemaphoresEXT(GLsizei n, const GLuint *semaphores) {
GET_CTX_V2();
ctx->dispatcher().glDeleteSemaphoresEXT(n, semaphores);
}
GL_APICALL GLboolean glIsSemaphoreEXT(GLuint semaphore) {
GET_CTX_V2_RET(GL_FALSE);
return ctx->dispatcher().glIsSemaphoreEXT(semaphore);
}
GL_APICALL void GL_APIENTRY glSemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, const GLuint64 *params) {
GET_CTX_V2();
ctx->dispatcher().glSemaphoreParameterui64vEXT(semaphore, pname, params);
}
GL_APICALL void GL_APIENTRY glGetSemaphoreParameterui64vEXT(GLuint semaphore, GLenum pname, GLuint64 *params) {
GET_CTX_V2();
ctx->dispatcher().glGetSemaphoreParameterui64vEXT(semaphore, pname, params);
}
GL_APICALL void GL_APIENTRY glWaitSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *srcLayouts) {
GET_CTX_V2();
ctx->dispatcher().glWaitSemaphoreEXT(semaphore, numBufferBarriers, buffers, numTextureBarriers, textures, srcLayouts);
}
GL_APICALL void GL_APIENTRY glSignalSemaphoreEXT(GLuint semaphore, GLuint numBufferBarriers, const GLuint *buffers, GLuint numTextureBarriers, const GLuint *textures, const GLenum *dstLayouts) {
GET_CTX_V2();
ctx->dispatcher().glSignalSemaphoreEXT(semaphore, numBufferBarriers, buffers, numTextureBarriers, textures, dstLayouts);
}
GL_APICALL void GL_APIENTRY glPrimitiveRestartIndex(GLuint index) {
GET_CTX_V2();
ctx->dispatcher().glPrimitiveRestartIndex(index);
}
GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT() {
GET_CTX_V2_RET(GL_NO_ERROR);
GLenum error = ctx->dispatcher().glGetError();
if (error && !ctx->getGLerror()) {
ctx->setGLerror(error);
}
auto fptr = ctx->dispatcher().glGetGraphicsResetStatusEXT;
if (!fptr) {
// If we're running on native OpenGL (not ANGLE) and glGetGraphicsResetStatusEXT
// isn't supported by the driver, then default to no error. See b/185407409
return GL_NO_ERROR;
}
GLenum res = fptr();
// On some versions of SwANGLE it sets GL_INVALID_OPERATION after calling
// glGetGraphicsResetStatusEXT. We should discard such error code.
ctx->dispatcher().glGetError();
return res;
}
} // namespace translator
} // namespace gles2