Bug 570294, part c: C++ part of Layers IPC interface. r=Bas sr=vlad
authorChris Jones <jones.chris.g@gmail.com>
Wed, 21 Jul 2010 16:17:33 -0500
changeset 48136 f3ee7f068902cfcd619766029fc92e6736ea82b4
parent 48135 6ee9399bde01da63f0d95e3f7bd8f811262407d4
child 48137 e6299aaa482e4231d8c6ce214efe04b8cdff2440
push id14589
push usercjones@mozilla.com
push dateFri, 23 Jul 2010 17:12:29 +0000
treeherdermozilla-central@49185ce20807 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas, vlad
bugs570294
milestone2.0b3pre
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 570294, part c: C++ part of Layers IPC interface. r=Bas sr=vlad
gfx/layers/Layers.h
gfx/layers/Makefile.in
gfx/layers/ipc/ShadowLayers.h
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -72,16 +72,17 @@ namespace layers {
 
 class Layer;
 class ThebesLayer;
 class ContainerLayer;
 class ImageLayer;
 class ColorLayer;
 class ImageContainer;
 class CanvasLayer;
+class SpecificLayerAttributes;
 
 #define MOZ_LAYER_DECL_NAME(n, e)                           \
   virtual const char* Name() const { return n; }            \
   virtual LayerType GetType() const { return e; }
 
 /*
  * Motivation: For truly smooth animation and video playback, we need to
  * be able to compose frames and render them on a dedicated thread (i.e.
@@ -315,17 +316,18 @@ class THEBES_API Layer {
   NS_INLINE_DECL_REFCOUNTING(Layer)  
 
 public:
   enum LayerType {
     TYPE_THEBES,
     TYPE_CONTAINER,
     TYPE_IMAGE,
     TYPE_COLOR,
-    TYPE_CANVAS
+    TYPE_CANVAS,
+    TYPE_SHADOW
   };
 
   virtual ~Layer() {}
 
   /**
    * Returns the LayoutManager this Layer belongs to. Cannot be null.
    */
   LayerManager* Manager() { return mManager; }
@@ -425,16 +427,24 @@ public:
   PRBool IsOpaqueContent() { return mIsOpaqueContent; }
   const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; }
   ContainerLayer* GetParent() { return mParent; }
   Layer* GetNextSibling() { return mNextSibling; }
   Layer* GetPrevSibling() { return mPrevSibling; }
   virtual Layer* GetFirstChild() { return nsnull; }
   const gfx3DMatrix& GetTransform() { return mTransform; }
 
+  /**
+   * DRAWING PHASE ONLY
+   *
+   * Write layer-subtype-specific attributes into aAttrs.  Used to
+   * synchronize layer attributes to their shadows'.
+   */
+  virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs) { }
+
   // Returns true if it's OK to save the contents of aLayer in an
   // opaque surface (a surface without an alpha channel).
   // If we can use a surface without an alpha channel, we should, because
   // it will often make painting of antialiased text faster and higher
   // quality.
   PRBool CanUseOpaqueSurface();
 
   // This setter and getter can be used anytime. The user data is initially
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -42,16 +42,20 @@ VPATH       = \
   $(srcdir) \
   $(srcdir)/basic \
   $(srcdir)/opengl \
   $(srcdir)/d3d9 \
   $(NULL)
 
 include $(DEPTH)/config/autoconf.mk
 
+ifdef MOZ_IPC
+VPATH       += $(srcdir)/ipc
+endif
+
 MODULE         = thebes
 LIBRARY_NAME   = layers
 LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 
 DEFINES += -DIMPL_THEBES
 ifdef MOZ_DEBUG
 DEFINES += -DD3D_DEBUG_INFO
@@ -97,16 +101,20 @@ endif
 ifdef MOZ_X11
 ifdef MOZ_PLATFORM_MAEMO
 DEFINES += -DUSE_GLES2
 endif
 endif
 
 include $(topsrcdir)/config/rules.mk
 
+ifdef MOZ_IPC
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
+endif
+
 CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
 
 LayerManagerOGLShaders.h: LayerManagerOGLShaders.txt genshaders.py $(GLOBAL_DEPS)
 	$(PYTHON) $(srcdir)/opengl/genshaders.py $< $@
 
 LayerManagerOGL.$(OBJ_SUFFIX): LayerManagerOGLShaders.h
 
 GARBAGE += LayerManagerOGLShaders.h
