b=565833; add GLX GLContextProvider, pbuffers only; r=vlad
authorMatt Woodrow <matt.woodrow+bugzilla@gmail.com>
Mon, 14 Jun 2010 23:55:08 -0700
changeset 43628 3b3e795a1c2e
parent 43627 608dcf62fa85
child 43629 0d8bf91aa71e
push id13817
push uservladimir@mozilla.com
push date2010-06-15 06:57 +0000
treeherdermozilla-central@0d8bf91aa71e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs565833
milestone1.9.3a6pre
b=565833; add GLX GLContextProvider, pbuffers only; r=vlad
gfx/layers/opengl/LayerManagerOGL.cpp
gfx/thebes/public/GLContext.h
gfx/thebes/public/GLXLibrary.h
gfx/thebes/public/Makefile.in
gfx/thebes/public/WGLLibrary.h
gfx/thebes/src/GLContext.cpp
gfx/thebes/src/GLContextProviderGLX.cpp
gfx/thebes/src/Makefile.in
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -221,16 +221,18 @@ LayerManagerOGL::Initialize()
     mGLContext->fDeleteTextures(1, &mBackBufferTexture);
   }
 
   if (mFBOTextureTarget == LOCAL_GL_NONE) {
     /* Unable to find a texture target that works with FBOs and NPOT textures */
     return false;
   }
 
+  mGLContext->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
+
   if (mFBOTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
     /* If we're using TEXTURE_RECTANGLE, then we must have the ARB
      * extension -- the EXT variant does not provide support for
      * texture rectangle access inside GLSL (sampler2DRect,
      * texture2DRect).
      */
     if (strstr(extensionStr, "ARB_texture_rectangle") == NULL)
       return false;
--- a/gfx/thebes/public/GLContext.h
+++ b/gfx/thebes/public/GLContext.h
@@ -160,16 +160,18 @@ public:
 
 protected:
 
     PRBool mInitialized;
     nsDataHashtable<nsVoidPtrHashKey, void*> mUserData;
 
     PRBool InitWithPrefix(const char *prefix, PRBool trygl);
 
+    PRBool IsExtensionSupported(const char *extension);
+
     //
     // the wrapped functions
     //
 public:
     /* One would think that this would live in some nice
      * perl-or-python-or-js script somewhere and would be
      * autogenerated; one would be wrong.
      */
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/GLXLibrary.h
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bas Schouten <bschouten@mozilla.com>
+ *   Vladimir Vukicevic <vladimir@pobox.com>
+ *   Matt Woodrow <mwoodrow@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "GLContext.h"
+typedef realGLboolean GLboolean;
+#include <GL/glx.h>
+
+namespace mozilla {
+namespace gl {
+
+class GLXLibrary
+{
+public:
+    GLXLibrary() : mInitialized(PR_FALSE), mOGLLibrary(nsnull) {}
+
+    typedef GLXContext (GLAPIENTRY * PFNGLXCREATECONTEXTPROC) (Display*,
+                                                               XVisualInfo*,
+                                                               GLXContext,
+                                                               Bool);
+    PFNGLXCREATECONTEXTPROC xCreateContext;
+    typedef void (GLAPIENTRY * PFNGLXDELETECONTEXTPROC) (Display*,
+                                                         GLXContext);
+    PFNGLXDELETECONTEXTPROC xDeleteContext;
+    typedef Bool (GLAPIENTRY * PFNGLXMAKECURRENTPROC) (Display*,
+                                                       GLXDrawable,
+                                                       GLXContext);
+    PFNGLXMAKECURRENTPROC xMakeCurrent;
+    typedef void* (GLAPIENTRY * PFNGLXGETPROCADDRESSPROC) (const char *);
+    PFNGLXGETPROCADDRESSPROC xGetProcAddress;
+    typedef XVisualInfo* (GLAPIENTRY * PFNGLXCHOOSEVISUALPROC) (Display*,
+                                                                int,
+                                                                int *);
+    PFNGLXCHOOSEVISUALPROC xChooseVisual;
+    typedef GLXFBConfig* (GLAPIENTRY * PFNGLXCHOOSEFBCONFIG) (Display *,
+                                                              int,
+                                                              const int *,
+                                                              int *);
+    PFNGLXCHOOSEFBCONFIG xChooseFBConfig;
+    typedef GLXPbuffer (GLAPIENTRY * PFNGLXCREATEPBUFFER) (Display *,
+                                                           GLXFBConfig,
+                                                           const int *);
+    PFNGLXCREATEPBUFFER xCreatePbuffer;
+    typedef GLXContext (GLAPIENTRY * PFNGLXCREATENEWCONTEXT) (Display *,
+                                                              GLXFBConfig,
+                                                              int,
+                                                              GLXContext,
+                                                              Bool);
+    PFNGLXCREATENEWCONTEXT xCreateNewContext;
+    typedef void (GLAPIENTRY * PFNGLXDESTROYPBUFFER) (Display *,
+                                                      GLXPbuffer);
+    PFNGLXDESTROYPBUFFER xDestroyPbuffer;
+
+    typedef XVisualInfo* (GLAPIENTRY * PFNGLXGETVISUALFROMFBCONFIG) (Display *,
+                                                                     GLXFBConfig);
+    PFNGLXGETVISUALFROMFBCONFIG xGetVisualFromFBConfig;
+    
+    PRBool EnsureInitialized();
+
+private:
+    PRBool mInitialized;
+    PRLibrary *mOGLLibrary;
+};
+
+// a global GLXLibrary instance
+extern GLXLibrary sGLXLibrary;
+
+} /* namespace gl */
+} /* namespace mozilla */
+
--- a/gfx/thebes/public/Makefile.in
+++ b/gfx/thebes/public/Makefile.in
@@ -69,17 +69,19 @@ EXPORTS += \
 	gfxFT2Fonts.h \
 	gfxFT2FontBase.h \
 	$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 
 ifdef MOZ_X11
-EXPORTS += gfxXlibSurface.h
+EXPORTS += gfxXlibSurface.h \
+           GLXLibrary.h \
+           $(NULL)
 endif
 
 ifdef MOZ_PANGO 
 EXPORTS += gfxPangoFonts.h
 else
 EXPORTS += gfxFT2Fonts.h
 endif
 
@@ -89,16 +91,23 @@ endif
 
 EXPORTS += gfxPlatformGtk.h gfxGdkNativeRenderer.h
 EXPORTS += gfxPDFSurface.h gfxPSSurface.h
 EXPORTS += gfxFT2FontBase.h
 
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),qt)
+
+ifdef MOZ_X11
+EXPORTS += gfxXlibSurface.h \
+           GLXLibrary.h \
+           $(NULL)
+endif
+
 ifdef MOZ_PANGO
 EXPORTS += gfxPangoFonts.h
 else
 EXPORTS += gfxFT2Fonts.h
 endif
 EXPORTS += gfxQtPlatform.h gfxQPainterSurface.h
 EXPORTS += gfxXlibSurface.h gfxQtNativeRenderer.h
 EXPORTS += gfxFT2FontBase.h
