Bug 721467 - Add a codepath to only use glTexImage2D instead of glTexSubImage2D when texture uploading in GLContext
authorGeorge Wright <gwright@mozilla.com>
Mon, 30 Jan 2012 15:09:02 -0500
changeset 90879 f042470aaafc1677161d98d19a94dc72b41849db
parent 90878 d47c32d6795d85dcfa04bd74eea8b4017f94bb22
child 90880 0b940c84521d36d1a4303293d32b029edc8591db
push idunknown
push userunknown
push dateunknown
bugs721467
milestone12.0a1
Bug 721467 - Add a codepath to only use glTexImage2D instead of glTexSubImage2D when texture uploading in GLContext
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderGLX.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -377,32 +377,45 @@ GLContext::InitWithPrefix(const char *pr
             if (!LoadSymbols(&symbols_desktop[0], trygl, prefix)) {
                 NS_RUNTIMEABORT("Desktop symbols failed to load.");
                 mInitialized = false;
             }
         }
     }
 
     const char *glVendorString;
+    const char *glRendererString;
 
     if (mInitialized) {
         glVendorString = (const char *)fGetString(LOCAL_GL_VENDOR);
         const char *vendorMatchStrings[VendorOther] = {
                 "Intel",
                 "NVIDIA",
                 "ATI",
                 "Qualcomm"
         };
         mVendor = VendorOther;
         for (int i = 0; i < VendorOther; ++i) {
-            if (DoesVendorStringMatch(glVendorString, vendorMatchStrings[i])) {
+            if (DoesStringMatch(glVendorString, vendorMatchStrings[i])) {
                 mVendor = i;
                 break;
             }
         }
+
+        glRendererString = (const char *)fGetString(LOCAL_GL_RENDERER);
+        const char *rendererMatchStrings[RendererOther] = {
+                "Adreno 200"
+        };
+        mRenderer = RendererOther;
+        for (int i = 0; i < RendererOther; ++i) {
+            if (DoesStringMatch(glRendererString, rendererMatchStrings[i])) {
+                mRenderer = i;
+                break;
+            }
+        }
     }
 
     if (mInitialized) {
 #ifdef DEBUG
         static bool once = false;
         if (!once) {
             const char *vendors[VendorOther] = {
                 "Intel",
@@ -585,16 +598,25 @@ GLContext::InitExtensions()
 }
 
 bool
 GLContext::IsExtensionSupported(const char *extension)
 {
     return ListHasExtension(fGetString(LOCAL_GL_EXTENSIONS), extension);
 }
 
+bool
+GLContext::CanUploadSubTextures()
+{
+    // There are certain GPUs that we don't want to use glTexSubImage2D on
+    // because that function can be very slow and/or buggy
+
+    return !(Renderer() == RendererAdreno200);
+}
+
 // Common code for checking for both GL extensions and GLX extensions.
 bool
 GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
 {
     // fix bug 612572 - we were crashing as we were calling this function with extensions==null
     if (extensions == nsnull || extension == nsnull)
         return false;
 
@@ -683,17 +705,22 @@ BasicTextureImage::~BasicTextureImage()
 }
 
 gfxASurface*
 BasicTextureImage::BeginUpdate(nsIntRegion& aRegion)
 {
     NS_ASSERTION(!mUpdateSurface, "BeginUpdate() without EndUpdate()?");
 
     // determine the region the client will need to repaint
-    GetUpdateRegion(aRegion);
+    if (mGLContext->CanUploadSubTextures()) {
+        GetUpdateRegion(aRegion);
+    } else {
+        aRegion = nsIntRect(nsIntPoint(0, 0), mSize);
+    }
+
     mUpdateRegion = aRegion;
 
     nsIntRect rgnSize = mUpdateRegion.GetBounds();
     if (!nsIntRect(nsIntPoint(0, 0), mSize).Contains(rgnSize)) {
         NS_ERROR("update outside of image");
         return NULL;
     }
 
@@ -846,17 +873,18 @@ TiledTextureImage::TiledTextureImage(GLC
 TiledTextureImage::~TiledTextureImage()
 {
 }
 
 bool 
 TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion, const nsIntPoint& aFrom /* = nsIntPoint(0, 0) */)
 {
     nsIntRegion region;
-    if (mTextureState != Valid) {
+
+    if (mTextureState != Valid || !mGL->CanUploadSubTextures()) {
         nsIntRect bounds = nsIntRect(0, 0, mSize.width, mSize.height);
         region = nsIntRegion(bounds);
     } else {
         region = aRegion;
     }
 
     bool result = true;
     for (unsigned i = 0; i < mImages.Length(); i++) {
@@ -2044,17 +2072,17 @@ GLContext::UploadSurfaceToTexture(gfxASu
         // bounding rectangle. We need to find the offset of this rect
         // within the region and adjust the data pointer accordingly.
         unsigned char *rectData = 
             data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
 
         NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0), 
                      "Must be uploading to the origin when we don't have an existing texture");
 
-        if (textureInited) {
+        if (textureInited && CanUploadSubTextures()) {
             TexSubImage2D(LOCAL_GL_TEXTURE_2D,
                           0,
                           iterRect->x,
                           iterRect->y,
                           iterRect->width,
                           iterRect->height,
                           stride,
                           pixelSize,
@@ -2095,16 +2123,20 @@ static GLint GetAddressAlignment(ptrdiff
 
 void
 GLContext::TexImage2D(GLenum target, GLint level, GLint internalformat, 
                       GLsizei width, GLsizei height, GLsizei stride,
                       GLint pixelsize, GLint border, GLenum format, 
                       GLenum type, const GLvoid *pixels)
 {
 #ifdef USE_GLES2
+
+    NS_ASSERTION(format == internalformat,
+                 "format and internalformat not the same for glTexImage2D on GLES2");
+
     // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
     // implemented in TexSubImage2D.
     fTexImage2D(target,
                 border,
                 internalformat,
                 width,
                 height,
                 border,
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -540,16 +540,17 @@ public:
         mIsGLES2(true),
 #else
         mIsGLES2(false),
 #endif
         mIsGlobalSharedContext(false),
         mHasRobustness(false),
         mContextLost(false),
         mVendor(-1),
+        mRenderer(-1),
         mDebugMode(0),
         mCreationFormat(aFormat),
         mSharedContext(aSharedContext),
         mOffscreenTexture(0),
         mFlipped(false),
         mBlitProgram(0),
         mBlitFramebuffer(0),
         mOffscreenDrawFBO(0),
@@ -683,20 +684,31 @@ public:
     enum {
         VendorIntel,
         VendorNVIDIA,
         VendorATI,
         VendorQualcomm,
         VendorOther
     };
 
+    enum {
+        RendererAdreno200,
+        RendererOther
+    };
+
     int Vendor() const {
         return mVendor;
     }
 
+    int Renderer() const {
+        return mRenderer;
+    }
+
+    bool CanUploadSubTextures();
+
     /**
      * If this context wraps a double-buffered target, swap the back
      * and front buffers.  It should be assumed that after a swap, the
      * contents of the new back buffer are undefined.
      */
     virtual bool SwapBuffers() { return false; }
 
     /**
@@ -762,16 +774,17 @@ public:
     bool IsOffscreen() {
         return mIsOffscreen;
     }
 
 protected:
     bool mFlushGuaranteesResolve;
 
 public:
+
     void SetFlushGuaranteesResolve(bool aFlushGuaranteesResolve) {
         mFlushGuaranteesResolve = aFlushGuaranteesResolve;
     }
     
     // Before reads from offscreen texture
     void GuaranteeResolve() {
         if (mFlushGuaranteesResolve) {
             BlitDirtyFBOs();
@@ -1376,16 +1389,17 @@ protected:
     bool mInitialized;
     bool mIsOffscreen;
     bool mIsGLES2;
     bool mIsGlobalSharedContext;
     bool mHasRobustness;
     bool mContextLost;
 
     PRInt32 mVendor;
+    PRInt32 mRenderer;
 
     enum {
         DebugEnabled = 1 << 0,
         DebugTrace = 1 << 1,
         DebugAbortOnError = 1 << 2
     };
 
     PRUint32 mDebugMode;
@@ -2678,33 +2692,33 @@ public:
     nsTArray<NamedResource> mTrackedFramebuffers;
     nsTArray<NamedResource> mTrackedRenderbuffers;
     nsTArray<NamedResource> mTrackedBuffers;
 #endif
 
 };
 
 inline bool
-DoesVendorStringMatch(const char* aVendorString, const char *aWantedVendor)
+DoesStringMatch(const char* aString, const char *aWantedString)
 {
-    if (!aVendorString || !aWantedVendor)
+    if (!aString || !aWantedString)
         return false;
 
-    const char *occurrence = strstr(aVendorString, aWantedVendor);
-
-    // aWantedVendor not found
+    const char *occurrence = strstr(aString, aWantedString);
+
+    // aWanted not found
     if (!occurrence)
         return false;
 
-    // aWantedVendor preceded by alpha character
-    if (occurrence != aVendorString && isalpha(*(occurrence-1)))
+    // aWantedString preceded by alpha character
+    if (occurrence != aString && isalpha(*(occurrence-1)))
         return false;
 
     // aWantedVendor followed by alpha character
-    const char *afterOccurrence = occurrence + strlen(aWantedVendor);
+    const char *afterOccurrence = occurrence + strlen(aWantedString);
     if (isalpha(*afterOccurrence))
         return false;
 
     return true;
 }
 
 } /* namespace gl */
 } /* namespace mozilla */
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -256,21 +256,21 @@ GLXLibrary::EnsureInitialized()
         NS_WARNING("Texture from pixmap disabled");
     }
 
     if (HasExtension(extensionsStr, "GLX_ARB_create_context_robustness") &&
         LibrarySymbolLoader::LoadSymbols(mOGLLibrary, symbols_robustness)) {
         mHasRobustness = true;
     }
 
-    gIsATI = serverVendor && DoesVendorStringMatch(serverVendor, "ATI");
+    gIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI");
     gIsChromium = (serverVendor &&
-                   DoesVendorStringMatch(serverVendor, "Chromium")) ||
+                   DoesStringMatch(serverVendor, "Chromium")) ||
         (serverVersionStr &&
-         DoesVendorStringMatch(serverVersionStr, "Chromium"));
+         DoesStringMatch(serverVersionStr, "Chromium"));
 
     mInitialized = true;
     return true;
 }
 
 bool
 GLXLibrary::SupportsTextureFromPixmap(gfxASurface* aSurface)
 {