Bug 919676 - Fix multiple hwc prepare calls with different layer lists. r=mwu, r=dwilson
authorSushil Chauhan <sushilc@codeaurora.org>
Tue, 08 Oct 2013 08:29:35 -0700
changeset 150210 a13d52159c513fc81a4f234e971d944b65865dcd
parent 150209 d67872a94a98deb731925884e6559a1205420cf9
child 150211 e4c2830550418025aad2f51134982a83b8648c3b
push idunknown
push userunknown
push dateunknown
reviewersmwu, dwilson
bugs919676
milestone27.0a1
Bug 919676 - Fix multiple hwc prepare calls with different layer lists. r=mwu, r=dwilson
gfx/gl/GLContextProviderEGL.cpp
widget/gonk/HwcComposer2D.cpp
widget/gonk/HwcComposer2D.h
widget/gonk/libdisplay/GonkDisplay.h
widget/gonk/libdisplay/GonkDisplayICS.cpp
widget/gonk/libdisplay/GonkDisplayICS.h
widget/gonk/libdisplay/GonkDisplayJB.cpp
widget/gonk/libdisplay/GonkDisplayJB.h
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -600,19 +600,23 @@ public:
             return nullptr;
         }
     }
 
     bool SwapBuffers()
     {
         if (mSurface && !mPlatformContext) {
 #ifdef MOZ_WIDGET_GONK
-            if (!mIsOffscreen)
-                return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
-            else
+            if (!mIsOffscreen) {
+                if (mHwc) {
+                    return mHwc->Render(EGL_DISPLAY(), mSurface);
+                } else {
+                    return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
+                }
+            } else
 #endif
                 return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
         } else {
             return false;
         }
     }
     // GLContext interface - returns Tiled Texture Image in our case
     virtual already_AddRefed<TextureImage>
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -440,55 +440,124 @@ HwcComposer2D::PrepareLayerList(Layer* a
 
 
 #if ANDROID_VERSION >= 18
 bool
 HwcComposer2D::TryHwComposition()
 {
     FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
 
+    if (!(fbsurface && fbsurface->lastHandle)) {
+        LOGD("H/W Composition failed. FBSurface not initialized.");
+        return false;
+    }
+
+    // Add FB layer
+    int idx = mList->numHwLayers++;
+    if (idx >= mMaxLayerCount) {
+        if (!ReallocLayerList() || idx >= mMaxLayerCount) {
+            LOGE("TryHwComposition failed! Could not add FB layer");
+            return false;
+        }
+    }
+
+    Prepare(fbsurface->lastHandle, -1);
+
+    for (int j = 0; j < idx; j++) {
+        if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
+            LOGD("GPU or Partial HWC Composition");
+            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;
+}
+
+bool
+HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
+{
+    if (!mList) {
+        // After boot, HWC list hasn't been created yet
+        return GetGonkDisplay()->SwapBuffers(dpy, sur);
+    }
+
+    GetGonkDisplay()->UpdateFBSurface(dpy, sur);
+
+    FramebufferSurface* fbsurface = (FramebufferSurface*)(GetGonkDisplay()->GetFBSurface());
     if (!fbsurface) {
         LOGE("H/W Composition failed. FBSurface not initialized.");
         return false;
     }
 
-    hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL};
+    if (mList->numHwLayers != 0) {
+        // No mHwc prepare, if already prepared in current draw cycle
+        mList->hwLayers[mList->numHwLayers - 1].handle = fbsurface->lastHandle;
+        mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = fbsurface->lastFenceFD;
+    } else {
+        mList->numHwLayers = 2;
+        mList->hwLayers[0].hints = 0;
+        mList->hwLayers[0].compositionType = HWC_BACKGROUND;
+        mList->hwLayers[0].flags = HWC_SKIP_LAYER;
+        mList->hwLayers[0].backgroundColor = {0};
+        mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height};
+        Prepare(fbsurface->lastHandle, fbsurface->lastFenceFD);
+    }
+
+    // GPU or partial HWC Composition
+    Commit();
+
+    GetGonkDisplay()->SetFBReleaseFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd);
+    mList->numHwLayers = 0;
+    return true;
+}
+
+void
+HwcComposer2D::Prepare(buffer_handle_t fbHandle, int fence)
+{
+    int idx = mList->numHwLayers - 1;
     const hwc_rect_t r = {0, 0, mScreenRect.width, mScreenRect.height};
-    int idx = mList->numHwLayers;
+    hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
 
     displays[HWC_DISPLAY_PRIMARY] = mList;
     mList->flags = HWC_GEOMETRY_CHANGED;
+    mList->outbufAcquireFenceFd = -1;
+    mList->outbuf = nullptr;
     mList->retireFenceFd = -1;
 
     mList->hwLayers[idx].hints = 0;
     mList->hwLayers[idx].flags = 0;
     mList->hwLayers[idx].transform = 0;
-    mList->hwLayers[idx].handle = fbsurface->lastHandle;
+    mList->hwLayers[idx].handle = fbHandle;
     mList->hwLayers[idx].blending = HWC_BLENDING_PREMULT;
     mList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET;
     mList->hwLayers[idx].sourceCrop = r;
     mList->hwLayers[idx].displayFrame = r;
     mList->hwLayers[idx].visibleRegionScreen.numRects = 1;
     mList->hwLayers[idx].visibleRegionScreen.rects = &mList->hwLayers[idx].sourceCrop;
-    mList->hwLayers[idx].acquireFenceFd = -1;
+    mList->hwLayers[idx].acquireFenceFd = fence;
     mList->hwLayers[idx].releaseFenceFd = -1;
     mList->hwLayers[idx].planeAlpha = 0xFF;
-    mList->numHwLayers++;
 
     mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
+}
 
