Bug 1081125 - WebGL2 3D textures - Part 1: add WebGLTexDimensions enum instead of using plain ints to distinguish between 2D and 3D calls - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Mon, 13 Oct 2014 19:42:15 -0400
changeset 210267 25a2488b32d783ed714d98de02a8477230037d47
parent 210266 5383ac93d36d06385287be8e15f6bd632ba67783
child 210268 191b4351c850c480dc62467cf593c8a23f2eb3e9
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjgilbert
bugs1081125
milestone35.0a1
Bug 1081125 - WebGL2 3D textures - Part 1: add WebGLTexDimensions enum instead of using plain ints to distinguish between 2D and 3D calls - r=jgilbert
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLContextUtils.h
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLTypes.h
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1767,18 +1767,21 @@ WebGLContext::DidRefresh()
 bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level,
                               GLenum internalformat, GLenum format, GLenum type,
                               mozilla::dom::Element& elt)
 {
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
-    if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageFormatAndType(format, type,
+                                       WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
+    {
         return false;
+    }
 
     HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
     if (!video) {
         return false;
     }
 
     uint16_t readyState;
     if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -478,20 +478,22 @@ public:
     template<class ElementType>
     void TexImage2D(GLenum rawTexImgTarget, GLint level,
                     GLenum internalformat, GLenum format, GLenum type,
                     ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        auto dims = 2;
-
-        if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
+        if (!ValidateTexImageTarget(rawTexImgTarget,
+                                    WebGLTexImageFunc::TexImage,
+                                    WebGLTexDimensions::Tex2D))
+        {
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
+        }
 
         const TexImageTarget texImageTarget(rawTexImgTarget);
 
         if (level < 0)
             return ErrorInvalidValue("texImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
@@ -547,18 +549,19 @@ public:
                        GLint xoffset, GLint yoffset,
                        GLenum format,
                        GLenum type,
                        ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        if (!ValidateTexImageTarget(2, rawTexImageTarget,
-                                    WebGLTexImageFunc::TexSubImage))
+        if (!ValidateTexImageTarget(rawTexImageTarget,
+                                    WebGLTexImageFunc::TexSubImage,
+                                    WebGLTexDimensions::Tex2D))
         {
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
         }
 
         const TexImageTarget texImageTarget(rawTexImageTarget);
 
         if (level < 0)
             return ErrorInvalidValue("texSubImage2D: level is negative");
@@ -1093,60 +1096,77 @@ protected:
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char *info);
     bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info);
     bool ValidateTextureTargetEnum(GLenum target, const char *info);
     bool ValidateComparisonEnum(GLenum target, const char *info);
     bool ValidateStencilOpEnum(GLenum action, const char *info);
     bool ValidateFaceEnum(GLenum face, const char *info);
     bool ValidateTexInputData(GLenum type,
                               js::Scalar::Type jsArrayType,
-                              WebGLTexImageFunc func);
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char *info);
     bool ValidateAttribIndex(GLuint index, const char *info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
     bool ValidateCopyTexImage(GLenum internalformat,
-                              WebGLTexImageFunc func);
-    bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
+    bool ValidateTexImage(TexImageTarget texImageTarget,
                           GLint level, GLenum internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
                           GLint border, GLenum format, GLenum type,
-                          WebGLTexImageFunc func);
-    bool ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func);
+                          WebGLTexImageFunc func,
+                          WebGLTexDimensions dims);
+    bool ValidateTexImageTarget(GLenum target,
+                                WebGLTexImageFunc func,
+                                WebGLTexDimensions dims);
     bool ValidateTexImageFormat(GLenum internalformat,
-                                WebGLTexImageFunc func);
-    bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func);
-    bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func);
+                                WebGLTexImageFunc func,
+                                WebGLTexDimensions dims);
+    bool ValidateTexImageType(GLenum type,
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
+    bool ValidateTexImageFormatAndType(GLenum format,
+                                       GLenum type,
+                                       WebGLTexImageFunc func,
+                                       WebGLTexDimensions dims);
     bool ValidateCompTexImageInternalFormat(GLenum format,
-                                            WebGLTexImageFunc func);
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims);
     bool ValidateCopyTexImageInternalFormat(GLenum format,
-                                            WebGLTexImageFunc func);
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims);
     bool ValidateTexImageSize(TexImageTarget target, GLint level,
                               GLint width, GLint height, GLint depth,
-                              WebGLTexImageFunc func);
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
     bool ValidateTexSubImageSize(GLint x, GLint y, GLint z,
                                  GLsizei width, GLsizei height, GLsizei depth,
                                  GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth,
-                                 WebGLTexImageFunc func);
-
+                                 WebGLTexImageFunc func,
+                                 WebGLTexDimensions dims);
     bool ValidateCompTexImageSize(GLint level,
                                   GLenum internalformat,
                                   GLint xoffset, GLint yoffset,
                                   GLsizei width, GLsizei height,
                                   GLsizei levelWidth, GLsizei levelHeight,
-                                  WebGLTexImageFunc func);
+                                  WebGLTexImageFunc func,
+                                  WebGLTexDimensions dims);
     bool ValidateCompTexImageDataSize(GLint level,
                                       GLenum internalformat,
                                       GLsizei width, GLsizei height,
-                                      uint32_t byteLength, WebGLTexImageFunc func);
+                                      uint32_t byteLength,
+                                      WebGLTexImageFunc func,
+                                      WebGLTexDimensions dims);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -363,32 +363,35 @@ WebGLContext::CopyTexSubImage2D_base(Tex
                                      GLsizei width,
                                      GLsizei height,
                                      bool sub)
 {
     const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
-    const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
-    WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
+    WebGLTexImageFunc func = sub
+                             ? WebGLTexImageFunc::CopyTexSubImage
+                             : WebGLTexImageFunc::CopyTexImage;
+    WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+    const char* info = InfoFrom(func, dims);
 
     // TODO: This changes with color_buffer_float. Reassess when the
     // patch lands.
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
+    if (!ValidateTexImage(texImageTarget, level, internalformat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0,
                           LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
-    if (!ValidateCopyTexImage(internalformat.get(), func))
+    if (!ValidateCopyTexImage(internalformat.get(), func, dims))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     MakeContextCurrent();
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -495,30 +498,31 @@ WebGLContext::CopyTexImage2D(GLenum rawT
                              GLsizei height,
                              GLint border)
 {
     if (IsContextLost())
         return;
 
     // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
     const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
+    if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
                           border, LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
-    if (!ValidateCopyTexImage(internalformat, func))
+    if (!ValidateCopyTexImage(internalformat, func, dims))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
 }
 
@@ -3305,37 +3309,38 @@ WebGLContext::CompressedTexImage2D(GLenu
                                    GLenum internalformat,
                                    GLsizei width, GLsizei height, GLint border,
                                    const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
+    if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
                           0, 0, 0, width, height, 0,
                           border, LOCAL_GL_NONE,
                           LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func)) {
+    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims)) {
         return;
     }
 
-    if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func))
+    if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func, dims))
     {
         return;
     }
 
     const TexImageTarget texImageTarget(rawTexImgTarget);
 
     WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
