Bug 942500 - Move GLContext::TexImage2D and friends out of GLContext - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Tue, 03 Dec 2013 13:44:38 -0500
changeset 174282 11d9777debba413f62c1c16dc8c91eab70789cb2
parent 174281 3f08f279aec71e1f8c3248d49db58a3a4c978d83
child 174283 7c7c405d9373a0ae722411613b841161bbbfc86d
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs942500
milestone28.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 942500 - Move GLContext::TexImage2D and friends out of GLContext - r=jgilbert
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLUploadHelpers.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -1140,53 +1140,16 @@ GLContext::InitExtensions()
         MarkExtensionSupported(OES_rgb8_rgba8);
     }
 
 #ifdef DEBUG
     firstRun = false;
 #endif
 }
 
-
-// Take texture data in a given buffer and copy it into a larger buffer,
-// padding out the edge pixels for filtering if necessary
-static void
-CopyAndPadTextureData(const GLvoid* srcBuffer,
-                      GLvoid* dstBuffer,
-                      GLsizei srcWidth, GLsizei srcHeight,
-                      GLsizei dstWidth, GLsizei dstHeight,
-                      GLsizei stride, GLint pixelsize)
-{
-    unsigned char *rowDest = static_cast<unsigned char*>(dstBuffer);
-    const unsigned char *source = static_cast<const unsigned char*>(srcBuffer);
-
-    for (GLsizei h = 0; h < srcHeight; ++h) {
-        memcpy(rowDest, source, srcWidth * pixelsize);
-        rowDest += dstWidth * pixelsize;
-        source += stride;
-    }
-
-    GLsizei padHeight = srcHeight;
-
-    // Pad out an extra row of pixels so that edge filtering doesn't use garbage data
-    if (dstHeight > srcHeight) {
-        memcpy(rowDest, source - stride, srcWidth * pixelsize);
-        padHeight++;
-    }
-
-    // Pad out an extra column of pixels
-    if (dstWidth > srcWidth) {
-        rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize;
-        for (GLsizei h = 0; h < padHeight; ++h) {
-            memcpy(rowDest, rowDest - pixelsize, pixelsize);
-            rowDest += dstWidth * pixelsize;
-        }
-    }
-}
-
 // In both of these cases (for the Adreno at least) it is impossible
 // 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()
@@ -2512,266 +2475,16 @@ GLContext::ReadPixelsIntoImageSurface(gf
                 }
             }
             dest->MarkDirty();
         }
     }
 #endif
 }
 