--- a/gfx/thebes/public/WGLLibrary.h
+++ b/gfx/thebes/public/WGLLibrary.h
@@ -37,17 +37,17 @@
 #include "GLContext.h"
 
 namespace mozilla {
 namespace gl {
 
 class WGLLibrary
 {
 public:
-    WGLLibrary() : mInitialized(PR_FALSE) {}
+    WGLLibrary() : mInitialized(PR_FALSE), mOGLLibrary(nsnull) {}
 
     typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC);
     PFNWGLCREATECONTEXTPROC fCreateContext;
     typedef BOOL (GLAPIENTRY * PFNWGLDELETECONTEXTPROC) (HGLRC);
     PFNWGLDELETECONTEXTPROC fDeleteContext;
     typedef BOOL (GLAPIENTRY * PFNWGLMAKECURRENTPROC) (HDC, HGLRC);
     PFNWGLMAKECURRENTPROC fMakeCurrent;
     typedef PROC (GLAPIENTRY * PFNWGLGETPROCADDRESSPROC) (LPCSTR);
--- a/gfx/thebes/src/GLContext.cpp
+++ b/gfx/thebes/src/GLContext.cpp
@@ -323,14 +323,48 @@ GLContext::InitWithPrefix(const char *pr
 	{ (PRFuncPtr*) &fUnmapBuffer, { "UnmapBuffer", NULL } },
 #endif
 
         { NULL, { NULL } },
 
     };
 
     mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
+    return mInitialized;
+}
 
-    return mInitialized;
+PRBool
+GLContext::IsExtensionSupported(const char *extension)
+{
+    const GLubyte *extensions = NULL;
+    const GLubyte *start;
+    GLubyte *where, *terminator;
+
+    /* Extension names should not have spaces. */
+    where = (GLubyte *) strchr(extension, ' ');
+    if (where || *extension == '\0')
+        return PR_FALSE;
+
+    extensions = fGetString(LOCAL_GL_EXTENSIONS);
+    /* 
+     * It takes a bit of care to be fool-proof about parsing the
+     * OpenGL extensions string. Don't be fooled by sub-strings,
+     * etc. 
+     */
+    start = extensions;
+    for (;;) {
+        where = (GLubyte *) strstr((const char *) start, extension);
+        if (!where) {
+	    break;
+        }
+        terminator = where + strlen(extension);
+        if (where == start || *(where - 1) == ' ') {
+	    if (*terminator == ' ' || *terminator == '\0') {
+	        return PR_TRUE;
+	    }
+        }
+        start = terminator;
+    }
+    return PR_FALSE;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/GLContextProviderGLX.cpp
@@ -0,0 +1,283 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@mozilla.com>
+ *   Bas Schouten <bschouten@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef MOZ_WIDGET_GTK2
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+// we're using default display for now
+#define GET_NATIVE_WINDOW(aWidget) GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
+#define DISPLAY gdk_x11_get_default_xdisplay
+#elif defined(MOZ_WIDGET_QT)
+#include <QWidget>
+#include <QX11Info>
+// we're using default display for now
+#define GET_NATIVE_WINDOW(aWidget) static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->handle()
+#define DISPLAY QX11Info().display
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include "GLContextProvider.h"
+#include "nsDebug.h"
+#include "nsIWidget.h"
+#include "GLXLibrary.h"
+
+namespace mozilla {
+namespace gl {
+
+GLContextProvider sGLContextProvider;
+
+PRBool
+GLXLibrary::EnsureInitialized()
+{
+    if (mInitialized) {
+        return PR_TRUE;
+    }
+
+    if (!mOGLLibrary) {
+        mOGLLibrary = PR_LoadLibrary("libGL.so.1");
+        if (!mOGLLibrary) {
+	    NS_WARNING("Couldn't load OpenGL shared library.");
+	    return PR_FALSE;
+        }
+    }
+
+    LibrarySymbolLoader::SymLoadStruct symbols[] = {
+        { (PRFuncPtr*) &xCreateContext, { "glXCreateContext", NULL } },
+        { (PRFuncPtr*) &xDeleteContext, { "glXDestroyContext", NULL } },
+        { (PRFuncPtr*) &xMakeCurrent, { "glXMakeCurrent", NULL } },
+        { (PRFuncPtr*) &xGetProcAddress, { "glXGetProcAddress", NULL } },
+        { (PRFuncPtr*) &xChooseVisual, { "glXChooseVisual", NULL } },
+        { (PRFuncPtr*) &xChooseFBConfig, { "glXChooseFBConfig", NULL } },
+        { (PRFuncPtr*) &xCreatePbuffer, { "glXCreatePbuffer", NULL } },
+        { (PRFuncPtr*) &xCreateNewContext, { "glXCreateNewContext", NULL } },
+        { (PRFuncPtr*) &xDestroyPbuffer, { "glXDestroyPbuffer", NULL } },
+        { (PRFuncPtr*) &xGetVisualFromFBConfig, { "glXGetVisualFromFBConfig", NULL } },
+        { NULL, { NULL } }
+    };
+
+    if (!LibrarySymbolLoader::LoadSymbols(mOGLLibrary, &symbols[0])) {
+        NS_WARNING("Couldn't find required entry point in OpenGL shared library");
+        return PR_FALSE;
+    }
+
+    mInitialized = PR_TRUE;
+    return PR_TRUE;
+}
+
+GLXLibrary sGLXLibrary;
+
+static bool ctxErrorOccurred = false;
+static int
+ctxErrorHandler(Display *dpy, XErrorEvent *ev)
+{
+    ctxErrorOccurred = true;
+    return 0;
+}
+
+class GLContextGLX : public GLContext
+{
+public:
+    static GLContextGLX *CreateGLContext(Display *display, GLXDrawable drawable, GLXFBConfig cfg, PRBool pbuffer)
+    {
+        ctxErrorOccurred = false;
+        int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler);
+
+        GLXContext context = sGLXLibrary.xCreateNewContext(display,
+                                                           cfg,
+                                                           GLX_RGBA_TYPE,
+                                                           NULL,
+                                                           True);
+
+        XSync(display, False);
+        XSetErrorHandler(oldHandler);
+
+        if (!context || ctxErrorOccurred) {
+            NS_WARNING("Failed to create GLXContext!");
+            return nsnull;
+        }
+
+        GLContextGLX *glContext = new GLContextGLX(display, 
+                                                   drawable, 
+                                                   context,
+                                                   pbuffer);
+        if (!glContext->Init()) {
+            return nsnull;
+        }
+
+        return glContext;
+    }
+
+    ~GLContextGLX()
+    {
+        if (mPBuffer) {
+            sGLXLibrary.xDestroyPbuffer(mDisplay, mWindow);
+        }
+
+        sGLXLibrary.xDeleteContext(mDisplay, mContext);
+    }
+
+    PRBool Init()
+    {
+        MakeCurrent();
+        SetupLookupFunction();
+        if (!InitWithPrefix("gl", PR_TRUE)) {
+            return PR_FALSE;
+        }
+
+        return IsExtensionSupported("GL_EXT_framebuffer_object");
+    }
+
+    PRBool MakeCurrent()
+    {
+        Bool succeeded = sGLXLibrary.xMakeCurrent(mDisplay, mWindow, mContext);
+        NS_ASSERTION(succeeded, "Failed to make GL context current!");
+        return succeeded;
+    }
+
+    PRBool SetupLookupFunction()
+    {
+        mLookupFunc = (PlatformLookupFunction)sGLXLibrary.xGetProcAddress;
+        return PR_TRUE;
+    }
+
+    void *GetNativeData(NativeDataType aType)
+    {
+        switch(aType) {
+        case NativeGLContext:
+            return mContext;
+ 
+        case NativePBuffer:
+            if (mPBuffer) {
+                return (void *)mWindow;
+            }
+
+        default:
+            return nsnull;
+        }
+    }
+
+private:
+    GLContextGLX(Display *aDisplay, GLXDrawable aWindow, GLXContext aContext, PRBool aPBuffer = PR_FALSE)
+        : mContext(aContext), 
+          mDisplay(aDisplay), 
+          mWindow(aWindow), 
+          mPBuffer(aPBuffer) {}
+
+    GLXContext mContext;
+    Display *mDisplay;
+    GLXDrawable mWindow;
+    PRBool mPBuffer;
+};
+
+already_AddRefed<GLContext>
+GLContextProvider::CreateForWindow(nsIWidget *aWidget)
+{
+    return nsnull;
+}
+
+already_AddRefed<GLContext>
+GLContextProvider::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat)
+{
+    if (!sGLXLibrary.EnsureInitialized()) {
+        return nsnull;
+    }
+
+    nsTArray<int> attribs;
+
+#define A1_(_x)  do { attribs.AppendElement(_x); } while(0)
+#define A2_(_x,_y)  do {                                                \
+        attribs.AppendElement(_x);                                      \
+        attribs.AppendElement(_y);                                      \
+    } while(0)
+
+    int numFormats;
+    Display *display = DISPLAY();
+    int xscreen = DefaultScreen(display);
+
+    A2_(GLX_DOUBLEBUFFER, False);
+    A2_(GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT);
+
+    A2_(GLX_RED_SIZE, aFormat.red);
+    A2_(GLX_GREEN_SIZE, aFormat.green);
+    A2_(GLX_BLUE_SIZE, aFormat.blue);
+    A2_(GLX_ALPHA_SIZE, aFormat.alpha);
+    A2_(GLX_DEPTH_SIZE, aFormat.depth);
+    A1_(0);
+
+    GLXFBConfig *cfg = sGLXLibrary.xChooseFBConfig(display,
+                                                   xscreen,
+                                                   attribs.Elements(),
+                                                   &numFormats);
+
+    if (!cfg) {
+        return nsnull;
+    }
+    NS_ASSERTION(numFormats > 0, "");
+   
+    nsTArray<int> pbattribs;
+    pbattribs.AppendElement(GLX_PBUFFER_WIDTH);
+    pbattribs.AppendElement(aSize.width);
+    pbattribs.AppendElement(GLX_PBUFFER_HEIGHT);
+    pbattribs.AppendElement(aSize.height);
+    pbattribs.AppendElement(GLX_PRESERVED_CONTENTS);
+    pbattribs.AppendElement(True);
+
+    GLXPbuffer pbuffer = sGLXLibrary.xCreatePbuffer(display,
+                                                    cfg[0],
+                                                    pbattribs.Elements());
+
+    if (pbuffer == 0) {
+        XFree(cfg);
+        return nsnull;
+    }
+
+    nsRefPtr<GLContextGLX> glContext = GLContextGLX::CreateGLContext(display,
+                                                                     pbuffer,
+                                                                     cfg[0],
+                                                                     PR_TRUE);
+    XFree(cfg);
+
+    if (!glContext) {
+        return nsnull;
+    }
+
+    return glContext.forget().get();
+}
+
+} /* namespace gl */
+} /* namespace mozilla */
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -227,16 +227,21 @@ EXTRA_DSO_LDOPTS += $(TK_LIBS)
 GL_PROVIDER = Null
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 ifndef WINCE
 GL_PROVIDER = WGL
 endif
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
+ifndef MOZ_PLATFORM_MAEMO
+GL_PROVIDER = GLX
+endif
+endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 GL_PROVIDER = CGL
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2)
 ifdef MOZ_PLATFORM_MAEMO
 GL_PROVIDER = EGL