Bug 1323626 - Initialize tex image data during completeness checks. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 20 Dec 2016 17:10:34 -0800
changeset 452153 eb3cee59564f6634ce1dd25318efcee34c6b230c
parent 452152 c8c6c1a5a097504a69cbfb919622a1da04f7db03
child 540154 12e68f74fd7548d353fede479d06d9e0c3f8366c
push id39325
push userbmo:jgilbert@mozilla.com
push dateWed, 21 Dec 2016 06:03:40 +0000
reviewersdaoshengmu
bugs1323626
milestone53.0a1
Bug 1323626 - Initialize tex image data during completeness checks. - r=daoshengmu MozReview-Commit-ID: 9g5EETBEfU2
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
dom/canvas/test/webgl-conf/generated-mochitest.ini
dom/canvas/test/webgl-conf/mochitest-errata.ini
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -186,18 +186,20 @@ WebGLTexture::SetImageInfosAtLevel(uint3
     for (uint8_t i = 0; i < mFaceCount; i++) {
         ImageInfoAtFace(i, level) = newInfo;
     }
 
     InvalidateResolveCache();
 }
 
 bool
-WebGLTexture::IsMipmapComplete(uint32_t texUnit) const
+WebGLTexture::IsMipmapComplete(const char* funcName, uint32_t texUnit,
+                               bool* const out_initFailed)
 {
+    *out_initFailed = false;
     MOZ_ASSERT(DoesMinFilterRequireMipmap());
     // GLES 3.0.4, p161
 
     uint32_t maxLevel;
     if (!MaxEffectiveMipmapLevel(texUnit, &maxLevel))
         return false;
 
     // "* `level_base <= level_max`"
@@ -209,16 +211,21 @@ WebGLTexture::IsMipmapComplete(uint32_t 
 
     // Reference dimensions based on the current level.
     uint32_t refWidth = baseImageInfo.mWidth;
     uint32_t refHeight = baseImageInfo.mHeight;
     uint32_t refDepth = baseImageInfo.mDepth;
     MOZ_ASSERT(refWidth && refHeight && refDepth);
 
     for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
+        if (!EnsureLevelInitialized(funcName, level)) {
+            *out_initFailed = true;
+            return false;
+        }
+
         // "A cube map texture is mipmap complete if each of the six texture images,
         //  considered individually, is mipmap complete."
 
         for (uint8_t face = 0; face < mFaceCount; face++) {
             const ImageInfo& cur = ImageInfoAtFace(face, level);
 
             // "* The set of mipmap arrays `level_base` through `q` (where `q` is defined
             //    the "Mipmapping" discussion of section 3.8.10) were each specified with
@@ -296,18 +303,26 @@ WebGLTexture::IsCubeComplete() const
             return false;
         }
     }
 
     return true;
 }
 
 bool
