Merge last PGO-green changeset of mozilla-inbound to mozilla-central
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 19 Nov 2012 22:15:02 -0800
changeset 113785 bc69705c162dad69a4c6b42aedbd10a75d7d1a77
parent 113699 cd8533b0fae7641fca51d4adf5f61bbfb1d719ec (current diff)
parent 113716 669ac8371d192b66409e633bde26914a70385766 (diff)
child 113786 a9d59073400bbc2980b3562c8ef9b3aea9a67809
push id18384
push useremorley@mozilla.com
push dateTue, 20 Nov 2012 15:57:40 +0000
treeherdermozilla-inbound@74f765e3695b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.0a1
first release with
nightly linux32
bc69705c162d / 20.0a1 / 20121120030739 / files
nightly linux64
bc69705c162d / 20.0a1 / 20121120030739 / files
nightly mac
bc69705c162d / 20.0a1 / 20121120030739 / files
nightly win32
bc69705c162d / 20.0a1 / 20121120030739 / files
nightly win64
bc69705c162d / 20.0a1 / 20121120030739 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
--- a/.hgtags
+++ b/.hgtags
@@ -83,8 +83,9 @@ 357da346ceb705d196a46574804c7c4ec44ac186
 26dcd1b1a20893ad99341c61c6b1239ff1523858 FIREFOX_AURORA_15_BASE
 0accd12a8e7e217836ea3f1ee7c411913fc75d8e FIREFOX_AURORA_16_BASE
 0000000000000000000000000000000000000000 FIREFOX_AURORA_16_BASE
 9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
 9697eadafa13b4e9233b39aaeecfeac79503cb54 FIREFOX_AURORA_16_BASE
 6fdf9985acfe6f939da584b2559464ab22264fe7 FIREFOX_AURORA_16_BASE
 fd72dbbd692012224145be1bf13df1d7675fd277 FIREFOX_AURORA_17_BASE
 2704e441363fe2a48e992dfac694482dfd82664a FIREFOX_AURORA_18_BASE
+cf8750abee06cde395c659f8ecd8ae019d7512e3 FIREFOX_AURORA_19_BASE
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,16 +1,16 @@
 # 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/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=19.0a1
+MOZ_APP_VERSION=20.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_UA_OS_AGNOSTIC=1
 
 MOZ_B2G_VERSION=1.0.0-prerelease
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1,1 +1,1 @@
-19.0a1
+20.0a1
--- a/config/milestone.txt
+++ b/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-19.0a1
+20.0a1
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -14,17 +14,17 @@
 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
 #elif defined(MOZ_WIDGET_QT)
 #include <QtOpenGL/QGLContext>
 #define GLdouble_defined 1
 // we're using default display for now
 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)static_cast<QWidget*>(aWidget->GetNativeData(NS_NATIVE_SHELLWIDGET))->winId()
 #elif defined(MOZ_WIDGET_GONK)
 #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
-#include "HWComposer.h"
+#include "HwcComposer2D.h"
 #endif
 
 #if defined(MOZ_X11)
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include "mozilla/X11Util.h"
 #include "gfxXlibSurface.h"
 #endif
