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
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a379111..2289444 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -218,6 +218,18 @@
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 e9ba5ff..9790699 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -87,6 +87,7 @@
void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
Vector< sp<LayerBase> > 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 63f3d91..c63d0cf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -649,20 +649,101 @@
}
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<mDisplays.size() ; dpy++) {
+ const sp<DisplayDevice>& 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 ; i<count ; i++) {
+ if (currentLayers[i]->onPreComposition()) {
+ needExtraInvalidate = true;
+ }
+ }
+ if (needExtraInvalidate) {
+ signalLayerUpdate();
+ }
+}
+
+void SurfaceFlinger::postComposition()
+{
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ currentLayers[i]->onPostComposition();
+ }
+}
+
+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<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
@@ -684,10 +765,13 @@
}
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 @@
mHwWorkListDirty = false;
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
- const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
+ const Vector< sp<LayerBase> >& currentLayers(
+ hw->getVisibleLayersSortedByZ());
const size_t count = currentLayers.size();
const int32_t id = hw->getDisplayId();
@@ -723,32 +808,27 @@
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<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& 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 @@
mDebugInSwapBuffers = now;
HWComposer& hwc(getHwComposer());
-
- for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
- const sp<DisplayDevice>& hw(mDisplays[dpy]);
- if (hwc.initCheck() == NO_ERROR) {
- const Vector< sp<LayerBase> >& 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<count ; ++i, ++cur) {
- const sp<LayerBase>& 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 @@
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 @@
* 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 @@
if (mLayersRemoved) {
mLayersRemoved = false;
mVisibleRegionsDirty = true;
- const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
const size_t count = previousLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(previousLayers[i]);
@@ -1130,16 +1182,13 @@
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<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(layers[i]);
+ const sp<LayerBase>& layer(currentLayers[i]);
const Region dirty(layer->latchBuffer(visibleRegions));
Layer::State s(layer->drawingState());
invalidateLayerStack(s.layerStack, dirty);
@@ -1153,36 +1202,15 @@
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<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
- if (layer->onPreComposition()) {
- needInvalidate = true;
- }
- }
- if (needInvalidate) {
- signalLayerUpdate();
- }
-}
-void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& 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 @@
}
}
- composeSurfaces(hw, dirtyRegion);
+ doComposeSurfaces(hw, dirtyRegion);
- const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
- const size_t count = currentLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- currentLayers[i]->onPostComposition();
+ // 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<const DisplayDevice>& hw, const Region& dirty)
+void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
{
HWComposer& hwc(getHwComposer());
int32_t id = hw->getDisplayId();
@@ -1259,74 +1292,32 @@
for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& 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<const DisplayDevice>& 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 4831d9d..1f79906 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -248,9 +248,6 @@
*/
void handlePageFlip();
- void handleRefresh();
- void handleRepaint(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);
-
/* ------------------------------------------------------------------------
* Transactions
*/
@@ -348,8 +345,19 @@
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<const DisplayDevice>& hw,
+ const Region& dirtyRegion);
+ void doComposeSurfaces(const sp<const DisplayDevice>& hw,
+ const Region& dirty);
+
void postFramebuffer();
- void composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
void drawWormhole(const Region& region) const;
GLuint getProtectedTexName() const {
return mProtectedTexName;
@@ -358,7 +366,6 @@
/* ------------------------------------------------------------------------
* Debugging & dumpsys
*/
- void debugFlashRegions(const sp<const DisplayDevice>& hw, const Region& dirtyReg);
void listLayersLocked(const Vector<String16>& args, size_t& index,
String8& result, char* buffer, size_t SIZE) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index,