Bug 731836 - Add preference to use Mesa LLVMpipe for software rendering - r=bjacob
authorAndrew Quartey <andrew.quartey@gmail.com>
Sat, 02 Jun 2012 12:05:45 -0400
changeset 95659 ffcc51500617ba9207ce9314dd9557de80178155
parent 95658 b9bf4324d66f1e38968d764fb47bcb14298439cd
child 95660 7ee3f3fe90fb7ea9483390a1ff3f760a50a42024
push id22826
push userphilringnalda@gmail.com
push dateSun, 03 Jun 2012 19:07:58 +0000
treeherdermozilla-central@07d362aa2c1b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs731836
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 731836 - Add preference to use Mesa LLVMpipe for software rendering - r=bjacob
content/canvas/src/WebGLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderImpl.h
gfx/gl/GLContextProviderOSMesa.cpp
gfx/gl/GLContextProviderWGL.cpp
gfx/gl/WGLLibrary.h
modules/libpref/src/init/all.js
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -374,16 +374,18 @@ WebGLContext::SetDimensions(PRInt32 widt
 #ifdef XP_WIN
     bool preferEGL =
         Preferences::GetBool("webgl.prefer-egl", false);
     bool preferOpenGL =
         Preferences::GetBool("webgl.prefer-native-gl", false);
 #endif
     bool forceEnabled =
         Preferences::GetBool("webgl.force-enabled", false);
+    bool useMesaLlvmPipe =
+        Preferences::GetBool("gfx.prefer-mesa-llvmpipe", false);
     bool disabled =
         Preferences::GetBool("webgl.disabled", false);
 
     ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
 
     if (disabled)
         return NS_ERROR_FAILURE;
 
@@ -459,17 +461,17 @@ WebGLContext::SetDimensions(PRInt32 widt
                 useANGLE = false;
             }
         }
 #endif
     }
 
 #ifdef XP_WIN
     // allow forcing GL and not EGL/ANGLE
-    if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
+    if (useMesaLlvmPipe || PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
         preferEGL = false;
         useANGLE = false;
         useOpenGL = true;
     }
 #endif
 
 
 #ifdef ANDROID
@@ -523,20 +525,25 @@ WebGLContext::SetDimensions(PRInt32 widt
         if (!gl || !InitAndValidateGL()) {
             GenerateWarning("Error during ANGLE OpenGL ES initialization");
             return NS_ERROR_FAILURE;
         }
     }
 #endif
 
     // try the default provider, whatever that is
