Bug 1238865 - Part 2: Add more format/type checks for WebGL2. r=jgilbert
authorMorris Tseng <mtseng@mozilla.com>
Thu, 21 Jan 2016 14:51:59 +0800
changeset 280831 136001a011e82e9a9b5c9cd776f9982e4a41bf39
parent 280830 2cd90b7d3dbd3cbc4759a493da12cfbbb1364c92
child 280832 d556ea474a82901a827c0d9654ed961f8d835ca7
push id70605
push usermtseng@mozilla.com
push dateThu, 21 Jan 2016 06:53:07 +0000
treeherdermozilla-inbound@d556ea474a82 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1238865
milestone46.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 1238865 - Part 2: Add more format/type checks for WebGL2. r=jgilbert
dom/canvas/WebGLContextGL.cpp
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1311,25 +1311,60 @@ WebGLContext::DoReadPixelsAndConvert(GLi
         return true;
     }
 
     gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
     return true;
 }
 
 static bool
-IsFormatAndTypeUnpackable(GLenum format, GLenum type)
+IsFormatAndTypeUnpackable(GLenum format, GLenum type, bool isWebGL2)
 {
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
+        switch (format) {
+        case LOCAL_GL_LUMINANCE:
+        case LOCAL_GL_LUMINANCE_ALPHA:
+            if (!isWebGL2)
+                return false;
+        case LOCAL_GL_ALPHA:
+        case LOCAL_GL_RED:
+        case LOCAL_GL_RED_INTEGER:
+        case LOCAL_GL_RG:
+        case LOCAL_GL_RG_INTEGER:
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGB_INTEGER:
+        case LOCAL_GL_RGBA:
+        case LOCAL_GL_RGBA_INTEGER:
+            return true;
+        default:
+            return false;
+        }
+
+    case LOCAL_GL_BYTE:
+        switch (format) {
+        case LOCAL_GL_RED:
+        case LOCAL_GL_RED_INTEGER:
+        case LOCAL_GL_RG:
+        case LOCAL_GL_RG_INTEGER:
+        case LOCAL_GL_RGB:
+        case LOCAL_GL_RGB_INTEGER:
+        case LOCAL_GL_RGBA:
+        case LOCAL_GL_RGBA_INTEGER:
+            return true;
+        default:
+            return false;
+        }
+
     case LOCAL_GL_FLOAT:
     case LOCAL_GL_HALF_FLOAT:
     case LOCAL_GL_HALF_FLOAT_OES:
         switch (format) {
-        case LOCAL_GL_ALPHA:
+        case LOCAL_GL_RED:
+        case LOCAL_GL_RG:
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
             return true;
         default:
             return false;
         }
 
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
@@ -1343,24 +1378,38 @@ IsFormatAndTypeUnpackable(GLenum format,
         return false;
     }
 }
 
 static bool
 IsIntegerFormatAndTypeUnpackable(GLenum format, GLenum type)
 {
     switch (type) {
+    case LOCAL_GL_UNSIGNED_SHORT:
+    case LOCAL_GL_SHORT:
     case LOCAL_GL_UNSIGNED_INT:
     case LOCAL_GL_INT:
         switch (format) {
+        case LOCAL_GL_RED_INTEGER:
+        case LOCAL_GL_RG_INTEGER:
+        case LOCAL_GL_RGB_INTEGER:
         case LOCAL_GL_RGBA_INTEGER:
             return true;
         default:
             return false;
         }
+
+    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+        return format == LOCAL_GL_RGBA ||
+               format == LOCAL_GL_RGBA_INTEGER;
+
+    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+    case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
+        return format == LOCAL_GL_RGB;
+
     default:
         return false;
     }
 }
 
 
 CheckedUint32
 WebGLContext::GetPackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
