Bug 915729 - Add mixed HWC and GPU Composition. r=ncameron, r=dwilson
authorSushil Chauhan <sushilchauhan@codeaurora.org>
Tue, 15 Oct 2013 14:01:42 -0700
changeset 165774 bdce774ee8866c42cf6d257668de772cb065df3a
parent 165773 27a8b93a8285a1f9c70da3f7a7c8a8b089b46247
child 165775 c92ba82eb05488e212b9fdc1da75d1a990315c29
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersncameron, dwilson
bugs915729
milestone27.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 915729 - Add mixed HWC and GPU Composition. r=ncameron, r=dwilson
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/composite/LayerManagerComposite.h
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -193,17 +193,23 @@ ContainerRender(ContainerT* aContainer,
     }
 
     nsIntRect clipRect = layerToRender->GetLayer()->
         CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
     if (clipRect.IsEmpty()) {
       continue;
     }
 
-    layerToRender->RenderLayer(childOffset, clipRect);
+    if (layerToRender->HasLayerBeenComposited()) {
+      // Composer2D will compose this layer so skip GPU composition
+      // this time & reset composition flag for next composition phase
+      layerToRender->SetLayerComposited(false);
+    } else {
+      layerToRender->RenderLayer(childOffset, clipRect);
+    }
     // invariant: our GL context should be current here, I don't think we can
     // assert it though
   }
 
   if (needsSurface) {
     // Unbind the current surface and rebind the previous one.
 #ifdef MOZ_DUMP_PAINTING
     if (gfxUtils::sDumpPainting) {
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -721,16 +721,17 @@ LayerManagerComposite::CreateDrawTarget(
 
 LayerComposite::LayerComposite(LayerManagerComposite *aManager)
   : mCompositeManager(aManager)
   , mCompositor(aManager->GetCompositor())
   , mShadowOpacity(1.0)
   , mUseShadowClipRect(false)
   , mShadowTransformSetByAnimation(false)
   , mDestroyed(false)
+  , mLayerComposited(false)
 { }
 
 LayerComposite::~LayerComposite()
 {
 }
 
 void
 LayerComposite::Destroy()
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -376,32 +376,39 @@ public:
   {
     mShadowTransform = aMatrix;
   }
   void SetShadowTransformSetByAnimation(bool aSetByAnimation)
   {
     mShadowTransformSetByAnimation = aSetByAnimation;
   }
 
+  void SetLayerComposited(bool value)
+  {
+    mLayerComposited = value;
+  }
+
   // These getters can be used anytime.
   float GetShadowOpacity() { return mShadowOpacity; }
   const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
   const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
   const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
   bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
+  bool HasLayerBeenComposited() { return mLayerComposited; }
 
 protected:
   gfx3DMatrix mShadowTransform;
   nsIntRegion mShadowVisibleRegion;
   nsIntRect mShadowClipRect;
   LayerManagerComposite* mCompositeManager;
   RefPtr<Compositor> mCompositor;
   float mShadowOpacity;
   bool mUseShadowClipRect;
   bool mShadowTransformSetByAnimation;
   bool mDestroyed;
+  bool mLayerComposited;
 };
 
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LayerManagerComposite_H */
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -429,16 +429,17 @@ HwcComposer2D::PrepareLayerList(Layer* a
         ColorLayer* colorLayer = aLayer->AsColorLayer();
         if (colorLayer->GetColor().a < 1.0) {
             LOGD("Color layer has semitransparency which is unsupported");
             return false;
         }
         hwcLayer.transform = colorLayer->GetColor().Packed();
     }
 
+    mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
     mList->numHwLayers++;
     return true;
 }
 
 
 #if ANDROID_VERSION >= 18
 bool
 HwcComposer2D::TryHwComposition()
@@ -456,23 +457,39 @@ HwcComposer2D::TryHwComposition()
         if (!ReallocLayerList() || idx >= mMaxLayerCount) {
             LOGE("TryHwComposition failed! Could not add FB layer");
             return false;
         }
     }
 
     Prepare(fbsurface->lastHandle, -1);
 
+    bool fullHwcComposite = true;
     for (int j = 0; j < idx; j++) {
         if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
+            // After prepare, if there is an HWC_FRAMEBUFFER layer,
+            // it means full HWC Composition is not possible this time
             LOGD("GPU or Partial HWC Composition");
-            return false;
+            fullHwcComposite = false;
+            break;
         }
     }
 
