Bug 1323626 - Initialize tex image data during completeness checks. - r=daoshengmu
MozReview-Commit-ID: 9g5EETBEfU2
--- 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')