Bug 1309913: Pass the compositor type to canvas on creation. r=dvander
authorMilan Sreckovic <milan@mozilla.com>
Thu, 03 Nov 2016 10:57:33 -0400
changeset 366029 aa134dc8e0c73c67f044bba35718ad50a2430c6f
parent 366028 bf15eb2ce373ec2baf9b91d11d3f079282e4946f
child 366030 e81cbf6ee940b7cb3bd1fab044f3db091bf943d4
push id1369
push userjlorenzo@mozilla.com
push dateMon, 27 Feb 2017 14:59:41 +0000
treeherdermozilla-release@d75a1dba431f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs1309913
milestone52.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 1309913: Pass the compositor type to canvas on creation. r=dvander MozReview-Commit-ID: 81HtvWPdLQa
dom/canvas/CanvasRenderingContext2D.cpp
dom/canvas/CanvasRenderingContext2D.h
dom/canvas/CanvasRenderingContextHelper.cpp
dom/canvas/CanvasRenderingContextHelper.h
dom/html/HTMLCanvasElement.cpp
gfx/thebes/gfxPlatform.cpp
layout/reftests/canvas/reftest.list
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1048,18 +1048,19 @@ NS_INTERFACE_MAP_END
 
 
 // Initialize our static variables.
 uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
 
 
 
-CanvasRenderingContext2D::CanvasRenderingContext2D()
+CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend)
   : mRenderingMode(RenderingMode::OpenGLBackendMode)
+  , mCompositorBackend(aCompositorBackend)
   // these are the default values from the Canvas spec
   , mWidth(0), mHeight(0)
   , mZero(false), mOpaque(false)
   , mResetLayer(true)
   , mIPC(false)
   , mIsSkiaGL(false)
   , mHasPendingStableStateCallback(false)
   , mDrawObserver(nullptr)
