Add Mesa as a GL backend.
http://codereview.appspot.com/4545055/


git-svn-id: http://skia.googlecode.com/svn/trunk@1382 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/Makefile b/Makefile
index 32a793f..0bf3574 100644
--- a/Makefile
+++ b/Makefile
@@ -96,27 +96,48 @@
 #	CC := gcc-4.0 $(SDK_OPTS)
 
 	C_INCLUDES += -I/opt/local/include
-	LINKER_OPTS += -L/opt/local/lib -framework Carbon -lpng -framework OpenGL -framework AGL
+	LINKER_OPTS += -L/opt/local/lib -framework Carbon -lpng
 	DEFINES += -DSK_BUILD_FOR_MAC -DSK_ENABLE_LIBPNG
-
+	ifeq ($(SKIA_MESA),true)
+		C_INCLUDES += -I/usr/X11/include
+		LINKER_OPTS += -L/usr/X11/lib -lOSMesa -lGLU
+		DEFINES += -DSK_MESA
+	else
+		LINKER_OPTS += -framework OpenGL -framework AGL
+	endif
 	C_INCLUDES += -Iinclude/utils/mac
 #	SRC_LIST += src/ports/SkImageDecoder_CG.cpp
 	SRC_LIST += src/utils/mac/SkCreateCGImageRef.cpp
-	SRC_LIST += src/utils/mac/SkEGLContext_mac.cpp
+	ifeq ($(SKIA_MESA),true)
+		SRC_LIST += src/utils/mesa/SkEGLContext_Mesa.cpp
+	else
+		SRC_LIST += src/utils/mac/SkEGLContext_mac.cpp
+	endif
 	SRC_LIST += src/core/SkTypefaceCache.cpp
 	SRC_LIST += src/ports/SkFontHost_mac_coretext.cpp
 
-    # these are our registry-based factories
+	# these are our registry-based factories
 	SRC_LIST += src/images/SkImageDecoder_Factory.cpp
 	SRC_LIST += src/images/SkImageEncoder_Factory.cpp
         SRC_LIST += src/images/SkImageDecoder_libpng.cpp
-    # support files
+	# support files
 	SRC_LIST += src/images/SkScaledBitmapSampler.cpp
 	
-	SRC_LIST += gpu/src/mac/GrGLDefaultInterface_mac.cpp
+	ifeq ($(SKIA_MESA),true)
+		SRC_LIST += gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
+	else
+		SRC_LIST += gpu/src/mac/GrGLDefaultInterface_mac.cpp
+	endif
+	
 else
-	LINKER_OPTS += -lpng -lfreetype -lGL -lGLU -lX11
+	LINKER_OPTS += -lpng -lfreetype
 	DEFINES += -DSK_BUILD_FOR_UNIX -DSK_ENABLE_LIBPNG -DGR_LINUX_BUILD=1
+	ifeq ($(SKIA_MESA),true)
+		LINKER_OPTS += -lOSMesa -lGLU
+		DEFINES += -DSK_MESA
+	else
+		LINKER_OPTS += -lGL -lGLU -lX11
+	endif
 
 	#Assume the color order for now.
 	DEFINES += -DSK_SAMPLES_FOR_X
@@ -127,15 +148,23 @@
 	SRC_LIST += src/ports/SkFontHost_gamma_none.cpp
 	SRC_LIST += src/ports/SkFontHost_FreeType.cpp
 	SRC_LIST += src/ports/SkFontHost_FreeType_Subpixel.cpp
-	SRC_LIST += src/utils/unix/SkEGLContext_Unix.cpp
-    # these are our registry-based factories
+	ifeq ($(SKIA_MESA),true)
+		SRC_LIST += src/utils/mesa/SkEGLContext_Mesa.cpp
+	else
+		SRC_LIST += src/utils/unix/SkEGLContext_Unix.cpp
+	endif
+	# these are our registry-based factories
 	SRC_LIST += src/images/SkImageDecoder_Factory.cpp
 	SRC_LIST += src/images/SkImageEncoder_Factory.cpp
         SRC_LIST += src/images/SkImageDecoder_libpng.cpp
