Bug 686735 - 1/2 - Implement no-gfx-driver-workarounds mode - r=joe,ajuma,jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Tue, 10 Apr 2012 11:49:10 -0400
changeset 91316 469e2e5b18e5e0da7446b7823b1fe232fca8672d
parent 91313 2fd41fea3b27e5ac331b54786b38d30039a03201
child 91317 fb6f8a081a475246f26b910cbc4f642c2e736209
push id22438
push usermbrubeck@mozilla.com
push dateWed, 11 Apr 2012 15:56:36 +0000
treeherdermozilla-central@63f78a93ae5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe, ajuma, jgilbert
bugs686735
milestone14.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 686735 - 1/2 - Implement no-gfx-driver-workarounds mode - r=joe,ajuma,jgilbert Part 1: introduce the gfx.work-around-driver-bugs preference and handle most existing workarounds
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
modules/libpref/src/init/all.js
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -1370,19 +1370,22 @@ WebGLContext::DisableVertexAttribArray(W
 
 int
 WebGLContext::WhatDoesVertexAttrib0Need()
 {
   // here we may assume that mCurrentProgram != null
 
     // work around Mac OSX crash, see bug 631420
 #ifdef XP_MACOSX
-    if (mAttribBuffers[0].enabled &&
+    if (gl->WorkAroundDriverBugs() &&
+        mAttribBuffers[0].enabled &&
         !mCurrentProgram->IsAttribInUse(0))
+    {
         return VertexAttrib0Status::EmulatedUninitializedArray;
+    }
 #endif
 
     return (gl->IsGLES2() || mAttribBuffers[0].enabled) ? VertexAttrib0Status::Default
          : mCurrentProgram->IsAttribInUse(0)            ? VertexAttrib0Status::EmulatedInitializedArray
                                                         : VertexAttrib0Status::EmulatedUninitializedArray;
 }
 
 bool
@@ -2637,17 +2640,20 @@ WebGLContext::GetProgramParameter(nsIWeb
             wrval->SetAsBool(bool(i));
         }
             break;
         case LOCAL_GL_VALIDATE_STATUS:
         {
             GLint i = 0;
 #ifdef XP_MACOSX
             // See comment in ValidateProgram below.
-            i = 1;
+            if (gl->WorkAroundDriverBugs())
+                i = 1;
+            else
+                gl->fGetProgramiv(progname, pname, &i);
 #else
             gl->fGetProgramiv(progname, pname, &i);
 #endif
             wrval->SetAsBool(bool(i));
         }
             break;
 
         default:
@@ -4392,18 +4398,20 @@ WebGLContext::ValidateProgram(nsIWebGLPr
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>("validateProgram", pobj, &progname))
         return NS_OK;
 
     MakeContextCurrent();
 
 #ifdef XP_MACOSX
     // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
-    LogMessageIfVerbose("validateProgram: implemented as a no-operation on Mac to work around crashes");
-    return NS_OK;
+    if (gl->WorkAroundDriverBugs()) {
+        LogMessageIfVerbose("validateProgram: implemented as a no-operation on Mac to work around crashes");
+        return NS_OK;
+    }
 #endif
 
     gl->fValidateProgram(progname);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -4501,36 +4509,43 @@ WebGLContext::CompileShader(nsIWebGLShad
             return NS_OK;
 
         const nsPromiseFlatString& flatSource = PromiseFlatString(cleanSource);
 
         // shaderSource() already checks that the source stripped of comments is in the
         // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
         const nsCString& sourceCString = NS_LossyConvertUTF16toASCII(flatSource);
 
-        const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
-        if (sourceCString.Length() > maxSourceLength)
-            return ErrorInvalidValue("compileShader: source has more than %d characters", maxSourceLength);
+        if (gl->WorkAroundDriverBugs()) {
+            const PRUint32 maxSourceLength = (PRUint32(1)<<18) - 1;
+            if (sourceCString.Length() > maxSourceLength)
+                return ErrorInvalidValue("compileShader: source has more than %d characters", 
+                                         maxSourceLength);
+        }
 
         const char *s = sourceCString.get();
 
         compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
                                        SH_WEBGL_SPEC,
                                        targetShaderSourceLanguage,
                                        &resources);
 
         int compileOptions = 0;
         if (useShaderSourceTranslation) {
             compileOptions |= SH_OBJECT_CODE
                             | SH_MAP_LONG_VARIABLE_NAMES
                             | SH_ATTRIBUTES_UNIFORMS;
 #ifdef XP_MACOSX
             // work around bug 665578
-            if (!nsCocoaFeatures::OnLionOrLater() && gl->Vendor() == gl::GLContext::VendorATI)
+            if (gl->WorkAroundDriverBugs() &&
+                !nsCocoaFeatures::OnLionOrLater() &&
+                gl->Vendor() == gl::GLContext::VendorATI)
+            {
                 compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+            }
 #endif
         }
 
         if (!ShCompile(compiler, &s, 1, compileOptions)) {
             int len = 0;
             ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &len);
 
             if (len) {
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -636,17 +636,18 @@ WebGLContext::InitAndValidateGL()
         // specifically enabled on desktop GLSL.
         gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
 
         // we don't do the following glEnable(GL_POINT_SPRITE) on ATI cards on Windows, because bug 602183 shows that it causes
         // crashes in the ATI/Windows driver; and point sprites on ATI seem like a lost cause anyway, see
         //    http://www.gamedev.net/community/forums/topic.asp?topic_id=525643
         // Also, if the ATI/Windows driver implements a recent GL spec version, this shouldn't be needed anyway.
 #ifdef XP_WIN
-        if (gl->Vendor() != gl::GLContext::VendorATI)
+        if (!(gl->WorkAroundDriverBugs() &&
+              gl->Vendor() == gl::GLContext::VendorATI))
 #else
         if (true)
 #endif
         {
             // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
             // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
             //   http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
             gl->fEnable(LOCAL_GL_POINT_SPRITE);
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -121,16 +121,18 @@ GLContext::InitWithPrefix(const char *pr
 {
     ScopedGfxFeatureReporter reporter("GL Context");
 
     if (mInitialized) {
         reporter.SetSuccessful();
         return true;
     }
 
+    mWorkAroundDriverBugs = gfxPlatform::GetPlatform()->WorkAroundDriverBugs();
+
     SymLoadStruct symbols[] = {
         { (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", NULL } },
         { (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", NULL } },
         { (PRFuncPtr*) &mSymbols.fBlendEquation, { "BlendEquation", NULL } },
@@ -496,17 +498,18 @@ GLContext::InitWithPrefix(const char *pr
         fGetIntegerv(LOCAL_GL_VIEWPORT, v);
         mViewportStack.AppendElement(nsIntRect(v[0], v[1], v[2], v[3]));
 
         fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
         fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
         fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
 
 #ifdef XP_MACOSX
-        if (mVendor == VendorIntel) {
+        if (mWorkAroundDriverBugs &&
+            mVendor == VendorIntel) {
             // see bug 737182 for 2D textures, bug 684822 for cube map textures.
             mMaxTextureSize        = NS_MIN(mMaxTextureSize,        4096);
             mMaxCubeMapTextureSize = NS_MIN(mMaxCubeMapTextureSize, 512);
             // for good measure, we align renderbuffers on what we do for 2D textures
             mMaxRenderbufferSize   = NS_MIN(mMaxRenderbufferSize,   4096);
         }
 #endif
 
@@ -629,32 +632,38 @@ CopyAndPadTextureData(const GLvoid* srcB
 // to determine good or bad driver versions for POT texture uploads,
 // so blacklist them all. Newer drivers use a different rendering
 // string in the form "Adreno (TM) 200" and the drivers we've seen so
 // far work fine with NPOT textures, so don't blacklist those until we
 // have evidence of any problems with them.
 bool
 GLContext::CanUploadSubTextures()
 {
+    if (!mWorkAroundDriverBugs)
+        return true;
+
     // There are certain GPUs that we don't want to use glTexSubImage2D on
     // because that function can be very slow and/or buggy
     if (Renderer() == RendererAdreno200 || Renderer() == RendererAdreno205)
         return false;
 
     // On PowerVR glTexSubImage does a readback, so it will be slower
     // than just doing a glTexImage2D() directly. i.e. 26ms vs 10ms
     if (Renderer() == RendererSGX540 || Renderer() == RendererSGX530)
         return false;
 
     return true;
 }
 
 bool
 GLContext::CanUploadNonPowerOfTwo()
 {
+    if (!mWorkAroundDriverBugs)
+        return true;
+
     static bool sPowerOfTwoForced;
     static bool sPowerOfTwoPrefCached = false;
 
     if (!sPowerOfTwoPrefCached) {
         sPowerOfTwoPrefCached = true;
         mozilla::Preferences::AddBoolVarCache(&sPowerOfTwoForced,
                                               "gfx.textures.poweroftwo.force-enabled");
     }
@@ -668,17 +677,18 @@ bool
 GLContext::WantsSmallTiles()
 {
     // We must use small tiles for good performance if we can't use
     // glTexSubImage2D() for some reason.
     if (!CanUploadSubTextures())
         return true;
 
     // We can't use small tiles on the SGX 540, because of races in texture upload.
-    if (Renderer() == RendererSGX540)
+    if (mWorkAroundDriverBugs &&
+        Renderer() == RendererSGX540)
         return false;
 
     // Don't use small tiles otherwise. (If we implement incremental texture upload,
     // then we will want to revisit this.)
     return false;
 }
 
 // Common code for checking for both GL extensions and GLX extensions.
@@ -2060,17 +2070,19 @@ GLContext::BlitTextureImage(TextureImage
     NS_ASSERTION(!aDst->InUpdate(), "Destination texture is in update!");
 
     if (aSrcRect.IsEmpty() || aDstRect.IsEmpty())
         return;
 
     // only save/restore this stuff on Qualcomm Adreno, to work
     // around an apparent bug
     int savedFb = 0;
-    if (mVendor == VendorQualcomm) {
+    if (mWorkAroundDriverBugs &&
+        mVendor == VendorQualcomm)
+    {
         fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &savedFb);
     }
 
     fDisable(LOCAL_GL_SCISSOR_TEST);
     fDisable(LOCAL_GL_BLEND);
 
     // 2.0 means scale up by two
     float blitScaleX = float(aDstRect.width) / float(aSrcRect.width);
@@ -2195,17 +2207,18 @@ GLContext::BlitTextureImage(TextureImage
     SetBlitFramebufferForDestTexture(0);
 
     // then put back the previous framebuffer, and don't
     // enable stencil if it wasn't enabled on entry to work
     // around Adreno 200 bug that causes us to crash if
     // we enable scissor test while the current FBO is invalid
     // (which it will be, once we assign texture 0 to the color
     // attachment)
-    if (mVendor == VendorQualcomm) {
+    if (mWorkAroundDriverBugs &&
+        mVendor == VendorQualcomm) {
         fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, savedFb);
     }
 
     fEnable(LOCAL_GL_SCISSOR_TEST);
     fEnable(LOCAL_GL_BLEND);
 }
 
 static unsigned int 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -550,17 +550,18 @@ public:
         mOffscreenDrawFBO(0),
         mOffscreenReadFBO(0),
         mOffscreenColorRB(0),
         mOffscreenDepthRB(0),
         mOffscreenStencilRB(0),
         mMaxTextureSize(0),
         mMaxCubeMapTextureSize(0),
         mMaxTextureImageSize(0),
-        mMaxRenderbufferSize(0)
+        mMaxRenderbufferSize(0),
+        mWorkAroundDriverBugs(true)
 #ifdef DEBUG
         , mGLError(LOCAL_GL_NO_ERROR)
 #endif
     {
         mUserData.Init();
     }
 
     virtual ~GLContext() {
@@ -1649,16 +1650,18 @@ protected:
     ExtensionBitset<Extensions_Max> mAvailableExtensions;
 
     // Clear to transparent black, with 0 depth and stencil,
     // while preserving current ClearColor etc. values.
     // Useful for resizing offscreen buffers.
 public:
     void ClearSafely();
 
+    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
+
 protected:
 
     nsDataHashtable<nsPtrHashKey<void>, void*> mUserData;
 
     void SetIsGLES2(bool aIsGLES2) {
         NS_ASSERTION(!mInitialized, "SetIsGLES2 can only be called before initialization!");
         mIsGLES2 = aIsGLES2;
     }
@@ -1680,28 +1683,29 @@ protected:
     }
 
     bool IsOffscreenSizeAllowed(const gfxIntSize& aSize) const {
         PRInt32 biggerDimension = NS_MAX(aSize.width, aSize.height);
         PRInt32 maxAllowed = NS_MIN(mMaxRenderbufferSize, mMaxTextureSize);
         return biggerDimension <= maxAllowed;
     }
 
-protected:
     nsTArray<nsIntRect> mViewportStack;
     nsTArray<nsIntRect> mScissorStack;
 
     GLint mMaxTextureSize;
     GLint mMaxCubeMapTextureSize;
     GLint mMaxTextureImageSize;
     GLint mMaxRenderbufferSize;
+    bool mWorkAroundDriverBugs;
 
     bool IsTextureSizeSafeToPassToDriver(GLenum target, GLsizei width, GLsizei height) const {
 #ifdef XP_MACOSX
-        if (mVendor == VendorIntel) {
+        if (mWorkAroundDriverBugs &&
+            mVendor == VendorIntel) {
             // see bug 737182 for 2D textures, bug 684822 for cube map textures.
             // some drivers handle incorrectly some large texture sizes that are below the
             // max texture size that they report. So we check ourselves against our own values
             // (mMax[CubeMap]TextureSize).
             GLsizei maxSize = target == LOCAL_GL_TEXTURE_CUBE_MAP ||
                                 (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
                                 target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)
                               ? mMaxCubeMapTextureSize
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -331,16 +331,18 @@ gfxPlatform::Init()
 
     /* Create and register our CMS Override observer. */
     gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, "gfx.color_management.force_srgb");
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
+    gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
+
     // Force registration of the gfx component, thus arranging for
     // ::Shutdown to be called.
     nsCOMPtr<nsISupports> forceReg
         = do_CreateInstance("@mozilla.org/gfx/init;1");
 }
 
 void
 gfxPlatform::Shutdown()
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -450,16 +450,18 @@ public:
     virtual gfxImageFormat GetOffscreenFormat()
     { return gfxASurface::FormatFromContent(gfxASurface::CONTENT_COLOR); }
 
     /**
      * Returns a logger if one is available and logging is enabled
      */
     static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
 
+    bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], PRUint32 &aLen, 
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
                                                
     PRInt8  mAllowDownloadableFonts;
@@ -488,11 +490,12 @@ private:
 
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     nsRefPtr<gfxASurface> mScreenReferenceSurface;
     nsTArray<PRUint32> mCJKPrefLangs;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureBackendCollector;
+    bool mWorkAroundDriverBugs;
 };
 
 #endif /* GFX_PLATFORM_H */
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -240,16 +240,18 @@ pref("gfx.canvas.azure.enabled", true);
 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("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
 
 pref("accessibility.browsewithcaret_shortcut.enabled", true);
 
 #ifndef XP_MACOSX
 // Tab focus model bit field:
 // 1 focuses text controls, 2 focuses other form elements, 4 adds links.