Bug 939276 - Use a single GLContext for all SkiaGL canvases r=jgilbert,vlad,gwright,bjacob
authorJames Willcox <snorp@snorp.net>
Wed, 05 Mar 2014 15:49:37 -0600
changeset 172136 2dda16c0a398f234cc06b4f64102f666614572a3
parent 172135 ccf27e254ed812d41a74360762c6388e02c972bf
child 172137 6f287c42495b97b458eaa6b7b299cdb217949d95
push id26351
push usercbook@mozilla.com
push dateThu, 06 Mar 2014 12:13:01 +0000
treeherdermozilla-central@0f81cbeae0d4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, vlad, gwright, bjacob
bugs939276
milestone30.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 939276 - Use a single GLContext for all SkiaGL canvases r=jgilbert,vlad,gwright,bjacob
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
gfx/2d/2D.h
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
gfx/2d/Factory.cpp
gfx/2d/Types.h
gfx/gl/GLContextSkia.cpp
gfx/gl/GLContextSkia.h
gfx/gl/GLScreenBuffer.cpp
gfx/gl/GLScreenBuffer.h
gfx/gl/SharedSurfaceGL.cpp
gfx/gl/SharedSurfaceGL.h
gfx/gl/SkiaGLGlue.cpp
gfx/gl/SkiaGLGlue.h
gfx/gl/SurfaceStream.cpp
gfx/gl/SurfaceStream.h
gfx/gl/moz.build
gfx/layers/CopyableCanvasLayer.cpp
gfx/layers/CopyableCanvasLayer.h
gfx/layers/Layers.h
gfx/layers/client/CanvasClient.cpp
gfx/layers/client/ClientCanvasLayer.cpp
gfx/layers/client/ClientCanvasLayer.h
gfx/layers/opengl/TextureClientOGL.cpp
gfx/layers/opengl/TextureClientOGL.h
gfx/thebes/gfxPlatform.cpp
gfx/thebes/gfxPlatform.h
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -89,24 +89,24 @@
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "mozilla/dom/TextMetrics.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "nsGlobalWindow.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 
-#ifdef USE_SKIA_GPU
 #undef free // apparently defined by some windows header, clashing with a free()
             // method in SkTypes.h
-#include "GLContextSkia.h"
+#include "SkiaGLGlue.h"
+#include "SurfaceStream.h"
 #include "SurfaceTypes.h"
-#include "nsIGfxInfo.h"
-#endif
+
 using mozilla::gl::GLContext;
+using mozilla::gl::SkiaGLGlue;
 using mozilla::gl::GLContextProvider;
 
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "mozilla/layers/ShadowLayers.h"
@@ -425,38 +425,28 @@ public:
   }
   ~CanvasRenderingContext2DUserData()
   {
     if (mContext) {
       mContext->mUserDatas.RemoveElement(this);
     }
   }
 
-#ifdef USE_SKIA_GPU
   static void PreTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
       static_cast<CanvasRenderingContext2DUserData*>(aData);
     CanvasRenderingContext2D* context = self->mContext;
-    if (!context)
-      return;
-
-    GLContext* glContext = static_cast<GLContext*>(context->mTarget->GetGLContext());
-    if (!glContext)
+    if (!context || !context->mStream || !context->mTarget)
       return;
 
-    if (context->mTarget) {
-      // Since SkiaGL default to store drawing command until flush
-      // We will have to flush it before present.
-      context->mTarget->Flush();
-    }
-    glContext->MakeCurrent();
-    glContext->PublishFrame();
+    // Since SkiaGL default to store drawing command until flush
+    // We will have to flush it before present.
+    context->mTarget->Flush();
   }
-#endif
 
   static void DidTransactionCallback(void* aData)
   {
     CanvasRenderingContext2DUserData* self =
       static_cast<CanvasRenderingContext2DUserData*>(aData);
     if (self->mContext) {
       self->mContext->MarkContextClean();
     }
@@ -537,45 +527,40 @@ NS_INTERFACE_MAP_END
 
 // Initialize our static variables.
 uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
 
 
 
 CanvasRenderingContext2D::CanvasRenderingContext2D()
-  : mZero(false), mOpaque(false), mResetLayer(true)
+  : mForceSoftware(false), mZero(false), mOpaque(false), mResetLayer(true)
   , mIPC(false)
+  , mStream(nullptr)
   , mIsEntireFrameInvalid(false)
   , mPredictManyRedrawCalls(false), mPathTransformWillUpdate(false)
   , mInvalidateCount(0)
 {
   sNumLivingContexts++;
   SetIsDOMBinding();
-
-#ifdef USE_SKIA_GPU
-  mForceSoftware = false;
-#endif
 }
 
 CanvasRenderingContext2D::~CanvasRenderingContext2D()
 {
   Reset();
   // Drop references from all CanvasRenderingContext2DUserData to this context
   for (uint32_t i = 0; i < mUserDatas.Length(); ++i) {
     mUserDatas[i]->Forget();
   }
   sNumLivingContexts--;
   if (!sNumLivingContexts) {
     NS_IF_RELEASE(sErrorTarget);
   }
 
-#ifdef USE_SKIA_GPU
   RemoveDemotableContext(this);
-#endif
 }
 
 JSObject*
 CanvasRenderingContext2D::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
 {
   return CanvasRenderingContext2DBinding::Wrap(cx, scope, this);
 }
 
@@ -633,16 +618,17 @@ CanvasRenderingContext2D::Reset()
 
   // only do this for non-docshell created contexts,
   // since those are the ones that we created a surface for
   if (mTarget && IsTargetValid() && !mDocShell) {
     gCanvasAzureMemoryUsed -= mWidth * mHeight * 4;
   }
 
   mTarget = nullptr;
+  mStream = nullptr;
 
   // reset hit regions
 #ifdef ACCESSIBILITY
   mHitRegionsOptions.EnumerateEntries(RemoveHitRegionProperty, nullptr);
 #endif
   mHitRegionsOptions.Clear();
 
   // Since the target changes the backing texture will change, and this will
@@ -760,25 +746,25 @@ CanvasRenderingContext2D::RedrawUser(con
 
   mgfx::Rect newr =
     mTarget->GetTransform().TransformBounds(ToRect(r));
   Redraw(newr);
 }
 
 void CanvasRenderingContext2D::Demote()
 {
-#ifdef  USE_SKIA_GPU
-  if (!IsTargetValid() || mForceSoftware || !mTarget->GetGLContext())
+  if (!IsTargetValid() || mForceSoftware || !mStream)
     return;
 
   RemoveDemotableContext(this);
 
   RefPtr<SourceSurface> snapshot = mTarget->Snapshot();
   RefPtr<DrawTarget> oldTarget = mTarget;
   mTarget = nullptr;
+  mStream = nullptr;
   mResetLayer = true;
   mForceSoftware = true;
 
   // Recreate target, now demoted to software only
   EnsureTarget();
   if (!IsTargetValid())
     return;
 
@@ -787,36 +773,29 @@ void CanvasRenderingContext2D::Demote()
   mTarget->DrawSurface(snapshot, r, r);
 
   // Restore the clips and transform
   for (uint32_t i = 0; i < CurrentState().clipsPushed.size(); i++) {
     mTarget->PushClip(CurrentState().clipsPushed[i]);
   }
 
   mTarget->SetTransform(oldTarget->GetTransform());
-#endif
 }
 
-#ifdef USE_SKIA_GPU
-
 std::vector<CanvasRenderingContext2D*>&
 CanvasRenderingContext2D::DemotableContexts()
 {
   static std::vector<CanvasRenderingContext2D*> contexts;
   return contexts;
 }
 
 void
 CanvasRenderingContext2D::DemoteOldestContextIfNecessary()
 {
-#ifdef MOZ_GFX_OPTIMIZE_MOBILE
-  const size_t kMaxContexts = 2;
-#else
-  const size_t kMaxContexts = 16;
-#endif
+  const size_t kMaxContexts = 64;
 
   std::vector<CanvasRenderingContext2D*>& contexts = DemotableContexts();
   if (contexts.size() < kMaxContexts)
     return;
 
   CanvasRenderingContext2D* oldest = contexts.front();
   oldest->Demote();
 }
@@ -840,18 +819,16 @@ CanvasRenderingContext2D::RemoveDemotabl
 }
 
 bool
 CheckSizeForSkiaGL(IntSize size) {
   int minsize = Preferences::GetInt("gfx.canvas.min-size-for-skia-gl", 128);
   return size.width >= minsize && size.height >= minsize;
 }
 
