/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <OpenGLESDispatch/GLESv3Dispatch.h> #include "GLESv3.h" #include <string> #include <vector> // Stubs (common) static void glDeleteFencesNV(GLsizei, const GLuint*) { printf("%s: not implemented\n", __func__); } static void glDisableDriverControlQCOM(GLuint) { printf("%s: not implemented\n", __func__); } static void glDiscardFramebufferEXT(GLenum, GLsizei, const GLenum*) { printf("%s: not implemented\n", __func__); } static void glEnableDriverControlQCOM(GLuint) { printf("%s: not implemented\n", __func__); } static void glEndTilingQCOM(GLbitfield) { printf("%s: not implemented\n", __func__); } static void glExtGetBufferPointervQCOM(GLenum, GLvoid**) { printf("%s: not implemented\n", __func__); } static void glExtGetBuffersQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetFramebuffersQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetProgramBinarySourceQCOM(GLuint, GLenum, GLchar*, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetProgramsQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetRenderbuffersQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetShadersQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetTexLevelParameterivQCOM(GLuint, GLenum, GLint, GLenum, GLint*) { printf("%s: not implemented\n", __func__); } static void glExtGetTexSubImageQCOM(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, GLvoid*) { printf("%s: not implemented\n", __func__); } static void glExtGetTexturesQCOM(GLuint*, GLint, GLint*) { printf("%s: not implemented\n", __func__); } static GLboolean glExtIsProgramBinaryQCOM(GLuint) { printf("%s: not implemented\n", __func__); return GL_FALSE; } static void glExtTexObjectStateOverrideiQCOM(GLenum, GLenum, GLint) { printf("%s: not implemented\n", __func__); } static void glFinishFenceNV(GLuint) { printf("%s: not implemented\n", __func__); } static void glFramebufferTexture2DMultisampleIMG(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) { printf("%s: not implemented\n", __func__); } static void glGenFencesNV(GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glGetDriverControlsQCOM(GLint*, GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glGetDriverControlStringQCOM(GLuint, GLsizei, GLsizei*, GLchar*) { printf("%s: not implemented\n", __func__); } static void glGetFenceivNV(GLuint, GLenum, GLint*) { printf("%s: not implemented\n", __func__); } static GLboolean glIsFenceNV(GLuint) { printf("%s: not implemented\n", __func__); return GL_FALSE; } static void* glMapBufferOES(GLenum, GLenum) { printf("%s: not implemented\n", __func__); return nullptr; } static void glMultiDrawArraysEXT(GLenum, const GLint*, const GLsizei*, GLsizei) { printf("%s: not implemented\n", __func__); } static void glMultiDrawElementsEXT(GLenum, const GLsizei*, GLenum, const GLvoid* const*, GLsizei) { printf("%s: not implemented\n", __func__); } static void glRenderbufferStorageMultisampleIMG(GLenum, GLsizei, GLenum, GLsizei, GLsizei) { printf("%s: not implemented\n", __func__); } static void glSetFenceNV(GLuint, GLenum) { printf("%s: not implemented\n", __func__); } static void glStartTilingQCOM(GLuint, GLuint, GLuint, GLuint, GLbitfield) { printf("%s: not implemented\n", __func__); } static GLboolean glTestFenceNV(GLuint) { printf("%s: not implemented\n", __func__); return GL_FALSE; } // Stubs (ES 3.1) static void glBeginPerfMonitorAMD(GLuint) { printf("%s: not implemented\n", __func__); } static void glCoverageMaskNV(GLboolean) { printf("%s: not implemented\n", __func__); } static void glCoverageOperationNV(GLenum) { printf("%s: not implemented\n", __func__); } static void glDeletePerfMonitorsAMD(GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glEndPerfMonitorAMD(GLuint) { printf("%s: not implemented\n", __func__); } static void glGenPerfMonitorsAMD(GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorCounterDataAMD(GLuint, GLenum, GLsizei, GLuint*, GLint*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorCounterInfoAMD(GLuint, GLuint, GLenum, GLvoid*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorCountersAMD(GLuint, GLint*, GLint*, GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorCounterStringAMD(GLuint, GLuint, GLsizei, GLsizei*, GLchar*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorGroupsAMD(GLint*, GLsizei, GLuint*) { printf("%s: not implemented\n", __func__); } static void glGetPerfMonitorGroupStringAMD(GLuint, GLsizei, GLsizei*, GLchar*) { printf("%s: not implemented\n", __func__); } static void glSelectPerfMonitorCountersAMD(GLuint, GLboolean, GLuint, GLint, GLuint*) { printf("%s: not implemented\n", __func__); } // Non-stubs (common) static void glDrawElementsData(GLenum mode, GLsizei count, GLenum type, void* indices, GLuint) { s_gles3.glDrawElements(mode, count, type, indices); } static void glDrawElementsOffset(GLenum mode, GLsizei count, GLenum type, GLuint offset) { s_gles3.glDrawElements(mode, count, type, reinterpret_cast<const GLvoid*>(offset)); } static GLint glFinishRoundTrip() { s_gles3.glFinish(); return 0; } static void glGetCompressedTextureFormats(int count, GLint* formats) { int nFormats; s_gles3.glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &nFormats); if (nFormats <= count) s_gles3.glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats); } // Non-stubs (ES 3.1) struct GlSync { GlSync(GLESv3* ctx_, GLsync sync_) : sync(sync_), id(ctx_->sync_nextId++), ctx(ctx_) { ctx->sync_map.emplace(id, this); } ~GlSync() { ctx->sync_map.erase(id); } GLsync sync; uint64_t id; private: GLESv3* ctx; }; static GLenum glClientWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) { GLESv3* ctx = static_cast<GLESv3*>(ctx_); std::map<uint64_t, GlSync*>::iterator it; it = ctx->sync_map.find(wait_on); if (it == ctx->sync_map.end()) return GL_INVALID_VALUE; GlSync* sync = it->second; return s_gles3.glClientWaitSync(sync->sync, flags, timeout); } static void glCompressedTexImage2DOffsetAEMU(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLuint offset) { s_gles3.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, reinterpret_cast<const GLvoid*>(offset)); } static void glCompressedTexImage3DOffsetAEMU(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLuint offset) { s_gles3.glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, reinterpret_cast<const GLvoid*>(offset)); } static void glCompressedTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLuint offset) { s_gles3.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, reinterpret_cast<const GLvoid*>(offset)); } static void glCompressedTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLuint offset) { s_gles3.glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, reinterpret_cast<const GLvoid*>(offset)); } static GLuint glCreateShaderProgramvAEMU(GLenum type, GLsizei, const char* packedStrings, GLuint) { return s_gles3.glCreateShaderProgramv(type, 1, &packedStrings); } static void glDeleteSyncAEMU(void* ctx_, uint64_t to_delete) { GLESv3* ctx = static_cast<GLESv3*>(ctx_); std::map<uint64_t, GlSync*>::iterator it; it = ctx->sync_map.find(to_delete); if (it == ctx->sync_map.end()) return; GlSync* sync = it->second; s_gles3.glDeleteSync(sync->sync); delete sync; } static void glDrawArraysIndirectDataAEMU(GLenum mode, const void* indirect, GLuint) { s_gles3.glDrawArraysIndirect(mode, indirect); } static void glDrawArraysIndirectOffsetAEMU(GLenum mode, GLuint offset) { s_gles3.glDrawArraysIndirect(mode, reinterpret_cast<const void*>(offset)); } static void glDrawElementsIndirectDataAEMU(GLenum mode, GLenum type, const void* indirect, GLuint) { s_gles3.glDrawElementsIndirect(mode, type, indirect); } static void glDrawElementsIndirectOffsetAEMU(GLenum mode, GLenum type, GLuint offset) { s_gles3.glDrawElementsIndirect(mode, type, reinterpret_cast<const void*>(offset)); } static void glDrawElementsInstancedDataAEMU(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount, GLsizei) { s_gles3.glDrawElementsInstanced(mode, count, type, indices, primcount); } static void glDrawElementsInstancedOffsetAEMU(GLenum mode, GLsizei count, GLenum type, GLuint offset, GLsizei primcount) { s_gles3.glDrawElementsInstanced(mode, count, type, reinterpret_cast<const void*>(offset), primcount); } static void glDrawRangeElementsDataAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices, GLsizei) { s_gles3.glDrawRangeElements(mode, start, end, count, type, indices); } static void glDrawRangeElementsOffsetAEMU(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLuint offset) { s_gles3.glDrawRangeElements(mode, start, end, count, type, reinterpret_cast<const GLvoid*>(offset)); } static uint64_t glFenceSyncAEMU(void* ctx_, GLenum condition, GLbitfield flags) { GLsync sync_ = s_gles3.glFenceSync(condition, flags); if (sync_ == 0) return 0U; GLESv3* ctx = static_cast<GLESv3*>(ctx_); GlSync* sync = new (std::nothrow) GlSync(ctx, sync_); if (!sync) { s_gles3.glDeleteSync(sync_); return 0U; } return sync->id; } static void glFlushMappedBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer) { if (guest_buffer && length) { void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); if (gpuPtr) { memcpy(gpuPtr, guest_buffer, length); s_gles3.glFlushMappedBufferRange(target, 0, length); s_gles3.glUnmapBuffer(target); } } } static void glGetSyncivAEMU(void* ctx_, uint64_t sync_, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values) { GLESv3* ctx = static_cast<GLESv3*>(ctx_); std::map<uint64_t, GlSync*>::iterator it; it = ctx->sync_map.find(sync_); if (it == ctx->sync_map.end()) return; GlSync* sync = it->second; s_gles3.glGetSynciv(sync->sync, pname, bufSize, length, values); } static std::vector<std::string> sUnpackVarNames(GLsizei count, const char* packedNames) { std::vector<std::string> unpacked; GLsizei current = 0; while (current < count) { const char* delimPos = strstr(packedNames, ";"); size_t nameLen = delimPos - packedNames; std::string next; next.resize(nameLen); memcpy(&next[0], packedNames, nameLen); unpacked.push_back(next); packedNames = delimPos + 1; current++; } return unpacked; } static void glGetUniformIndicesAEMU(GLuint program, GLsizei uniformCount, const GLchar* packedNames, GLsizei packedLen, GLuint* uniformIndices) { std::vector<std::string> unpacked = sUnpackVarNames(uniformCount, packedNames); GLchar** unpackedArray = new GLchar*[unpacked.size()]; GLsizei i = 0; for (auto& elt : unpacked) { unpackedArray[i] = (GLchar*)&elt[0]; i++; } s_gles3.glGetUniformIndices(program, uniformCount, const_cast<const GLchar**>(unpackedArray), uniformIndices); delete[] unpackedArray; } static GLboolean glIsSyncAEMU(void* ctx_, uint64_t sync) { GLESv3* ctx = static_cast<GLESv3*>(ctx_); return ctx->sync_map.count(sync) ? GL_TRUE : GL_FALSE; } static void glMapBufferRangeAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* mapped) { if ((access & GL_MAP_READ_BIT) || ((access & GL_MAP_WRITE_BIT) && (!(access & GL_MAP_INVALIDATE_RANGE_BIT) && !(access & GL_MAP_INVALIDATE_BUFFER_BIT)))) { void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); if (gpuPtr) { if (mapped) memcpy(mapped, gpuPtr, length); s_gles3.glUnmapBuffer(target); } } } static void glReadPixelsOffsetAEMU(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset) { s_gles3.glReadPixels(x, y, width, height, format, type, reinterpret_cast<GLvoid*>(offset)); } static void glShaderString(GLuint shader, const GLchar* string, GLsizei) { s_gles3.glShaderSource(shader, 1, &string, NULL); } static void glTexImage2DOffsetAEMU(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLuint offset) { s_gles3.glTexImage2D(target, level, internalformat, width, height, border, format, type, reinterpret_cast<const GLvoid*>(offset)); } static void glTexImage3DOffsetAEMU(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLuint offset) { s_gles3.glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, reinterpret_cast<const GLvoid*>(offset)); } static void glTexSubImage2DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLuint offset) { s_gles3.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, reinterpret_cast<const GLvoid*>(offset)); } static void glTexSubImage3DOffsetAEMU(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLuint offset) { s_gles3.glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, reinterpret_cast<const GLvoid*>(offset)); } static void glTransformFeedbackVaryingsAEMU(GLuint program, GLsizei count, const char* packedVaryings, GLuint packedVaryingsLen, GLenum bufferMode) { std::vector<std::string> unpacked = sUnpackVarNames(count, packedVaryings); char** unpackedArray = new char*[unpacked.size()]; GLsizei i = 0; for (auto& elt : unpacked) { unpackedArray[i] = &elt[0]; i++; } s_gles3.glTransformFeedbackVaryings(program, count, const_cast<const char**>(unpackedArray), bufferMode); delete[] unpackedArray; } static void glUnmapBufferAEMU(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, void* guest_buffer, GLboolean* out_res) { *out_res = GL_TRUE; if (access & GL_MAP_WRITE_BIT) { if (guest_buffer) { void* gpuPtr = s_gles3.glMapBufferRange(target, offset, length, access); if (gpuPtr) memcpy(gpuPtr, guest_buffer, length); } *out_res = s_gles3.glUnmapBuffer(target); } } static void glVertexAttribIPointerDataAEMU(GLuint index, GLint size, GLenum type, GLsizei, void* data, GLuint) { s_gles3.glVertexAttribIPointer(index, size, type, 0, data); } static void glVertexAttribIPointerOffsetAEMU(GLuint index, GLint size, GLenum type, GLsizei, GLuint offset) { s_gles3.glVertexAttribIPointer(index, size, type, 0, reinterpret_cast<const GLvoid*>(offset)); } static void glVertexAttribPointerData(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei, void* data, GLuint) { s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0, data); } static void glVertexAttribPointerOffset(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei, GLuint offset) { s_gles3.glVertexAttribPointer(indx, size, type, normalized, 0, reinterpret_cast<const GLvoid*>(offset)); } static void glWaitSyncAEMU(void* ctx_, uint64_t wait_on, GLbitfield flags, GLuint64 timeout) { GLESv3* ctx = static_cast<GLESv3*>(ctx_); std::map<uint64_t, GlSync*>::iterator it; it = ctx->sync_map.find(wait_on); if (it == ctx->sync_map.end()) return; GlSync* sync = it->second; s_gles3.glWaitSync(sync->sync, flags, timeout); } #define KNIT(return_type, function_name, signature, callargs) function_name = s_gles3.function_name; GLESv3::GLESv3() { LIST_GLES3_FUNCTIONS(KNIT, KNIT) // Remap some ES 2.0 extensions that become core in ES 3.1 glBindVertexArrayOES = glBindVertexArray; glDeleteVertexArraysOES = glDeleteVertexArrays; glGenVertexArraysOES = glGenVertexArrays; glGetProgramBinaryOES = glGetProgramBinary; glIsVertexArrayOES = glIsVertexArray; glProgramBinaryOES = glProgramBinary; glUnmapBufferOES = glUnmapBuffer; // Entrypoints requiring custom wrappers (common) glDrawElementsData = ::glDrawElementsData; glDrawElementsOffset = ::glDrawElementsOffset; glFinishRoundTrip = ::glFinishRoundTrip; glGetCompressedTextureFormats = ::glGetCompressedTextureFormats; // Entrypoints requiring custom wrappers (ES 3.1) glClientWaitSyncAEMU = ::glClientWaitSyncAEMU; glCompressedTexImage2DOffsetAEMU = ::glCompressedTexImage2DOffsetAEMU; glCompressedTexImage3DOffsetAEMU = ::glCompressedTexImage3DOffsetAEMU; glCompressedTexSubImage2DOffsetAEMU = ::glCompressedTexSubImage2DOffsetAEMU; glCompressedTexSubImage3DOffsetAEMU = ::glCompressedTexSubImage3DOffsetAEMU; glCreateShaderProgramvAEMU = ::glCreateShaderProgramvAEMU; glDeleteSyncAEMU = ::glDeleteSyncAEMU; glDrawArraysIndirectDataAEMU = ::glDrawArraysIndirectDataAEMU; glDrawArraysIndirectOffsetAEMU = ::glDrawArraysIndirectOffsetAEMU; glDrawElementsIndirectDataAEMU = ::glDrawElementsIndirectDataAEMU; glDrawElementsIndirectOffsetAEMU = ::glDrawElementsIndirectOffsetAEMU; glDrawElementsInstancedDataAEMU = ::glDrawElementsInstancedDataAEMU; glDrawElementsInstancedOffsetAEMU = ::glDrawElementsInstancedOffsetAEMU; glDrawRangeElementsDataAEMU = ::glDrawRangeElementsDataAEMU; glDrawRangeElementsOffsetAEMU = ::glDrawRangeElementsOffsetAEMU; glFenceSyncAEMU = ::glFenceSyncAEMU; glFlushMappedBufferRangeAEMU = ::glFlushMappedBufferRangeAEMU; glGetSyncivAEMU = ::glGetSyncivAEMU; glGetUniformIndicesAEMU = ::glGetUniformIndicesAEMU; glIsSyncAEMU = ::glIsSyncAEMU; glMapBufferRangeAEMU = ::glMapBufferRangeAEMU; glReadPixelsOffsetAEMU = ::glReadPixelsOffsetAEMU; glShaderString = ::glShaderString; glTexImage2DOffsetAEMU = ::glTexImage2DOffsetAEMU; glTexImage3DOffsetAEMU = ::glTexImage3DOffsetAEMU; glTexSubImage2DOffsetAEMU = ::glTexSubImage2DOffsetAEMU; glTexSubImage3DOffsetAEMU = ::glTexSubImage3DOffsetAEMU; glTransformFeedbackVaryingsAEMU = ::glTransformFeedbackVaryingsAEMU; glUnmapBufferAEMU = ::glUnmapBufferAEMU; glVertexAttribIPointerDataAEMU = ::glVertexAttribIPointerDataAEMU; glVertexAttribIPointerOffsetAEMU = ::glVertexAttribIPointerOffsetAEMU; glVertexAttribPointerData = ::glVertexAttribPointerData; glVertexAttribPointerOffset = ::glVertexAttribPointerOffset; glWaitSyncAEMU = ::glWaitSyncAEMU; // Stub some extensions we will never implement (common) glDeleteFencesNV = ::glDeleteFencesNV; glDisableDriverControlQCOM = ::glDisableDriverControlQCOM; glDiscardFramebufferEXT = ::glDiscardFramebufferEXT; glEnableDriverControlQCOM = ::glEnableDriverControlQCOM; glEndTilingQCOM = ::glEndTilingQCOM; glExtGetBufferPointervQCOM = ::glExtGetBufferPointervQCOM; glExtGetBuffersQCOM = ::glExtGetBuffersQCOM; glExtGetFramebuffersQCOM = ::glExtGetFramebuffersQCOM; glExtGetProgramBinarySourceQCOM = ::glExtGetProgramBinarySourceQCOM; glExtGetProgramsQCOM = ::glExtGetProgramsQCOM; glExtGetRenderbuffersQCOM = ::glExtGetRenderbuffersQCOM; glExtGetShadersQCOM = ::glExtGetShadersQCOM; glExtGetTexLevelParameterivQCOM = ::glExtGetTexLevelParameterivQCOM; glExtGetTexSubImageQCOM = ::glExtGetTexSubImageQCOM; glExtGetTexturesQCOM = ::glExtGetTexturesQCOM; glExtIsProgramBinaryQCOM = ::glExtIsProgramBinaryQCOM; glExtTexObjectStateOverrideiQCOM = ::glExtTexObjectStateOverrideiQCOM; glFinishFenceNV = ::glFinishFenceNV; glFramebufferTexture2DMultisampleIMG = ::glFramebufferTexture2DMultisampleIMG; glGenFencesNV = ::glGenFencesNV; glGetDriverControlsQCOM = ::glGetDriverControlsQCOM; glGetDriverControlStringQCOM = ::glGetDriverControlStringQCOM; glGetFenceivNV = ::glGetFenceivNV; glIsFenceNV = ::glIsFenceNV; glMapBufferOES = ::glMapBufferOES; glMultiDrawArraysEXT = ::glMultiDrawArraysEXT; glMultiDrawElementsEXT = ::glMultiDrawElementsEXT; glRenderbufferStorageMultisampleIMG = ::glRenderbufferStorageMultisampleIMG; glSetFenceNV = ::glSetFenceNV; glStartTilingQCOM = ::glStartTilingQCOM; glTestFenceNV = ::glTestFenceNV; // Stub some extensions we will never implement (ES 3.1) glBeginPerfMonitorAMD = ::glBeginPerfMonitorAMD; glCoverageMaskNV = ::glCoverageMaskNV; glCoverageOperationNV = ::glCoverageOperationNV; glDeletePerfMonitorsAMD = ::glDeletePerfMonitorsAMD; glEndPerfMonitorAMD = ::glEndPerfMonitorAMD; glGenPerfMonitorsAMD = ::glGenPerfMonitorsAMD; glGetPerfMonitorCounterDataAMD = ::glGetPerfMonitorCounterDataAMD; glGetPerfMonitorCounterInfoAMD = ::glGetPerfMonitorCounterInfoAMD; glGetPerfMonitorCountersAMD = ::glGetPerfMonitorCountersAMD; glGetPerfMonitorCounterStringAMD = ::glGetPerfMonitorCounterStringAMD; glGetPerfMonitorGroupsAMD = ::glGetPerfMonitorGroupsAMD; glGetPerfMonitorGroupStringAMD = ::glGetPerfMonitorGroupStringAMD; glSelectPerfMonitorCountersAMD = ::glSelectPerfMonitorCountersAMD; }