@@ -3357,26 +3362,27 @@ WebGLContext::CompressedTexSubImage2D(GL
                                       GLint yoffset, GLsizei width, GLsizei height,
                                       GLenum internalformat,
                                       const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexSubImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget,
+    if (!ValidateTexImage(rawTexImgTarget,
                           level, internalformat,
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
     const TexImageTarget texImageTarget(rawTexImgTarget);
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
@@ -3384,24 +3390,24 @@ WebGLContext::CompressedTexSubImage2D(GL
 
     if (internalformat != levelInfo.EffectiveInternalFormat()) {
         return ErrorInvalidOperation("compressedTexImage2D: internalformat does not match the existing image");
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
+    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims))
         return;
 
     if (!ValidateCompTexImageSize(level, internalformat,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
-                                  func))
+                                  func, dims))
     {
         return;
     }
 
     if (levelInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(texImageTarget, level);
 
     MakeContextCurrent();
@@ -3647,41 +3653,42 @@ WebGLContext::TexImage2D_base(TexImageTa
                               GLint border,
                               GLenum format,
                               GLenum type,
                               void* data, uint32_t byteLength,
                               js::Scalar::Type jsArrayType,
                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
 
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat,
+    if (!ValidateTexImage(texImageTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
-                          border, format, type, func))
+                          border, format, type, func, dims))
     {
         return;
     }
 
     const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT ||
                                 format == LOCAL_GL_DEPTH_STENCIL;
 
     if (isDepthTexture && !IsWebGL2()) {
         if (data != nullptr || level != 0)
             return ErrorInvalidOperation("texImage2D: "
                                          "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
                                          "data must be nullptr, "
                                          "level must be zero");
     }
 
-    if (!ValidateTexInputData(type, jsArrayType, func))
+    if (!ValidateTexInputData(type, jsArrayType, func, dims))
         return;
 
     TexInternalFormat effectiveInternalFormat =
         EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
 
     if (effectiveInternalFormat == LOCAL_GL_NONE) {
         return ErrorInvalidOperation("texImage2D: bad combination of internalformat and type");
     }
@@ -3811,17 +3818,17 @@ WebGLContext::TexImage2D(GLenum rawTarge
         const ArrayBufferView& view = pixels.Value();
         view.ComputeLengthAndData();
 
         data = view.Data();
         length = view.Length();
         jsArrayType = JS_GetArrayBufferViewType(view.Obj());
     }
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexImage2D_base(rawTarget, level, internalformat, width, height, 0, border, format, type,
                            data, length, jsArrayType,
                            WebGLTexelFormat::Auto, false);
 }
 
 void
@@ -3840,17 +3847,17 @@ WebGLContext::TexImage2D(GLenum rawTarge
     Uint8ClampedArray arr;
     DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
     MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
     void* pixelData = arr.Data();
     const uint32_t pixelDataLength = arr.Length();
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(),
                            pixels->Height(), 4*pixels->Width(), 0,
                            format, type, pixelData, pixelDataLength, js::Scalar::TypeMax,
                            WebGLTexelFormat::RGBA8, false);
 }
 
