Check that target is valid for formats. draft
authorJeff Gilbert <jdashg@gmail.com>
Thu, 17 Dec 2015 16:16:51 -0800
changeset 316078 f8e054f41b6b223b55a2d419a2a4f46ef34f21a0
parent 316077 024d3b6003293ddee6914f2469f656bf721b9682
child 316079 96d9b10d0c81414adf03df0f2ecdf8849c66dd1b
push id8514
push userjgilbert@mozilla.com
push dateFri, 18 Dec 2015 00:24:33 +0000
milestone45.0a1
Check that target is valid for formats. Depth and depth/stencil formats work with TEXTURE_2D_ARRAY, but not TEXTURE_3D.
dom/canvas/WebGLTextureUpload.cpp
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -848,67 +848,112 @@ ValidateCompressedTexImageRestrictions(c
             return true;
 
         if (level == 0)
             return false;
 
         return (size == 0 || size == 1 || size == 2);
     };
 
-    bool supports2DArray = false;
     switch (format->compression->family) {
     case webgl::CompressionFamily::PVRTC:
         if (!IsPowerOfTwo(width) || !IsPowerOfTwo(height)) {
             webgl->ErrorInvalidValue("%s: %s requires power-of-two width and height.",
                                      funcName, format->name);
             return false;
         }
 
         break;
 
-    // Block-aligned:
-    case webgl::CompressionFamily::ES3:
-        supports2DArray = true;
-        break;
-
     case webgl::CompressionFamily::S3TC:
-        supports2DArray = true;
-
         if (!fnIsDimValid_S3TC(width, format->compression->blockWidth) ||
             !fnIsDimValid_S3TC(height, format->compression->blockHeight))
         {
             webgl->ErrorInvalidOperation("%s: %s requires that width and height are"
                                          " block-aligned, or, if level>0, equal to 0, 1,"
                                          " or 2.",
                                          funcName, format->name);
             return false;
         }
 
         break;
 
     // Default: There are no restrictions on CompressedTexImage.
-    default: // ATC, ETC1
+    default: // ATC, ETC1, ES3
         break;
     }
 
-    bool targetSupported = true;
-    switch (target.get()) {
-    case LOCAL_GL_TEXTURE_3D:
-        targetSupported = false;
+    return true;
+}
+
+static bool
+ValidateTargetForFormat(const char* funcName, WebGLContext* webgl, TexImageTarget target,
+                        const webgl::FormatInfo* format)
+{
+    // GLES 3.0.4 p127:
+    // "Textures with a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL are
+    //  supported by texture image specification commands only if `target` is TEXTURE_2D,
+    //  TEXTURE_2D_ARRAY, or TEXTURE_CUBE_MAP. Using these formats in conjunction with any
+    //  other `target` will result in an INVALID_OPERATION error."
+
+    switch (format->effectiveFormat) {
+    // TEXTURE_2D_ARRAY but not TEXTURE_3D:
+    // D and DS formats
+    case webgl::EffectiveFormat::DEPTH_COMPONENT16:
+    case webgl::EffectiveFormat::DEPTH_COMPONENT24:
+    case webgl::EffectiveFormat::DEPTH_COMPONENT32F:
+    case webgl::EffectiveFormat::DEPTH24_STENCIL8:
+    case webgl::EffectiveFormat::DEPTH32F_STENCIL8:
+    // CompressionFamily::ES3
+    case webgl::EffectiveFormat::COMPRESSED_R11_EAC:
+    case webgl::EffectiveFormat::COMPRESSED_SIGNED_R11_EAC:
+    case webgl::EffectiveFormat::COMPRESSED_RG11_EAC:
+    case webgl::EffectiveFormat::COMPRESSED_SIGNED_RG11_EAC:
+    case webgl::EffectiveFormat::COMPRESSED_RGB8_ETC2:
+    case webgl::EffectiveFormat::COMPRESSED_SRGB8_ETC2:
+    case webgl::EffectiveFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case webgl::EffectiveFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA8_ETC2_EAC:
+    case webgl::EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    // CompressionFamily::S3TC
+    case webgl::EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5_EXT:
+        if (target == LOCAL_GL_TEXTURE_3D) {
+            webgl->ErrorInvalidOperation("%s: Format %s cannot be used with TEXTURE_3D.",
+                                         funcName, format->name);
+            return false;
+        }
         break;
 
-    case LOCAL_GL_TEXTURE_2D_ARRAY:
-        targetSupported = supports2DArray;
+    // No 3D targets:
+    // CompressionFamily::ATC
+    case webgl::EffectiveFormat::ATC_RGB_AMD:
+    case webgl::EffectiveFormat::ATC_RGBA_EXPLICIT_ALPHA_AMD:
+    case webgl::EffectiveFormat::ATC_RGBA_INTERPOLATED_ALPHA_AMD:
+    // CompressionFamily::PVRTC
+    case webgl::EffectiveFormat::COMPRESSED_RGB_PVRTC_4BPPV1:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA_PVRTC_4BPPV1:
+    case webgl::EffectiveFormat::COMPRESSED_RGB_PVRTC_2BPPV1:
+    case webgl::EffectiveFormat::COMPRESSED_RGBA_PVRTC_2BPPV1:
+    // CompressionFamily::ETC1
+    case webgl::EffectiveFormat::ETC1_RGB8_OES:
+        if (target == LOCAL_GL_TEXTURE_3D ||
+            target == LOCAL_GL_TEXTURE_2D_ARRAY)
+        {
+            webgl->ErrorInvalidOperation("%s: Format %s cannot be used with TEXTURE_3D or"
+                                         " TEXTURE_2D_ARRAY.",
+                                         funcName, format->name);
+            return false;
+        }
         break;
-    }
 
-    if (!targetSupported) {
-        webgl->ErrorInvalidOperation("%s: This target is not supported by this %s.",
-                                     funcName, format->name);
-        return false;
+    default:
+        break;
     }
 
     return true;
 }
 
 void
 WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels,
                          GLenum sizedFormat, GLsizei width, GLsizei height, GLsizei depth)