-static GLint GetAddressAlignment(ptrdiff_t aAddress)
-{
-    if (!(aAddress & 0x7)) {
-       return 8;
-    } else if (!(aAddress & 0x3)) {
-        return 4;
-    } else if (!(aAddress & 0x1)) {
-        return 2;
-    } else {
-        return 1;
-    }
-}
-
-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)
-{
-    if (IsGLES2()) {
-
-        NS_ASSERTION(format == (GLenum)internalformat,
-                    "format and internalformat not the same for glTexImage2D on GLES2");
-
-        if (!CanUploadNonPowerOfTwo()
-            && (stride != width * pixelsize
-            || !IsPowerOfTwo(width)
-            || !IsPowerOfTwo(height))) {
-
-            // Pad out texture width and height to the next power of two
-            // as we don't support/want non power of two texture uploads
-            GLsizei paddedWidth = NextPowerOfTwo(width);
-            GLsizei paddedHeight = NextPowerOfTwo(height);
-
-            GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize];
-
-            // Pad out texture data to be in a POT sized buffer for uploading to
-            // a POT sized texture
-            CopyAndPadTextureData(pixels, paddedPixels, width, height,
-                                  paddedWidth, paddedHeight, stride, pixelsize);
-
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)paddedPixels),
-                            GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize)));
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        paddedWidth,
-                        paddedHeight,
-                        border,
-                        format,
-                        type,
-                        paddedPixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-
-            delete[] static_cast<unsigned char*>(paddedPixels);
-            return;
-        }
-
-        if (stride == width * pixelsize) {
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        width,
-                        height,
-                        border,
-                        format,
-                        type,
-                        pixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-        } else {
-            // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
-            // implemented in TexSubImage2D.
-            fTexImage2D(target,
-                        border,
-                        internalformat,
-                        width,
-                        height,
-                        border,
-                        format,
-                        type,
-                        nullptr);
-            TexSubImage2D(target,
-                          level,
-                          0,
-                          0,
-                          width,
-                          height,
-                          stride,
-                          pixelsize,
-                          format,
-                          type,
-                          pixels);
-        }
-    } else {
-        // desktop GL (non-ES) path
-
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-        int rowLength = stride/pixelsize;
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-        fTexImage2D(target,
-                    level,
-                    internalformat,
-                    width,
-                    height,
-                    border,
-                    format,
-                    type,
-                    pixels);
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-    }
-}
-
-void
-GLContext::TexSubImage2D(GLenum target, GLint level,
-                         GLint xoffset, GLint yoffset,
-                         GLsizei width, GLsizei height, GLsizei stride,
-                         GLint pixelsize, GLenum format,
-                         GLenum type, const GLvoid* pixels)
-{
-    if (IsGLES2()) {
-        if (stride == width * pixelsize) {
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-            fTexSubImage2D(target,
-                          level,
-                          xoffset,
-                          yoffset,
-                          width,
-                          height,
-                          format,
-                          type,
-                          pixels);
-            fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-        } else if (IsExtensionSupported(EXT_unpack_subimage)) {
-            TexSubImage2DWithUnpackSubimageGLES(target, level, xoffset, yoffset,
-                                                width, height, stride,
-                                                pixelsize, format, type, pixels);
-
-        } else {
-            TexSubImage2DWithoutUnpackSubimage(target, level, xoffset, yoffset,
-                                              width, height, stride,
-                                              pixelsize, format, type, pixels);
-        }
-    } else {
-        // desktop GL (non-ES) path
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-        int rowLength = stride/pixelsize;
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-        fTexSubImage2D(target,
-                      level,
-                      xoffset,
-                      yoffset,
-                      width,
-                      height,
-                      format,
-                      type,
-                      pixels);
-        fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-        fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-    }
-}
-
-void
-GLContext::TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
-                                               GLint xoffset, GLint yoffset,
-                                               GLsizei width, GLsizei height,
-                                               GLsizei stride, GLint pixelsize,
-                                               GLenum format, GLenum type,
-                                               const GLvoid* pixels)
-{
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                 std::min(GetAddressAlignment((ptrdiff_t)pixels),
-                        GetAddressAlignment((ptrdiff_t)stride)));
-    // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra
-    // driver crash where the driver apparently tries to read
-    // (stride - width * pixelsize) bytes past the end of the last input
-    // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH,
-    // and then we upload the final row separately. See bug 697990.
-    int rowLength = stride/pixelsize;
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset,
-                    width,
-                    height-1,
-                    format,
-                    type,
-                    pixels);
-    fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset+height-1,
-                    width,
-                    1,
-                    format,
-                    type,
-                    (const unsigned char *)pixels+(height-1)*stride);
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-}
-
-void
-GLContext::TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
-                                              GLint xoffset, GLint yoffset,
-                                              GLsizei width, GLsizei height,
-                                              GLsizei stride, GLint pixelsize,
-                                              GLenum format, GLenum type,
-                                              const GLvoid* pixels)
-{
-    // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH
-    // isn't supported. We make a copy of the texture data we're using,
-    // such that we're using the whole row of data in the copy. This turns
-    // out to be more efficient than uploading row-by-row; see bug 698197.
-    unsigned char *newPixels = new unsigned char[width*height*pixelsize];
-    unsigned char *rowDest = newPixels;
-    const unsigned char *rowSource = (const unsigned char *)pixels;
-    for (int h = 0; h < height; h++) {
-            memcpy(rowDest, rowSource, width*pixelsize);
-            rowDest += width*pixelsize;
-            rowSource += stride;
-    }
-
-    stride = width*pixelsize;
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
-                    std::min(GetAddressAlignment((ptrdiff_t)newPixels),
-                            GetAddressAlignment((ptrdiff_t)stride)));
-    fTexSubImage2D(target,
-                    level,
-                    xoffset,
-                    yoffset,
-                    width,
-                    height,
-                    format,
-                    type,
-                    newPixels);
-    delete [] newPixels;
-    fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
-}
-
 #ifdef MOZ_ENABLE_GL_TRACKING
 void
 GLContext::CreatedProgram(GLContext *aOrigin, GLuint aName)
 {
     mTrackedPrograms.AppendElement(NamedResource(aOrigin, aName));
 }
 
 void
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2668,46 +2668,16 @@ public:
     void ReadPixelsIntoImageSurface(gfxImageSurface* dest);
 
     // Similar to ReadPixelsIntoImageSurface, but pulls from the screen
     // instead of the currently bound framebuffer.
     void ReadScreenIntoImageSurface(gfxImageSurface* dest);
 
     TemporaryRef<gfx::SourceSurface> ReadPixelsToSourceSurface(const gfx::IntSize &aSize);
 
