Implementation of a GL-virtualization layer for Skia. This allows for
environments using skia to specify a GL implementation at run-time, instead of
relying on the linker to pull in the appropriate GL impl.
A new structure, GrGLInterface is exposed. This struct contains a set of
function pointers that should point to an appropriate GL implementation.
This change also removes the reliance on GLew on windows builds.
Review: http://codereview.appspot.com/4254059/
git-svn-id: http://skia.googlecode.com/svn/trunk@937 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLInterface.cpp b/gpu/src/GrGLInterface.cpp
new file mode 100644
index 0000000..e74d29d
--- /dev/null
+++ b/gpu/src/GrGLInterface.cpp
@@ -0,0 +1,350 @@
+/*
+ Copyright 2011 Google Inc.
+
+ 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 "GrGLInterface.h"
+#include "GrTypes.h"
+
+#include <stdio.h>
+
+#if defined(GR_GL_PROC_ADDRESS_HEADER)
+ #include GR_GL_PROC_ADDRESS_HEADER
+#endif
+
+#if !defined(GR_GL_PROC_ADDRESS)
+ #error "Must define GR_GL_PROC_ADDRESS"
+#endif
+
+#define GR_GL_GET_PROC(PROC_NAME) \
+ glBindings->f##PROC_NAME = \
+ reinterpret_cast<GrGLInterface::GrGL##PROC_NAME##Proc>( \
+ GR_GL_PROC_ADDRESS(gl##PROC_NAME)); \
+ GrAssert(NULL != glBindings->f##PROC_NAME && \
+ "Missing GL binding: " #PROC_NAME);
+
+#define GR_GL_GET_PROC_SUFFIX(PROC_NAME, SUFFIX) \
+ glBindings->f##PROC_NAME = \
+ reinterpret_cast<GrGLInterface::GrGL##PROC_NAME##Proc>( \
+ GR_GL_PROC_ADDRESS(gl##PROC_NAME##SUFFIX)); \
+ GrAssert(NULL != glBindings->f##PROC_NAME && \
+ "Missing GL binding: " #PROC_NAME);
+
+#define GR_GL_GET_PROC_SYMBOL(PROC_NAME) \
+ glBindings->f##PROC_NAME = reinterpret_cast<GrGLInterface::GrGL##PROC_NAME##Proc>(gl##PROC_NAME);
+
+namespace {
+
+void gl_version_from_string(int* major, int* minor,
+ const char* versionString) {
+ if (NULL == versionString) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#if GR_SUPPORT_GLDESKTOP
+ int n = sscanf(versionString, "%d.%d", major, minor);
+ if (n != 2) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#else
+ char profile[2];
+ int n = sscanf(versionString, "OpenGL ES-%c%c %d.%d", profile, profile+1,
+ major, minor);
+ bool ok = 4 == n;
+ if (!ok) {
+ int n = sscanf(versionString, "OpenGL ES %d.%d", major, minor);
+ ok = 2 == n;
+ }
+ if (!ok) {
+ GrAssert(0);
+ *major = 0;
+ *minor = 0;
+ return;
+ }
+#endif
+}
+
+bool has_gl_extension_from_string(const char* ext,
+ const char* extensionString) {
+ int extLength = strlen(ext);
+
+ while (true) {
+ int n = strcspn(extensionString, " ");
+ if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
+ return true;
+ }
+ if (0 == extensionString[n]) {
+ return false;
+ }
+ extensionString += n+1;
+ }
+
+ return false;
+}
+
+GrGLInterface* gGLInterface = NULL;
+
+void InitializeGLInterfaceExtensions(GrGLInterface* glBindings) {
+ int major, minor;
+ const char* versionString = reinterpret_cast<const char*>(
+ glBindings->fGetString(GL_VERSION));
+ const char* extensionString = reinterpret_cast<const char*>(
+ glBindings->fGetString(GL_EXTENSIONS));
+ gl_version_from_string(&major, &minor, versionString);
+
+ bool fboFound = false;
+#if GR_SUPPORT_GLDESKTOP
+ if (major >= 3 || has_gl_extension_from_string("GL_ARB_framebuffer_object",
+ extensionString)) {
+ // GL_ARB_framebuffer_object doesn't use ARB suffix.
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ GR_GL_GET_PROC(RenderbufferStorageMultisample);
+ GR_GL_GET_PROC(BlitFramebuffer);
+ fboFound = true;
+ }
+
+ #if GL_EXT_framebuffer_object && !GR_MAC_BUILD
+ if (!fboFound &&
+ has_gl_extension_from_string("GL_EXT_framebuffer_object",
+ extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, EXT);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, EXT);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, EXT);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, EXT);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, EXT);
+ fboFound = true;
+
+ if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
+ extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+ }
+ if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
+ extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+ }
+ }
+ #endif
+
+ // we assume we have at least GL 1.5 or higher (VBOs introduced in 1.5)
+ GrAssert((major == 1 && minor >= 5) || major >=2);
+ GR_GL_GET_PROC(MapBuffer);
+ GR_GL_GET_PROC(UnmapBuffer);
+#else // !GR_SUPPORT_GLDESKTOP
+ #if GR_SUPPORT_GLES2
+ if (!fboFound && major >= 2) {// ES 2.0 supports FBO
+ GR_GL_GET_PROC(GenFramebuffers);
+ GR_GL_GET_PROC(BindFramebuffer);
+ GR_GL_GET_PROC(FramebufferTexture2D);
+ GR_GL_GET_PROC(CheckFramebufferStatus);
+ GR_GL_GET_PROC(DeleteFramebuffers);
+ GR_GL_GET_PROC(RenderbufferStorage);
+ GR_GL_GET_PROC(GenRenderbuffers);
+ GR_GL_GET_PROC(DeleteRenderbuffers);
+ GR_GL_GET_PROC(FramebufferRenderbuffer);
+ GR_GL_GET_PROC(BindRenderbuffer);
+ fboFound = true;
+ }
+ #endif
+
+ #if GL_OES_mapbuffer
+ if (!fboFound &&
+ has_gl_extension_from_string("GL_OES_framebuffer_object",
+ extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(GenFramebuffers, OES);
+ GR_GL_GET_PROC_SUFFIX(BindFramebuffer, OES);
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2D, OES);
+ GR_GL_GET_PROC_SUFFIX(CheckFramebufferStatus, OES);
+ GR_GL_GET_PROC_SUFFIX(DeleteFramebuffers, OES);
+ GR_GL_GET_PROC_SUFFIX(RenderbufferStorage, OES);
+ GR_GL_GET_PROC_SUFFIX(GenRenderbuffers, OES);
+ GR_GL_GET_PROC_SUFFIX(DeleteRenderbuffers, OES);
+ GR_GL_GET_PROC_SUFFIX(FramebufferRenderbuffer, OES);
+ GR_GL_GET_PROC_SUFFIX(BindRenderbuffer, OES);
+ fboFound = true;
+ }
+ #endif
+
+ #if GL_APPLE_framebuffer_multisample
+ if (has_gl_extension_from_string("GL_APPLE_framebuffer_multisample",
+ extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(ResolveMultisampleFramebuffer, APPLE);
+ }
+ #endif
+
+ #if GL_IMG_multisampled_render_to_texture
+ if (has_gl_extension_from_string(
+ "GL_IMG_multisampled_render_to_texture", extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(FramebufferTexture2DMultisample, IMG);
+ }
+ #endif
+
+ #if GL_OES_mapbuffer
+ if (has_gl_extension_from_string("GL_OES_mapbuffer", extensionString)) {
+ GR_GL_GET_PROC_SUFFIX(MapBuffer, OES);
+ GR_GL_GET_PROC_SUFFIX(UnmapBuffer, OES);
+ }
+ #endif
+#endif // !GR_SUPPORT_GLDESKTOP
+
+ if (!fboFound) {
+ // we require some form of FBO
+ GrAssert(!"No FBOs supported?");
+ }
+}
+
+void GrGLInitializeGLInterface(GrGLInterface* glBindings) {
+ Gr_bzero(glBindings, sizeof(GrGLInterface));
+
+#if GR_SUPPORT_GLDESKTOP
+ // These entry points only exist on desktop GL implementations.
+ GR_GL_GET_PROC_SYMBOL(Color4ub);
+ GR_GL_GET_PROC_SYMBOL(ColorPointer);
+ GR_GL_GET_PROC_SYMBOL(DisableClientState);
+ GR_GL_GET_PROC_SYMBOL(EnableClientState);
+ GR_GL_GET_PROC_SYMBOL(LoadMatrixf);
+ GR_GL_GET_PROC_SYMBOL(MatrixMode);
+ GR_GL_GET_PROC_SYMBOL(PointSize);
+ GR_GL_GET_PROC_SYMBOL(ShadeModel);
+ GR_GL_GET_PROC_SYMBOL(TexCoordPointer);
+ GR_GL_GET_PROC_SYMBOL(TexEnvi);
+ GR_GL_GET_PROC_SYMBOL(VertexPointer);
+ GR_GL_GET_PROC(ClientActiveTexture);
+#endif
+
+ // The following gl entry points are part of GL 1.1, and will always be
+ // exported as symbols.
+ // Note that on windows, the wglGetProcAddress call will fail to retrieve
+ // these entry points.
+ GR_GL_GET_PROC_SYMBOL(BlendFunc);
+ GR_GL_GET_PROC_SYMBOL(Clear);
+ GR_GL_GET_PROC_SYMBOL(ClearColor);
+ GR_GL_GET_PROC_SYMBOL(ClearStencil);
+ GR_GL_GET_PROC_SYMBOL(ColorMask);
+ GR_GL_GET_PROC_SYMBOL(CullFace);
+ GR_GL_GET_PROC_SYMBOL(DeleteTextures);
+ GR_GL_GET_PROC_SYMBOL(DepthMask);
+ GR_GL_GET_PROC_SYMBOL(Disable);
+ GR_GL_GET_PROC_SYMBOL(DrawArrays);
+ GR_GL_GET_PROC_SYMBOL(DrawElements);
+ GR_GL_GET_PROC_SYMBOL(Enable);
+ GR_GL_GET_PROC_SYMBOL(FrontFace);
+ GR_GL_GET_PROC_SYMBOL(GenTextures);
+ GR_GL_GET_PROC_SYMBOL(GetError);
+ GR_GL_GET_PROC_SYMBOL(GetIntegerv);
+ GR_GL_GET_PROC_SYMBOL(GetString);
+ GR_GL_GET_PROC_SYMBOL(LineWidth);
+ GR_GL_GET_PROC_SYMBOL(PixelStorei);
+ GR_GL_GET_PROC_SYMBOL(ReadPixels);
+ GR_GL_GET_PROC_SYMBOL(Scissor);
+ GR_GL_GET_PROC_SYMBOL(StencilFunc);
+ GR_GL_GET_PROC_SYMBOL(StencilMask);
+ GR_GL_GET_PROC_SYMBOL(StencilOp);
+ GR_GL_GET_PROC_SYMBOL(TexImage2D);
+ GR_GL_GET_PROC_SYMBOL(TexParameteri);
+ GR_GL_GET_PROC_SYMBOL(TexSubImage2D);
+ GR_GL_GET_PROC_SYMBOL(Viewport);
+
+ // Capture the remaining entry points as gl extensions.
+ GR_GL_GET_PROC(ActiveTexture);
+ GR_GL_GET_PROC(AttachShader);
+ GR_GL_GET_PROC(BindAttribLocation);
+ GR_GL_GET_PROC(BindBuffer);
+ GR_GL_GET_PROC(BindTexture);
+ GR_GL_GET_PROC(BufferData);
+ GR_GL_GET_PROC(BufferSubData);
+ GR_GL_GET_PROC(CompileShader);
+ GR_GL_GET_PROC(CompressedTexImage2D);
+ GR_GL_GET_PROC(CreateProgram);
+ GR_GL_GET_PROC(CreateShader);
+ GR_GL_GET_PROC(DeleteBuffers);
+ GR_GL_GET_PROC(DeleteProgram);
+ GR_GL_GET_PROC(DeleteShader);
+ GR_GL_GET_PROC(DisableVertexAttribArray);
+ GR_GL_GET_PROC(EnableVertexAttribArray);
+ GR_GL_GET_PROC(GenBuffers);
+ GR_GL_GET_PROC(GetBufferParameteriv);
+ GR_GL_GET_PROC(GetProgramInfoLog);
+ GR_GL_GET_PROC(GetProgramiv);
+ GR_GL_GET_PROC(GetShaderInfoLog);
+ GR_GL_GET_PROC(GetShaderiv);
+ GR_GL_GET_PROC(GetUniformLocation);
+ GR_GL_GET_PROC(LinkProgram);
+ GR_GL_GET_PROC(ShaderSource);
+ GR_GL_GET_PROC(StencilFuncSeparate);
+ GR_GL_GET_PROC(StencilMaskSeparate);
+ GR_GL_GET_PROC(StencilOpSeparate);
+ GR_GL_GET_PROC(Uniform1fv);
+ GR_GL_GET_PROC(Uniform1i);
+ GR_GL_GET_PROC(Uniform4fv);
+ GR_GL_GET_PROC(UniformMatrix3fv);
+ GR_GL_GET_PROC(UseProgram);
+ GR_GL_GET_PROC(VertexAttrib4fv);
+ GR_GL_GET_PROC(VertexAttribPointer);
+
+ InitializeGLInterfaceExtensions(glBindings);
+}
+
+} // unnamed namespace
+
+void GrGLSetGLInterface(GrGLInterface* gl_interface) {
+ gGLInterface = gl_interface;
+}
+
+GrGLInterface* GrGLGetGLInterface() {
+ return gGLInterface;
+}
+
+void GrGLSetDefaultGLInterface() {
+ static GrGLInterface gDefaultInterface;
+ static bool gDefaultInitialized = false;
+ GrAssert(!gDefaultInitialized);
+
+ if (!gDefaultInitialized) {
+ GrGLInitializeGLInterface(&gDefaultInterface);
+ GrGLSetGLInterface(&gDefaultInterface);
+ }
+}
+
+bool has_gl_extension(const char* ext) {
+ const char* glstr = reinterpret_cast<const char*>(
+ GrGLGetGLInterface()->fGetString(GL_EXTENSIONS));
+
+ return has_gl_extension_from_string(ext, glstr);
+}
+
+void gl_version(int* major, int* minor) {
+ const char* v = reinterpret_cast<const char*>(
+ GrGLGetGLInterface()->fGetString(GL_VERSION));
+ gl_version_from_string(major, minor, v);
+}