-#endif
-
 void
 CanvasRenderingContext2D::EnsureTarget()
 {
   if (mTarget) {
     return;
   }
 
    // Check that the dimensions are sane
@@ -867,52 +844,39 @@ CanvasRenderingContext2D::EnsureTarget()
     nsRefPtr<LayerManager> layerManager = nullptr;
 
     if (ownerDoc) {
       layerManager =
         nsContentUtils::PersistentLayerManagerForDocument(ownerDoc);
     }
 
      if (layerManager) {
-#ifdef USE_SKIA_GPU
-      if (gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas()) {
-        SurfaceCaps caps = SurfaceCaps::ForRGBA();
-        caps.preserve = true;
-
-#ifdef MOZ_WIDGET_GONK
-        layers::ShadowLayerForwarder *forwarder = layerManager->AsShadowForwarder();
-        if (forwarder) {
-          caps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
-        }
-#endif
-
+      if (gfxPlatform::GetPlatform()->UseAcceleratedSkiaCanvas() &&
+          !mForceSoftware &&
+          CheckSizeForSkiaGL(size)) {
         DemoteOldestContextIfNecessary();
 
-        nsRefPtr<GLContext> glContext;
-        nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
-        nsString vendor;
-
-        if (!mForceSoftware && CheckSizeForSkiaGL(size))
-        {
-          glContext = GLContextProvider::CreateOffscreen(gfxIntSize(size.width, size.height),
-                                                         caps);
+        SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
+
+        if (glue) {
+          mTarget = Factory::CreateDrawTargetSkiaWithGrContext(glue->GetGrContext(), size, format);
+          if (mTarget) {
+            mStream = gfx::SurfaceStream::CreateForType(SurfaceStreamType::TripleBuffer, glue->GetGLContext());
+            AddDemotableContext(this);
+          } else {
+            printf_stderr("Failed to create a SkiaGL DrawTarget, falling back to software\n");
+          }
         }
-
-        if (glContext) {
-          SkAutoTUnref<GrGLInterface> i(CreateGrGLInterfaceFromGLContext(glContext));
-          mTarget = Factory::CreateDrawTargetSkiaWithGLContextAndGrGLInterface(glContext, i, size, format);
-          AddDemotableContext(this);
-        } else {
+        if (!mTarget) {
           mTarget = layerManager->CreateDrawTarget(size, format);
         }
       } else
-#endif
-       mTarget = layerManager->CreateDrawTarget(size, format);
+        mTarget = layerManager->CreateDrawTarget(size, format);
      } else {
-       mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
+        mTarget = gfxPlatform::GetPlatform()->CreateOffscreenCanvasDrawTarget(size, format);
      }
   }
 
   if (mTarget) {
     static bool registered = false;
     if (!registered) {
       registered = true;
       RegisterStrongMemoryReporter(new Canvas2dPixelsReporter());
@@ -1087,22 +1051,20 @@ CanvasRenderingContext2D::SetContextOpti
 {
   if (aOptions.isNullOrUndefined()) {
     return NS_OK;
   }
 
   ContextAttributes2D attributes;
   NS_ENSURE_TRUE(attributes.Init(aCx, aOptions), NS_ERROR_UNEXPECTED);
 
-#ifdef USE_SKIA_GPU
   if (Preferences::GetBool("gfx.canvas.willReadFrequently.enable", false)) {
     // Use software when there is going to be a lot of readback
     mForceSoftware = attributes.mWillReadFrequently;
   }
-#endif
 
   return NS_OK;
 }
 
 void
 CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
                                          int32_t* aFormat)
 {
@@ -3335,33 +3297,31 @@ CanvasRenderingContext2D::DrawDirectlyTo
          gfxRect(gfxPoint(dx, dy), gfxIntSize(dw, dh)),
          nsIntRect(nsIntPoint(0, 0), gfxIntSize(imgSize.width, imgSize.height)),
          gfxIntSize(imgSize.width, imgSize.height), nullptr, image.mWhichFrame,
          modifiedFlags);
 
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
-#ifdef USE_SKIA_GPU
 static bool
 IsStandardCompositeOp(CompositionOp op)
 {
     return (op == CompositionOp::OP_SOURCE ||
             op == CompositionOp::OP_ATOP ||
             op == CompositionOp::OP_IN ||
             op == CompositionOp::OP_OUT ||
             op == CompositionOp::OP_OVER ||
             op == CompositionOp::OP_DEST_IN ||
             op == CompositionOp::OP_DEST_OUT ||
             op == CompositionOp::OP_DEST_OVER ||
             op == CompositionOp::OP_DEST_ATOP ||
             op == CompositionOp::OP_ADD ||
             op == CompositionOp::OP_XOR);
 }
-#endif
 
 void
 CanvasRenderingContext2D::SetGlobalCompositeOperation(const nsAString& op,
                                                       ErrorResult& error)
 {
   CompositionOp comp_op;
 
 #define CANVAS_OP_TO_GFX_OP(cvsop, op2d) \
@@ -3392,21 +3352,19 @@ CanvasRenderingContext2D::SetGlobalCompo
   else CANVAS_OP_TO_GFX_OP("exclusion", EXCLUSION)
   else CANVAS_OP_TO_GFX_OP("hue", HUE)
   else CANVAS_OP_TO_GFX_OP("saturation", SATURATION)
   else CANVAS_OP_TO_GFX_OP("color", COLOR)
   else CANVAS_OP_TO_GFX_OP("luminosity", LUMINOSITY)
   // XXX ERRMSG we need to report an error to developers here! (bug 329026)
   else return;
 
-#ifdef USE_SKIA_GPU
   if (!IsStandardCompositeOp(comp_op)) {
     Demote();
   }
-#endif
 
 #undef CANVAS_OP_TO_GFX_OP
   CurrentState().op = comp_op;
 }
 
 void
 CanvasRenderingContext2D::GetGlobalCompositeOperation(nsAString& op,
                                                       ErrorResult& error)
@@ -3442,21 +3400,19 @@ CanvasRenderingContext2D::GetGlobalCompo
   else CANVAS_OP_TO_GFX_OP("hue", HUE)
   else CANVAS_OP_TO_GFX_OP("saturation", SATURATION)
   else CANVAS_OP_TO_GFX_OP("color", COLOR)
   else CANVAS_OP_TO_GFX_OP("luminosity", LUMINOSITY)
   else {
     error.Throw(NS_ERROR_FAILURE);
   }
 
-#ifdef USE_SKIA_GPU
   if (!IsStandardCompositeOp(comp_op)) {
     Demote();
   }
-#endif
 
 #undef CANVAS_OP_TO_GFX_OP
 }
 
 void
 CanvasRenderingContext2D::DrawWindow(nsGlobalWindow& window, double x,
                                      double y, double w, double h,
                                      const nsAString& bgColor,
@@ -4146,17 +4102,27 @@ CanvasRenderingContext2D::GetCanvasLayer
   mTarget->Flush();
 
   if (!mResetLayer && aOldLayer) {
     CanvasRenderingContext2DUserData* userData =
       static_cast<CanvasRenderingContext2DUserData*>(
         aOldLayer->GetUserData(&g2DContextLayerUserData));
 
     CanvasLayer::Data data;
-    data.mGLContext = static_cast<GLContext*>(mTarget->GetGLContext());
+    if (mStream) {
+      SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
+
+      if (glue) {
+        data.mGLContext = glue->GetGLContext();
+        data.mStream = mStream.get();
+      }
+    } else {
+      data.mDrawTarget = mTarget;
+    }
+
     if (userData && userData->IsForContext(this) && aOldLayer->IsDataValid(data)) {
       nsRefPtr<CanvasLayer> ret = aOldLayer;
       return ret.forget();
     }
   }
 
   nsRefPtr<CanvasLayer> canvasLayer = aManager->CreateCanvasLayer();
   if (!canvasLayer) {
@@ -4179,25 +4145,27 @@ CanvasRenderingContext2D::GetCanvasLayer
   // The userData will receive DidTransactionCallbacks, which flush the
   // the invalidation state to indicate that the canvas is up to date.
   userData = new CanvasRenderingContext2DUserData(this);
   canvasLayer->SetDidTransactionCallback(
           CanvasRenderingContext2DUserData::DidTransactionCallback, userData);
   canvasLayer->SetUserData(&g2DContextLayerUserData, userData);
 
   CanvasLayer::Data data;
-#ifdef USE_SKIA_GPU
-  GLContext* glContext = static_cast<GLContext*>(mTarget->GetGLContext());
-  if (glContext) {
-    canvasLayer->SetPreTransactionCallback(
-            CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
-    data.mGLContext = glContext;
-  } else
-#endif
-  {
+  if (mStream) {
+    SkiaGLGlue* glue = gfxPlatform::GetPlatform()->GetSkiaGLGlue();
+
+    if (glue) {
+      canvasLayer->SetPreTransactionCallback(
+              CanvasRenderingContext2DUserData::PreTransactionCallback, userData);
+      data.mGLContext = glue->GetGLContext();
+      data.mStream = mStream.get();
+      data.mTexID = (uint32_t)((uintptr_t)mTarget->GetNativeSurface(NativeSurfaceType::OPENGL_TEXTURE));
+    }
+  } else {
     data.mDrawTarget = mTarget;
   }
 
   data.mSize = nsIntSize(mWidth, mHeight);
 
   canvasLayer->Initialize(data);
   uint32_t flags = mOpaque ? Layer::CONTENT_OPAQUE : 0;
   canvasLayer->SetContentFlags(flags);
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -26,16 +26,17 @@
 #include "nsLayoutUtils.h"
 
 class nsGlobalWindow;
 class nsXULElement;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
+class SurfaceStream;
 }
 
 namespace dom {
 class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
 class ImageData;
 class StringOrCanvasGradientOrCanvasPattern;
 class OwningStringOrCanvasGradientOrCanvasPattern;
 class TextMetrics;
@@ -591,26 +592,24 @@ protected:
   nsString& GetFont()
   {
     /* will initilize the value if not set, else does nothing */
     GetCurrentFontStyle();
 
     return CurrentState().font;
   }
 
-#if USE_SKIA_GPU
   static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
   static void DemoteOldestContextIfNecessary();
 
   static void AddDemotableContext(CanvasRenderingContext2D* context);
   static void RemoveDemotableContext(CanvasRenderingContext2D* context);
 
   // Do not use GL
   bool mForceSoftware;
-#endif
 
   // 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;
 
@@ -627,16 +626,18 @@ protected:
   // If mCanvasElement is not provided, then a docshell is
   nsCOMPtr<nsIDocShell> mDocShell;
 
   // This is created lazily so it is necessary to call EnsureTarget before
   // accessing it. In the event of an error it will be equal to
   // sErrorTarget.
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
 
+  RefPtr<gfx::SurfaceStream> mStream;
+
   /**
     * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
     * Redraw is called, reset to false when Render is called.
     */
   bool mIsEntireFrameInvalid;
   /**
     * When this is set, the first call to Redraw(gfxRect) should set
     * mIsEntireFrameInvalid since we expect it will be followed by
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -966,25 +966,20 @@ public:
   virtual void SetPermitSubpixelAA(bool aPermitSubpixelAA) {
     mPermitSubpixelAA = aPermitSubpixelAA;
   }
 
   bool GetPermitSubpixelAA() {
     return mPermitSubpixelAA;
   }
 
-  virtual GenericRefCountedBase* GetGLContext() const {
-    return nullptr;
-  }
-
 #ifdef USE_SKIA_GPU
-  virtual void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
-                                            GrGLInterface* aGrGLInterface,
-                                            const IntSize &aSize,
-                                            SurfaceFormat aFormat)
+  virtual void InitWithGrContext(GrContext* aGrContext,
+                                 const IntSize &aSize,
+                                 SurfaceFormat aFormat)
   {
     MOZ_CRASH();
   }
 #endif
 
 protected:
   UserData mUserData;
   Matrix mTransform;
@@ -1080,23 +1075,19 @@ public:
 
   static TemporaryRef<DrawEventRecorder>
     CreateEventRecorderForFile(const char *aFilename);
 
   static void SetGlobalEventRecorder(DrawEventRecorder *aRecorder);
 
 #ifdef USE_SKIA_GPU
   static TemporaryRef<DrawTarget>
-    CreateDrawTargetSkiaWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
-                                                      GrGLInterface* aGrGLInterface,
-                                                      const IntSize &aSize,
-                                                      SurfaceFormat aFormat);
-
-  static void
-    SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes);
+    CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
+                                      const IntSize &aSize,
+                                      SurfaceFormat aFormat);
 #endif
 
   static void PurgeAllCaches();
 
 #if defined(USE_SKIA) && defined(MOZ_ENABLE_FREETYPE)
   static TemporaryRef<GlyphRenderingOptions>
     CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting);
 #endif
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -74,90 +74,16 @@ public:
   BackendType GetBackendType() const { return BackendType::SKIA; }
 
   std::vector<SkColor> mColors;
   std::vector<SkScalar> mPositions;
   int mCount;
   ExtendMode mExtendMode;
 };
 
-#ifdef USE_SKIA_GPU
-int DrawTargetSkia::sTextureCacheCount = 256;
-int DrawTargetSkia::sTextureCacheSizeInBytes = 96*1024*1024;
-
-static std::vector<DrawTargetSkia*>&
-GLDrawTargets()
-{
-  static std::vector<DrawTargetSkia*> targets;
-  return targets;
-}
-
-void
-DrawTargetSkia::RebalanceCacheLimits()
-{
-  // Divide the global cache limits equally between all currently active GL-backed
-  // Skia DrawTargets.
-  std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
-  uint32_t targetCount = targets.size();
-  if (targetCount == 0)
-    return;
-
-  int individualCacheSize = sTextureCacheSizeInBytes / targetCount;
-  for (uint32_t i = 0; i < targetCount; i++) {
-    targets[i]->SetCacheLimits(sTextureCacheCount, individualCacheSize);
-  }
-}
-
-static void
-AddGLDrawTarget(DrawTargetSkia* target)
-{
-  GLDrawTargets().push_back(target);
-  DrawTargetSkia::RebalanceCacheLimits();
-}
-
-static void
-RemoveGLDrawTarget(DrawTargetSkia* target)
-{
-  std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
-  std::vector<DrawTargetSkia*>::iterator it = std::find(targets.begin(), targets.end(), target);
-  if (it != targets.end()) {
-    targets.erase(it);
-    DrawTargetSkia::RebalanceCacheLimits();
-  }
-}
-
-void
-DrawTargetSkia::SetGlobalCacheLimits(int aCount, int aSizeInBytes)
-{
-  sTextureCacheCount = aCount;
-  sTextureCacheSizeInBytes = aSizeInBytes;
-
-  DrawTargetSkia::RebalanceCacheLimits();
-}
-
-void
-DrawTargetSkia::PurgeCaches()
-{
-  if (mGrContext) {
-    mGrContext->freeGpuResources();
-  }
-}
-
-/* static */ void
-DrawTargetSkia::PurgeAllCaches()
-{
-  std::vector<DrawTargetSkia*>& targets = GLDrawTargets();
-  uint32_t targetCount = targets.size();
-  for (uint32_t i = 0; i < targetCount; i++) {
-    targets[i]->PurgeCaches();
-  }
-}
-
-#endif
-
 /**
  * When constructing a temporary SkBitmap via GetBitmapForSurface, we may also
  * have to construct a temporary DataSourceSurface, which must live as long as
  * the SkBitmap. So we return a pair of the SkBitmap and the (optional)
  * temporary surface.
  */
 struct TempBitmap
 {
@@ -184,25 +110,22 @@ GetBitmapForSurface(SourceSurface* aSurf
                                  surf->GetSize().width, surf->GetSize().height,
                                  surf->Stride());
   result.mBitmap.setPixels(surf->GetData());
   result.mTmpSurface = surf.forget();
   return result;
 }
 
 DrawTargetSkia::DrawTargetSkia()
-  : mSnapshot(nullptr)
+  : mTexture(0), mSnapshot(nullptr)
 {
 }
 
 DrawTargetSkia::~DrawTargetSkia()
 {
-#ifdef USE_SKIA_GPU
-  RemoveGLDrawTarget(this);
-#endif
 }
 
 TemporaryRef<SourceSurface>
 DrawTargetSkia::Snapshot()
 {
   RefPtr<SourceSurfaceSkia> snapshot = mSnapshot;
   if (!snapshot) {
     snapshot = new SourceSurfaceSkia();
@@ -765,55 +688,43 @@ DrawTargetSkia::Init(const IntSize &aSiz
 
   mCanvas = canvas.get();
   mFormat = aFormat;
   return true;
 }
 
 #ifdef USE_SKIA_GPU
 void
-DrawTargetSkia::InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
-                                                  GrGLInterface* aGrGLInterface,
-                                                  const IntSize &aSize,
-                                                  SurfaceFormat aFormat)
+DrawTargetSkia::InitWithGrContext(GrContext* aGrContext,
+                                  const IntSize &aSize,
+                                  SurfaceFormat aFormat)
 {
-  mGLContext = aGLContext;
+  mGrContext = aGrContext;
+
   mSize = aSize;
   mFormat = aFormat;
 
-  mGrGLInterface = aGrGLInterface;
-  mGrGLInterface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
+  GrTextureDesc targetDescriptor;
 
-  GrBackendContext backendContext = reinterpret_cast<GrBackendContext>(aGrGLInterface);
-  SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, backendContext));
-  mGrContext = gr.get();
-
-  GrBackendRenderTargetDesc targetDescriptor;
-
+  targetDescriptor.fFlags = kRenderTarget_GrTextureFlagBit;
   targetDescriptor.fWidth = mSize.width;
   targetDescriptor.fHeight = mSize.height;
   targetDescriptor.fConfig = GfxFormatToGrConfig(mFormat);
   targetDescriptor.fOrigin = kBottomLeft_GrSurfaceOrigin;
   targetDescriptor.fSampleCnt = 0;
-  targetDescriptor.fRenderTargetHandle = 0; // GLContext always exposes the right framebuffer as id 0
+
+  SkAutoTUnref<GrTexture> skiaTexture(mGrContext->createUncachedTexture(targetDescriptor, NULL, 0));
 
-  SkAutoTUnref<GrRenderTarget> target(mGrContext->wrapBackendRenderTarget(targetDescriptor));
-  SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), target.get()));
+  mTexture = (uint32_t)skiaTexture->getTextureHandle();
+
+  SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(mGrContext.get(), skiaTexture->asRenderTarget()));
   SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
   mCanvas = canvas.get();
-
-  AddGLDrawTarget(this);
 }
 
-void
-DrawTargetSkia::SetCacheLimits(int aCount, int aSizeInBytes)
-{
-  MOZ_ASSERT(mGrContext, "No GrContext!");
-  mGrContext->setTextureCacheLimits(aCount, aSizeInBytes);
-}
 #endif
 
 void
 DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
 {
   SkAlphaType alphaType = kPremul_SkAlphaType;
   if (aFormat == SurfaceFormat::B8G8R8X8) {
     // We have to manually set the A channel to be 255 as Skia doesn't understand BGRX
@@ -835,16 +746,27 @@ void
 DrawTargetSkia::SetTransform(const Matrix& aTransform)
 {
   SkMatrix mat;
   GfxMatrixToSkiaMatrix(aTransform, mat);
   mCanvas->setMatrix(mat);
   mTransform = aTransform;
 }
 
+void*
+DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType)
+{
+  if (aType == NativeSurfaceType::OPENGL_TEXTURE) {
+    return (void*)((uintptr_t)mTexture);
+  }
+
+  return nullptr;  
+}
+
+
 TemporaryRef<PathBuilder> 
 DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const
 {
   RefPtr<PathBuilderSkia> pb = new PathBuilderSkia(aFillRule);
   return pb;
 }
 
 void
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -95,33 +95,25 @@ public:
   virtual TemporaryRef<SourceSurface>
     CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
   virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FillRule::FILL_WINDING) const;
   virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = ExtendMode::CLAMP) const;
   virtual TemporaryRef<FilterNode> CreateFilter(FilterType aType);
   virtual void SetTransform(const Matrix &aTransform);
+  virtual void *GetNativeSurface(NativeSurfaceType aType);
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
   void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
 
 #ifdef USE_SKIA_GPU
-  virtual GenericRefCountedBase* GetGLContext() const MOZ_OVERRIDE { return mGLContext; }
-  void InitWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
-                                         GrGLInterface* aGrGLInterface,
-                                         const IntSize &aSize,
-                                         SurfaceFormat aFormat) MOZ_OVERRIDE;
-
-  void SetCacheLimits(int aCount, int aSizeInBytes);
-  void PurgeCaches();
-
-  static void SetGlobalCacheLimits(int aCount, int aSizeInBytes);
-  static void RebalanceCacheLimits();
-  static void PurgeAllCaches();
+  void InitWithGrContext(GrContext* aGrContext,
+                         const IntSize &aSize,
+                         SurfaceFormat aFormat) MOZ_OVERRIDE;
 #endif
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 
@@ -129,28 +121,18 @@ private:
   friend class SourceSurfaceSkia;
   void SnapshotDestroyed();
 
   void MarkChanged();
 
   SkRect SkRectCoveringWholeSurface() const;
 
 #ifdef USE_SKIA_GPU