@@ -3860,16 +3867,17 @@ WebGLContext::TexSubImage2D_base(TexImag
                                  GLint xoffset, GLint yoffset,
                                  GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                                  GLenum format, GLenum type,
                                  void* data, uint32_t byteLength,
                                  js::Scalar::Type jsArrayType,
                                  WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
 
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     if (!tex) {
         return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
@@ -3877,26 +3885,26 @@ WebGLContext::TexSubImage2D_base(TexImag
 
     if (!tex->HasImageInfoAt(texImageTarget, level)) {
         return ErrorInvalidOperation("texSubImage2D: no previously defined texture image");
     }
 
     const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
     const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
 
-    if (!ValidateTexImage(2, texImageTarget, level,
+    if (!ValidateTexImage(texImageTarget, level,
                           existingEffectiveInternalFormat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
-                          0, format, type, func))
+                          0, format, type, func, dims))
     {
         return;
     }
 
-    if (!ValidateTexInputData(type, jsArrayType, func))
+    if (!ValidateTexInputData(type, jsArrayType, func, dims))
         return;
 
     if (type != TypeFromInternalFormat(existingEffectiveInternalFormat)) {
         return ErrorInvalidOperation("texSubImage2D: type differs from that of the existing image");
     }
 
     size_t srcTexelSize = size_t(-1);
     if (srcFormat == WebGLTexelFormat::Auto) {
@@ -3991,17 +3999,17 @@ WebGLContext::TexSubImage2D(GLenum rawTa
         return;
 
     if (pixels.IsNull())
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
     const ArrayBufferView& view = pixels.Value();
     view.ComputeLengthAndData();
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexSubImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexSubImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
                               width, height, 0, format, type,
                               view.Data(), view.Length(),
                               JS_GetArrayBufferViewType(view.Obj()),
                               WebGLTexelFormat::Auto, false);
 }
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -841,9 +841,37 @@ WebGLContext::AssertCachedState()
 
     AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStorePackAlignment);
     AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStoreUnpackAlignment);
 
     MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
 #endif
 }
 
+const char*
+InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
+{
+    switch (dims) {
+    case WebGLTexDimensions::Tex2D:
+        switch (func) {
+        case WebGLTexImageFunc::TexImage:        return "texImage2D";
+        case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
+        case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
+        case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
+        case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
+        case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
+        default:
+            MOZ_CRASH();
+        }
+    case WebGLTexDimensions::Tex3D:
+        switch (func) {
+        case WebGLTexImageFunc::TexSubImage:     return "texSubImage3D";
+        case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
+        case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
+        default:
+            MOZ_CRASH();
+        }
+    default:
+        MOZ_CRASH();
+    }
+}
+
 } // namespace mozilla
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -101,11 +101,18 @@ WebGLContext::WebGLObjectAsJSObject(JSCo
 {
     JS::Value v = WebGLObjectAsJSValue(cx, object, rv);
     if (v.isNull()) {
         return nullptr;
     }
     return &v.toObject();
 }
 
+/**
+ * Return the displayable name for the texture function that is the
+ * source for validation.
+ */
+const char*
+InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims);
+
 } // namespace mozilla
 
 #endif // WEBGLCONTEXTUTILS_H_
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -56,56 +56,35 @@ BlockSizeFor(GLenum format, GLint* block
 
     case LOCAL_GL_ETC1_RGB8_OES:
         // 4x4 blocks, but no 4-multiple requirement.
     default:
         break;
     }
 }
 
-/**
- * Return the displayable name for the texture function that is the
- * source for validation.
- */
-static const char*
-InfoFrom(WebGLTexImageFunc func)
-{
-    // TODO: Account for dimensions (WebGL 2)
-    switch (func) {
-    case WebGLTexImageFunc::TexImage:        return "texImage2D";
-    case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
-    case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
-    case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
-    case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
-    case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
-    default:
-        MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
-        return "(error)";
-    }
-}
-
 static bool
 IsCompressedFunc(WebGLTexImageFunc func)
 {
     return func == WebGLTexImageFunc::CompTexImage ||
            func == WebGLTexImageFunc::CompTexSubImage;
 }
 
 /**
  * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
  * name for \a glenum.
  */
 static void
-ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
+ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     const char* name = WebGLContext::EnumName(glenum);
     if (name)
-        ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
+        ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func, dims), msg, name);
     else
-        ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
+        ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func, dims), msg, glenum);
 }
 
 /**
  * Return true if the format is valid for source calls.
  */
 static bool
 IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
 {
@@ -381,17 +360,17 @@ WebGLContext::ValidateFramebufferAttachm
     return false;
 }
 
 /**
  * Return true if format is a valid texture image format for source,
  * taking into account enabled WebGL extensions.
  */
 bool
-WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
+WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     /* Core WebGL texture formats */
     if (format == LOCAL_GL_ALPHA ||
         format == LOCAL_GL_RGB ||
         format == LOCAL_GL_RGBA ||
         format == LOCAL_GL_LUMINANCE ||
         format == LOCAL_GL_LUMINANCE_ALPHA)
     {
@@ -404,103 +383,112 @@ WebGLContext::ValidateTexImageFormat(GLe
         format == LOCAL_GL_RED_INTEGER ||
         format == LOCAL_GL_RG_INTEGER ||
         format == LOCAL_GL_RGB_INTEGER ||
         format == LOCAL_GL_RGBA_INTEGER)
     {
         bool valid = IsWebGL2();
         if (!valid) {
             ErrorInvalidEnum("%s:  invalid format %s: requires WebGL version 2.0 or newer",
-                             InfoFrom(func), EnumName(format));
+                             InfoFrom(func, dims), EnumName(format));
         }
         return valid;
     }
 
     /* WEBGL_depth_texture added formats */
     if (format == LOCAL_GL_DEPTH_COMPONENT ||
         format == LOCAL_GL_DEPTH_STENCIL)
     {
         if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), EnumName(format));
+                             InfoFrom(func, dims), EnumName(format));
             return false;
         }
 
         // If WEBGL_depth_texture is enabled, then it is not allowed to be used with the
         // copyTexImage, or copyTexSubImage methods, and it is not allowed with
         // texSubImage in WebGL1.
         if ((func == WebGLTexImageFunc::TexSubImage && !IsWebGL2()) ||
             func == WebGLTexImageFunc::CopyTexImage ||
             func == WebGLTexImageFunc::CopyTexSubImage)
         {
-            ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func), EnumName(format));
+            ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func, dims), EnumName(format));
             return false;
         }
 
         return true;
     }
 
     // Needs to be below the depth_texture check because an invalid operation
     // error needs to be generated instead of invalid enum.
     /* Only core formats are valid for CopyTex(Sub)?Image */
     // TODO: Revisit this once color_buffer_(half_)?float lands
     if (IsCopyFunc(func)) {
-        ErrorInvalidEnumWithName(this, "invalid format", format, func);
+        ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
         return false;
     }
 
     /* EXT_sRGB added formats */
     if (format == LOCAL_GL_SRGB ||
         format == LOCAL_GL_SRGB_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
-    ErrorInvalidEnumWithName(this, "invalid format", format, func);
+    ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
 
     return false;
 }
 
 /**
  * Check if the given texture target is valid for TexImage.
  */
 bool