-WebGLTexture::IsComplete(uint32_t texUnit, const char** const out_reason) const
+WebGLTexture::IsComplete(const char* funcName, uint32_t texUnit,
+                         const char** const out_reason, bool* const out_initFailed)
 {
+    *out_initFailed = false;
+
+    if (!EnsureLevelInitialized(funcName, mBaseMipmapLevel)) {
+        *out_initFailed = true;
+        return false;
+    }
+
     // Texture completeness is established at GLES 3.0.4, p160-161.
     // "[A] texture is complete unless any of the following conditions hold true:"
 
     // "* Any dimension of the `level_base` array is not positive."
     const ImageInfo& baseImageInfo = BaseImageInfo();
     if (!baseImageInfo.IsDefined()) {
         // In case of undefined texture image, we don't print any message because this is
         // a very common and often legitimate case (asynchronous texture loading).
@@ -329,17 +344,20 @@ WebGLTexture::IsComplete(uint32_t texUni
     WebGLSampler* sampler = mContext->mBoundSamplers[texUnit];
     TexMinFilter minFilter = sampler ? sampler->mMinFilter : mMinFilter;
     TexMagFilter magFilter = sampler ? sampler->mMagFilter : mMagFilter;
 
     // "* The minification filter requires a mipmap (is neither NEAREST nor LINEAR) and
     //    the texture is not mipmap complete."
     const bool requiresMipmap = (minFilter != LOCAL_GL_NEAREST &&
                                  minFilter != LOCAL_GL_LINEAR);
-    if (requiresMipmap && !IsMipmapComplete(texUnit)) {
+    if (requiresMipmap && !IsMipmapComplete(funcName, texUnit, out_initFailed)) {
+        if (*out_initFailed)
+            return false;
+
         *out_reason = "Because the minification filter requires mipmapping, the texture"
                       " must be \"mipmap complete\".";
         return false;
     }
 
     const bool isMinFilteringNearest = (minFilter == LOCAL_GL_NEAREST ||
                                         minFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     const bool isMagFilteringNearest = (magFilter == LOCAL_GL_NEAREST);
@@ -452,84 +470,35 @@ WebGLTexture::MaxEffectiveMipmapLevel(ui
     return true;
 }
 
 bool
 WebGLTexture::GetFakeBlackType(const char* funcName, uint32_t texUnit,
                                FakeBlackType* const out_fakeBlack)
 {
     const char* incompleteReason;
-    if (!IsComplete(texUnit, &incompleteReason)) {
+    bool initFailed = false;
+    if (!IsComplete(funcName, texUnit, &incompleteReason, &initFailed)) {
+        if (initFailed) {
+            mContext->ErrorOutOfMemory("%s: Failed to initialize texture data.",
+                                       funcName);
+            return false; // The world just exploded.
+        }
+
         if (incompleteReason) {
             mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
                                       " 'incomplete', and will be rendered as"
                                       " RGBA(0,0,0,1), as per the GLES 2.0.24 $3.8.2: %s",
                                       funcName, texUnit, mTarget.get(),
                                       incompleteReason);
         }
         *out_fakeBlack = FakeBlackType::RGBA0001;
         return true;
     }
 
-    // We may still want FakeBlack as an optimization for uninitialized image data.
-    bool hasUninitializedData = false;
-    bool hasInitializedData = false;
-
-    uint32_t maxLevel;
-    MOZ_ALWAYS_TRUE( MaxEffectiveMipmapLevel(texUnit, &maxLevel) );
-
-    MOZ_ASSERT(mBaseMipmapLevel <= maxLevel);
-    for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
-        for (uint8_t face = 0; face < mFaceCount; face++) {
-            const auto& cur = ImageInfoAtFace(face, level);
-            if (cur.IsDataInitialized())
-                hasInitializedData = true;
-            else
-                hasUninitializedData = true;
-        }
-    }
-    MOZ_ASSERT(hasUninitializedData || hasInitializedData);
-
-    if (!hasUninitializedData) {
-        *out_fakeBlack = FakeBlackType::None;
-        return true;
-    }
-
-    if (!hasInitializedData) {
-        const auto format = ImageInfoAtFace(0, mBaseMipmapLevel).mFormat->format;
-        if (format->IsColorFormat()) {
-            *out_fakeBlack = (format->a ? FakeBlackType::RGBA0000
-                                        : FakeBlackType::RGBA0001);
-            return true;
-        }
-
-        mContext->GenerateWarning("%s: Active texture %u for target 0x%04x is"
-                                  " uninitialized, and will be (perhaps slowly) cleared"
-                                  " by the implementation.",
-                                  funcName, texUnit, mTarget.get());
-    } else {
-        mContext->GenerateWarning("%s: Active texture %u for target 0x%04x contains"
-                                  " TexImages with uninitialized data along with"
-                                  " TexImages with initialized data, forcing the"
-                                  " implementation to (slowly) initialize the"
-                                  " uninitialized TexImages.",
-                                  funcName, texUnit, mTarget.get());
-    }
-
-    GLenum baseImageTarget = mTarget.get();
-    if (baseImageTarget == LOCAL_GL_TEXTURE_CUBE_MAP)
-        baseImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
-
-    for (uint32_t level = mBaseMipmapLevel; level <= maxLevel; level++) {
-        for (uint8_t face = 0; face < mFaceCount; face++) {
-            TexImageTarget imageTarget = baseImageTarget + face;
-            if (!EnsureImageDataInitialized(funcName, imageTarget, level))
-                return false; // The world just exploded.
-        }
-    }
 
     *out_fakeBlack = FakeBlackType::None;
     return true;
 }
 
 static void
 SetSwizzle(gl::GLContext* gl, TexTarget target, const GLint* swizzle)
 {
@@ -580,24 +549,41 @@ WebGLTexture::ResolveForDraw(const char*
     return true;
 }
 
 bool
 WebGLTexture::EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
                                          uint32_t level)
 {
     auto& imageInfo = ImageInfoAt(target, level);
-    MOZ_ASSERT(imageInfo.IsDefined());
+    if (!imageInfo.IsDefined())
+        return true;
 
     if (imageInfo.IsDataInitialized())
         return true;
 
     return InitializeImageData(funcName, target, level);
 }
 
+bool
+WebGLTexture::EnsureLevelInitialized(const char* funcName, uint32_t level)
+{
+    if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
+        return EnsureImageDataInitialized(funcName, mTarget.get(), level);
+
+    for (GLenum texImageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+         texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+         ++texImageTarget)
+    {
+        if (!EnsureImageDataInitialized(funcName, texImageTarget, level))
+            return false;
+    }
+    return true;
+}
+
 static void
 ZeroANGLEDepthTexture(WebGLContext* webgl, GLuint tex,
                       const webgl::FormatUsageInfo* usage, uint32_t width,
                       uint32_t height)
 {
     const auto& format = usage->format;
     GLenum attachPoint = 0;
     GLbitfield clearBits = 0;
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -345,16 +345,17 @@ public:
     }
 
     size_t MemoryUsage() const;
 
     bool InitializeImageData(const char* funcName, TexImageTarget target, uint32_t level);
 protected:
     bool EnsureImageDataInitialized(const char* funcName, TexImageTarget target,
                                     uint32_t level);
+    bool EnsureLevelInitialized(const char* funcName, uint32_t level);
 
     bool CheckFloatTextureFilterParams() const {
         // Without OES_texture_float_linear, only NEAREST and
         // NEAREST_MIMPAMP_NEAREST are supported.
         return mMagFilter == LOCAL_GL_NEAREST &&
                (mMinFilter == LOCAL_GL_NEAREST ||
                 mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     }
@@ -371,21 +372,23 @@ public:
     }
 
     void SetGeneratedMipmap();
 
     void SetCustomMipmap();
 
     bool AreAllLevel0ImageInfosEqual() const;
 
-    bool IsMipmapComplete(uint32_t texUnit) const;
+    bool IsMipmapComplete(const char* funcName, uint32_t texUnit,
+                          bool* const out_initFailed);
 
     bool IsCubeComplete() const;
 
-    bool IsComplete(uint32_t texUnit, const char** const out_reason) const;
+    bool IsComplete(const char* funcName, uint32_t texUnit, const char** const out_reason,
+                    bool* const out_initFailed);
 
     bool IsMipmapCubeComplete() const;
 
     bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
 
     // Resolve cache optimizations
 protected:
     bool GetFakeBlackType(const char* funcName, uint32_t texUnit,
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -4706,17 +4706,16 @@ skip-if = (os == 'android' || os == 'lin
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__oes-texture-float-linear.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-compressed-texture-atc.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-compressed-texture-pvrtc.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc.html]
-fail-if = (os == 'mac') || (os == 'win')
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-compressed-texture-size-limit.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-debug-renderer-info.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-debug-shaders.html]
 skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1'))
 [generated/test_2_conformance__extensions__webgl-shared-resources.html]
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -131,18 +131,16 @@ skip-if = (os == 'android' && debug)
 skip-if = (os == 'mac' && os_version == '10.6')
 [generated/test_conformance__textures__misc__texture-size.html]
 # application crashed [@ mozilla::gl::GLContext::AfterGLCall]
 skip-if = (os == 'android') || (os == 'win')
 
 [generated/test_2_conformance__textures__misc__cube-incomplete-fbo.html]
 fail-if = (os == 'mac')
 skip-if = (os == 'win')
-[generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc.html]
-fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance2__rendering__draw-buffers.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance__textures__misc__tex-image-with-format-and-type.html]
 fail-if = (os == 'mac')
 [generated/test_2_conformance__attribs__gl-vertexattribpointer.html]
 fail-if = (os == 'mac') || (os == 'win')
 [generated/test_2_conformance2__vertex_arrays__vertex-array-object.html]
 fail-if = (os == 'mac') || (os == 'win')