-    void TexImage2D(GLenum target, GLint level, GLint internalformat,
-                    GLsizei width, GLsizei height, GLsizei stride,
-                    GLint pixelsize, GLint border, GLenum format,
-                    GLenum type, const GLvoid *pixels);
-
-    void TexSubImage2D(GLenum target, GLint level,
-                       GLint xoffset, GLint yoffset,
-                       GLsizei width, GLsizei height, GLsizei stride,
-                       GLint pixelsize, GLenum format,
-                       GLenum type, const GLvoid* pixels);
-
-    /**
-     * Uses the Khronos GL_EXT_unpack_subimage extension, working around
-     * quirks in the Tegra implementation of this extension.
-     */
-    void TexSubImage2DWithUnpackSubimageGLES(GLenum target, GLint level,
-                                             GLint xoffset, GLint yoffset,
-                                             GLsizei width, GLsizei height,
-                                             GLsizei stride, GLint pixelsize,
-                                             GLenum format, GLenum type,
-                                             const GLvoid* pixels);
-
-    void TexSubImage2DWithoutUnpackSubimage(GLenum target, GLint level,
-                                            GLint xoffset, GLint yoffset,
-                                            GLsizei width, GLsizei height,
-                                            GLsizei stride, GLint pixelsize,
-                                            GLenum format, GLenum type,
-                                            const GLvoid* pixels);
-
-
     // Shared code for GL extensions and GLX extensions.
     static bool ListHasExtension(const GLubyte *extensions,
                                  const char *extension);
 
     GLint GetMaxTextureImageSize() { return mMaxTextureImageSize; }
     void SetFlipped(bool aFlipped) { mFlipped = aFlipped; }
 
 
--- a/gfx/gl/GLUploadHelpers.cpp
+++ b/gfx/gl/GLUploadHelpers.cpp
@@ -38,16 +38,307 @@ ImageFormatForSurfaceFormat(gfx::Surface
             return gfxImageFormatRGB16_565;
         case gfx::FORMAT_A8:
             return gfxImageFormatA8;
         default:
             return gfxImageFormatUnknown;
     }
 }
 
