Bug 1506665 - Add more GLContext failure handling r=jgilbert
authorsotaro <sotaro.ikeda.g@gmail.com>
Fri, 01 Mar 2019 22:37:37 +0000
changeset 519929 86fe7556c9af2059d858e9eb0c7afca4c1ba65d0
parent 519928 efec51b1aaf2bab63edb2eced66637eb1e030a17
child 519930 f8f4200ccbb9b054ec7196761287d688e0a55742
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1506665
milestone67.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
Bug 1506665 - Add more GLContext failure handling r=jgilbert Differential Revision: https://phabricator.services.mozilla.com/D19623
dom/canvas/WebGLContext.cpp
gfx/layers/CanvasRenderer.cpp
gfx/layers/CanvasRenderer.h
gfx/layers/CopyableCanvasRenderer.cpp
gfx/layers/client/CanvasClient.cpp
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1145,16 +1145,21 @@ already_AddRefed<layers::Layer> WebGLCon
     userData = new WebGLContextUserData(mCanvasElement);
   }
 
   canvasLayer->SetUserData(&gWebGLLayerUserData, userData);
 
   CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
   if (!InitializeCanvasRenderer(builder, canvasRenderer)) return nullptr;
 
+  if (!gl) {
+    NS_WARNING("GLContext is null!");
+    return nullptr;
+  }
+
   uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
   canvasLayer->SetContentFlags(flags);
 
   mResetLayer = false;
 
   return canvasLayer.forget();
 }
 
@@ -1198,20 +1203,20 @@ bool WebGLContext::InitializeCanvasRende
     // The userData will receive DidTransactionCallbacks, which flush the
     // 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.mHasAlpha = mOptions.alpha;
   data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
