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
--- 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')