author | Greyson Gilbert <greyson.gilbert.oss@gmail.com> |
Tue, 30 Jul 2019 23:32:29 +0000 | |
changeset 485450 | 6019fc32fbf36e44a00248aa12f94c6f111a9213 |
parent 485449 | 9de8e9eca62071ac3519f9ce65b1d9a21600e876 |
child 485451 | 56b1594759719d8d815f91a7017641a131dfa88f |
push id | 91305 |
push user | jgilbert@mozilla.com |
push date | Tue, 30 Jul 2019 23:33:38 +0000 |
treeherder | autoland@6019fc32fbf3 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jgilbert |
bugs | 1564293 |
milestone | 70.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
|
--- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -835,17 +835,17 @@ void WebGLFramebuffer::ResolveAttachment if (mContext->IsWebGL2()) { const uint32_t uiZeros[4] = {}; const int32_t iZeros[4] = {}; const float fZeros[4] = {}; const float fOne[] = {1.0f}; for (const auto& cur : mAttachments) { const auto& imageInfo = cur->GetImageInfo(); - if (!imageInfo || imageInfo->mHasData) + if (!imageInfo || !imageInfo->mUninitializedSlices) continue; // Nothing attached, or already has data. const auto fnClearBuffer = [&]() { const auto& format = imageInfo->mFormat->format; MOZ_ASSERT(format->estimatedBytesPerPixel <= sizeof(uiZeros)); MOZ_ASSERT(format->estimatedBytesPerPixel <= sizeof(iZeros)); MOZ_ASSERT(format->estimatedBytesPerPixel <= sizeof(fZeros)); @@ -875,40 +875,42 @@ void WebGLFramebuffer::ResolveAttachment } } }; if (imageInfo->mDepth > 1) { const auto& tex = cur->Texture(); const gl::ScopedFramebuffer scopedFB(gl); const gl::ScopedBindFramebuffer scopedBindFB(gl, scopedFB.FB()); - for (uint32_t z = 0; z < imageInfo->mDepth; z++) { - gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, - cur->mAttachmentPoint, tex->mGLName, - cur->MipLevel(), z); - fnClearBuffer(); + for (const auto z : IntegerRange(imageInfo->mDepth)) { + if ((*imageInfo->mUninitializedSlices)[z]) { + gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, + cur->mAttachmentPoint, tex->mGLName, + cur->MipLevel(), z); + fnClearBuffer(); + } } } else { fnClearBuffer(); } - imageInfo->mHasData = true; + imageInfo->mUninitializedSlices = {}; } return; } uint32_t clearBits = 0; std::vector<GLenum> drawBufferForClear; const auto fnGather = [&](const WebGLFBAttachPoint& attach, const uint32_t attachClearBits) { const auto& imageInfo = attach.GetImageInfo(); - if (!imageInfo || imageInfo->mHasData) return false; + if (!imageInfo || !imageInfo->mUninitializedSlices) return false; clearBits |= attachClearBits; - imageInfo->mHasData = true; // Just mark it now. + imageInfo->mUninitializedSlices = {}; // Just mark it now. return true; }; ////// for (const auto& cur : mColorAttachments) { if (fnGather(cur, LOCAL_GL_COLOR_BUFFER_BIT)) { const uint32_t id = cur.mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0;
--- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -187,18 +187,20 @@ void WebGLRenderbuffer::RenderbufferStor InvalidateCaches(); } return; } mContext->OnDataAllocCall(); const uint32_t depth = 1; - const bool hasData = false; - mImageInfo = {usage, width, height, depth, hasData, uint8_t(samples)}; + auto uninitializedSlices = Some(std::vector<bool>(depth, true)); + mImageInfo = { + usage, width, height, depth, std::move(uninitializedSlices), + uint8_t(samples)}; InvalidateCaches(); } void WebGLRenderbuffer::DoFramebufferRenderbuffer( const GLenum attachment) const { gl::GLContext* gl = mContext->gl; if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
--- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -51,16 +51,19 @@ Maybe<ImageInfo> ImageInfo::NextMip(cons next.mDepth = std::max(uint32_t(1), next.mDepth / 2); } else { // TEXTURE_2D_ARRAY may have depth != 1, but that's normal. if (mWidth <= 1 && mHeight <= 1) { return {}; } } + if (next.mUninitializedSlices) { + next.mUninitializedSlices = Some(std::vector<bool>(next.mDepth, true)); + } next.mWidth = std::max(uint32_t(1), next.mWidth / 2); next.mHeight = std::max(uint32_t(1), next.mHeight / 2); return Some(next); } } // namespace webgl @@ -127,18 +130,17 @@ void WebGLTexture::PopulateMipChain(cons if (!next) break; ref = next.ref(); } InvalidateCaches(); } 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); + const webgl::ImageInfo& info); bool 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(); @@ -159,28 +161,27 @@ bool WebGLTexture::IsMipAndCubeComplete( // "* The dimensions of the arrays follow the sequence described in // the "Mipmapping" discussion of section 3.8.10." if (cur.mWidth != ref.mWidth || cur.mHeight != ref.mHeight || cur.mDepth != ref.mDepth || cur.mFormat != ref.mFormat) { return false; } - if (MOZ_UNLIKELY(ensureInit && !cur.mHasData)) { + if (MOZ_UNLIKELY(ensureInit && cur.mUninitializedSlices)) { 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)) { + if (!ZeroTextureData(mContext, mGLName, imageTarget, level, cur)) { mContext->ErrorOutOfMemory("Failed to zero tex image data."); *out_initFailed = true; return false; } - cur.mHasData = true; + cur.mUninitializedSlices = {}; } } const auto next = ref.NextMip(mTarget.get()); if (!next) break; ref = next.ref(); } @@ -456,37 +457,37 @@ void WebGLTexture::RefreshSwizzle() cons } } bool WebGLTexture::EnsureImageDataInitialized(const TexImageTarget target, const uint32_t level) { auto& imageInfo = ImageInfoAt(target, level); if (!imageInfo.IsDefined()) return true; - if (imageInfo.mHasData) return true; + if (!imageInfo.mUninitializedSlices) return true; - if (!ZeroTextureData(mContext, mGLName, target, level, imageInfo.mFormat, - imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth)) { + if (!ZeroTextureData(mContext, mGLName, target, level, imageInfo)) { return false; } - imageInfo.mHasData = true; + imageInfo.mUninitializedSlices = {}; return true; } static bool ClearDepthTexture(const WebGLContext& webgl, const GLuint tex, const TexImageTarget imageTarget, const uint32_t level, - const webgl::FormatUsageInfo* const usage, - const uint32_t depth) { + const webgl::ImageInfo& info) { + const auto& gl = webgl.gl; + const auto& usage = info.mFormat; + const auto& format = usage->format; + // Depth resources actually clear to 1.0f, not 0.0f! // They are also always renderable. MOZ_ASSERT(usage->IsRenderable()); - - const auto& gl = webgl.gl; - const auto& format = usage->format; + MOZ_ASSERT(info.mUninitializedSlices); GLenum attachPoint = LOCAL_GL_DEPTH_ATTACHMENT; GLbitfield clearBits = LOCAL_GL_DEPTH_BUFFER_BIT; if (format->s) { attachPoint = LOCAL_GL_DEPTH_STENCIL_ATTACHMENT; clearBits |= LOCAL_GL_STENCIL_BUFFER_BIT; } @@ -515,45 +516,51 @@ static bool ClearDepthTexture(const WebG } else { gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachPoint, imageTarget.get(), tex, level); } break; } }; - for (uint32_t z = 0; z < depth; ++z) { - fnAttach(z); - gl->fClear(clearBits); + for (const auto z : IntegerRange(info.mDepth)) { + if ((*info.mUninitializedSlices)[z]) { + fnAttach(z); + gl->fClear(clearBits); + } } const auto& status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); const bool isComplete = (status == LOCAL_GL_FRAMEBUFFER_COMPLETE); MOZ_ASSERT(isComplete); return isComplete; } 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) { - // This has two usecases: - // 1. Lazy zeroing of uninitialized textures: + const webgl::ImageInfo& info) { + // This has one usecase: + // 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. + // We have no sympathy for this case. // "Doctor, it hurts when I do this!" "Well don't do that!" + MOZ_ASSERT(info.mUninitializedSlices); + const auto targetStr = EnumString(target.get()); - webgl->GeneratePerfWarning( + webgl->GenerateWarning( "Tex image %s level %u is incurring lazy initialization.", targetStr.c_str(), level); gl::GLContext* gl = webgl->GL(); + const auto& width = info.mWidth; + const auto& height = info.mHeight; + const auto& depth = info.mDepth; + const auto& usage = info.mFormat; 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: case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z: @@ -576,67 +583,78 @@ static bool ZeroTextureData(const WebGLC }; const auto widthBlocks = fnSizeInBlocks(width, compression->blockWidth); const auto heightBlocks = fnSizeInBlocks(height, compression->blockHeight); CheckedUint32 checkedByteCount = compression->bytesPerBlock; checkedByteCount *= widthBlocks; checkedByteCount *= heightBlocks; - checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; - const size_t byteCount = checkedByteCount.value(); + const size_t sliceByteCount = checkedByteCount.value(); - UniqueBuffer zeros = calloc(1u, byteCount); + UniqueBuffer zeros = calloc(1u, sliceByteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with // striding it well. - const auto error = - DoCompressedTexSubImage(gl, target.get(), level, 0, 0, 0, width, height, - depth, sizedFormat, byteCount, zeros.get()); + GLenum error = 0; + for (const auto z : IntegerRange(depth)) { + if ((*info.mUninitializedSlices)[z]) { + error = DoCompressedTexSubImage(gl, target.get(), level, 0, 0, z, width, + height, 1, sizedFormat, sliceByteCount, + zeros.get()); + if (error) break; + } + } return !error; } const auto driverUnpackInfo = usage->idealUnpack; MOZ_RELEASE_ASSERT(driverUnpackInfo, "GFX: ideal unpack info not set."); if (usage->format->d) { // ANGLE_depth_texture does not allow uploads, so we have to clear. // (Restriction because of D3D9) // Also, depth resources are cleared to 1.0f and are always renderable, so // just use FB clears. - return ClearDepthTexture(*webgl, tex, target, level, usage, depth); + return ClearDepthTexture(*webgl, tex, target, level, info); } const webgl::PackingInfo packing = driverUnpackInfo->ToPacking(); const auto bytesPerPixel = webgl::BytesPerPixel(packing); CheckedUint32 checkedByteCount = bytesPerPixel; checkedByteCount *= width; checkedByteCount *= height; - checkedByteCount *= depth; if (!checkedByteCount.isValid()) return false; - const size_t byteCount = checkedByteCount.value(); + const size_t sliceByteCount = checkedByteCount.value(); - UniqueBuffer zeros = calloc(1u, byteCount); + UniqueBuffer zeros = calloc(1u, sliceByteCount); if (!zeros) return false; ScopedUnpackReset scopedReset(webgl); gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); // Don't bother with striding it well. - const auto error = DoTexSubImage(gl, target, level, 0, 0, 0, width, height, - depth, packing, zeros.get()); + + GLenum error = 0; + for (const auto z : IntegerRange(depth)) { + if ((*info.mUninitializedSlices)[z]) { + error = DoTexSubImage(gl, target, level, 0, 0, z, width, height, 1, + packing, zeros.get()); + if (error) break; + } + } return !error; } template <typename T, typename R> static R Clamp(const T val, const R min, const R max) { if (val < min) return min; if (val > max) return max; return static_cast<R>(val);
--- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -69,17 +69,17 @@ struct SamplingState final { struct ImageInfo final { static const ImageInfo kUndefined; const webgl::FormatUsageInfo* mFormat = nullptr; uint32_t mWidth = 0; uint32_t mHeight = 0; uint32_t mDepth = 0; - mutable bool mHasData = false; + mutable Maybe<std::vector<bool>> mUninitializedSlices; uint8_t mSamples = 0; // - size_t MemoryUsage() const; bool IsDefined() const { if (!mFormat) {
--- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -748,31 +748,41 @@ static bool DoChannelsMatchForCopyTexIma return false; } } static bool EnsureImageDataInitializedForUpload( WebGLTexture* tex, TexImageTarget target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset, uint32_t width, uint32_t height, uint32_t depth, webgl::ImageInfo* imageInfo) { - if (!imageInfo->mHasData) { - const bool isFullUpload = - (!xOffset && !yOffset && !zOffset && width == imageInfo->mWidth && - height == imageInfo->mHeight && depth == imageInfo->mDepth); - if (!isFullUpload) { - WebGLContext* webgl = tex->mContext; - webgl->GenerateWarning( - "Texture has not been initialized prior to a" - " partial upload, forcing the browser to clear it." - " This may be slow."); - if (!tex->EnsureImageDataInitialized(target, level)) { - MOZ_ASSERT(false, "Unexpected failure to init image data."); - return false; - } + if (!imageInfo->mUninitializedSlices) return true; + + if (width == imageInfo->mWidth && height == imageInfo->mHeight) { + for (const auto z : + IntegerRange(uint32_t(zOffset), uint32_t(zOffset) + depth)) { + (*imageInfo->mUninitializedSlices)[z] = false; + } + bool hasUninitialized = false; + for (const auto z : IntegerRange(imageInfo->mDepth)) { + hasUninitialized |= (*imageInfo->mUninitializedSlices)[z]; } + if (!hasUninitialized) { + imageInfo->mUninitializedSlices = {}; + } + return true; + } + + WebGLContext* webgl = tex->mContext; + webgl->GenerateWarning( + "Texture has not been initialized prior to a" + " partial upload, forcing the browser to clear it." + " This may be slow."); + if (!tex->EnsureImageDataInitialized(target, level)) { + MOZ_ASSERT(false, "Unexpected failure to init image data."); + return false; } return true; } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // Actual calls @@ -1106,19 +1116,20 @@ void WebGLTexture::TexStorage(TexTarget gfxCriticalError() << "Unexpected error from driver: " << call.BeginReading(); return; } //////////////////////////////////// // Update our specification data. - const bool isDataInitialized = false; + auto uninitializedSlices = Some(std::vector<bool>(depth, true)); const webgl::ImageInfo newInfo{dstUsage, uint32_t(width), uint32_t(height), - uint32_t(depth), isDataInitialized}; + uint32_t(depth), + std::move(uninitializedSlices)}; { const auto base_level = mBaseMipmapLevel; mBaseMipmapLevel = 0; ImageInfoAtFace(0, 0) = newInfo; PopulateMipChain(levels - 1); @@ -1204,19 +1215,21 @@ void WebGLTexture::TexImage(TexImageTarg } } //////////////////////////////////// // Do the thing! // It's tempting to do allocation first, and TexSubImage second, but this is // generally slower. - + auto uninitializedSlices = + blob->HasData() ? Nothing() : Some(std::vector<bool>(blob->mDepth, true)); const webgl::ImageInfo newImageInfo{dstUsage, blob->mWidth, blob->mHeight, - blob->mDepth, blob->HasData()}; + blob->mDepth, + std::move(uninitializedSlices)}; const bool isSubImage = false; const bool needsRespec = (imageInfo->mWidth != newImageInfo.mWidth || imageInfo->mHeight != newImageInfo.mHeight || imageInfo->mDepth != newImageInfo.mDepth || imageInfo->mFormat != newImageInfo.mFormat); const GLint xOffset = 0; const GLint yOffset = 0; @@ -1326,18 +1339,16 @@ void WebGLTexture::TexSubImage(TexImageT driverUnpackInfo->unpackType); mContext->ErrorInvalidOperation("%s", dui.BeginReading()); gfxCriticalError() << mContext->FuncName() << ": " << dui.BeginReading(); return; } //////////////////////////////////// // Update our specification data? - - imageInfo->mHasData = true; } //////////////////////////////////////// // CompressedTex(Sub)Image UniquePtr<webgl::TexUnpackBytes> WebGLContext::FromCompressed( TexImageTarget target, GLsizei rawWidth, GLsizei rawHeight, GLsizei rawDepth, GLint border, const TexImageSource& src, @@ -1433,19 +1444,19 @@ void WebGLTexture::CompressedTexImage(Te gfxCriticalError() << "Unexpected error from driver: " << call.BeginReading(); return; } //////////////////////////////////// // Update our specification data. - const bool isDataInitialized = true; + const auto uninitializedSlices = Nothing(); const webgl::ImageInfo newImageInfo{usage, blob->mWidth, blob->mHeight, - blob->mDepth, isDataInitialized}; + blob->mDepth, uninitializedSlices}; *imageInfo = newImageInfo; InvalidateCaches(); } static inline bool IsSubImageBlockAligned( const webgl::CompressedFormatInfo* compression, const webgl::ImageInfo* imageInfo, GLint xOffset, GLint yOffset, uint32_t width, uint32_t height) { @@ -1581,18 +1592,16 @@ void WebGLTexture::CompressedTexSubImage uint32_t(blob->mAvailBytes), error); gfxCriticalError() << "Unexpected error from driver: " << call.BeginReading(); return; } //////////////////////////////////// // Update our specification data? - - imageInfo->mHasData = true; } //////////////////////////////////////// // CopyTex(Sub)Image static bool ValidateCopyTexImageFormats(WebGLContext* webgl, const webgl::FormatInfo* srcFormat, const webgl::FormatInfo* dstFormat) { @@ -2095,19 +2104,19 @@ void WebGLTexture::CopyTexImage2D(TexIma return; } mContext->OnDataAllocCall(); //////////////////////////////////// // Update our specification data. - const bool isDataInitialized = true; + const auto uninitializedSlices = Nothing(); const webgl::ImageInfo newImageInfo{dstUsage, width, height, depth, - isDataInitialized}; + uninitializedSlices}; *imageInfo = newImageInfo; InvalidateCaches(); } void WebGLTexture::CopyTexSubImage(TexImageTarget target, GLint level, GLint xOffset, GLint yOffset, GLint zOffset, GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight) { @@ -2174,13 +2183,11 @@ void WebGLTexture::CopyTexSubImage(TexIm if (!DoCopyTexOrSubImage(mContext, isSubImage, this, target, level, x, y, srcTotalWidth, srcTotalHeight, srcUsage, xOffset, yOffset, zOffset, width, height, dstUsage)) { return; } //////////////////////////////////// // Update our specification data? - - imageInfo->mHasData = true; } } // namespace mozilla