-  /*
-   * These members have inter-dependencies, but do not keep each other alive, so
-   * destruction order is very important here: mGrContext uses mGrGLInterface, and
-   * through it, uses mGLContext, so it is important that they be declared in the
-   * present order.
-   */
-  RefPtr<GenericRefCountedBase> mGLContext;
-  SkRefPtr<GrGLInterface> mGrGLInterface;
   SkRefPtr<GrContext> mGrContext;
-
-  static int sTextureCacheCount;
-  static int sTextureCacheSizeInBytes;
+  uint32_t mTexture;
 #endif
 
   IntSize mSize;
   SkRefPtr<SkCanvas> mCanvas;
   SourceSurfaceSkia* mSnapshot;
 };
 
 }
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -581,40 +581,31 @@ Factory::D2DCleanup()
 {
   DrawTargetD2D::CleanupD2D();
 }
 
 #endif // XP_WIN
 
 #ifdef USE_SKIA_GPU
 TemporaryRef<DrawTarget>
-Factory::CreateDrawTargetSkiaWithGLContextAndGrGLInterface(GenericRefCountedBase* aGLContext,
-                                                           GrGLInterface* aGrGLInterface,
-                                                           const IntSize &aSize,
-                                                           SurfaceFormat aFormat)
+Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
+                                           const IntSize &aSize,
+                                           SurfaceFormat aFormat)
 {
   DrawTargetSkia* newDrawTargetSkia = new DrawTargetSkia();
-  newDrawTargetSkia->InitWithGLContextAndGrGLInterface(aGLContext, aGrGLInterface, aSize, aFormat);
+  newDrawTargetSkia->InitWithGrContext(aGrContext, aSize, aFormat);
   RefPtr<DrawTarget> newTarget = newDrawTargetSkia;
   return newTarget;
 }
 
