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 a13d52159c51
parent 150209 d67872a94a98
child 150211 e4c283055041
push id25427
push userryanvm@gmail.com
push dateWed, 09 Oct 2013 19:31:28 +0000
treeherdermozilla-central@a141e39bf6da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmwu, dwilson
bugs919676
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 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;