@@ -1413,62 +1462,90 @@ WebGLContext::ReadPixels(GLint x, GLint 
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("readPixels: negative size passed");
 
     if (pixels.IsNull())
         return ErrorInvalidValue("readPixels: null destination buffer");
 
     if (!(IsWebGL2() && IsIntegerFormatAndTypeUnpackable(format, type)) &&
-        !IsFormatAndTypeUnpackable(format, type)) {
+        !IsFormatAndTypeUnpackable(format, type, IsWebGL2())) {
         return ErrorInvalidEnum("readPixels: Bad format or type.");
     }
 
     int channels = 0;
 
     // Check the format param
     switch (format) {
     case LOCAL_GL_ALPHA:
+    case LOCAL_GL_LUMINANCE:
+    case LOCAL_GL_RED:
+    case LOCAL_GL_RED_INTEGER:
         channels = 1;
         break;
+    case LOCAL_GL_LUMINANCE_ALPHA:
+    case LOCAL_GL_RG:
+    case LOCAL_GL_RG_INTEGER:
+        channels = 2;
+        break;
     case LOCAL_GL_RGB:
+    case LOCAL_GL_RGB_INTEGER:
         channels = 3;
         break;
     case LOCAL_GL_RGBA:
     case LOCAL_GL_RGBA_INTEGER:
         channels = 4;
         break;
     default:
         MOZ_CRASH("bad `format`");
     }
 
 
     // Check the type param
     int bytesPerPixel;
     int requiredDataType;
     switch (type) {
+    case LOCAL_GL_BYTE:
+        bytesPerPixel = 1*channels;
+        requiredDataType = js::Scalar::Int8;
+        break;
+
     case LOCAL_GL_UNSIGNED_BYTE:
         bytesPerPixel = 1*channels;
         requiredDataType = js::Scalar::Uint8;
         break;
 
+    case LOCAL_GL_SHORT:
+        bytesPerPixel = 2*channels;
+        requiredDataType = js::Scalar::Int16;
+        break;
+
+    case LOCAL_GL_UNSIGNED_SHORT:
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
         bytesPerPixel = 2;
         requiredDataType = js::Scalar::Uint16;
         break;
 
+    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+    case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
+    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
+    case LOCAL_GL_UNSIGNED_INT_24_8:
+        bytesPerPixel = 4;
+        requiredDataType = js::Scalar::Uint32;
+        break;
+
     case LOCAL_GL_UNSIGNED_INT:
-        bytesPerPixel = 4;
+        bytesPerPixel = 4*channels;
         requiredDataType = js::Scalar::Uint32;
         break;
 
     case LOCAL_GL_INT:
-        bytesPerPixel = 4;
+        bytesPerPixel = 4*channels;
         requiredDataType = js::Scalar::Int32;
         break;
 
     case LOCAL_GL_FLOAT:
         bytesPerPixel = 4*channels;
         requiredDataType = js::Scalar::Float32;
         break;
 
@@ -1519,40 +1596,65 @@ WebGLContext::ReadPixels(GLint x, GLint 
     MakeContextCurrent();
 
     const webgl::FormatUsageInfo* srcFormat;
     uint32_t srcWidth;
     uint32_t srcHeight;
     if (!ValidateCurFBForRead("readPixels", &srcFormat, &srcWidth, &srcHeight))
         return;
 
+    // Check the format and type params to assure they are an acceptable pair (as per spec)
     auto srcType = srcFormat->format->componentType;
-    const bool isSrcTypeFloat = (srcType == webgl::ComponentType::Float);
-
-    // Check the format and type params to assure they are an acceptable pair (as per spec)
-
-    const GLenum mainReadFormat = LOCAL_GL_RGBA;
-    const GLenum mainReadType = isSrcTypeFloat ? LOCAL_GL_FLOAT
-                                               : LOCAL_GL_UNSIGNED_BYTE;
+    GLenum mainReadFormat;
+    GLenum mainReadType;
+    switch (srcType) {
+        case webgl::ComponentType::Float:
+            mainReadFormat = LOCAL_GL_RGBA;
+            mainReadType = LOCAL_GL_FLOAT;
+            break;
+        case webgl::ComponentType::UInt:
+            mainReadFormat = LOCAL_GL_RGBA_INTEGER;
+            mainReadType = LOCAL_GL_UNSIGNED_INT;
+            break;
+        case webgl::ComponentType::Int:
+            mainReadFormat = LOCAL_GL_RGBA_INTEGER;
+            mainReadType = LOCAL_GL_INT;
+            break;
+        default:
+            mainReadFormat = LOCAL_GL_RGBA;
+            mainReadType = LOCAL_GL_UNSIGNED_BYTE;
+            break;
+    }
 
     GLenum auxReadFormat = mainReadFormat;
     GLenum auxReadType = mainReadType;
 
     // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
     // combination for glReadPixels().
     if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
         gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
                          reinterpret_cast<GLint*>(&auxReadFormat));
         gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
                          reinterpret_cast<GLint*>(&auxReadType));
     }
 
     const bool mainMatches = (format == mainReadFormat && type == mainReadType);
     const bool auxMatches = (format == auxReadFormat && type == auxReadType);
-    const bool isValid = mainMatches || auxMatches;
+    bool isValid = mainMatches || auxMatches;
+
+    // OpenGL ES 3.0.4 p194 - When the internal format of the rendering surface is
+    // RGB10_A2, a third combination of format RGBA and type UNSIGNED_INT_2_10_10_10_REV
+    // is accepted.
+    if (srcFormat->format->effectiveFormat == webgl::EffectiveFormat::RGB10_A2 &&
+        format == LOCAL_GL_RGBA &&
+        type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV)
+    {
+        isValid = true;
+    }
+
     if (!isValid)
         return ErrorInvalidOperation("readPixels: Invalid format/type pair");
 
     // Now that the errors are out of the way, on to actually reading!
 
     uint32_t readX, readY;
     uint32_t writeX, writeY;
     uint32_t rwWidth, rwHeight;