blob: dd2707d17c213f6b674517c2eba7c7ee690ea832 [file] [log] [blame]
/*
* 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;
}