+static GLint GetAddressAlignment(ptrdiff_t aAddress)
+{
+    if (!(aAddress & 0x7)) {
+       return 8;
+    } else if (!(aAddress & 0x3)) {
+        return 4;
+    } else if (!(aAddress & 0x1)) {
+        return 2;
+    } else {
+        return 1;
+    }
+}
+
+// Take texture data in a given buffer and copy it into a larger buffer,
+// padding out the edge pixels for filtering if necessary
+static void
+CopyAndPadTextureData(const GLvoid* srcBuffer,
+                      GLvoid* dstBuffer,
+                      GLsizei srcWidth, GLsizei srcHeight,
+                      GLsizei dstWidth, GLsizei dstHeight,
+                      GLsizei stride, GLint pixelsize)
+{
+    unsigned char *rowDest = static_cast<unsigned char*>(dstBuffer);
+    const unsigned char *source = static_cast<const unsigned char*>(srcBuffer);
+
+    for (GLsizei h = 0; h < srcHeight; ++h) {
+        memcpy(rowDest, source, srcWidth * pixelsize);
+        rowDest += dstWidth * pixelsize;
+        source += stride;
+    }
+
+    GLsizei padHeight = srcHeight;
+
+    // Pad out an extra row of pixels so that edge filtering doesn't use garbage data
+    if (dstHeight > srcHeight) {
+        memcpy(rowDest, source - stride, srcWidth * pixelsize);
+        padHeight++;
+    }
+
+    // Pad out an extra column of pixels
+    if (dstWidth > srcWidth) {
+        rowDest = static_cast<unsigned char*>(dstBuffer) + srcWidth * pixelsize;
+        for (GLsizei h = 0; h < padHeight; ++h) {
+            memcpy(rowDest, rowDest - pixelsize, pixelsize);
+            rowDest += dstWidth * pixelsize;
+        }
+    }
+}
+
+static void
+TexSubImage2DWithUnpackSubimageGLES(GLContext* gl,
+                                    GLenum target, GLint level,
+                                    GLint xoffset, GLint yoffset,
+                                    GLsizei width, GLsizei height,
+                                    GLsizei stride, GLint pixelsize,
+                                    GLenum format, GLenum type,
+                                    const GLvoid* pixels)
+{
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                     std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                              GetAddressAlignment((ptrdiff_t)stride)));
+    // When using GL_UNPACK_ROW_LENGTH, we need to work around a Tegra
+    // driver crash where the driver apparently tries to read
+    // (stride - width * pixelsize) bytes past the end of the last input
+    // row. We only upload the first height-1 rows using GL_UNPACK_ROW_LENGTH,
+    // and then we upload the final row separately. See bug 697990.
+    int rowLength = stride/pixelsize;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset,
+                       width,
+                       height-1,
+                       format,
+                       type,
+                       pixels);
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset+height-1,
+                       width,
+                       1,
+                       format,
+                       type,
+                       (const unsigned char *)pixels+(height-1)*stride);
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+}
+
+static void
+TexSubImage2DWithoutUnpackSubimage(GLContext* gl,
+                                   GLenum target, GLint level,
+                                   GLint xoffset, GLint yoffset,
+                                   GLsizei width, GLsizei height,
+                                   GLsizei stride, GLint pixelsize,
+                                   GLenum format, GLenum type,
+                                   const GLvoid* pixels)
+{
+    // Not using the whole row of texture data and GL_UNPACK_ROW_LENGTH
+    // isn't supported. We make a copy of the texture data we're using,
+    // such that we're using the whole row of data in the copy. This turns
+    // out to be more efficient than uploading row-by-row; see bug 698197.
+    unsigned char *newPixels = new unsigned char[width*height*pixelsize];
+    unsigned char *rowDest = newPixels;
+    const unsigned char *rowSource = (const unsigned char *)pixels;
+    for (int h = 0; h < height; h++) {
+            memcpy(rowDest, rowSource, width*pixelsize);
+            rowDest += width*pixelsize;
+            rowSource += stride;
+    }
+
+    stride = width*pixelsize;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                     std::min(GetAddressAlignment((ptrdiff_t)newPixels),
+                              GetAddressAlignment((ptrdiff_t)stride)));
+    gl->fTexSubImage2D(target,
+                       level,
+                       xoffset,
+                       yoffset,
+                       width,
+                       height,
+                       format,
+                       type,
+                       newPixels);
+    delete [] newPixels;
+    gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+}
+
+static void
+TexSubImage2DHelper(GLContext *gl,
+                    GLenum target, GLint level,
+                    GLint xoffset, GLint yoffset,
+                    GLsizei width, GLsizei height, GLsizei stride,
+                    GLint pixelsize, GLenum format,
+                    GLenum type, const GLvoid* pixels)
+{
+    if (gl->IsGLES2()) {
+        if (stride == width * pixelsize) {
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                      GetAddressAlignment((ptrdiff_t)stride)));
+            gl->fTexSubImage2D(target,
+                               level,
+                               xoffset,
+                               yoffset,
+                               width,
+                               height,
+                               format,
+                               type,
+                               pixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+        } else if (gl->IsExtensionSupported(GLContext::EXT_unpack_subimage)) {
+            TexSubImage2DWithUnpackSubimageGLES(gl, target, level, xoffset, yoffset,
+                                                width, height, stride,
+                                                pixelsize, format, type, pixels);
+
+        } else {
+            TexSubImage2DWithoutUnpackSubimage(gl, target, level, xoffset, yoffset,
+                                              width, height, stride,
+                                              pixelsize, format, type, pixels);
+        }
+    } else {
+        // desktop GL (non-ES) path
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                         std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                  GetAddressAlignment((ptrdiff_t)stride)));
+        int rowLength = stride/pixelsize;
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+        gl->fTexSubImage2D(target,
+                           level,
+                           xoffset,
+                           yoffset,
+                           width,
+                           height,
+                           format,
+                           type,
+                           pixels);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+    }
+}
+
+static void
+TexImage2DHelper(GLContext *gl,
+                 GLenum target, GLint level, GLint internalformat,
+                 GLsizei width, GLsizei height, GLsizei stride,
+                 GLint pixelsize, GLint border, GLenum format,
+                 GLenum type, const GLvoid *pixels)
+{
+    if (gl->IsGLES2()) {
+
+        NS_ASSERTION(format == (GLenum)internalformat,
+                    "format and internalformat not the same for glTexImage2D on GLES2");
+
+        if (!gl->CanUploadNonPowerOfTwo()
+            && (stride != width * pixelsize
+            || !gfx::IsPowerOfTwo(width)
+            || !gfx::IsPowerOfTwo(height))) {
+
+            // Pad out texture width and height to the next power of two
+            // as we don't support/want non power of two texture uploads
+            GLsizei paddedWidth = gfx::NextPowerOfTwo(width);
+            GLsizei paddedHeight = gfx::NextPowerOfTwo(height);
+
+            GLvoid* paddedPixels = new unsigned char[paddedWidth * paddedHeight * pixelsize];
+
+            // Pad out texture data to be in a POT sized buffer for uploading to
+            // a POT sized texture
+            CopyAndPadTextureData(pixels, paddedPixels, width, height,
+                                  paddedWidth, paddedHeight, stride, pixelsize);
+
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)paddedPixels),
+                                      GetAddressAlignment((ptrdiff_t)paddedWidth * pixelsize)));
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            paddedWidth,
+                            paddedHeight,
+                            border,
+                            format,
+                            type,
+                            paddedPixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+
+            delete[] static_cast<unsigned char*>(paddedPixels);
+            return;
+        }
+
+        if (stride == width * pixelsize) {
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                             std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                      GetAddressAlignment((ptrdiff_t)stride)));
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            width,
+                            height,
+                            border,
+                            format,
+                            type,
+                            pixels);
+            gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+        } else {
+            // Use GLES-specific workarounds for GL_UNPACK_ROW_LENGTH; these are
+            // implemented in TexSubImage2D.
+            gl->fTexImage2D(target,
+                            border,
+                            internalformat,
+                            width,
+                            height,
+                            border,
+                            format,
+                            type,
+                            nullptr);
+            TexSubImage2DHelper(gl,
+                                target,
+                                level,
+                                0,
+                                0,
+                                width,
+                                height,
+                                stride,
+                                pixelsize,
+                                format,
+                                type,
+                                pixels);
+        }
+    } else {
+        // desktop GL (non-ES) path
+
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                         std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                  GetAddressAlignment((ptrdiff_t)stride)));
+        int rowLength = stride/pixelsize;
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, rowLength);
+        gl->fTexImage2D(target,
+                        level,
+                        internalformat,
+                        width,
+                        height,
+                        border,
+                        format,
+                        type,
+                        pixels);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ROW_LENGTH, 0);
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4);
+    }
+}
+
 SurfaceFormat
 UploadImageDataToTexture(GLContext* gl,
                          unsigned char* aData,
                          int32_t aStride,
                          gfxImageFormat aFormat,
                          const nsIntRegion& aDstRegion,
                          GLuint& aTexture,
                          bool aOverwrite,
@@ -151,39 +442,41 @@ UploadImageDataToTexture(GLContext* gl,
         // within the region and adjust the data pointer accordingly.
         unsigned char *rectData =
             aData + DataOffset(iterRect->TopLeft() - topLeft, aStride, aFormat);
 
         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 && gl->CanUploadSubTextures()) {
-            gl->TexSubImage2D(aTextureTarget,
-                              0,
-                              iterRect->x,
-                              iterRect->y,
-                              iterRect->width,
-                              iterRect->height,
-                              aStride,
-                              pixelSize,
-                              format,
-                              type,
-                              rectData);
+            TexSubImage2DHelper(gl,
+                                aTextureTarget,
+                                0,
+                                iterRect->x,
+                                iterRect->y,
+                                iterRect->width,
+                                iterRect->height,
+                                aStride,
+                                pixelSize,
+                                format,
+                                type,
+                                rectData);
         } else {
-            gl->TexImage2D(aTextureTarget,
-                           0,
-                           internalFormat,
-                           iterRect->width,
-                           iterRect->height,
-                           aStride,
-                           pixelSize,
-                           0,
-                           format,
-                           type,
-                          rectData);
+            TexImage2DHelper(gl,
+                             aTextureTarget,
+                             0,
+                             internalFormat,
+                             iterRect->width,
+                             iterRect->height,
+                             aStride,
+                             pixelSize,
+                             0,
+                             format,
+                             type,
+                             rectData);
         }
 
     }
 
     return surfaceFormat;
 }
 
 SurfaceFormat