Bug 1478216 - Don't init tex images in FBAttachment::IsComplete. r=kvark
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 18 Oct 2018 16:52:39 -0700
changeset 442905 5ef21255897e9c49c234be77b32b07ac3db7dc6c
parent 442904 434f70360933449c52ece7a00a6268391f805f08
child 442906 42961627bc9a1bfd12acb11c62bdbc327ffd7303
push id34927
push userncsoregi@mozilla.com
push dateThu, 25 Oct 2018 04:45:44 +0000
treeherdermozilla-central@76d5b62fb151 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1478216
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1478216 - Don't init tex images in FBAttachment::IsComplete. r=kvark Also: - Only init the base tex level for GenerateMipmap. - Change ZeroTextureData warning into a perf warning. Differential Revision: https://phabricator.services.mozilla.com/D9177
dom/canvas/WebGLFramebuffer.cpp
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/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -126,17 +126,18 @@ WebGLFBAttachPoint::IsComplete(WebGLCont
     if (tex) {
         // ES 3.0 spec, pg 213 has giant blocks of text that bake down to requiring that
         // attached tex images are within the valid mip-levels of the texture.
         // While it draws distinction to only test non-immutable textures, that's because
         // immutable textures are *always* texture-complete.
         // We need to check immutable textures though, because checking completeness is
         // also when we zero invalidated/no-data tex images.
         const bool complete = [&]() {
-            const auto texCompleteness = tex->CalcCompletenessInfo();
+            const bool ensureInit = false;
+            const auto texCompleteness = tex->CalcCompletenessInfo(ensureInit);
             if (!texCompleteness) // OOM
                 return false;
             if (!texCompleteness->levels)
                 return false;
 
             const auto baseLevel = tex->BaseMipmapLevel();
             const auto maxLevel = baseLevel + texCompleteness->levels - 1;
             return baseLevel <= mTexImageLevel && mTexImageLevel <= maxLevel;
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -150,17 +150,17 @@ WebGLTexture::PopulateMipChain(const uin
 
 static bool
 ZeroTextureData(const WebGLContext* webgl, GLuint tex,
                 TexImageTarget target, uint32_t level,
                 const webgl::FormatUsageInfo* usage, uint32_t width, uint32_t height,
                 uint32_t depth);
 
 bool
-WebGLTexture::IsMipAndCubeComplete(const uint32_t maxLevel,
+WebGLTexture::IsMipAndCubeComplete(const uint32_t maxLevel, const bool ensureInit,
                                    bool* const out_initFailed) const
 {
     *out_initFailed = false;
 
     // Reference dimensions based on baseLevel.
     auto ref = BaseImageInfo();
     MOZ_ASSERT(ref.mWidth && ref.mHeight && ref.mDepth);
 
@@ -182,17 +182,17 @@ WebGLTexture::IsMipAndCubeComplete(const
             if (cur.mWidth != ref.mWidth ||
                 cur.mHeight != ref.mHeight ||
                 cur.mDepth != ref.mDepth ||
                 cur.mFormat != ref.mFormat)
             {
                 return false;
             }
 
-            if (MOZ_UNLIKELY( !cur.mHasData )) {
+            if (MOZ_UNLIKELY( ensureInit && !cur.mHasData )) {
                 auto imageTarget = mTarget.get();
                 if (imageTarget == LOCAL_GL_TEXTURE_CUBE_MAP) {
                     imageTarget = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
                 }
                 if (!ZeroTextureData(mContext, mGLName, imageTarget, level,
                                      cur.mFormat, cur.mWidth, cur.mHeight, cur.mDepth))
                 {
                     mContext->ErrorOutOfMemory("Failed to zero tex image data.");
@@ -208,17 +208,17 @@ WebGLTexture::IsMipAndCubeComplete(const
             break;
         ref = next.ref();
     }
 
     return true;
 }
 
 Maybe<const WebGLTexture::CompletenessInfo>
-WebGLTexture::CalcCompletenessInfo() const
+WebGLTexture::CalcCompletenessInfo(const bool ensureInit, const bool skipMips) const
 {
     Maybe<CompletenessInfo> ret = Some(CompletenessInfo());
 
     // -
 
     if (mBaseMipmapLevel > kMaxLevelCount - 1) {
         ret->incompleteReason = "`level_base` too high.";
         return ret;
@@ -238,17 +238,17 @@ WebGLTexture::CalcCompletenessInfo() con
 
     if (!baseImageInfo.mWidth || !baseImageInfo.mHeight || !baseImageInfo.mDepth) {
         ret->incompleteReason = "The dimensions of `level_base` are not all positive.";
         return ret;
     }
 
     // "* The texture is a cube map texture, and is not cube complete."
     bool initFailed = false;
-    if (!IsMipAndCubeComplete(mBaseMipmapLevel, &initFailed)) {
+    if (!IsMipAndCubeComplete(mBaseMipmapLevel, ensureInit, &initFailed)) {
         if (initFailed)
             return {};
 
         // Can only fail if not cube-complete.
         ret->incompleteReason = "Cubemaps must be \"cube complete\".";
         return ret;
     }
     ret->levels = 1;
@@ -274,17 +274,20 @@ WebGLTexture::CalcCompletenessInfo() con
     // "* `level_base <= level_max`"
 
     const auto maxLevel = EffectiveMaxLevel();
     if (mBaseMipmapLevel > maxLevel) {
         ret->incompleteReason = "`level_base > level_max`.";
         return ret;
     }
 
-    if (!IsMipAndCubeComplete(maxLevel, &initFailed)) {
+    if (skipMips)
+        return ret;
+
+    if (!IsMipAndCubeComplete(maxLevel, ensureInit, &initFailed)) {
         if (initFailed)
             return {};
 
         ret->incompleteReason = "Bad mipmap dimension or format.";
         return ret;
     }
     ret->levels = maxLevel - mBaseMipmapLevel + 1;
     ret->mipmapComplete = true;
@@ -294,17 +297,18 @@ WebGLTexture::CalcCompletenessInfo() con
     return ret;
 }
 
 Maybe<const webgl::SampleableInfo>
 WebGLTexture::CalcSampleableInfo(const WebGLSampler* const sampler) const
 {
     Maybe<webgl::SampleableInfo> ret = Some(webgl::SampleableInfo());
 
-    const auto completeness = CalcCompletenessInfo();
+    const bool ensureInit = true;
+    const auto completeness = CalcCompletenessInfo(ensureInit);
     if (!completeness)
         return {};
 
     ret->incompleteReason = completeness->incompleteReason;
 
     if (!completeness->levels)
         return ret;
 
@@ -572,18 +576,19 @@ ZeroTextureData(const WebGLContext* webg
     // 1. Lazy zeroing of uninitialized textures:
     //    a. Before draw.
     //    b. Before partial upload. (TexStorage + TexSubImage)
     // 2. Zero subrects from out-of-bounds blits. (CopyTex(Sub)Image)
 
     // We have no sympathy for any of these cases.
 
     // "Doctor, it hurts when I do this!" "Well don't do that!"
-    webgl->GenerateWarning("This operation requires zeroing texture data. This is"
-                           " slow.");
+    const auto targetStr = EnumString(target.get());
+    webgl->GeneratePerfWarning("Tex image %s level %u is incurring lazy initialization.",
+                               targetStr.c_str(), level);
 
     gl::GLContext* gl = webgl->GL();
 
     GLenum scopeBindTarget;
     switch (target.get()) {
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
@@ -732,17 +737,20 @@ WebGLTexture::BindTexture(TexTarget texT
 void
 WebGLTexture::GenerateMipmap()
 {
     // GLES 3.0.4 p160:
     // "Mipmap generation replaces texel array levels level base + 1 through q with arrays
     //  derived from the level base array, regardless of their previous contents. All
     //  other mipmap arrays, including the level base array, are left unchanged by this
     //  computation."
-    const auto completeness = CalcCompletenessInfo();
+    // But only check and init the base level.
+    const bool ensureInit = true;
+    const bool skipMips = true;
+    const auto completeness = CalcCompletenessInfo(ensureInit, skipMips);
     if (!completeness || !completeness->levels) {
         mContext->ErrorInvalidOperation("The texture's base level must be complete.");
         return;
     }
     const auto& usage = completeness->usage;
     const auto& format = usage->format;
     if (!mContext->IsWebGL2()) {
         if (!completeness->powerOfTwo) {
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -140,17 +140,18 @@ protected:
         bool mipmapComplete = false;
         const webgl::FormatUsageInfo* usage = nullptr;
         const char* incompleteReason = nullptr;
     };
 
     mutable CacheWeakMap<const WebGLSampler*, webgl::SampleableInfo> mSamplingCache;
 
 public:
-    Maybe<const CompletenessInfo> CalcCompletenessInfo() const;
+    Maybe<const CompletenessInfo> CalcCompletenessInfo(bool ensureInit,
+                                                       bool skipMips = false) const;
     Maybe<const webgl::SampleableInfo> CalcSampleableInfo(const WebGLSampler*) const;
 
     const webgl::SampleableInfo* GetSampleableInfo(const WebGLSampler*) const;
 
 
     // -
 
     const auto& Immutable() const { return mImmutable; }
@@ -303,17 +304,18 @@ public:
         return ImageInfoAtFace(0, mBaseMipmapLevel);
     }
 
     size_t MemoryUsage() const;
 
     bool EnsureImageDataInitialized(TexImageTarget target,
                                     uint32_t level);
     void PopulateMipChain(uint32_t maxLevel);
-    bool IsMipAndCubeComplete(uint32_t maxLevel, bool* out_initFailed) const;
+    bool IsMipAndCubeComplete(uint32_t maxLevel, bool ensureInit,
+                              bool* out_initFailed) const;
 
     bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); }
 };
 
 inline TexImageTarget
 TexImageTargetForTargetAndFace(TexTarget target, uint8_t face)
 {
     switch (target.get()) {
--- a/dom/canvas/test/webgl-conf/generated-mochitest.ini
+++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini
@@ -5319,16 +5319,17 @@ fail-if = (os == 'win')
 [generated/test_2_conformance2__rendering__element-index-uint.html]
 subsuite = webgl2-core
 [generated/test_2_conformance2__rendering__framebuffer-completeness-draw-framebuffer.html]
 subsuite = webgl2-core
 [generated/test_2_conformance2__rendering__framebuffer-completeness-unaffected.html]
 subsuite = webgl2-core
 [generated/test_2_conformance2__rendering__framebuffer-texture-changing-base-level.html]
 subsuite = webgl2-core
+fail-if = (os == 'win')
 [generated/test_2_conformance2__rendering__framebuffer-texture-level1.html]
 subsuite = webgl2-core
 fail-if = (os == 'mac')
 [generated/test_2_conformance2__rendering__framebuffer-unsupported.html]
 subsuite = webgl2-core
 [generated/test_2_conformance2__rendering__fs-color-type-mismatch-color-buffer-type.html]
 subsuite = webgl2-core
 fail-if = (os == 'mac') || (os == 'win')
--- a/dom/canvas/test/webgl-conf/mochitest-errata.ini
+++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini
@@ -1096,8 +1096,11 @@ skip-if = (os == 'win')
 [generated/test_conformance__misc__webgl-specific-stencil-settings.html]
 skip-if = (os == 'win')
 [generated/test_conformance__textures__misc__tex-video-using-tex-unit-non-zero.html]
 # Fails on QuantumRender configs, but passes on standard configs?
 # Might be intermittant.
 skip-if = (os == 'win')
 [generated/test_2_conformance__textures__misc__tex-video-using-tex-unit-non-zero.html]
 skip-if = (os == 'win')
+[generated/test_2_conformance2__rendering__framebuffer-texture-changing-base-level.html]
+# https://bugzilla.mozilla.org/show_bug.cgi?id=1501868 (ANGLE bug)
+fail-if = (os == 'win')