-WebGLContext::ValidateTexImageTarget(GLuint dims,
-                                     GLenum target,
-                                     WebGLTexImageFunc func)
+WebGLContext::ValidateTexImageTarget(GLenum target,
+                                     WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     switch (dims) {
-    case 2:
+    case WebGLTexDimensions::Tex2D:
         if (target == LOCAL_GL_TEXTURE_2D ||
             IsTexImageCubemapTarget(target))
         {
             return true;
         }
 
-        ErrorInvalidEnumWithName(this, "invalid target", target, func);
+        ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
+        return false;
+
+    case WebGLTexDimensions::Tex3D:
+        if (target == LOCAL_GL_TEXTURE_3D)
+        {
+            return true;
+        }
+
+        ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
         return false;
 
     default:
         MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
     }
 
     return false;
 }
 
 /**
  * Return true if type is a valid texture image type for source,
  * taking into account enabled WebGL extensions.
  */
 bool
 WebGLContext::ValidateTexImageType(GLenum type,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     /* Core WebGL texture types */
     if (type == LOCAL_GL_UNSIGNED_BYTE ||
         type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
         type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
         type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
     {
         return true;
@@ -513,182 +501,185 @@ WebGLContext::ValidateTexImageType(GLenu
         type == LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV ||
         type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV ||
         type == LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV ||
         type == LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV)
     {
         bool validType = IsWebGL2();
         if (!validType) {
             ErrorInvalidEnum("%s: invalid type %s: requires WebGL version 2.0 or newer",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         }
         return validType;
     }
 
     /* OES_texture_float added types */
     if (type == LOCAL_GL_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* OES_texture_half_float add types */
     if (type == LOCAL_GL_HALF_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* WEBGL_depth_texture added types */
     if (type == LOCAL_GL_UNSIGNED_SHORT ||
         type == LOCAL_GL_UNSIGNED_INT ||
         type == LOCAL_GL_UNSIGNED_INT_24_8)
     {
         bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
-    ErrorInvalidEnumWithName(this, "invalid type", type, func);
+    ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
     return false;
 }
 
 /**
  * Validate texture image sizing extra constraints for
  * CompressedTex(Sub)?Image.
  */
 // TODO: WebGL 2
 bool
 WebGLContext::ValidateCompTexImageSize(GLint level,
                                        GLenum format,
                                        GLint xoffset, GLint yoffset,
                                        GLsizei width, GLsizei height,
                                        GLsizei levelWidth, GLsizei levelHeight,
-                                       WebGLTexImageFunc func)
+                                       WebGLTexImageFunc func,
+                                       WebGLTexDimensions dims)
 {
     // Negative parameters must already have been handled above
     MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
                width >= 0 && height >= 0);
 
     if (xoffset + width > (GLint) levelWidth) {
-        ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
+        ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func, dims));
         return false;
     }
 
     if (yoffset + height > (GLint) levelHeight) {
-        ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
+        ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func, dims));
         return false;
     }
 
     GLint blockWidth = 1;
     GLint blockHeight = 1;
     BlockSizeFor(format, &blockWidth, &blockHeight);
 
     /* If blockWidth || blockHeight != 1, then the compressed format
      * had block-based constraints to be checked. (For example, PVRTC is compressed but
      * isn't a block-based format)
      */
     if (blockWidth != 1 || blockHeight != 1) {
         /* offsets must be multiple of block size */
         if (xoffset % blockWidth != 0) {
             ErrorInvalidOperation("%s: xoffset must be multiple of %d",
-                                  InfoFrom(func), blockWidth);
+                                  InfoFrom(func, dims), blockWidth);
             return false;
         }
 
         if (yoffset % blockHeight != 0) {
             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
-                                  InfoFrom(func), blockHeight);
+                                  InfoFrom(func, dims), blockHeight);
             return false;
         }
 
         /* The size must be a multiple of blockWidth and blockHeight,
          * or must be using offset+size that exactly hits the edge.
          * Important for small mipmap levels.
          */
         /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
          * "When level equals zero width and height must be a multiple of 4. When
          *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
          *  If they are not an INVALID_OPERATION error is generated."
          */
         if (level == 0) {
             if (width % blockWidth != 0) {
                 ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
-                                      InfoFrom(func), blockWidth);
+                                      InfoFrom(func, dims), blockWidth);
                 return false;
             }
 
             if (height % blockHeight != 0) {
                 ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
-                                      InfoFrom(func), blockHeight);
+                                      InfoFrom(func, dims), blockHeight);
                 return false;
             }
         }
         else if (level > 0) {
             if (width % blockWidth != 0 && width > 2) {
                 ErrorInvalidOperation("%s: width of level %d must be multiple"
                                       " of %d or 0, 1, 2",
-                                      InfoFrom(func), level, blockWidth);
+                                      InfoFrom(func, dims), level, blockWidth);
                 return false;
             }
 
             if (height % blockHeight != 0 && height > 2) {
                 ErrorInvalidOperation("%s: height of level %d must be multiple"
                                       " of %d or 0, 1, 2",
-                                      InfoFrom(func), level, blockHeight);
+                                      InfoFrom(func, dims), level, blockHeight);
                 return false;
             }
         }
 
         if (IsSubFunc(func)) {
             if ((xoffset % blockWidth) != 0) {
                 ErrorInvalidOperation("%s: xoffset must be multiple of %d",
-                                      InfoFrom(func), blockWidth);
+                                      InfoFrom(func, dims), blockWidth);
                 return false;
             }
 
             if (yoffset % blockHeight != 0) {
                 ErrorInvalidOperation("%s: yoffset must be multiple of %d",
-                                      InfoFrom(func), blockHeight);
+                                      InfoFrom(func, dims), blockHeight);
                 return false;
             }
         }
     }
 
     switch (format) {
     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:
         if (!is_pot_assuming_nonnegative(width) ||
             !is_pot_assuming_nonnegative(height))
         {
             ErrorInvalidValue("%s: width and height must be powers of two",
-                              InfoFrom(func));
+                              InfoFrom(func, dims));
             return false;
         }
     }
 
     return true;
 }
 
 /**
  * Return true if the enough data is present to satisfy compressed
  * texture format constraints.
  */
 bool
 WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
                                            GLsizei width, GLsizei height,
-                                           uint32_t byteLength, WebGLTexImageFunc func)
+                                           uint32_t byteLength,
+                                           WebGLTexImageFunc func,
+                                           WebGLTexDimensions dims)
 {
     // negative width and height must already have been handled above
     MOZ_ASSERT(width >= 0 && height >= 0);
 
     CheckedUint32 required_byteLength = 0;
 
     switch (format) {
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
@@ -717,33 +708,33 @@ WebGLContext::ValidateCompTexImageDataSi
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
         {
             required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
             break;
         }
     }
 
     if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
-        ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
+        ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func, dims));
         return false;
     }
 
     return true;
 }
 
 /**
  * Validate the width, height, and depth of a texture image, \return
  * true is valid, false otherwise.
  * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
  * Target and level must have been validated before calling.
  */
 bool
 WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
                                    GLint width, GLint height, GLint depth,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     MOZ_ASSERT(level >= 0, "level should already be validated");
 
     /* Bug 966630: maxTextureSize >> level runs into "undefined"
      * behaviour depending on ISA. For example, on Intel shifts
      * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
      * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
      * what would be expected. Make the required behaviour explicit by
@@ -761,262 +752,267 @@ WebGLContext::ValidateTexImageSize(TexIm
 
     if (!isSub && isCubemapTarget && (width != height)) {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "When the target parameter to TexImage2D is one of the
          *   six cube map two-dimensional image targets, the error
          *   INVALID_VALUE is generated if the width and height
          *   parameters are not equal."
          */