-    for (int j = 0; j < idx; j++) {
-        if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
-            LOGD("GPU or Partial MDP Composition");
-            return false;
-        }
-    }
+bool
+HwcComposer2D::Commit()
+{
+    hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
+    displays[HWC_DISPLAY_PRIMARY] = mList;
 
-    // Full MDP Composition
-    mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
+    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 (!i) {
             // Wait for previous retire Fence to signal.
             // Denotes contents on display have been replaced.
@@ -499,35 +568,38 @@ HwcComposer2D::TryHwComposition()
                 LOGE("Wait timed-out for retireFenceFd %d", mPrevRelFd[i]);
             }
         }
         close(mPrevRelFd[i]);
         mPrevRelFd[i] = -1;
     }
 
     mPrevRelFd[0] = mList->retireFenceFd;
-    for (uint32_t j = 0; j < idx; j++) {
+    for (uint32_t j = 0; j < (mList->numHwLayers - 1); j++) {
         if (mList->hwLayers[j].compositionType == HWC_OVERLAY) {
             mPrevRelFd[j + 1] = mList->hwLayers[j].releaseFenceFd;
             mList->hwLayers[j].releaseFenceFd = -1;
         }
     }
 
-    close(mList->hwLayers[idx].releaseFenceFd);
-    mList->hwLayers[idx].releaseFenceFd = -1;
     mList->retireFenceFd = -1;
-    mList->numHwLayers = 0;
-    return true;
+    return !err;
 }
 #else
 bool
 HwcComposer2D::TryHwComposition()
 {
     return !mHwc->set(mHwc, mDpy, mSur, mList);
 }
+
+bool
+HwcComposer2D::Render(EGLDisplay dpy, EGLSurface sur)
+{
+    return GetGonkDisplay()->SwapBuffers(dpy, sur);
+}
 #endif
 
 bool
 HwcComposer2D::TryRender(Layer* aRoot,
                          const gfxMatrix& aGLWorldTransform)
 {
     if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) {
         LOGD("Render aborted. World transform has non-square angle rotation");
@@ -544,22 +616,24 @@ HwcComposer2D::TryRender(Layer* aRoot,
     mVisibleRegions.clear();
 
     if (!PrepareLayerList(aRoot,
                           mScreenRect,
                           gfxMatrix(),
                           aGLWorldTransform))
     {
         LOGD("Render aborted. Nothing was drawn to the screen");
+        if (mList) {
+           mList->numHwLayers = 0;
+        }
         return false;
     }
 
     if (!TryHwComposition()) {
-      // Full MDP Composition
-      LOGE("H/W Composition failed");
-      return false;
+        LOGD("H/W Composition failed");
+        return false;
     }
 
     LOGD("Frame rendered");
     return true;
 }
 
 } // namespace mozilla
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -57,17 +57,21 @@ 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
     bool TryRender(layers::Layer* aRoot, const gfxMatrix& aGLWorldTransform) MOZ_OVERRIDE;
 
+    bool Render(EGLDisplay dpy, EGLSurface sur);
+
 private:
+    void Prepare(buffer_handle_t fbHandle, int fence);
+    bool Commit();
     bool TryHwComposition();
     bool ReallocLayerList();
     bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip,
           const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform);
 
     HwcDevice*              mHwc;
     HwcList*                mList;
     hwc_display_t           mDpy;
