Bug 1427668 - Lose context if EnsureDefaultFB fails. - r=daoshengmu
MozReview-Commit-ID: 8OqXYXpUv4I
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1942,28 +1942,16 @@ CanvasRenderingContext2D::TryBasicTarget
if (!aOutDT) {
return false;
}
aOutProvider = new PersistentBufferProviderBasic(aOutDT);
return true;
}
-int32_t
-CanvasRenderingContext2D::GetWidth() const
-{
- return mWidth;
-}
-
-int32_t
-CanvasRenderingContext2D::GetHeight() const
-{
- return mHeight;
-}
-
NS_IMETHODIMP
CanvasRenderingContext2D::SetDimensions(int32_t aWidth, int32_t aHeight)
{
ClearTarget();
// Zero sized surfaces can cause problems.
mZero = false;
if (aHeight == 0) {
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -421,19 +421,19 @@ public:
bool SwitchRenderingMode(RenderingMode aRenderingMode);
// Eventually this should be deprecated. Keeping for now to keep the binding functional.
void Demote();
nsresult Redraw();
- virtual int32_t GetWidth() const override;
- virtual int32_t GetHeight() const override;
gfx::IntSize GetSize() const { return gfx::IntSize(mWidth, mHeight); }
+ virtual int32_t GetWidth() override { return GetSize().width; }
+ virtual int32_t GetHeight() override { return GetSize().height; }
// nsICanvasRenderingContextInternal
/**
* Gets the pres shell from either the canvas element or the doc shell
*/
virtual nsIPresShell *GetPresShell() override {
if (mCanvasElement) {
return mCanvasElement->OwnerDoc()->GetShell();
--- a/dom/canvas/ImageBitmapRenderingContext.cpp
+++ b/dom/canvas/ImageBitmapRenderingContext.cpp
@@ -65,28 +65,16 @@ ImageBitmapRenderingContext::TransferFro
if (!mImage) {
return;
}
Redraw(gfxRect(0, 0, mWidth, mHeight));
}
-int32_t
-ImageBitmapRenderingContext::GetWidth() const
-{
- return mWidth;
-}
-
-int32_t
-ImageBitmapRenderingContext::GetHeight() const
-{
- return mHeight;
-}
-
NS_IMETHODIMP
ImageBitmapRenderingContext::SetDimensions(int32_t aWidth, int32_t aHeight)
{
mWidth = aWidth;
mHeight = aHeight;
return NS_OK;
}
--- a/dom/canvas/ImageBitmapRenderingContext.h
+++ b/dom/canvas/ImageBitmapRenderingContext.h
@@ -45,18 +45,18 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ImageBitmapRenderingContext)
void TransferImageBitmap(ImageBitmap& aImageBitmap);
void TransferFromImageBitmap(ImageBitmap& aImageBitmap);
// nsICanvasRenderingContextInternal
- virtual int32_t GetWidth() const override;
- virtual int32_t GetHeight() const override;
+ virtual int32_t GetWidth() override { return mWidth; }
+ virtual int32_t GetHeight() override { return mHeight; }
NS_IMETHOD SetDimensions(int32_t aWidth, int32_t aHeight) override;
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell* aDocShell,
NotNull<gfx::DrawTarget*> aTarget) override;
virtual mozilla::UniquePtr<uint8_t[]> GetImageBuffer(int32_t* aFormat) override;
NS_IMETHOD GetInputStream(const char* aMimeType,
--- a/dom/canvas/WebGL2ContextFramebuffers.cpp
+++ b/dom/canvas/WebGL2ContextFramebuffers.cpp
@@ -174,17 +174,17 @@ WebGLContext::ValidateInvalidateFramebuf
MOZ_CRASH("GFX: Bad target.");
}
if (fb) {
const auto fbStatus = fb->CheckFramebufferStatus(funcName);
if (fbStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return false; // Not an error, but don't run forward to driver either.
} else {
- if (!EnsureDefaultFB())
+ if (!EnsureDefaultFB(funcName))
return false;
}
DoBindFB(fb, target);
*out_glNumAttachments = attachments.Length();
*out_glAttachments = attachments.Elements();
if (fb) {
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -735,17 +735,17 @@ WebGLContext::CreateAndInitGL(bool force
out_failReasons->push_back(FailureReason("FEATURE_FAILURE_WEBGL_EXHAUSTED_DRIVERS",
"Exhausted GL driver options."));
return false;
}
// Fallback for resizes:
bool
-WebGLContext::EnsureDefaultFB() const
+WebGLContext::EnsureDefaultFB(const char* const funcName)
{
if (mDefaultFB) {
MOZ_ASSERT(mDefaultFB->mSize == mRequestedSize);
return true;
}
const bool depthStencil = mOptions.depth || mOptions.stencil;
auto attemptSize = mRequestedSize;
@@ -771,27 +771,31 @@ WebGLContext::EnsureDefaultFB() const
if (mDefaultFB)
break;
attemptSize.width /= 2;
attemptSize.height /= 2;
}
- if (!mDefaultFB)
+ if (!mDefaultFB) {
+ GenerateWarning("%s: Backbuffer resize failed. Losing context.", funcName);
+ ForceLoseContext();
return false;
+ }
mDefaultFB_IsInvalid = true;
if (mDefaultFB->mSize != mRequestedSize) {
GenerateWarning("Requested size %dx%d was too large, but resize"
" to %dx%d succeeded.",
mRequestedSize.width, mRequestedSize.height,
mDefaultFB->mSize.width, mDefaultFB->mSize.height);
}
+ mRequestedSize = mDefaultFB->mSize;
return true;
}
void
WebGLContext::ThrowEvent_WebGLContextCreationError(const nsACString& text)
{
RefPtr<EventTarget> target = mCanvasElement;
if (!target && mOffscreenCanvas) {
@@ -964,17 +968,16 @@ WebGLContext::SetDimensions(int32_t sign
text.AppendASCII("\n* ");
text.Append(cur.info);
}
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_REASON");
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}
MOZ_ASSERT(gl);
- MOZ_ASSERT_IF(mOptions.alpha, gl->Caps().alpha);
if (mOptions.failIfMajorPerformanceCaveat) {
if (gl->IsWARP()) {
DestroyResourcesAndContext();
MOZ_ASSERT(!gl);
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_PERF_WARP");
const nsLiteralCString text("failIfMajorPerformanceCaveat: Driver is not"
@@ -995,17 +998,19 @@ WebGLContext::SetDimensions(int32_t sign
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}
#endif
}
MOZ_ASSERT(!mDefaultFB);
mRequestedSize = {width, height};
- if (!EnsureDefaultFB()) {
+ if (!EnsureDefaultFB("context initialization")) {
+ MOZ_ASSERT(!gl);
+
failureId = NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBGL_BACKBUFFER");
const nsLiteralCString text("Initializing WebGL backbuffer failed.");
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}
if (GLContext::ShouldSpew()) {
printf_stderr("--- WebGL context created: %p\n", gl.get());
@@ -1315,17 +1320,17 @@ WebGLContext::InitializeCanvasRenderer(n
// the invalidation state to indicate that the canvas is up to date.
data.mPreTransCallback = WebGLContextUserData::PreTransactionCallback;
data.mPreTransCallbackData = this;
data.mDidTransCallback = WebGLContextUserData::DidTransactionCallback;
data.mDidTransCallbackData = this;
}
data.mGLContext = gl;
- data.mSize = DrawingBufferSize();
+ data.mSize = DrawingBufferSize("InitializeCanvasRenderer");
data.mHasAlpha = mOptions.alpha;
data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
aRenderer->Initialize(data);
aRenderer->SetDirty();
return true;
}
@@ -1956,40 +1961,37 @@ WebGLContext::DidRefresh()
if (gl) {
gl->FlushIfHeavyGLCallsSinceLastFlush();
}
}
////////////////////////////////////////////////////////////////////////////////
gfx::IntSize
-WebGLContext::DrawingBufferSize() const
+WebGLContext::DrawingBufferSize(const char* const funcName)
{
const gfx::IntSize zeros{0, 0};
if (IsContextLost())
return zeros;
- if (!EnsureDefaultFB())
+ if (!EnsureDefaultFB(funcName))
return zeros;
return mDefaultFB->mSize;
}
bool
WebGLContext::ValidateAndInitFB(const char* const funcName,
const WebGLFramebuffer* const fb)
{
if (fb)
return fb->ValidateAndInitAttachments(funcName);
- if (!EnsureDefaultFB()) {
- GenerateWarning("%s: Lazy resize failed. Losing context.", funcName);
- ForceLoseContext();
+ if (!EnsureDefaultFB(funcName))
return false;
- }
if (mDefaultFB_IsInvalid) {
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mDefaultFB->mFB);
const GLbitfield bits = LOCAL_GL_COLOR_BUFFER_BIT |
LOCAL_GL_DEPTH_BUFFER_BIT |
LOCAL_GL_STENCIL_BUFFER_BIT;
const bool fakeNoAlpha = !mOptions.alpha;
ForceClearFramebufferWithDefaultValues(bits, fakeNoAlpha);
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -337,18 +337,18 @@ public:
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override = 0;
NS_DECL_NSIDOMWEBGLRENDERINGCONTEXT
virtual void OnVisibilityChange() override;
virtual void OnMemoryPressure() override;
// nsICanvasRenderingContextInternal
- virtual int32_t GetWidth() const override { return DrawingBufferWidth(); }
- virtual int32_t GetHeight() const override { return DrawingBufferHeight(); }
+ virtual int32_t GetWidth() override { return DrawingBufferWidth("get width"); }
+ virtual int32_t GetHeight() override { return DrawingBufferHeight("get height"); }
NS_IMETHOD SetDimensions(int32_t width, int32_t height) override;
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*,
NotNull<gfx::DrawTarget*>) override
{
return NS_ERROR_NOT_IMPLEMENTED;
}
@@ -496,20 +496,24 @@ public:
dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
nsIDocument* GetOwnerDoc() const;
// WebIDL WebGLRenderingContext API
void Commit();
void GetCanvas(Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval);
private:
- gfx::IntSize DrawingBufferSize() const;
+ gfx::IntSize DrawingBufferSize(const char* funcName);
public:
- GLsizei DrawingBufferWidth() const { return DrawingBufferSize().width; }
- GLsizei DrawingBufferHeight() const { return DrawingBufferSize().height; }
+ GLsizei DrawingBufferWidth(const char* const funcName = "drawingBufferWidth") {
+ return DrawingBufferSize(funcName).width;
+ }
+ GLsizei DrawingBufferHeight(const char* const funcName = "drawingBufferHeight") {
+ return DrawingBufferSize(funcName).height;
+ }
layers::LayersBackend GetCompositorBackendType() const;
void
GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
bool IsContextLost() const { return mContextStatus != ContextNotLost; }
void GetSupportedExtensions(dom::Nullable< nsTArray<nsString> >& retval,
@@ -1985,24 +1989,24 @@ protected:
const bool mAllowFBInvalidation;
bool Has64BitTimestamps() const;
// --
const uint8_t mMsaaSamples;
- gfx::IntSize mRequestedSize;
+ mutable gfx::IntSize mRequestedSize;
mutable UniquePtr<gl::MozFramebuffer> mDefaultFB;
mutable bool mDefaultFB_IsInvalid;
mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB;
// --
- bool EnsureDefaultFB() const;
+ bool EnsureDefaultFB(const char* funcName);
bool ValidateAndInitFB(const char* funcName, const WebGLFramebuffer* fb);
void DoBindFB(const WebGLFramebuffer* fb, GLenum target = LOCAL_GL_FRAMEBUFFER) const;
bool BindCurFBForDraw(const char* funcName);
bool BindCurFBForColorRead(const char* funcName,
const webgl::FormatUsageInfo** out_format,
uint32_t* out_width, uint32_t* out_height);
void DoColorMask(uint8_t bitmask) const;
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -357,17 +357,17 @@ WebGLContext::GetParameter(JSContext* cx
return JS::Int32Value(refValue & stencilMask);
}
case LOCAL_GL_SAMPLE_BUFFERS:
case LOCAL_GL_SAMPLES: {
const auto& fb = mBoundDrawFramebuffer;
auto samples = [&]() -> Maybe<uint32_t> {
if (!fb) {
- if (!EnsureDefaultFB())
+ if (!EnsureDefaultFB(funcName))
return Nothing();
return Some(mDefaultFB->mSamples);
}
if (!fb->IsCheckFramebufferStatusComplete(funcName))
return Some(0);
DoBindFB(fb, LOCAL_GL_FRAMEBUFFER);
--- a/dom/canvas/nsICanvasRenderingContextInternal.h
+++ b/dom/canvas/nsICanvasRenderingContextInternal.h
@@ -88,18 +88,18 @@ public:
}
void SetOffscreenCanvas(mozilla::dom::OffscreenCanvas* aOffscreenCanvas)
{
mOffscreenCanvas = aOffscreenCanvas;
}
// Dimensions of the canvas, in pixels.
- virtual int32_t GetWidth() const = 0;
- virtual int32_t GetHeight() const = 0;
+ virtual int32_t GetWidth() = 0;
+ virtual int32_t GetHeight() = 0;
// Sets the dimensions of the canvas, in pixels. Called
// whenever the size of the element changes.
NS_IMETHOD SetDimensions(int32_t width, int32_t height) = 0;
// Initializes with an nsIDocShell and DrawTarget. The size is taken from the
// DrawTarget.
NS_IMETHOD InitializeWithDrawTarget(nsIDocShell *aDocShell,
--- a/gfx/gl/MozFramebuffer.cpp
+++ b/gfx/gl/MozFramebuffer.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MozFramebuffer.h"
#include "GLContext.h"
+#include "mozilla/gfx/Logging.h"
#include "ScopedGLHelpers.h"
namespace mozilla {
namespace gl {
static void
DeleteByTarget(GLContext* const gl, const GLenum target, const GLuint name)
{
@@ -56,17 +57,20 @@ MozFramebuffer::Create(GLContext* const
gl->fBindBuffer(LOCAL_GL_PIXEL_UNPACK_BUFFER, 0);
gl->fTexImage2D(colorTarget, 0, LOCAL_GL_RGBA,
size.width, size.height, 0,
LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr);
}
const auto err = errorScope.GetError();
if (err) {
- MOZ_ASSERT(err == LOCAL_GL_OUT_OF_MEMORY);
+ if (err != LOCAL_GL_OUT_OF_MEMORY) {
+ gfxCriticalNote << "Unexpected error: " << gfx::hexa(err) << ": "
+ << GLContext::GLErrorToString(err);
+ }
DeleteByTarget(gl, colorTarget, colorName);
return nullptr;
}
return CreateWith(gl, size, samples, depthStencil, colorTarget, colorName);
}
UniquePtr<MozFramebuffer>