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
This commit is contained in:
Mathias Agopian 2012-08-16 16:28:27 -07:00
parent 5f20e2d446
commit cd60f99aba
4 changed files with 167 additions and 156 deletions

View File

@ -218,6 +218,18 @@ bool DisplayDevice::getSecureLayerVisible() const {
return mSecureLayerVisible; 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 { bool DisplayDevice::canDraw() const {

View File

@ -87,6 +87,7 @@ public:
void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers); void setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const; Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const;
bool getSecureLayerVisible() const; bool getSecureLayerVisible() const;
Region getDirtyRegion(bool repaintEverything) const;
status_t setOrientation(int orientation); status_t setOrientation(int orientation);
void setLayerStack(uint32_t stack); void setLayerStack(uint32_t stack);

View File

@ -649,20 +649,101 @@ void SurfaceFlinger::handleMessageTransaction() {
} }
void SurfaceFlinger::handleMessageInvalidate() { void SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
handlePageFlip(); handlePageFlip();
} }
void SurfaceFlinger::handleMessageRefresh() { 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)) { if (CC_UNLIKELY(mVisibleRegionsDirty)) {
ATRACE_CALL();
mVisibleRegionsDirty = false; mVisibleRegionsDirty = false;
invalidateHwcGeometry(); invalidateHwcGeometry();
/*
* rebuild the visible layer list per screen
*/
const LayerVector& currentLayers(mDrawingState.layersSortedByZ); const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]); const sp<DisplayDevice>& hw(mDisplays[dpy]);
@ -684,10 +765,13 @@ void SurfaceFlinger::handleMessageRefresh() {
} }
hw->setVisibleLayersSortedByZ(layersSortedByZ); hw->setVisibleLayersSortedByZ(layersSortedByZ);
hw->undefinedRegion.set(hw->getBounds()); 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()); HWComposer& hwc(getHwComposer());
if (hwc.initCheck() == NO_ERROR) { if (hwc.initCheck() == NO_ERROR) {
// build the h/w work list // build the h/w work list
@ -695,7 +779,8 @@ void SurfaceFlinger::handleMessageRefresh() {
mHwWorkListDirty = false; mHwWorkListDirty = false;
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[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 size_t count = currentLayers.size();
const int32_t id = hw->getDisplayId(); const int32_t id = hw->getDisplayId();
@ -723,32 +808,27 @@ void SurfaceFlinger::handleMessageRefresh() {
status_t err = hwc.prepare(); status_t err = hwc.prepare();
ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
} }
}
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything); const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]); const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->canDraw()) {
// transform the dirty region into this screen's coordinate space // transform the dirty region into this screen's coordinate space
const Transform& planeTransform(hw->getTransform()); const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
Region dirtyRegion; if (!dirtyRegion.isEmpty()) {
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()) {
// repaint the framebuffer (if needed) // 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 // inform the h/w that we're done compositing
hw->compositionComplete(); hw->compositionComplete();
} }
postFramebuffer(); postFramebuffer();
} }
@ -760,30 +840,13 @@ void SurfaceFlinger::postFramebuffer()
mDebugInSwapBuffers = now; mDebugInSwapBuffers = now;
HWComposer& hwc(getHwComposer()); 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) { if (hwc.initCheck() == NO_ERROR) {
// FIXME: eventually commit() won't take arguments // FIXME: eventually commit() won't take arguments
// FIXME: EGL spec says: // FIXME: EGL spec says:
// "surface must be bound to the calling thread's current context, // "surface must be bound to the calling thread's current context,
// for the current rendering API." // 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()); hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
} }
@ -798,18 +861,7 @@ void SurfaceFlinger::postFramebuffer()
for (size_t i = 0; cur != end && i < count; ++i, ++cur) { for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
currentLayers[i]->onLayerDisplayed(hw, &*cur); currentLayers[i]->onLayerDisplayed(hw, &*cur);
} }
} } else {
// 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());
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
currentLayers[i]->onLayerDisplayed(hw, NULL); currentLayers[i]->onLayerDisplayed(hw, NULL);
} }
@ -944,7 +996,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
* Perform our own transaction if needed * 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 // layers have been added
mVisibleRegionsDirty = true; mVisibleRegionsDirty = true;
} }
@ -954,7 +1007,6 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
if (mLayersRemoved) { if (mLayersRemoved) {
mLayersRemoved = false; mLayersRemoved = false;
mVisibleRegionsDirty = true; mVisibleRegionsDirty = true;
const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
const size_t count = previousLayers.size(); const size_t count = previousLayers.size();
for (size_t i=0 ; i<count ; i++) { for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(previousLayers[i]); const sp<LayerBase>& layer(previousLayers[i]);
@ -1130,16 +1182,13 @@ void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
void SurfaceFlinger::handlePageFlip() void SurfaceFlinger::handlePageFlip()
{ {
ATRACE_CALL();
Region dirtyRegion; Region dirtyRegion;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
bool visibleRegions = false; bool visibleRegions = false;
const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
const size_t count = currentLayers.size(); const size_t count = currentLayers.size();
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) { 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)); const Region dirty(layer->latchBuffer(visibleRegions));
Layer::State s(layer->drawingState()); Layer::State s(layer->drawingState());
invalidateLayerStack(s.layerStack, dirty); invalidateLayerStack(s.layerStack, dirty);
@ -1153,36 +1202,15 @@ void SurfaceFlinger::invalidateHwcGeometry()
mHwWorkListDirty = true; 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) const Region& inDirtyRegion)
{ {
ATRACE_CALL();
Region dirtyRegion(inDirtyRegion); Region dirtyRegion(inDirtyRegion);
// compute the invalid region // compute the invalid region
hw->swapRegion.orSelf(dirtyRegion); hw->swapRegion.orSelf(dirtyRegion);
if (CC_UNLIKELY(mDebugRegion)) {
debugFlashRegions(hw, dirtyRegion);
}
uint32_t flags = hw->getFlags(); uint32_t flags = hw->getFlags();
if (flags & DisplayDevice::SWAP_RECTANGLE) { if (flags & DisplayDevice::SWAP_RECTANGLE) {
// we can redraw only what's dirty, but since SWAP_RECTANGLE only // we can redraw only what's dirty, but since SWAP_RECTANGLE only
@ -1203,19 +1231,24 @@ void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
} }
} }
composeSurfaces(hw, dirtyRegion); doComposeSurfaces(hw, dirtyRegion);
const LayerVector& currentLayers(mDrawingState.layersSortedByZ); // FIXME: we need to call eglSwapBuffers() on displays that have
const size_t count = currentLayers.size(); // GL composition and only on those.
for (size_t i=0 ; i<count ; i++) { // however, currently hwc.commit() already does that for the main
currentLayers[i]->onPostComposition(); // 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 // update the swap region and clear the dirty region
hw->swapRegion.orSelf(dirtyRegion); 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()); HWComposer& hwc(getHwComposer());
int32_t id = hw->getDisplayId(); int32_t id = hw->getDisplayId();
@ -1259,74 +1292,32 @@ void SurfaceFlinger::composeSurfaces(const sp<const DisplayDevice>& hw, const Re
for (size_t i=0 ; i<count ; ++i) { for (size_t i=0 ; i<count ; ++i) {
const sp<LayerBase>& layer(layers[i]); const sp<LayerBase>& layer(layers[i]);
const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); 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) { 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; ++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 void SurfaceFlinger::drawWormhole(const Region& region) const
{ {
glDisable(GL_TEXTURE_EXTERNAL_OES); glDisable(GL_TEXTURE_EXTERNAL_OES);

View File

@ -248,9 +248,6 @@ private:
*/ */
void handlePageFlip(); void handlePageFlip();
void handleRefresh();
void handleRepaint(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Transactions * Transactions
*/ */
@ -348,8 +345,19 @@ private:
void computeVisibleRegions(const LayerVector& currentLayers, void computeVisibleRegions(const LayerVector& currentLayers,
uint32_t layerStack, uint32_t layerStack,
Region& dirtyRegion, Region& opaqueRegion); 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 postFramebuffer();
void composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
void drawWormhole(const Region& region) const; void drawWormhole(const Region& region) const;
GLuint getProtectedTexName() const { GLuint getProtectedTexName() const {
return mProtectedTexName; return mProtectedTexName;
@ -358,7 +366,6 @@ private:
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Debugging & dumpsys * Debugging & dumpsys
*/ */
void debugFlashRegions(const sp<const DisplayDevice>& hw, const Region& dirtyReg);
void listLayersLocked(const Vector<String16>& args, size_t& index, void listLayersLocked(const Vector<String16>& args, size_t& index,
String8& result, char* buffer, size_t SIZE) const; String8& result, char* buffer, size_t SIZE) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index, void dumpStatsLocked(const Vector<String16>& args, size_t& index,