Remove 'native extensions' from WebGL 2. draft
authorJeff Gilbert <jdashg@gmail.com>
Thu, 17 Dec 2015 16:16:52 -0800
changeset 316089 23c3937dddc34c59ebb7c616d03ab92d69eb3ac2
parent 316088 f66102a05e932beb93ae7cf7315c36300f1a6b22
child 316090 07b1b4dd813bf996ca732b026364460ec8d686bc
push id8514
push userjgilbert@mozilla.com
push dateFri, 18 Dec 2015 00:24:33 +0000
milestone45.0a1
Remove 'native extensions' from WebGL 2.
dom/canvas/WebGL2Context.cpp
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextExtensions.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextState.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertices.cpp
dom/canvas/WebGLExtensionSRGB.cpp
dom/canvas/WebGLShaderValidator.cpp
dom/canvas/WebGLTextureUpload.cpp
gfx/gl/GLContext.h
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -50,25 +50,16 @@ JSObject*
 WebGL2Context::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGL2RenderingContextBinding::Wrap(cx, this, givenProto);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // WebGL 2 initialisation
 
-// These WebGL 1 extensions are natively supported by WebGL 2.
-static const WebGLExtensionID kNativelySupportedExtensions[] = {
-    WebGLExtensionID::ANGLE_instanced_arrays,
-    WebGLExtensionID::EXT_blend_minmax,
-    WebGLExtensionID::OES_element_index_uint,
-    WebGLExtensionID::OES_standard_derivatives,
-    WebGLExtensionID::OES_vertex_array_object
-};
-
 static const gl::GLFeature kRequiredFeatures[] = {
     gl::GLFeature::blend_minmax,
     gl::GLFeature::clear_buffers,
     gl::GLFeature::copy_buffer,
     gl::GLFeature::depth_texture,
     gl::GLFeature::draw_instanced,
     gl::GLFeature::draw_range_elements,
     gl::GLFeature::element_index_uint,
@@ -141,31 +132,31 @@ WebGLContext::InitWebGL2()
             exts.AppendLiteral("\n  ");
             exts.Append(gl::GLContext::GetFeatureName(*itr));
         }
         GenerateWarning("WebGL 2 unavailable. The following required features are"
                         " unavailible: %s", exts.BeginReading());
         return false;
     }
 
-    // ok WebGL 2 is compatible, we can enable natively supported extensions.
-    for (size_t i = 0; i < ArrayLength(kNativelySupportedExtensions); i++) {
-        EnableExtension(kNativelySupportedExtensions[i]);
-
-        MOZ_ASSERT(IsExtensionEnabled(kNativelySupportedExtensions[i]));
-    }
-
     // we initialise WebGL 2 related stuff.
     gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                      &mGLMaxTransformFeedbackSeparateAttribs);
     gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
                      &mGLMaxUniformBufferBindings);
 
     mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs);
     mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings);
 
     mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
     mBoundTransformFeedback = mDefaultTransformFeedback;
 
