Bug 948002 - Fix WebGL framebuffer completeness checks. r=bjacob
authorDan Glastonbury <dglastonbury@mozilla.com>
Fri, 24 Jan 2014 13:53:53 +1000
changeset 165605 2b636fd22dd76cb1df680f968b591514a323769f
parent 165604 cfeec70c1b29b69c030e8d95030d6e65766422c1
child 165606 56af0a9846fd5698ac8e03f023333e94e650d797
push id4623
push userryanvm@gmail.com
push dateTue, 28 Jan 2014 21:48:39 +0000
treeherderfx-team@7e79536aca0a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs948002
milestone29.0a1
Bug 948002 - Fix WebGL framebuffer completeness checks. r=bjacob When changing WebGLTexture::ImageInfo to consistently store GL internal format instead of format, code that checked for depth textures broke because general depth component format type was being checked instead of the sized formats. With :bjacob, we audited the locations of the checks and updated the code to accept the internal formats by utilizing helper functions that check the GLenum.
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextUtils.cpp
content/canvas/src/WebGLContextUtils.h
content/canvas/src/WebGLFramebuffer.cpp
content/canvas/src/WebGLTexelConversions.h
content/canvas/src/WebGLTexture.cpp
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -633,40 +633,42 @@ WebGLContext::CopyTexSubImage2D(GLenum t
     GLsizei texHeight = imageInfo.Height();
 
     if (xoffset + width > texWidth || xoffset + width < 0)
       return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
 
     if (yoffset + height > texHeight || yoffset + height < 0)
       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
 
-    GLenum format = imageInfo.InternalFormat();
-    bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
-                                  format == LOCAL_GL_ALPHA ||
-                                  format == LOCAL_GL_LUMINANCE_ALPHA;
+    GLenum internalFormat = imageInfo.InternalFormat();
+    bool texFormatRequiresAlpha = (internalFormat == LOCAL_GL_RGBA ||
+                                   internalFormat == LOCAL_GL_ALPHA ||
+                                   internalFormat == LOCAL_GL_LUMINANCE_ALPHA);
     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
                                                : bool(gl->GetPixelFormat().alpha > 0);
 
     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
                                      "but the framebuffer doesn't have one");
 
-    if (format == LOCAL_GL_DEPTH_COMPONENT ||
-        format == LOCAL_GL_DEPTH_STENCIL)
+    if (IsGLDepthFormat(internalFormat) ||
+        IsGLDepthStencilFormat(internalFormat))
+    {
         return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+    }
 
     if (mBoundFramebuffer)
         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
 
     if (imageInfo.HasUninitializedImageData()) {
         tex->DoDeferredImageInitialization(target, level);
     }
 