@@ -260,22 +260,24 @@ public:
     {
         // any EGL contexts will always be GLESv2
         SetIsGLES2(true);
 
 #ifdef DEBUG
         printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 #ifdef MOZ_WIDGET_GONK
-        if (!aIsOffscreen)
-            mHwc = new HWComposer();
-
-        if (mHwc && mHwc->init()) {
-            NS_WARNING("HWComposer initialization failed!");
-            mHwc = nullptr;
+        if (!aIsOffscreen) {
+            mHwc = HwcComposer2D::GetInstance();
+            MOZ_ASSERT(!mHwc->Initialized());
+
+            if (mHwc->Init(EGL_DISPLAY(), mSurface)) {
+                NS_WARNING("HWComposer initialization failed!");
+                mHwc = nullptr;
+            }
         }
 #endif
     }
 
     ~GLContextEGL()
     {
         if (MakeCurrent()) {
             if (mTemporaryEGLImageTexture != 0) {
@@ -667,17 +669,17 @@ protected:
     nsRefPtr<gfxASurface> mThebesSurface;
     bool mBound;
 
     bool mIsPBuffer;
     bool mIsDoubleBuffered;
     bool mCanBindToTexture;
     bool mShareWithEGLImage;
 #ifdef MOZ_WIDGET_GONK
-    nsAutoPtr<HWComposer> mHwc;
+    nsRefPtr<HwcComposer2D> mHwc;
 #endif
 
     // A dummy texture ID that can be used when we need a texture object whose
     // images we're going to define with EGLImageTargetTexture2D.
     GLuint mTemporaryEGLImageTexture;
 
     static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
                                                            EGLenum bindToTextureFormat,
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -895,16 +895,22 @@ public:
   virtual ContainerLayer* AsContainerLayer() { return nullptr; }
 
    /**
     * Dynamic cast to a RefLayer. Returns null if this is not a
     * RefLayer.
     */
   virtual RefLayer* AsRefLayer() { return nullptr; }
 
+   /**
+    * Dynamic cast to a Color. Returns null if this is not a
+    * ColorLayer.
+    */
+  virtual ColorLayer* AsColorLayer() { return nullptr; }
+
   /**
    * Dynamic cast to a ShadowLayer.  Return null if this is not a
    * ShadowLayer.  Can be used anytime.
    */
   virtual ShadowLayer* AsShadowLayer() { return nullptr; }
 
   /**
    * Dynamic cast to a ShadowableLayer.  Return null if this is not a
@@ -1358,16 +1364,18 @@ protected:
 
 /**
  * A Layer which just renders a solid color in its visible region. It actually
  * can fill any area that contains the visible region, so if you need to
  * restrict the area filled, set a clip region on this layer.
  */
 class THEBES_API ColorLayer : public Layer {
 public:
+  virtual ColorLayer* AsColorLayer() { return this; }
+
   /**
    * CONSTRUCTION PHASE ONLY
    * Set the color of the layer.
    */
   virtual void SetColor(const gfxRGBA& aColor)
   {
     mColor = aColor;
   }
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -26,16 +26,17 @@ DEFINES += -DIMPL_THEBES
 ifdef MOZ_DEBUG
 DEFINES += -DD3D_DEBUG_INFO
 endif
 
 EXPORTS = \
         BasicLayers.h \
         BasicTiledThebesLayer.h \
         BasicImplData.h \
+        Composer2D.h \
         GonkIOSurfaceImage.h \
         FrameMetrics.h \
         CompositorChild.h \
         CompositorParent.h \
         ImageContainer.h \
         ImageLayers.h \
         ImageTypes.h \
         Layers.h \
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp
+++ b/gfx/layers/opengl/CanvasLayerOGL.cpp
@@ -471,16 +471,26 @@ ShadowCanvasLayerOGL::Destroy()
 }
 
 Layer*
 ShadowCanvasLayerOGL::GetLayer()
 {
   return this;
 }
 
+LayerRenderState
+ShadowCanvasLayerOGL::GetRenderState()
+{
+  if (mDestroyed) {
+    return LayerRenderState();
+  }
+  return LayerRenderState(&mFrontBufferDescriptor,
+                          mNeedsYFlip ? LAYER_RENDER_STATE_Y_FLIPPED : 0);
+}
+
 void
 ShadowCanvasLayerOGL::RenderLayer(int aPreviousFrameBuffer,
                                   const nsIntPoint& aOffset)
 {
   if (!mTexImage && !IsValidSharedTexDescriptor(mFrontBufferDescriptor)) {
     return;
   }
 
--- a/gfx/layers/opengl/CanvasLayerOGL.h
+++ b/gfx/layers/opengl/CanvasLayerOGL.h
@@ -121,16 +121,17 @@ public:
 
   virtual void DestroyFrontBuffer();
 
   virtual void Disconnect();
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
+  virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
   virtual void CleanupResources();
 
 private:
   nsRefPtr<TextureImage> mTexImage;
 
   bool mNeedsYFlip;
new file mode 100644
--- /dev/null
+++ b/gfx/layers/opengl/Composer2D.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* 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_layers_Composer2D_h
+#define mozilla_layers_Composer2D_h
+
+#include "gfxTypes.h"
+#include "nsISupportsImpl.h"
+
+/**
+ * Many platforms have dedicated hardware for simple composition.
+ * This hardware is usually faster or more power efficient than the
+ * GPU.  However, in exchange for this better performance, generality
+ * has to be sacrificed: no 3d transforms, no intermediate surfaces,
+ * no special shader effects, loss of other goodies depending on the
+ * platform.
+ *
+ * Composer2D is a very simple interface to this class of hardware
+ * that allows an implementation to "try rendering" with the fast
+ * path.  If the given layer tree requires more generality than the
+ * hardware provides, the implementation should bail and have the
+ * layer manager fall back on full GPU composition.
+ */
+
+class gfxMatrix;
+
+namespace mozilla {
+namespace layers {
+
+class Layer;
+
+class THEBES_API Composer2D {
+  NS_INLINE_DECL_REFCOUNTING(Composer2D)
+
+public:
+  virtual ~Composer2D() {}
+
+  /**
+   * Return true if |aRoot| met the implementation's criteria for fast
+   * composition and the render was successful.  Return false to fall
+   * back on the GPU.
+   *
+   * |aWorldTransform| must be applied to |aRoot|'s subtree when
+   * rendering to the framebuffer.  This is a global transform on the
+   * entire scene, defined in GL space.  If the Composer2D
+   * implementation is unable to honor the transform, it should return
+   * false.
+   *
+   * Currently, when TryRender() returns true, the entire framebuffer
+   * must have been rendered.
+   */
+  virtual bool TryRender(Layer* aRoot, const gfxMatrix& aWorldTransform) = 0;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_Composer2D_h
--- a/gfx/layers/opengl/ImageLayerOGL.cpp
+++ b/gfx/layers/opengl/ImageLayerOGL.cpp
@@ -812,16 +812,38 @@ ShadowImageLayerOGL::Destroy()
 }
 
 Layer*
 ShadowImageLayerOGL::GetLayer()
 {
   return this;
 }
 
+LayerRenderState
+ShadowImageLayerOGL::GetRenderState()
+{
+  if (!mImageContainerID) {
+    return LayerRenderState();
+  }
+
+  // Update the associated compositor ID in case Composer2D succeeds,
+  // because we won't enter RenderLayer() if so ...
+  ImageContainerParent::SetCompositorIDForImage(
+    mImageContainerID, mOGLManager->GetCompositorID());
+  // ... but do *not* try to update the local image version.  We need
+  // to retain that information in case we fall back on GL, so that we
+  // can upload / attach buffers properly.
+
+  SharedImage* img = ImageContainerParent::GetSharedImage(mImageContainerID);
+  if (img && img->type() == SharedImage::TSurfaceDescriptor) {
+    return LayerRenderState(&img->get_SurfaceDescriptor());
+  }
+  return LayerRenderState();
+}
+
 void ShadowImageLayerOGL::UploadSharedYUVToTexture(const YUVImage& yuv)
 {
   AutoOpenSurface asurfY(OPEN_READ_ONLY, yuv.Ydata());
   AutoOpenSurface asurfU(OPEN_READ_ONLY, yuv.Udata());
   AutoOpenSurface asurfV(OPEN_READ_ONLY, yuv.Vdata());
   nsRefPtr<gfxImageSurface> surfY = asurfY.GetAsImage();
   nsRefPtr<gfxImageSurface> surfU = asurfU.GetAsImage();
   nsRefPtr<gfxImageSurface> surfV = asurfV.GetAsImage();
@@ -922,16 +944,18 @@ ShadowImageLayerOGL::RenderLayer(int aPr
       if (img && (img->type() == SharedImage::TYUVImage)) {
         UploadSharedYUVToTexture(img->get_YUVImage());
   
         mImageVersion = imgVersion;
       } else if (img && (img->type() == SharedImage::TYCbCrImage)) {
         ShmemYCbCrImage shmemImage(img->get_YCbCrImage().data(),
                                    img->get_YCbCrImage().offset());
         UploadSharedYCbCrToTexture(shmemImage, img->get_YCbCrImage().picture());
+
+        mImageVersion = imgVersion;
 #ifdef MOZ_WIDGET_GONK
       } else if (img
                  && (img->type() == SharedImage::TSurfaceDescriptor)
                  && (img->get_SurfaceDescriptor().type() == SurfaceDescriptor::TSurfaceDescriptorGralloc)) {
         const SurfaceDescriptorGralloc& desc = img->get_SurfaceDescriptor().get_SurfaceDescriptorGralloc();
         sp<GraphicBuffer> graphicBuffer = GrallocBufferActor::GetFrom(desc);
         mSize = gfxIntSize(graphicBuffer->getWidth(), graphicBuffer->getHeight());
         if (!mExternalBufferTexture.IsAllocated()) {
--- a/gfx/layers/opengl/ImageLayerOGL.h
+++ b/gfx/layers/opengl/ImageLayerOGL.h
@@ -168,16 +168,17 @@ public:
 
   virtual void Disconnect();
 
   // LayerOGL impl
   virtual void Destroy();
   virtual bool LoadAsTexture(GLuint aTextureUnit, gfxIntSize* aSize);
 
   virtual Layer* GetLayer();
+  virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
 
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
 
   virtual void CleanupResources();
 
 private:
   bool Init(const SharedImage& aFront);
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -3,16 +3,17 @@
  * 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/layers/PLayers.h"
 
 /* This must occur *after* layers/PLayers.h to avoid typedefs conflicts. */
 #include "mozilla/Util.h"
 
+#include "Composer2D.h"
 #include "LayerManagerOGL.h"
 #include "ThebesLayerOGL.h"
 #include "ContainerLayerOGL.h"
 #include "ImageLayerOGL.h"
 #include "ColorLayerOGL.h"
 #include "CanvasLayerOGL.h"
 #include "TiledThebesLayerOGL.h"
 #include "mozilla/TimeStamp.h"
@@ -578,16 +579,18 @@ LayerManagerOGL::Initialize(nsRefPtr<GLC
         Preferences::AddBoolVarCache(&sDrawFPS, "layers.acceleration.draw-fps");
         Preferences::AddBoolVarCache(&sFrameCounter, "layers.acceleration.frame-counter");
         return NS_OK;
       }
     };
     NS_DispatchToMainThread(new ReadDrawFPSPref());
   }
 
+  mComposer2D = mWidget->GetComposer2D();
+
   reporter.SetSuccessful();
   return true;
 }
 
 void
 LayerManagerOGL::SetClippingRegion(const nsIntRegion& aClippingRegion)
 {
   mClippingRegion = aClippingRegion;
@@ -666,17 +669,41 @@ LayerManagerOGL::EndTransaction(DrawTheb
     // The results of our drawing always go directly into a pixel buffer,
     // so we don't need to pass any global transform here.
     mRoot->ComputeEffectiveTransforms(gfx3DMatrix());
 
     mThebesLayerCallback = aCallback;
     mThebesLayerCallbackData = aCallbackData;
     SetCompositingDisabled(aFlags & END_NO_COMPOSITE);
 
-    Render();
+    bool needGLRender = true;
+    if (mComposer2D && mComposer2D->TryRender(mRoot, mWorldMatrix)) {
+      needGLRender = false;
+
+      if (sDrawFPS) {
+        if (!mFPS) {
+          mFPS = new FPSState();
+        }
+        double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
+        printf_stderr("HWComposer: FPS is %g\n", fps);
+      }
+
+      // This lets us reftest and screenshot content rendered by the
+      // 2d composer.
+      if (mTarget) {
+        MakeCurrent();
+        CopyToTarget(mTarget);
+        mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
+      }
+      MOZ_ASSERT(!needGLRender);
+    }
+
+    if (needGLRender) {
+      Render();
+    }
 
     mThebesLayerCallback = nullptr;
     mThebesLayerCallbackData = nullptr;
   }
 
   mTarget = NULL;
 
 #ifdef MOZ_LAYERS_HAVE_LOG
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -31,16 +31,17 @@ typedef int GLsizei;
 #include "gfxContext.h"
 #include "gfx3DMatrix.h"
 #include "nsIWidget.h"
 #include "GLContext.h"
 
 namespace mozilla {
 namespace layers {
 
+class Composer2D;
 class LayerOGL;
 class ShadowThebesLayer;
 class ShadowContainerLayer;
 class ShadowImageLayer;
 class ShadowCanvasLayer;
 class ShadowColorLayer;
 struct FPSState;
 
@@ -382,16 +383,19 @@ private:
 
   /** 
    * Context target, NULL when drawing directly to our swap chain.
    */
   nsRefPtr<gfxContext> mTarget;
 
   nsRefPtr<GLContext> mGLContext;
 
+  /** Our more efficient but less powerful alter ego, if one is available. */
+  nsRefPtr<Composer2D> mComposer2D;
+
   already_AddRefed<mozilla::gl::GLContext> CreateContext();
 
   /** Backbuffer */
   GLuint mBackBufferFBO;
   GLuint mBackBufferTexture;
   nsIntSize mBackBufferSize;
 
   /** Shader Programs */
@@ -473,16 +477,40 @@ private:
   // next forwarded transaction that re-validates their buffers.
   bool mMaybeInvalidTree;
 #endif
 
   static bool sDrawFPS;
   static bool sFrameCounter;
 };
 
+enum LayerRenderStateFlags {
+  LAYER_RENDER_STATE_Y_FLIPPED = 1 << 0,
+  LAYER_RENDER_STATE_BUFFER_ROTATION = 1 << 1
+};
+
+struct LayerRenderState {
+  LayerRenderState() : mSurface(nullptr), mFlags(0)
+  {}
+
+  LayerRenderState(SurfaceDescriptor* aSurface, uint32_t aFlags = 0)
+    : mSurface(aSurface)
+    , mFlags(aFlags)
+  {}
+
+  bool YFlipped() const
+  { return mFlags & LAYER_RENDER_STATE_Y_FLIPPED; }
+
+  bool BufferRotated() const
+  { return mFlags & LAYER_RENDER_STATE_BUFFER_ROTATION; }
+
+  SurfaceDescriptor* mSurface;
+  uint32_t mFlags;
+};
+
 /**
  * General information and tree management for OGL layers.
  */
 class LayerOGL
 {
 public:
   LayerOGL(LayerManagerOGL *aManager)
     : mOGLManager(aManager), mDestroyed(false)
@@ -496,16 +524,18 @@ public:
 
   /* Do NOT call this from the generic LayerOGL destructor.  Only from the
    * concrete class destructor
    */
   virtual void Destroy() = 0;
 
   virtual Layer* GetLayer() = 0;
 
+  virtual LayerRenderState GetRenderState() { return LayerRenderState(); }
+
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset) = 0;
 
   typedef mozilla::gl::GLContext GLContext;
 
   LayerManagerOGL* OGLManager() const { return mOGLManager; }
   GLContext *gl() const { return mOGLManager->gl(); }
   virtual void CleanupResources() = 0;
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp
+++ b/gfx/layers/opengl/ThebesLayerOGL.cpp
@@ -943,16 +943,20 @@ public:
   void Upload(gfxASurface* aUpdate, const nsIntRegion& aUpdated,
               const nsIntRect& aRect, const nsIntPoint& aRotation);
 
   already_AddRefed<TextureImage>
   Swap(TextureImage* aNewBackBuffer,
        const nsIntRect& aRect, const nsIntPoint& aRotation,
        nsIntRect* aPrevRect, nsIntPoint* aPrevRotation);
 
+  nsIntPoint Rotation() {
+    return mBufferRotation;
+  }
+
 protected:
   virtual nsIntPoint GetOriginOffset() {
     return mBufferRect.TopLeft() - mBufferRotation;
   }
 
 private:
   nsIntRect mBufferRect;
   nsIntPoint mBufferRotation;
@@ -1144,16 +1148,27 @@ ShadowThebesLayerOGL::Destroy()
 }
 
 Layer*
 ShadowThebesLayerOGL::GetLayer()
 {
   return this;
 }
 
+LayerRenderState
+ShadowThebesLayerOGL::GetRenderState()
+{
+  if (!mBuffer || mDestroyed) {
+    return LayerRenderState();
+  }
+  uint32_t flags = (mBuffer->Rotation() != nsIntPoint()) ?
+                   LAYER_RENDER_STATE_BUFFER_ROTATION : 0;
+  return LayerRenderState(&mBufferDescriptor, flags);
+}
+
 bool
 ShadowThebesLayerOGL::IsEmpty()
 {
   return !mBuffer;
 }
 
 void
 ShadowThebesLayerOGL::RenderLayer(int aPreviousFrameBuffer,
--- a/gfx/layers/opengl/ThebesLayerOGL.h
+++ b/gfx/layers/opengl/ThebesLayerOGL.h
@@ -126,16 +126,17 @@ public:
   virtual void SetValidRegion(const nsIntRegion& aRegion)
   {
     ShadowThebesLayer::SetValidRegion(aRegion);
   }
 
   // LayerOGL impl
   void Destroy();
   Layer* GetLayer();
+  virtual LayerRenderState GetRenderState() MOZ_OVERRIDE;
   virtual bool IsEmpty();
   virtual void RenderLayer(int aPreviousFrameBuffer,
                            const nsIntPoint& aOffset);
   virtual void CleanupResources();
 
 private:
   nsRefPtr<ShadowBufferOGL> mBuffer;
   SurfaceDescriptor mBufferDescriptor;
--- a/js/src/config/milestone.txt
+++ b/js/src/config/milestone.txt
@@ -5,9 +5,9 @@
 #    x.x.x.x
 #    x.x.x+
 #
 # Referenced by milestone.pl.
 # Hopefully I'll be able to automate replacement of *all*
 # hardcoded milestones in the tree from these two files.
 #--------------------------------------------------------
 
-19.0a1
+20.0a1
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -1,16 +1,16 @@
 # 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/.
 
 MOZ_APP_BASENAME=Fennec
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=19.0a1
+MOZ_APP_VERSION=20.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=1
 
--- a/mobile/xul/confvars.sh
+++ b/mobile/xul/confvars.sh
@@ -1,16 +1,16 @@
 # 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/.
 
 MOZ_APP_BASENAME=Fennec
 MOZ_APP_VENDOR=Mozilla
 
-MOZ_APP_VERSION=19.0a1
+MOZ_APP_VERSION=20.0a1
 
 MOZ_BRANDING_DIRECTORY=mobile/xul/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/xul/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 
 MOZ_SERVICES_COMMON=1
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -3661,16 +3661,19 @@ pref("layers.acceleration.force-enabled"
 
 pref("layers.acceleration.draw-fps", false);
 
 // Whether to animate simple opacity and transforms on the compositor
 pref("layers.offmainthreadcomposition.animate-opacity", false);
 pref("layers.offmainthreadcomposition.animate-transform", false);
 pref("layers.offmainthreadcomposition.log-animations", false);
 
+// Whether to (try) to use a Composer2D if available on this platform.
+pref("layers.composer2d.enabled", false);
+
 #ifdef MOZ_X11
 #ifdef MOZ_WIDGET_GTK2
 pref("gfx.xrender.enabled",true);
 #endif
 #endif
 
 #ifdef XP_WIN
 // Whether to disable the automatic detection and use of direct2d.
--- a/services/sync/Makefile.in
+++ b/services/sync/Makefile.in
@@ -5,17 +5,17 @@
 DEPTH     := @DEPTH@
 topsrcdir := @top_srcdir@
 srcdir    := @srcdir@
 VPATH     := @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 # Definitions used by constants.js.
-weave_version := 1.21.0
+weave_version := 1.22.0
 weave_channel := rel
 weave_id      := {340c2bbc-ce74-4362-90b5-7c26312808ef}
 
 # Preprocess files.
 SYNC_PP := modules/constants.js
 SYNC_PP_FLAGS := \
  -Dweave_version=$(weave_version) \
  -Dweave_channel=$(weave_channel) \
--- a/widget/gonk/HWComposer.h
+++ b/widget/gonk/HWComposer.h
@@ -12,19 +12,20 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #ifndef ANDROID_SF_HWCOMPOSER_H
 #define ANDROID_SF_HWCOMPOSER_H
 
-#include <hardware/hwcomposer.h>
 #include <utils/Vector.h>
 
+#include "hardware/hwcomposer.h"
+
 namespace android {
 // ---------------------------------------------------------------------------
 
 class String8;
 
 class HWComposer
 {
 public:
@@ -32,17 +33,17 @@ public:
     HWComposer();
     ~HWComposer();
 
     int init();
 
     // swap buffers using vendor specific implementation
     status_t swapBuffers(hwc_display_t dpy, hwc_surface_t surf) const;
 
-private:
+protected:
     struct cb_context {
         hwc_procs_t procs;
         HWComposer* hwc;
     };
     void invalidate();
 
     hw_module_t const*      mModule;
     hwc_composer_device_t*  mHwc;
new file mode 100644
--- /dev/null
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/log.h>
+#include <EGL/egl.h>
+#include <hardware/hardware.h>
+
+#include "Framebuffer.h"
+#include "HwcComposer2D.h"
+#include "LayerManagerOGL.h"
+#include "mozilla/layers/PLayers.h"
+#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIScreenManager.h"
+#include "nsMathUtils.h"
+#include "nsServiceManagerUtils.h"
+
+#define LOG_TAG "HWComposer"
+
+#if (LOG_NDEBUG == 0)
+#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args)
+#else
+#define LOGD(args...) ((void)0)
+#endif
+
+#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args)
+
+#define LAYER_COUNT_INCREMENTS 5
+
+using namespace android;
+using namespace mozilla::layers;
+
+enum {
+    HWC_USE_GPU = HWC_FRAMEBUFFER,
+    HWC_USE_OVERLAY = HWC_OVERLAY,
+    HWC_USE_COPYBIT
+};
+
+namespace mozilla {
+
+static StaticRefPtr<HwcComposer2D> sInstance;
+
+HwcComposer2D::HwcComposer2D()
+    : mMaxLayerCount(0)
+    , mList(nullptr)
+{
+}
+
+HwcComposer2D::~HwcComposer2D() {
+    free(mList);
+}
+
+int
+HwcComposer2D::Init(hwc_display_t dpy, hwc_surface_t sur)
+{
+    MOZ_ASSERT(!Initialized());
+
+    if (int err = init()) {
+        LOGE("Failed to initialize hwc");
+        return err;
+    }
+
+    nsIntSize screenSize;
+
+    mozilla::Framebuffer::GetSize(&screenSize);
+    mScreenWidth  = screenSize.width;
+    mScreenHeight = screenSize.height;
+
+    mDpy = dpy;
+    mSur = sur;
+
+    return 0;
+}
+
+HwcComposer2D*
+HwcComposer2D::GetInstance()
+{
+    if (!sInstance) {
+        LOGD("Creating new instance");
+        sInstance = new HwcComposer2D();
+    }
+    return sInstance;
+}
+
+bool
+HwcComposer2D::ReallocLayerList()
+{
+    int size = sizeof(hwc_layer_list_t) +
+        ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(hwc_layer_t));
+
+    hwc_layer_list_t* listrealloc = (hwc_layer_list_t*)realloc(mList, size);
+
+    if (!listrealloc) {
+        return false;
+    }
+
+    if (!mList) {
+        //first alloc, initialize
+        listrealloc->numHwLayers = 0;
+        listrealloc->flags = 0;
+    }
+
+    mList = listrealloc;
+    mMaxLayerCount += LAYER_COUNT_INCREMENTS;
+    return true;
+}
+
+int
+HwcComposer2D::GetRotation()
+{
+    int halrotation = 0;
+    uint32_t screenrotation;
+
+    if (!mScreen) {
+        nsCOMPtr<nsIScreenManager> screenMgr =
+            do_GetService("@mozilla.org/gfx/screenmanager;1");
+        if (screenMgr) {
+            screenMgr->GetPrimaryScreen(getter_AddRefs(mScreen));
+        }
+    }
+
+    if (mScreen) {
+        if (NS_SUCCEEDED(mScreen->GetRotation(&screenrotation))) {
+            switch (screenrotation) {
+            case nsIScreen::ROTATION_0_DEG:
+                 halrotation = 0;
+                 break;
+
+            case nsIScreen::ROTATION_90_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_90;
+                 break;
+
+            case nsIScreen::ROTATION_180_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_180;
+                 break;
+
+            case nsIScreen::ROTATION_270_DEG:
+                 halrotation = HWC_TRANSFORM_ROT_270;
+                 break;
+            }
+        }
+    }
+
+    return halrotation;
+}
+
+/**
+ * Sets hwc layer rectangles required for hwc composition
+ *
+ * @param aVisible Input. Layer's unclipped visible rectangle
+ *        The origin is the layer's buffer
+ * @param aTransform Input. Layer's transformation matrix
+ *        It transforms from layer space to screen space
+ * @param aClip Input. A clipping rectangle.
+ *        The origin is the top-left corner of the screen
+ * @param aBufferRect Input. The layer's buffer bounds
+ *        The origin is the buffer itself and hence always (0,0)
+ * @param aSurceCrop Output. Area of the source to consider,
+ *        the origin is the top-left corner of the buffer
+ * @param aVisibleRegionScreen Output. Visible region in screen space.
+ *        The origin is the top-left corner of the screen
+ * @return true if the layer should be rendered.
+ *         false if the layer can be skipped
+ */
+static bool
+PrepareLayerRects(nsIntRect aVisible, const gfxMatrix& aTransform,
+                  nsIntRect aClip, nsIntRect aBufferRect,
+                  hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) {
+
+    gfxRect visibleRect(aVisible);
+    gfxRect clip(aClip);
+    gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect);
+    // |clip| is guaranteed to be integer
+    visibleRectScreen.IntersectRect(visibleRectScreen, clip);
+
+    if (visibleRectScreen.IsEmpty()) {
+        LOGD("Skip layer");
+        return false;
+    }
+
+    gfxMatrix inverse(aTransform);
+    inverse.Invert();
+    gfxRect crop = inverse.TransformBounds(visibleRectScreen);
+    // Map to buffer space
+    crop -= visibleRect.TopLeft();
+    gfxRect bufferRect(aBufferRect);
+    //clip to buffer size
+    crop.IntersectRect(crop, aBufferRect);
+    crop.RoundOut();
+
+    if (crop.IsEmpty()) {
+        LOGD("Skip layer");
+        return false;
+    }
+
+
+    //propagate buffer clipping back to visible rect
+    visibleRectScreen = aTransform.TransformBounds(crop + visibleRect.TopLeft());
+    visibleRectScreen.RoundOut();
+
+    aSourceCrop->left = crop.x;
+    aSourceCrop->top  = crop.y;
+    aSourceCrop->right  = crop.x + crop.width;
+    aSourceCrop->bottom = crop.y + crop.height;
+
+    aVisibleRegionScreen->left = visibleRectScreen.x;
+    aVisibleRegionScreen->top  = visibleRectScreen.y;
+    aVisibleRegionScreen->right  = visibleRectScreen.x + visibleRectScreen.width;
+    aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height;
+
+    return true;
+}
+
+bool
+HwcComposer2D::PrepareLayerList(Layer* aLayer,
+                                const nsIntRect& aClip)
+{
+    // NB: we fall off this path whenever there are container layers
+    // that require intermediate surfaces.  That means all the
+    // GetEffective*() coordinates are relative to the framebuffer.
+
+    const bool TESTING = true;
+
+    const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
+    if (visibleRegion.IsEmpty()) {
+        return true;
+    }
+
+    float opacity = aLayer->GetEffectiveOpacity();
+    if (opacity <= 0) {
+        LOGD("Layer is fully transparent so skip rendering");
+        return true;
+    }
+    else if (opacity < 1) {
+        LOGD("Layer has planar semitransparency which is unsupported");
+        return false;
+    }
+
+    if (!TESTING &&
+        visibleRegion.GetNumRects() > 1) {
+        // FIXME/bug 808339
+        LOGD("Layer has nontrivial visible region");
+        return false;
+    }
+
+
+    if (ContainerLayer* container = aLayer->AsContainerLayer()) {
+        if (container->UseIntermediateSurface()) {
+            LOGD("Container layer needs intermediate surface");
+            return false;
+        }
+        nsAutoTArray<Layer*, 12> children;
+        container->SortChildrenBy3DZOrder(children);
+
+        //FIXME/bug 810334
+        for (PRUint32 i = 0; i < children.Length(); i++) {
+            if (!PrepareLayerList(children[i], aClip)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    LayerOGL* layerGL = static_cast<LayerOGL*>(aLayer->ImplData());
+    LayerRenderState state = layerGL->GetRenderState();
+
+    if (!state.mSurface ||
+        state.mSurface->type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
+        LOGD("Layer doesn't have a gralloc buffer");
+        return false;
+    }
+    if (state.BufferRotated()) {
+        LOGD("Layer has a rotated buffer");
+        return false;
+    }
+
+    gfxMatrix transform;
+    const gfx3DMatrix& transform3D = aLayer->GetEffectiveTransform();
+    if (!transform3D.Is2D(&transform) || !transform.PreservesAxisAlignedRectangles()) {
+        LOGD("Layer has a 3D transform or a non-square angle rotation");
+        return false;
+    }
+
+    // OK!  We can compose this layer with hwc.
+
+    int current = mList ? mList->numHwLayers : 0;
+    if (!mList || current >= mMaxLayerCount) {
+        if (!ReallocLayerList() || current >= mMaxLayerCount) {
+            LOGE("PrepareLayerList failed! Could not increase the maximum layer count");
+            return false;
+        }
+    }
+
+    sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(*state.mSurface);
+
+    nsIntRect visibleRect = visibleRegion.GetBounds();
+
+    nsIntRect bufferRect = nsIntRect(0, 0, int(buffer->getWidth()),
+        int(buffer->getHeight()));
+
+    hwc_layer_t& hwcLayer = mList->hwLayers[current];
+
+    //FIXME/bug 810334
+    if(!PrepareLayerRects(visibleRect, transform, aClip, bufferRect,
+                          &(hwcLayer.sourceCrop), &(hwcLayer.displayFrame))) {
+        return true;
+    }
+
+    buffer_handle_t handle = buffer->getNativeBuffer()->handle;
+    hwcLayer.handle = handle;
+
+    hwcLayer.blending = HWC_BLENDING_NONE;
+    hwcLayer.flags = 0;
+    hwcLayer.hints = 0;
+
+
+    hwcLayer.compositionType = HWC_USE_COPYBIT;
+
+    if (transform.xx == 0) {
+        if (transform.xy < 0) {
+            hwcLayer.transform = HWC_TRANSFORM_ROT_90;
+            LOGD("Layer buffer rotated 90 degrees");
+        }
+        else {
+            hwcLayer.transform = HWC_TRANSFORM_ROT_270;
+            LOGD("Layer buffer rotated 270 degrees");
+        }
+    }
+    else if (transform.xx < 0) {
+        hwcLayer.transform = HWC_TRANSFORM_ROT_180;
+        LOGD("Layer buffer rotated 180 degrees");
+    }
+    else {
+        hwcLayer.transform = 0;
+    }
+
+    hwcLayer.transform |= state.YFlipped() ? HWC_TRANSFORM_FLIP_V : 0;
+
+    hwc_region_t region;
+    region.numRects = 1;
+    region.rects = &(hwcLayer.displayFrame);
+    hwcLayer.visibleRegionScreen = region;
+
+    mList->numHwLayers++;
+
+    return true;
+}
+
+bool
+HwcComposer2D::TryRender(Layer* aRoot,
+                         const gfxMatrix& aGLWorldTransform)
+{
+    MOZ_ASSERT(Initialized());
+    if (mList) {
+        mList->numHwLayers = 0;
+    }
+    // XXX use GL world transform instead of GetRotation()
+    int rotation = GetRotation();
+
+    int fbHeight, fbWidth;
+
+    if (rotation == 0 || rotation == HWC_TRANSFORM_ROT_180) {
+        fbWidth = mScreenWidth;
+        fbHeight = mScreenHeight;
+    } else {
+        fbWidth = mScreenHeight;
+        fbHeight = mScreenWidth;
+    }
+
+    if (!PrepareLayerList(aRoot, nsIntRect(0, 0, fbWidth, fbHeight))) {
+        LOGD("Render aborted. Nothing was drawn to the screen");
+        return false;
+    }
+
+    if (mHwc->set(mHwc, mDpy, mSur, mList)) {
+        LOGE("Hardware device failed to render");
+        return false;
+    }
+
+    LOGD("Frame rendered");
+    return true;
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gonk/HwcComposer2D.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_HwcComposer2D
+#define mozilla_HwcComposer2D
+
+#include "Composer2D.h"
+#include "HWComposer.h"
+#include "Layers.h"
+#include "nsIScreen.h"
+
+namespace mozilla {
+
+namespace layers {
+class ContainerLayer;
+class Layer;
+}
+
+class HwcComposer2D : public android::HWComposer,
+                      public mozilla::layers::Composer2D {
+public:
+    HwcComposer2D();
+    virtual ~HwcComposer2D();
+
+    int Init(hwc_display_t aDisplay, hwc_surface_t aSurface);
+
+    bool Initialized() const { return mHwc; }
+
+    static HwcComposer2D* GetInstance();
+
+    // Returns TRUE if the container has been succesfully rendered
+    // Returns FALSE if the container cannot be fully rendered
+    // by this composer so nothing was rendered at all
+    bool TryRender(layers::Layer* aRoot, const gfxMatrix& aGLWorldTransform) MOZ_OVERRIDE;
+
+private:
+    bool ReallocLayerList();
+    bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip);
+    int GetRotation();
+
+    hwc_layer_list_t*       mList;
+    nsCOMPtr<nsIScreen>     mScreen;
+    int                     mScreenWidth, mScreenHeight;
+    int                     mMaxLayerCount;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_HwcComposer2D
--- a/widget/gonk/Makefile.in
+++ b/widget/gonk/Makefile.in
@@ -30,16 +30,17 @@ IS_COMPONENT    = 1
 MODULE_NAME     = nsWidgetGonkModule
 GRE_MODULE      = 1
 LIBXUL_LIBRARY  = 1
 
 
 CPPSRCS	= \
 	Framebuffer.cpp \
 	HWComposer.cpp \
+	HwcComposer2D.cpp \
 	nsAppShell.cpp \
 	nsWidgetFactory.cpp \
 	nsWindow.cpp \
 	nsLookAndFeel.cpp \
 	nsIdleServiceGonk.cpp \
 	OrientationObserver.cpp \
 	EventHub.cpp \
 	GonkMemoryPressureMonitoring.cpp \
new file mode 100644
--- /dev/null
+++ b/widget/gonk/hardware/hwcomposer.h
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H
+#define ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <cutils/native_handle.h>
+
+__BEGIN_DECLS
+
+/*****************************************************************************/
+
+#define HWC_API_VERSION 1
+
+/**
+ * The id of this module
+ */
+#define HWC_HARDWARE_MODULE_ID "hwcomposer"
+
+/**
+ * Name of the sensors device to open
+ */
+#define HWC_HARDWARE_COMPOSER   "composer"
+
+
+enum {
+    /* hwc_composer_device_t::set failed in EGL */
+    HWC_EGL_ERROR = -1
+};
+
+/*
+ * hwc_layer_t::hints values
+ * Hints are set by the HAL and read by SurfaceFlinger
+ */
+enum {
+    /*
+     * HWC can set the HWC_HINT_TRIPLE_BUFFER hint to indicate to SurfaceFlinger
+     * that it should triple buffer this layer. Typically HWC does this when
+     * the layer will be unavailable for use for an extended period of time,
+     * e.g. if the display will be fetching data directly from the layer and
+     * the layer can not be modified until after the next set().
+     */
+    HWC_HINT_TRIPLE_BUFFER  = 0x00000001,
+
+    /*
+     * HWC sets HWC_HINT_CLEAR_FB to tell SurfaceFlinger that it should clear the
+     * framebuffer with transparent pixels where this layer would be.
+     * SurfaceFlinger will only honor this flag when the layer has no blending
+     *
+     */
+    HWC_HINT_CLEAR_FB       = 0x00000002
+};
+
+/*
+ * hwc_layer_t::flags values
+ * Flags are set by SurfaceFlinger and read by the HAL
+ */
+enum {
+    /*
+     * HWC_SKIP_LAYER is set by SurfaceFlnger to indicate that the HAL
+     * shall not consider this layer for composition as it will be handled
+     * by SurfaceFlinger (just as if compositionType was set to HWC_OVERLAY).
+     */
+    HWC_SKIP_LAYER = 0x00000001,
+};
+
+/*
+ * hwc_layer_t::compositionType values
+ */
+enum {
+    /* this layer is to be drawn into the framebuffer by SurfaceFlinger */
+    HWC_FRAMEBUFFER = 0,
+
+    /* this layer will be handled in the HWC */
+    HWC_OVERLAY = 1,
+};
+
+/*
+ * hwc_layer_t::blending values
+ */
+enum {
+    /* no blending */
+    HWC_BLENDING_NONE     = 0x0100,
+
+    /* ONE / ONE_MINUS_SRC_ALPHA */
+    HWC_BLENDING_PREMULT  = 0x0105,
+
+    /* SRC_ALPHA / ONE_MINUS_SRC_ALPHA */
+    HWC_BLENDING_COVERAGE = 0x0405
+};
+
+/*
+ * hwc_layer_t::transform values
+ */
+enum {
+    /* flip source image horizontally */
+    HWC_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H,
+    /* flip source image vertically */
+    HWC_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V,
+    /* rotate source image 90 degrees clock-wise */
+    HWC_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,
+    /* rotate source image 180 degrees */
+    HWC_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,
+    /* rotate source image 270 degrees clock-wise */
+    HWC_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,
+};
+
+typedef struct hwc_rect {
+    int left;
+    int top;
+    int right;
+    int bottom;
+} hwc_rect_t;
+
+typedef struct hwc_region {
+    size_t numRects;
+    hwc_rect_t const* rects;
+} hwc_region_t;
+
+typedef struct hwc_layer {
+    /*
+     * initially set to HWC_FRAMEBUFFER, indicates the layer will
+     * be drawn into the framebuffer using OpenGL ES.
+     * The HWC can toggle this value to HWC_OVERLAY, to indicate
+     * it will handle the layer.
+     */
+    int32_t compositionType;
+
+    /* see hwc_layer_t::hints above */
+    uint32_t hints;
+
+    /* see hwc_layer_t::flags above */
+    uint32_t flags;
+
+    /* handle of buffer to compose. this handle is guaranteed to have been
+     * allocated with gralloc */
+    buffer_handle_t handle;
+
+    /* transformation to apply to the buffer during composition */
+    uint32_t transform;
+
+    /* blending to apply during composition */
+    int32_t blending;
+
+    /* area of the source to consider, the origin is the top-left corner of
+     * the buffer */
+    hwc_rect_t sourceCrop;
+
+    /* where to composite the sourceCrop onto the display. The sourceCrop
+     * is scaled using linear filtering to the displayFrame. The origin is the
+     * top-left corner of the screen.
+     */
+    hwc_rect_t displayFrame;
+
+    /* visible region in screen space. The origin is the
+     * top-left corner of the screen.
+     * The visible region INCLUDES areas overlapped by a translucent layer.
+     */
+    hwc_region_t visibleRegionScreen;
+} hwc_layer_t;
+
+
+/*
+ * hwc_layer_list_t::flags values
+ */
+enum {
+    /*
+     * HWC_GEOMETRY_CHANGED is set by SurfaceFlinger to indicate that the list
+     * passed to (*prepare)() has changed by more than just the buffer handles.
+     */
+    HWC_GEOMETRY_CHANGED = 0x00000001,
+};
+
+/*
+ * List of layers.
+ * The handle members of hwLayers elements must be unique.
+ */
+typedef struct hwc_layer_list {
+    uint32_t flags;
+    size_t numHwLayers;
+    hwc_layer_t hwLayers[0];
+} hwc_layer_list_t;
+
+/* This represents a display, typically an EGLDisplay object */
+typedef void* hwc_display_t;
+
+/* This represents a surface, typically an EGLSurface object  */
+typedef void* hwc_surface_t;
+
+
+/* see hwc_composer_device::registerProcs()
+ * Any of the callbacks can be NULL, in which case the corresponding
+ * functionality is not supported.
+ */
+typedef struct hwc_procs {
+    /*
+     * (*invalidate)() triggers a screen refresh, in particular prepare and set
+     * will be called shortly after this call is made. Note that there is
+     * NO GUARANTEE that the screen refresh will happen after invalidate()
+     * returns (in particular, it could happen before).
+     * invalidate() is GUARANTEED TO NOT CALL BACK into the h/w composer HAL and
+     * it is safe to call invalidate() from any of hwc_composer_device
+     * hooks, unless noted otherwise.
+     */
+    void (*invalidate)(struct hwc_procs* procs);
+} hwc_procs_t;
+
+
+/*****************************************************************************/
+
+typedef struct hwc_module {
+    struct hw_module_t common;
+} hwc_module_t;
+
+
+typedef struct hwc_composer_device {
+    struct hw_device_t common;
+
+    /*
+     * (*prepare)() is called for each frame before composition and is used by
+     * SurfaceFlinger to determine what composition steps the HWC can handle.
+     *
+     * (*prepare)() can be called more than once, the last call prevails.
+     *
+     * The HWC responds by setting the compositionType field to either
+     * HWC_FRAMEBUFFER or HWC_OVERLAY. In the former case, the composition for
+     * this layer is handled by SurfaceFlinger with OpenGL ES, in the later
+     * case, the HWC will have to handle this layer's composition.
+     *
+     * (*prepare)() is called with HWC_GEOMETRY_CHANGED to indicate that the
+     * list's geometry has changed, that is, when more than just the buffer's
+     * handles have been updated. Typically this happens (but is not limited to)
+     * when a window is added, removed, resized or moved.
+     *
+     * a NULL list parameter or a numHwLayers of zero indicates that the
+     * entire composition will be handled by SurfaceFlinger with OpenGL ES.
+     *
+     * returns: 0 on success. An negative error code on error. If an error is
+     * returned, SurfaceFlinger will assume that none of the layer will be
+     * handled by the HWC.
+     */
+    int (*prepare)(struct hwc_composer_device *dev, hwc_layer_list_t* list);
+
+
+    /*
+     * (*set)() is used in place of eglSwapBuffers(), and assumes the same
+     * functionality, except it also commits the work list atomically with
+     * the actual eglSwapBuffers().
+     *
+     * The list parameter is guaranteed to be the same as the one returned
+     * from the last call to (*prepare)().
+     *
+     * When this call returns the caller assumes that:
+     *
+     * - the display will be updated in the near future with the content
+     *   of the work list, without artifacts during the transition from the
+     *   previous frame.
+     *
+     * - all objects are available for immediate access or destruction, in
+     *   particular, hwc_region_t::rects data and hwc_layer_t::layer's buffer.
+     *   Note that this means that immediately accessing (potentially from a
+     *   different process) a buffer used in this call will not result in
+     *   screen corruption, the driver must apply proper synchronization or
+     *   scheduling (eg: block the caller, such as gralloc_module_t::lock(),
+     *   OpenGL ES, Camera, Codecs, etc..., or schedule the caller's work
+     *   after the buffer is freed from the actual composition).
+     *
+     * a NULL list parameter or a numHwLayers of zero indicates that the
+     * entire composition has been handled by SurfaceFlinger with OpenGL ES.
+     * In this case, (*set)() behaves just like eglSwapBuffers().
+     *
+     * dpy, sur, and list are set to NULL to indicate that the screen is
+     * turning off. This happens WITHOUT prepare() being called first.
+     * This is a good time to free h/w resources and/or power
+     * the relevant h/w blocks down.
+     *
+     * IMPORTANT NOTE: there is an implicit layer containing opaque black
+     * pixels behind all the layers in the list.
+     * It is the responsibility of the hwcomposer module to make
+     * sure black pixels are output (or blended from).
+     *
+     * returns: 0 on success. An negative error code on error:
+     *    HWC_EGL_ERROR: eglGetError() will provide the proper error code
+     *    Another code for non EGL errors.
+     *
+     */
+    int (*set)(struct hwc_composer_device *dev,
+                hwc_display_t dpy,
+                hwc_surface_t sur,
+                hwc_layer_list_t* list);
+    /*
+     * This hook is OPTIONAL.
+     *
+     * If non NULL it will be called by SurfaceFlinger on dumpsys
+     */
+    void (*dump)(struct hwc_composer_device* dev, char *buff, int buff_len);
+
+    /*
+     * This hook is OPTIONAL.
+     *
+     * (*registerProcs)() registers a set of callbacks the h/w composer HAL
+     * can later use. It is FORBIDDEN to call any of the callbacks from
+     * within registerProcs(). registerProcs() must save the hwc_procs_t pointer
+     * which is needed when calling a registered callback.
+     * Each call to registerProcs replaces the previous set of callbacks.
+     * registerProcs is called with NULL to unregister all callbacks.
+     *
+     * Any of the callbacks can be NULL, in which case the corresponding
+     * functionality is not supported.
+     */
+    void (*registerProcs)(struct hwc_composer_device* dev,
+            hwc_procs_t const* procs);
+
+    void* reserved_proc[6];
+
+} hwc_composer_device_t;
+
+
+/** convenience API for opening and closing a device */
+
+static inline int hwc_open(const struct hw_module_t* module,
+        hwc_composer_device_t** device) {
+    return module->methods->open(module,
+            HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device);
+}
+
+static inline int hwc_close(hwc_composer_device_t* device) {
+    return device->common.close(&device->common);
+}
+
+
+/*****************************************************************************/
+
+__END_DECLS
+
+#endif /* ANDROID_INCLUDE_HARDWARE_HWCOMPOSER_H */
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -24,16 +24,17 @@
 #include "mozilla/Hal.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/FileUtils.h"
 #include "Framebuffer.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "GLContextProvider.h"
+#include "HwcComposer2D.h"
 #include "LayerManagerOGL.h"
 #include "nsAutoPtr.h"
 #include "nsAppShell.h"
 #include "nsIdleService.h"
 #include "nsScreenManagerGonk.h"
 #include "nsTArray.h"
 #include "nsWindow.h"
 #include "nsIWidgetListener.h"
@@ -61,16 +62,17 @@ static gfxMatrix sRotationMatrix;
 
 static nsRefPtr<GLContext> sGLContext;
 static nsTArray<nsWindow *> sTopWindows;
 static nsWindow *gWindowToRedraw = nullptr;
 static nsWindow *gFocusedWindow = nullptr;
 static android::FramebufferNativeWindow *gNativeWindow = nullptr;
 static bool sFramebufferOpen;
 static bool sUsingOMTC;
+static bool sUsingHwc;
 static bool sScreenInitialized;
 static nsRefPtr<gfxASurface> sOMTCSurface;
 static pthread_t sFramebufferWatchThread;
 
 namespace {
 
 static int
 CancelBufferNoop(ANativeWindow* aWindow, android_native_buffer_t* aBuffer)
@@ -210,16 +212,17 @@ nsWindow::nsWindow()
         // This is a hack to force initialization of the compositor
         // resources, if we're going to use omtc.
         //
         // NB: GetPlatform() will create the gfxPlatform, which wants
         // to know the color depth, which asks our native window.
         // This has to happen after other init has finished.
         gfxPlatform::GetPlatform();
         sUsingOMTC = UseOffMainThreadCompositing();
+        sUsingHwc = Preferences::GetBool("layers.composer2d.enabled", false);
 
         if (sUsingOMTC) {
           sOMTCSurface = new gfxImageSurface(gfxIntSize(1, 1),
                                              gfxASurface::ImageFormatRGB24);
         }
     }
 }
 
@@ -690,16 +693,28 @@ bool
 nsWindow::NeedsPaint()
 {
   if (!mLayerManager) {
     return false;
   }
   return nsIWidget::NeedsPaint();
 }
 
+Composer2D*
+nsWindow::GetComposer2D()
+{
+    if (!sUsingHwc) {
+        return nullptr;
+    }
+    if (HwcComposer2D* hwc = HwcComposer2D::GetInstance()) {
+        return hwc->Initialized() ? hwc : nullptr;
+    }
+    return nullptr;
+}
+
 // nsScreenGonk.cpp
 
 nsScreenGonk::nsScreenGonk(void *nativeScreen)
 {
 }
 
 nsScreenGonk::~nsScreenGonk()
 {
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -104,16 +104,18 @@ public:
                                       const InputContextAction& aAction);
     NS_IMETHOD_(InputContext) GetInputContext();
 
     virtual uint32_t GetGLFrameBufferFormat() MOZ_OVERRIDE;
 
     virtual nsIntRect GetNaturalBounds() MOZ_OVERRIDE;
     virtual bool NeedsPaint();
 
+    virtual Composer2D* GetComposer2D() MOZ_OVERRIDE;
+
 protected:
     nsWindow* mParent;
     bool mVisible;
     nsIntRegion mDirtyRegion;
     InputContext mInputContext;
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
 
     void BringToTop();
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -37,16 +37,17 @@ class   ViewWrapper;
 class   nsIWidgetListener;
 class   nsIntRegion;
 
 namespace mozilla {
 namespace dom {
 class TabChild;
 }
 namespace layers {
+class Composer2D;
 class CompositorChild;
 class LayerManager;
 class PLayersChild;
 }
 }
 
 /**
  * Callback function that processes events.
@@ -86,18 +87,18 @@ typedef nsEventStatus (* EVENT_CALLBACK)
 #ifdef XP_WIN
 #define NS_NATIVE_TSF_THREAD_MGR       100
 #define NS_NATIVE_TSF_CATEGORY_MGR     101
 #define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
 #define NS_NATIVE_ICOREWINDOW          103 // winrt specific
 #endif
 
 #define NS_IWIDGET_IID \
-  { 0xb7c60bda, 0xe16c, 0x4e89, \
-    { 0x86, 0x8c, 0xc3, 0x2e, 0x62, 0x40, 0x05, 0xb2 } }
+  { 0xdb9b0931, 0xebf9, 0x4e0d, \
+    { 0xb2, 0x0a, 0xf7, 0x5f, 0xcb, 0x17, 0xe6, 0xe1 } }
 
 /*
  * Window shadow styles
  * Also used for the -moz-window-shadow CSS property
  */
 
 #define NS_STYLE_WINDOW_SHADOW_NONE             0
 #define NS_STYLE_WINDOW_SHADOW_DEFAULT          1
@@ -408,16 +409,17 @@ struct SizeConstraints {
  * The base class for all the widgets. It provides the interface for
  * all basic and necessary functionality.
  */
 class nsIWidget : public nsISupports {
   protected:
     typedef mozilla::dom::TabChild TabChild;
 
   public:
+    typedef mozilla::layers::Composer2D Composer2D;
     typedef mozilla::layers::CompositorChild CompositorChild;
     typedef mozilla::layers::LayerManager LayerManager;
     typedef mozilla::layers::LayersBackend LayersBackend;
     typedef mozilla::layers::PLayersChild PLayersChild;
     typedef mozilla::widget::IMEState IMEState;
     typedef mozilla::widget::InputContext InputContext;
     typedef mozilla::widget::InputContextAction InputContextAction;
     typedef mozilla::widget::SizeConstraints SizeConstraints;
@@ -1668,16 +1670,26 @@ class nsIWidget : public nsISupports {
 
     /**
      * If this isn't directly compositing to its window surface,
      * return the compositor which is doing that on our behalf.
      */
     virtual CompositorChild* GetRemoteRenderer()
     { return nullptr; }
 
+    /**
+     * If this widget has a more efficient composer available for its
+     * native framebuffer, return it.
+     *
+     * This can be called from a non-main thread, but that thread must
+     * hold a strong reference to this.
+     */
+    virtual Composer2D* GetComposer2D()
+    { return nullptr; }
+
 protected:
     /**
      * Like GetDefaultScale, but taking into account only the system settings
      * and ignoring Gecko preferences.
      */
     virtual double GetDefaultScaleInternal() { return 1.0; }
 
     // keep the list of children.  We also keep track of our siblings.
--- a/xpcom/components/Module.h
+++ b/xpcom/components/Module.h
@@ -16,17 +16,17 @@ namespace mozilla {
 /**
  * A module implements one or more XPCOM components. This structure is used
  * for both binary and script modules, but the registration members
  * (cids/contractids/categoryentries) are unused for modules which are loaded
  * via a module loader.
  */
 struct Module
 {
-  static const unsigned int kVersion = 19;
+  static const unsigned int kVersion = 20;
 
   struct CIDEntry;
 
   typedef already_AddRefed<nsIFactory> (*GetFactoryProcPtr)
     (const Module& module, const CIDEntry& entry);
 
   typedef nsresult (*ConstructorProcPtr)(nsISupports* aOuter,
                                          const nsIID& aIID,