SurfaceFlinger::~SurfaceFlinger()
{
- glDeleteTextures(1, &mWormholeTexName);
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(display);
}
} pack565;
- const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
- const uint16_t g1 = pack565(0x17,0x2f,0x17);
- const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };
- glGenTextures(1, &mWormholeTexName);
- glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
- GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);
-
const uint16_t protTexData[] = { pack565(0x03, 0x03, 0x03) };
glGenTextures(1, &mProtectedTexName);
glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
uint32_t transactionFlags = peekTransactionFlags(mask);
if (transactionFlags) {
- Region dirtyRegion;
- dirtyRegion = handleTransaction(transactionFlags);
- // XXX: dirtyRegion should be per screen
- mDirtyRegion |= dirtyRegion;
+ handleTransaction(transactionFlags);
}
}
void SurfaceFlinger::handleMessageInvalidate() {
- Region dirtyRegion;
- dirtyRegion = handlePageFlip();
- // XXX: dirtyRegion should be per screen
- mDirtyRegion |= dirtyRegion;
+ handlePageFlip();
}
void SurfaceFlinger::handleMessageRefresh() {
handleRefresh();
if (mVisibleRegionsDirty) {
- Region opaqueRegion;
- Region dirtyRegion;
- const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
- computeVisibleRegions(currentLayers, dirtyRegion, opaqueRegion);
- mDirtyRegion.orSelf(dirtyRegion);
+ mVisibleRegionsDirty = false;
+ invalidateHwcGeometry();
/*
* rebuild the visible layer list per screen
*/
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
// TODO: iterate through all displays
- DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(0)));
+ {
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(0)));
- Vector< sp<LayerBase> > layersSortedByZ;
- const size_t count = currentLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- if (!currentLayers[i]->visibleRegion.isEmpty()) {
- // TODO: also check that this layer is associated to this display
- layersSortedByZ.add(currentLayers[i]);
+ Region opaqueRegion;
+ Region dirtyRegion;
+ computeVisibleRegions(currentLayers,
+ hw.getLayerStack(), dirtyRegion, opaqueRegion);
+ hw.dirtyRegion.orSelf(dirtyRegion);
+
+ Vector< sp<LayerBase> > layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const Layer::State& s(currentLayers[i]->drawingState());
+ if (s.layerStack == hw.getLayerStack()) {
+ if (!currentLayers[i]->visibleRegion.isEmpty()) {
+ layersSortedByZ.add(currentLayers[i]);
+ }
+ }
}
+ hw.setVisibleLayersSortedByZ(layersSortedByZ);
+ hw.undefinedRegion.set(hw.getBounds());
+ hw.undefinedRegion.subtractSelf(hw.getTransform().transform(opaqueRegion));
}
- hw.setVisibleLayersSortedByZ(layersSortedByZ);
-
-
- // FIXME: mWormholeRegion needs to be calculated per screen
- //const DisplayHardware& hw(getDefaultDisplayHardware()); // XXX: we can't keep that here
- mWormholeRegion = Region(hw.getBounds()).subtract(
- hw.getTransform().transform(opaqueRegion) );
- mVisibleRegionsDirty = false;
- invalidateHwcGeometry();
}
-
- // XXX: dirtyRegion should be per screen, we should check all of them
- if (mDirtyRegion.isEmpty()) {
- return;
- }
+ const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
// TODO: iterate through all displays
- const DisplayHardware& hw(getDisplayHardware(0));
-
- // XXX: dirtyRegion should be per screen
- // transform the dirty region into this screen's coordinate space
- const Transform& planeTransform(hw.getTransform());
- mDirtyRegion = planeTransform.transform(mDirtyRegion);
- mDirtyRegion.orSelf(getAndClearInvalidateRegion());
- mDirtyRegion.andSelf(hw.bounds());
+ for (int dpy=0 ; dpy<1 ; dpy++) {
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(0)));
+ if (hw.dirtyRegion.isEmpty()) {
+ continue;
+ }
+ // transform the dirty region into this screen's coordinate space
+ const Transform& planeTransform(hw.getTransform());
+ Region dirtyRegion;
+ if (repaintEverything) {
+ dirtyRegion = planeTransform.transform(hw.dirtyRegion);
+ dirtyRegion.andSelf(hw.bounds());
+ } else {
+ dirtyRegion.set(hw.bounds());
+ }
+ hw.dirtyRegion.clear();
- if (CC_UNLIKELY(mHwWorkListDirty)) {
// build the h/w work list
- handleWorkList(hw);
- }
+ if (CC_UNLIKELY(mHwWorkListDirty)) {
+ handleWorkList(hw);
+ }
- if (CC_LIKELY(hw.canDraw())) {
- // repaint the framebuffer (if needed)
- handleRepaint(hw);
- // inform the h/w that we're done compositing
- hw.compositionComplete();
- postFramebuffer();
- } else {
- // pretend we did the post
- hw.compositionComplete();
+ if (CC_LIKELY(hw.canDraw())) {
+ // repaint the framebuffer (if needed)
+ handleRepaint(hw, dirtyRegion);
+ // inform the h/w that we're done compositing
+ hw.compositionComplete();
+ postFramebuffer();
+ } else {
+ // pretend we did the post
+ hw.compositionComplete();
+ }
}
+
+#if 0
// render to the external display if we have one
EGLSurface externalDisplaySurface = getExternalDisplaySurface();
if (externalDisplaySurface != EGL_NO_SURFACE) {
ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
}
+#endif
}
}
}
- hw.flip(mSwapRegion);
+ hw.flip(hw.swapRegion);
+ hw.swapRegion.clear();
if (hwc.initCheck() == NO_ERROR) {
hwc.commit(mEGLDisplay, hw.getEGLSurface());
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
- mSwapRegion.clear();
}
-Region SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
+void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
- Region dirtyRegion;
-
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
mDebugInTransaction = now;
const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
transactionFlags = getTransactionFlags(mask);
- dirtyRegion = handleTransactionLocked(transactionFlags);
+ handleTransactionLocked(transactionFlags);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
-
- return dirtyRegion;
}
-Region SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
+void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
- Region dirtyRegion;
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size();
// the orientation has changed, recompute all visible regions
// and invalidate everything.
- const int dpy = 0; // TODO: should be a parameter
+ const int dpy = 0; // FIXME: should be a parameter
DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(dpy)));
hw.setOrientation(mCurrentState.orientation);
+ hw.dirtyRegion.set(hw.bounds());
- // FIXME: mVisibleRegionsDirty & mDirtyRegion should this be per DisplayHardware?
mVisibleRegionsDirty = true;
- mDirtyRegion.set(hw.bounds());
}
if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
const size_t count = previousLayers.size();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(previousLayers[i]);
- if (currentLayers.indexOf( layer ) < 0) {
+ if (currentLayers.indexOf(layer) < 0) {
// this layer is not visible anymore
- // TODO: we could traverse the tree from front to back and compute the actual visible region
+ // TODO: we could traverse the tree from front to back and
+ // compute the actual visible region
// TODO: we could cache the transformed region
Layer::State front(layer->drawingState());
Region visibleReg = front.transform.transform(
Region(Rect(front.active.w, front.active.h)));
- dirtyRegion.orSelf(visibleReg);
+ invalidateLayerStack(front.layerStack, visibleReg);
}
}
}
}
commitTransaction();
- return dirtyRegion;
}
void SurfaceFlinger::commitTransaction()
}
void SurfaceFlinger::computeVisibleRegions(
- const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
+ const LayerVector& currentLayers, uint32_t layerStack,
+ Region& outDirtyRegion, Region& outOpaqueRegion)
{
ATRACE_CALL();
Region aboveCoveredLayers;
Region dirty;
- dirtyRegion.clear();
+ outDirtyRegion.clear();
size_t i = currentLayers.size();
while (i--) {
// start with the whole surface at its current location
const Layer::State& s(layer->drawingState());
+ // only consider the layers on the given later stack
+ if (s.layerStack != layerStack)
+ continue;
+
/*
* opaqueRegion: area of a surface that is fully opaque.
*/
dirty.subtractSelf(aboveOpaqueLayers);
// accumulate to the screen dirty region
- dirtyRegion.orSelf(dirty);
+ outDirtyRegion.orSelf(dirty);
// Update aboveOpaqueLayers for next (lower) layer
aboveOpaqueLayers.orSelf(opaqueRegion);
layer->setCoveredRegion(coveredRegion);
}
- opaqueRegion = aboveOpaqueLayers;
+ outOpaqueRegion = aboveOpaqueLayers;
}
-Region SurfaceFlinger::handlePageFlip()
+void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
+ const Region& dirty) {
+ // FIXME: update the dirty region of all displays
+ // presenting this layer's layer stack.
+ DisplayHardware& hw(const_cast<DisplayHardware&>(getDisplayHardware(0)));
+ hw.dirtyRegion.orSelf(dirty);
+}
+
+void SurfaceFlinger::handlePageFlip()
{
ATRACE_CALL();
Region dirtyRegion;
sp<LayerBase> const* layers = currentLayers.array();
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(layers[i]);
- dirtyRegion.orSelf( layer->latchBuffer(visibleRegions) );
+ const Region dirty(layer->latchBuffer(visibleRegions));
+ Layer::State s(layer->drawingState());
+ invalidateLayerStack(s.layerStack, dirty);
}
mVisibleRegionsDirty |= visibleRegions;
-
- return dirtyRegion;
}
void SurfaceFlinger::invalidateHwcGeometry()
}
}
-void SurfaceFlinger::handleRepaint(const DisplayHardware& hw)
+void SurfaceFlinger::handleRepaint(const DisplayHardware& hw,
+ const Region& inDirtyRegion)
{
ATRACE_CALL();
+ Region dirtyRegion(inDirtyRegion);
+
// compute the invalid region
- mSwapRegion.orSelf(mDirtyRegion);
+ hw.swapRegion.orSelf(dirtyRegion);
if (CC_UNLIKELY(mDebugRegion)) {
- debugFlashRegions(hw);
+ debugFlashRegions(hw, dirtyRegion);
}
// set the frame buffer
// we can redraw only what's dirty, but since SWAP_RECTANGLE only
// takes a rectangle, we must make sure to update that whole
// rectangle in that case
- mDirtyRegion.set(mSwapRegion.bounds());
+ dirtyRegion.set(hw.swapRegion.bounds());
} else {
if (flags & DisplayHardware::PARTIAL_UPDATES) {
// We need to redraw the rectangle that will be updated
// (pushed to the framebuffer).
// This is needed because PARTIAL_UPDATES only takes one
// rectangle instead of a region (see DisplayHardware::flip())
- mDirtyRegion.set(mSwapRegion.bounds());
+ dirtyRegion.set(hw.swapRegion.bounds());
} else {
// we need to redraw everything (the whole screen)
- mDirtyRegion.set(hw.bounds());
- mSwapRegion = mDirtyRegion;
+ dirtyRegion.set(hw.bounds());
+ hw.swapRegion = dirtyRegion;
}
}
setupHardwareComposer(hw);
- composeSurfaces(hw, mDirtyRegion);
+ composeSurfaces(hw, dirtyRegion);
// update the swap region and clear the dirty region
- mSwapRegion.orSelf(mDirtyRegion);
- mDirtyRegion.clear();
+ hw.swapRegion.orSelf(dirtyRegion);
}
void SurfaceFlinger::setupHardwareComposer(const DisplayHardware& hw)
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
} else {
+ const Region region(hw.undefinedRegion.intersect(dirty));
// screen is already cleared here
- if (!mWormholeRegion.isEmpty()) {
+ if (!region.isEmpty()) {
// can happen with SurfaceView
- drawWormhole();
+ drawWormhole(region);
}
}
}
}
-void SurfaceFlinger::debugFlashRegions(const DisplayHardware& hw)
+void SurfaceFlinger::debugFlashRegions(const DisplayHardware& hw,
+ const Region& dirtyRegion)
{
const uint32_t flags = hw.getFlags();
const int32_t height = hw.getHeight();
- if (mSwapRegion.isEmpty()) {
+ if (hw.swapRegion.isEmpty()) {
return;
}
if (!(flags & DisplayHardware::SWAP_RECTANGLE)) {
const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
- mDirtyRegion.bounds() : hw.bounds());
+ dirtyRegion.bounds() : hw.bounds());
composeSurfaces(hw, repaint);
}
glColor4f(1, 1, 0, 1);
}
- Region::const_iterator it = mDirtyRegion.begin();
- Region::const_iterator const end = mDirtyRegion.end();
+ Region::const_iterator it = dirtyRegion.begin();
+ Region::const_iterator const end = dirtyRegion.end();
while (it != end) {
const Rect& r = *it++;
GLfloat vertices[][2] = {
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
- hw.flip(mSwapRegion);
+ hw.flip(hw.swapRegion);
if (mDebugRegion > 1)
usleep(mDebugRegion * 1000);
}
-void SurfaceFlinger::drawWormhole() const
+void SurfaceFlinger::drawWormhole(const Region& region) const
{
- const Region region(mWormholeRegion.intersect(mDirtyRegion));
- if (region.isEmpty())
- return;
-
glDisable(GL_TEXTURE_EXTERNAL_OES);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
result.append(buffer);
- mWormholeRegion.dump(result, "WormholeRegion");
+ hw.undefinedRegion.dump(result, "undefinedRegion");
snprintf(buffer, SIZE,
" orientation=%d, canDraw=%d\n",
mCurrentState.orientation, hw.canDraw());
}
void SurfaceFlinger::repaintEverything() {
- const DisplayHardware& hw(getDefaultDisplayHardware()); // FIXME: this cannot be bound the default display
- const Rect bounds(hw.getBounds());
- setInvalidateRegion(Region(bounds));
+ android_atomic_or(1, &mRepaintEverything);
signalTransaction();
}
-void SurfaceFlinger::setInvalidateRegion(const Region& reg) {
- Mutex::Autolock _l(mInvalidateLock);
- mInvalidateRegion = reg;
-}
-
-Region SurfaceFlinger::getAndClearInvalidateRegion() {
- Mutex::Autolock _l(mInvalidateLock);
- Region reg(mInvalidateRegion);
- mInvalidateRegion.clear();
- return reg;
-}
-
// ---------------------------------------------------------------------------
status_t SurfaceFlinger::renderScreenToTexture(DisplayID dpy,
}
// make sure to redraw the whole screen when the animation is done
- mDirtyRegion.set(hw.bounds());
+ hw.dirtyRegion.set(hw.bounds());
signalTransaction();
return NO_ERROR;
void handleMessageInvalidate();
void handleMessageRefresh();
- Region handleTransaction(uint32_t transactionFlags);
- Region handleTransactionLocked(uint32_t transactionFlags);
+ void handleTransaction(uint32_t transactionFlags);
+ void handleTransactionLocked(uint32_t transactionFlags);
/* handlePageFilp: this is were we latch a new buffer
* if available and compute the dirty region.
- * The return value is the dirty region expressed in the
- * window manager's coordinate space (or the layer's state
- * space, which is the same thing), in particular the dirty
- * region is independent from a specific display's orientation.
*/
- Region handlePageFlip();
+ void handlePageFlip();
void handleRefresh();
void handleWorkList(const DisplayHardware& hw);
- void handleRepaint(const DisplayHardware& hw);
+ void handleRepaint(const DisplayHardware& hw, const Region& dirtyRegion);
/* ------------------------------------------------------------------------
* Transactions
uint32_t getMaxViewportDims() const;
/* ------------------------------------------------------------------------
- * Display management
+ * Display and layer stack management
*/
const DisplayHardware& getDisplayHardware(DisplayID dpy) const {
return *mDisplayHardwares[dpy];
}
+ // mark a region of a layer stack dirty. this updates the dirty
+ // region of all screens presenting this layer stack.
+ void invalidateLayerStack(uint32_t layerStack, const Region& dirty);
+
/* ------------------------------------------------------------------------
* H/W composer
*/
*/
void invalidateHwcGeometry();
void computeVisibleRegions(const LayerVector& currentLayers,
- Region& dirtyRegion, Region& wormholeRegion);
+ uint32_t layerStack,
+ Region& dirtyRegion, Region& opaqueRegion);
void postFramebuffer();
void setupHardwareComposer(const DisplayHardware& hw);
void composeSurfaces(const DisplayHardware& hw, const Region& dirty);
- void setInvalidateRegion(const Region& reg);
- Region getAndClearInvalidateRegion();
- void drawWormhole() const;
+ void drawWormhole(const Region& region) const;
GLuint getProtectedTexName() const {
return mProtectedTexName;
}
/* ------------------------------------------------------------------------
* Debugging & dumpsys
*/
- void debugFlashRegions(const DisplayHardware& hw);
+ void debugFlashRegions(const DisplayHardware& 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,
bool mLayersRemoved;
// access must be protected by mInvalidateLock
- mutable Mutex mInvalidateLock;
- Region mInvalidateRegion;
+ volatile int32_t mRepaintEverything;
// constant members (no synchronization needed for access)
HWComposer* mHwc;
- GLuint mWormholeTexName;
GLuint mProtectedTexName;
nsecs_t mBootTime;
sp<EventThread> mEventThread;
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState;
- Region mDirtyRegion;
- Region mDirtyRegionRemovedLayer;
- Region mSwapRegion;
- Region mWormholeRegion;
bool mVisibleRegionsDirty;
bool mHwWorkListDirty;
int32_t mElectronBeamAnimationMode;