-    return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
+    return CopyTexSubImage2D_base(target, level, internalFormat, xoffset, yoffset, x, y, width, height, true);
 }
 
 
 already_AddRefed<WebGLProgram>
 WebGLContext::CreateProgram()
 {
     if (IsContextLost())
         return nullptr;
@@ -1177,25 +1179,27 @@ WebGLContext::GenerateMipmap(GLenum targ
     if (!tex->HasImageInfoAt(imageTarget, 0))
     {
         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
     }
 
     if (!tex->IsFirstImagePowerOfTwo())
         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
 
-    GLenum format = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
-    if (IsTextureFormatCompressed(format))
+    GLenum internalFormat = tex->ImageInfoAt(imageTarget, 0).InternalFormat();
+    if (IsTextureFormatCompressed(internalFormat))
         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
 
     if (IsExtensionEnabled(WEBGL_depth_texture) &&
-        (format == LOCAL_GL_DEPTH_COMPONENT || format == LOCAL_GL_DEPTH_STENCIL))
+        (IsGLDepthFormat(internalFormat) || IsGLDepthStencilFormat(internalFormat)))
+    {
         return ErrorInvalidOperation("generateMipmap: "
                                      "A texture that has a base internal format of "
                                      "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
+    }
 
     if (!tex->AreAllLevel0ImageInfosEqual())
         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
 
     tex->SetGeneratedMipmap();
 
     MakeContextCurrent();
 
@@ -4120,87 +4124,103 @@ BaseTypeAndSizeFromUniformType(GLenum uT
         default:
             return false;
     }
 
     return true;
 }
 
 
-WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum format, GLenum type)
+WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum internalformat, GLenum type)
 {
     //
     // WEBGL_depth_texture
-    if (format == LOCAL_GL_DEPTH_COMPONENT) {
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
         switch (type) {
             case LOCAL_GL_UNSIGNED_SHORT:
                 return WebGLTexelFormat::D16;
             case LOCAL_GL_UNSIGNED_INT:
                 return WebGLTexelFormat::D32;
-            default:
-                MOZ_CRASH("Invalid WebGL texture format/type?");
         }
-    } else if (format == LOCAL_GL_DEPTH_STENCIL) {
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
         switch (type) {
             case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
                 return WebGLTexelFormat::D24S8;
-            default:
-                MOZ_CRASH("Invalid WebGL texture format/type?");
         }
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
     }
 
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
+        return WebGLTexelFormat::D16;
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
+        return WebGLTexelFormat::D32;
+    }
+
+    if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
+        return WebGLTexelFormat::D24S8;
+    }
 
     if (type == LOCAL_GL_UNSIGNED_BYTE) {
-        switch (format) {
+        switch (internalformat) {
             case LOCAL_GL_RGBA:
             case LOCAL_GL_SRGB_ALPHA_EXT:
                 return WebGLTexelFormat::RGBA8;
             case LOCAL_GL_RGB:
             case LOCAL_GL_SRGB_EXT:
                 return WebGLTexelFormat::RGB8;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelFormat::A8;
             case LOCAL_GL_LUMINANCE:
                 return WebGLTexelFormat::R8;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return WebGLTexelFormat::RA8;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
         }
-    } else if (type == LOCAL_GL_FLOAT) {
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
+    }
+
+    if (type == LOCAL_GL_FLOAT) {
         // OES_texture_float
-        switch (format) {
+        switch (internalformat) {
             case LOCAL_GL_RGBA:
+            case LOCAL_GL_RGBA32F:
                 return WebGLTexelFormat::RGBA32F;
             case LOCAL_GL_RGB:
                 return WebGLTexelFormat::RGB32F;
             case LOCAL_GL_ALPHA:
                 return WebGLTexelFormat::A32F;
             case LOCAL_GL_LUMINANCE:
                 return WebGLTexelFormat::R32F;
             case LOCAL_GL_LUMINANCE_ALPHA:
                 return WebGLTexelFormat::RA32F;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
         }
-    } else {
-        switch (type) {
-            case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-                return WebGLTexelFormat::RGBA4444;
-            case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-                return WebGLTexelFormat::RGBA5551;
-            case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-                return WebGLTexelFormat::RGB565;
-            default:
-                MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
-                return WebGLTexelFormat::BadFormat;
-        }
+
+        MOZ_CRASH("Invalid WebGL texture format/type?");
     }
+
+    switch (type) {
+        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+           return WebGLTexelFormat::RGBA4444;
+        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+           return WebGLTexelFormat::RGBA5551;
+        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+           return WebGLTexelFormat::RGB565;
+        default:
+            MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
+            return WebGLTexelFormat::BadFormat;
+    }
+
+    MOZ_CRASH("Invalid WebGL texture format/type?");
 }
 
 GLenum
 InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2)
 {
     // ES2 requires that format == internalformat; floating-point is
     // indicated purely by the type that's loaded.  For desktop GL, we
     // have to specify a floating point internal format.
--- a/content/canvas/src/WebGLContextUtils.cpp
+++ b/content/canvas/src/WebGLContextUtils.cpp
@@ -18,16 +18,35 @@
 
 #include "nsIDOMEvent.h"
 #include "nsIDOMDataContainerEvent.h"
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
 
+namespace mozilla {
+
+bool
+IsGLDepthFormat(GLenum internalFormat)
+{
+    return (internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
+            internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
+            internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+}
+
+bool
+IsGLDepthStencilFormat(GLenum internalFormat)
+{
+    return (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
+            internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+}
+
+} // namespace mozilla
+
 void
 WebGLContext::GenerateWarning(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
 
     GenerateWarning(fmt, ap);
 
@@ -192,42 +211,32 @@ WebGLContext::ErrorName(GLenum error)
             MOZ_ASSERT(false);
             return "[unknown WebGL error!]";
     }
 }
 
 bool
 WebGLContext::IsTextureFormatCompressed(GLenum format)
 {
-    switch(format) {
-        case LOCAL_GL_RGB:
-        case LOCAL_GL_RGBA:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-        case LOCAL_GL_LUMINANCE_ALPHA:
-        case LOCAL_GL_DEPTH_COMPONENT:
-        case LOCAL_GL_DEPTH_STENCIL:
-            return false;
-
+    switch (format) {
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
         case LOCAL_GL_ATC_RGB:
         case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
         case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
         case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
         case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
             return true;
+        default:
+            return false;
     }
-
-    MOZ_ASSERT(false, "Invalid WebGL texture format?");
-    return false;
 }
 
 void
 WebGLContext::UpdateWebGLErrorAndClearGLError(GLenum *currentGLError)
 {
     // get and clear GL error in ALL cases
     GLenum error = gl->GetAndClearError();
     if (currentGLError)
--- a/content/canvas/src/WebGLContextUtils.h
+++ b/content/canvas/src/WebGLContextUtils.h
@@ -7,16 +7,19 @@
 #define WEBGLCONTEXTUTILS_H_
 
 #include "WebGLContext.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/BindingUtils.h"
 
 namespace mozilla {
 
+bool IsGLDepthFormat(GLenum internalFormat);
+bool IsGLDepthStencilFormat(GLenum internalFormat);
+
 template <typename WebGLObjectType>
 JS::Value
 WebGLContext::WebGLObjectAsJSValue(JSContext *cx, const WebGLObjectType *object, ErrorResult& rv) const
 {
     if (!object) {
         return JS::NullValue();
     }
     MOZ_ASSERT(this == object->Context());
--- a/content/canvas/src/WebGLFramebuffer.cpp
+++ b/content/canvas/src/WebGLFramebuffer.cpp
@@ -123,34 +123,73 @@ WebGLFramebuffer::Attachment::RectangleO
     } else if (Renderbuffer()) {
         return *Renderbuffer();
     }
 
     MOZ_CRASH("Should not get here.");
 }
 
 static inline bool
-IsValidAttachedTextureColorFormat(GLenum format)
+IsValidFBOTextureColorFormat(GLenum internalFormat)
 {
     return (
         /* linear 8-bit formats */
-        format == LOCAL_GL_ALPHA ||
-        format == LOCAL_GL_LUMINANCE ||
-        format == LOCAL_GL_LUMINANCE_ALPHA ||
-        format == LOCAL_GL_RGB ||
-        format == LOCAL_GL_RGBA ||
+        internalFormat == LOCAL_GL_ALPHA ||
+        internalFormat == LOCAL_GL_LUMINANCE ||
+        internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
+        internalFormat == LOCAL_GL_RGB ||
+        internalFormat == LOCAL_GL_RGBA ||
         /* sRGB 8-bit formats */
-        format == LOCAL_GL_SRGB_EXT ||
-        format == LOCAL_GL_SRGB_ALPHA_EXT ||
+        internalFormat == LOCAL_GL_SRGB_EXT ||
+        internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
         /* linear float32 formats */
-        format ==  LOCAL_GL_ALPHA32F_ARB ||
-        format ==  LOCAL_GL_LUMINANCE32F_ARB ||
-        format ==  LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
-        format ==  LOCAL_GL_RGB32F_ARB ||
-        format ==  LOCAL_GL_RGBA32F_ARB);
+        internalFormat == LOCAL_GL_ALPHA32F_ARB ||
+        internalFormat == LOCAL_GL_LUMINANCE32F_ARB ||
+        internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
+        internalFormat == LOCAL_GL_RGB32F_ARB ||
+        internalFormat == LOCAL_GL_RGBA32F_ARB);
+}
+
+static inline bool
+IsValidFBOTextureDepthFormat(GLenum internalFormat) {
+    return (
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
+        internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
+}
+
+static inline bool
+IsValidFBOTextureDepthStencilFormat(GLenum internalFormat) {
+    return (
+        internalFormat == LOCAL_GL_DEPTH_STENCIL ||
+        internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
+}
+
+static inline bool
+IsValidFBORenderbufferColorFormat(GLenum internalFormat) {
+    return (
+        internalFormat == LOCAL_GL_RGB565 ||
+        internalFormat == LOCAL_GL_RGB5_A1 ||
+        internalFormat == LOCAL_GL_RGBA4 ||
+        internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT);
+}
+
+static inline bool
+IsValidFBORenderbufferDepthFormat(GLenum internalFormat) {
+    return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
+}
+
+static inline bool
+IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat) {
+    return internalFormat == LOCAL_GL_DEPTH24_STENCIL8;
+}
+
+static inline bool
+IsValidFBORenderbufferStencilFormat(GLenum internalFormat) {
+    return internalFormat == LOCAL_GL_STENCIL_INDEX8;
 }
 
 bool
 WebGLFramebuffer::Attachment::IsComplete() const
 {
     if (!HasImage())
         return false;
 
@@ -159,47 +198,53 @@ WebGLFramebuffer::Attachment::IsComplete
     if (!rect.Width() ||
         !rect.Height())
     {
         return false;
     }
 
     if (mTexturePtr) {
         MOZ_ASSERT(mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
-        GLenum format = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat();
+        const WebGLTexture::ImageInfo& imageInfo =
+            mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel);
+        GLenum internalFormat = imageInfo.InternalFormat();
+
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
+            return IsValidFBOTextureDepthFormat(internalFormat);
 
-        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_COMPONENT;
-        } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_STENCIL;
-        } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-                   mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+            return IsValidFBOTextureDepthStencilFormat(internalFormat);
+
+        if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
+                                      WebGLContext::sMaxColorAttachments))
         {
-            return IsValidAttachedTextureColorFormat(format);
+            return IsValidFBOTextureColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     if (mRenderbufferPtr) {
-        GLenum format = mRenderbufferPtr->InternalFormat();
+        GLenum internalFormat = mRenderbufferPtr->InternalFormat();
+
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
+            return IsValidFBORenderbufferDepthFormat(internalFormat);
+
+        if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
+            return IsValidFBORenderbufferStencilFormat(internalFormat);
 
-        if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_COMPONENT16;
-        } else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_STENCIL_INDEX8;
-        } else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
-            return format == LOCAL_GL_DEPTH_STENCIL;
-        } else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
-                   mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
+        if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
+            return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
+
+        if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
+            mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
+                                      WebGLContext::sMaxColorAttachments))
         {
-            return format == LOCAL_GL_RGB565 ||
-                   format == LOCAL_GL_RGB5_A1 ||
-                   format == LOCAL_GL_RGBA4 ||
-                   format == LOCAL_GL_SRGB8_ALPHA8_EXT;
+            return IsValidFBORenderbufferColorFormat(internalFormat);
         }
         MOZ_ASSERT(false, "Invalid WebGL attachment point?");
         return false;
     }
 
     MOZ_ASSERT(false, "Should not get here.");
     return false;
 }