new file mode 100644
--- /dev/null
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -0,0 +1,406 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Chris Jones <jones.chris.g@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_layers_ShadowLayers_h
+#define mozilla_layers_ShadowLayers_h 1
+
+#include "gfxASurface.h"
+
+#include "ImageLayers.h"
+#include "Layers.h"
+
+class gfxSharedImageSurface;
+
+namespace mozilla {
+namespace layers {
+
+struct Edit;
+struct EditReply;
+class PLayerChild;
+class PLayersChild;
+class PLayersParent;
+class ShadowableLayer;
+class ShadowThebesLayer;
+class ShadowImageLayer;
+class ShadowCanvasLayer;
+class Transaction;
+
+/**
+ * We want to share layer trees across thread contexts and address
+ * spaces for several reasons; chief among them
+ *
+ *  - a parent process can paint a child process's layer tree while
+ *    the child process is blocked, say on content script.  This is
+ *    important on mobile devices where UI responsiveness is key.
+ *
+ *  - a dedicated "compositor" process can asynchronously (wrt the
+ *    browser process) composite and animate layer trees, allowing a
+ *    form of pipeline parallelism between compositor/browser/content
+ *
+ *  - a dedicated "compositor" process can take all responsibility for
+ *    accessing the GPU, which is desirable on systems with
+ *    buggy/leaky drivers because the compositor process can die while
+ *    browser and content live on (and failover mechanisms can be
+ *    installed to quickly bring up a replacement compositor)
+ *
+ * The Layers model has a crisply defined API, which makes it easy to
+ * safely "share" layer trees.  The ShadowLayers API extends Layers to
+ * allow a remote, parent process to access a child process's layer
+ * tree.
+ *
+ * ShadowLayerForwarder publishes a child context's layer tree to a
+ * parent context.  This comprises recording layer-tree modifications
+ * into atomic transactions and pushing them over IPC.
+ *
+ * ShadowLayerManager grafts layer subtrees published by child-context
+ * ShadowLayerForwarder(s) into a parent-context layer tree.
+ *
+ * (Advanced note: because our process tree may have a height >2, a
+ * non-leaf subprocess may both receive updates from child processes
+ * and publish them to parent processes.  Put another way,
+ * LayerManagers may be both ShadowLayerManagers and
+ * ShadowLayerForwarders.)
+ *
+ * There are only shadow types for layers that have different shadow
+ * vs. not-shadow behavior.  ColorLayers and ContainerLayers behave
+ * the same way in both regimes (so far).
+ */
+
+class ShadowLayerForwarder
+{
+public:
+  virtual ~ShadowLayerForwarder();
+
+  /**
+   * Begin recording a transaction to be forwarded atomically to a
+   * ShadowLayerManager.
+   */
+  void BeginTransaction();
+
+  /**
+   * The following methods may only be called after BeginTransaction()
+   * but before EndTransaction().  They mirror the LayerManager
+   * interface in Layers.h.
+   */
+
+  /**
+   * Notify the shadow manager that a new, "real" layer has been
+   * created, and a corresponding shadow layer should be created in
+   * the compositing process.
+   */
+  void CreatedThebesLayer(ShadowableLayer* aThebes);
+  void CreatedContainerLayer(ShadowableLayer* aContainer);
+  void CreatedImageLayer(ShadowableLayer* aImage);
+  void CreatedColorLayer(ShadowableLayer* aColor);
+  void CreatedCanvasLayer(ShadowableLayer* aCanvas);
+
+  /**
+   * Notify the shadow manager that a buffer has been created for the
+   * specificed layer.  |aInitialFrontSurface| is one of the newly
+   * created, transparent black buffers for the layer; the "real"
+   * layer holds on to the other as its back buffer.  We send it
+   * across on buffer creation to avoid special cases in the buffer
+   * swapping logic for Painted*() operations.
+   *
+   * It is expected that Created*Buffer() will be followed by a
+   * Painted*Buffer() in the same transaction, so that
+   * |aInitialFrontBuffer| is never actually drawn to screen.
+   */
+  /**
+   * |aBufferRect| is the screen rect covered by |aInitialFrontBuffer|.
+   */
+  void CreatedThebesBuffer(ShadowableLayer* aThebes,
+                           nsIntRect aBufferRect,
+                           gfxSharedImageSurface* aInitialFrontBuffer);
+  /**
+   * For the next two methods, |aSize| is the size of
+   * |aInitialFrontSurface|.
+   */
+  void CreatedImageBuffer(ShadowableLayer* aImage,
+                          nsIntSize aSize,
+                          gfxSharedImageSurface* aInitialFrontSurface);
+  void CreatedCanvasBuffer(ShadowableLayer* aCanvas,
+                           nsIntSize aSize,
+                           gfxSharedImageSurface* aInitialFrontSurface);
+
+  /**
+   * At least one attribute of |aMutant| has changed, and |aMutant|
+   * needs to sync to its shadow layer.  This initial implementation
+   * forwards all attributes when any is mutated.
+   */
+  void Mutated(ShadowableLayer* aMutant);
+
+  void SetRoot(ShadowableLayer* aRoot);
+  /**
+   * Insert |aChild| after |aAfter| in |aContainer|.  |aAfter| can be
+   * NULL to indicated that |aChild| should be appended to the end of
+   * |aContainer|'s child list.
+   */
+  void InsertAfter(ShadowableLayer* aContainer,
+                   ShadowableLayer* aChild,
+                   ShadowableLayer* aAfter=NULL);
+  void RemoveChild(ShadowableLayer* aContainer,
+                   ShadowableLayer* aChild);
+
+  /**
+   * Notify the shadow manager that the specified layer's back buffer
+   * has new pixels and should become the new front buffer, and be
+   * re-rendered, in the compositing process.  The former front buffer
+   * is swapped for |aNewFrontBuffer| and becomes the new back buffer
+   * for the "real" layer.
+   */
+  /**
+   * |aBufferRect| is the screen rect covered as a whole by the
+   * possibly-toroidally-rotated |aNewFrontBuffer|.  |aBufferRotation|
+   * is buffer's rotation, if any.
+   */
+  void PaintedThebesBuffer(ShadowableLayer* aThebes,
+                           nsIntRect aBufferRect,
+                           nsIntPoint aBufferRotation,
+                           gfxSharedImageSurface* aNewFrontBuffer);
+  /**
+   * NB: this initial implementation only forwards RGBA data for
+   * ImageLayers.  This is slow, and will be optimized.
+   */
+  void PaintedImage(ShadowableLayer* aImage,
+                    gfxSharedImageSurface* aNewFrontSurface);
+  void PaintedCanvas(ShadowableLayer* aCanvas,
+                     gfxSharedImageSurface* aNewFrontSurface);
+
+  /**
+   * End the current transaction and forward it to ShadowLayerManager.
+   * |aReplies| are directions from the ShadowLayerManager to the
+   * caller of EndTransaction().
+   */
+  PRBool EndTransaction(nsTArray<EditReply>* aReplies);
+
+  /**
+   * True if this is forwarding to a ShadowLayerManager.
+   */
+  PRBool HasShadowManager() { return !!mShadowManager; }
+
+  PRBool AllocDoubleBuffer(const gfxIntSize& aSize,
+                           gfxASurface::gfxImageFormat aFormat,
+                           gfxSharedImageSurface** aFrontBuffer,
+                           gfxSharedImageSurface** aBackBuffer);
+
+  void DestroySharedSurface(gfxSharedImageSurface* aSurface);
+
+  /**
+   * Construct a shadow of |aLayer| on the "other side", at the
+   * ShadowLayerManager.
+   */
+  PLayerChild* ConstructShadowFor(ShadowableLayer* aLayer);
+
+protected:
+  ShadowLayerForwarder();
+
+  PLayersChild* mShadowManager;
+
+private:
+  Transaction* mTxn;
+};
+
+
+class ShadowLayerManager : public LayerManager
+{
+public:
+  virtual ~ShadowLayerManager() {}
+
+  PRBool HasForwarder() { return !!mForwarder; }
+
+  void SetForwarder(PLayersParent* aForwarder)
+  {
+    NS_ASSERTION(!HasForwarder(), "setting forwarder twice?");
+    mForwarder = aForwarder;
+  }
+
+  void DestroySharedSurface(gfxSharedImageSurface* aSurface);
+
+  /** CONSTRUCTION PHASE ONLY */
+  virtual already_AddRefed<ShadowThebesLayer> CreateShadowThebesLayer() = 0;
+  /** CONSTRUCTION PHASE ONLY */
+  virtual already_AddRefed<ShadowImageLayer> CreateShadowImageLayer() = 0;
+  /** CONSTRUCTION PHASE ONLY */
+  virtual already_AddRefed<ShadowCanvasLayer> CreateShadowCanvasLayer() = 0;
+
+protected:
+  ShadowLayerManager() : mForwarder(NULL) {}
+
+  PLayersParent* mForwarder;
+};
+
+
+/**
+ * A ShadowableLayer is a Layer can be shared with a parent context
+ * through a ShadowLayerForwarder.  A ShadowableLayer maps to a
+ * Shadow*Layer in a parent context.
+ *
+ * Note that ShadowLayers can themselves be ShadowableLayers.
+ */
+class ShadowableLayer
+{
+public:
+  virtual ~ShadowableLayer() {}
+
+  virtual Layer* AsLayer() = 0;
+
+  /**
+   * True if this layer has a shadow in a parent process.
+   */
+  PRBool HasShadow() { return !!mShadow; }
+
+  /**
+   * Return the IPC handle to a Shadow*Layer referring to this if one
+   * exists, NULL if not.
+   */
+  PLayerChild* GetShadow() { return mShadow; }
+
+protected:
+  ShadowableLayer() : mShadow(NULL) {}
+
+  PLayerChild* mShadow;
+};
+
+
+class ShadowThebesLayer : public ThebesLayer
+{
+public:
+  virtual void InvalidateRegion(const nsIntRegion& aRegion)
+  {
+    NS_RUNTIMEABORT("ShadowThebesLayers can't fill invalidated regions");
+  }
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   */
+  void SetValidRegion(const nsIntRegion& aRegion)
+  {
+    mValidRegion = aRegion;
+    Mutated();
+  }
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   *
+   * Publish the remote layer's back ThebesLayerBuffer to this shadow,
+   * swapping out the old front ThebesLayerBuffer (the new back buffer
+   * for the remote layer).
+   *
+   * XXX should the receiving process blit updates from the new front
+   * buffer to the previous front buffer (new back buffer) while it has
+   * access to the new front buffer?  Or is it better to fill the
+   * updates bits in anew on the new back buffer?
+   *
+   * Seems like memcpy()s from new-front to new-back would have to
+   * always be no slower than any kind of fill from content, so one
+   * would expect the former to win in terms of total throughput.
+   * However, that puts the blit on the critical path of
+   * publishing-process-blocking-on-receiving-process, so
+   * responsiveness might suffer, pointing to the latter.  Experience
+   * will tell!  (Maybe possible to choose between both depending on
+   * size of blit vs. expense of re-fill?)
+   */
+  virtual already_AddRefed<gfxSharedImageSurface>
+  Swap(gfxSharedImageSurface* aNewFront,
+       const nsIntRect& aBufferRect,
+       const nsIntPoint& aRotation) = 0;
+
+  MOZ_LAYER_DECL_NAME("ShadowThebesLayer", TYPE_SHADOW)
+
+protected:
+  ShadowThebesLayer(LayerManager* aManager, void* aImplData) :
+    ThebesLayer(aManager, aImplData) {}
+};
+
+
+class ShadowCanvasLayer : public CanvasLayer
+{
+public:
+  /**
+   * CONSTRUCTION PHASE ONLY
+   *
+   * Publish the remote layer's back surface to this shadow, swapping
+   * out the old front surface (the new back surface for the remote
+   * layer).
+   */
+  virtual already_AddRefed<gfxSharedImageSurface>
+  Swap(gfxSharedImageSurface* aNewFront) = 0;
+
+  MOZ_LAYER_DECL_NAME("ShadowCanvasLayer", TYPE_SHADOW)
+
+protected:
+  ShadowCanvasLayer(LayerManager* aManager, void* aImplData) :
+    CanvasLayer(aManager, aImplData) {}
+};
+
+
+class ShadowImageLayer : public ImageLayer
+{
+public:
+  /**
+   * CONSTRUCTION PHASE ONLY
+   *
+   * Initialize this with a (temporary) front surface with the given
+   * size.  This is expected to be followed with a Swap() in the same
+   * transaction to bring in real pixels.  Init() may only be called
+   * once.
+   */
+  virtual PRBool Init(gfxSharedImageSurface* aFront, const nsIntSize& aSize) = 0;
+
+  /**
+   * CONSTRUCTION PHASE ONLY
+   * @see ShadowCanvasLayer::Swap
+   */
+  virtual already_AddRefed<gfxSharedImageSurface>
+  Swap(gfxSharedImageSurface* newFront) = 0;
+
+  MOZ_LAYER_DECL_NAME("ShadowImageLayer", TYPE_SHADOW)
+
+protected:
+  ShadowImageLayer(LayerManager* aManager, void* aImplData) :
+    ImageLayer(aManager, aImplData) {}
+};
+
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // ifndef mozilla_layers_ShadowLayers_h