From cd60f99aba9e750700a967db30b74a29145739cf Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 16 Aug 2012 16:28:27 -0700 Subject: [PATCH] refactor compositing code to avoid multiple eglMakeCurrent() calls when multiple displays are connected, we ended-up having to call eglMakeCurrent() twice per display due to a limitation in EGL. this fixes that. Change-Id: I11e4584df50f8c24bbecee74e37b28b3ee031d2f --- services/surfaceflinger/DisplayDevice.cpp | 12 + services/surfaceflinger/DisplayDevice.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 293 ++++++++++----------- services/surfaceflinger/SurfaceFlinger.h | 17 +- 4 files changed, 167 insertions(+), 156 deletions(-) diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index a379111c7..228944422 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -218,6 +218,18 @@ bool DisplayDevice::getSecureLayerVisible() const { return mSecureLayerVisible; } +Region DisplayDevice::getDirtyRegion(bool repaintEverything) const { + Region dirty; + const Transform& planeTransform(mGlobalTransform); + if (repaintEverything) { + dirty.set(getBounds()); + } else { + dirty = planeTransform.transform(this->dirtyRegion); + dirty.andSelf(getBounds()); + } + return dirty; +} + // ---------------------------------------------------------------------------- bool DisplayDevice::canDraw() const { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e9ba5ff84..979069954 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -87,6 +87,7 @@ public: void setVisibleLayersSortedByZ(const Vector< sp >& layers); Vector< sp > getVisibleLayersSortedByZ() const; bool getSecureLayerVisible() const; + Region getDirtyRegion(bool repaintEverything) const; status_t setOrientation(int orientation); void setLayerStack(uint32_t stack); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 63f3d91f0..c63d0cf14 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -649,20 +649,101 @@ void SurfaceFlinger::handleMessageTransaction() { } void SurfaceFlinger::handleMessageInvalidate() { + ATRACE_CALL(); handlePageFlip(); } void SurfaceFlinger::handleMessageRefresh() { - handleRefresh(); + ATRACE_CALL(); + preComposition(); + rebuildLayerStacks(); + setUpHWComposer(); + doDebugFlashRegions(); + doComposition(); + postComposition(); +} +void SurfaceFlinger::doDebugFlashRegions() +{ + // is debugging enabled + if (CC_LIKELY(!mDebugRegion)) + return; + + const bool repaintEverything = mRepaintEverything; + for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { + // redraw the whole screen + doComposeSurfaces(hw, Region(hw->bounds())); + + // and draw the dirty region + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + glDisable(GL_BLEND); + glColor4f(1, 0, 1, 1); + const int32_t height = hw->getHeight(); + Region::const_iterator it = dirtyRegion.begin(); + Region::const_iterator const end = dirtyRegion.end(); + while (it != end) { + const Rect& r = *it++; + GLfloat vertices[][2] = { + { r.left, height - r.top }, + { r.left, height - r.bottom }, + { r.right, height - r.bottom }, + { r.right, height - r.top } + }; + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + hw->compositionComplete(); + // FIXME + if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) { + eglSwapBuffers(mEGLDisplay, hw->getEGLSurface()); + } + } + } + } + + postFramebuffer(); + + if (mDebugRegion > 1) { + usleep(mDebugRegion * 1000); + } +} + +void SurfaceFlinger::preComposition() +{ + bool needExtraInvalidate = false; + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; ionPreComposition()) { + needExtraInvalidate = true; + } + } + if (needExtraInvalidate) { + signalLayerUpdate(); + } +} + +void SurfaceFlinger::postComposition() +{ + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); + const size_t count = currentLayers.size(); + for (size_t i=0 ; ionPostComposition(); + } +} + +void SurfaceFlinger::rebuildLayerStacks() { + // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { + ATRACE_CALL(); mVisibleRegionsDirty = false; invalidateHwcGeometry(); - - /* - * rebuild the visible layer list per screen - */ - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); @@ -684,10 +765,13 @@ void SurfaceFlinger::handleMessageRefresh() { } hw->setVisibleLayersSortedByZ(layersSortedByZ); hw->undefinedRegion.set(hw->getBounds()); - hw->undefinedRegion.subtractSelf(hw->getTransform().transform(opaqueRegion)); + hw->undefinedRegion.subtractSelf( + hw->getTransform().transform(opaqueRegion)); } } +} +void SurfaceFlinger::setUpHWComposer() { HWComposer& hwc(getHwComposer()); if (hwc.initCheck() == NO_ERROR) { // build the h/w work list @@ -695,7 +779,8 @@ void SurfaceFlinger::handleMessageRefresh() { mHwWorkListDirty = false; for (size_t dpy=0 ; dpy hw(mDisplays[dpy]); - const Vector< sp >& currentLayers(hw->getVisibleLayersSortedByZ()); + const Vector< sp >& currentLayers( + hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); const int32_t id = hw->getDisplayId(); @@ -723,32 +808,27 @@ void SurfaceFlinger::handleMessageRefresh() { status_t err = hwc.prepare(); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); } +} +void SurfaceFlinger::doComposition() { + ATRACE_CALL(); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); - - // transform the dirty region into this screen's coordinate space - const Transform& planeTransform(hw->getTransform()); - Region dirtyRegion; - if (repaintEverything) { - dirtyRegion.set(hw->bounds()); - } else { - dirtyRegion = planeTransform.transform(hw->dirtyRegion); - dirtyRegion.andSelf(hw->bounds()); - } - hw->dirtyRegion.clear(); - - if (!dirtyRegion.isEmpty()) { - if (hw->canDraw()) { + if (hw->canDraw()) { + // transform the dirty region into this screen's coordinate space + const Region dirtyRegion(hw->getDirtyRegion(repaintEverything)); + if (!dirtyRegion.isEmpty()) { // repaint the framebuffer (if needed) - handleRepaint(hw, dirtyRegion); + doDisplayComposition(hw, dirtyRegion); } + hw->dirtyRegion.clear(); + hw->flip(hw->swapRegion); + hw->swapRegion.clear(); } // inform the h/w that we're done compositing hw->compositionComplete(); } - postFramebuffer(); } @@ -760,30 +840,13 @@ void SurfaceFlinger::postFramebuffer() mDebugInSwapBuffers = now; HWComposer& hwc(getHwComposer()); - - for (size_t dpy=0 ; dpy& hw(mDisplays[dpy]); - if (hwc.initCheck() == NO_ERROR) { - const Vector< sp >& currentLayers(hw->getVisibleLayersSortedByZ()); - const size_t count = currentLayers.size(); - const int32_t id = hw->getDisplayId(); - HWComposer::LayerListIterator cur = hwc.begin(id); - const HWComposer::LayerListIterator end = hwc.end(id); - for (size_t i=0 ; cur!=end && i& layer(currentLayers[i]); - layer->setAcquireFence(hw, *cur); - } - } - hw->flip(hw->swapRegion); - hw->swapRegion.clear(); - } - if (hwc.initCheck() == NO_ERROR) { // FIXME: eventually commit() won't take arguments // FIXME: EGL spec says: // "surface must be bound to the calling thread's current context, // for the current rendering API." - DisplayDevice::makeCurrent(getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext); + DisplayDevice::makeCurrent( + getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext); hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface()); } @@ -798,18 +861,7 @@ void SurfaceFlinger::postFramebuffer() for (size_t i = 0; cur != end && i < count; ++i, ++cur) { currentLayers[i]->onLayerDisplayed(hw, &*cur); } - } - - // FIXME: we need to call eglSwapBuffers() on displays that have - // GL composition and only on those. - // however, currently hwc.commit() already does that for the main - // display and never for the other ones - if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) { - // FIXME: EGL spec says: - // "surface must be bound to the calling thread's current context, - // for the current rendering API." - DisplayDevice::makeCurrent(hw, mEGLContext); - eglSwapBuffers(mEGLDisplay, hw->getEGLSurface()); + } else { for (size_t i = 0; i < count; i++) { currentLayers[i]->onLayerDisplayed(hw, NULL); } @@ -944,7 +996,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) * Perform our own transaction if needed */ - if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { + const LayerVector& previousLayers(mDrawingState.layersSortedByZ); + if (currentLayers.size() > previousLayers.size()) { // layers have been added mVisibleRegionsDirty = true; } @@ -954,7 +1007,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; - const LayerVector& previousLayers(mDrawingState.layersSortedByZ); const size_t count = previousLayers.size(); for (size_t i=0 ; i& layer(previousLayers[i]); @@ -1130,16 +1182,13 @@ void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack, void SurfaceFlinger::handlePageFlip() { - ATRACE_CALL(); Region dirtyRegion; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - bool visibleRegions = false; + const LayerVector& currentLayers(mDrawingState.layersSortedByZ); const size_t count = currentLayers.size(); - sp const* layers = currentLayers.array(); for (size_t i=0 ; i& layer(layers[i]); + const sp& layer(currentLayers[i]); const Region dirty(layer->latchBuffer(visibleRegions)); Layer::State s(layer->drawingState()); invalidateLayerStack(s.layerStack, dirty); @@ -1153,36 +1202,15 @@ void SurfaceFlinger::invalidateHwcGeometry() mHwWorkListDirty = true; } -void SurfaceFlinger::handleRefresh() -{ - bool needInvalidate = false; - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); - for (size_t i=0 ; i& layer(currentLayers[i]); - if (layer->onPreComposition()) { - needInvalidate = true; - } - } - if (needInvalidate) { - signalLayerUpdate(); - } -} -void SurfaceFlinger::handleRepaint(const sp& hw, +void SurfaceFlinger::doDisplayComposition(const sp& hw, const Region& inDirtyRegion) { - ATRACE_CALL(); - Region dirtyRegion(inDirtyRegion); // compute the invalid region hw->swapRegion.orSelf(dirtyRegion); - if (CC_UNLIKELY(mDebugRegion)) { - debugFlashRegions(hw, dirtyRegion); - } - uint32_t flags = hw->getFlags(); if (flags & DisplayDevice::SWAP_RECTANGLE) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only @@ -1203,19 +1231,24 @@ void SurfaceFlinger::handleRepaint(const sp& hw, } } - composeSurfaces(hw, dirtyRegion); + doComposeSurfaces(hw, dirtyRegion); - const LayerVector& currentLayers(mDrawingState.layersSortedByZ); - const size_t count = currentLayers.size(); - for (size_t i=0 ; ionPostComposition(); + // FIXME: we need to call eglSwapBuffers() on displays that have + // GL composition and only on those. + // however, currently hwc.commit() already does that for the main + // display and never for the other ones + if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) { + // FIXME: EGL spec says: + // "surface must be bound to the calling thread's current context, + // for the current rendering API." + eglSwapBuffers(mEGLDisplay, hw->getEGLSurface()); } // update the swap region and clear the dirty region hw->swapRegion.orSelf(dirtyRegion); } -void SurfaceFlinger::composeSurfaces(const sp& hw, const Region& dirty) +void SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty) { HWComposer& hwc(getHwComposer()); int32_t id = hw->getDisplayId(); @@ -1259,74 +1292,32 @@ void SurfaceFlinger::composeSurfaces(const sp& hw, const Re for (size_t i=0 ; i& layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); - if (!clip.isEmpty()) { - if (cur != end && cur->getCompositionType() == HWC_OVERLAY) { - if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) - && layer->isOpaque()) { - // never clear the very first layer since we're - // guaranteed the FB is already cleared - layer->clearWithOpenGL(hw, clip); - } - ++cur; - continue; - } - // render the layer - layer->draw(hw, clip); - } if (cur != end) { + // we're using h/w composer + if (!clip.isEmpty()) { + if (cur->getCompositionType() == HWC_OVERLAY) { + if (i && (cur->getHints() & HWC_HINT_CLEAR_FB) + && layer->isOpaque()) { + // never clear the very first layer since we're + // guaranteed the FB is already cleared + layer->clearWithOpenGL(hw, clip); + } + } else { + layer->draw(hw, clip); + } + layer->setAcquireFence(hw, *cur); + } ++cur; + } else { + // we're not using h/w composer + if (!clip.isEmpty()) { + layer->draw(hw, clip); + } } } } } -void SurfaceFlinger::debugFlashRegions(const sp& hw, - const Region& dirtyRegion) -{ - const uint32_t flags = hw->getFlags(); - const int32_t height = hw->getHeight(); - if (hw->swapRegion.isEmpty()) { - return; - } - - if (!(flags & DisplayDevice::SWAP_RECTANGLE)) { - const Region repaint((flags & DisplayDevice::PARTIAL_UPDATES) ? - dirtyRegion.bounds() : hw->bounds()); - composeSurfaces(hw, repaint); - } - - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - - static int toggle = 0; - toggle = 1 - toggle; - if (toggle) { - glColor4f(1, 0, 1, 1); - } else { - glColor4f(1, 1, 0, 1); - } - - Region::const_iterator it = dirtyRegion.begin(); - Region::const_iterator const end = dirtyRegion.end(); - while (it != end) { - const Rect& r = *it++; - GLfloat vertices[][2] = { - { r.left, height - r.top }, - { r.left, height - r.bottom }, - { r.right, height - r.bottom }, - { r.right, height - r.top } - }; - glVertexPointer(2, GL_FLOAT, 0, vertices); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } - - hw->flip(hw->swapRegion); - - if (mDebugRegion > 1) - usleep(mDebugRegion * 1000); -} - void SurfaceFlinger::drawWormhole(const Region& region) const { glDisable(GL_TEXTURE_EXTERNAL_OES); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4831d9d8d..1f799068d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -248,9 +248,6 @@ private: */ void handlePageFlip(); - void handleRefresh(); - void handleRepaint(const sp& hw, const Region& dirtyRegion); - /* ------------------------------------------------------------------------ * Transactions */ @@ -348,8 +345,19 @@ private: void computeVisibleRegions(const LayerVector& currentLayers, uint32_t layerStack, Region& dirtyRegion, Region& opaqueRegion); + + void preComposition(); + void postComposition(); + void rebuildLayerStacks(); + void setUpHWComposer(); + void doComposition(); + void doDebugFlashRegions(); + void doDisplayComposition(const sp& hw, + const Region& dirtyRegion); + void doComposeSurfaces(const sp& hw, + const Region& dirty); + void postFramebuffer(); - void composeSurfaces(const sp& hw, const Region& dirty); void drawWormhole(const Region& region) const; GLuint getProtectedTexName() const { return mProtectedTexName; @@ -358,7 +366,6 @@ private: /* ------------------------------------------------------------------------ * Debugging & dumpsys */ - void debugFlashRegions(const sp& hw, const Region& dirtyReg); void listLayersLocked(const Vector& args, size_t& index, String8& result, char* buffer, size_t SIZE) const; void dumpStatsLocked(const Vector& args, size_t& index,