Bug 1391136 - Handle context lost in layers-free mode. r=jgilbert
authorMorris Tseng <mtseng@mozilla.com>
Fri, 18 Aug 2017 15:13:29 +0800
changeset 427578 682c2b84072489db964cbd5967a568cafb554c4b
parent 427577 34d11e7339f31468077ff67c895908affc0414da
child 427579 7cbc5c672ea43e4868801a7e999241dd65b40088
push id1567
push userjlorenzo@mozilla.com
push dateThu, 02 Nov 2017 12:36:05 +0000
treeherdermozilla-release@e512c14a0406 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1391136
milestone57.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 1391136 - Handle context lost in layers-free mode. r=jgilbert MozReview-Commit-ID: 1J0EggRmM4i
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/nsICanvasRenderingContextInternal.h
dom/html/HTMLCanvasElement.cpp
dom/html/HTMLCanvasElement.h
layout/generic/nsHTMLCanvasFrame.cpp
layout/generic/nsHTMLCanvasFrame.h
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -6284,17 +6284,17 @@ CanvasRenderingContext2D::GetCanvasLayer
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
 
   mResetLayer = false;
 
   return canvasLayer.forget();
 }
 
-void
+bool
 CanvasRenderingContext2D::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                                    CanvasRenderer* aRenderer,
                                                    bool aMirror)
 {
   CanvasInitializeData data;
   data.mSize = GetSize();
   data.mHasAlpha = !mOpaque;
   data.mPreTransCallback = CanvasRenderingContext2DUserData::PreTransactionCallback;
@@ -6311,16 +6311,17 @@ CanvasRenderingContext2D::InitializeCanv
         data.mFrontbufferGLTex = skiaGLTex;
       }
   }
 
   data.mBufferProvider = mBufferProvider;
 
   aRenderer->Initialize(data);
   aRenderer->SetDirty();
