Bug 1324312 - Handle alloc failure when uploading texture. r?sotaro draft
authorJamie Nicol <jnicol@mozilla.com>
Mon, 23 Jan 2017 20:00:05 +0000
changeset 465664 7fde5686244daf3a0d909cbee70880dbf6d78988
parent 465527 8ff550409e1d1f8b54f6f7f115545dbef857be0b
child 543210 884b271875e4179ec4c122e855d50d667b0d8809
push id42666
push userbmo:jnicol@mozilla.com
push dateTue, 24 Jan 2017 16:43:06 +0000
reviewerssotaro
bugs1324312
milestone54.0a1
Bug 1324312 - Handle alloc failure when uploading texture. r?sotaro When GL_UNPACK_ROW_LENGTH is not supported and the source data has a different stride to that of the texture (often because we are uploading only the modified subimage) we allocate a temporary buffer with the correct stride. This was found to be more efficient than uploading each row of texture data individually. Sometimes allocating the buffer will fail, however. In such cases fall back to uploading the texture row-by-row, rather than aborting. MozReview-Commit-ID: E7LE8nHPE0M
gfx/gl/GLUploadHelpers.cpp
--- a/gfx/gl/GLUploadHelpers.cpp
+++ b/gfx/gl/GLUploadHelpers.cpp
@@ -156,40 +156,62 @@ TexSubImage2DWithoutUnpackSubimage(GLCon
                                    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++) {
+    unsigned char* newPixels = new (fallible) unsigned char[width*height*pixelsize];
+
+    if (newPixels) {
+        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);
 
-    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);
+    } else {
+        // If we did not have sufficient memory for the required
+        // temporary buffer, then fall back to uploading row-by-row.
+        const unsigned char* rowSource = (const unsigned char*)pixels;
+
+        gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
+                         std::min(GetAddressAlignment((ptrdiff_t)pixels),
+                                  GetAddressAlignment((ptrdiff_t)stride)));
+
+        for (int i = 0; i < height; i++) {
+            gl->fTexSubImage2D(target, level,
+                               xoffset, yoffset + i,
+                               width, 1,
+                               format, type, rowSource);
+            rowSource += stride;
+        }
+
+        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,