--- a/widget/gonk/libdisplay/GonkDisplay.h
+++ b/widget/gonk/libdisplay/GonkDisplay.h
@@ -38,16 +38,20 @@ public:
     virtual void* GetFBSurface() = 0;
 
     virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur) = 0;
 
     virtual ANativeWindowBuffer* DequeueBuffer() = 0;
 
     virtual bool QueueBuffer(ANativeWindowBuffer* buf) = 0;
 
+    virtual void UpdateFBSurface(EGLDisplay dpy, EGLSurface sur) = 0;
+
+    virtual void SetFBReleaseFd(int fd) = 0;
+
     float xdpi;
     uint32_t surfaceformat;
 };
 
 __attribute__ ((weak))
 GonkDisplay* GetGonkDisplay();
 
 }
--- a/widget/gonk/libdisplay/GonkDisplayICS.cpp
+++ b/widget/gonk/libdisplay/GonkDisplayICS.cpp
@@ -191,16 +191,27 @@ GonkDisplayICS::DequeueBuffer()
 
 bool
 GonkDisplayICS::QueueBuffer(ANativeWindowBuffer *buf)
 {
     ANativeWindow *window = static_cast<ANativeWindow *>(mFBSurface.get());
     return !window->queueBuffer(window, buf);
 }
 
+void
+GonkDisplayICS::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur)
+{
+    eglSwapBuffers(dpy, sur);
+}
+
+void
+GonkDisplayICS::SetFBReleaseFd(int fd)
+{
+}
+
 __attribute__ ((visibility ("default")))
 GonkDisplay*
 GetGonkDisplay()
 {
     if (!sGonkDisplay)
         sGonkDisplay = new GonkDisplayICS();
     return sGonkDisplay;
 }
--- a/widget/gonk/libdisplay/GonkDisplayICS.h
+++ b/widget/gonk/libdisplay/GonkDisplayICS.h
@@ -41,16 +41,20 @@ public:
     virtual void* GetFBSurface();
 
     virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur);
 
     virtual ANativeWindowBuffer* DequeueBuffer();
 
     virtual bool QueueBuffer(ANativeWindowBuffer* handle);
 
+    virtual void UpdateFBSurface(EGLDisplay dpy, EGLSurface sur);
+
+    virtual void SetFBReleaseFd(int fd);
+
 private:
     hw_module_t const*        mModule;
     hwc_composer_device_t*    mHwc;
     android::sp<android::FramebufferNativeWindow> mFBSurface;
 };
 
 }
 
--- a/widget/gonk/libdisplay/GonkDisplayJB.cpp
+++ b/widget/gonk/libdisplay/GonkDisplayJB.cpp
@@ -267,16 +267,30 @@ GonkDisplayJB::DequeueBuffer()
 
 bool
 GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf)
 {
     bool success = Post(buf->handle, -1);
     return success;
 }
 
+void
+GonkDisplayJB::UpdateFBSurface(EGLDisplay dpy, EGLSurface sur)
+{
+    StopBootAnimation();
+    mBootAnimBuffer = nullptr;
+    eglSwapBuffers(dpy, sur);
+}
+
+void
+GonkDisplayJB::SetFBReleaseFd(int fd)
+{
+    mFBSurface->setReleaseFenceFd(fd);
+}
+
 __attribute__ ((visibility ("default")))
 GonkDisplay*
 GetGonkDisplay()
 {
     if (!sGonkDisplay)
         sGonkDisplay = new GonkDisplayJB();
     return sGonkDisplay;
 }
--- a/widget/gonk/libdisplay/GonkDisplayJB.h
+++ b/widget/gonk/libdisplay/GonkDisplayJB.h
@@ -40,16 +40,20 @@ public:
     virtual void* GetFBSurface();
 
     virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur);
 
     virtual ANativeWindowBuffer* DequeueBuffer();
 
     virtual bool QueueBuffer(ANativeWindowBuffer* buf);
 
+    virtual void UpdateFBSurface(EGLDisplay dpy, EGLSurface sur);
+
+    virtual void SetFBReleaseFd(int fd);
+
     bool Post(buffer_handle_t buf, int fence);
 
 private:
     hw_module_t const*        mModule;
     hw_module_t const*        mFBModule;
     hwc_composer_device_1_t*  mHwc;
     framebuffer_device_t*     mFBDevice;
     power_module_t*           mPowerModule;