-void
-Factory::SetGlobalSkiaCacheLimits(int aCount, int aSizeInBytes)
-{
-    DrawTargetSkia::SetGlobalCacheLimits(aCount, aSizeInBytes);
-}
 #endif // USE_SKIA_GPU
 
 void
 Factory::PurgeAllCaches()
 {
-#ifdef USE_SKIA_GPU
-  DrawTargetSkia::PurgeAllCaches();
-#endif
 }
 
 #ifdef USE_SKIA_FREETYPE
 TemporaryRef<GlyphRenderingOptions>
 Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHinting)
 {
   RefPtr<GlyphRenderingOptionsCairo> options =
     new GlyphRenderingOptionsCairo();
--- a/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -91,17 +91,18 @@ MOZ_BEGIN_ENUM_CLASS(FontType, int8_t)
   COREGRAPHICS
 MOZ_END_ENUM_CLASS(FontType)
 
 MOZ_BEGIN_ENUM_CLASS(NativeSurfaceType, int8_t)
   D3D10_TEXTURE,
   CAIRO_SURFACE,
   CAIRO_CONTEXT,
   CGCONTEXT,
-  CGCONTEXT_ACCELERATED
+  CGCONTEXT_ACCELERATED,
+  OPENGL_TEXTURE
 MOZ_END_ENUM_CLASS(NativeSurfaceType)
 
 MOZ_BEGIN_ENUM_CLASS(NativeFontType, int8_t)
   DWRITE_FONT_FACE,
   GDI_FONT_FACE,
   MAC_FONT_FACE,
   SKIA_FONT_FACE,
   CAIRO_FONT_FACE
deleted file mode 100644
--- a/gfx/gl/GLContextSkia.h
+++ /dev/null
@@ -1,8 +0,0 @@
-/* -*- 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 "skia/GrGLInterface.h"
-
-GrGLInterface* CreateGrGLInterfaceFromGLContext(mozilla::gl::GLContext* context);
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -38,16 +38,17 @@ GLScreenBuffer::Create(GLContext* gl,
         return nullptr;
     }
 
     SurfaceFactory_GL* factory = nullptr;
 
 #ifdef MOZ_WIDGET_GONK
     /* On B2G, we want a Gralloc factory, and we want one right at the start */
     if (!factory &&
+        caps.surfaceAllocator &&
         XRE_GetProcessType() != GeckoProcessType_Default)
     {
         factory = new SurfaceFactory_Gralloc(gl, caps);
     }
 #endif
 #ifdef XP_MACOSX
     /* On OSX, we want an IOSurface factory, and we want one right at the start */
     if (!factory)
@@ -65,17 +66,16 @@ GLScreenBuffer::Create(GLContext* gl,
         gl,
         nullptr);
 
     return new GLScreenBuffer(gl, caps, factory, stream);
 }
 
 GLScreenBuffer::~GLScreenBuffer()
 {
-    delete mStream;
     delete mDraw;
     delete mRead;
 
     // bug 914823: it is crucial to destroy the Factory _after_ we destroy
     // the SharedSurfaces around here! Reason: the shared surfaces will want
     // to ask the Allocator (e.g. the ClientLayerManager) to destroy their
     // buffers, but that Allocator may be kept alive by the Factory,
     // as it currently the case in SurfaceFactory_Gralloc holding a nsRefPtr
@@ -373,17 +373,16 @@ GLScreenBuffer::Morph(SurfaceFactory_GL*
     }
 
     if (mStream->mType == streamType)
         return;
 
     SurfaceStream* newStream = SurfaceStream::CreateForType(streamType, mGL, mStream);
     MOZ_ASSERT(newStream);
 
-    delete mStream;
     mStream = newStream;
 }
 
 void
 GLScreenBuffer::Attach(SharedSurface* surface, const gfx::IntSize& size)
 {
     ScopedBindFramebuffer autoFB(mGL);
 
--- a/gfx/gl/GLScreenBuffer.h
+++ b/gfx/gl/GLScreenBuffer.h
@@ -11,16 +11,17 @@
  * actually the screen, just draw to 0. This GLScreenBuffer class takes the
  * logic handling out of GLContext.
 */
 
 #ifndef SCREEN_BUFFER_H_
 #define SCREEN_BUFFER_H_
 
 #include "SurfaceTypes.h"
+#include "SurfaceStream.h"
 #include "GLContextTypes.h"
 #include "GLDefs.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Point.h"
 
 // Forwards:
 class gfxImageSurface;
 
@@ -151,17 +152,17 @@ public:
     static GLScreenBuffer* Create(GLContext* gl,
                                   const gfx::IntSize& size,
                                   const SurfaceCaps& caps);
 
 protected:
     GLContext* const mGL;         // Owns us.
     SurfaceCaps mCaps;
     SurfaceFactory_GL* mFactory;  // Owned by us.
-    SurfaceStream* mStream;       // Owned by us.
+    RefPtr<SurfaceStream> mStream;
 
     DrawBuffer* mDraw;            // Owned by us.
     ReadBuffer* mRead;            // Owned by us.
 
     bool mNeedsBlit;
 
     // Below are the parts that help us pretend to be framebuffer 0:
     GLuint mUserDrawFB;
--- a/gfx/gl/SharedSurfaceGL.cpp
+++ b/gfx/gl/SharedSurfaceGL.cpp
@@ -278,72 +278,102 @@ SharedSurface_Basic::SharedSurface_Basic
                                          bool hasAlpha,
                                          SurfaceFormat format,
                                          GLuint tex)
     : SharedSurface_GL(SharedSurfaceType::Basic,
                        AttachmentType::GLTexture,
                        gl,
                        size,
                        hasAlpha)