+  data.mGLContext = gl;
 
   aRenderer->Initialize(data);
   aRenderer->SetDirty();
   mVRReady = true;
   return true;
 }
 
 layers::LayersBackend WebGLContext::GetCompositorBackendType() const {
--- a/gfx/layers/CanvasRenderer.cpp
+++ b/gfx/layers/CanvasRenderer.cpp
@@ -4,16 +4,19 @@
  * 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 "CanvasRenderer.h"
 
 namespace mozilla {
 namespace layers {
 
+CanvasInitializeData::CanvasInitializeData() = default;
+CanvasInitializeData::~CanvasInitializeData() = default;
+
 CanvasRenderer::CanvasRenderer()
     : mPreTransCallback(nullptr),
       mPreTransCallbackData(nullptr),
       mDidTransCallback(nullptr),
       mDidTransCallbackData(nullptr),
       mDirty(false) {
   MOZ_COUNT_CTOR(CanvasRenderer);
 }
--- a/gfx/layers/CanvasRenderer.h
+++ b/gfx/layers/CanvasRenderer.h
@@ -23,49 +23,40 @@ namespace mozilla {
 namespace layers {
 
 class AsyncCanvasRenderer;
 class ClientCanvasRenderer;
 class CopyableCanvasRenderer;
 class PersistentBufferProvider;
 class WebRenderCanvasRendererAsync;
 
-struct CanvasInitializeData {
-  CanvasInitializeData()
-      : mBufferProvider(nullptr),
-        mGLContext(nullptr),
-        mRenderer(nullptr),
-        mPreTransCallback(nullptr),
-        mPreTransCallbackData(nullptr),
-        mDidTransCallback(nullptr),
-        mDidTransCallbackData(nullptr),
-        mSize(0, 0),
-        mHasAlpha(false),
-        mIsGLAlphaPremult(true) {}
+struct CanvasInitializeData final {
+  CanvasInitializeData();
+  ~CanvasInitializeData();
 
   // One of these three must be specified for Canvas2D, but never more than one
-  PersistentBufferProvider*
+  RefPtr<PersistentBufferProvider>
       mBufferProvider;  // A BufferProvider for the Canvas contents
-  mozilla::gl::GLContext* mGLContext;  // or this, for GL.
-  AsyncCanvasRenderer* mRenderer;      // or this, for OffscreenCanvas
+  RefPtr<mozilla::gl::GLContext> mGLContext;  // or this, for GL.
+  RefPtr<AsyncCanvasRenderer> mRenderer;      // or this, for OffscreenCanvas
 
   typedef void (*TransactionCallback)(void* closureData);
-  TransactionCallback mPreTransCallback;
-  void* mPreTransCallbackData;
-  TransactionCallback mDidTransCallback;
-  void* mDidTransCallbackData;
+  TransactionCallback mPreTransCallback = nullptr;
+  void* mPreTransCallbackData = nullptr;
+  TransactionCallback mDidTransCallback = nullptr;
+  void* mDidTransCallbackData = nullptr;
 
   // The size of the canvas content
-  gfx::IntSize mSize;
+  gfx::IntSize mSize = {0,0};
 
   // Whether the canvas drawingbuffer has an alpha channel.
-  bool mHasAlpha;
+  bool mHasAlpha = false;
 
   // Whether mGLContext contains data that is alpha-premultiplied.
-  bool mIsGLAlphaPremult;
+  bool mIsGLAlphaPremult = true;
 };
 
 // Based class which used for canvas rendering. There are many derived classes
 // for different purposes. such as:
 //
 // CopyableCanvasRenderer provides a utility which readback canvas content to a
 // SourceSurface. BasicCanvasLayer uses CopyableCanvasRenderer.
 //
--- a/gfx/layers/CopyableCanvasRenderer.cpp
+++ b/gfx/layers/CopyableCanvasRenderer.cpp
@@ -48,31 +48,30 @@ CopyableCanvasRenderer::~CopyableCanvasR
   Destroy();
   MOZ_COUNT_DTOR(CopyableCanvasRenderer);
 }
 
 void CopyableCanvasRenderer::Initialize(const CanvasInitializeData& aData) {
   CanvasRenderer::Initialize(aData);
 
   if (aData.mGLContext) {
+    if (aData.mGLContext->IsDestroyed()) {
+      return;
+    }
     mGLContext = aData.mGLContext;
     mIsAlphaPremultiplied = aData.mIsGLAlphaPremult;
     mOriginPos = gl::OriginPos::BottomLeft;
 
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
   } else if (aData.mBufferProvider) {
     mBufferProvider = aData.mBufferProvider;
   } else if (aData.mRenderer) {
     mAsyncRenderer = aData.mRenderer;
     mOriginPos = gl::OriginPos::BottomLeft;
-  } else {
-    MOZ_CRASH(
-        "GFX: CanvasRenderer created without BufferProvider, DrawTarget or "
-        "GLContext?");
   }
 
   mOpaque = !aData.mHasAlpha;
 }
 
 bool CopyableCanvasRenderer::IsDataValid(const CanvasInitializeData& aData) {
   return mGLContext == aData.mGLContext &&
          mBufferProvider == aData.mBufferProvider;
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -290,18 +290,20 @@ static already_AddRefed<TextureClient> T
     } else if (readFormat == LOCAL_GL_RGBA &&
                readType == LOCAL_GL_UNSIGNED_BYTE) {
       // [RR, GG, BB, AA]
       texClient = factory.CreateR8G8B8AX8();
     } else {
       MOZ_CRASH("GFX: Bad `read{Format,Type}`.");
     }
 
-    MOZ_ASSERT(texClient);
-    if (!texClient) return nullptr;
+    if (!texClient) {
+      gfxWarning() << "Couldn't create texClient for readback.";
+      return nullptr;
+    }
 
     // With a texClient, we can lock for writing.
     TextureClientAutoLock autoLock(texClient, OpenMode::OPEN_WRITE);
     DebugOnly<bool> succeeded = autoLock.Succeeded();
     MOZ_ASSERT(succeeded, "texture should have locked");
 
     MappedTextureData mapped;
     texClient->BorrowMappedData(mapped);
@@ -450,20 +452,19 @@ void CanvasClientSharedSurface::UpdateRe
     //
     // Otherwise, if surface type isn't Basic, we will read from
     // SharedSurface directly from main-thread. We still pass
     // mReadbackClient which is nullptr here to tell
     // AsyncCanvasRenderer reset some properties.
     asyncRenderer->CopyFromTextureClient(mReadbackClient);
   }
 
-  MOZ_ASSERT(newFront);
   if (!newFront) {
     // May happen in a release build in case of memory pressure.
-    gfxCriticalError()
+    gfxWarning()
         << "Failed to allocate a TextureClient for SharedSurface Canvas. Size: "
         << aSize;
     return;
   }
 
   mNewFront = newFront;
 }