@@ -943,16 +988,19 @@ WebGLTexture::TexStorage(const char* fun
     auto dstUsage = mContext->mFormatUsage->GetSizedTexUsage(sizedFormat);
     if (!dstUsage) {
         mContext->ErrorInvalidEnum("%s: Invalid internalformat: 0x%04x", funcName,
                                    sizedFormat);
         return;
     }
     auto dstFormat = dstUsage->format;
 
+    if (!ValidateTargetForFormat(funcName, mContext, testTarget, dstFormat))
+        return;
+
     if (dstFormat->compression) {
         if (!ValidateCompressedTexImageRestrictions(funcName, mContext, testTarget,
                                                     testLevel, dstFormat, width, height,
                                                     depth))
         {
             return;
         }
     }
@@ -1104,16 +1152,19 @@ WebGLTexture::TexImage(const char* funcN
     const bool isFunc3D = Is3D(target);
     if (!blob->ValidateUnpack(mContext, funcName, isFunc3D, srcPacking))
         return;
 
     ////////////////////////////////////
     // Check that source and dest info are compatible
     auto dstFormat = dstUsage->format;
 
+    if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
+        return;
+
     if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
         if (target != LOCAL_GL_TEXTURE_2D ||
             blob->mHasData ||
             level != 0)
         {
             mContext->ErrorInvalidOperation("%s: With format %s, this function may only"
                                             " be called with target=TEXTURE_2D,"
                                             " data=null, and level=0.",
@@ -1283,16 +1334,19 @@ WebGLTexture::CompressedTexImage(const c
 
     auto format = usage->format;
     if (!format->compression) {
         mContext->ErrorInvalidEnum("%s: Specified internalFormat must be compressed.",
                                    funcName);
         return;
     }
 
+    if (!ValidateTargetForFormat(funcName, mContext, target, format))
+        return;
+
     ////////////////////////////////////
     // Get source info
 
     void* mutData;
     size_t dataSize;
     js::Scalar::Type jsType;
     ComputeLengthAndData(view, &mutData, &dataSize, &jsType);
     const void* data = mutData;
@@ -1578,16 +1632,19 @@ WebGLTexture::CopyTexImage2D(TexImageTar
 
     if (!dstUsage) {
         mContext->ErrorInvalidEnum("%s: Invalid internalFormat 0x%04x for FB format %s.",
                                    funcName, internalFormat, srcFormat->name);
         return;
     }
     auto dstFormat = dstUsage->format;
 
+    if (!ValidateTargetForFormat(funcName, mContext, target, dstFormat))
+        return;
+
     if (!mContext->IsWebGL2() && dstFormat->hasDepth) {
         mContext->ErrorInvalidOperation("%s: Function may not be called with format %s.",
                                         funcName, dstFormat->name);
         return;
     }
 
     if (!ValidateCopyTexImageFormats(mContext, funcName, srcFormat, dstFormat))
         return;