+  return true;
 }
 
 void
 CanvasRenderingContext2D::MarkContextClean()
 {
   if (mInvalidateCount > 0) {
     mPredictManyRedrawCalls = mInvalidateCount > kCanvasMaxInvalidateCount;
   }
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -463,17 +463,17 @@ public:
 
   virtual void SetIsOpaque(bool aIsOpaque) override;
   bool GetIsOpaque() override { return mOpaque; }
   NS_IMETHOD Reset() override;
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer* aOldLayer,
                                          LayerManager* aManager,
                                          bool aMirror = false) override;
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer,
                                 bool aMirror = false) override;
   virtual bool ShouldForceInactiveLayer(LayerManager* aManager) override;
   void MarkContextClean() override;
   void MarkContextCleanForFrameCapture() override;
   bool IsContextCleanForFrameCapture() override;
   NS_IMETHOD SetIsIPC(bool aIsIPC) override;
   // this rect is in canvas device space
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -1317,19 +1317,16 @@ private:
 };
 
 already_AddRefed<layers::Layer>
 WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
                              Layer* oldLayer,
                              LayerManager* manager,
                              bool aMirror /*= false*/)
 {
-    if (IsContextLost())
-        return nullptr;
-
     if (!mResetLayer && oldLayer &&
         oldLayer->HasUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData)) {
         RefPtr<layers::Layer> ret = oldLayer;
         return ret.forget();
     }
 
     RefPtr<CanvasLayer> canvasLayer = manager->CreateCanvasLayer();
     if (!canvasLayer) {
@@ -1340,34 +1337,39 @@ WebGLContext::GetCanvasLayer(nsDisplayLi
     WebGLContextUserData* userData = nullptr;
     if (builder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         userData = new WebGLContextUserData(mCanvasElement);
     }
 
     canvasLayer->SetUserData(aMirror ? &gWebGLMirrorLayerUserData : &gWebGLLayerUserData, userData);
 
     CanvasRenderer* canvasRenderer = canvasLayer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(builder, canvasRenderer, aMirror);
+    if (!InitializeCanvasRenderer(builder, canvasRenderer, aMirror))
+      return nullptr;
+
     uint32_t flags = gl->Caps().alpha ? 0 : Layer::CONTENT_OPAQUE;
     canvasLayer->SetContentFlags(flags);
 
     mResetLayer = false;
     // We only wish to update mLayerIsMirror when a new layer is returned.
     // If a cached layer is returned above, aMirror is not changing since
     // the last cached layer was created and mLayerIsMirror is still valid.
     mLayerIsMirror = aMirror;
 
     return canvasLayer.forget();
 }
 
-void
+bool
 WebGLContext::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                        CanvasRenderer* aRenderer,
                                        bool aMirror)
 {
+    if (IsContextLost())
+        return false;
+
     CanvasInitializeData data;
     if (aBuilder->IsPaintingToWindow() && mCanvasElement && !aMirror) {
         // Make the layer tell us whenever a transaction finishes (including
         // the current transaction), so we can clear our invalidation state and
         // start invalidating again. We need to do this for the layer that is
         // being painted to a window (there shouldn't be more than one at a time,
         // and if there is, flushing the invalidation state more often than
         // necessary is harmless).
@@ -1386,16 +1388,17 @@ WebGLContext::InitializeCanvasRenderer(n
     data.mGLContext = gl;
     data.mSize = nsIntSize(mWidth, mHeight);
     data.mHasAlpha = gl->Caps().alpha;
     data.mIsGLAlphaPremult = IsPremultAlpha() || !data.mHasAlpha;
     data.mIsMirror = aMirror;
 
     aRenderer->Initialize(data);
     aRenderer->SetDirty();
+    return true;
 }
 
 layers::LayersBackend
 WebGLContext::GetCompositorBackendType() const
 {
     if (mCanvasElement) {
         return mCanvasElement->GetCompositorBackendType();
     } else if (mOffscreenCanvas) {
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -457,17 +457,17 @@ public:
     }
 
     void InvalidateResolveCacheForTextureWithTexUnit(const GLuint);
 
     already_AddRefed<Layer>
     GetCanvasLayer(nsDisplayListBuilder* builder, Layer* oldLayer,
                    LayerManager* manager,
                    bool aMirror = false) override;
-    void
+    bool
     InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                              CanvasRenderer* aRenderer,
                              bool aMirror = false) override;
 
     // Note that 'clean' here refers to its invalidation state, not the
     // contents of the buffer.
     void MarkContextClean() override { mInvalidated = false; }
 
--- a/dom/canvas/nsICanvasRenderingContextInternal.h
+++ b/dom/canvas/nsICanvasRenderingContextInternal.h
@@ -136,19 +136,19 @@ public:
   NS_IMETHOD Reset() = 0;
 
   // Return the CanvasLayer for this context, creating
   // one for the given layer manager if not available.
   virtual already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* builder,
                                                  Layer *oldLayer,
                                                  LayerManager *manager,
                                                  bool aMirror = false) = 0;
-  virtual void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  virtual bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                         CanvasRenderer* aRenderer,
-                                        bool aMirror = false) { };
+                                        bool aMirror = false) { return true; }
 
   // Return true if the canvas should be forced to be "inactive" to ensure
   // it can be drawn to the screen even if it's too large to be blitted by
   // an accelerated CanvasLayer.
   virtual bool ShouldForceInactiveLayer(LayerManager *manager) { return false; }
 
   virtual void MarkContextClean() = 0;
 
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -1183,39 +1183,45 @@ HTMLCanvasElement::GetCanvasLayer(nsDisp
       NS_WARNING("CreateCanvasLayer failed!");
       return nullptr;
     }
 
     LayerUserData* userData = nullptr;
     layer->SetUserData(&sOffscreenCanvasLayerUserDataDummy, userData);
 
     CanvasRenderer* canvasRenderer = layer->CreateOrGetCanvasRenderer();
-    InitializeCanvasRenderer(aBuilder, canvasRenderer);
+
+    if (!InitializeCanvasRenderer(aBuilder, canvasRenderer)) {
+      return nullptr;
+    }
 
     layer->Updated();
     return layer.forget();
   }
 
   return nullptr;
 }
 
