diff options
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 370 |
1 files changed, 256 insertions, 114 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2b06f6f..e6bdfd1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -53,6 +53,7 @@ #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" +#include "DisplayHardware/HWComposer.h" /* ideally AID_GRAPHICS would be in a semi-public header * or there would be a way to map a user/group name to its id @@ -78,12 +79,14 @@ SurfaceFlinger::SurfaceFlinger() mReadFramebuffer("android.permission.READ_FRAME_BUFFER"), mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), + mHwWorkListDirty(false), mDeferReleaseConsole(false), mFreezeDisplay(false), mFreezeCount(0), mFreezeDisplayTime(0), mDebugRegion(0), mDebugBackground(0), + mDebugDisableHWC(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), @@ -165,7 +168,7 @@ void SurfaceFlinger::bootFinished() { const nsecs_t now = systemTime(); const nsecs_t duration = now - mBootTime; - LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); + LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); mBootFinished = true; property_set("ctl.stop", "bootanim"); } @@ -201,10 +204,10 @@ status_t SurfaceFlinger::readyToRun() mServerHeap = new MemoryHeapBase(4096, MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap"); LOGE_IF(mServerHeap==0, "can't create shared memory dealer"); - + mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase()); LOGE_IF(mServerCblk==0, "can't get to shared control block's address"); - + new(mServerCblk) surface_flinger_cblk_t; // initialize primary screen @@ -233,7 +236,7 @@ status_t SurfaceFlinger::readyToRun() // Initialize OpenGL|ES glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glPixelStorei(GL_PACK_ALIGNMENT, 4); + glPixelStorei(GL_PACK_ALIGNMENT, 4); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_SCISSOR_TEST); glShadeModel(GL_FLAT); @@ -267,7 +270,7 @@ status_t SurfaceFlinger::readyToRun() // start boot animation property_set("ctl.start", "bootanim"); - + return NO_ERROR; } @@ -370,6 +373,11 @@ bool SurfaceFlinger::threadLoop() // post surfaces (if needed) handlePageFlip(); + if (UNLIKELY(mHwWorkListDirty)) { + // build the h/w work list + handleWorkList(); + } + const DisplayHardware& hw(graphicPlane(0).displayHardware()); if (LIKELY(hw.canDraw() && !isFrozen())) { // repaint the framebuffer (if needed) @@ -384,13 +392,12 @@ bool SurfaceFlinger::threadLoop() logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index); hw.compositionComplete(); - // release the clients before we flip ('cause flip might block) - logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index); - unlockClients(); - logger.log(GraphicLog::SF_SWAP_BUFFERS, index); postFramebuffer(); + logger.log(GraphicLog::SF_UNLOCK_CLIENTS, index); + unlockClients(); + logger.log(GraphicLog::SF_REPAINT_DONE, index); } else { // pretend we did the post @@ -455,6 +462,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) handleTransactionLocked(transactionFlags, ditchedLayers); mLastTransactionTime = systemTime() - now; mDebugInTransaction = 0; + mHwWorkListDirty = true; // here the transaction has been committed } @@ -462,6 +470,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) * Clean-up all layers that went away * (do this without the lock held) */ + const size_t count = ditchedLayers.size(); for (size_t i=0 ; i<count ; i++) { if (ditchedLayers[i] != 0) { @@ -665,7 +674,7 @@ void SurfaceFlinger::computeVisibleRegions( // Update aboveOpaqueLayers for next (lower) layer aboveOpaqueLayers.orSelf(opaqueRegion); - + // Store the visible region is screen space layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); @@ -695,8 +704,8 @@ void SurfaceFlinger::commitTransaction() void SurfaceFlinger::handlePageFlip() { bool visibleRegions = mVisibleRegionsDirty; - LayerVector& currentLayers = const_cast<LayerVector&>( - mDrawingState.layersSortedByZ); + LayerVector& currentLayers( + const_cast<LayerVector&>(mDrawingState.layersSortedByZ)); visibleRegions |= lockPageFlip(currentLayers); const DisplayHardware& hw = graphicPlane(0).displayHardware(); @@ -719,6 +728,7 @@ void SurfaceFlinger::handlePageFlip() mWormholeRegion = screenRegion.subtract(opaqueRegion); mVisibleRegionsDirty = false; + mHwWorkListDirty = true; } unlockPageFlip(currentLayers); @@ -749,6 +759,24 @@ void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) } } +void SurfaceFlinger::handleWorkList() +{ + mHwWorkListDirty = false; + HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer()); + if (hwc.initCheck() == NO_ERROR) { + const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ); + const size_t count = currentLayers.size(); + hwc.createWorkList(count); + hwc_layer_t* const cur(hwc.getLayers()); + for (size_t i=0 ; cur && i<count ; i++) { + currentLayers[i]->setGeometry(&cur[i]); + if (mDebugDisableHWC) { + cur[i].compositionType = HWC_FRAMEBUFFER; + cur[i].flags |= HWC_SKIP_LAYER; + } + } + } +} void SurfaceFlinger::handleRepaint() { @@ -769,8 +797,8 @@ void SurfaceFlinger::handleRepaint() glLoadIdentity(); uint32_t flags = hw.getFlags(); - if ((flags & DisplayHardware::SWAP_RECTANGLE) || - (flags & DisplayHardware::BUFFER_PRESERVED)) + if ((flags & DisplayHardware::SWAP_RECTANGLE) || + (flags & DisplayHardware::BUFFER_PRESERVED)) { // we can redraw only what's dirty, but since SWAP_RECTANGLE only // takes a rectangle, we must make sure to update that whole @@ -813,9 +841,73 @@ void SurfaceFlinger::composeSurfaces(const Region& dirty) // draw something... drawWormhole(); } + + status_t err = NO_ERROR; const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); - const size_t count = layers.size(); - for (size_t i=0 ; i<count ; ++i) { + size_t count = layers.size(); + + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + HWComposer& hwc(hw.getHwComposer()); + hwc_layer_t* const cur(hwc.getLayers()); + + LOGE_IF(cur && hwc.getNumLayers() != count, + "HAL number of layers (%d) doesn't match surfaceflinger (%d)", + hwc.getNumLayers(), count); + + // just to be extra-safe, use the smallest count + if (hwc.initCheck() == NO_ERROR) { + count = count < hwc.getNumLayers() ? count : hwc.getNumLayers(); + } + + /* + * update the per-frame h/w composer data for each layer + * and build the transparent region of the FB + */ + Region transparent; + if (cur) { + for (size_t i=0 ; i<count ; i++) { + const sp<LayerBase>& layer(layers[i]); + layer->setPerFrameData(&cur[i]); + if (cur[i].hints & HWC_HINT_CLEAR_FB) { + if (!(layer->needsBlending())) { + transparent.orSelf(layer->visibleRegionScreen); + } + } + } + err = hwc.prepare(); + LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err)); + } + + /* + * clear the area of the FB that need to be transparent + */ + transparent.andSelf(dirty); + if (!transparent.isEmpty()) { + glClearColor(0,0,0,0); + Region::const_iterator it = transparent.begin(); + Region::const_iterator const end = transparent.end(); + const int32_t height = hw.getHeight(); + while (it != end) { + const Rect& r(*it++); + const GLint sy = height - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glClear(GL_COLOR_BUFFER_BIT); + } + } + + + /* + * and then, render the layers targeted at the framebuffer + */ + for (size_t i=0 ; i<count ; i++) { + if (cur) { + if ((cur[i].compositionType != HWC_FRAMEBUFFER) && + !(cur[i].flags & HWC_SKIP_LAYER)) { + // skip layers handled by the HAL + continue; + } + } + const sp<LayerBase>& layer(layers[i]); const Region clip(dirty.intersect(layer->visibleRegionScreen)); if (!clip.isEmpty()) { @@ -1054,7 +1146,7 @@ void SurfaceFlinger::closeGlobalTransaction() if (android_atomic_dec(&mTransactionCount) == 1) { signalEvent(); - // if there is a transaction with a resize, wait for it to + // if there is a transaction with a resize, wait for it to // take effect before returning. Mutex::Autolock _l(mStateLock); while (mResizeTransationPending) { @@ -1098,7 +1190,7 @@ status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags) return NO_ERROR; } -int SurfaceFlinger::setOrientation(DisplayID dpy, +int SurfaceFlinger::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) @@ -1131,14 +1223,17 @@ sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, int(w), int(h)); return surfaceHandle; } - + //LOGD("createSurface for pid %d (%d x %d)", pid, w, h); sp<Layer> normalLayer; switch (flags & eFXSurfaceMask) { case eFXSurfaceNormal: +#if HAS_PUSH_BUFFERS if (UNLIKELY(flags & ePushBuffers)) { layer = createPushBuffersSurface(client, d, w, h, flags); - } else { + } else +#endif + { normalLayer = createNormalSurface(client, d, w, h, flags, format); layer = normalLayer; } @@ -1157,7 +1252,7 @@ sp<ISurface> SurfaceFlinger::createSurface(const sp<Client>& client, int pid, ssize_t token = addClientLayer(client, layer); surfaceHandle = layer->getSurface(); - if (surfaceHandle != 0) { + if (surfaceHandle != 0) { params->token = token; params->identity = surfaceHandle->getIdentity(); params->width = w; @@ -1241,7 +1336,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) /* * 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). @@ -1262,7 +1357,7 @@ status_t SurfaceFlinger::removeSurface(const sp<Client>& client, SurfaceID sid) status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) { // called by ~ISurface() when all references are gone - + class MessageDestroySurface : public MessageBase { SurfaceFlinger* flinger; sp<LayerBaseClient> layer; @@ -1275,9 +1370,9 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) layer.clear(); // clear it outside of the lock; Mutex::Autolock _l(flinger->mStateLock); /* - * remove the layer from the current list -- chances are that it's - * not in the list anyway, because it should have been removed - * already upon request of the client (eg: window manager). + * remove the layer from the current list -- chances are that it's + * not in the list anyway, because it should have been removed + * already upon request of the client (eg: window manager). * However, a buggy client could have not done that. * Since we know we don't have any more clients, we don't need * to use the purgatory. @@ -1392,7 +1487,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) } const bool locked(retry >= 0); if (!locked) { - snprintf(buffer, SIZE, + snprintf(buffer, SIZE, "SurfaceFlinger appears to be unresponsive, " "dumping anyways (no locks held)\n"); result.append(buffer); @@ -1434,6 +1529,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } + HWComposer& hwc(hw.getHwComposer()); + snprintf(buffer, SIZE, " h/w composer %s and %s\n", + hwc.initCheck()==NO_ERROR ? "present" : "not present", + mDebugDisableHWC ? "disabled" : "enabled"); + result.append(buffer); + hwc.dump(result, buffer, SIZE); + const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); @@ -1507,6 +1609,11 @@ status_t SurfaceFlinger::onTransact( n = data.readInt32(); mDebugBackground = n ? 1 : 0; return NO_ERROR; + case 1008: // toggle use of hw composer + n = data.readInt32(); + mDebugDisableHWC = n ? 1 : 0; + mHwWorkListDirty = true; + // fall-through... case 1004:{ // repaint everything Mutex::Autolock _l(mStateLock); const DisplayHardware& hw(graphicPlane(0).displayHardware()); @@ -1546,9 +1653,117 @@ status_t SurfaceFlinger::onTransact( // --------------------------------------------------------------------------- +status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, + sp<IMemoryHeap>* heap, + uint32_t* w, uint32_t* h, PixelFormat* f, + uint32_t sw, uint32_t sh) +{ + status_t result = PERMISSION_DENIED; + + // only one display supported for now + if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) + return BAD_VALUE; + + if (!GLExtensions::getInstance().haveFramebufferObject()) + return INVALID_OPERATION; + + // get screen geometry + const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); + const uint32_t hw_w = hw.getWidth(); + const uint32_t hw_h = hw.getHeight(); + + if ((sw > hw_w) || (sh > hw_h)) + return BAD_VALUE; + + sw = (!sw) ? hw_w : sw; + sh = (!sh) ? hw_h : sh; + const size_t size = sw * sh * 4; + + // make sure to clear all GL error flags + while ( glGetError() != GL_NO_ERROR ) ; + + // create a FBO + GLuint name, tname; + glGenRenderbuffersOES(1, &tname); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); + glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + + // invert everything, b/c glReadPixel() below will invert the FB + glViewport(0, 0, sw, sh); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrthof(0, hw_w, 0, hw_h, 0, 1); + glMatrixMode(GL_MODELVIEW); + + // redraw the screen entirely... + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; ++i) { + const sp<LayerBase>& layer(layers[i]); + layer->drawForSreenShot(); + } + + // XXX: this is needed on tegra + glScissor(0, 0, sw, sh); + + // 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) { + // capture the screen with 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; + } + } else { + result = NO_MEMORY; + } + } + + glEnable(GL_SCISSOR_TEST); + glViewport(0, 0, hw_w, hw_h); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + + } else { + result = BAD_VALUE; + } + + // release FBO resources + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDeleteRenderbuffersOES(1, &tname); + glDeleteFramebuffersOES(1, &name); + return result; +} + + status_t SurfaceFlinger::captureScreen(DisplayID dpy, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format) + uint32_t* width, uint32_t* height, PixelFormat* format, + uint32_t sw, uint32_t sh) { // only one display supported for now if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) @@ -1564,12 +1779,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, uint32_t* w; uint32_t* h; PixelFormat* f; + uint32_t sw; + uint32_t sh; status_t result; public: MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy, - sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f) + sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f, + uint32_t sw, uint32_t sh) : flinger(flinger), dpy(dpy), - heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED) + heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED) { } status_t getResult() const { @@ -1582,94 +1800,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy, if (flinger->mSecureFrameBuffer) return true; - // make sure to clear all GL error flags - while ( glGetError() != GL_NO_ERROR ) ; - - // get screen geometry - const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware()); - const uint32_t sw = hw.getWidth(); - const uint32_t sh = hw.getHeight(); - const Region screenBounds(hw.bounds()); - const size_t size = sw * sh * 4; - - // create a FBO - GLuint name, tname; - glGenRenderbuffersOES(1, &tname); - glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname); - glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh); - glGenFramebuffersOES(1, &name); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); - glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, - GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname); - - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); - if (status == GL_FRAMEBUFFER_COMPLETE_OES) { - - // invert everything, b/c glReadPixel() below will invert the FB - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrthof(0, sw, 0, sh, 0, 1); - glMatrixMode(GL_MODELVIEW); - - // redraw the screen entirely... - glClearColor(0,0,0,1); - glClear(GL_COLOR_BUFFER_BIT); - const Vector< sp<LayerBase> >& layers( - flinger->mVisibleLayersSortedByZ); - const size_t count = layers.size(); - for (size_t i=0 ; i<count ; ++i) { - const sp<LayerBase>& layer(layers[i]); - if (!strcmp(layer->getTypeId(), "LayerBuffer")) { - // we cannot render LayerBuffer because it doens't - // use OpenGL, and won't show-up in the FBO. - continue; - } - layer->draw(screenBounds); - } - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - - // 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) { - // capture the screen with 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; - } - } else { - result = NO_MEMORY; - } - } - } else { - result = BAD_VALUE; - } + result = flinger->captureScreenImplLocked(dpy, + heap, w, h, f, sw, sh); - // release FBO resources - glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); - glDeleteRenderbuffersOES(1, &tname); - glDeleteFramebuffersOES(1, &name); return true; } }; sp<MessageBase> msg = new MessageCaptureScreen(this, - dpy, heap, width, height, format); + dpy, heap, width, height, format, sw, sh); status_t res = postMessageSync(msg); if (res == NO_ERROR) { res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult(); @@ -1819,12 +1958,15 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const { int32_t name = NAME_NOT_FOUND; sp<Layer> layer(mFlinger->getLayer(sur)); - if (layer == 0) return name; + if (layer == 0) { + return name; + } // if this layer already has a token, just return it name = layer->getToken(); - if ((name >= 0) && (layer->getClient() == this)) + if ((name >= 0) && (layer->getClient() == this)) { return name; + } name = 0; do { |