@@ -1070,17 +1071,17 @@ CanvasRenderingContext2D::CanvasRenderin
   , mInvalidateCount(0)
 {
   sNumLivingContexts++;
 
   mShutdownObserver = new CanvasShutdownObserver(this);
   nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
 
   // The default is to use OpenGL mode
-  if (gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+  if (AllowOpenGLCanvas()) {
     mDrawObserver = new CanvasDrawObserver(this);
   } else {
     mRenderingMode = RenderingMode::SoftwareBackendMode;
   }
 }
 
 CanvasRenderingContext2D::~CanvasRenderingContext2D()
 {
@@ -1316,28 +1317,48 @@ CanvasRenderingContext2D::RedrawUser(con
     ++mInvalidateCount;
     return;
   }
 
   gfx::Rect newr = mTarget->GetTransform().TransformBounds(ToRect(aR));
   Redraw(newr);
 }
 
+bool
+CanvasRenderingContext2D::AllowOpenGLCanvas() const
+{
+  // If we somehow didn't have the correct compositor in the constructor,
+  // we could do something like this to get it:
+  //
+  // HTMLCanvasElement* el = GetCanvas();
+  // if (el) {
+  //   mCompositorBackend = el->GetCompositorBackendType();
+  // }
+  //
+  // We could have LAYERS_NONE if there was no widget at the time of
+  // canvas creation, but in that case the
+  // HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
+  // as well, so it wouldn't help much.
+
+  return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
+    gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
+}
+
 bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
 {
   if (!IsTargetValid() || mRenderingMode == aRenderingMode) {
     return false;
   }
 
   MOZ_ASSERT(mBufferProvider);
 
 #ifdef USE_SKIA_GPU
   // Do not attempt to switch into GL mode if the platform doesn't allow it.
   if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
-      !gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+      !AllowOpenGLCanvas()) {
       return false;
   }
 #endif
 
   RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
 
   // Return the old target to the buffer provider.
   // We need to do this before calling EnsureTarget.
@@ -1703,23 +1724,20 @@ LayerManagerFromCanvasElement(nsINode* a
 
 bool
 CanvasRenderingContext2D::TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
                                           RefPtr<layers::PersistentBufferProvider>& aOutProvider)
 {
   aOutDT = nullptr;
   aOutProvider = nullptr;
 
-
   mIsSkiaGL = false;
 
   IntSize size(mWidth, mHeight);
-  if (!gfxPlatform::GetPlatform()->AllowOpenGLCanvas() ||
-      !CheckSizeForSkiaGL(size)) {
-
+  if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
     return false;
   }
 
 
   RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
 
   if (!layerManager) {
     return false;
@@ -4755,17 +4773,17 @@ CanvasRenderingContext2D::DrawImage(cons
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
 
 #ifdef USE_SKIA_GPU
   if (mRenderingMode == RenderingMode::OpenGLBackendMode &&
       mIsSkiaGL &&
       !srcSurf &&
       aImage.IsHTMLVideoElement() &&
-      gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+      AllowOpenGLCanvas()) {
     mozilla::gl::GLContext* gl = gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext();
     MOZ_ASSERT(gl);
 
     HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
     if (!video) {
       return;
     }
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -61,23 +61,23 @@ class CanvasShutdownObserver;
  **/
 class CanvasRenderingContext2D final :
   public nsICanvasRenderingContextInternal,
   public nsWrapperCache
 {
   virtual ~CanvasRenderingContext2D();
 
 public:
-  CanvasRenderingContext2D();
+  explicit CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend);
 
   virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLCanvasElement* GetCanvas() const
   {
-    if (mCanvasElement->IsInNativeAnonymousSubtree()) {
+    if (!mCanvasElement || mCanvasElement->IsInNativeAnonymousSubtree()) {
       return nullptr;
     }
 
     // corresponds to changes to the old bindings made in bug 745025
     return mCanvasElement->GetOriginalCanvas();
   }
 
   void Save();
@@ -533,16 +533,20 @@ public:
   // Given a point, return hit region ID if it exists
   nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override;
 
 
   // return true and fills in the bound rect if element has a hit region.
   bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
 
   void OnShutdown();
+
+  // Check the global setup, as well as the compositor type:
+  bool AllowOpenGLCanvas() const;
+
 protected:
   nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
                              uint32_t aWidth, uint32_t aHeight,
                              JSObject** aRetval);
 
   nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
                                  dom::Uint8ClampedArray* aArray,
                                  bool aHasDirtyRect, int32_t aDirtyX, int32_t aDirtyY,
@@ -728,16 +732,18 @@ protected:
   static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
   static void DemoteOldestContextIfNecessary();
 
   static void AddDemotableContext(CanvasRenderingContext2D* aContext);
   static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
 
   RenderingMode mRenderingMode;
 
+  layers::LayersBackend mCompositorBackend;
+
   // Member vars
   int32_t mWidth, mHeight;
 
   // This is true when the canvas is valid, but of zero size, this requires
   // specific behavior on some operations.
   bool mZero;
 
   bool mOpaque;
--- a/dom/canvas/CanvasRenderingContextHelper.cpp
+++ b/dom/canvas/CanvasRenderingContextHelper.cpp
@@ -118,26 +118,33 @@ CanvasRenderingContextHelper::ToBlob(JSC
                                        format,
                                        GetWidthHeight(),
                                        callback);
 }
 
 already_AddRefed<nsICanvasRenderingContextInternal>
 CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
 {
+  return CreateContextHelper(aContextType, layers::LayersBackend::LAYERS_NONE);
+}
+
+already_AddRefed<nsICanvasRenderingContextInternal>
+CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType,
+                                                  layers::LayersBackend aCompositorBackend)
+{
   MOZ_ASSERT(aContextType != CanvasContextType::NoContext);
   RefPtr<nsICanvasRenderingContextInternal> ret;
 
   switch (aContextType) {
   case CanvasContextType::NoContext:
     break;
 
   case CanvasContextType::Canvas2D:
     Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
-    ret = new CanvasRenderingContext2D();
+    ret = new CanvasRenderingContext2D(aCompositorBackend);
     break;
 
   case CanvasContextType::WebGL1:
     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
 
     ret = WebGL1Context::Create();
     if (!ret)
       return nullptr;
--- a/dom/canvas/CanvasRenderingContextHelper.h
+++ b/dom/canvas/CanvasRenderingContextHelper.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
 #define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
 
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/layers/LayersTypes.h"
 #include "nsSize.h"
 
 class nsICanvasRenderingContextInternal;
 class nsIGlobalObject;
 
 namespace mozilla {
 
 class ErrorResult;
@@ -61,16 +62,20 @@ protected:
 
   void ToBlob(JSContext* aCx, nsIGlobalObject* aGlobal, EncodeCompleteCallback* aCallback,
               const nsAString& aType, JS::Handle<JS::Value> aParams,
               ErrorResult& aRv);
 
   virtual already_AddRefed<nsICanvasRenderingContextInternal>
   CreateContext(CanvasContextType aContextType);
 
+  already_AddRefed<nsICanvasRenderingContextInternal>
+  CreateContextHelper(CanvasContextType aContextType,
+                      layers::LayersBackend aCompositorBackend);
+
   virtual nsIntSize GetWidthHeight() = 0;
 
   CanvasContextType mCurrentContextType;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -397,18 +397,19 @@ NS_IMPL_ELEMENT_CLONE(HTMLCanvasElement)
 HTMLCanvasElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return HTMLCanvasElementBinding::Wrap(aCx, this, aGivenProto);
 }
 
 already_AddRefed<nsICanvasRenderingContextInternal>
 HTMLCanvasElement::CreateContext(CanvasContextType aContextType)
 {
+  // Note that the compositor backend will be LAYERS_NONE if there is no widget.
   RefPtr<nsICanvasRenderingContextInternal> ret =
-    CanvasRenderingContextHelper::CreateContext(aContextType);
+    CreateContextHelper(aContextType, GetCompositorBackendType());
 
   // Add Observer for webgl canvas.
   if (aContextType == CanvasContextType::WebGL1 ||
       aContextType == CanvasContextType::WebGL2) {
     if (!mContextObserver) {
       mContextObserver = new HTMLCanvasElementObserver(this);
     }
   }
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1254,20 +1254,25 @@ gfxPlatform::SupportsAzureContentForDraw
   return SupportsAzureContentForType(aTarget->GetBackendType());
 }
 
 bool gfxPlatform::AllowOpenGLCanvas()
 {
   // For now, only allow Skia+OpenGL, unless it's blocked.
   // Allow acceleration on Skia if the preference is set, unless it's blocked
   // as long as we have the accelerated layers
-  if (gfxPrefs::CanvasAzureAccelerated() &&
-      mCompositorBackend == LayersBackend::LAYERS_OPENGL &&
-      (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA))
-  {
+
+  // The compositor backend is only set correctly in the parent process,
+  // so we let content process always assume correct compositor backend.
+  // The callers have to do the right thing.
+  bool correctBackend = !XRE_IsParentProcess() ||
+    ((mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
+     (GetContentBackendFor(mCompositorBackend) == BackendType::SKIA));
+
+  if (gfxPrefs::CanvasAzureAccelerated() && correctBackend) {
     nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
     int32_t status;
     nsCString discardFailureId;
     return !gfxInfo ||
       (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION,
                                               discardFailureId,
                                               &status)) &&
        status == nsIGfxInfo::FEATURE_STATUS_OK);
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -61,18 +61,17 @@ random-if(!d2d) != text-subpixel-1.html 
 ## if they have an Emoji font installed when running the tests.)
 ## WAS: random-if(OSX==1007) != text-emoji.html text-emoji-notref.html
 # With Skia canvas on OS X (bug 932958) it fails even on 10.8 and 10.10.
 random-if(cocoaWidget&&azureSkia) random-if(!cocoaWidget||OSX==1006||OSX==1007) != text-emoji.html text-emoji-notref.html
 
 # azure quartz uses CGDrawLinearGradient instead of DrawShading
 # so we have less control over degenerate behaviour as tested by this
 # test
-# This test should pass with SkiaGL, but due to bug 1309913, e10s prevents SkiaGL from working.
-fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&(browserIsRemote||Android))) == linear-gradient-1a.html linear-gradient-1-ref.html
+fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&Android)) == linear-gradient-1a.html linear-gradient-1-ref.html
 
 # this passes with cairo on 10.7 and 10.8 but not with azure for reasons unknown
 # This test should pass with SkiaGL, but due to bug 1309913, e10s prevents SkiaGL from working.
 fails-if((azureSkia&&!azureSkiaGL)||azureQuartz||(azureSkiaGL&&(browserIsRemote||Android))) == linear-gradient-1b.html linear-gradient-1-ref.html
 
 == zero-dimensions.html zero-dimensions-ref.html
 
 != evenodd-fill-1.html nonzero-fill-1.html