-void
+bool
 HTMLCanvasElement::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                             CanvasRenderer* aRenderer)
 {
   if (mCurrentContext) {
-    mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
+    return mCurrentContext->InitializeCanvasRenderer(aBuilder, aRenderer);
   }
 
   if (mOffscreenCanvas) {
     CanvasInitializeData data;
     data.mRenderer = GetAsyncCanvasRenderer();
     data.mSize = GetWidthHeight();
     aRenderer->Initialize(data);
+    return true;
   }
+
+  return true;
 }
 
 bool
 HTMLCanvasElement::ShouldForceInactiveLayer(LayerManager* aManager)
 {
   if (mCurrentContext) {
     return mCurrentContext->ShouldForceInactiveLayer(aManager);
   }
--- a/dom/html/HTMLCanvasElement.h
+++ b/dom/html/HTMLCanvasElement.h
@@ -305,17 +305,17 @@ public:
 
   /*
    * Helpers called by various users of Canvas
    */
 
   already_AddRefed<Layer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                          Layer *aOldLayer,
                                          LayerManager *aManager);
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer);
   // Should return true if the canvas layer should always be marked inactive.
   // We should return true here if we can't do accelerated compositing with
   // a non-BasicCanvasLayer.
   bool ShouldForceInactiveLayer(LayerManager *aManager);
 
   // Call this whenever we need future changes to the canvas
   // to trigger fresh invalidation requests. This needs to be called
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -136,17 +136,20 @@ public:
       {
         bool isRecycled;
         RefPtr<WebRenderCanvasData> canvasData =
           aManager->CreateOrRecycleWebRenderUserData<WebRenderCanvasData>(this, &isRecycled);
         WebRenderCanvasRendererAsync* data =
           static_cast<WebRenderCanvasRendererAsync*>(canvasData->GetCanvasRenderer());
 
         if (isRecycled) {
-          static_cast<nsHTMLCanvasFrame*>(mFrame)->InitializeCanvasRenderer(aDisplayListBuilder, data);
+          nsHTMLCanvasFrame* canvasFrame = static_cast<nsHTMLCanvasFrame*>(mFrame);
+          if (!canvasFrame->InitializeCanvasRenderer(aDisplayListBuilder, data)) {
+            return true;
+          }
         }
 
         data->UpdateCompositableClient();
 
         // Push IFrame for async image pipeline.
         // XXX Remove this once partial display list update is supported.
 
         /* ScrollingLayersHelper scroller(this, aBuilder, aSc); */
@@ -450,22 +453,22 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayL
   } else if (layer->GetType() == layers::Layer::TYPE_IMAGE) {
     RefPtr<ImageLayer> imageLayer = static_cast<ImageLayer*>(layer.get());
     imageLayer->SetSamplingFilter(nsLayoutUtils::GetSamplingFilterForFrame(this));
   }
 
   return layer.forget();
 }
 
-void
+bool
 nsHTMLCanvasFrame::InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                             CanvasRenderer* aRenderer)
 {
   HTMLCanvasElement* element = static_cast<HTMLCanvasElement*>(GetContent());
-  element->InitializeCanvasRenderer(aBuilder, aRenderer);
+  return element->InitializeCanvasRenderer(aBuilder, aRenderer);
 }
 
 void
 nsHTMLCanvasFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                     const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
--- a/layout/generic/nsHTMLCanvasFrame.h
+++ b/layout/generic/nsHTMLCanvasFrame.h
@@ -47,17 +47,17 @@ public:
 
   virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                 const nsDisplayListSet& aLists) override;
 
   already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                      LayerManager* aManager,
                                      nsDisplayItem* aItem,
                                      const ContainerLayerParameters& aContainerParameters);
-  void InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
+  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
                                 CanvasRenderer* aRenderer);
 
   /* get the size of the canvas's image */
   nsIntSize GetCanvasSize();
 
   virtual nscoord GetMinISize(gfxContext *aRenderingContext) override;
   virtual nscoord GetPrefISize(gfxContext *aRenderingContext) override;
   virtual mozilla::IntrinsicSize GetIntrinsicSize() override;