diff --git a/dom/canvas/WebGLBuffer.cpp b/dom/canvas/WebGLBuffer.cpp index 52008c7aa4c24..cb744524bb1e1 100644 --- a/dom/canvas/WebGLBuffer.cpp +++ b/dom/canvas/WebGLBuffer.cpp @@ -115,106 +115,105 @@ WebGLBuffer::BufferData(GLenum target, size_t size, const void* data, GLenum usa } #endif - const void* uploadData = data; - - UniqueBuffer newIndexCache; - if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER && - mContext->mNeedsIndexValidation) - { - newIndexCache = malloc(size); - if (!newIndexCache) { - mContext->ErrorOutOfMemory("%s: Failed to alloc index cache.", funcName); - return; - } - memcpy(newIndexCache.get(), data, size); - uploadData = newIndexCache.get(); + const void* uploadData = data; + + UniqueBuffer newIndexCache; + if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER && + mContext->mNeedsIndexValidation) { + newIndexCache = malloc(size); + if (!newIndexCache) { + mContext->ErrorOutOfMemory("%s: Failed to alloc index cache.", funcName); + return; } + memcpy(newIndexCache.get(), data, size); + uploadData = newIndexCache.get(); + } - const auto& gl = mContext->gl; - gl->MakeCurrent(); - const ScopedLazyBind lazyBind(gl, target, this); - - const bool sizeChanges = (size != ByteLength()); - if (sizeChanges) { - mContext->InvalidateBufferFetching(); - - gl::GLContext::LocalErrorScope errorScope(*gl); - gl->fBufferData(target, size, uploadData, usage); - const auto error = errorScope.GetError(); - - if (error) { - MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); - mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, error); - return; - } - } else { - gl->fBufferData(target, size, uploadData, usage); + const auto& gl = mContext->gl; + const ScopedLazyBind lazyBind(gl, target, this); + + const bool sizeChanges = (size != ByteLength()); + if (sizeChanges) { + gl::GLContext::LocalErrorScope errorScope(*gl); + gl->fBufferData(target, size, uploadData, usage); + const auto error = errorScope.GetError(); + + if (error) { + MOZ_ASSERT(error == LOCAL_GL_OUT_OF_MEMORY); + mContext->ErrorOutOfMemory("%s: Error from driver: 0x%04x", funcName, + error); + + // Truncate + mByteLength = 0; + // mFetchInvalidator.InvalidateCaches(); + mIndexCache = nullptr; + return; } + } else { + gl->fBufferData(target, size, uploadData, usage); + } - mContext->OnDataAllocCall(); + mContext->OnDataAllocCall(); - mUsage = usage; - mByteLength = size; - mIndexCache = Move(newIndexCache); + mUsage = usage; + mByteLength = size; + mIndexCache = Move(newIndexCache); - if (mIndexCache) { - if (mIndexRanges.size()) { - mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this, - uint32_t(mIndexRanges.size())); - mIndexRanges.clear(); - } + if (mIndexCache) { + if (mIndexRanges.size()) { + mContext->GeneratePerfWarning("[%p] Invalidating %u ranges.", this, + uint32_t(mIndexRanges.size())); + mIndexRanges.clear(); } + } + } -void -WebGLBuffer::BufferSubData(GLenum target, size_t dstByteOffset, size_t dataLen, - const void* data) const -{ - const char funcName[] = "bufferSubData"; +void WebGLBuffer::BufferSubData(GLenum target, size_t dstByteOffset, + size_t dataLen, const void* data) const { + const char funcName[] = "bufferSubData"; - if (!ValidateRange(funcName, dstByteOffset, dataLen)) - return; + if (!ValidateRange(funcName, dstByteOffset, dataLen)) return; - if (!CheckedInt(dataLen).isValid()) - return mContext->ErrorOutOfMemory("%s: Size too large.", funcName); + if (!CheckedInt(dataLen).isValid()) + return mContext->ErrorOutOfMemory("%s: Size too large.", funcName); - //// + //// - const void* uploadData = data; - if (mIndexCache) { - const auto cachedDataBegin = (uint8_t*)mIndexCache.get() + dstByteOffset; - memcpy(cachedDataBegin, data, dataLen); - uploadData = cachedDataBegin; + const void* uploadData = data; + if (mIndexCache) { + const auto cachedDataBegin = (uint8_t*)mIndexCache.get() + dstByteOffset; + memcpy(cachedDataBegin, data, dataLen); + uploadData = cachedDataBegin; - InvalidateCacheRange(dstByteOffset, dataLen); - } + InvalidateCacheRange(dstByteOffset, dataLen); + } - //// + //// - const auto& gl = mContext->gl; - gl->MakeCurrent(); - const ScopedLazyBind lazyBind(gl, target, this); + const auto& gl = mContext->gl; + const ScopedLazyBind lazyBind(gl, target, this); - gl->fBufferSubData(target, dstByteOffset, dataLen, uploadData); + gl->fBufferSubData(target, dstByteOffset, dataLen, uploadData); } -bool -WebGLBuffer::ValidateRange(const char* funcName, size_t byteOffset, size_t byteLen) const -{ - auto availLength = mByteLength; - if (byteOffset > availLength) { - mContext->ErrorInvalidValue("%s: Offset passes the end of the buffer.", funcName); - return false; - } - availLength -= byteOffset; +bool WebGLBuffer::ValidateRange(const char* funcName, size_t byteOffset, + size_t byteLen) const { + auto availLength = mByteLength; + if (byteOffset > availLength) { + mContext->ErrorInvalidValue("%s: Offset passes the end of the buffer.", + funcName); + return false; + } + availLength -= byteOffset; - if (byteLen > availLength) { - mContext->ErrorInvalidValue("%s: Offset+size passes the end of the buffer.", - funcName); - return false; - } + if (byteLen > availLength) { + mContext->ErrorInvalidValue("%s: Offset+size passes the end of the buffer.", + funcName); + return false; + } - return true; + return true; } //////////////////////////////////////// diff --git a/dom/canvas/WebGLRenderbuffer.cpp b/dom/canvas/WebGLRenderbuffer.cpp index 6044076449f90..6d16cd53d2fc8 100644 --- a/dom/canvas/WebGLRenderbuffer.cpp +++ b/dom/canvas/WebGLRenderbuffer.cpp @@ -194,39 +194,37 @@ WebGLRenderbuffer::RenderbufferStorage(const char* funcName, uint32_t samples, mContext->ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer" " size.", funcName); - return; - } - - mContext->MakeContextCurrent(); - - if (!usage->maxSamplesKnown) { - const_cast(usage)->ResolveMaxSamples(mContext->gl); - } - MOZ_ASSERT(usage->maxSamplesKnown); - - if (samples > usage->maxSamples) { - mContext->ErrorInvalidOperation("%s: `samples` is out of the valid range.", funcName); - return; - } - - // Validation complete. - - const GLenum error = DoRenderbufferStorage(samples, usage, width, height); - if (error) { - const char* errorName = mContext->ErrorName(error); - mContext->GenerateWarning("%s generated error %s", funcName, errorName); - return; + return; + } + + // Validation complete. + + const GLenum error = DoRenderbufferStorage(samples, usage, width, height); + if (error) { + const char* errorName = mContext->ErrorName(error); + mContext->GenerateWarning("%s generated error %s", funcName, errorName); + if (error != LOCAL_GL_OUT_OF_MEMORY) { + // Truncate. + mSamples = 0; + mFormat = nullptr; + mWidth = 0; + mHeight = 0; + mImageDataStatus = WebGLImageDataStatus::NoImageData; + + InvalidateStatusOfAttachedFBs(funcName); } + return; + } - mContext->OnDataAllocCall(); + mContext->OnDataAllocCall(); - mSamples = samples; - mFormat = usage; - mWidth = width; - mHeight = height; - mImageDataStatus = WebGLImageDataStatus::UninitializedImageData; + mSamples = samples; + mFormat = usage; + mWidth = width; + mHeight = height; + mImageDataStatus = WebGLImageDataStatus::UninitializedImageData; - InvalidateStatusOfAttachedFBs(funcName); + InvalidateStatusOfAttachedFBs(funcName); } void diff --git a/dom/canvas/WebGLTexture.cpp b/dom/canvas/WebGLTexture.cpp index 6ee0ee770e112..b05b386d5b5c6 100644 --- a/dom/canvas/WebGLTexture.cpp +++ b/dom/canvas/WebGLTexture.cpp @@ -26,95 +26,74 @@ namespace mozilla { //////////////////////////////////////// template -static inline T& -Mutable(const T& x) -{ - return const_cast(x); +static inline T& Mutable(const T& x) { + return const_cast(x); } -void -WebGLTexture::ImageInfo::Clear(const char* funcName) -{ - if (!IsDefined()) - return; +void WebGLTexture::ImageInfo::Clear(const char* funcName) { + if (!IsDefined()) return; - OnRespecify(funcName); + OnRespecify(funcName); - Mutable(mFormat) = LOCAL_GL_NONE; - Mutable(mWidth) = 0; - Mutable(mHeight) = 0; - Mutable(mDepth) = 0; + Mutable(mFormat) = LOCAL_GL_NONE; + Mutable(mWidth) = 0; + Mutable(mHeight) = 0; + Mutable(mDepth) = 0; - MOZ_ASSERT(!IsDefined()); + MOZ_ASSERT(!IsDefined()); } -void -WebGLTexture::ImageInfo::Set(const char* funcName, const ImageInfo& a) -{ - MOZ_ASSERT(a.IsDefined()); - - Mutable(mFormat) = a.mFormat; - Mutable(mWidth) = a.mWidth; - Mutable(mHeight) = a.mHeight; - Mutable(mDepth) = a.mDepth; +void WebGLTexture::ImageInfo::Set(const char* funcName, const ImageInfo& a) { + Mutable(mFormat) = a.mFormat; + Mutable(mWidth) = a.mWidth; + Mutable(mHeight) = a.mHeight; + Mutable(mDepth) = a.mDepth; - mIsDataInitialized = a.mIsDataInitialized; + mIsDataInitialized = a.mIsDataInitialized; - // But *don't* transfer mAttachPoints! - MOZ_ASSERT(a.mAttachPoints.empty()); - OnRespecify(funcName); + // But *don't* transfer mAttachPoints! + MOZ_ASSERT(a.mAttachPoints.empty()); + OnRespecify(funcName); } -bool -WebGLTexture::ImageInfo::IsPowerOfTwo() const -{ - return mozilla::IsPowerOfTwo(mWidth) && - mozilla::IsPowerOfTwo(mHeight) && - mozilla::IsPowerOfTwo(mDepth); +bool WebGLTexture::ImageInfo::IsPowerOfTwo() const { + return mozilla::IsPowerOfTwo(mWidth) && mozilla::IsPowerOfTwo(mHeight) && + mozilla::IsPowerOfTwo(mDepth); } -void -WebGLTexture::ImageInfo::AddAttachPoint(WebGLFBAttachPoint* attachPoint) -{ - const auto pair = mAttachPoints.insert(attachPoint); - DebugOnly didInsert = pair.second; - MOZ_ASSERT(didInsert); +void WebGLTexture::ImageInfo::AddAttachPoint(WebGLFBAttachPoint* attachPoint) { + const auto pair = mAttachPoints.insert(attachPoint); + DebugOnly didInsert = pair.second; + MOZ_ASSERT(didInsert); } -void -WebGLTexture::ImageInfo::RemoveAttachPoint(WebGLFBAttachPoint* attachPoint) -{ - DebugOnly numElemsErased = mAttachPoints.erase(attachPoint); - MOZ_ASSERT_IF(IsDefined(), numElemsErased == 1); +void WebGLTexture::ImageInfo::RemoveAttachPoint( + WebGLFBAttachPoint* attachPoint) { + DebugOnly numElemsErased = mAttachPoints.erase(attachPoint); + MOZ_ASSERT_IF(IsDefined(), numElemsErased == 1); } -void -WebGLTexture::ImageInfo::OnRespecify(const char* funcName) const -{ - for (auto cur : mAttachPoints) { - cur->OnBackingStoreRespecified(funcName); - } +void WebGLTexture::ImageInfo::OnRespecify(const char* funcName) const { + for (auto cur : mAttachPoints) { + cur->OnBackingStoreRespecified(funcName); + } } -size_t -WebGLTexture::ImageInfo::MemoryUsage() const -{ - if (!IsDefined()) - return 0; +size_t WebGLTexture::ImageInfo::MemoryUsage() const { + if (!IsDefined()) return 0; - const auto bytesPerTexel = mFormat->format->estimatedBytesPerPixel; - return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bytesPerTexel; + const auto bytesPerTexel = mFormat->format->estimatedBytesPerPixel; + return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bytesPerTexel; } -void -WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, WebGLTexture* tex) -{ - MOZ_ASSERT(tex); - MOZ_ASSERT(this >= &tex->mImageInfoArr[0]); - MOZ_ASSERT(this < &tex->mImageInfoArr[kMaxLevelCount * kMaxFaceCount]); +void WebGLTexture::ImageInfo::SetIsDataInitialized(bool isDataInitialized, + WebGLTexture* tex) { + MOZ_ASSERT(tex); + MOZ_ASSERT(this >= &tex->mImageInfoArr[0]); + MOZ_ASSERT(this < &tex->mImageInfoArr[kMaxLevelCount * kMaxFaceCount]); - mIsDataInitialized = isDataInitialized; - tex->InvalidateResolveCache(); + mIsDataInitialized = isDataInitialized; + tex->InvalidateResolveCache(); } //////////////////////////////////////// @@ -1222,6 +1201,12 @@ WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& mContext->gl->fTexParameterf(texTarget.get(), pname, clamped.f); } +void WebGLTexture::Truncate() { + for (auto& cur : mImageInfoArr) { + SetImageInfo("OUT_OF_MEMORY", &cur, ImageInfo()); + } +} + //////////////////////////////////////////////////////////////////////////////// NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture) diff --git a/dom/canvas/WebGLTexture.h b/dom/canvas/WebGLTexture.h index 62a6c61cc6b13..c18dd12526c9e 100644 --- a/dom/canvas/WebGLTexture.h +++ b/dom/canvas/WebGLTexture.h @@ -387,6 +387,7 @@ class WebGLTexture final bool* const out_initFailed); bool IsMipmapCubeComplete() const; + void Truncate(); bool IsCubeMap() const { return (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP); } diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index b568b32bf212b..851db0bf9314e 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -1169,6 +1169,7 @@ WebGLTexture::TexStorage(const char* funcName, TexTarget target, GLsizei levels, if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during texture allocation.", funcName); + Truncate(); return; } if (error) { @@ -1303,6 +1304,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level, if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1391,6 +1393,7 @@ WebGLTexture::TexSubImage(const char* funcName, TexImageTarget target, GLint lev if (glError == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Driver ran out of memory during upload.", funcName); + Truncate(); return; } @@ -1508,6 +1511,7 @@ WebGLTexture::CompressedTexImage(const char* funcName, TexImageTarget target, GL mContext->OnDataAllocCall(); if (error == LOCAL_GL_OUT_OF_MEMORY) { mContext->ErrorOutOfMemory("%s: Ran out of memory during upload.", funcName); + Truncate(); return; } if (error) { @@ -2000,7 +2004,7 @@ WebGLTexture::ValidateCopyTexImageForFeedback(const char* funcName, uint32_t lev static bool DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, - const WebGLTexture* tex, TexImageTarget target, GLint level, + WebGLTexture* tex, TexImageTarget target, GLint level, GLint xWithinSrc, GLint yWithinSrc, uint32_t srcTotalWidth, uint32_t srcTotalHeight, const webgl::FormatUsageInfo* srcUsage, @@ -2077,6 +2081,7 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, if (error == LOCAL_GL_OUT_OF_MEMORY) { webgl->ErrorOutOfMemory("%s: Ran out of memory during texture copy.", funcName); + tex->Truncate(); return false; }