-    if (!gl && useOpenGL) {
-        gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), format);
+    if (!gl && useOpenGL) {
+        GLContext::ContextFlags flag = useMesaLlvmPipe 
+                                       ? GLContext::ContextFlagsMesaLLVMPipe
+                                       : GLContext::ContextFlagsNone;
+        gl = gl::GLContextProvider::CreateOffscreen(gfxIntSize(width, height), 
+                                                               format, flag);
         if (gl && !InitAndValidateGL()) {
-            GenerateWarning("Error during OpenGL initialization");
+            GenerateWarning("Error during %s initialization", 
+                            useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
             return NS_ERROR_FAILURE;
         }
     }
 
     // finally, try OSMesa
     if (!gl) {
         gl = gl::GLContextProviderOSMesa::CreateOffscreen(gfxIntSize(width, height), format);
         if (gl) {
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -549,17 +549,18 @@ public:
             tip->SharedContextDestroyed(this);
             tip->ReportOutstandingNames();
         }
 #endif
     }
 
     enum ContextFlags {
         ContextFlagsNone = 0x0,
-        ContextFlagsGlobal = 0x1
+        ContextFlagsGlobal = 0x1,
+        ContextFlagsMesaLLVMPipe = 0x2
     };
 
     enum GLContextType {
         ContextTypeUnknown,
         ContextTypeWGL,
         ContextTypeCGL,
         ContextTypeGLX,
         ContextTypeEGL,
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -602,17 +602,17 @@ already_AddRefed<GLContext>
 GLContextProviderCGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
 {
     return nsnull;
 }
 
 static nsRefPtr<GLContext> gGlobalContext;
 
 GLContext *
-GLContextProviderCGL::GetGlobalContext()
+GLContextProviderCGL::GetGlobalContext(const ContextFlags)
 {
     if (!sCGLLibrary.EnsureInitialized()) {
         return nsnull;
     }
 
     if (!gGlobalContext) {
         // There are bugs in some older drivers with pbuffers less
         // than 16x16 in size; also 16x16 is POT so that we can do
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -1942,17 +1942,17 @@ GLContextProviderEGL::CreateForNativePix
     return glContext.forget().get();
 #else
     // Not implemented
     return nsnull;
 #endif
 }
 
 GLContext *
-GLContextProviderEGL::GetGlobalContext()
+GLContextProviderEGL::GetGlobalContext(const ContextFlags)
 {
     static bool triedToCreateContext = false;
     if (!triedToCreateContext && !gGlobalContext) {
         triedToCreateContext = true;
         // Don't assign directly to gGlobalContext here, because
         // CreateOffscreen can call us re-entrantly.
         nsRefPtr<GLContext> ctx =
             GLContextProviderEGL::CreateOffscreen(gfxIntSize(16, 16),
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -1350,17 +1350,17 @@ GLContextProviderGLX::CreateForNativePix
                                                                      xs);
 
     return glContext.forget();
 }
 
 static nsRefPtr<GLContext> gGlobalContext;
 
 GLContext *
-GLContextProviderGLX::GetGlobalContext()
+GLContextProviderGLX::GetGlobalContext(const ContextFlags)
 {
     static bool triedToCreateContext = false;
     if (!triedToCreateContext && !gGlobalContext) {
         triedToCreateContext = true;
         gGlobalContext = CreateOffscreenPixmapContext(gfxIntSize(1, 1),
                                                       ContextFormat(ContextFormat::BasicRGB24),
                                                       false);
         if (gGlobalContext)
--- a/gfx/gl/GLContextProviderImpl.h
+++ b/gfx/gl/GLContextProviderImpl.h
@@ -73,16 +73,16 @@ public:
      */
     static already_AddRefed<GLContext>
     CreateForNativePixmapSurface(gfxASurface *aSurface);
 
     /**
      * Get a pointer to the global context, creating it if it doesn't exist.
      */
     static GLContext *
-    GetGlobalContext();
+    GetGlobalContext( const ContextFlags aFlags = GLContext::ContextFlagsNone);
 
     /**
      * Free any resources held by this Context Provider.
      */
     static void
     Shutdown();
 };
--- a/gfx/gl/GLContextProviderOSMesa.cpp
+++ b/gfx/gl/GLContextProviderOSMesa.cpp
@@ -243,17 +243,17 @@ GLContextProviderOSMesa::CreateOffscreen
     {
         return nsnull;
     }
 
     return glContext.forget();
 }
 
 GLContext *
-GLContextProviderOSMesa::GetGlobalContext()
+GLContextProviderOSMesa::GetGlobalContext(const ContextFlags)
 {
     return nsnull;
 }
 
 void
 GLContextProviderOSMesa::Shutdown()
 {
 }
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -18,27 +18,30 @@
 
 #include "prenv.h"
 
 #include "mozilla/Preferences.h"
 
 namespace mozilla {
 namespace gl {
 
-WGLLibrary sWGLLibrary;
+typedef WGLLibrary::LibraryType LibType;
+
+WGLLibrary sWGLLib[WGLLibrary::LIBS_MAX];
 
-static HWND gSharedWindow = 0;
-static HDC gSharedWindowDC = 0;
-static HGLRC gSharedWindowGLContext = 0;
-static int gSharedWindowPixelFormat = 0;
+LibType
+WGLLibrary::SelectLibrary(const GLContext::ContextFlags& aFlags)
+{
+  return (aFlags & GLContext::ContextFlagsMesaLLVMPipe) 
+          ? WGLLibrary::MESA_LLVMPIPE_LIB
+          : WGLLibrary::OPENGL_LIB;
+}
 
-static bool gUseDoubleBufferedWindows = false;
-
-static HWND
-CreateDummyWindow(HDC *aWindowDC = nsnull)
+HWND
+WGLLibrary::CreateDummyWindow(HDC *aWindowDC)
 {
     WNDCLASSW wc;
     if (!GetClassInfoW(GetModuleHandle(NULL), L"GLContextWGLClass", &wc)) {
         ZeroMemory(&wc, sizeof(WNDCLASSW));
         wc.style = CS_OWNDC;
         wc.hInstance = GetModuleHandle(NULL);
         wc.lpfnWndProc = DefWindowProc;
         wc.lpszClassName = L"GLContextWGLClass";
@@ -52,38 +55,38 @@ CreateDummyWindow(HDC *aWindowDC = nsnul
     HWND win = CreateWindowW(L"GLContextWGLClass", L"GLContextWGL", 0,
                              0, 0, 16, 16,
                              NULL, NULL, GetModuleHandle(NULL), NULL);
     NS_ENSURE_TRUE(win, NULL);
 
     HDC dc = GetDC(win);
     NS_ENSURE_TRUE(dc, NULL);
 
-    if (gSharedWindowPixelFormat == 0) {
+    if (mWindowPixelFormat == 0) {
         PIXELFORMATDESCRIPTOR pfd;
         ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
         pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
         pfd.nVersion = 1;
         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
-        if (gUseDoubleBufferedWindows)
+        if (mUseDoubleBufferedWindows)
             pfd.dwFlags |= PFD_DOUBLEBUFFER;
         pfd.iPixelType = PFD_TYPE_RGBA;
         pfd.cColorBits = 24;
         pfd.cRedBits = 8;
         pfd.cGreenBits = 8;
         pfd.cBlueBits = 8;
         pfd.cAlphaBits = 8;
         pfd.cDepthBits = 0;
         pfd.iLayerType = PFD_MAIN_PLANE;
 
-        gSharedWindowPixelFormat = ChoosePixelFormat(dc, &pfd);
+        mWindowPixelFormat = ChoosePixelFormat(dc, &pfd);
     }
 
-    if (!gSharedWindowPixelFormat ||
-        !SetPixelFormat(dc, gSharedWindowPixelFormat, NULL))
+    if (!mWindowPixelFormat ||
+        !SetPixelFormat(dc, mWindowPixelFormat, NULL))
     {
         NS_WARNING("SetPixelFormat failed!");
         DestroyWindow(win);
         return NULL;
     }
 
     if (aWindowDC) {
         *aWindowDC = dc;
@@ -95,32 +98,35 @@ CreateDummyWindow(HDC *aWindowDC = nsnul
 static inline bool
 HasExtension(const char* aExtensions, const char* aRequiredExtension)
 {
     return GLContext::ListHasExtension(
         reinterpret_cast<const GLubyte*>(aExtensions), aRequiredExtension);
 }
 
 bool
-WGLLibrary::EnsureInitialized()
+WGLLibrary::EnsureInitialized(bool aUseMesaLlvmPipe)
 {
     if (mInitialized)
         return true;
+    
+    mozilla::ScopedGfxFeatureReporter reporter("WGL", aUseMesaLlvmPipe);
 
-    mozilla::ScopedGfxFeatureReporter reporter("WGL");
-
+    const char* libGLFilename = aUseMesaLlvmPipe 
+                                ? "mesallvmpipe.dll" 
+                                : "Opengl32.dll";
     if (!mOGLLibrary) {
-        mOGLLibrary = PR_LoadLibrary("Opengl32.dll");
+        mOGLLibrary = PR_LoadLibrary(libGLFilename);
         if (!mOGLLibrary) {
-            NS_WARNING("Couldn't load OpenGL DLL.");
+            NS_WARNING("Couldn't load OpenGL library.");
             return false;
         }
     }
 
-    gUseDoubleBufferedWindows = PR_GetEnv("MOZ_WGL_DB") != nsnull;
+    mUseDoubleBufferedWindows = PR_GetEnv("MOZ_WGL_DB") != nsnull;
 
     GLLibraryLoader::SymLoadStruct earlySymbols[] = {
         { (PRFuncPtr*) &fCreateContext, { "wglCreateContext", NULL } },
         { (PRFuncPtr*) &fMakeCurrent, { "wglMakeCurrent", NULL } },
         { (PRFuncPtr*) &fGetProcAddress, { "wglGetProcAddress", NULL } },
         { (PRFuncPtr*) &fDeleteContext, { "wglDeleteContext", NULL } },
         { (PRFuncPtr*) &fGetCurrentContext, { "wglGetCurrentContext", NULL } },
         { (PRFuncPtr*) &fGetCurrentDC, { "wglGetCurrentDC", NULL } },
@@ -130,27 +136,27 @@ WGLLibrary::EnsureInitialized()
 
     if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &earlySymbols[0])) {
         NS_WARNING("Couldn't find required entry points in OpenGL DLL (early init)");
         return false;
     }
 
     // This is ridiculous -- we have to actually create a context to
     // get the OpenGL ICD to load.
-    gSharedWindow = CreateDummyWindow(&gSharedWindowDC);
-    NS_ENSURE_TRUE(gSharedWindow, false);
+    mWindow = CreateDummyWindow(&mWindowDC);
+    NS_ENSURE_TRUE(mWindow, false);
 
     // create rendering context
-    gSharedWindowGLContext = fCreateContext(gSharedWindowDC);
-    NS_ENSURE_TRUE(gSharedWindowGLContext, false);
+    mWindowGLContext = fCreateContext(mWindowDC);
+    NS_ENSURE_TRUE(mWindowGLContext, false);
 
     HGLRC curCtx = fGetCurrentContext();
     HDC curDC = fGetCurrentDC();
 
-    if (!fMakeCurrent((HDC)gSharedWindowDC, (HGLRC)gSharedWindowGLContext)) {
+    if (!fMakeCurrent((HDC)mWindowDC, (HGLRC)mWindowGLContext)) {
         NS_WARNING("wglMakeCurrent failed");
         return false;
     }
 
     // Now we can grab all the other symbols that we couldn't without having
     // a context current.
 
     GLLibraryLoader::SymLoadStruct pbufferSymbols[] = {
@@ -189,102 +195,112 @@ WGLLibrary::EnsureInitialized()
 
     GLLibraryLoader::SymLoadStruct robustnessSymbols[] = {
         { (PRFuncPtr *) &fCreateContextAttribs, { "wglCreateContextAttribsARB", NULL} },
         { NULL, { NULL } }
     };
 
     if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0],
         (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) {
-        const char *wglExts = fGetExtensionsString(gSharedWindowDC);
+        const char *wglExts = fGetExtensionsString(mWindowDC);
         if (wglExts && HasExtension(wglExts, "WGL_ARB_create_context")) {
             GLLibraryLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0],
             (GLLibraryLoader::PlatformLookupFunction)fGetProcAddress);
             if (HasExtension(wglExts, "WGL_ARB_create_context_robustness")) {
                 mHasRobustness = true;
             }
         }
     }
 
     // reset back to the previous context, just in case
     fMakeCurrent(curDC, curCtx);
 
     if (mHasRobustness) {
-        fDeleteContext(gSharedWindowGLContext);
+        fDeleteContext(mWindowGLContext);
 
         int attribs[] = {
             LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
             LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
             NULL
         };
 
-        gSharedWindowGLContext = fCreateContextAttribs(gSharedWindowDC, NULL, attribs);
-        if (!gSharedWindowGLContext) {
+        mWindowGLContext = fCreateContextAttribs(mWindowDC, NULL, attribs);
+        if (!mWindowGLContext) {
             mHasRobustness = false;
-            gSharedWindowGLContext = fCreateContext(gSharedWindowDC);
+            mWindowGLContext = fCreateContext(mWindowDC);
         }
     }
 
     mInitialized = true;
 
+    GLContext::ContextFlags flag = GLContext::ContextFlagsNone;
+    if (aUseMesaLlvmPipe) {
+      mLibType = WGLLibrary::MESA_LLVMPIPE_LIB;
+      flag = GLContext::ContextFlagsMesaLLVMPipe;
+    }
+
     // Call this to create the global GLContext instance,
     // and to check for errors.  Note that this must happen /after/
     // setting mInitialized to TRUE, or an infinite loop results.
-    if (GLContextProviderWGL::GetGlobalContext() == nsnull) {
+    if (GLContextProviderWGL::GetGlobalContext(flag) == nsnull) {
         mInitialized = false;
         return false;
     }
 
     reporter.SetSuccessful();
     return true;
 }
 
 class GLContextWGL : public GLContext
 {
 public:
     GLContextWGL(const ContextFormat& aFormat,
                  GLContext *aSharedContext,
                  HDC aDC,
                  HGLRC aContext,
+                 LibType aLibUsed,
                  HWND aWindow = nsnull,
                  bool aIsOffscreen = false)
         : GLContext(aFormat, aIsOffscreen, aSharedContext),
           mDC(aDC),
           mContext(aContext),
           mWnd(aWindow),
           mPBuffer(NULL),
           mPixelFormat(0),
+          mLibType(aLibUsed),
           mIsDoubleBuffered(false)
     {
     }
 
     GLContextWGL(const ContextFormat& aFormat,
                  GLContext *aSharedContext,
                  HANDLE aPbuffer,
                  HDC aDC,
                  HGLRC aContext,
-                 int aPixelFormat)
+                 int aPixelFormat,
+                 LibType aLibUsed)
         : GLContext(aFormat, true, aSharedContext),
           mDC(aDC),
           mContext(aContext),
           mWnd(NULL),
           mPBuffer(aPbuffer),
           mPixelFormat(aPixelFormat),
+          mLibType(aLibUsed),
           mIsDoubleBuffered(false)
     {
     }
 
     ~GLContextWGL()
     {
         MarkDestroyed();
 
-        sWGLLibrary.fDeleteContext(mContext);
+        sWGLLib[mLibType].fDeleteContext(mContext);
 
         if (mPBuffer)
-            sWGLLibrary.fDestroyPbuffer(mPBuffer);
+            sWGLLib[mLibType].fDestroyPbuffer(mPBuffer);
         if (mWnd)
             DestroyWindow(mWnd);
     }
 
     GLContextType GetContextType() {
         return ContextTypeWGL;
     }
 
@@ -305,46 +321,46 @@ public:
     bool MakeCurrentImpl(bool aForce = false)
     {
         BOOL succeeded = true;
 
         // wglGetCurrentContext seems to just pull the HGLRC out
         // of its TLS slot, so no need to do our own tls slot.
         // You would think that wglMakeCurrent would avoid doing
         // work if mContext was already current, but not so much..
-        if (aForce || sWGLLibrary.fGetCurrentContext() != mContext) {
-            succeeded = sWGLLibrary.fMakeCurrent(mDC, mContext);
+        if (aForce || sWGLLib[mLibType].fGetCurrentContext() != mContext) {
+            succeeded = sWGLLib[mLibType].fMakeCurrent(mDC, mContext);
             NS_ASSERTION(succeeded, "Failed to make GL context current!");
         }
 
         return succeeded;
     }
 
     void SetIsDoubleBuffered(bool aIsDB) {
         mIsDoubleBuffered = aIsDB;
     }
 
     virtual bool IsDoubleBuffered() {
         return mIsDoubleBuffered;
     }
 
     bool SupportsRobustness()
     {
-        return sWGLLibrary.HasRobustness();
+        return sWGLLib[mLibType].HasRobustness();
     }
 
     virtual bool SwapBuffers() {
         if (!mIsDoubleBuffered)
             return false;
         return ::SwapBuffers(mDC);
     }
 
     bool SetupLookupFunction()
     {
-        mLookupFunc = (PlatformLookupFunction)sWGLLibrary.fGetProcAddress;
+        mLookupFunc = (PlatformLookupFunction)sWGLLib[mLibType].fGetProcAddress;
         return true;
     }
 
     void *GetNativeData(NativeDataType aType)
     {
         switch (aType) {
         case NativeGLContext:
             return mContext;
@@ -363,17 +379,17 @@ public:
 protected:
     friend class GLContextProviderWGL;
 
     HDC mDC;
     HGLRC mContext;
     HWND mWnd;
     HANDLE mPBuffer;
     int mPixelFormat;
-
+    LibType mLibType;
     bool mIsDoubleBuffered;
 };
 
 bool
 GLContextWGL::BindTex2DOffscreen(GLContext *aOffscreen)
 {
     if (aOffscreen->GetContextType() != ContextTypeWGL) {
         NS_WARNING("non-WGL context");
@@ -383,24 +399,29 @@ GLContextWGL::BindTex2DOffscreen(GLConte
     if (!aOffscreen->IsOffscreen()) {
         NS_WARNING("non-offscreen context");
         return false;
     }
 
     GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
 
     if (offs->mPBuffer) {
-        BOOL ok = sWGLLibrary.fBindTexImage(offs->mPBuffer,
+        BOOL ok = sWGLLib[mLibType].fBindTexImage(offs->mPBuffer,
                                             LOCAL_WGL_FRONT_LEFT_ARB);
         if (!ok) {
             NS_WARNING("CanvasLayerOGL::Updated wglBindTexImageARB failed");
             return false;
         }
     } else if (offs->mOffscreenTexture) {
-        if (offs->GetSharedContext() != GLContextProviderWGL::GetGlobalContext())
+          GLContext::ContextFlags flag = 
+                       sWGLLib[mLibType].GetLibraryType() == WGLLibrary::MESA_LLVMPIPE_LIB
+                       ? GLContext::ContextFlagsMesaLLVMPipe
+                       : GLContext::ContextFlagsNone;
+
+        if (offs->GetSharedContext() != GLContextProviderWGL::GetGlobalContext(flag))
         {
             NS_WARNING("offscreen FBO context can only be bound with context sharing!");
             return false;
         }
 
         fBindTexture(LOCAL_GL_TEXTURE_2D, offs->mOffscreenTexture);
     } else {
         NS_WARNING("don't know how to bind this!");
@@ -415,170 +436,175 @@ GLContextWGL::UnbindTex2DOffscreen(GLCon
 {
     NS_ASSERTION(aOffscreen->GetContextType() == ContextTypeWGL, "wrong type");
 
     GLContextWGL *offs = static_cast<GLContextWGL*>(aOffscreen);
     if (offs->mPBuffer) {
         // XXX so, according to the extension, ReleaseTexImage is not required to
         // preserve color buffer contents.  This sucks, but everywhere that I've
         // tried it the color buffer is preserved.  So let's cross our fingers..
-        sWGLLibrary.fReleaseTexImage(offs->mPBuffer, LOCAL_WGL_FRONT_LEFT_ARB);
+        sWGLLib[mLibType].fReleaseTexImage(offs->mPBuffer, LOCAL_WGL_FRONT_LEFT_ARB);
     }
 }
 
 
 static bool
-GetMaxSize(HDC hDC, int format, gfxIntSize& size)
+GetMaxSize(HDC hDC, int format, gfxIntSize& size, LibType aLibToUse)
 {
     int query[] = {LOCAL_WGL_MAX_PBUFFER_WIDTH_ARB, LOCAL_WGL_MAX_PBUFFER_HEIGHT_ARB};
     int result[2];
 
     // (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int* piAttributes, int *piValues)
-    if (!sWGLLibrary.fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result))
+    if (!sWGLLib[aLibToUse].fGetPixelFormatAttribiv(hDC, format, 0, 2, query, result))
         return false;
 
     size.width = result[0];
     size.height = result[1];
     return true;
 }
 
 static bool
-IsValidSizeForFormat(HDC hDC, int format, const gfxIntSize& requested)
+IsValidSizeForFormat(HDC hDC, int format, 
+                     const gfxIntSize& requested,
+                     LibType aLibUsed)
 {
     gfxIntSize max;
-    if (!GetMaxSize(hDC, format, max))
+    if (!GetMaxSize(hDC, format, max, aLibUsed))
         return true;
 
     if (requested.width > max.width)
         return false;
     if (requested.height > max.height)
         return false;
 
     return true;
 }
 
 bool
 GLContextWGL::ResizeOffscreen(const gfxIntSize& aNewSize)
 {
     if (mPBuffer) {
-        if (!IsValidSizeForFormat(gSharedWindowDC, mPixelFormat, aNewSize))
+        if (!IsValidSizeForFormat(sWGLLib[mLibType].GetWindowDC(), mPixelFormat, aNewSize, mLibType))
             return false;
 
         int pbattrs[] = {
             LOCAL_WGL_TEXTURE_FORMAT_ARB,
               mCreationFormat.alpha > 0 ? LOCAL_WGL_TEXTURE_RGBA_ARB
                                         : LOCAL_WGL_TEXTURE_RGB_ARB,
             LOCAL_WGL_TEXTURE_TARGET_ARB, LOCAL_WGL_TEXTURE_2D_ARB,
             0
         };
 
-        HANDLE newbuf = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, mPixelFormat,
+        HANDLE newbuf = sWGLLib[mLibType].fCreatePbuffer(sWGLLib[mLibType].GetWindowDC(), mPixelFormat,
                                                    aNewSize.width, aNewSize.height,
                                                    pbattrs);
         if (!newbuf)
             return false;
 
         bool isCurrent = false;
-        if (sWGLLibrary.fGetCurrentContext() == mContext) {
-            sWGLLibrary.fMakeCurrent(NULL, NULL);
+        if (sWGLLib[mLibType].fGetCurrentContext() == mContext) {
+            sWGLLib[mLibType].fMakeCurrent(NULL, NULL);
             isCurrent = true;
         }
 
-        sWGLLibrary.fDestroyPbuffer(mPBuffer);
+        sWGLLib[mLibType].fDestroyPbuffer(mPBuffer);
 
         mPBuffer = newbuf;
-        mDC = sWGLLibrary.fGetPbufferDC(mPBuffer);
+        mDC = sWGLLib[mLibType].fGetPbufferDC(mPBuffer);
 
         mOffscreenSize = aNewSize;
         mOffscreenActualSize = aNewSize;
 
         MakeCurrent();
         ClearSafely();
 
         return ResizeOffscreenFBOs(aNewSize, false);
     }
 
     return ResizeOffscreenFBOs(aNewSize, true);
 }
 
 static GLContextWGL *
-GetGlobalContextWGL()
+GetGlobalContextWGL(const GLContext::ContextFlags aFlags = GLContext::ContextFlagsNone)
 {
-    return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext());
+    return static_cast<GLContextWGL*>(GLContextProviderWGL::GetGlobalContext(aFlags));
 }
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateForWindow(nsIWidget *aWidget)
 {
-    if (!sWGLLibrary.EnsureInitialized()) {
+    LibType libToUse = WGLLibrary::OPENGL_LIB;
+    
+    if (!sWGLLib[libToUse].EnsureInitialized(false)) {
         return nsnull;
     }
 
     /**
        * We need to make sure we call SetPixelFormat -after- calling 
        * EnsureInitialized, otherwise it can load/unload the dll and 
        * wglCreateContext will fail.
        */
 
     HDC dc = (HDC)aWidget->GetNativeData(NS_NATIVE_GRAPHIC);
 
-    SetPixelFormat(dc, gSharedWindowPixelFormat, NULL);
+    SetPixelFormat(dc, sWGLLib[libToUse].GetWindowPixelFormat(), NULL);
     HGLRC context;
 
     GLContextWGL *shareContext = GetGlobalContextWGL();
 
-    if (sWGLLibrary.HasRobustness()) {
+    if (sWGLLib[libToUse].HasRobustness()) {
         int attribs[] = {
             LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
             LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
             NULL
         };
 
-        context = sWGLLibrary.fCreateContextAttribs(dc,
+        context = sWGLLib[libToUse].fCreateContextAttribs(dc,
                                                     shareContext ? shareContext->Context() : nsnull,
                                                     attribs);
         if (!context && shareContext) {
-            context = sWGLLibrary.fCreateContextAttribs(dc, nsnull, attribs);
+            context = sWGLLib[libToUse].fCreateContextAttribs(dc, nsnull, attribs);
             if (context) {
                 shareContext = nsnull;
             }
         } else {
-            context = sWGLLibrary.fCreateContext(dc);
-            if (context && shareContext && !sWGLLibrary.fShareLists(shareContext->Context(), context)) {
+            context = sWGLLib[libToUse].fCreateContext(dc);
+            if (context && shareContext && !sWGLLib[libToUse].fShareLists(shareContext->Context(), context)) {
                 shareContext = nsnull;
             }
         }
     } else {
-        context = sWGLLibrary.fCreateContext(dc);
+        context = sWGLLib[libToUse].fCreateContext(dc);
         if (context &&
             shareContext &&
-            !sWGLLibrary.fShareLists(shareContext->Context(), context))
+            !sWGLLib[libToUse].fShareLists(shareContext->Context(), context))
         {
             shareContext = nsnull;
         }
     }
 
     if (!context) {
         return nsnull;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24),
-                                                        shareContext, dc, context);
+                                                        shareContext, dc, context, libToUse);
     if (!glContext->Init()) {
         return nsnull;
     }
 
-    glContext->SetIsDoubleBuffered(gUseDoubleBufferedWindows);
+    glContext->SetIsDoubleBuffered(sWGLLib[libToUse].UseDoubleBufferedWindows());
 
     return glContext.forget();
 }
 
 static already_AddRefed<GLContextWGL>
 CreatePBufferOffscreenContext(const gfxIntSize& aSize,
-                              const ContextFormat& aFormat)
+                              const ContextFormat& aFormat,
+                              LibType aLibToUse)
 {
 #define A1(_a,_x)  do { _a.AppendElement(_x); } while(0)
 #define A2(_a,_x,_y)  do { _a.AppendElement(_x); _a.AppendElement(_y); } while(0)
 
     nsTArray<int> attrs;
 
     A2(attrs, LOCAL_WGL_SUPPORT_OPENGL_ARB, LOCAL_GL_TRUE);
     A2(attrs, LOCAL_WGL_DRAW_TO_PBUFFER_ARB, LOCAL_GL_TRUE);
@@ -614,140 +640,146 @@ CreatePBufferOffscreenContext(const gfxI
     } else {
         A2(pbattrs, LOCAL_WGL_TEXTURE_FORMAT_ARB, LOCAL_WGL_TEXTURE_RGB_ARB);
     }
     A1(pbattrs, 0);
 
     UINT numFormats = 256;
     int formats[256];
 
-    if (!sWGLLibrary.fChoosePixelFormat(gSharedWindowDC,
+    if (!sWGLLib[aLibToUse].fChoosePixelFormat(sWGLLib[aLibToUse].GetWindowDC(),
                                         attrs.Elements(), NULL,
                                         numFormats, formats, &numFormats)
         || numFormats == 0)
     {
         return nsnull;
     }
 
     // XXX add back the priority choosing code here
     int chosenFormat = formats[0];
 
-    if (!IsValidSizeForFormat(gSharedWindowDC, chosenFormat, aSize))
+    if (!IsValidSizeForFormat(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat, aSize, aLibToUse))
         return nsnull;
 
-    HANDLE pbuffer = sWGLLibrary.fCreatePbuffer(gSharedWindowDC, chosenFormat,
+    HANDLE pbuffer = sWGLLib[aLibToUse].fCreatePbuffer(sWGLLib[aLibToUse].GetWindowDC(), chosenFormat,
                                                 aSize.width, aSize.height,
                                                 pbattrs.Elements());
     if (!pbuffer) {
         return nsnull;
     }
 
-    HDC pbdc = sWGLLibrary.fGetPbufferDC(pbuffer);
+    HDC pbdc = sWGLLib[aLibToUse].fGetPbufferDC(pbuffer);
     NS_ASSERTION(pbdc, "expected a dc");
 
     HGLRC context;
-    if (sWGLLibrary.HasRobustness()) {
+    if (sWGLLib[aLibToUse].HasRobustness()) {
         int attribs[] = {
             LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
             LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
             NULL
         };
 
-        context = sWGLLibrary.fCreateContextAttribs(pbdc, nsnull, attribs);
+        context = sWGLLib[aLibToUse].fCreateContextAttribs(pbdc, nsnull, attribs);
     } else {
-        context = sWGLLibrary.fCreateContext(pbdc);
+        context = sWGLLib[aLibToUse].fCreateContext(pbdc);
     }
 
     if (!context) {
-        sWGLLibrary.fDestroyPbuffer(pbuffer);
+        sWGLLib[aLibToUse].fDestroyPbuffer(pbuffer);
         return false;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat,
                                                         nsnull,
                                                         pbuffer,
                                                         pbdc,
                                                         context,
-                                                        chosenFormat);
+                                                        chosenFormat,
+                                                        aLibToUse);
 
     return glContext.forget();
 }
 
 static already_AddRefed<GLContextWGL>
-CreateWindowOffscreenContext(const ContextFormat& aFormat)
+CreateWindowOffscreenContext(const ContextFormat& aFormat,
+                             const GLContext::ContextFlags aFlags)
 {
     // CreateWindowOffscreenContext must return a global-shared context
-    GLContextWGL *shareContext = GetGlobalContextWGL();
+    GLContextWGL *shareContext = GetGlobalContextWGL(aFlags);
     if (!shareContext) {
         return nsnull;
     }
     
+    LibType libToUse = WGLLibrary::SelectLibrary(aFlags);
     HDC dc;
-    HWND win = CreateDummyWindow(&dc);
+    HWND win = sWGLLib[libToUse].CreateDummyWindow(&dc);
     if (!win) {
         return nsnull;
     }
     
-    HGLRC context = sWGLLibrary.fCreateContext(dc);
-    if (sWGLLibrary.HasRobustness()) {
+    HGLRC context = sWGLLib[libToUse].fCreateContext(dc);
+    if (sWGLLib[libToUse].HasRobustness()) {
         int attribs[] = {
             LOCAL_WGL_CONTEXT_FLAGS_ARB, LOCAL_WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB,
             LOCAL_WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, LOCAL_WGL_LOSE_CONTEXT_ON_RESET_ARB,
             NULL
         };
 
-        context = sWGLLibrary.fCreateContextAttribs(dc, shareContext->Context(), attribs);
+        context = sWGLLib[libToUse].fCreateContextAttribs(dc, shareContext->Context(), attribs);
     } else {
-        context = sWGLLibrary.fCreateContext(dc);
+        context = sWGLLib[libToUse].fCreateContext(dc);
         if (context && shareContext &&
-            !sWGLLibrary.fShareLists(shareContext->Context(), context))
+            !sWGLLib[libToUse].fShareLists(shareContext->Context(), context))
         {
             NS_WARNING("wglShareLists failed!");
 
-            sWGLLibrary.fDeleteContext(context);
+            sWGLLib[libToUse].fDeleteContext(context);
             DestroyWindow(win);
             return nsnull;
         }
     }
 
     if (!context) {
         return nsnull;
     }
 
     nsRefPtr<GLContextWGL> glContext = new GLContextWGL(aFormat, shareContext,
-                                                        dc, context, win, true);
+                                                        dc, context, libToUse,
+                                                        win, true);
 
     return glContext.forget();
 }
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateOffscreen(const gfxIntSize& aSize,
                                       const ContextFormat& aFormat,
-                                      const ContextFlags)
+                                      const ContextFlags aFlags)
 {
-    if (!sWGLLibrary.EnsureInitialized()) {
+    LibType libToUse = WGLLibrary::SelectLibrary(aFlags);
+    
+    if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) {
         return nsnull;
     }
 
     nsRefPtr<GLContextWGL> glContext;
 
     // Always try to create a pbuffer context first, because we
     // want the context isolation.
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), nsnull);
     const bool preferFBOs = Preferences::GetBool("wgl.prefer-fbo", false);
     if (!preferFBOs &&
-        sWGLLibrary.fCreatePbuffer &&
-        sWGLLibrary.fChoosePixelFormat)
+        sWGLLib[libToUse].fCreatePbuffer &&
+        sWGLLib[libToUse].fChoosePixelFormat)
     {
-        glContext = CreatePBufferOffscreenContext(aSize, aFormat);
+        glContext = CreatePBufferOffscreenContext(aSize, aFormat,libToUse);
     }
 
     // If it failed, then create a window context and use a FBO.
     if (!glContext) {
-        glContext = CreateWindowOffscreenContext(aFormat);
+        glContext = CreateWindowOffscreenContext(aFormat, aFlags);
     }
 
     if (!glContext ||
         !glContext->Init())
     {
         return nsnull;
     }
 
@@ -761,45 +793,51 @@ GLContextProviderWGL::CreateOffscreen(co
 }
 
 already_AddRefed<GLContext>
 GLContextProviderWGL::CreateForNativePixmapSurface(gfxASurface *aSurface)
 {
     return nsnull;
 }
 
-static nsRefPtr<GLContextWGL> gGlobalContext;
+static nsRefPtr<GLContextWGL> gGlobalContext[WGLLibrary::LIBS_MAX];
 
 GLContext *
-GLContextProviderWGL::GetGlobalContext()
+GLContextProviderWGL::GetGlobalContext(const ContextFlags aFlags)
 {
-    if (!sWGLLibrary.EnsureInitialized()) {
+    LibType libToUse = WGLLibrary::SelectLibrary(aFlags);
+    
+    if (!sWGLLib[libToUse].EnsureInitialized(libToUse == WGLLibrary::MESA_LLVMPIPE_LIB)) {
         return nsnull;
     }
 
-    static bool triedToCreateContext = false;
+    static bool triedToCreateContext[WGLLibrary::LIBS_MAX] = {false, false};
 
-    if (!triedToCreateContext && !gGlobalContext) {
-        triedToCreateContext = true;
+    if (!triedToCreateContext[libToUse] && !gGlobalContext[libToUse]) {
+        triedToCreateContext[libToUse] = true;
 
         // conveniently, we already have what we need...
-        gGlobalContext = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), nsnull,
-                                          gSharedWindowDC, gSharedWindowGLContext);
-        if (!gGlobalContext->Init()) {
+        gGlobalContext[libToUse] = new GLContextWGL(ContextFormat(ContextFormat::BasicRGB24), 
+                                          nsnull,
+                                          sWGLLib[libToUse].GetWindowDC(), 
+                                          sWGLLib[libToUse].GetWindowGLContext(),
+                                          libToUse);
+        if (!gGlobalContext[libToUse]->Init()) {
             NS_WARNING("Global context GLContext initialization failed?");
-            gGlobalContext = nsnull;
+            gGlobalContext[libToUse] = nsnull;
             return false;
         }
 
-        gGlobalContext->SetIsGlobalSharedContext(true);
+        gGlobalContext[libToUse]->SetIsGlobalSharedContext(true);
     }
 
-    return static_cast<GLContext*>(gGlobalContext);
+    return static_cast<GLContext*>(gGlobalContext[libToUse]);
 }
 
 void
 GLContextProviderWGL::Shutdown()
 {
-    gGlobalContext = nsnull;
+    for (int i = 0; i < WGLLibrary::LIBS_MAX; ++i)
+      gGlobalContext[i] = nsnull;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/WGLLibrary.h
+++ b/gfx/gl/WGLLibrary.h
@@ -6,18 +6,34 @@
 #include "GLContext.h"
 
 namespace mozilla {
 namespace gl {
 
 class WGLLibrary
 {
 public:
-    WGLLibrary() : mInitialized(false), mOGLLibrary(nsnull),
-    mHasRobustness(false) {}
+    WGLLibrary() 
+      : mInitialized(false), 
+        mOGLLibrary(nsnull),
+        mHasRobustness(false), 
+        mWindow (0),
+        mWindowDC(0),
+        mWindowGLContext(0),
+        mWindowPixelFormat (0),
+        mUseDoubleBufferedWindows(false),
+        mLibType(OPENGL_LIB)     
+    {}
+
+    enum LibraryType
+    {
+      OPENGL_LIB = 0,
+      MESA_LLVMPIPE_LIB = 1,
+      LIBS_MAX
+    };
 
     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);
@@ -47,24 +63,41 @@ public:
     PFNWGLGETPIXELFORMATATTRIBIVPROC fGetPixelFormatAttribiv;
 
     typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGPROC) (HDC hdc);
     PFNWGLGETEXTENSIONSSTRINGPROC fGetExtensionsString;
 
     typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSPROC) (HDC hdc, HGLRC hShareContext, const int *attribList);
     PFNWGLCREATECONTEXTATTRIBSPROC fCreateContextAttribs;
 
-    bool EnsureInitialized();
+    bool EnsureInitialized(bool aUseMesaLlvmPipe);
+    HWND CreateDummyWindow(HDC *aWindowDC = nsnull);
 
-    bool HasRobustness() const { return mHasRobustness; }
-
+    bool HasRobustness() const { return mHasRobustness; }
+    bool IsInitialized() const { return mInitialized; }
+    HWND GetWindow() const { return mWindow; }
+    HDC GetWindowDC() const {return mWindowDC; }
+    HGLRC GetWindowGLContext() const {return mWindowGLContext; }
+    int GetWindowPixelFormat() const { return mWindowPixelFormat; }
+    bool UseDoubleBufferedWindows() const { return mUseDoubleBufferedWindows; }
+    LibraryType GetLibraryType() const { return mLibType; }
+    static LibraryType SelectLibrary(const GLContext::ContextFlags& aFlags);
+    
 private:
     bool mInitialized;
     PRLibrary *mOGLLibrary;
     bool mHasRobustness;
+
+    HWND mWindow;
+    HDC mWindowDC;
+    HGLRC mWindowGLContext;
+    int mWindowPixelFormat;
+    bool mUseDoubleBufferedWindows;
+    LibraryType mLibType;
+
 };
 
 // a global WGLLibrary instance
-extern WGLLibrary sWGLLibrary;
+extern WGLLibrary sWGLLibrary[WGLLibrary::LIBS_MAX];
 
 } /* namespace gl */
 } /* namespace mozilla */
 
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -232,16 +232,17 @@ pref("gfx.canvas.azure.enabled", true);
 #endif
 #endif
 
 #ifdef ANDROID
 pref("gfx.textures.poweroftwo.force-enabled", false);
 #endif
 
 pref("gfx.work-around-driver-bugs", true);
+pref("gfx.prefer-mesa-llvmpipe", false);
 
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);
 
 #ifndef XP_MACOSX
 // Tab focus model bit field: