diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 1044 |
1 files changed, 589 insertions, 455 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 055bfe4..ef0d521 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -39,7 +39,8 @@ #include <gui/BufferQueue.h> #include <gui/GuiConfig.h> #include <gui/IDisplayEventConnection.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/Surface.h> +#include <gui/GraphicBufferAlloc.h> #include <ui/GraphicBufferAllocator.h> #include <ui/PixelFormat.h> @@ -52,6 +53,7 @@ #include <utils/Trace.h> #include <private/android_filesystem_config.h> +#include <private/gui/SyncFeatures.h> #include "clz.h" #include "DdmConnection.h" @@ -61,18 +63,16 @@ #include "GLExtensions.h" #include "Layer.h" #include "LayerDim.h" -#include "LayerScreenshot.h" #include "SurfaceFlinger.h" #include "DisplayHardware/FramebufferSurface.h" -#include "DisplayHardware/GraphicBufferAlloc.h" #include "DisplayHardware/HWComposer.h" - - -#define EGL_VERSION_HW_ANDROID 0x3143 +#include "DisplayHardware/VirtualDisplaySurface.h" #define DISPLAY_COUNT 1 +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + namespace android { // --------------------------------------------------------------------------- @@ -93,6 +93,7 @@ SurfaceFlinger::SurfaceFlinger() mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), + mAnimCompositionPending(false), mDebugRegion(0), mDebugDDMS(0), mDebugDisableHWC(0), @@ -108,6 +109,9 @@ SurfaceFlinger::SurfaceFlinger() // debugging stuff... char value[PROPERTY_VALUE_MAX]; + property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); + mGpuToCpuSupported = !atoi(value); + property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); @@ -488,6 +492,10 @@ status_t SurfaceFlinger::readyToRun() mEGLConfig = selectEGLConfig(mEGLDisplay, format); mEGLContext = createGLContext(mEGLDisplay, mEGLConfig); + // figure out which format we got + eglGetConfigAttrib(mEGLDisplay, mEGLConfig, + EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId); + LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); @@ -501,11 +509,10 @@ status_t SurfaceFlinger::readyToRun() createBuiltinDisplayLocked(type); wp<IBinder> token = mBuiltinDisplays[i]; - sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i); - sp<SurfaceTextureClient> stc = new SurfaceTextureClient( - static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue())); sp<DisplayDevice> hw = new DisplayDevice(this, - type, isSecure, token, stc, fbs, mEGLConfig); + type, allocateHwcDisplayId(type), isSecure, token, + new FramebufferSurface(*mHwc, i), + mEGLConfig); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests // for displays other than the main display, so we always @@ -571,44 +578,10 @@ uint32_t SurfaceFlinger::getMaxViewportDims() const { // ---------------------------------------------------------------------------- bool SurfaceFlinger::authenticateSurfaceTexture( - const sp<ISurfaceTexture>& surfaceTexture) const { + const sp<IGraphicBufferProducer>& bufferProducer) const { Mutex::Autolock _l(mStateLock); - sp<IBinder> surfaceTextureBinder(surfaceTexture->asBinder()); - - // Check the visible layer list for the ISurface - const LayerVector& currentLayers = mCurrentState.layersSortedByZ; - size_t count = currentLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); - sp<LayerBaseClient> lbc(layer->getLayerBaseClient()); - if (lbc != NULL) { - wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder(); - if (lbcBinder == surfaceTextureBinder) { - return true; - } - } - } - - // Check the layers in the purgatory. This check is here so that if a - // SurfaceTexture gets destroyed before all the clients are done using it, - // the error will not be reported as "surface XYZ is not authenticated", but - // will instead fail later on when the client tries to use the surface, - // which should be reported as "surface XYZ returned an -ENODEV". The - // purgatorized layers are no less authentic than the visible ones, so this - // should not cause any harm. - size_t purgatorySize = mLayerPurgatory.size(); - for (size_t i=0 ; i<purgatorySize ; i++) { - const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i)); - sp<LayerBaseClient> lbc(layer->getLayerBaseClient()); - if (lbc != NULL) { - wp<IBinder> lbcBinder = lbc->getSurfaceTextureBinder(); - if (lbcBinder == surfaceTextureBinder) { - return true; - } - } - } - - return false; + sp<IBinder> surfaceTextureBinder(bufferProducer->asBinder()); + return mGraphicBufferProducerList.indexOf(surfaceTextureBinder) >= 0; } status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) { @@ -771,6 +744,9 @@ void SurfaceFlinger::eventControl(int disp, int event, int enabled) { void SurfaceFlinger::onMessageReceived(int32_t what) { ATRACE_CALL(); switch (what) { + case MessageQueue::TRANSACTION: + handleMessageTransaction(); + break; case MessageQueue::INVALIDATE: handleMessageTransaction(); handleMessageInvalidate(); @@ -831,10 +807,10 @@ void SurfaceFlinger::doDebugFlashRegions() 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 } + { (GLfloat) r.left, (GLfloat) (height - r.top) }, + { (GLfloat) r.left, (GLfloat) (height - r.bottom) }, + { (GLfloat) r.right, (GLfloat) (height - r.bottom) }, + { (GLfloat) r.right, (GLfloat) (height - r.top) } }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -880,6 +856,22 @@ void SurfaceFlinger::postComposition() for (size_t i=0 ; i<count ; i++) { currentLayers[i]->onPostComposition(); } + + if (mAnimCompositionPending) { + mAnimCompositionPending = false; + + const HWComposer& hwc = getHwComposer(); + sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY); + if (presentFence->isValid()) { + mAnimFrameTracker.setActualPresentFence(presentFence); + } else { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY); + mAnimFrameTracker.setActualPresentTime(presentTime); + } + mAnimFrameTracker.advanceFrame(); + } } void SurfaceFlinger::rebuildLayerStacks() { @@ -893,7 +885,7 @@ void SurfaceFlinger::rebuildLayerStacks() { for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) { Region opaqueRegion; Region dirtyRegion; - Vector< sp<LayerBase> > layersSortedByZ; + Vector< sp<Layer> > layersSortedByZ; const sp<DisplayDevice>& hw(mDisplays[dpy]); const Transform& tr(hw->getTransform()); const Rect bounds(hw->getBounds()); @@ -903,7 +895,7 @@ void SurfaceFlinger::rebuildLayerStacks() { const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); const Layer::State& s(layer->drawingState()); if (s.layerStack == hw->getLayerStack()) { Region drawRegion(tr.transform( @@ -933,14 +925,14 @@ void SurfaceFlinger::setUpHWComposer() { sp<const DisplayDevice> hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { - const Vector< sp<LayerBase> >& currentLayers( + const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); if (hwc.createWorkList(id, count) == NO_ERROR) { 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]); + const sp<Layer>& layer(currentLayers[i]); layer->setGeometry(hw, *cur); if (mDebugDisableHWC || mDebugRegion) { cur->setSkip(true); @@ -956,7 +948,7 @@ void SurfaceFlinger::setUpHWComposer() { sp<const DisplayDevice> hw(mDisplays[dpy]); const int32_t id = hw->getHwcDisplayId(); if (id >= 0) { - const Vector< sp<LayerBase> >& currentLayers( + const Vector< sp<Layer> >& currentLayers( hw->getVisibleLayersSortedByZ()); const size_t count = currentLayers.size(); HWComposer::LayerListIterator cur = hwc.begin(id); @@ -966,7 +958,7 @@ void SurfaceFlinger::setUpHWComposer() { * update the per-frame h/w composer data for each layer * and build the transparent region of the FB */ - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); layer->setPerFrameData(hw, *cur); } } @@ -1020,7 +1012,7 @@ void SurfaceFlinger::postFramebuffer() 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<Layer> >& currentLayers(hw->getVisibleLayersSortedByZ()); hw->onSwapBuffersCompleted(hwc); const size_t count = currentLayers.size(); int32_t id = hw->getHwcDisplayId(); @@ -1076,7 +1068,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (transactionFlags & eTraversalNeeded) { for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); if (!trFlags) continue; @@ -1113,11 +1105,14 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // Call makeCurrent() on the primary display so we can // be sure that nothing associated with this display // is current. - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); - DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext); + const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice()); + DisplayDevice::makeCurrent(mEGLDisplay, defaultDisplay, mEGLContext); + sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i))); + if (hw != NULL) + hw->disconnect(getHwComposer()); + if (draw[i].type < DisplayDevice::NUM_DISPLAY_TYPES) + mEventThread->onHotplugReceived(draw[i].type, false); mDisplays.removeItem(draw.keyAt(i)); - getHwComposer().disconnectDisplay(draw[i].type); - mEventThread->onHotplugReceived(draw[i].type, false); } else { ALOGW("trying to remove the main display"); } @@ -1130,6 +1125,9 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // recreating the DisplayDevice, so we just remove it // from the drawing state, so that it get re-added // below. + sp<DisplayDevice> hw(getDisplayDevice(display)); + if (hw != NULL) + hw->disconnect(getHwComposer()); mDisplays.removeItem(display); mDrawingState.displays.removeItemsAt(i); dc--; i--; @@ -1159,38 +1157,48 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (draw.indexOfKey(curr.keyAt(i)) < 0) { const DisplayDeviceState& state(curr[i]); - sp<FramebufferSurface> fbs; - sp<SurfaceTextureClient> stc; - if (!state.isVirtualDisplay()) { - + sp<DisplaySurface> dispSurface; + int32_t hwcDisplayId = -1; + if (state.isVirtualDisplay()) { + // Virtual displays without a surface are dormant: + // they have external state (layer stack, projection, + // etc.) but no internal state (i.e. a DisplayDevice). + if (state.surface != NULL) { + hwcDisplayId = allocateHwcDisplayId(state.type); + dispSurface = new VirtualDisplaySurface( + *mHwc, hwcDisplayId, state.surface, + state.displayName); + } + } else { ALOGE_IF(state.surface!=NULL, "adding a supported display, but rendering " "surface is provided (%p), ignoring it", state.surface.get()); - + hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface - fbs = new FramebufferSurface(*mHwc, state.type); - stc = new SurfaceTextureClient( - static_cast< sp<ISurfaceTexture> >( - fbs->getBufferQueue())); - } else { - if (state.surface != NULL) { - stc = new SurfaceTextureClient(state.surface); - } + dispSurface = new FramebufferSurface(*mHwc, state.type); } const wp<IBinder>& display(curr.keyAt(i)); - if (stc != NULL) { + if (dispSurface != NULL) { sp<DisplayDevice> hw = new DisplayDevice(this, - state.type, state.isSecure, display, stc, fbs, - mEGLConfig); + state.type, hwcDisplayId, state.isSecure, + display, dispSurface, mEGLConfig); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); hw->setDisplayName(state.displayName); mDisplays.add(display, hw); - mEventThread->onHotplugReceived(state.type, true); + if (state.isVirtualDisplay()) { + if (hwcDisplayId >= 0) { + mHwc->setVirtualDisplayProperties(hwcDisplayId, + hw->getWidth(), hw->getHeight(), + hw->getFormat()); + } + } else { + mEventThread->onHotplugReceived(state.type, true); + } } } } @@ -1223,8 +1231,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) // NOTE: we rely on the fact that layers are sorted by // layerStack first (so we don't have to traverse the list // of displays for every layer). - const sp<LayerBase>& layerBase(currentLayers[i]); - uint32_t layerStack = layerBase->drawingState().layerStack; + const sp<Layer>& layer(currentLayers[i]); + uint32_t layerStack = layer->drawingState().layerStack; if (i==0 || currentlayerStack != layerStack) { currentlayerStack = layerStack; // figure out if this layerstack is mirrored @@ -1237,17 +1245,22 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) if (disp == NULL) { disp = hw; } else { - disp = getDefaultDisplayDevice(); + disp = NULL; break; } } } } - if (disp != NULL) { - // presumably this means this layer is using a layerStack - // that is not visible on any display - layerBase->updateTransformHint(disp); + if (disp == NULL) { + // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to + // redraw after transform hint changes. See bug 8508397. + + // could be null when this layer is using a layerStack + // that is not visible on any display. Also can occur at + // screen off/on times. + disp = getDefaultDisplayDevice(); } + layer->updateTransformHint(disp); } } @@ -1269,7 +1282,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) mVisibleRegionsDirty = true; const size_t count = previousLayers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(previousLayers[i]); + const sp<Layer>& layer(previousLayers[i]); if (currentLayers.indexOf(layer) < 0) { // this layer is not visible anymore // TODO: we could traverse the tree from front to back and @@ -1296,6 +1309,10 @@ void SurfaceFlinger::commitTransaction() mLayersPendingRemoval.clear(); } + // If this transaction is part of a window animation then the next frame + // we composite should be considered an animation as well. + mAnimCompositionPending = mAnimTransactionPending; + mDrawingState = mCurrentState; mTransactionPending = false; mAnimTransactionPending = false; @@ -1316,12 +1333,12 @@ void SurfaceFlinger::computeVisibleRegions( size_t i = currentLayers.size(); while (i--) { - const sp<LayerBase>& layer = currentLayers[i]; + const sp<Layer>& layer = currentLayers[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 + // only consider the layers on the given layer stack if (s.layerStack != layerStack) continue; @@ -1358,7 +1375,7 @@ void SurfaceFlinger::computeVisibleRegions( // handle hidden surfaces by setting the visible region to empty if (CC_LIKELY(layer->isVisible())) { const bool translucent = !layer->isOpaque(); - Rect bounds(layer->computeBounds()); + Rect bounds(s.transform.transform(layer->computeBounds())); visibleRegion.set(bounds); if (!visibleRegion.isEmpty()) { // Remove the transparent area from the visible region @@ -1367,14 +1384,14 @@ void SurfaceFlinger::computeVisibleRegions( if (tr.transformed()) { if (tr.preserveRects()) { // transform the transparent region - transparentRegion = tr.transform(s.transparentRegion); + transparentRegion = tr.transform(s.activeTransparentRegion); } else { // transformation too complex, can't do the // transparent region optimization. transparentRegion.clear(); } } else { - transparentRegion = s.transparentRegion; + transparentRegion = s.activeTransparentRegion; } } @@ -1459,7 +1476,7 @@ void SurfaceFlinger::handlePageFlip() 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]); + const sp<Layer>& layer(currentLayers[i]); const Region dirty(layer->latchBuffer(visibleRegions)); const Layer::State& s(layer->drawingState()); invalidateLayerStack(s.layerStack, dirty); @@ -1541,7 +1558,20 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); } else { - const Region region(hw->undefinedRegion.intersect(dirty)); + // we start with the whole screen area + const Region bounds(hw->getBounds()); + + // we remove the scissor part + // we're left with the letterbox region + // (common case is that letterbox ends-up being empty) + const Region letterbox(bounds.subtract(hw->getScissor())); + + // compute the area to clear + Region region(hw->undefinedRegion.merge(letterbox)); + + // but limit it to the dirty region + region.andSelf(dirty); + // screen is already cleared here if (!region.isEmpty()) { // can happen with SurfaceView @@ -1549,13 +1579,12 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const } } - if (hw->getDisplayType() >= DisplayDevice::DISPLAY_EXTERNAL) { - // TODO: just to be on the safe side, we don't set the + if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) { + // just to be on the safe side, we don't set the // scissor on the main display. It should never be needed // anyways (though in theory it could since the API allows it). const Rect& bounds(hw->getBounds()); - const Transform& tr(hw->getTransform()); - const Rect scissor(tr.transform(hw->getViewport())); + const Rect& scissor(hw->getScissor()); if (scissor != bounds) { // scissor doesn't match the screen's dimensions, so we // need to clear everything outside of it and enable @@ -1563,9 +1592,6 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const const GLint height = hw->getHeight(); glScissor(scissor.left, height - scissor.bottom, scissor.getWidth(), scissor.getHeight()); - // clear everything unscissored - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); // enable scissor for this frame glEnable(GL_SCISSOR_TEST); } @@ -1576,13 +1602,13 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const * and then, render the layers targeted at the framebuffer */ - const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); + const Vector< sp<Layer> >& layers(hw->getVisibleLayersSortedByZ()); const size_t count = layers.size(); const Transform& tr = hw->getTransform(); if (cur != end) { // we're using h/w composer for (size_t i=0 ; i<count && cur!=end ; ++i, ++cur) { - const sp<LayerBase>& layer(layers[i]); + const sp<Layer>& layer(layers[i]); const Region clip(dirty.intersect(tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { switch (cur->getCompositionType()) { @@ -1614,7 +1640,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const } else { // we're not using h/w composer for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); + const sp<Layer>& layer(layers[i]); const Region clip(dirty.intersect( tr.transform(layer->visibleRegion))); if (!clip.isEmpty()) { @@ -1641,66 +1667,43 @@ void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& hw, 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 } + { (GLfloat) r.left, (GLfloat) (height - r.top) }, + { (GLfloat) r.left, (GLfloat) (height - r.bottom) }, + { (GLfloat) r.right, (GLfloat) (height - r.bottom) }, + { (GLfloat) r.right, (GLfloat) (height - r.top) } }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } } -ssize_t SurfaceFlinger::addClientLayer(const sp<Client>& client, - const sp<LayerBaseClient>& lbc) +void SurfaceFlinger::addClientLayer(const sp<Client>& client, + const sp<IBinder>& handle, + const sp<IGraphicBufferProducer>& gbc, + const sp<Layer>& lbc) { // attach this layer to the client - size_t name = client->attachLayer(lbc); + client->attachLayer(handle, lbc); // add this layer to the current state list Mutex::Autolock _l(mStateLock); mCurrentState.layersSortedByZ.add(lbc); - - return ssize_t(name); + mGraphicBufferProducerList.add(gbc->asBinder()); } -status_t SurfaceFlinger::removeLayer(const sp<LayerBase>& layer) +status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { Mutex::Autolock _l(mStateLock); - status_t err = purgatorizeLayer_l(layer); - if (err == NO_ERROR) - setTransactionFlags(eTransactionNeeded); - return err; -} - -status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) -{ - ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); + ssize_t index = mCurrentState.layersSortedByZ.remove(layer); if (index >= 0) { + mLayersPendingRemoval.push(layer); mLayersRemoved = true; + setTransactionFlags(eTransactionNeeded); return NO_ERROR; } return status_t(index); } -status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) -{ - // First add the layer to the purgatory list, which makes sure it won't - // go away, then remove it from the main list (through a transaction). - ssize_t err = removeLayer_l(layerBase); - if (err >= 0) { - mLayerPurgatory.add(layerBase); - } - - mLayersPendingRemoval.push(layerBase); - - // it's possible that we don't find a layer, because it might - // have been destroyed already -- this is not technically an error - // from the user because there is a race between Client::destroySurface(), - // ~Client() and ~ISurface(). - return (err == NAME_NOT_FOUND) ? status_t(NO_ERROR) : err; -} - uint32_t SurfaceFlinger::peekTransactionFlags(uint32_t flags) { return android_atomic_release_load(&mTransactionFlags); @@ -1843,7 +1846,7 @@ uint32_t SurfaceFlinger::setClientStateLocked( const layer_state_t& s) { uint32_t flags = 0; - sp<LayerBaseClient> layer(client->getLayerUser(s.surface)); + sp<Layer> layer(client->getLayerUser(s.surface)); if (layer != 0) { const uint32_t what = s.what; if (what & layer_state_t::ePositionChanged) { @@ -1901,55 +1904,49 @@ uint32_t SurfaceFlinger::setClientStateLocked( return flags; } -sp<ISurface> SurfaceFlinger::createLayer( - ISurfaceComposerClient::surface_data_t* params, +status_t SurfaceFlinger::createLayer( const String8& name, const sp<Client>& client, - uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags) + uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp) { - sp<LayerBaseClient> layer; - sp<ISurface> surfaceHandle; - + //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); if (int32_t(w|h) < 0) { ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)", int(w), int(h)); - return surfaceHandle; + return BAD_VALUE; } - //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string()); + status_t result = NO_ERROR; + + sp<Layer> layer; + switch (flags & ISurfaceComposerClient::eFXSurfaceMask) { case ISurfaceComposerClient::eFXSurfaceNormal: - layer = createNormalLayer(client, w, h, flags, format); + result = createNormalLayer(client, + name, w, h, flags, format, + handle, gbp, &layer); break; - case ISurfaceComposerClient::eFXSurfaceBlur: case ISurfaceComposerClient::eFXSurfaceDim: - layer = createDimLayer(client, w, h, flags); + result = createDimLayer(client, + name, w, h, flags, + handle, gbp, &layer); break; - case ISurfaceComposerClient::eFXSurfaceScreenshot: - layer = createScreenshotLayer(client, w, h, flags); + default: + result = BAD_VALUE; break; } - if (layer != 0) { - layer->initStates(w, h, flags); - layer->setName(name); - ssize_t token = addClientLayer(client, layer); - surfaceHandle = layer->getSurface(); - if (surfaceHandle != 0) { - params->token = token; - params->identity = layer->getIdentity(); - } + if (result == NO_ERROR) { + addClientLayer(client, *handle, *gbp, layer); setTransactionFlags(eTransactionNeeded); } - - return surfaceHandle; + return result; } -sp<Layer> SurfaceFlinger::createNormalLayer( - const sp<Client>& client, - uint32_t w, uint32_t h, uint32_t flags, - PixelFormat& format) +status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { // initialize the surfaces switch (format) { @@ -1971,71 +1968,48 @@ sp<Layer> SurfaceFlinger::createNormalLayer( format = PIXEL_FORMAT_RGBA_8888; #endif - sp<Layer> layer = new Layer(this, client); - status_t err = layer->setBuffers(w, h, format, flags); - if (CC_LIKELY(err != NO_ERROR)) { - ALOGE("createNormalLayer() failed (%s)", strerror(-err)); - layer.clear(); + *outLayer = new Layer(this, client, name, w, h, flags); + status_t err = (*outLayer)->setBuffers(w, h, format, flags); + if (err == NO_ERROR) { + *handle = (*outLayer)->getHandle(); + *gbp = (*outLayer)->getBufferQueue(); } - return layer; -} -sp<LayerDim> SurfaceFlinger::createDimLayer( - const sp<Client>& client, - uint32_t w, uint32_t h, uint32_t flags) -{ - sp<LayerDim> layer = new LayerDim(this, client); - return layer; + ALOGE_IF(err, "createNormalLayer() failed (%s)", strerror(-err)); + return err; } -sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer( - const sp<Client>& client, - uint32_t w, uint32_t h, uint32_t flags) +status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, + sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer) { - sp<LayerScreenshot> layer = new LayerScreenshot(this, client); - return layer; + *outLayer = new LayerDim(this, client, name, w, h, flags); + *handle = (*outLayer)->getHandle(); + *gbp = (*outLayer)->getBufferQueue(); + return NO_ERROR; } -status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, SurfaceID sid) +status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle) { - /* - * called by the window manager, when a surface should be marked for - * destruction. - * - * The surface is removed from the current and drawing lists, but placed - * in the purgatory queue, so it's not destroyed right-away (we need - * to wait for all client's references to go away first). - */ - - status_t err = NAME_NOT_FOUND; - Mutex::Autolock _l(mStateLock); - sp<LayerBaseClient> layer = client->getLayerUser(sid); - - if (layer != 0) { - err = purgatorizeLayer_l(layer); - if (err == NO_ERROR) { - setTransactionFlags(eTransactionNeeded); - } + // called by the window manager when it wants to remove a Layer + status_t err = NO_ERROR; + sp<Layer> l(client->getLayerUser(handle)); + if (l != NULL) { + err = removeLayer(l); + ALOGE_IF(err<0 && err != NAME_NOT_FOUND, + "error removing layer=%p (%s)", l.get(), strerror(-err)); } return err; } -status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer) +status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer) { - // called by ~ISurface() when all references are gone + // called by ~LayerCleaner() when all references to the IBinder (handle) + // are gone status_t err = NO_ERROR; - sp<LayerBaseClient> l(layer.promote()); + sp<Layer> l(layer.promote()); if (l != NULL) { - Mutex::Autolock _l(mStateLock); - err = removeLayer_l(l); - if (err == NAME_NOT_FOUND) { - // The surface wasn't in the current list, which means it was - // removed already, which means it is in the purgatory, - // and need to be removed from there. - ssize_t idx = mLayerPurgatory.remove(l); - ALOGE_IF(idx < 0, - "layer=%p is not in the purgatory list", l.get()); - } + err = removeLayer(l); ALOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); } @@ -2045,12 +2019,14 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<LayerBaseClient>& layer) // --------------------------------------------------------------------------- void SurfaceFlinger::onInitializeDisplays() { - // reset screen orientation + // reset screen orientation and use primary layer stack Vector<ComposerState> state; Vector<DisplayState> displays; DisplayState d; - d.what = DisplayState::eDisplayProjectionChanged; + d.what = DisplayState::eDisplayProjectionChanged | + DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; + d.layerStack = 0; d.orientation = DisplayState::eOrientationDefault; d.frame.makeInvalid(); d.viewport.makeInvalid(); @@ -2173,11 +2149,14 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) char buffer[SIZE]; String8 result; - if (!PermissionCache::checkCallingPermission(sDump)) { + + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission(sDump, pid, uid)) { snprintf(buffer, SIZE, "Permission Denial: " - "can't dump SurfaceFlinger from pid=%d, uid=%d\n", - IPCThreadState::self()->getCallingPid(), - IPCThreadState::self()->getCallingUid()); + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); result.append(buffer); } else { // Try to get the main lock, but don't insist if we can't @@ -2239,7 +2218,7 @@ void SurfaceFlinger::listLayersLocked(const Vector<String16>& args, size_t& inde const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); snprintf(buffer, SIZE, "%s\n", layer->getName().string()); result.append(buffer); } @@ -2254,22 +2233,26 @@ void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index index++; } - const LayerVector& currentLayers = mCurrentState.layersSortedByZ; - const size_t count = currentLayers.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); - if (name.isEmpty()) { - snprintf(buffer, SIZE, "%s\n", layer->getName().string()); - result.append(buffer); - } - if (name.isEmpty() || (name == layer->getName())) { - layer->dumpStats(result, buffer, SIZE); + const nsecs_t period = + getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); + result.appendFormat("%lld\n", period); + + if (name.isEmpty()) { + mAnimFrameTracker.dump(result); + } else { + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Layer>& layer(currentLayers[i]); + if (name == layer->getName()) { + layer->dumpStats(result, buffer, SIZE); + } } } } void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index, - String8& result, char* buffer, size_t SIZE) const + String8& result, char* buffer, size_t SIZE) { String8 name; if (index < args.size()) { @@ -2280,11 +2263,13 @@ void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& inde const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); if (name.isEmpty() || (name == layer->getName())) { layer->clearStats(); } } + + mAnimFrameTracker.clear(); } /*static*/ void SurfaceFlinger::appendSfConfigString(String8& result) @@ -2326,6 +2311,10 @@ void SurfaceFlinger::dumpAllLocked( appendGuiConfigString(result); result.append("\n"); + result.append("Sync configuration: "); + result.append(SyncFeatures::getInstance().toString()); + result.append("\n"); + /* * Dump the visible layer list */ @@ -2334,23 +2323,11 @@ void SurfaceFlinger::dumpAllLocked( snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); result.append(buffer); for (size_t i=0 ; i<count ; i++) { - const sp<LayerBase>& layer(currentLayers[i]); + const sp<Layer>& layer(currentLayers[i]); layer->dump(result, buffer, SIZE); } /* - * Dump the layers in the purgatory - */ - - const size_t purgatorySize = mLayerPurgatory.size(); - snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize); - result.append(buffer); - for (size_t i=0 ; i<purgatorySize ; i++) { - const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i)); - layer->shortDump(result, buffer, SIZE); - } - - /* * Dump Display state */ @@ -2371,17 +2348,20 @@ void SurfaceFlinger::dumpAllLocked( HWComposer& hwc(getHwComposer()); sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const GLExtensions& extensions(GLExtensions::getInstance()); + + snprintf(buffer, SIZE, "EGL implementation : %s\n", + eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION)); + result.append(buffer); + snprintf(buffer, SIZE, "%s\n", + eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS)); + result.append(buffer); + snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(), extensions.getVersion()); result.append(buffer); - - snprintf(buffer, SIZE, "EGL : %s\n", - eglQueryString(mEGLDisplay, EGL_VERSION_HW_ANDROID)); - result.append(buffer); - - snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); + snprintf(buffer, SIZE, "%s\n", extensions.getExtension()); result.append(buffer); hw->undefinedRegion.dump(result, "undefinedRegion"); @@ -2395,13 +2375,18 @@ void SurfaceFlinger::dumpAllLocked( " transaction-flags : %08x\n" " refresh-rate : %f fps\n" " x-dpi : %f\n" - " y-dpi : %f\n", + " y-dpi : %f\n" + " EGL_NATIVE_VISUAL_ID : %d\n" + " gpu_to_cpu_unsupported : %d\n" + , mLastSwapBufferTime/1000.0, mLastTransactionTime/1000.0, mTransactionFlags, 1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY), hwc.getDpiX(HWC_DISPLAY_PRIMARY), - hwc.getDpiY(HWC_DISPLAY_PRIMARY)); + hwc.getDpiY(HWC_DISPLAY_PRIMARY), + mEGLNativeVisualId, + !mGpuToCpuSupported); result.append(buffer); snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", @@ -2435,10 +2420,22 @@ void SurfaceFlinger::dumpAllLocked( alloc.dump(result); } -const Vector< sp<LayerBase> >& -SurfaceFlinger::getLayerSortedByZForHwcDisplay(int disp) { +const Vector< sp<Layer> >& +SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) { // Note: mStateLock is held here - return getDisplayDevice( getBuiltInDisplay(disp) )->getVisibleLayersSortedByZ(); + wp<IBinder> dpy; + for (size_t i=0 ; i<mDisplays.size() ; i++) { + if (mDisplays.valueAt(i)->getHwcDisplayId() == id) { + dpy = mDisplays.keyAt(i); + break; + } + } + if (dpy == NULL) { + ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id); + // Just use the primary display so we have something to return + dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY); + } + return getDisplayDevice(dpy)->getVisibleLayersSortedByZ(); } bool SurfaceFlinger::startDdmConnection() @@ -2464,6 +2461,7 @@ status_t SurfaceFlinger::onTransact( { switch (code) { case CREATE_CONNECTION: + case CREATE_DISPLAY: case SET_TRANSACTION_STATE: case BOOT_FINISHED: case BLANK: @@ -2570,101 +2568,320 @@ void SurfaceFlinger::repaintEverything() { } // --------------------------------------------------------------------------- +// Capture screen into an IGraphiBufferProducer +// --------------------------------------------------------------------------- -status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut) -{ - Mutex::Autolock _l(mStateLock); - return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut); +/* The code below is here to handle b/8734824 + * + * We create a IGraphicBufferProducer wrapper that forwards all calls + * to the calling binder thread, where they are executed. This allows + * the calling thread to be reused (on the other side) and not + * depend on having "enough" binder threads to handle the requests. + * + */ + +class GraphicProducerWrapper : public BBinder, public MessageHandler { + sp<IGraphicBufferProducer> impl; + sp<Looper> looper; + status_t result; + bool exitPending; + bool exitRequested; + mutable Barrier barrier; + volatile int32_t memoryBarrier; + uint32_t code; + Parcel const* data; + Parcel* reply; + + enum { + MSG_API_CALL, + MSG_EXIT + }; + + /* + * this is called by our "fake" BpGraphicBufferProducer. We package the + * data and reply Parcel and forward them to the calling thread. + */ + virtual status_t transact(uint32_t code, + const Parcel& data, Parcel* reply, uint32_t flags) { + this->code = code; + this->data = &data; + this->reply = reply; + android_atomic_acquire_store(0, &memoryBarrier); + if (exitPending) { + // if we've exited, we run the message synchronously right here + handleMessage(Message(MSG_API_CALL)); + } else { + barrier.close(); + looper->sendMessage(this, Message(MSG_API_CALL)); + barrier.wait(); + } + return NO_ERROR; + } + + /* + * here we run on the binder calling thread. All we've got to do is + * call the real BpGraphicBufferProducer. + */ + virtual void handleMessage(const Message& message) { + android_atomic_release_load(&memoryBarrier); + if (message.what == MSG_API_CALL) { + impl->asBinder()->transact(code, data[0], reply); + barrier.open(); + } else if (message.what == MSG_EXIT) { + exitRequested = true; + } + } + +public: + GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) : + impl(impl), looper(new Looper(true)), result(NO_ERROR), + exitPending(false), exitRequested(false) { + } + + status_t waitForResponse() { + do { + looper->pollOnce(-1); + } while (!exitRequested); + return result; + } + + void exit(status_t result) { + exitPending = true; + looper->sendMessage(this, Message(MSG_EXIT)); + } +}; + +status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool isCpuConsumer) { + + if (CC_UNLIKELY(display == 0)) + return BAD_VALUE; + + if (CC_UNLIKELY(producer == 0)) + return BAD_VALUE; + + + class MessageCaptureScreen : public MessageBase { + SurfaceFlinger* flinger; + sp<IBinder> display; + sp<IGraphicBufferProducer> producer; + uint32_t reqWidth, reqHeight; + uint32_t minLayerZ,maxLayerZ; + bool useReadPixels; + status_t result; + public: + MessageCaptureScreen(SurfaceFlinger* flinger, + const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, bool useReadPixels) + : flinger(flinger), display(display), producer(producer), + reqWidth(reqWidth), reqHeight(reqHeight), + minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), + useReadPixels(useReadPixels), + result(PERMISSION_DENIED) + { + } + status_t getResult() const { + return result; + } + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + sp<const DisplayDevice> hw(flinger->getDisplayDevice(display)); + if (!useReadPixels) { + result = flinger->captureScreenImplLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + } else { + result = flinger->captureScreenImplCpuConsumerLocked(hw, + producer, reqWidth, reqHeight, minLayerZ, maxLayerZ); + } + static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result); + return true; + } + }; + + // make sure to process transactions before screenshots -- a transaction + // might already be pending but scheduled for VSYNC; this guarantees we + // will handle it before the screenshot. When VSYNC finally arrives + // the scheduled transaction will be a no-op. If no transactions are + // scheduled at this time, this will end-up being a no-op as well. + mEventQueue.invalidateTransactionNow(); + + bool useReadPixels = false; + if (isCpuConsumer) { + bool formatSupportedBytBitmap = + (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBA_8888) || + (mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBX_8888); + if (formatSupportedBytBitmap == false) { + // the pixel format we have is not compatible with + // Bitmap.java, which is the likely client of this API, + // so we just revert to glReadPixels() in that case. + useReadPixels = true; + } + if (mGpuToCpuSupported == false) { + // When we know the GL->CPU path works, we can call + // captureScreenImplLocked() directly, instead of using the + // glReadPixels() workaround. + useReadPixels = true; + } + } + + // this creates a "fake" BBinder which will serve as a "fake" remote + // binder to receive the marshaled calls and forward them to the + // real remote (a BpGraphicBufferProducer) + sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); + + // the asInterface() call below creates our "fake" BpGraphicBufferProducer + // which does the marshaling work forwards to our "fake remote" above. + sp<MessageBase> msg = new MessageCaptureScreen(this, + display, IGraphicBufferProducer::asInterface( wrapper ), + reqWidth, reqHeight, minLayerZ, maxLayerZ, + useReadPixels); + + status_t res = postMessageAsync(msg); + if (res == NO_ERROR) { + res = wrapper->waitForResponse(); + } + return res; } -status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack, - GLuint* textureName, GLfloat* uOut, GLfloat* vOut) + +void SurfaceFlinger::renderScreenImplLocked( + const sp<const DisplayDevice>& hw, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ, + bool yswap) { ATRACE_CALL(); - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - // get screen geometry - // FIXME: figure out what it means to have a screenshot texture w/ multi-display - sp<const DisplayDevice> hw(getDefaultDisplayDevice()); const uint32_t hw_w = hw->getWidth(); const uint32_t hw_h = hw->getHeight(); - GLfloat u = 1; - GLfloat v = 1; + + const bool filtering = reqWidth != hw_w || reqWidth != hw_h; // make sure to clear all GL error flags while ( glGetError() != GL_NO_ERROR ) ; - // create a FBO - GLuint name, tname; - glGenTextures(1, &tname); - glBindTexture(GL_TEXTURE_2D, tname); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - if (glGetError() != GL_NO_ERROR) { - while ( glGetError() != GL_NO_ERROR ) ; - GLint tw = (2 << (31 - clz(hw_w))); - GLint th = (2 << (31 - clz(hw_h))); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, - tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); - u = GLfloat(hw_w) / tw; - v = GLfloat(hw_h) / th; - } - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); - - DisplayDevice::setViewportAndProjection(hw); + // set-up our viewport + glViewport(0, 0, reqWidth, reqHeight); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + if (yswap) glOrthof(0, hw_w, hw_h, 0, 0, 1); + else glOrthof(0, hw_w, 0, hw_h, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); // redraw the screen entirely... - glDisable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); + glDisable(GL_SCISSOR_TEST); glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); + glDisable(GL_TEXTURE_EXTERNAL_OES); + glDisable(GL_TEXTURE_2D); + + const LayerVector& layers( mDrawingState.layersSortedByZ ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); - layer->draw(hw); + const sp<Layer>& layer(layers[i]); + const Layer::State& state(layer->drawingState()); + if (state.layerStack == hw->getLayerStack()) { + if (state.z >= minLayerZ && state.z <= maxLayerZ) { + if (layer->isVisible()) { + if (filtering) layer->setFiltering(true); + layer->draw(hw); + if (filtering) layer->setFiltering(false); + } + } + } } + // compositionComplete is needed for older driver hw->compositionComplete(); +} - // back to main framebuffer - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteFramebuffersOES(1, &name); - *textureName = tname; - *uOut = u; - *vOut = v; +status_t SurfaceFlinger::captureScreenImplLocked( + const sp<const DisplayDevice>& hw, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ) +{ + ATRACE_CALL(); + + // get screen geometry + const uint32_t hw_w = hw->getWidth(); + const uint32_t hw_h = hw->getHeight(); + + // if we have secure windows on this display, never allow the screen capture + if (hw->getSecureLayerVisible()) { + ALOGW("FB is protected: PERMISSION_DENIED"); + return PERMISSION_DENIED; + } + + if ((reqWidth > hw_w) || (reqHeight > hw_h)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", + reqWidth, reqHeight, hw_w, hw_h); + return BAD_VALUE; + } + + reqWidth = (!reqWidth) ? hw_w : reqWidth; + reqHeight = (!reqHeight) ? hw_h : reqHeight; + + // Create a surface to render into + sp<Surface> surface = new Surface(producer); + ANativeWindow* const window = surface.get(); + + // set the buffer size to what the user requested + native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight); + + // and create the corresponding EGLSurface + EGLSurface eglSurface = eglCreateWindowSurface( + mEGLDisplay, mEGLConfig, window, NULL); + if (eglSurface == EGL_NO_SURFACE) { + ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x", + eglGetError()); + return BAD_VALUE; + } + + if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) { + ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x", + eglGetError()); + eglDestroySurface(mEGLDisplay, eglSurface); + return BAD_VALUE; + } + + renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, false); + + // and finishing things up... + if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) { + ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x", + eglGetError()); + eglDestroySurface(mEGLDisplay, eglSurface); + return BAD_VALUE; + } + + eglDestroySurface(mEGLDisplay, eglSurface); + return NO_ERROR; } -// --------------------------------------------------------------------------- -status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, - sp<IMemoryHeap>* heap, - uint32_t* w, uint32_t* h, PixelFormat* f, - uint32_t sw, uint32_t sh, +status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked( + const sp<const DisplayDevice>& hw, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ) { ATRACE_CALL(); - status_t result = PERMISSION_DENIED; - if (!GLExtensions::getInstance().haveFramebufferObject()) { return INVALID_OPERATION; } // get screen geometry - sp<const DisplayDevice> hw(getDisplayDevice(display)); const uint32_t hw_w = hw->getWidth(); const uint32_t hw_h = hw->getHeight(); @@ -2674,28 +2891,22 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, return PERMISSION_DENIED; } - if ((sw > hw_w) || (sh > hw_h)) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h); + if ((reqWidth > hw_w) || (reqHeight > hw_h)) { + ALOGE("size mismatch (%d, %d) > (%d, %d)", + reqWidth, reqHeight, hw_w, hw_h); return BAD_VALUE; } - sw = (!sw) ? hw_w : sw; - sh = (!sh) ? hw_h : sh; - const size_t size = sw * sh * 4; - const bool filtering = sw != hw_w || sh != hw_h; - -// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d", -// sw, sh, minLayerZ, maxLayerZ); + reqWidth = (!reqWidth) ? hw_w : reqWidth; + reqHeight = (!reqHeight) ? hw_h : reqHeight; - // make sure to clear all GL error flags - while ( glGetError() != GL_NO_ERROR ) ; - - // create a FBO - GLuint name, tname; + GLuint tname; glGenRenderbuffersOES(1, &tname); glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, reqWidth, reqHeight); + // create a FBO + GLuint name; glGenFramebuffersOES(1, &name); glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, @@ -2703,150 +2914,73 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display, GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + status_t result = NO_ERROR; if (status == GL_FRAMEBUFFER_COMPLETE_OES) { - // invert everything, b/c glReadPixel() below will invert the FB - GLint viewport[4]; - glGetIntegerv(GL_VIEWPORT, viewport); - glViewport(0, 0, sw, sh); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrthof(0, hw_w, hw_h, 0, 0, 1); - glMatrixMode(GL_MODELVIEW); - - // redraw the screen entirely... - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); - - const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ()); - const size_t count = layers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); - const uint32_t z = layer->drawingState().z; - if (z >= minLayerZ && z <= maxLayerZ) { - if (filtering) layer->setFiltering(true); - layer->draw(hw); - if (filtering) layer->setFiltering(false); - } - } - - // check for errors and return screen capture - if (glGetError() != GL_NO_ERROR) { - // error while rendering - result = INVALID_OPERATION; - } else { - // allocate shared memory large enough to hold the - // screen capture - sp<MemoryHeapBase> base( - new MemoryHeapBase(size, 0, "screen-capture") ); - void* const ptr = base->getBase(); - if (ptr != MAP_FAILED) { - // capture the screen with glReadPixels() - ScopedTrace _t(ATRACE_TAG, "glReadPixels"); - glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr); - if (glGetError() == GL_NO_ERROR) { - *heap = base; - *w = sw; - *h = sh; - *f = PIXEL_FORMAT_RGBA_8888; - result = NO_ERROR; + renderScreenImplLocked(hw, reqWidth, reqHeight, minLayerZ, maxLayerZ, true); + + // Below we render the screenshot into the + // CpuConsumer using glReadPixels from our FBO. + // Some older drivers don't support the GL->CPU path so we + // have to wrap it with a CPU->CPU path, which is what + // glReadPixels essentially is. + + sp<Surface> sur = new Surface(producer); + ANativeWindow* window = sur.get(); + + if (native_window_api_connect(window, NATIVE_WINDOW_API_CPU) == NO_ERROR) { + int err = 0; + err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); + err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); + err |= native_window_set_usage(window, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + + if (err == NO_ERROR) { + ANativeWindowBuffer* buffer; + if (native_window_dequeue_buffer_and_wait(window, &buffer) == NO_ERROR) { + sp<GraphicBuffer> buf = static_cast<GraphicBuffer*>(buffer); + void* vaddr; + if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, &vaddr) == NO_ERROR) { + glReadPixels(0, 0, buffer->stride, reqHeight, + GL_RGBA, GL_UNSIGNED_BYTE, vaddr); + buf->unlock(); + } + window->queueBuffer(window, buffer, -1); } - } else { - result = NO_MEMORY; } + native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU); } - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); + } else { - result = BAD_VALUE; + ALOGE("got GL_FRAMEBUFFER_COMPLETE_OES while taking screenshot"); + result = INVALID_OPERATION; } - // release FBO resources + // back to main framebuffer glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteRenderbuffersOES(1, &tname); glDeleteFramebuffersOES(1, &name); - hw->compositionComplete(); - -// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK"); + DisplayDevice::setViewportAndProjection(hw); return result; } - -status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, - sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, - uint32_t sw, uint32_t sh, - uint32_t minLayerZ, uint32_t maxLayerZ) -{ - if (CC_UNLIKELY(display == 0)) - return BAD_VALUE; - - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - - class MessageCaptureScreen : public MessageBase { - SurfaceFlinger* flinger; - sp<IBinder> display; - sp<IMemoryHeap>* heap; - uint32_t* w; - uint32_t* h; - PixelFormat* f; - uint32_t sw; - uint32_t sh; - uint32_t minLayerZ; - uint32_t maxLayerZ; - status_t result; - public: - MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display, - sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, - uint32_t sw, uint32_t sh, - uint32_t minLayerZ, uint32_t maxLayerZ) - : flinger(flinger), display(display), - heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), - minLayerZ(minLayerZ), maxLayerZ(maxLayerZ), - result(PERMISSION_DENIED) - { - } - status_t getResult() const { - return result; - } - virtual bool handler() { - Mutex::Autolock _l(flinger->mStateLock); - result = flinger->captureScreenImplLocked(display, - heap, w, h, f, sw, sh, minLayerZ, maxLayerZ); - return true; - } - }; - - sp<MessageBase> msg = new MessageCaptureScreen(this, - display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ); - status_t res = postMessageSync(msg); - if (res == NO_ERROR) { - res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); - } - return res; -} - // --------------------------------------------------------------------------- SurfaceFlinger::LayerVector::LayerVector() { } SurfaceFlinger::LayerVector::LayerVector(const LayerVector& rhs) - : SortedVector<sp<LayerBase> >(rhs) { + : SortedVector<sp<Layer> >(rhs) { } int SurfaceFlinger::LayerVector::do_compare(const void* lhs, const void* rhs) const { // sort layers per layer-stack, then by z-order and finally by sequence - const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs)); - const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs)); + const sp<Layer>& l(*reinterpret_cast<const sp<Layer>*>(lhs)); + const sp<Layer>& r(*reinterpret_cast<const sp<Layer>*>(rhs)); uint32_t ls = l->currentState().layerStack; uint32_t rs = r->currentState().layerStack; @@ -2868,7 +3002,7 @@ SurfaceFlinger::DisplayDeviceState::DisplayDeviceState() } SurfaceFlinger::DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type) - : type(type), layerStack(0), orientation(0) { + : type(type), layerStack(DisplayDevice::NO_LAYER_STACK), orientation(0) { viewport.makeInvalid(); frame.makeInvalid(); } |