-    # support files
+	# support files
 	SRC_LIST += src/images/SkScaledBitmapSampler.cpp
 	
-	SRC_LIST += gpu/src/unix/GrGLDefaultInterface_unix.cpp
+	ifeq ($(SKIA_MESA),true)
+		SRC_LIST += gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
+	else
+		SRC_LIST += gpu/src/unix/GrGLDefaultInterface_unix.cpp
+	endif
 endif
 
 # For these files, and these files only, compile with -msse2.
diff --git a/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp b/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
new file mode 100644
index 0000000..b494d76
--- /dev/null
+++ b/gpu/src/mesa/GrGLDefaultInterface_mesa.cpp
@@ -0,0 +1,183 @@
+/*
+    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 "GL/osmesa.h"
+#include <GL/glext.h>
+#include <GL/glu.h>
+
+#define GR_GL_GET_PROC(F) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
+        OSMesaGetProcAddress("gl" #F);
+#define GR_GL_GET_PROC_SUFFIX(F, S) gDefaultInterface.f ## F = (GrGL ## F ## Proc) \
+        OSMesaGetProcAddress("gl" #F #S);
+
+void GrGLSetDefaultGLInterface() {
+    static GrGLInterface gDefaultInterface;
+    static bool gDefaultInterfaceInit;
+    if (!gDefaultInterfaceInit && NULL != OSMesaGetCurrentContext()) {
+        int major, minor;
+        const char* versionString = (const char*) glGetString(GL_VERSION);
+        const char* extString = (const char*) glGetString(GL_EXTENSIONS);
+        gl_version_from_string(&major, &minor, versionString);
+
+        if (major == 1 && minor < 5) {
+            // We must have array and element_array buffer objects.
+            return;
+        }
+
+        gDefaultInterface.fActiveTexture = glActiveTexture;
+        GR_GL_GET_PROC(AttachShader);
+        GR_GL_GET_PROC(BindAttribLocation);
+        GR_GL_GET_PROC(BindBuffer);
+        gDefaultInterface.fBindTexture = glBindTexture;
+        gDefaultInterface.fBlendColor = glBlendColor;
+        gDefaultInterface.fBlendFunc = glBlendFunc;
+        GR_GL_GET_PROC(BufferData);
+        GR_GL_GET_PROC(BufferSubData);
+        gDefaultInterface.fClear = glClear;
+        gDefaultInterface.fClearColor = glClearColor;
+        gDefaultInterface.fClearStencil = glClearStencil;
+        gDefaultInterface.fClientActiveTexture = glClientActiveTexture;
+        gDefaultInterface.fColorMask = glColorMask;
+        gDefaultInterface.fColorPointer = glColorPointer;
+        gDefaultInterface.fColor4ub = glColor4ub;
+        GR_GL_GET_PROC(CompileShader);
+        gDefaultInterface.fCompressedTexImage2D = glCompressedTexImage2D;
+        GR_GL_GET_PROC(CreateProgram);
+        GR_GL_GET_PROC(CreateShader);
+        gDefaultInterface.fCullFace = glCullFace;
+        GR_GL_GET_PROC(DeleteBuffers);
+        GR_GL_GET_PROC(DeleteProgram);
+        GR_GL_GET_PROC(DeleteShader);
+        gDefaultInterface.fDeleteTextures = glDeleteTextures;
+        gDefaultInterface.fDepthMask = glDepthMask;
+        gDefaultInterface.fDisable = glDisable;
+        gDefaultInterface.fDisableClientState = glDisableClientState;
+        GR_GL_GET_PROC(DisableVertexAttribArray);
+        gDefaultInterface.fDrawArrays = glDrawArrays;
+        gDefaultInterface.fDrawElements = glDrawElements;
+        gDefaultInterface.fEnable = glEnable;
+        gDefaultInterface.fEnableClientState = glEnableClientState;
+        GR_GL_GET_PROC(EnableVertexAttribArray);
+        gDefaultInterface.fFrontFace = glFrontFace;
+        GR_GL_GET_PROC(GenBuffers);
+        GR_GL_GET_PROC(GetBufferParameteriv);
+        gDefaultInterface.fGetError = glGetError;
+        gDefaultInterface.fGetIntegerv = glGetIntegerv;
+        GR_GL_GET_PROC(GetProgramInfoLog);
+        GR_GL_GET_PROC(GetProgramiv);
+        GR_GL_GET_PROC(GetShaderInfoLog);
+        GR_GL_GET_PROC(GetShaderiv);
+        gDefaultInterface.fGetString = glGetString;
+        gDefaultInterface.fGenTextures = glGenTextures;
+        GR_GL_GET_PROC(GetUniformLocation);
+        gDefaultInterface.fLineWidth = glLineWidth;
+        GR_GL_GET_PROC(LinkProgram);
+        gDefaultInterface.fLoadMatrixf = glLoadMatrixf;
+        GR_GL_GET_PROC(MapBuffer);
+        gDefaultInterface.fMatrixMode = glMatrixMode;
+        gDefaultInterface.fPointSize = glPointSize;
+        gDefaultInterface.fPixelStorei = glPixelStorei;
+        gDefaultInterface.fReadPixels = glReadPixels;
+        gDefaultInterface.fScissor = glScissor;
+        gDefaultInterface.fShadeModel = glShadeModel;
+        GR_GL_GET_PROC(ShaderSource);
+        gDefaultInterface.fStencilFunc = glStencilFunc;
+        GR_GL_GET_PROC(StencilFuncSeparate);
+        gDefaultInterface.fStencilMask = glStencilMask;
+        GR_GL_GET_PROC(StencilMaskSeparate);
+        gDefaultInterface.fStencilOp = glStencilOp;
+        GR_GL_GET_PROC(StencilOpSeparate);
+        gDefaultInterface.fTexCoordPointer = glTexCoordPointer;
+        gDefaultInterface.fTexEnvi = glTexEnvi;
+        //OSMesa on Mac's glTexImage2D takes a GLenum for internalFormat rather than a GLint.
+        gDefaultInterface.fTexImage2D = reinterpret_cast<GrGLTexImage2DProc>(glTexImage2D);
+        gDefaultInterface.fTexParameteri = glTexParameteri;
+        gDefaultInterface.fTexSubImage2D = glTexSubImage2D;
+        GR_GL_GET_PROC(Uniform1f);
+        GR_GL_GET_PROC(Uniform1i);
+        GR_GL_GET_PROC(Uniform1fv);
+        GR_GL_GET_PROC(Uniform1iv);
+        GR_GL_GET_PROC(Uniform2f);
+        GR_GL_GET_PROC(Uniform2i);
+        GR_GL_GET_PROC(Uniform2fv);
+        GR_GL_GET_PROC(Uniform2iv);
+        GR_GL_GET_PROC(Uniform3f);
+        GR_GL_GET_PROC(Uniform3i);
+        GR_GL_GET_PROC(Uniform3fv);
+        GR_GL_GET_PROC(Uniform3iv);
+        GR_GL_GET_PROC(Uniform4f);
+        GR_GL_GET_PROC(Uniform4i);
+        GR_GL_GET_PROC(Uniform4fv);
+        GR_GL_GET_PROC(Uniform4iv);
+        GR_GL_GET_PROC(UniformMatrix2fv);
+        GR_GL_GET_PROC(UniformMatrix3fv);
+        GR_GL_GET_PROC(UniformMatrix4fv);
+        GR_GL_GET_PROC(UnmapBuffer);
+        GR_GL_GET_PROC(UseProgram);
+        GR_GL_GET_PROC(VertexAttrib4fv);
+        GR_GL_GET_PROC(VertexAttribPointer);
+        gDefaultInterface.fVertexPointer = glVertexPointer;
+        gDefaultInterface.fViewport = glViewport;
+
+        // First look for GL3.0 FBO or GL_ARB_framebuffer_object (same since
+        // GL_ARB_framebuffer_object doesn't use ARB suffix.)
+        if (major >= 3 || has_gl_extension_from_string(
+                "GL_ARB_framebuffer_object", extString)) {
+            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);
+        } else if (has_gl_extension_from_string("GL_EXT_framebuffer_object",
+                                                extString)) {
+            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);
+            if (has_gl_extension_from_string("GL_EXT_framebuffer_multisample",
+                                             extString)) {
+                GR_GL_GET_PROC_SUFFIX(RenderbufferStorageMultisample, EXT);
+            }
+            if (has_gl_extension_from_string("GL_EXT_framebuffer_blit",
+                                             extString)) {
+                GR_GL_GET_PROC_SUFFIX(BlitFramebuffer, EXT);
+            }
+        } else {
+            // we must have FBOs
+            return;
+        }
+        gDefaultInterface.fBindingsExported = kDesktop_GrGLBinding;
+
+        gDefaultInterfaceInit = true;
+    }
+    if (gDefaultInterfaceInit)
+        GrGLSetGLInterface(&gDefaultInterface);
+}
diff --git a/include/utils/SkEGLContext.h b/include/utils/SkEGLContext.h
index 6aa8518..d67cf0c 100644
--- a/include/utils/SkEGLContext.h
+++ b/include/utils/SkEGLContext.h
@@ -1,7 +1,9 @@
 #ifndef SkEGLContext_DEFINED
 #define SkEGLContext_DEFINED
 
-#if defined(SK_BUILD_FOR_MAC)
+#if defined(SK_MESA)
+    #include "GL/osmesa.h"
+#elif defined(SK_BUILD_FOR_MAC)
     #include <AGL/agl.h>
 #elif defined(SK_BUILD_FOR_UNIX)
     #include <X11/Xlib.h>
@@ -18,10 +20,13 @@
     SkEGLContext();
     ~SkEGLContext();
 
-    bool init(int width, int height);
+    bool init(const int width, const int height);
 
 private:
-#if defined(SK_BUILD_FOR_MAC)
+#if defined(SK_MESA)
+    OSMesaContext context;
+    GLfloat *image;
+#elif defined(SK_BUILD_FOR_MAC)
     AGLContext context;
 #elif defined(SK_BUILD_FOR_UNIX)
     GLXContext context;
diff --git a/src/utils/mesa/SkEGLContext_Mesa.cpp b/src/utils/mesa/SkEGLContext_Mesa.cpp
new file mode 100644
index 0000000..ed1b7cd
--- /dev/null
+++ b/src/utils/mesa/SkEGLContext_Mesa.cpp
@@ -0,0 +1,128 @@
+#include "SkEGLContext.h"
+#include "SkTypes.h"
+
+#include "GL/osmesa.h"
+#include "GL/glu.h"
+
+#define SK_GL_DECL_PROC(T, F) T F ## _func = NULL;
+#define SK_GL_GET_PROC(T, F) F ## _func = (T)OSMesaGetProcAddress(#F);
+#define SK_GL_GET_EXT_PROC(T, F) F ## _func = (T)OSMesaGetProcAddress(#F "EXT");
+
+SkEGLContext::SkEGLContext() : context(NULL), image(NULL) {
+}
+
+SkEGLContext::~SkEGLContext() {
+    if (this->image)
+        free(this->image);
+    
+    if (this->context)
+        OSMesaDestroyContext(this->context);
+}
+
+#if SK_B32_SHIFT < SK_G32_SHIFT &&\
+                   SK_G32_SHIFT < SK_R32_SHIFT &&\
+                                  SK_R32_SHIFT < SK_A32_SHIFT
+    #define SK_OSMESA_COLOR_ORDER OSMESA_BGRA
+#elif SK_R32_SHIFT < SK_G32_SHIFT &&\
+                     SK_G32_SHIFT < SK_B32_SHIFT &&\
+                                    SK_B32_SHIFT < SK_A32_SHIFT
+    #define SK_OSMESA_COLOR_ORDER OSMESA_RGBA
+#elif SK_A32_SHIFT < SK_R32_SHIFT && \
+                     SK_R32_SHIFT < SK_G32_SHIFT && \
+                                    SK_G32_SHIFT < SK_B32_SHIFT
+    #define SK_OSMESA_COLOR_ORDER OSMESA_ARGB
+#else
+    //Color order (rgba) SK_R32_SHIFT SK_G32_SHIFT SK_B32_SHIFT SK_A32_SHIFT
+    #define SK_OSMESA_COLOR_ORDER OSMESA_RGBA
+#endif
+
+bool SkEGLContext::init(const int width, const int height) {
+    /* Create an RGBA-mode context */
+#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
+    /* specify Z, stencil, accum sizes */
+    OSMesaContext ctx = OSMesaCreateContextExt(SK_OSMESA_COLOR_ORDER, 16, 0, 0, NULL);
+#else
+    OSMesaContext ctx = OSMesaCreateContext(SK_OSMESA_COLOR_ORDER, NULL);
+#endif
+    if (!ctx) {
+        SkDebugf("OSMesaCreateContext failed!\n");
+        return false;
+    }
+    this->context = ctx;
+    
+    // Allocate the image buffer
+    GLfloat *buffer = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
+    if (!buffer) {
+        SkDebugf("Alloc image buffer failed!\n");
+        return false;
+    }
+    this->image = buffer;
+    
+    // Bind the buffer to the context and make it current
+    if (!OSMesaMakeCurrent(ctx, buffer, GL_FLOAT, width, height)) {
+        SkDebugf("OSMesaMakeCurrent failed!\n");
+        return false;
+    }
+    
+    //Setup the framebuffers
+    SK_GL_DECL_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
+    SK_GL_DECL_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
+    SK_GL_DECL_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
+    SK_GL_DECL_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
+    SK_GL_DECL_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
+    SK_GL_DECL_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
+    SK_GL_DECL_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
+    
+    const GLubyte* glExts = glGetString(GL_EXTENSIONS);
+    if (gluCheckExtension(
+          reinterpret_cast<const GLubyte*>("GL_ARB_framebuffer_object")
+          , glExts))
+    {
+        SK_GL_GET_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
+        SK_GL_GET_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
+        SK_GL_GET_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
+        SK_GL_GET_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
+        SK_GL_GET_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
+        SK_GL_GET_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
+        SK_GL_GET_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
+        
+    //osmesa on mac currently only supports EXT
+    } else if (gluCheckExtension(
+          reinterpret_cast<const GLubyte*>("GL_EXT_framebuffer_object")
+          , glExts))
+    {
+        SK_GL_GET_EXT_PROC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffers)
+        SK_GL_GET_EXT_PROC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebuffer)
+        SK_GL_GET_EXT_PROC(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers)
+        SK_GL_GET_EXT_PROC(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer)
+        SK_GL_GET_EXT_PROC(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage)
+        SK_GL_GET_EXT_PROC(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer)
+        SK_GL_GET_EXT_PROC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatus)
+    } else {
+      SkDebugf("GL_ARB_framebuffer_object not found.\n");
+      return false;
+    }
+    
+    GLuint fboID;
+    GLuint cbID;
+    GLuint dsID;
+    glGenFramebuffers_func(1, &fboID);
+    glBindFramebuffer_func(GL_FRAMEBUFFER, fboID);
+    
+    glGenRenderbuffers_func(1, &cbID);
+    glBindRenderbuffer_func(GL_RENDERBUFFER, cbID);
+    glRenderbufferStorage_func(GL_RENDERBUFFER, OSMESA_RGBA, width, height);
+    glFramebufferRenderbuffer_func(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cbID);
+    
+    glGenRenderbuffers_func(1, &dsID);
+    glBindRenderbuffer_func(GL_RENDERBUFFER_EXT, dsID);
+    glRenderbufferStorage_func(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
+    glFramebufferRenderbuffer_func(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, dsID);
+    
+    glViewport(0, 0, width, height);
+    glClearStencil(0);
+    glClear(GL_STENCIL_BUFFER_BIT);
+
+    GLenum status = glCheckFramebufferStatus_func(GL_FRAMEBUFFER);
+    return GL_FRAMEBUFFER_COMPLETE == status;
+}