-        ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
+        ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func, dims));
         return false;
     }
 
     if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
     {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If wt and ht are the specified image width and height,
          *   and if either wt or ht are less than zero, then the error
          *   INVALID_VALUE is generated."
          */
         if (width < 0) {
-            ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
         if (height < 0) {
-            ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "The maximum allowable width and height of a
          *   two-dimensional texture image must be at least 2**(k−lod)
          *   for image arrays of level zero through k, where k is the
          *   log base 2 of MAX_TEXTURE_SIZE. and lod is the
          *   level-of-detail of the image array. It may be zero for
          *   image arrays of any level-of-detail greater than k. The
          *   error INVALID_VALUE is generated if the specified image
          *   is too large to be stored under any conditions.
          */
         if (width > (int) maxTexImageSize) {
             ErrorInvalidValue("%s: the maximum width for level %d is %u",
-                              InfoFrom(func), level, maxTexImageSize);
+                              InfoFrom(func, dims), level, maxTexImageSize);
             return false;
         }
 
         if (height > (int) maxTexImageSize) {
             ErrorInvalidValue("%s: tex maximum height for level %d is %u",
-                              InfoFrom(func), level, maxTexImageSize);
+                              InfoFrom(func, dims), level, maxTexImageSize);
             return false;
         }
 
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If level is greater than zero, and either width or
          *   height is not a power-of-two, the error INVALID_VALUE is
          *   generated."
          */
         if (level > 0) {
             if (!is_pot_assuming_nonnegative(width)) {
                 ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
-                                  InfoFrom(func), width);
+                                  InfoFrom(func, dims), width);
                 return false;
             }
 
             if (!is_pot_assuming_nonnegative(height)) {
                 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
-                                  InfoFrom(func), height);
+                                  InfoFrom(func, dims), height);
                 return false;
             }
         }
     }
 
     // TODO: WebGL 2
     if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
         if (depth < 0) {
-            ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
         if (!is_pot_assuming_nonnegative(depth)) {
             ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
-                              InfoFrom(func), depth);
+                              InfoFrom(func, dims), depth);
             return false;
         }
     }
 
     return true;
 }
 
 /**
  * Validate texture image sizing for Tex(Sub)?Image variants.
  */
 // TODO: WebGL 2. Update this to handle 3D textures.
 bool
 WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
                                       GLsizei width, GLsizei height, GLsizei /*depth*/,
                                       GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
-                                      WebGLTexImageFunc func)
+                                      WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
      *   "Taking wt and ht to be the specified width and height of the
      *   texture array, and taking x, y, w, and h to be the xoffset,
      *   yoffset, width, and height argument values, any of the
      *   following relationships generates the error INVALID_VALUE:
      *       x < 0
      *       x + w > wt
      *       y < 0
      *       y + h > ht"
      */
 
     if (xoffset < 0) {
-        ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
+        ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func, dims));
         return false;
     }
 
     if (yoffset < 0) {
-        ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
+        ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func, dims));
         return false;
     }
 
     if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
-        ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
+        ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func, dims));
         return false;
     }
 
     return true;
 }
 
 /**
  * Perform validation of format/type combinations for TexImage variants.
  * Returns true if the format/type is a valid combination, false otherwise.
  */
 bool
 WebGLContext::ValidateTexImageFormatAndType(GLenum format,
-                                            GLenum type, WebGLTexImageFunc func)
+                                            GLenum type,
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims)
 {
     if (IsCompressedFunc(func) || IsCopyFunc(func))
     {
         MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
         return true;
     }
-    if (!ValidateTexImageFormat(format, func) ||
-        !ValidateTexImageType(type, func))
+    if (!ValidateTexImageFormat(format, func, dims) ||
+        !ValidateTexImageType(type, func, dims))
     {
         return false;
     }
 
     // Here we're reinterpreting format as an unsized internalformat;
     // these are the same in practice and there's no point in having the
     // same code implemented twice.
     TexInternalFormat effective =
         EffectiveInternalFormatFromInternalFormatAndType(format, type);
     bool validCombo = effective != LOCAL_GL_NONE;
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
-                              InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
+                              InfoFrom(func, dims), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
 
     return validCombo;
 }
 
 bool
 WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