-    , mTex(tex)
+    , mTex(tex), mFB(0)
 {
+    mGL->MakeCurrent();
+    mGL->fGenFramebuffers(1, &mFB);
+
+    ScopedBindFramebuffer autoFB(mGL, mFB);
+    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
+                              LOCAL_GL_COLOR_ATTACHMENT0,
+                              LOCAL_GL_TEXTURE_2D,
+                              mTex,
+                              0);
+
+    GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
+    if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
+        mGL->fDeleteFramebuffers(1, &mFB);
+        mFB = 0;
+    }
+
     mData = Factory::CreateDataSourceSurfaceWithStride(size, format,
               GetAlignedStride<4>(size.width * BytesPerPixel(format)));
 }
 
 SharedSurface_Basic::~SharedSurface_Basic()
 {
     if (!mGL->MakeCurrent())
         return;
 
+    if (mFB)
+        mGL->fDeleteFramebuffers(1, &mFB);
+
     mGL->fDeleteTextures(1, &mTex);
 }
 
 void
 SharedSurface_Basic::Fence()
 {
-    MOZ_ASSERT(mData->GetSize() == mGL->OffscreenSize());
+    mGL->MakeCurrent();
 
-    mGL->MakeCurrent();
+    ScopedBindFramebuffer autoFB(mGL, mFB);
 
     DataSourceSurface::MappedSurface map;
     mData->Map(DataSourceSurface::MapType::WRITE, &map);
     nsRefPtr<gfxImageSurface> wrappedData =
       new gfxImageSurface(map.mData,
                           ThebesIntSize(mData->GetSize()),
                           map.mStride,
                           SurfaceFormatToImageFormat(mData->GetFormat()));
-    ReadScreenIntoImageSurface(mGL, wrappedData);
+    ReadPixelsIntoImageSurface(mGL, wrappedData);
     mData->Unmap();
 }
 
 
 
 SharedSurface_GLTexture*
 SharedSurface_GLTexture::Create(GLContext* prodGL,
                                 GLContext* consGL,
                                 const GLFormats& formats,
                                 const gfx::IntSize& size,
-                                bool hasAlpha)
+                                bool hasAlpha,
+                                GLuint texture)
 {
     MOZ_ASSERT(prodGL);
     MOZ_ASSERT(!consGL || prodGL->SharesWith(consGL));
 
     prodGL->MakeCurrent();
-    GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
+
+    GLuint tex = texture;
+
+    bool ownsTex = false;
 
-    return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex);
+    if (!tex) {
+      tex = CreateTextureForOffscreen(prodGL, formats, size);
+      ownsTex = true;
+    }
+
+    return new SharedSurface_GLTexture(prodGL, consGL, size, hasAlpha, tex, ownsTex);
 }
 
 SharedSurface_GLTexture::~SharedSurface_GLTexture()
 {
     if (!mGL->MakeCurrent())
         return;
 
-    mGL->fDeleteTextures(1, &mTex);
+    if (mOwnsTex) {
+        mGL->fDeleteTextures(1, &mTex);
+    }
 
     if (mSync) {
         mGL->fDeleteSync(mSync);
     }
 }
 
 void
 SharedSurface_GLTexture::Fence()
--- a/gfx/gl/SharedSurfaceGL.h
+++ b/gfx/gl/SharedSurfaceGL.h
@@ -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/. */
 
 #ifndef SHARED_SURFACE_GL_H_
 #define SHARED_SURFACE_GL_H_
 
+#include "ScopedGLHelpers.h"
 #include "SharedSurface.h"
 #include "SurfaceFactory.h"
 #include "SurfaceTypes.h"
 #include "GLContextTypes.h"
 #include "nsAutoPtr.h"
 #include "gfxTypes.h"
 #include "mozilla/Mutex.h"
 
@@ -130,16 +131,18 @@ public:
     static SharedSurface_Basic* Cast(SharedSurface* surf) {
         MOZ_ASSERT(surf->Type() == SharedSurfaceType::Basic);
 
         return (SharedSurface_Basic*)surf;
     }
 
 protected:
     const GLuint mTex;
+    GLuint mFB;
+
     RefPtr<gfx::DataSourceSurface> mData;
 
     SharedSurface_Basic(GLContext* gl,
                         const gfx::IntSize& size,
                         bool hasAlpha,
                         gfx::SurfaceFormat format,
                         GLuint tex);
 
@@ -187,42 +190,46 @@ public:
 class SharedSurface_GLTexture
     : public SharedSurface_GL
 {
 public:
     static SharedSurface_GLTexture* Create(GLContext* prodGL,
                                            GLContext* consGL,
                                            const GLFormats& formats,
                                            const gfx::IntSize& size,
-                                           bool hasAlpha);
+                                           bool hasAlpha,
+                                           GLuint texture = 0);
 
     static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
         MOZ_ASSERT(surf->Type() == SharedSurfaceType::GLTextureShare);
 
         return (SharedSurface_GLTexture*)surf;
     }
 
 protected:
     GLContext* mConsGL;
     const GLuint mTex;
+    const bool mOwnsTex;
     GLsync mSync;
     mutable Mutex mMutex;
 
     SharedSurface_GLTexture(GLContext* prodGL,
                             GLContext* consGL,
                             const gfx::IntSize& size,
                             bool hasAlpha,
-                            GLuint tex)
+                            GLuint tex,
+                            bool ownsTex)
         : SharedSurface_GL(SharedSurfaceType::GLTextureShare,
                            AttachmentType::GLTexture,
                            prodGL,
                            size,
                            hasAlpha)
         , mConsGL(consGL)
         , mTex(tex)
+        , mOwnsTex(ownsTex)
         , mSync(0)
         , mMutex("SharedSurface_GLTexture mutex")
     {
     }
 
 public:
     virtual ~SharedSurface_GLTexture();
 
rename from gfx/gl/GLContextSkia.cpp
rename to gfx/gl/SkiaGLGlue.cpp
--- a/gfx/gl/GLContextSkia.cpp
+++ b/gfx/gl/SkiaGLGlue.cpp
@@ -1,39 +1,42 @@
 /* -*- 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 "skia/GrContext.h"
 #include "skia/GrGLInterface.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/ThreadLocal.h"
 #include "mozilla/DebugOnly.h"
 
 /* SkPostConfig.h includes windows.h, which includes windef.h
  * which redefines min/max. We don't want that. */
 #ifdef _WIN32
 #undef min
 #undef max
 #endif
 
 #include "GLContext.h"
+#include "SkiaGLGlue.h"
 
 using mozilla::gl::GLContext;
 using mozilla::gl::GLFeature;
+using mozilla::gl::SkiaGLGlue;
 using mozilla::gfx::DrawTarget;
 
 static mozilla::ThreadLocal<GLContext*> sGLContext;
 
 extern "C" {
 
 void EnsureGLContext(const GrGLInterface* i)
 {
-    const DrawTarget* drawTarget = reinterpret_cast<const DrawTarget*>(i->fCallbackData);
-    GLContext* gl = static_cast<GLContext*>(drawTarget->GetGLContext());
+    const SkiaGLGlue* contextSkia = reinterpret_cast<const SkiaGLGlue*>(i->fCallbackData);
+    GLContext* gl = contextSkia->GetGLContext();
     gl->MakeCurrent();
 
     if (!sGLContext.initialized()) {
       mozilla::DebugOnly<bool> success = sGLContext.init();
       MOZ_ASSERT(success);
     }
     sGLContext.set(gl);
 }
@@ -770,17 +773,17 @@ GrGLvoid glTexGenfv_mozilla(GrGLenum coo
 
 GrGLvoid glVertexPointer_mozilla(GrGLint size, GrGLenum type, GrGLsizei stride, const GrGLvoid* pointer)
 {
     return sGLContext.get()->fVertexPointer(size, type, stride, pointer);
 }
 
 } // extern "C"
 
-GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
+static GrGLInterface* CreateGrGLInterfaceFromGLContext(GLContext* context)
 {
     GrGLInterface* i = new GrGLInterface();
     i->fCallback = EnsureGLContext;
     i->fCallbackData = 0; // must be later initialized to be a valid DrawTargetSkia* pointer
 
     // Core GL functions required by Ganesh
     i->fActiveTexture = glActiveTexture_mozilla;
     i->fAttachShader = glAttachShader_mozilla;
@@ -929,8 +932,19 @@ GrGLInterface* CreateGrGLInterfaceFromGL
     if (context->IsGLES2()) {
         i->fBindingsExported = kES2_GrGLBinding;
     } else {
         i->fBindingsExported = kDesktop_GrGLBinding;
     }
 
     return i;
 }
+
+SkiaGLGlue::SkiaGLGlue(GLContext* context)
+    : mGLContext(context)
+{
+    SkAutoTUnref<GrGLInterface> i(CreateGrGLInterfaceFromGLContext(mGLContext));
+    i->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
+    mGrGLInterface = i;
+    SkAutoTUnref<GrContext> gr(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)mGrGLInterface.get()));
+
+    mGrContext = gr;
+}
new file mode 100755
--- /dev/null
+++ b/gfx/gl/SkiaGLGlue.h
@@ -0,0 +1,64 @@
+/* -*- 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 "mozilla/RefPtr.h"
+
+#ifdef USE_SKIA_GPU
+
+#include "GLContext.h"
+#include "skia/GrGLInterface.h"
+#include "skia/GrContext.h"
+
+namespace mozilla {
+namespace gl {
+
+class SkiaGLGlue : public GenericAtomicRefCounted
+{
+public:
+  SkiaGLGlue(GLContext* context);
+  GLContext* GetGLContext() const { return mGLContext.get(); }
+  GrContext* GetGrContext() const { return mGrContext.get(); }
+
+protected:
+  virtual ~SkiaGLGlue() {
+    /*
+     * These members have inter-dependencies, but do not keep each other alive, so
+     * destruction order is very important here: mGrContext uses mGrGLInterface, and
+     * through it, uses mGLContext
+     */
+    mGrContext = nullptr;
+    mGrGLInterface = nullptr;
+    mGLContext = nullptr;
+  }
+
+private:
+  RefPtr<GLContext> mGLContext;
+  SkRefPtr<GrGLInterface> mGrGLInterface;
+  SkRefPtr<GrContext> mGrContext;
+};
+
+}
+}
+
+#else
+
+class GrContext;
+
+namespace mozilla {
+namespace gl {
+
+class GLContext;
+
+class SkiaGLGlue : public GenericAtomicRefCounted
+{
+public:
+  SkiaGLGlue(GLContext* context);
+  GLContext* GetGLContext() const { return nullptr; }
+  GrContext* GetGrContext() const { return nullptr; }
+};
+}
+}
+
+#endif
\ No newline at end of file
--- a/gfx/gl/SurfaceStream.cpp
+++ b/gfx/gl/SurfaceStream.cpp
@@ -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/. */
 
 #include "SurfaceStream.h"
 
 #include "gfxPoint.h"
 #include "SharedSurface.h"
+#include "SharedSurfaceGL.h"
 #include "SurfaceFactory.h"
 #include "GeckoProfiler.h"
 
 namespace mozilla {
 namespace gfx {
 
 SurfaceStreamType
 SurfaceStream::ChooseGLStreamType(SurfaceStream::OMTC omtc,
@@ -48,16 +49,32 @@ SurfaceStream::CreateForType(SurfaceStre
         default:
             MOZ_CRASH("Invalid Type.");
     }
 
     result->mGLContext = glContext;
     return result;
 }
 
+bool
+SurfaceStream_TripleBuffer::CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory)
+{
+    if (!mProducer) {
+        New(factory, src->Size(), mProducer);
+        if (!mProducer) {
+            return false;
+        }
+    }
+
+    MOZ_ASSERT(src->Size() == mProducer->Size(), "Size mismatch");
+
+    SharedSurface::Copy(src, mProducer, factory);
+    return true;
+}
+
 void
 SurfaceStream::New(SurfaceFactory* factory, const gfx::IntSize& size,
                    SharedSurface*& surf)
 {
     MOZ_ASSERT(!surf);
     surf = factory->NewSharedSurface(size);
 
     if (surf)
--- a/gfx/gl/SurfaceStream.h
+++ b/gfx/gl/SurfaceStream.h
@@ -6,30 +6,31 @@
 #ifndef SURFACESTREAM_H_
 #define SURFACESTREAM_H_
 
 #include <stack>
 #include <set>
 #include "mozilla/Monitor.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/gfx/Point.h"
+#include "mozilla/GenericRefCounted.h"
 #include "SurfaceTypes.h"
 
 namespace mozilla {
 
 namespace gl {
 class GLContext;
 }
 
 namespace gfx {
 class SharedSurface;
 class SurfaceFactory;
 
 // Owned by: ScreenBuffer
-class SurfaceStream
+class SurfaceStream : public GenericAtomicRefCounted
 {
 public:
     typedef enum {
         MainThread,
         OffMainThread
     } OMTC;
 
     static SurfaceStreamType ChooseGLStreamType(OMTC omtc,
@@ -45,16 +46,18 @@ public:
 
     static SurfaceStream* FromHandle(SurfaceStreamHandle handle) {
         return (SurfaceStream*)handle;
     }
 
     const SurfaceStreamType mType;
 
     mozilla::gl::GLContext* GLContext() const { return mGLContext; }
+
+
 protected:
     // |mProd| is owned by us, but can be ripped away when
     // creating a new GLStream from this one.
     SharedSurface* mProducer;
     std::set<SharedSurface*> mSurfaces;
     std::stack<SharedSurface*> mScraps;
     mutable Monitor mMonitor;
     bool mIsAlive;
@@ -116,16 +119,18 @@ public:
      * and have everything work again.
      * One common failure is asking for a too-large |size|.
      */
     virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
                                         const gfx::IntSize& size) = 0;
 
     virtual SharedSurface* Resize(SurfaceFactory* factory, const gfx::IntSize& size);
 
+    virtual bool CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory) { MOZ_ASSERT(0); return false; }
+
 protected:
     // SwapCons will return the same surface more than once,
     // if nothing new has been published.
     virtual SharedSurface* SwapConsumer_NoWait() = 0;
 
 public:
     virtual SharedSurface* SwapConsumer();
 
@@ -184,16 +189,17 @@ protected:
     SharedSurface* mConsumer;
 
     // To support subclasses initializing the mType.
     SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream);
 
 public:
     SurfaceStream_TripleBuffer(SurfaceStream* prevStream);
     virtual ~SurfaceStream_TripleBuffer();
+    virtual bool CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory);
 
 private:
     // Common constructor code.
     void Init(SurfaceStream* prevStream);
 
 public:
     // Done writing to prod, swap prod and staging
     virtual SharedSurface* SwapProducer(SurfaceFactory* factory,
--- a/gfx/gl/moz.build
+++ b/gfx/gl/moz.build
@@ -70,19 +70,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'wind
         'SharedSurfaceANGLE.h',
         'WGLLibrary.h',
     ]
     UNIFIED_SOURCES += [
         'GLContextProviderEGL.cpp',
         'SharedSurfaceANGLE.cpp',
     ]
 if CONFIG['MOZ_ENABLE_SKIA_GPU']:
-    EXPORTS += ['GLContextSkia.h']
+    EXPORTS += ['SkiaGLGlue.h']
     UNIFIED_SOURCES += [
-        'GLContextSkia.cpp',
+        'SkiaGLGlue.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     UNIFIED_SOURCES += ['SharedSurfaceGralloc.cpp']
     EXPORTS += ['SharedSurfaceGralloc.h']
     LOCAL_INCLUDES += ['/widget/gonk']
 
 if gl_provider == 'CGL':
--- a/gfx/layers/CopyableCanvasLayer.cpp
+++ b/gfx/layers/CopyableCanvasLayer.cpp
@@ -27,32 +27,34 @@
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
 CopyableCanvasLayer::CopyableCanvasLayer(LayerManager* aLayerManager, void *aImplData) :
   CanvasLayer(aLayerManager, aImplData)
+  , mStream(nullptr)
 {
   MOZ_COUNT_CTOR(CopyableCanvasLayer);
 }
 
 CopyableCanvasLayer::~CopyableCanvasLayer()
 {
   MOZ_COUNT_DTOR(CopyableCanvasLayer);
 }
 
 void
 CopyableCanvasLayer::Initialize(const Data& aData)
 {
   NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!");
 
   if (aData.mGLContext) {
     mGLContext = aData.mGLContext;
+    mStream = aData.mStream;
     mIsGLAlphaPremult = aData.mIsGLAlphaPremult;
     mNeedsYFlip = true;
     MOZ_ASSERT(mGLContext->IsOffscreen(), "canvas gl context isn't offscreen");
 
     // [Basic Layers, non-OMTC] WebGL layer init.
     // `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer.
   } else if (aData.mDrawTarget) {
     mDrawTarget = aData.mDrawTarget;
@@ -65,17 +67,17 @@ CopyableCanvasLayer::Initialize(const Da
   }
 
   mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height);
 }
 
 bool
 CopyableCanvasLayer::IsDataValid(const Data& aData)
 {
-  return mGLContext == aData.mGLContext;
+  return mGLContext == aData.mGLContext && mStream == aData.mStream;
 }
 
 void
 CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget,
                                   SourceSurface* aMaskSurface)
 {
   if (!IsDirty())
     return;
--- a/gfx/layers/CopyableCanvasLayer.h
+++ b/gfx/layers/CopyableCanvasLayer.h
@@ -17,16 +17,23 @@
 #include "mozilla/Preferences.h"        // for Preferences
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/gfx/2D.h"             // for DrawTarget
 #include "mozilla/mozalloc.h"           // for operator delete, etc
 #include "nsAutoPtr.h"                  // for nsRefPtr
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 
 namespace mozilla {
+
+namespace gfx {
+class SurfaceStream;
+class SharedSurface;
+class SurfaceFactory;
+}
+
 namespace layers {
 
 class CanvasClientWebGL;
 
 /**
  * A shared CanvasLayer implementation that supports copying
  * its contents into a gfxASurface using UpdateSurface.
  */
@@ -49,16 +56,18 @@ protected:
   void UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr,
                     gfx::SourceSurface* aMaskSurface = nullptr);
 
   RefPtr<gfx::SourceSurface> mSurface;
   nsRefPtr<gfxASurface> mDeprecatedSurface;
   nsRefPtr<mozilla::gl::GLContext> mGLContext;
   mozilla::RefPtr<mozilla::gfx::DrawTarget> mDrawTarget;
 
+  RefPtr<gfx::SurfaceStream> mStream;
+
   uint32_t mCanvasFramebuffer;
 
   bool mIsGLAlphaPremult;
   bool mNeedsYFlip;
 
   RefPtr<gfx::DataSourceSurface> mCachedTempSurface;
   nsRefPtr<gfxImageSurface> mDeprecatedCachedTempSurface;
   gfx::IntSize mCachedSize;
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -58,16 +58,17 @@ class FrameLayerBuilder;
 class WebGLContext;
 
 namespace gl {
 class GLContext;
 }
 
 namespace gfx {
 class DrawTarget;
+class SurfaceStream;
 }
 
 namespace css {
 class ComputedTimingFunction;
 }
 
 namespace layers {
 
@@ -1791,24 +1792,32 @@ protected:
  * must not be modified during a layer transaction.
  */
 class CanvasLayer : public Layer {
 public:
   struct Data {
     Data()
       : mDrawTarget(nullptr)
       , mGLContext(nullptr)
+      , mStream(nullptr)
+      , mTexID(0)
       , mSize(0,0)
       , mIsGLAlphaPremult(false)
     { }
 
     // One of these two must be specified for Canvas2D, but never both
     mozilla::gfx::DrawTarget *mDrawTarget; // a DrawTarget for the canvas contents
     mozilla::gl::GLContext* mGLContext; // or this, for GL.
 
+    // Canvas/SkiaGL uses this
+    mozilla::gfx::SurfaceStream* mStream;
+
+    // ID of the texture backing the canvas layer (defaults to 0)
+    uint32_t mTexID;
+
     // The size of the canvas content
     nsIntSize mSize;
 
     // Whether mGLContext contains data that is alpha-premultiplied.
     bool mIsGLAlphaPremult;
   };
 
   /**
--- a/gfx/layers/client/CanvasClient.cpp
+++ b/gfx/layers/client/CanvasClient.cpp
@@ -111,17 +111,28 @@ CanvasClientSurfaceStream::CanvasClientS
   : CanvasClient(aLayerForwarder, aFlags)
 {
 }
 
 void
 CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
 {
   GLScreenBuffer* screen = aLayer->mGLContext->Screen();
-  SurfaceStream* stream = screen->Stream();
+  SurfaceStream* stream = nullptr;
+
+  if (aLayer->mStream) {
+    stream = aLayer->mStream;
+
+    // Copy our current surface to the current producer surface in our stream, then
+    // call SwapProducer to make a new buffer ready.
+    stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
+    stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
+  } else {
+    stream = screen->Stream();
+  }
 
   bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
   bool bufferCreated = false;
   if (isCrossProcess) {
 #ifdef MOZ_WIDGET_GONK
     SharedSurface* surf = stream->SwapConsumer();
     if (!surf) {
       printf_stderr("surf is null post-SwapConsumer!\n");
@@ -250,17 +261,25 @@ DeprecatedCanvasClientSurfaceStream::Upd
   }
 
   NS_ASSERTION(aLayer->mGLContext, "CanvasClientSurfaceStream should only be used with GL canvases");
 
   // the content type won't be used
   mDeprecatedTextureClient->EnsureAllocated(aSize, gfxContentType::COLOR);
 
   GLScreenBuffer* screen = aLayer->mGLContext->Screen();
-  SurfaceStream* stream = screen->Stream();
+  SurfaceStream* stream = nullptr;
+
+  if (aLayer->mStream) {
+    stream = aLayer->mStream;
+    stream->CopySurfaceToProducer(aLayer->mTextureSurface, aLayer->mFactory);
+    stream->SwapProducer(aLayer->mFactory, gfx::IntSize(aSize.width, aSize.height));
+  } else {
+    stream = screen->Stream();
+  }
 
   bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
   if (isCrossProcess) {
     // swap staging -> consumer so we can send it to the compositor
     SharedSurface* surf = stream->SwapConsumer();
     if (!surf) {
       printf_stderr("surf is null post-SwapConsumer!\n");
       return;
--- a/gfx/layers/client/ClientCanvasLayer.cpp
+++ b/gfx/layers/client/ClientCanvasLayer.cpp
@@ -28,59 +28,98 @@
 #include "gfxPrefs.h"                   // for WebGLForceLayersReadback
 
 using namespace mozilla::gfx;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
+ClientCanvasLayer::~ClientCanvasLayer()
+{
+  MOZ_COUNT_DTOR(ClientCanvasLayer);
+  if (mCanvasClient) {
+    mCanvasClient->OnDetach();
+    mCanvasClient = nullptr;
+  }
+  if (mTextureSurface) {
+    delete mTextureSurface;
+  }
+}
+
 void
 ClientCanvasLayer::Initialize(const Data& aData)
 {
   CopyableCanvasLayer::Initialize(aData);
- 
+
   mCanvasClient = nullptr;
 
   if (mGLContext) {
     GLScreenBuffer* screen = mGLContext->Screen();
+
+    SurfaceCaps caps = screen->Caps();
+    if (mStream) {
+      // The screen caps are irrelevant if we're using a separate stream
+      caps = GetContentFlags() & CONTENT_OPAQUE ? SurfaceCaps::ForRGB() : SurfaceCaps::ForRGBA();
+    }
+
     SurfaceStreamType streamType =
         SurfaceStream::ChooseGLStreamType(SurfaceStream::OffMainThread,
                                           screen->PreserveBuffer());
     SurfaceFactory_GL* factory = nullptr;
     if (!gfxPrefs::WebGLForceLayersReadback()) {
       if (ClientManager()->AsShadowForwarder()->GetCompositorBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) {
         if (mGLContext->GetContextType() == GLContextType::EGL) {
           bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
 
           if (!isCrossProcess) {
             // [Basic/OGL Layers, OMTC] WebGL layer init.
-            factory = SurfaceFactory_EGLImage::Create(mGLContext, screen->Caps());
+            factory = SurfaceFactory_EGLImage::Create(mGLContext, caps);
           } else {
             // [Basic/OGL Layers, OOPC] WebGL layer init. (Out Of Process Compositing)
 #ifdef MOZ_WIDGET_GONK
-            factory = new SurfaceFactory_Gralloc(mGLContext, screen->Caps(), ClientManager()->AsShadowForwarder());
+            factory = new SurfaceFactory_Gralloc(mGLContext, caps, ClientManager()->AsShadowForwarder());
 #else
             // we could do readback here maybe
             NS_NOTREACHED("isCrossProcess but not on native B2G!");
 #endif
           }
         } else {
           // [Basic Layers, OMTC] WebGL layer init.
           // Well, this *should* work...
 #ifdef XP_MACOSX
-          factory = new SurfaceFactory_IOSurface(mGLContext, screen->Caps());
+          factory = new SurfaceFactory_IOSurface(mGLContext, caps);
 #else
-          factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, screen->Caps());
+          factory = new SurfaceFactory_GLTexture(mGLContext, nullptr, caps);
 #endif
         }
       }
     }
 
-    if (factory) {
+    if (mStream) {
+      // We're using a stream other than the one in the default screen
+      mFactory = factory;
+      if (!mFactory) {
+        // Absolutely must have a factory here, so create a basic one
+        mFactory = new SurfaceFactory_Basic(mGLContext, caps);
+      }
+
+      gfx::IntSize size = gfx::IntSize(aData.mSize.width, aData.mSize.height);
+      mTextureSurface = SharedSurface_GLTexture::Create(mGLContext, mGLContext,
+                                                        mGLContext->GetGLFormats(),
+                                                        size, caps.alpha, aData.mTexID);
+      SharedSurface* producer = mStream->SwapProducer(mFactory, size);
+      if (!producer) {
+        // Fallback to basic factory
+        delete mFactory;
+        mFactory = new SurfaceFactory_Basic(mGLContext, caps);
+        producer = mStream->SwapProducer(mFactory, size);
+        MOZ_ASSERT(producer, "Failed to create initial canvas surface with basic factory");
+      }
+    } else if (factory) {
       screen->Morph(factory, streamType);
     }
   }
 }
 
 void
 ClientCanvasLayer::RenderLayer()
 {
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -28,27 +28,22 @@ class ShadowableLayer;
 class ClientCanvasLayer : public CopyableCanvasLayer,
                           public ClientLayer
 {
   typedef CanvasClient::CanvasClientType CanvasClientType;
 public:
   ClientCanvasLayer(ClientLayerManager* aLayerManager) :
     CopyableCanvasLayer(aLayerManager,
                         static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
+    , mTextureSurface(nullptr)
+    , mFactory(nullptr)
   {
     MOZ_COUNT_CTOR(ClientCanvasLayer);
   }
-  virtual ~ClientCanvasLayer()
-  {
-    MOZ_COUNT_DTOR(ClientCanvasLayer);
-    if (mCanvasClient) {
-      mCanvasClient->OnDetach();
-      mCanvasClient = nullptr;
-    }
-  }
+  virtual ~ClientCanvasLayer();
 
   virtual void SetVisibleRegion(const nsIntRegion& aRegion)
   {
     NS_ASSERTION(ClientManager()->InConstruction(),
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
@@ -92,16 +87,19 @@ protected:
     if (mGLContext) {
       return CanvasClient::CanvasClientGLContext;
     }
     return CanvasClient::CanvasClientSurface;
   }
 
   RefPtr<CanvasClient> mCanvasClient;
 
+  gfx::SharedSurface* mTextureSurface;
+  gfx::SurfaceFactory* mFactory;
+
   friend class DeprecatedCanvasClient2D;
   friend class CanvasClient2D;
   friend class DeprecatedCanvasClientSurfaceStream;
   friend class CanvasClientSurfaceStream;
 };
 }
 }
 
--- a/gfx/layers/opengl/TextureClientOGL.cpp
+++ b/gfx/layers/opengl/TextureClientOGL.cpp
@@ -81,17 +81,16 @@ SharedTextureClientOGL::Unlock()
 bool
 SharedTextureClientOGL::IsAllocated() const
 {
   return mHandle != 0;
 }
 
 StreamTextureClientOGL::StreamTextureClientOGL(TextureFlags aFlags)
   : TextureClient(aFlags)
-  , mStream(0)
   , mIsLocked(false)
 {
 }
 
 StreamTextureClientOGL::~StreamTextureClientOGL()
 {
   // the data is owned externally.
 }
@@ -126,16 +125,17 @@ StreamTextureClientOGL::ToSurfaceDescrip
   return true;
 }
 
 void
 StreamTextureClientOGL::InitWith(gfx::SurfaceStream* aStream)
 {
   MOZ_ASSERT(!IsAllocated());
   mStream = aStream;
+  mGL = mStream->GLContext();
 }
 
 bool
 StreamTextureClientOGL::IsAllocated() const
 {
   return mStream != 0;
 }
 
--- a/gfx/layers/opengl/TextureClientOGL.h
+++ b/gfx/layers/opengl/TextureClientOGL.h
@@ -92,16 +92,17 @@ public:
 
   virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
 
   void InitWith(gfx::SurfaceStream* aStream);
 
   virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
 
 protected:
-  gfx::SurfaceStream* mStream;
   bool mIsLocked;
+  RefPtr<gfx::SurfaceStream> mStream;
+  RefPtr<gl::GLContext> mGL;
 };
 
 } // namespace
 } // namespace
 
 #endif
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -71,16 +71,19 @@
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "TexturePoolOGL.h"
 #endif
 
 #ifdef USE_SKIA
 #include "mozilla/Hal.h"
 #include "skia/SkGraphics.h"
+
+#include "SkiaGLGlue.h"
+
 #endif
 
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Mutex.h"
 
 #include "nsIGfxInfo.h"
@@ -197,16 +200,18 @@ NS_IMPL_ISUPPORTS1(MemoryPressureObserve
 
 NS_IMETHODIMP
 MemoryPressureObserver::Observe(nsISupports *aSubject,
                                 const char *aTopic,
                                 const char16_t *someData)
 {
     NS_ASSERTION(strcmp(aTopic, "memory-pressure") == 0, "unexpected event topic");
     Factory::PurgeAllCaches();
+
+    gfxPlatform::GetPlatform()->PurgeSkiaCache();
     return NS_OK;
 }
 
 // this needs to match the list of pref font.default.xx entries listed in all.js!
 // the order *must* match the order in eFontPrefLang
 static const char *gPrefLangNames[] = {
     "x-western",
     "x-central-euro",
@@ -261,16 +266,18 @@ gfxPlatform::gfxPlatform()
     // XXX - When 957560 is fixed, the pref can go away entirely
     mLayersUseDeprecated =
         Preferences::GetBool("layers.use-deprecated-textures", true)
         && !gfxPrefs::LayersPreferOpenGL();
 #else
     mLayersUseDeprecated = false;
 #endif
 
+    mSkiaGlue = nullptr;
+
     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
     InitBackendPrefs(canvasMask, BackendType::CAIRO,
                      contentMask, BackendType::CAIRO);
 }
 
 gfxPlatform*
 gfxPlatform::GetPlatform()
@@ -417,20 +424,16 @@ gfxPlatform::Init()
     // ::Shutdown to be called.
     nsCOMPtr<nsISupports> forceReg
         = do_CreateInstance("@mozilla.org/gfx/init;1");
 
     Preferences::RegisterCallbackAndCall(RecordingPrefChanged, "gfx.2d.recording", nullptr);
 
     CreateCMSOutputProfile();
 
-#ifdef USE_SKIA
-    gPlatform->InitializeSkiaCaches();
-#endif
-
     // Listen to memory pressure event so we can purge DrawTarget caches
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
         gPlatform->mMemoryPressureObserver = new MemoryPressureObserver();
         obs->AddObserver(gPlatform->mMemoryPressureObserver, "memory-pressure", false);
     }
 
     RegisterStrongMemoryReporter(new GfxMemoryImageReporter());
@@ -820,19 +823,18 @@ gfxPlatform::SupportsAzureContentForDraw
 bool
 gfxPlatform::UseAcceleratedSkiaCanvas()
 {
   return gfxPrefs::CanvasAzureAccelerated() &&
          mPreferredCanvasBackend == BackendType::SKIA;
 }
 
 void
-gfxPlatform::InitializeSkiaCaches()
+gfxPlatform::InitializeSkiaCacheLimits()
 {
-#ifdef USE_SKIA_GPU
   if (UseAcceleratedSkiaCanvas()) {
     bool usingDynamicCache = gfxPrefs::CanvasSkiaGLDynamicCache();
     int cacheItemLimit = gfxPrefs::CanvasSkiaGLCacheItems();
     int cacheSizeLimit = gfxPrefs::CanvasSkiaGLCacheSize();
 
     // Prefs are in megabytes, but we want the sizes in bytes
     cacheSizeLimit *= 1024*1024;
 
@@ -842,22 +844,57 @@ gfxPlatform::InitializeSkiaCaches()
       if (totalMemory <= 256*1024*1024) {
         // We need a very minimal cache on 256 meg devices
         cacheSizeLimit = 2*1024*1024;
       } else if (totalMemory > 0) {
         cacheSizeLimit = totalMemory / 16;
       }
     }
 
-#ifdef DEBUG
+  #ifdef DEBUG
     printf_stderr("Determined SkiaGL cache limits: Size %i, Items: %i\n", cacheSizeLimit, cacheItemLimit);
+  #endif
+
+    mSkiaGlue->GetGrContext()->setTextureCacheLimits(cacheItemLimit, cacheSizeLimit);
+  }
+}
+
+mozilla::gl::SkiaGLGlue*
+gfxPlatform::GetSkiaGLGlue()
+{
+#ifdef USE_SKIA_GPU
+  if (!mSkiaGlue) {
+    /* Dummy context. We always draw into a FBO.
+     *
+     * FIXME: This should be stored in TLS or something, since there needs to be one for each thread using it. As it
+     * stands, this only works on the main thread.
+     */
+    mozilla::gfx::SurfaceCaps caps = mozilla::gfx::SurfaceCaps::ForRGBA();
+    nsRefPtr<mozilla::gl::GLContext> glContext = mozilla::gl::GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
+    if (!glContext) {
+      printf_stderr("Failed to create GLContext for SkiaGL!\n");
+      return nullptr;
+    }
+    mSkiaGlue = new mozilla::gl::SkiaGLGlue(glContext);
+    MOZ_ASSERT(mSkiaGlue->GetGrContext(), "No GrContext");
+    InitializeSkiaCacheLimits();
+  }
 #endif
 
-    Factory::SetGlobalSkiaCacheLimits(cacheItemLimit, cacheSizeLimit);
-  }
+  return mSkiaGlue;
+}
+
+void
+gfxPlatform::PurgeSkiaCache()
+{
+#ifdef USE_SKIA_GPU
+  if (!mSkiaGlue)
+      return;
+
+  mSkiaGlue->GetGrContext()->freeGpuResources();
 #endif
 }
 
 already_AddRefed<gfxASurface>
 gfxPlatform::GetThebesSurfaceForDrawTarget(DrawTarget *aTarget)
 {
   if (aTarget->GetType() == BackendType::CAIRO) {
     cairo_surface_t* csurf =
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -35,16 +35,17 @@ class gfxTextRun;
 class nsIURI;
 class nsIAtom;
 class nsIObserver;
 struct gfxRGBA;
 
 namespace mozilla {
 namespace gl {
 class GLContext;
+class SkiaGLGlue;
 }
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 class ScaledFont;
 class DrawEventRecorder;
 
 inline uint32_t
@@ -278,18 +279,17 @@ public:
      */
     bool SupportsAzureContentForDrawTarget(mozilla::gfx::DrawTarget* aTarget);
 
     bool SupportsAzureContentForType(mozilla::gfx::BackendType aType) {
       return BackendTypeBit(aType) & mContentBackendBitmask;
     }
 
     virtual bool UseAcceleratedSkiaCanvas();
-
-    virtual void InitializeSkiaCaches();
+    virtual void InitializeSkiaCacheLimits();
 
     void GetAzureBackendInfo(mozilla::widget::InfoObject &aObj) {
       aObj.DefineProperty("AzureCanvasBackend", GetBackendName(mPreferredCanvasBackend));
       aObj.DefineProperty("AzureSkiaAccelerated", UseAcceleratedSkiaCanvas());
       aObj.DefineProperty("AzureFallbackCanvasBackend", GetBackendName(mFallbackCanvasBackend));
       aObj.DefineProperty("AzureContentBackend", GetBackendName(mContentBackend));
     }
 
@@ -593,16 +593,19 @@ public:
      * Returns true if we should use raw memory to send data to the compositor
      * rather than using shmems.
      *
      * This method should not be called from the compositor thread.
      */
     bool PreferMemoryOverShmem() const;
     bool UseDeprecatedTextures() const { return mLayersUseDeprecated; }
 
+    mozilla::gl::SkiaGLGlue* GetSkiaGLGlue();
+    void PurgeSkiaCache();
+
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen, 
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
@@ -706,11 +709,12 @@ private:
     // Bitmask of backend types we can use to render content
     uint32_t mContentBackendBitmask;
 
     mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
 
     mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
     bool mLayersPreferMemoryOverShmem;
     bool mLayersUseDeprecated;
+    mozilla::RefPtr<mozilla::gl::SkiaGLGlue> mSkiaGlue;
 };
 
 #endif /* GFX_PLATFORM_H */