Bug 1049296 - Handle Sideband stream compositing in HwcComposer2D r=mwu,nical
authorSotaro Ikeda <sotaro.ikeda.g@gmail.com>
Mon, 18 Jan 2016 20:52:32 -0800
changeset 280424 9672f0dc4b626d6573f8ab3481a03c3a54f25c6e
parent 280423 6f5872d14fa47ae7a0c1b411f987e4e5a4096b85
child 280425 4724e966fc73c605cc4865cfb208d5e98c9319d8
push id70446
push usersikeda@mozilla.com
push dateTue, 19 Jan 2016 04:52:55 +0000
treeherdermozilla-inbound@9672f0dc4b62 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu, nical
bugs1049296
milestone46.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 1049296 - Handle Sideband stream compositing in HwcComposer2D r=mwu,nical
gfx/layers/Compositor.h
gfx/layers/composite/ImageHost.cpp
gfx/layers/composite/ImageHost.h
gfx/layers/composite/LayerManagerComposite.cpp
gfx/layers/opengl/Composer2D.h
gfx/layers/opengl/CompositorOGL.h
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
--- a/gfx/layers/Compositor.h
+++ b/gfx/layers/Compositor.h
@@ -114,16 +114,17 @@ class Matrix;
 class DrawTarget;
 } // namespace gfx
 
 namespace layers {
 
 struct Effect;
 struct EffectChain;
 class Image;
+class ImageHostOverlay;
 class Layer;
 class TextureSource;
 class DataTextureSource;
 class CompositingRenderTarget;
 class PCompositorParent;
 class LayerManagerComposite;
 
 enum SurfaceInitMode
@@ -448,16 +449,22 @@ public:
    * composite. Returns false if rendering should be aborted.
    */
   virtual bool Ready() { return true; }
 
   // XXX I expect we will want to move mWidget into this class and implement
   // these methods properly.
   virtual nsIWidget* GetWidget() const { return nullptr; }
 
+  virtual bool HasImageHostOverlays() { return false; }
+
+  virtual void AddImageHostOverlay(ImageHostOverlay* aOverlay) {}
+
+  virtual void RemoveImageHostOverlay(ImageHostOverlay* aOverlay) {}
+
   /**
    * Debug-build assertion that can be called to ensure code is running on the
    * compositor thread.
    */
   static void AssertOnCompositorThread();
 
   size_t GetFillRatio() {
     float fillRatio = 0;
--- a/gfx/layers/composite/ImageHost.cpp
+++ b/gfx/layers/composite/ImageHost.cpp
@@ -436,16 +436,19 @@ ImageHost::Composite(LayerComposite* aLa
 void
 ImageHost::SetCompositor(Compositor* aCompositor)
 {
   if (mCompositor != aCompositor) {
     for (auto& img : mImages) {
       img.mFrontBuffer->SetCompositor(aCompositor);
     }
   }
+  if (mImageHostOverlay) {
+    mImageHostOverlay->SetCompositor(aCompositor);
+  }
   CompositableHost::SetCompositor(aCompositor);
 }
 
 void
 ImageHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 {
   aStream << aPrefix;
   aStream << nsPrintfCString("ImageHost (0x%p)", this).get();
@@ -581,42 +584,59 @@ ImageHost::SetImageContainer(ImageContai
 
 ImageHostOverlay::ImageHostOverlay()
 {
   MOZ_COUNT_CTOR(ImageHostOverlay);
 }
 
 ImageHostOverlay::~ImageHostOverlay()
 {
+  if (mCompositor) {
+    mCompositor->RemoveImageHostOverlay(this);
+  }
   MOZ_COUNT_DTOR(ImageHostOverlay);
 }
 
 /* static */ bool
 ImageHostOverlay::IsValid(OverlaySource aOverlay)
 {
   if ((aOverlay.handle().type() == OverlayHandle::Tint32_t) &&
       aOverlay.handle().get_int32_t() != INVALID_OVERLAY) {
     return true;
   } else if (aOverlay.handle().type() == OverlayHandle::TGonkNativeHandle) {
     return true;
   }
   return false;
 }
 
 void
+ImageHostOverlay::SetCompositor(Compositor* aCompositor)
+{
+  if (mCompositor && (mCompositor != aCompositor)) {
+    mCompositor->RemoveImageHostOverlay(this);
+  }
+  if (aCompositor) {
+    aCompositor->AddImageHostOverlay(this);
+  }
+  mCompositor = aCompositor;
+}
+
+void
 ImageHostOverlay::Composite(Compositor* aCompositor,
                             uint32_t aFlashCounter,
                             LayerComposite* aLayer,
                             EffectChain& aEffectChain,
                             float aOpacity,
                             const gfx::Matrix4x4& aTransform,
                             const gfx::Filter& aFilter,
                             const gfx::Rect& aClipRect,
                             const nsIntRegion* aVisibleRegion)
 {
+  MOZ_ASSERT(mCompositor == aCompositor);
+
   if (mOverlay.handle().type() == OverlayHandle::Tnull_t) {
     return;
   }
 
   Color hollow(0.0f, 0.0f, 0.0f, 0.0f);
   aEffectChain.mPrimaryEffect = new EffectSolidColor(hollow);
   aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] = new EffectBlendMode(CompositionOp::OP_SOURCE);
 
--- a/gfx/layers/composite/ImageHost.h
+++ b/gfx/layers/composite/ImageHost.h
@@ -153,31 +153,34 @@ protected:
   virtual ~ImageHostOverlay();
 
 public:
   NS_INLINE_DECL_REFCOUNTING(ImageHostOverlay)
   ImageHostOverlay();
 
   static bool IsValid(OverlaySource aOverlay);
 
+  void SetCompositor(Compositor* aCompositor);
+
   virtual void Composite(Compositor* aCompositor,
                          uint32_t aFlashCounter,
                          LayerComposite* aLayer,
                          EffectChain& aEffectChain,
                          float aOpacity,
                          const gfx::Matrix4x4& aTransform,
                          const gfx::Filter& aFilter,
                          const gfx::Rect& aClipRect,
                          const nsIntRegion* aVisibleRegion);
   virtual LayerRenderState GetRenderState();
   virtual void UseOverlaySource(OverlaySource aOverlay,
                                 const gfx::IntRect& aPictureRect);
   virtual gfx::IntSize GetImageSize() const;
   virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
 protected:
+  RefPtr<Compositor> mCompositor;
   gfx::IntRect mPictureRect;
   OverlaySource mOverlay;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -804,17 +804,19 @@ LayerManagerComposite::Render(const nsIn
   /** Our more efficient but less powerful alter ego, if one is available. */
   RefPtr<Composer2D> composer2D;
   composer2D = mCompositor->GetWidget()->GetComposer2D();
 
   // We can't use composert2D if we have layer effects
   if (!mTarget && !haveLayerEffects &&
       gfxPrefs::Composer2DCompositionEnabled() &&
       composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot,
-          mCompositor->GetWidget(), mGeometryChanged))
+          mCompositor->GetWidget(),
+          mGeometryChanged,
+          mCompositor->HasImageHostOverlays()))
   {
     LayerScope::SetHWComposed();
     if (mFPS) {
       double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
       if (gfxPrefs::LayersDrawFPS()) {
         printf_stderr("HWComposer: FPS is %g\n", fps);
       }
     }
--- a/gfx/layers/opengl/Composer2D.h
+++ b/gfx/layers/opengl/Composer2D.h
@@ -44,18 +44,20 @@ public:
   /**
    * 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.
    *
    * Currently, when TryRender() returns true, the entire framebuffer
    * must have been rendered.
    */
-  virtual bool TryRenderWithHwc(Layer* aRoot, nsIWidget* aWidget,
-                                bool aGeometryChanged) = 0;
+  virtual bool TryRenderWithHwc(Layer* aRoot,
+                                nsIWidget* aWidget,
+                                bool aGeometryChanged,
+                                bool aHasImageHostOverlays) = 0;
 
   /**
    * Return true if Composer2D does composition. Return false if Composer2D
    * failed the composition.
    */
   virtual bool Render(nsIWidget* aWidget) = 0;
 
   /**
--- a/gfx/layers/opengl/CompositorOGL.h
+++ b/gfx/layers/opengl/CompositorOGL.h
@@ -29,30 +29,39 @@
 #include "nsDebug.h"                    // for NS_ASSERTION, NS_WARNING
 #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 #include "nsTArray.h"                   // for nsAutoTArray, nsTArray, etc
 #include "nsThreadUtils.h"              // for nsRunnable
 #include "nsXULAppAPI.h"                // for XRE_GetProcessType
 #include "nscore.h"                     // for NS_IMETHOD
 #include "gfxVR.h"
 
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+#include "nsTHashtable.h"               // for nsTHashtable
+#endif
+
 class nsIWidget;
 
 namespace mozilla {
 
 namespace layers {
 
 class CompositingRenderTarget;
 class CompositingRenderTargetOGL;
 class DataTextureSource;
 class GLManagerCompositor;
 class TextureSource;
 struct Effect;
 struct EffectChain;
 class GLBlitTextureImageHelper;
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+class ImageHostOverlay;
+#endif
+
 /**
  * Interface for pools of temporary gl textures for the compositor.
  * The textures are fully owned by the pool, so the latter is responsible
  * calling fDeleteTextures accordingly.
  * Users of GetTexture receive a texture that is only valid for the duration
  * of the current frame.
  * This is primarily intended for direct texturing APIs that need to attach
  * shared objects (such as an EGLImage) to a gl texture.
@@ -263,16 +272,39 @@ public:
     return LayersBackend::LAYERS_OPENGL;
   }
 
   virtual void Pause() override;
   virtual bool Resume() override;
 
   virtual nsIWidget* GetWidget() const override { return mWidget; }
 
+  virtual bool HasImageHostOverlays() override
+  {
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+    return mImageHostOverlays.Count() > 0;
+#else
+    return false;
+#endif
+  }
+
+  virtual void AddImageHostOverlay(ImageHostOverlay* aOverlay) override
+  {
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+    mImageHostOverlays.PutEntry(aOverlay);
+#endif
+  }
+
+  virtual void RemoveImageHostOverlay(ImageHostOverlay* aOverlay) override
+  {
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+    mImageHostOverlays.RemoveEntry(aOverlay);
+#endif
+  }
+
   GLContext* gl() const { return mGLContext; }
   /**
    * Clear the program state. This must be called
    * before operating on the GLContext directly. */
   void ResetProgram();
 
   gfx::SurfaceFormat GetFBOFormat() const {
     return gfx::SurfaceFormat::R8G8B8A8;
@@ -442,14 +474,19 @@ private:
    */
   gfx::IntSize mViewportSize;
 
   ShaderProgramOGL *mCurrentProgram;
 
   gfx::Rect mRenderBound;
 
   CompositorOGLVRObjects mVR;
+
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+  nsTHashtable<nsPtrHashKey<ImageHostOverlay> > mImageHostOverlays;
+#endif
+
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_COMPOSITOROGL_H */
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -118,17 +118,18 @@ HwcComposer2D::HwcComposer2D()
     win->query(win, NATIVE_WINDOW_WIDTH, &screenSize.width);
     win->query(win, NATIVE_WINDOW_HEIGHT, &screenSize.height);
     mScreenRect = gfx::IntRect(gfx::IntPoint(0, 0), screenSize);
 
     mColorFill = mHal->Query(HwcHALBase::QueryType::COLOR_FILL);
     mRBSwapSupport = mHal->Query(HwcHALBase::QueryType::RB_SWAP);
 }
 
-HwcComposer2D::~HwcComposer2D() {
+HwcComposer2D::~HwcComposer2D()
+{
     free(mList);
 }
 
 HwcComposer2D*
 HwcComposer2D::GetInstance()
 {
     if (!sInstance) {
 #ifdef HWC_DEBUG
@@ -265,17 +266,18 @@ HwcComposer2D::ReallocLayerList()
     mList = listrealloc;
     mMaxLayerCount += LAYER_COUNT_INCREMENTS;
     return true;
 }
 
 bool
 HwcComposer2D::PrepareLayerList(Layer* aLayer,
                                 const nsIntRect& aClip,
-                                const Matrix& aParentTransform)
+                                const Matrix& aParentTransform,
+                                bool aFindSidebandStreams)
 {
     // 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.
 
     bool fillColor = false;
 
     const nsIntRegion visibleRegion = aLayer->GetEffectiveVisibleRegion().ToUnknownRegion();
@@ -284,22 +286,22 @@ HwcComposer2D::PrepareLayerList(Layer* a
     }
 
     uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
     if (opacity == 0) {
         LOGD("%s Layer has zero opacity; skipping", aLayer->Name());
         return true;
     }
 
-    if (!mHal->SupportTransparency() && opacity < 0xFF) {
+    if (!mHal->SupportTransparency() && opacity < 0xFF && !aFindSidebandStreams) {
         LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name());
         return false;
     }
 
-    if (aLayer->GetMaskLayer()) {
+    if (aLayer->GetMaskLayer() && !aFindSidebandStreams) {
         LOGD("%s Layer has MaskLayer which is unsupported by hwcomposer", aLayer->Name());
         return false;
     }
 
     nsIntRect clip;
     nsIntRect layerClip = aLayer->GetEffectiveClipRect().valueOr(ParentLayerIntRect()).ToUnknownRect();
     nsIntRect* layerClipPtr = aLayer->GetEffectiveClipRect() ? &layerClip : nullptr;
     if (!HwcUtils::CalculateClipRect(aParentTransform,
@@ -330,25 +332,26 @@ HwcComposer2D::PrepareLayerList(Layer* a
     Matrix layerBufferTransform;
     if (!aLayer->GetEffectiveTransformForBuffer().Is2D(&layerBufferTransform) ||
         !layerBufferTransform.PreservesAxisAlignedRectangles()) {
         LOGD("Layer EffectiveTransformForBuffer has a 3D transform or a non-square angle rotation");
       return false;
     }
 
     if (ContainerLayer* container = aLayer->AsContainerLayer()) {
-        if (container->UseIntermediateSurface()) {
+        if (container->UseIntermediateSurface() && !aFindSidebandStreams) {
             LOGD("Container layer needs intermediate surface");
             return false;
         }
         nsAutoTArray<Layer*, 12> children;
         container->SortChildrenBy3DZOrder(children);
 
         for (uint32_t i = 0; i < children.Length(); i++) {
-            if (!PrepareLayerList(children[i], clip, layerTransform)) {
+            if (!PrepareLayerList(children[i], clip, layerTransform, aFindSidebandStreams) &&
+                !aFindSidebandStreams) {
                 return false;
             }
         }
         return true;
     }
 
     LayerRenderState state = aLayer->GetRenderState();
 
@@ -640,16 +643,22 @@ 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().ToABGR();
     }
 
+#if ANDROID_VERSION >= 21
+    if (aFindSidebandStreams && hwcLayer.compositionType == HWC_SIDEBAND) {
+        mCachedSidebandLayers.AppendElement(hwcLayer);
+    }
+#endif
+
     mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
     mList->numHwLayers++;
     return true;
 }
 
 
 #if ANDROID_VERSION >= 17
 bool
@@ -697,16 +706,19 @@ HwcComposer2D::TryHwComposition(nsScreen
         for (int k=0; k < idx; k++) {
             switch (mList->hwLayers[k].compositionType) {
                 case HWC_FRAMEBUFFER:
                     gpuComposite = true;
                     break;
                 case HWC_BLIT:
                     blitComposite = true;
                     break;
+#if ANDROID_VERSION >= 21
+                case HWC_SIDEBAND:
+#endif
                 case HWC_OVERLAY: {
                     // HWC will compose HWC_OVERLAY layers in partial
                     // Overlay Composition, set layer composition flag
                     // on mapped LayerComposite to skip GPU composition
                     mHwcLayerMap[k]->SetLayerComposited(true);
 
                     uint8_t opacity = std::min(0xFF, (int)(mHwcLayerMap[k]->GetLayer()->GetEffectiveOpacity() * 256.0));
                     if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) &&
@@ -775,16 +787,25 @@ HwcComposer2D::Render(nsIWidget* aWidget
         mList->numHwLayers = 2;
         mList->hwLayers[0].hints = 0;
         mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER;
         mList->hwLayers[0].flags = HWC_SKIP_LAYER;
         mList->hwLayers[0].backgroundColor = {0};
         mList->hwLayers[0].acquireFenceFd = -1;
         mList->hwLayers[0].releaseFenceFd = -1;
         mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height};
+
+#if ANDROID_VERSION >= 21
+        // Prepare layers for sideband streams
+        const uint32_t len = mCachedSidebandLayers.Length();
+        for (uint32_t i = 0; i < len; ++i) {
+            ++mList->numHwLayers;
+            mList->hwLayers[i+1] = mCachedSidebandLayers[i];
+        }
+#endif
         Prepare(dispSurface->lastHandle, dispSurface->GetPrevDispAcquireFd(), screen);
     }
 
     // GPU or partial HWC Composition
     return Commit(screen);
 }
 
 void
@@ -863,17 +884,18 @@ HwcComposer2D::Render(nsIWidget* aWidget
     nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen();
     return GetGonkDisplay()->SwapBuffers(screen->GetEGLDisplay(), screen->GetEGLSurface());
 }
 #endif
 
 bool
 HwcComposer2D::TryRenderWithHwc(Layer* aRoot,
                                 nsIWidget* aWidget,
-                                bool aGeometryChanged)
+                                bool aGeometryChanged,
+                                bool aHasImageHostOverlays)
 {
     if (!mHal->HasHwc()) {
         return false;
     }
 
     nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen();
 
     if (mList) {
@@ -888,22 +910,38 @@ HwcComposer2D::TryRenderWithHwc(Layer* a
     }
 
     // XXX: The clear() below means all rect vectors will be have to be
     // reallocated. We may want to avoid this if possible
     mVisibleRegions.clear();
 
     mScreenRect = screen->GetNaturalBounds().ToUnknownRect();
     MOZ_ASSERT(mHwcLayerMap.IsEmpty());
+    mCachedSidebandLayers.Clear();
     if (!PrepareLayerList(aRoot,
                           mScreenRect,
-                          gfx::Matrix()))
+                          gfx::Matrix(),
+                          /* aFindSidebandStreams */ false))
     {
         mHwcLayerMap.Clear();
-        LOGD("Render aborted. Nothing was drawn to the screen");
+        LOGD("Render aborted. Fallback to GPU Composition");
+        if (aHasImageHostOverlays) {
+            LOGD("Prepare layers of SidebandStreams");
+            // Failed to create a layer list for hwc. But we need the list
+            // only for handling sideband streams. Traverse layer tree without
+            // some early returns to make sure we can find all the layers.
+            // It is the best wrong thing that we can do.
+            PrepareLayerList(aRoot,
+                             mScreenRect,
+                             gfx::Matrix(),
+                             /* aFindSidebandStreams */ true);
+            // Reset mPrepared to false, since we already fell back to
+            // gpu composition.
+            mPrepared = false;
+        }
         return false;
     }
 
     // Send data to LayerScope for debugging
     SendtoLayerScope();
 
     if (!TryHwComposition(screen)) {
         LOGD("Full HWC Composition failed. Fallback to GPU Composition or partial OVERLAY Composition");
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -69,17 +69,18 @@ public:
 
     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
     virtual bool TryRenderWithHwc(layers::Layer* aRoot,
                                   nsIWidget* aWidget,
-                                  bool aGeometryChanged) override;
+                                  bool aGeometryChanged,
+                                  bool aHasImageHostOverlays) override;
 
     virtual bool Render(nsIWidget* aWidget) override;
 
     virtual bool HasHwc() override { return mHal->HasHwc(); }
 
     bool EnableVsync(bool aEnable);
     bool RegisterHwcEventCallback();
     void Vsync(int aDisplay, int64_t aTimestamp);
@@ -89,30 +90,32 @@ public:
 
 private:
     void Reset();
     void Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen);
     bool Commit(nsScreenGonk* aScreen);
     bool TryHwComposition(nsScreenGonk* aScreen);
     bool ReallocLayerList();
     bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip,
-          const gfx::Matrix& aParentTransform);
+          const gfx::Matrix& aParentTransform,
+          bool aFindSidebandStreams);
     void SendtoLayerScope();
 
     UniquePtr<HwcHALBase>   mHal;
     HwcList*                mList;
     nsIntRect               mScreenRect;
     int                     mMaxLayerCount;
     bool                    mColorFill;
     bool                    mRBSwapSupport;
     //Holds all the dynamically allocated RectVectors needed
     //to render the current frame
     std::list<HwcUtils::RectVector>   mVisibleRegions;
     layers::FenceHandle mPrevRetireFence;
     layers::FenceHandle mPrevDisplayFence;
+    nsTArray<HwcLayer>      mCachedSidebandLayers;
     nsTArray<layers::LayerComposite*> mHwcLayerMap;
     bool                    mPrepared;
     bool                    mHasHWVsync;
     layers::CompositorParent* mCompositorParent;
     Mutex mLock;
 };
 
 } // namespace mozilla