From fad26daa249ca1c651e950084fb45b89747027be Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 14 Jun 2010 23:55:08 -0700 Subject: [PATCH] b=565833; add GLX GLContextProvider, pbuffers only; r=vlad --- gfx/layers/opengl/LayerManagerOGL.cpp | 2 + gfx/thebes/public/GLContext.h | 2 + gfx/thebes/public/GLXLibrary.h | 103 +++++++++ gfx/thebes/public/Makefile.in | 11 +- gfx/thebes/public/WGLLibrary.h | 2 +- gfx/thebes/src/GLContext.cpp | 36 ++- gfx/thebes/src/GLContextProviderGLX.cpp | 283 ++++++++++++++++++++++++ gfx/thebes/src/Makefile.in | 5 + 8 files changed, 441 insertions(+), 3 deletions(-) create mode 100644 gfx/thebes/public/GLXLibrary.h create mode 100644 gfx/thebes/src/GLContextProviderGLX.cpp diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index b11a11b78d90..0bddb3ade79e 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -226,6 +226,8 @@ LayerManagerOGL::Initialize() 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 diff --git a/gfx/thebes/public/GLContext.h b/gfx/thebes/public/GLContext.h index 6ff4d298148d..b77539571dc6 100644 --- a/gfx/thebes/public/GLContext.h +++ b/gfx/thebes/public/GLContext.h @@ -165,6 +165,8 @@ protected: PRBool InitWithPrefix(const char *prefix, PRBool trygl); + PRBool IsExtensionSupported(const char *extension); + // // the wrapped functions // diff --git a/gfx/thebes/public/GLXLibrary.h b/gfx/thebes/public/GLXLibrary.h new file mode 100644 index 000000000000..eaaff175cf65 --- /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 + * Vladimir Vukicevic + * Matt Woodrow + * + * 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 + +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 */ + diff --git a/gfx/thebes/public/Makefile.in b/gfx/thebes/public/Makefile.in index 3c30ce3a4574..a11896789546 100644 --- a/gfx/thebes/public/Makefile.in +++ b/gfx/thebes/public/Makefile.in @@ -74,7 +74,9 @@ endif ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) ifdef MOZ_X11 -EXPORTS += gfxXlibSurface.h +EXPORTS += gfxXlibSurface.h \ + GLXLibrary.h \ + $(NULL) endif ifdef MOZ_PANGO @@ -94,6 +96,13 @@ 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 diff --git a/gfx/thebes/public/WGLLibrary.h b/gfx/thebes/public/WGLLibrary.h index 177d02f5c6be..e8df645c1362 100644 --- a/gfx/thebes/public/WGLLibrary.h +++ b/gfx/thebes/public/WGLLibrary.h @@ -42,7 +42,7 @@ namespace gl { class WGLLibrary { public: - WGLLibrary() : mInitialized(PR_FALSE) {} + WGLLibrary() : mInitialized(PR_FALSE), mOGLLibrary(nsnull) {} typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC); PFNWGLCREATECONTEXTPROC fCreateContext; diff --git a/gfx/thebes/src/GLContext.cpp b/gfx/thebes/src/GLContext.cpp index cbe57a6b7cb1..cde62ca6026d 100644 --- a/gfx/thebes/src/GLContext.cpp +++ b/gfx/thebes/src/GLContext.cpp @@ -328,9 +328,43 @@ GLContext::InitWithPrefix(const char *prefix, PRBool trygl) }; mInitialized = LoadSymbols(&symbols[0], trygl, prefix); - 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 */ diff --git a/gfx/thebes/src/GLContextProviderGLX.cpp b/gfx/thebes/src/GLContextProviderGLX.cpp new file mode 100644 index 000000000000..0f8ea5c17877 --- /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 + * Bas Schouten + * + * 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 +#include +// 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 +#include +// we're using default display for now +#define GET_NATIVE_WINDOW(aWidget) static_cast(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->handle() +#define DISPLAY QX11Info().display +#endif + +#include +#include + +#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 +GLContextProvider::CreateForWindow(nsIWidget *aWidget) +{ + return nsnull; +} + +already_AddRefed +GLContextProvider::CreatePBuffer(const gfxIntSize &aSize, const ContextFormat& aFormat) +{ + if (!sGLXLibrary.EnsureInitialized()) { + return nsnull; + } + + nsTArray 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 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 glContext = GLContextGLX::CreateGLContext(display, + pbuffer, + cfg[0], + PR_TRUE); + XFree(cfg); + + if (!glContext) { + return nsnull; + } + + return glContext.forget().get(); +} + +} /* namespace gl */ +} /* namespace mozilla */ diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in index 9665c942566f..331bc0464995 100644 --- a/gfx/thebes/src/Makefile.in +++ b/gfx/thebes/src/Makefile.in @@ -232,6 +232,11 @@ 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