+    if (!fullHwcComposite) {
+        for (int k=0; k < idx; k++) {
+            if (mList->hwLayers[k].compositionType == HWC_OVERLAY) {
+                // HWC will compose HWC_OVERLAY layers in partial
+                // HWC Composition, so set layer composition flag
+                // on mapped LayerComposite to skip GPU composition
+                mHwcLayerMap[k]->SetLayerComposited(true);
+            }
+        }
+        return false;
+    }
+
     // Full HWC Composition
     Commit();
 
     // No composition on FB layer, so closing releaseFenceFd
     close(mList->hwLayers[idx].releaseFenceFd);
     mList->hwLayers[idx].releaseFenceFd = -1;
     mList->numHwLayers = 0;
     return true;
@@ -549,38 +566,36 @@ HwcComposer2D::Prepare(buffer_handle_t f
 bool
 HwcComposer2D::Commit()
 {
     hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
     displays[HWC_DISPLAY_PRIMARY] = mList;
 
     int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
 
-    for (int i = 0; i <= MAX_HWC_LAYERS; i++) {
-        if (mPrevRelFd[i] <= 0) {
-            break;
+    if (!mPrevReleaseFds.IsEmpty()) {
+        // Wait for previous retire Fence to signal.
+        // Denotes contents on display have been replaced.
+        // For buffer-sync, framework should not over-write
+        // prev buffers until we close prev releaseFenceFds
+        sp<Fence> fence = new Fence(mPrevReleaseFds[0]);
+        if (fence->wait(1000) == -ETIME) {
+            LOGE("Wait timed-out for retireFenceFd %d", mPrevReleaseFds[0]);
         }
-        if (!i) {
-            // Wait for previous retire Fence to signal.
-            // Denotes contents on display have been replaced.
-            // For buffer-sync, framework should not over-write
-            // prev buffers until we close prev releaseFenceFds
-            sp<Fence> fence = new Fence(mPrevRelFd[i]);
-            if (fence->wait(1000) == -ETIME) {
-                LOGE("Wait timed-out for retireFenceFd %d", mPrevRelFd[i]);
-            }
+
+        for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
+            close(mPrevReleaseFds[i]);
         }
-        close(mPrevRelFd[i]);
-        mPrevRelFd[i] = -1;
+        mPrevReleaseFds.Clear();
     }
 
-    mPrevRelFd[0] = mList->retireFenceFd;
-    for (uint32_t j = 0; j < (mList->numHwLayers - 1); j++) {
+    mPrevReleaseFds.AppendElement(mList->retireFenceFd);
+    for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
         if (mList->hwLayers[j].compositionType == HWC_OVERLAY) {
-            mPrevRelFd[j + 1] = mList->hwLayers[j].releaseFenceFd;
+            mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
             mList->hwLayers[j].releaseFenceFd = -1;
         }
     }
 
     mList->retireFenceFd = -1;
     return !err;
 }
 #else
@@ -604,22 +619,24 @@ HwcComposer2D::TryRender(Layer* aRoot,
     if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) {
         LOGD("Render aborted. World transform has non-square angle rotation");
         return false;
     }
 
     MOZ_ASSERT(Initialized());
     if (mList) {
         mList->numHwLayers = 0;
+        mHwcLayerMap.Clear();
     }
 
     // XXX: The clear() below means all rect vectors will be have to be
     // reallocated. We may want to avoid this if possible
     mVisibleRegions.clear();
 
+    MOZ_ASSERT(mHwcLayerMap.IsEmpty());
     if (!PrepareLayerList(aRoot,
                           mScreenRect,
                           gfxMatrix(),
                           aGLWorldTransform))
     {
         LOGD("Render aborted. Nothing was drawn to the screen");
         if (mList) {
            mList->numHwLayers = 0;
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -19,18 +19,16 @@
 
 #include "Composer2D.h"
 #include "Layers.h"
 #include <vector>
 #include <list>
 
 #include <hardware/hwcomposer.h>
 
-#define MAX_HWC_LAYERS 15
-
 namespace mozilla {
 
 namespace layers {
 class ContainerLayer;
 class Layer;
 }
 
 //Holds a dynamically allocated vector of rectangles
@@ -78,14 +76,15 @@ private:
     hwc_surface_t           mSur;
     nsIntRect               mScreenRect;
     int                     mMaxLayerCount;
     bool                    mColorFill;
     bool                    mRBSwapSupport;
     //Holds all the dynamically allocated RectVectors needed
     //to render the current frame
     std::list<RectVector>   mVisibleRegions;
-    int                     mPrevRelFd[MAX_HWC_LAYERS + 1];
+    nsTArray<int>           mPrevReleaseFds;
+    nsTArray<layers::LayerComposite*> mHwcLayerMap;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_HwcComposer2D