+    if (!gl->IsGLES()) {
+        // Desktop OpenGL requires the following to be enabled in order to
+        // support sRGB operations on framebuffers.
+        gl->MakeCurrent();
+        gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
+    }
+
     return true;
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -143,20 +143,19 @@ WebGLContext::BindFakeBlack(uint32_t tex
     gl->fActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture);
 }
 
 ////////////////////////////////////////
 
 bool
 WebGLContext::DrawInstanced_check(const char* info)
 {
-    if ((IsWebGL2() ||
-         IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) &&
-        !mBufferFetchingHasPerVertex)
-    {
+    MOZ_ASSERT(IsWebGL2() ||
+               IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays));
+    if (!mBufferFetchingHasPerVertex) {
         /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
          *  If all of the enabled vertex attribute arrays that are bound to active
          *  generic attributes in the program have a non-zero divisor, the draw
          *  call should return INVALID_OPERATION.
          *
          * NB: This also appears to apply to NV_instanced_arrays, though the
          * INVALID_OPERATION emission is not explicitly stated.
          * ARB_instanced_arrays does not have this restriction.
@@ -228,20 +227,16 @@ WebGLContext::DrawArrays_check(GLint fir
     } else {
         ClearBackbufferIfNeeded();
     }
 
     if (!DoFakeVertexAttrib0(checked_firstPlusCount.value())) {
         return false;
     }
 
-    if (!DrawInstanced_check(info)) {
-        return false;
-    }
-
     return true;
 }
 
 void
 WebGLContext::DrawArrays(GLenum mode, GLint first, GLsizei count)
 {
     const char funcName[] = "drawArrays";
     if (IsContextLost())
@@ -281,16 +276,19 @@ WebGLContext::DrawArraysInstanced(GLenum
     bool error;
     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     if (error)
         return;
 
     if (!DrawArrays_check(first, count, primcount, funcName))
         return;
 
+    if (!DrawInstanced_check(funcName))
+        return;
+
     RunContextLossTimer();
 
     {
         ScopedMaskWorkaround autoMask(*this);
         gl->fDrawArraysInstanced(mode, first, count, primcount);
     }
 
     Draw_cleanup(funcName);
@@ -311,49 +309,50 @@ WebGLContext::DrawElements_check(GLsizei
         return false;
     }
 
     if (!ValidateStencilParamsForDrawCall()) {
         return false;
     }
 
     // If count is 0, there's nothing to do.
-    if (count == 0 || primcount == 0) {
+    if (count == 0 || primcount == 0)
+        return false;
+
+    uint8_t bytesPerElem = 0;
+    switch (type) {
+    case LOCAL_GL_UNSIGNED_BYTE:
+        bytesPerElem = 1;
+        break;
+
+    case LOCAL_GL_UNSIGNED_SHORT:
+        bytesPerElem = 2;
+        break;
+
+    case LOCAL_GL_UNSIGNED_INT:
+        if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
+            bytesPerElem = 4;
+        }
+        break;
+    }
+
+    if (!bytesPerElem) {
+        ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type);
         return false;
     }
 
-    CheckedUint32 checked_byteCount;
-
-    GLsizei first = 0;
-
-    if (type == LOCAL_GL_UNSIGNED_SHORT) {
-        checked_byteCount = 2 * CheckedUint32(count);
-        if (byteOffset % 2 != 0) {
-            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info);
-            return false;
-        }
-        first = byteOffset / 2;
-    }
-    else if (type == LOCAL_GL_UNSIGNED_BYTE) {
-        checked_byteCount = count;
-        first = byteOffset;
-    }
-    else if (type == LOCAL_GL_UNSIGNED_INT && IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) {
-        checked_byteCount = 4 * CheckedUint32(count);
-        if (byteOffset % 4 != 0) {
-            ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info);
-            return false;
-        }
-        first = byteOffset / 4;
-    }
-    else {
-        ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info);
+    if (byteOffset % bytesPerElem != 0) {
+        ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`",
+                              info);
         return false;
     }
 
+    const GLsizei first = byteOffset / bytesPerElem;
+    const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count);
+
     if (!checked_byteCount.isValid()) {
         ErrorInvalidValue("%s: overflow in byteCount", info);
         return false;
     }
 
     // Any checks below this depend on a program being available.
     if (!mCurrentProgram) {
         ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info);
@@ -483,16 +482,19 @@ WebGLContext::DrawElementsInstanced(GLen
     ScopedResolveTexturesForDraw scopedResolve(this, funcName, &error);
     if (error)
         return;
 
     GLuint upperBound = 0;
     if (!DrawElements_check(count, type, byteOffset, primcount, funcName, &upperBound))
         return;
 
+    if (!DrawInstanced_check(funcName))
+        return;
+
     RunContextLossTimer();
 
     {
         ScopedMaskWorkaround autoMask(*this);
         gl->fDrawElementsInstanced(mode, count, type,
                                    reinterpret_cast<GLvoid*>(byteOffset),
                                    primcount);
     }
--- a/dom/canvas/WebGLContextExtensions.cpp
+++ b/dom/canvas/WebGLContextExtensions.cpp
@@ -101,56 +101,30 @@ bool WebGLContext::IsExtensionSupported(
 }
 
 bool
 WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
 {
     if (mDisableExtensions)
         return false;
 
-    // In alphabetical order
+    // Extensions for both WebGL 1 and 2.
     switch (ext) {
-    // ANGLE_
-    case WebGLExtensionID::ANGLE_instanced_arrays:
-        return WebGLExtensionInstancedArrays::IsSupported(this);
-
+    // In alphabetical order
     // EXT_
-    case WebGLExtensionID::EXT_blend_minmax:
-        return WebGLExtensionBlendMinMax::IsSupported(this);
     case WebGLExtensionID::EXT_color_buffer_half_float:
         return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
-    case WebGLExtensionID::EXT_frag_depth:
-        return WebGLExtensionFragDepth::IsSupported(this);
-    case WebGLExtensionID::EXT_shader_texture_lod:
-        return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
-    case WebGLExtensionID::EXT_sRGB:
-        return WebGLExtensionSRGB::IsSupported(this);
     case WebGLExtensionID::EXT_texture_filter_anisotropic:
         return gl->IsExtensionSupported(gl::GLContext::EXT_texture_filter_anisotropic);
 
     // OES_
-    case WebGLExtensionID::OES_element_index_uint:
-        return gl->IsSupported(gl::GLFeature::element_index_uint);
-    case WebGLExtensionID::OES_standard_derivatives:
-        return gl->IsSupported(gl::GLFeature::standard_derivatives);
-    case WebGLExtensionID::OES_texture_float:
-        return gl->IsSupported(gl::GLFeature::texture_float);
     case WebGLExtensionID::OES_texture_float_linear:
         return gl->IsSupported(gl::GLFeature::texture_float_linear);
-    case WebGLExtensionID::OES_texture_half_float:
-        // If we have Feature::texture_half_float, we must not be on ES2
-        // and need to translate HALF_FLOAT_OES -> HALF_FLOAT.  We do that
-        // right before making the relevant calls.
-        return gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float) ||
-               gl->IsSupported(gl::GLFeature::texture_half_float);
-
     case WebGLExtensionID::OES_texture_half_float_linear:
         return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
-    case WebGLExtensionID::OES_vertex_array_object:
-        return true;
 
     // WEBGL_
     case WebGLExtensionID::WEBGL_color_buffer_float:
         return WebGLExtensionColorBufferFloat::IsSupported(this);
     case WebGLExtensionID::WEBGL_compressed_texture_atc:
         return gl->IsExtensionSupported(gl::GLContext::AMD_compressed_ATC_texture);
     case WebGLExtensionID::WEBGL_compressed_texture_etc1:
         return gl->IsExtensionSupported(gl::GLContext::OES_compressed_ETC1_RGB8_texture);
@@ -162,42 +136,84 @@ WebGLContext::IsExtensionSupported(WebGL
 
         return gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_dxt1) &&
                gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt3) &&
                gl->IsExtensionSupported(gl::GLContext::ANGLE_texture_compression_dxt5);
 
     case WebGLExtensionID::WEBGL_debug_renderer_info:
         return Preferences::GetBool("webgl.enable-debug-renderer-info", false);
 
-    case WebGLExtensionID::WEBGL_depth_texture:
-        // WEBGL_depth_texture supports DEPTH_STENCIL textures
-        if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
-            return false;
-
-        return gl->IsSupported(gl::GLFeature::depth_texture) ||
-               gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
-    case WebGLExtensionID::WEBGL_draw_buffers:
-        return WebGLExtensionDrawBuffers::IsSupported(this);
     case WebGLExtensionID::WEBGL_lose_context:
         // We always support this extension.
         return true;
 
     default:
         // For warnings-as-errors.
         break;
     }
 
-    if (gfxPrefs::WebGLDraftExtensionsEnabled() || IsWebGL2()) {
+    if (!IsWebGL2()) {
+        // WebGL1-only extensions
         switch (ext) {
-        case WebGLExtensionID::EXT_disjoint_timer_query:
-            return WebGLExtensionDisjointTimerQuery::IsSupported(this);
+        // ANGLE_
+        case WebGLExtensionID::ANGLE_instanced_arrays:
+            return WebGLExtensionInstancedArrays::IsSupported(this);
+
+        // EXT_
+        case WebGLExtensionID::EXT_blend_minmax:
+            return WebGLExtensionBlendMinMax::IsSupported(this);
+        case WebGLExtensionID::EXT_frag_depth:
+            return WebGLExtensionFragDepth::IsSupported(this);
+        case WebGLExtensionID::EXT_shader_texture_lod:
+            return gl->IsExtensionSupported(gl::GLContext::EXT_shader_texture_lod);
+        case WebGLExtensionID::EXT_sRGB:
+            return WebGLExtensionSRGB::IsSupported(this);
+
+        // OES_
+        case WebGLExtensionID::OES_element_index_uint:
+            return gl->IsSupported(gl::GLFeature::element_index_uint);
+        case WebGLExtensionID::OES_standard_derivatives:
+            return gl->IsSupported(gl::GLFeature::standard_derivatives);
+        case WebGLExtensionID::OES_texture_float:
+            return gl->IsSupported(gl::GLFeature::texture_float);
+        case WebGLExtensionID::OES_texture_half_float:
+            // If we have Feature::texture_half_float, we must not be on ES2
+            // and need to translate HALF_FLOAT_OES -> HALF_FLOAT.  We do that
+            // right before making the relevant calls.
+            return gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float) ||
+                   gl->IsSupported(gl::GLFeature::texture_half_float);
+
+        case WebGLExtensionID::OES_vertex_array_object:
+            return true;
+
+        // WEBGL_
+        case WebGLExtensionID::WEBGL_depth_texture:
+            // WEBGL_depth_texture supports DEPTH_STENCIL textures
+            if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil))
+                return false;
+
+            return gl->IsSupported(gl::GLFeature::depth_texture) ||
+                   gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
+        case WebGLExtensionID::WEBGL_draw_buffers:
+            return WebGLExtensionDrawBuffers::IsSupported(this);
         default:
             // For warnings-as-errors.
             break;
         }
+
+        if (gfxPrefs::WebGLDraftExtensionsEnabled()) {
+            switch (ext) {
+            case WebGLExtensionID::EXT_disjoint_timer_query:
+                return WebGLExtensionDisjointTimerQuery::IsSupported(this);
+
+            default:
+                // For warnings-as-errors.
+                break;
+            }
+        }
     }
 
     return false;
 }
 
 static bool
 CompareWebGLExtensionName(const nsACString& name, const char* other)
 {
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -968,23 +968,27 @@ void
 WebGLContext::Hint(GLenum target, GLenum mode)
 {
     if (IsContextLost())
         return;
 
     bool isValid = false;
 
     switch (target) {
-        case LOCAL_GL_GENERATE_MIPMAP_HINT:
+    case LOCAL_GL_GENERATE_MIPMAP_HINT:
+        isValid = true;
+        break;
+
+    case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
+        if (IsWebGL2() ||
+            IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
+        {
             isValid = true;
-            break;
-        case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
-            if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
-                isValid = true;
-            break;
+        }
+        break;
     }
 
     if (!isValid)
         return ErrorInvalidEnum("hint: invalid hint");
 
     MakeContextCurrent();
     gl->fHint(target, mode);
 }
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -161,25 +161,25 @@ WebGLContext::GetParameter(JSContext* cx
             const GLint index = (pname - LOCAL_GL_DRAW_BUFFER0);
             if (iv == LOCAL_GL_COLOR_ATTACHMENT0 + index)
                 return JS::Int32Value(LOCAL_GL_BACK);
 
             return JS::Int32Value(LOCAL_GL_NONE);
         }
     }
 
-    if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
         if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
             WebGLVertexArray* vao =
                 (mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
             return WebGLObjectAsJSValue(cx, vao, rv);
         }
     }
 
-    if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
         if (pname == LOCAL_GL_TIMESTAMP_EXT) {
             GLuint64 iv = 0;
             gl->fGetInteger64v(pname, (GLint64*) &iv);
             // TODO: JS doesn't support 64-bit integers. Be lossy and
             // cast to double (53 bits)
             return JS::NumberValue(static_cast<double>(iv));
         } else if (pname == LOCAL_GL_GPU_DISJOINT_EXT) {
             // When disjoint isn't supported, leave as false.
@@ -230,17 +230,17 @@ WebGLContext::GetParameter(JSContext* cx
                     hasRetVal = true;
                 }
 
                 return StringValue(cx, ret, rv);
             }
         }
     }
 
-    if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
         if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::Int32Value(i);
         }
     }
 
     if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -680,17 +680,17 @@ AssertUintParamCorrect(gl::GLContext*, G
 void
 WebGLContext::AssertCachedBindings()
 {
 #ifdef DEBUG
     MakeContextCurrent();
 
     GetAndFlushUnderlyingGLErrors();
 
-    if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
         GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
         AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
     }
 
     // Bound object state
     if (IsWebGL2()) {
         GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
                                              : 0;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -41,18 +41,21 @@ WebGLContext::ValidateBlendEquationEnum(
     switch (mode) {
     case LOCAL_GL_FUNC_ADD:
     case LOCAL_GL_FUNC_SUBTRACT:
     case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
         return true;
 
     case LOCAL_GL_MIN:
     case LOCAL_GL_MAX:
-        if (IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax))
+        if (IsWebGL2() ||
+            IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax))
+        {
             return true;
+        }
 
         break;
 
     default:
         break;
     }
 
     ErrorInvalidEnumInfo(info, mode);
--- a/dom/canvas/WebGLContextVertices.cpp
+++ b/dom/canvas/WebGLContextVertices.cpp
@@ -353,18 +353,21 @@ WebGLContext::GetVertexAttrib(JSContext*
 
     case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
         if (!mBoundVertexArray->mAttribs[index].enabled)
             return JS::NumberValue(uint32_t(LOCAL_GL_FLOAT));
 
         return JS::NumberValue(uint32_t(mBoundVertexArray->mAttribs[index].type));
 
     case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
-        if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
+        if (IsWebGL2() ||
+            IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
+        {
             return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor);
+        }
         break;
 
     case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
         {
             JS::RootedObject obj(cx);
             switch (mVertexAttribType[index]) {
             case LOCAL_GL_FLOAT:
                 obj = GetVertexAttribFloat32Array(cx, index);
--- a/dom/canvas/WebGLExtensionSRGB.cpp
+++ b/dom/canvas/WebGLExtensionSRGB.cpp
@@ -22,30 +22,34 @@ WebGLExtensionSRGB::WebGLExtensionSRGB(W
         // Desktop OpenGL requires the following to be enabled in order to
         // support sRGB operations on framebuffers.
         gl->MakeCurrent();
         gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
     }
 
     auto& fua = webgl->mFormatUsage;
 
-    const auto fnAdd = [&fua](webgl::EffectiveFormat effFormat, GLenum unpackFormat)
+    const auto fnAdd = [&fua, gl](webgl::EffectiveFormat effFormat, GLenum format,
+                                  GLenum desktopUnpackFormat)
     {
         auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8);
         usage->isFilterable = true;
 
-        const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat,
-                                             LOCAL_GL_UNSIGNED_BYTE};
+        webgl::DriverUnpackInfo dui = {format, format, LOCAL_GL_UNSIGNED_BYTE};
         const auto pi = dui.ToPacking();
+
+        if (!gl->IsGLES())
+            dui.unpackFormat = desktopUnpackFormat;
+
         fua->AddUnsizedTexFormat(pi, usage);
         usage->AddUnpack(pi, dui);
     };
 
-    fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB);
-    fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA);
+    fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB, LOCAL_GL_RGB);
+    fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA, LOCAL_GL_RGBA);
 
     auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
     usage->isRenderable = true;
     fua->AddRBFormat(LOCAL_GL_SRGB8_ALPHA8, usage);
 }
 
 WebGLExtensionSRGB::~WebGLExtensionSRGB()
 {
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -113,26 +113,26 @@ WebGLContext::CreateShaderValidator(GLen
     resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
     resources.MaxVaryingVectors = mGLMaxVaryingVectors;
     resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
     resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
     resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
     resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
     resources.MaxDrawBuffers = mGLMaxDrawBuffers;
 
-    if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
         resources.EXT_frag_depth = 1;
 
-    if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
         resources.OES_standard_derivatives = 1;
 
-    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
         resources.EXT_draw_buffers = 1;
 
-    if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
+    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
         resources.EXT_shader_texture_lod = 1;
 
     // Tell ANGLE to allow highp in frag shaders. (unless disabled)
     // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
     resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
 
     if (gl->WorkAroundDriverBugs()) {
 #ifdef XP_MACOSX
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -1144,17 +1144,17 @@ WebGLTexture::TexImage(const char* funcN
 
     if (glError == LOCAL_GL_OUT_OF_MEMORY) {
         mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.",
                                    funcName);
         return;
     }
 
     if (glError) {
-        mContext->ErrorInvalidOperation("%s: Unexpected error during upload: 0x04x",
+        mContext->ErrorInvalidOperation("%s: Unexpected error during upload: 0x%04x",
                                         funcName, glError);
         MOZ_ASSERT(false, "Unexpected GL error.");
         return;
     }
 
     ////////////////////////////////////
     // Update our specification data.
 
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -642,17 +642,21 @@ public:
             mOldTop = mGL.mTopError;
             mGL.mTopError = LOCAL_GL_NO_ERROR;
         }
 
         GLenum GetError() {
             MOZ_ASSERT(!mHasBeenChecked);
             mHasBeenChecked = true;
 
-            return mGL.fGetError();
+            const GLenum ret = mGL.fGetError();
+
+            while (mGL.fGetError()) {}
+
+            return ret;
         }
 
         ~LocalErrorScope() {
             MOZ_ASSERT(mHasBeenChecked);
 
             MOZ_ASSERT(mGL.fGetError() == LOCAL_GL_NO_ERROR);
 
             MOZ_ASSERT(mGL.mLocalErrorScopeStack.top() == this);