-                                                 WebGLTexImageFunc func)
+                                                 WebGLTexImageFunc func,
+                                                 WebGLTexDimensions dims)
 {
     if (!IsCompressedTextureFormat(format)) {
         ErrorInvalidEnum("%s: invalid compressed texture format: %s",
-                         InfoFrom(func), WebGLContext::EnumName(format));
+                         InfoFrom(func, dims), WebGLContext::EnumName(format));
         return false;
     }
 
     /* WEBGL_compressed_texture_atc added formats */
     if (format == LOCAL_GL_ATC_RGB ||
         format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
         format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     // WEBGL_compressed_texture_etc1
     if (format == LOCAL_GL_ETC1_RGB8_OES) {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     return false;
 }
 
 bool
 WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
-                                                 WebGLTexImageFunc func)
+                                                 WebGLTexImageFunc func,
+                                                 WebGLTexDimensions dims)
 {
     bool valid = format == LOCAL_GL_RGBA ||
                  format == LOCAL_GL_RGB ||
                  format == LOCAL_GL_LUMINANCE_ALPHA ||
                  format == LOCAL_GL_LUMINANCE ||
                  format == LOCAL_GL_ALPHA;
     if (!valid)
     {
         // in CopyTexImage, the internalformat is a function parameter,
         // so a bad value is an INVALID_ENUM error.
         // in CopyTexSubImage, the internalformat is part of existing state,
         // so this is an INVALID_OPERATION error.
         GenerateWarning("%s: invalid texture internal format: %s",
-                        InfoFrom(func), WebGLContext::EnumName(format));
+                        InfoFrom(func, dims), WebGLContext::EnumName(format));
         SynthesizeGLError(func == WebGLTexImageFunc::CopyTexImage
                           ? LOCAL_GL_INVALID_ENUM
                           : LOCAL_GL_INVALID_OPERATION);
     }
     return valid;
 }
 /**
  * Return true if format, type and jsArrayType are a valid combination.
  * Also returns the size for texel of format and type (in bytes) via
  * \a texelSize.
  *
  * It is assumed that type has previously been validated.
  */
 bool
 WebGLContext::ValidateTexInputData(GLenum type,
                                    js::Scalar::Type jsArrayType,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     bool validInput = false;
     const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
 
     // We're using js::Scalar::TypeMax as dummy value when the tex source wasn't a
     // typed array.
     if (jsArrayType == js::Scalar::TypeMax) {
         return true;
@@ -1060,114 +1056,116 @@ WebGLContext::ValidateTexInputData(GLenu
         validInput = jsArrayType == js::Scalar::Float32;
         break;
 
     default:
         break;
     }
 
     if (!validInput)
-        ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
+        ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
 
     return validInput;
 }
 
 /**
  * Checks specific for the CopyTex[Sub]Image2D functions.
  * Verifies:
  * - Framebuffer is complete and has valid read planes
  * - Copy format is a subset of framebuffer format (i.e. all required components are available)
  */
 bool
 WebGLContext::ValidateCopyTexImage(GLenum format,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     MOZ_ASSERT(IsCopyFunc(func));
 
     // Default framebuffer format
     GLenum fboFormat = bool(gl->GetPixelFormat().alpha > 0) ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
-            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func));
+            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func, dims));
             return false;
         }
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
             ErrorInvalidOperation("%s: Read source attachment doesn't have the"
-                                  " correct color/depth/stencil type.", InfoFrom(func));
+                                  " correct color/depth/stencil type.", InfoFrom(func, dims));
             return false;
         }
 
         // Get the correct format for the framebuffer, as it's not the default one
         const WebGLFramebuffer::Attachment& color0 = mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
         fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
     }
 
     // Make sure the format of the framebuffer is a superset of
     // the format requested by the CopyTex[Sub]Image2D functions.
     const GLComponents formatComps = GLComponents(format);
     const GLComponents fboComps = GLComponents(fboFormat);
     if (!formatComps.IsSubsetOf(fboComps)) {
         ErrorInvalidOperation("%s: format %s is not a subset of the current framebuffer format, which is %s.",
-                              InfoFrom(func), EnumName(format), EnumName(fboFormat));
+                              InfoFrom(func, dims), EnumName(format), EnumName(fboFormat));
         return false;
     }
 
     return true;
 }
 
 /**
  * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
  * Verifies each of the parameters against the WebGL standard and enabled extensions.
  */
 // TODO: Texture dims is here for future expansion in WebGL 2.0
 bool
-WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
+WebGLContext::ValidateTexImage(TexImageTarget texImageTarget,
                                GLint level,
                                GLenum internalFormat,
                                GLint xoffset, GLint yoffset, GLint zoffset,
                                GLint width, GLint height, GLint depth,
                                GLint border,
                                GLenum format,
                                GLenum type,
-                               WebGLTexImageFunc func)
+                               WebGLTexImageFunc func,
+                               WebGLTexDimensions dims)
 {
-    const char* info = InfoFrom(func);
+    const char* info = InfoFrom(func, dims);
 
     /* Check level */
     if (level < 0) {
         ErrorInvalidValue("%s: level must be >= 0", info);
         return false;
     }
 
     /* Check border */
     if (border != 0) {
         ErrorInvalidValue("%s: border must be 0", info);
         return false;
     }
 
     /* Check incoming image format and type */
-    if (!ValidateTexImageFormatAndType(format, type, func))
+    if (!ValidateTexImageFormatAndType(format, type, func, dims))
         return false;
 
     if (!TexInternalFormat::IsValueLegal(internalFormat)) {
         ErrorInvalidEnum("%s: invalid internalformat enum %s", info, EnumName(internalFormat));
         return false;
     }
     TexInternalFormat unsizedInternalFormat =
         UnsizedInternalFormatFromInternalFormat(internalFormat);
 
     if (IsCompressedFunc(func)) {
-        if (!ValidateCompTexImageInternalFormat(internalFormat, func)) {
+        if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims)) {
             return false;
         }
     } else if (IsCopyFunc(func)) {
-        if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func)) {
+        if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func, dims)) {
             return false;
         }
     } else if (format != unsizedInternalFormat) {
         if (IsWebGL2()) {
             // In WebGL2, it's OK to have internalformat != format if internalformat is the sized
             // internal format corresponding to the (format, type) pair according to Table 3.2
             // in the OpenGL ES 3.0.3 spec.
             if (internalFormat != EffectiveInternalFormatFromInternalFormatAndType(format, type)) {
@@ -1192,17 +1190,17 @@ WebGLContext::ValidateTexImage(GLuint di
         } else {
             // in WebGL 1, format must be equal to internalformat
             ErrorInvalidOperation("%s: internalformat does not match format", info);
             return false;
         }
     }
 
     /* Check texture image size */
-    if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func))
+    if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func, dims))
         return false;
 
     /* 5.14.8 Texture objects - WebGL Spec.
      *   "If an attempt is made to call these functions with no
      *    WebGLTexture bound (see above), an INVALID_OPERATION error
      *    is generated."
      */
     WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -1219,17 +1217,17 @@ WebGLContext::ValidateTexImage(GLuint di
             return false;
         }
 
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
 
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
-                                     func))
+                                     func, dims))
         {
             return false;
         }
     }
 
     /* Additional checks for depth textures */
     if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
         (format == LOCAL_GL_DEPTH_COMPONENT ||
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -41,66 +41,66 @@ namespace mozilla {
  *       with zero bytes, which means it's either opaque or transparent black
  *       depending on whether the image format has alpha.
  *
  * Why are there _two_ separate enums there, WebGLContextFakeBlackStatus
  * and WebGLTextureFakeBlackStatus? That's because each texture must know the precise
  * reason why it needs to be faked (incomplete texture vs. uninitialized image data),
  * whereas the WebGL context can only know whether _any_ faking is currently needed at all.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, uint8_t)
   Unknown,
   NotNeeded,
   Needed
 MOZ_END_ENUM_CLASS(WebGLContextFakeBlackStatus)
 
-MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, uint8_t)
   Unknown,
   NotNeeded,
   IncompleteTexture,
   UninitializedImageData
 MOZ_END_ENUM_CLASS(WebGLTextureFakeBlackStatus)
 
 /*
  * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
  * emulating the vertex attrib 0 array when it's not enabled. Indeed,
  * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
  * desktop OpenGL does not allow that.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, uint8_t)
     Default, // default status - no emulation needed
     EmulatedUninitializedArray, // need an artificial attrib 0 array, but contents may be left uninitialized
     EmulatedInitializedArray // need an artificial attrib 0 array, and contents must be initialized
 MOZ_END_ENUM_CLASS(WebGLVertexAttrib0Status)
 
 /*
  * Enum to track the status of image data (renderbuffer or texture image) presence
  * and initialization.
  *
  * - NoImageData is the initial state before any image data is allocated.
  * - InitializedImageData is the state after image data is allocated and initialized.
  * - UninitializedImageData is an intermediate state where data is allocated but not
  *   initialized. It is the state that renderbuffers are in after a renderbufferStorage call,
  *   and it is the state that texture images are in after a texImage2D call with null data.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, uint8_t)
     NoImageData,
     UninitializedImageData,
     InitializedImageData
 MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
 
 /*
  * The formats that may participate, either as source or destination formats,
  * in WebGL texture conversions. This includes:
  *  - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
  *  - additional formats provided by extensions, e.g. RGB32F
  *  - additional source formats, depending on browser details, used when uploading
  *    textures from DOM elements. See gfxImageSurface::Format().
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, uint8_t)
     // returned by SurfaceFromElementResultToImageSurface to indicate absence of image data
     None,
     // common value for formats for which format conversions are not supported
     FormatNotSupportingAnyConversion,
     // dummy pseudo-format meaning "use the other format".
     // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
     // is implicitly treated as being RGB8 itself.
     Auto,
@@ -125,25 +125,30 @@ MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, i
     RGBA8,
     BGRA8, // used for DOM elements
     RGBA5551,
     RGBA4444,
     RGBA16F, // OES_texture_half_float
     RGBA32F // OES_texture_float
 MOZ_END_ENUM_CLASS(WebGLTexelFormat)
 
-MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, uint8_t)
     TexImage,
     TexSubImage,
     CopyTexImage,
     CopyTexSubImage,
     CompTexImage,
     CompTexSubImage,
 MOZ_END_ENUM_CLASS(WebGLTexImageFunc)
 
+MOZ_BEGIN_ENUM_CLASS(WebGLTexDimensions, uint8_t)
+    Tex2D,
+    Tex3D
+MOZ_END_ENUM_CLASS(WebGLTexDimensions)
+
 // Please keep extensions in alphabetic order.
 MOZ_BEGIN_ENUM_CLASS(WebGLExtensionID, uint8_t)
     ANGLE_instanced_arrays,
     EXT_blend_minmax,
     EXT_color_buffer_half_float,
     EXT_frag_depth,
     EXT_sRGB,
     EXT_shader_texture_lod,