--- a/content/canvas/src/WebGLTexelConversions.h
+++ b/content/canvas/src/WebGLTexelConversions.h
@@ -90,16 +90,43 @@ template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLT
 struct IntermediateFormat
 {
     static const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Value
         = IsFloatFormat<Format>::Value
           ? WebGLTexelFormat::RGBA32F
           : WebGLTexelFormat::RGBA8;
 };
 
+inline GLenum
+GLFormatForTexelFormat(WebGLTexelFormat format) {
+    switch (format) {
+        case WebGLTexelFormat::R8:          return LOCAL_GL_LUMINANCE;
+        case WebGLTexelFormat::A8:          return LOCAL_GL_ALPHA;
+        case WebGLTexelFormat::RA8:         return LOCAL_GL_LUMINANCE_ALPHA;
+        case WebGLTexelFormat::RGBA5551:    return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::RGBA4444:    return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::RGB565:      return LOCAL_GL_RGB;
+        case WebGLTexelFormat::D16:         return LOCAL_GL_DEPTH_COMPONENT;
+        case WebGLTexelFormat::RGB8:        return LOCAL_GL_RGB;
+        case WebGLTexelFormat::RGBA8:       return LOCAL_GL_RGBA;
+        case WebGLTexelFormat::BGRA8:       return LOCAL_GL_BGRA;
+        case WebGLTexelFormat::BGRX8:       return LOCAL_GL_BGR;
+        case WebGLTexelFormat::R32F:        return LOCAL_GL_LUMINANCE;
+        case WebGLTexelFormat::A32F:        return LOCAL_GL_ALPHA;
+        case WebGLTexelFormat::D32:         return LOCAL_GL_DEPTH_COMPONENT;
+        case WebGLTexelFormat::D24S8:       return LOCAL_GL_DEPTH_STENCIL;
+        case WebGLTexelFormat::RA32F:       return LOCAL_GL_LUMINANCE_ALPHA;
+        case WebGLTexelFormat::RGB32F:      return LOCAL_GL_RGB;
+        case WebGLTexelFormat::RGBA32F:     return LOCAL_GL_RGBA;
+        default:
+            MOZ_CRASH("Unknown texel format. Coding mistake?");
+            return LOCAL_GL_INVALID_ENUM;
+    }
+}
+
 inline size_t TexelBytesForFormat(WebGLTexelFormat format) {
     switch (format) {
         case WebGLTexelFormat::R8:
         case WebGLTexelFormat::A8:
             return 1;
         case WebGLTexelFormat::RA8:
         case WebGLTexelFormat::RGBA5551:
         case WebGLTexelFormat::RGBA4444:
--- a/content/canvas/src/WebGLTexture.cpp
+++ b/content/canvas/src/WebGLTexture.cpp
@@ -425,20 +425,21 @@ WebGLTexture::DoDeferredImageInitializat
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
                         texelsize,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
     void *zeros = calloc(1, checked_byteLength.value());
 
+    GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
     mContext->UpdateWebGLErrorAndClearGLError();
     mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
                               imageInfo.mWidth, imageInfo.mHeight,
-                              0, imageInfo.mInternalFormat, imageInfo.mType,
+                              0, format, imageInfo.mType,
                               zeros);
     GLenum error = LOCAL_GL_NO_ERROR;
     mContext->UpdateWebGLErrorAndClearGLError(&error);
 
     free(zeros);
     SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
 
     if (error) {