diff options
Diffstat (limited to 'libs/surfaceflinger/Layer.cpp')
-rw-r--r-- | libs/surfaceflinger/Layer.cpp | 493 |
1 files changed, 119 insertions, 374 deletions
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 6f92515c32cc..ecb6b326476c 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -28,9 +28,9 @@ #include <ui/PixelFormat.h> #include <ui/Surface.h> +#include "Buffer.h" #include "clz.h" #include "Layer.h" -#include "LayerBitmap.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" @@ -47,26 +47,29 @@ const char* const Layer::typeID = "Layer"; // --------------------------------------------------------------------------- -Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i) - : LayerBaseClient(flinger, display, c, i), +Layer::Layer(SurfaceFlinger* flinger, DisplayID display, + const sp<Client>& c, int32_t i) + : LayerBaseClient(flinger, display, c, i), lcblk(NULL), mSecure(false), - mFrontBufferIndex(1), - mNeedsBlending(true), - mResizeTransactionDone(false) + mNeedsBlending(true) { // no OpenGL operation is possible here, since we might not be // in the OpenGL thread. + lcblk = new SharedBufferServer(c->ctrlblk, i, NUM_BUFFERS); + mFrontBufferIndex = lcblk->getFrontBuffer(); } Layer::~Layer() { destroy(); // the actual buffers will be destroyed here + delete lcblk; + } void Layer::destroy() { - for (int i=0 ; i<NUM_BUFFERS ; i++) { + for (size_t i=0 ; i<NUM_BUFFERS ; i++) { if (mTextures[i].name != -1U) { glDeleteTextures(1, &mTextures[i].name); mTextures[i].name = -1U; @@ -76,19 +79,11 @@ void Layer::destroy() eglDestroyImageKHR(dpy, mTextures[i].image); mTextures[i].image = EGL_NO_IMAGE_KHR; } - mBuffers[i].free(); + mBuffers[i].clear(); } mSurface.clear(); } -void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags) -{ - LayerBase::initStates(w,h,flags); - - if (flags & ISurfaceComposer::eDestroyBackbuffer) - lcblk->flags |= eNoCopyBack; -} - sp<LayerBaseClient::Surface> Layer::createSurface() const { return mSurface; @@ -112,13 +107,14 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, if (flags & ISurfaceComposer::eSecure) bufferFlags |= Buffer::SECURE; + mFormat = format; + mWidth = w; + mHeight = h; mSecure = (bufferFlags & Buffer::SECURE) ? true : false; mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; - for (int i=0 ; i<2 ; i++) { - err = mBuffers[i].init(lcblk->surface + i, w, h, format, bufferFlags); - if (err != NO_ERROR) { - return err; - } + mBufferFlags = bufferFlags; + for (size_t i=0 ; i<NUM_BUFFERS ; i++) { + mBuffers[i] = new Buffer(); } mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); return NO_ERROR; @@ -126,7 +122,8 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, void Layer::reloadTexture(const Region& dirty) { - const sp<Buffer>& buffer(frontBuffer().getBuffer()); + Mutex::Autolock _l(mLock); + sp<Buffer> buffer(getFrontBuffer()); if (LIKELY(mFlags & DisplayHardware::DIRECT_TEXTURE)) { int index = mFrontBufferIndex; if (LIKELY(!mTextures[index].dirty)) { @@ -202,80 +199,64 @@ void Layer::onDraw(const Region& clip) const const int index = (mFlags & DisplayHardware::DIRECT_TEXTURE) ? mFrontBufferIndex : 0; GLuint textureName = mTextures[index].name; - if (UNLIKELY(textureName == -1LU)) { - LOGW("Layer %p doesn't have a texture", this); + //LOGW("Layer %p doesn't have a texture", this); // the texture has not been created yet, this Layer has // in fact never been drawn into. this happens frequently with // SurfaceView. clearWithOpenGL(clip); return; } + drawWithOpenGL(clip, mTextures[index]); } -sp<SurfaceBuffer> Layer::peekBuffer(int usage) +sp<SurfaceBuffer> Layer::requestBuffer(int index, int usage) { /* - * This is called from the client's Surface::lock(), after it locked - * the surface successfully. We're therefore guaranteed that the - * back-buffer is not in use by ourselves. - * Of course, we need to validate all this, which is not trivial. - * - * FIXME: A resize could happen at any time here. What to do about this? - * - resize() form post() - * - resize() from doTransaction() - * - * We'll probably need an internal lock for this. - * + * This is called from the client's Surface::dequeue(). This can happen + * at any time, especially while we're in the middle of using the + * buffer 'index' as our front buffer. * - * TODO: We need to make sure that post() doesn't swap - * the buffers under us. + * Make sure the buffer we're resizing is not the front buffer and has been + * dequeued. Once this condition is asserted, we are guaranteed that this + * buffer cannot become the front buffer under our feet, since we're called + * from Surface::dequeue() */ + status_t err = lcblk->assertReallocate(index); + LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err)); - // it's okay to read swapState for the purpose of figuring out the - // backbuffer index, which cannot change (since the app has locked it). - const uint32_t state = lcblk->swapState; - const int32_t backBufferIndex = layer_cblk_t::backBuffer(state); + Mutex::Autolock _l(mLock); + uint32_t w = mWidth; + uint32_t h = mHeight; - // get rid of the EGL image, since we shouldn't need it anymore - // (note that we're in a different thread than where it is being used) - if (mTextures[backBufferIndex].image != EGL_NO_IMAGE_KHR) { - EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay()); - eglDestroyImageKHR(dpy, mTextures[backBufferIndex].image); - mTextures[backBufferIndex].image = EGL_NO_IMAGE_KHR; + sp<Buffer>& buffer(mBuffers[index]); + if (buffer->getStrongCount() == 1) { + err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags); + } else { + // here we have to reallocate a new buffer because we could have a + // client in our process with a reference to it (eg: status bar), + // and we can't release the handle under its feet. + buffer.clear(); + buffer = new Buffer(w, h, mFormat, usage, mBufferFlags); + err = buffer->initCheck(); } - - LayerBitmap& layerBitmap(mBuffers[backBufferIndex]); - sp<SurfaceBuffer> buffer = layerBitmap.allocate(usage); - - LOGD_IF(DEBUG_RESIZE, - "Layer::getBuffer(this=%p), index=%d, (%d,%d), (%d,%d)", - this, backBufferIndex, - layerBitmap.getWidth(), - layerBitmap.getHeight(), - layerBitmap.getBuffer()->getWidth(), - layerBitmap.getBuffer()->getHeight()); - - if (UNLIKELY(buffer == 0)) { - // XXX: what to do, what to do? + + if (err || buffer->handle == 0) { + LOGE_IF(err || buffer->handle == 0, + "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)", + this, index, w, h, strerror(-err)); } else { - // texture is now dirty... - mTextures[backBufferIndex].dirty = true; - // ... so it the visible region (because we consider the surface's - // buffer size for visibility calculations) - forceVisibilityTransaction(); - mFlinger->setTransactionFlags(eTraversalNeeded); + LOGD_IF(DEBUG_RESIZE, + "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d", + this, index, w, h); } - return buffer; -} -void Layer::scheduleBroadcast() -{ - sp<Client> ourClient(client.promote()); - if (ourClient != 0) { - mFlinger->scheduleBroadcast(ourClient); + if (err == NO_ERROR && buffer->handle != 0) { + // texture is now dirty... + mTextures[index].dirty = true; } + return buffer; } uint32_t Layer::doTransaction(uint32_t flags) @@ -283,114 +264,48 @@ uint32_t Layer::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - // the test front.{w|h} != temp.{w|h} is not enough because it is possible - // that the size changed back to its previous value before the buffer - // was resized (in the eLocked case below), in which case, we still - // need to execute the code below so the clients have a chance to be - // release. resize() deals with the fact that the size can be the same. - - /* - * Various states we could be in... - - resize = state & eResizeRequested; - if (backbufferChanged) { - if (resize == 0) { - // ERROR, the resized buffer doesn't have its resize flag set - } else if (resize == mask) { - // ERROR one of the buffer has already been resized - } else if (resize == mask ^ eResizeRequested) { - // ERROR, the resized buffer doesn't have its resize flag set - } else if (resize == eResizeRequested) { - // OK, Normal case, proceed with resize - } - } else { - if (resize == 0) { - // OK, nothing special, do nothing - } else if (resize == mask) { - // restarted transaction, do nothing - } else if (resize == mask ^ eResizeRequested) { - // restarted transaction, do nothing - } else if (resize == eResizeRequested) { - // OK, size reset to previous value, proceed with resize - } - } - */ - // Index of the back buffer const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h); - const uint32_t state = lcblk->swapState; - const int32_t clientBackBufferIndex = layer_cblk_t::backBuffer(state); - const uint32_t mask = clientBackBufferIndex ? eResizeBuffer1 : eResizeBuffer0; - uint32_t resizeFlags = state & eResizeRequested; - - if (UNLIKELY(backbufferChanged && (resizeFlags != eResizeRequested))) { - LOGE( "backbuffer size changed, but both resize flags are not set! " - "(layer=%p), state=%08x, requested (%dx%d), drawing (%d,%d), " - "index=%d, (%dx%d), (%dx%d)", - this, state, - int(temp.w), int(temp.h), - int(drawingState().w), int(drawingState().h), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - // if we get there we're pretty screwed. the only reasonable - // thing to do is to pretend we should do the resize since - // backbufferChanged is set (this also will give a chance to - // client to get unblocked) - resizeFlags = eResizeRequested; - } - - if (resizeFlags == eResizeRequested) { - // NOTE: asserting that clientBackBufferIndex!=mFrontBufferIndex - // here, would be wrong and misleading because by this point - // mFrontBufferIndex has not been updated yet. + if (backbufferChanged) { + // the size changed, we need to ask our client to request a new buffer LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), state=%08x, " - "requested (%dx%d), " - "drawing (%d,%d), " - "index=%d, (%dx%d), (%dx%d)", - this, state, - int(temp.w), int(temp.h), + "resize (layer=%p), requested (%dx%d), " + "drawing (%d,%d), (%dx%d), (%dx%d)", + this, int(temp.w), int(temp.h), int(drawingState().w), int(drawingState().h), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - if (state & eLocked) { - // if the buffer is locked, we can't resize anything because - // - the backbuffer is currently in use by the user - // - the front buffer is being shown - // We just act as if the transaction didn't happen and we - // reschedule it later... - flags |= eRestartTransaction; - } else { - // This buffer needs to be resized - status_t err = - resize(clientBackBufferIndex, temp.w, temp.h, "transaction"); - if (err == NO_ERROR) { - const uint32_t mask = clientBackBufferIndex ? - eResizeBuffer1 : eResizeBuffer0; - android_atomic_and(~mask, &(lcblk->swapState)); - // since a buffer became available, we can let the client go... - scheduleBroadcast(); - mResizeTransactionDone = true; - - // we're being resized and there is a freeze display request, - // acquire a freeze lock, so that the screen stays put - // until we've redrawn at the new size; this is to avoid - // glitches upon orientation changes. - if (mFlinger->hasFreezeRequest()) { - // if the surface is hidden, don't try to acquire the - // freeze lock, since hidden surfaces may never redraw - if (!(front.flags & ISurfaceComposer::eLayerHidden)) { - mFreezeLock = mFlinger->getFreezeLock(); - } - } + int(mBuffers[0]->getWidth()), int(mBuffers[0]->getHeight()), + int(mBuffers[1]->getWidth()), int(mBuffers[1]->getHeight())); + + // record the new size, form this point on, when the client request a + // buffer, it'll get the new size. + setDrawingSize(temp.w, temp.h); + + // all buffers need reallocation + lcblk->reallocate(); + + // recompute the visible region + // FIXME: ideally we would do that only when we have received + // a buffer of the right size + flags |= Layer::eVisibleRegion; + this->contentDirty = true; + +#if 0 + // FIXME: handle freeze lock + // we're being resized and there is a freeze display request, + // acquire a freeze lock, so that the screen stays put + // until we've redrawn at the new size; this is to avoid + // glitches upon orientation changes. + if (mFlinger->hasFreezeRequest()) { + // if the surface is hidden, don't try to acquire the + // freeze lock, since hidden surfaces may never redraw + if (!(front.flags & ISurfaceComposer::eLayerHidden)) { + mFreezeLock = mFlinger->getFreezeLock(); } } +#endif } - + if (temp.sequence != front.sequence) { if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) { // this surface is now hidden, so it shouldn't hold a freeze lock @@ -402,65 +317,10 @@ uint32_t Layer::doTransaction(uint32_t flags) return LayerBase::doTransaction(flags); } -status_t Layer::resize( - int32_t clientBackBufferIndex, - uint32_t width, uint32_t height, - const char* what) -{ - /* - * handle resize (backbuffer and frontbuffer reallocation) - * this is called from post() or from doTransaction() - */ - - const LayerBitmap& clientBackBuffer(mBuffers[clientBackBufferIndex]); - - // if the new (transaction) size is != from the the backbuffer - // then we need to reallocate the backbuffer - bool backbufferChanged = (clientBackBuffer.getWidth() != width) || - (clientBackBuffer.getHeight() != height); - - LOGD_IF(!backbufferChanged, - "(%s) eResizeRequested (layer=%p), but size not changed: " - "requested (%dx%d), drawing (%d,%d), current (%d,%d)," - "state=%08lx, index=%d, (%dx%d), (%dx%d)", - what, this, - int(width), int(height), - int(drawingState().w), int(drawingState().h), - int(currentState().w), int(currentState().h), - long(lcblk->swapState), - int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - // this can happen when changing the size back and forth quickly - status_t err = NO_ERROR; - if (backbufferChanged) { - - LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), " - "index=%d, (%dx%d), (%dx%d)", - this, int(width), int(height), int(clientBackBufferIndex), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - err = mBuffers[clientBackBufferIndex].setSize(width, height); - if (UNLIKELY(err != NO_ERROR)) { - // This really should never happen - LOGE("resizing buffer %d to (%u,%u) failed [%08x] %s", - clientBackBufferIndex, width, height, err, strerror(err)); - // couldn't reallocate the surface - android_atomic_write(eInvalidSurface, &lcblk->swapState); - } - } - return err; -} - -void Layer::setSizeChanged(uint32_t w, uint32_t h) -{ - LOGD_IF(DEBUG_RESIZE, - "setSizeChanged w=%d, h=%d (old: w=%d, h=%d)", - w, h, mCurrentState.w, mCurrentState.h); - android_atomic_or(eResizeRequested, &(lcblk->swapState)); +void Layer::setDrawingSize(uint32_t w, uint32_t h) { + Mutex::Autolock _l(mLock); + mWidth = w; + mHeight = h; } // ---------------------------------------------------------------------------- @@ -469,139 +329,26 @@ void Layer::setSizeChanged(uint32_t w, uint32_t h) void Layer::lockPageFlip(bool& recomputeVisibleRegions) { - uint32_t state = android_atomic_or(eBusy, &(lcblk->swapState)); - // preemptively block the client, because he might set - // eFlipRequested at any time and want to use this buffer - // for the next frame. This will be unset below if it - // turns out we didn't need it. - - uint32_t mask = eInvalidSurface | eFlipRequested | eResizeRequested; - if (!(state & mask)) - return; - - if (UNLIKELY(state & eInvalidSurface)) { - // if eInvalidSurface is set, this means the surface - // became invalid during a transaction (NO_MEMORY for instance) - scheduleBroadcast(); + ssize_t buf = lcblk->retireAndLock(); + if (buf < NO_ERROR) { + //LOGW("nothing to retire (%s)", strerror(-buf)); + // NOTE: here the buffer is locked because we will used + // for composition later in the loop return; } - - if (UNLIKELY(state & eFlipRequested)) { - uint32_t oldState; - mPostedDirtyRegion = post(&oldState, recomputeVisibleRegions); - if (oldState & eNextFlipPending) { - // Process another round (we know at least a buffer - // is ready for that client). - mFlinger->signalEvent(); - } - } -} - -Region Layer::post(uint32_t* previousSate, bool& recomputeVisibleRegions) -{ - // atomically swap buffers and (re)set eFlipRequested - int32_t oldValue, newValue; - layer_cblk_t * const lcblk = this->lcblk; - do { - oldValue = lcblk->swapState; - // get the current value - - LOG_ASSERT(oldValue&eFlipRequested, - "eFlipRequested not set, yet we're flipping! (state=0x%08lx)", - long(oldValue)); - - newValue = (oldValue ^ eIndex); - // swap buffers - - newValue &= ~(eFlipRequested | eNextFlipPending); - // clear eFlipRequested and eNextFlipPending - - if (oldValue & eNextFlipPending) - newValue |= eFlipRequested; - // if eNextFlipPending is set (second buffer already has something - // in it) we need to reset eFlipRequested because the client - // might never do it - - } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState))); - *previousSate = oldValue; - const int32_t index = (newValue & eIndex) ^ 1; - mFrontBufferIndex = index; + // we retired a buffer, which becomes the new front buffer + mFrontBufferIndex = buf; - /* NOTE: it's safe to set this flag here because this is only touched - * from LayerBitmap::allocate(), which by construction cannot happen - * while we're in post(). - */ - lcblk->surface[index].flags &= ~surface_info_t::eBufferDirty; - - // ... post the new front-buffer - Region dirty(lcblk->region + index); - dirty.andSelf(frontBuffer().getBounds()); - - //LOGD("Did post oldValue=%08lx, newValue=%08lx, mFrontBufferIndex=%u\n", - // oldValue, newValue, mFrontBufferIndex); - //dirty.dump("dirty"); + // get the dirty region + sp<Buffer> newFrontBuffer(getBuffer(buf)); + const Region dirty(lcblk->getDirtyRegion(buf)); + mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() ); - if (UNLIKELY(oldValue & eResizeRequested)) { - - LOGD_IF(DEBUG_RESIZE, - "post (layer=%p), state=%08x, " - "index=%d, (%dx%d), (%dx%d)", - this, newValue, - int(1-index), - int(mBuffers[0].getWidth()), int(mBuffers[0].getHeight()), - int(mBuffers[1].getWidth()), int(mBuffers[1].getHeight())); - - // here, we just posted the surface and we have resolved - // the front/back buffer indices. The client is blocked, so - // it cannot start using the new backbuffer. - - // If the backbuffer was resized in THIS round, we actually cannot - // resize the frontbuffer because it has *just* been drawn (and we - // would have nothing to draw). In this case we just skip the resize - // it'll happen after the next page flip or during the next - // transaction. - - const uint32_t mask = (1-index) ? eResizeBuffer1 : eResizeBuffer0; - if (mResizeTransactionDone && (newValue & mask)) { - // Resize the layer's second buffer only if the transaction - // happened. It may not have happened yet if eResizeRequested - // was set immediately after the "transactionRequested" test, - // in which case the drawing state's size would be wrong. - mFreezeLock.clear(); - const Layer::State& s(drawingState()); - if (resize(1-index, s.w, s.h, "post") == NO_ERROR) { - do { - oldValue = lcblk->swapState; - if ((oldValue & eResizeRequested) == eResizeRequested) { - // ugh, another resize was requested since we processed - // the first buffer, don't free the client, and let - // the next transaction handle everything. - break; - } - newValue = oldValue & ~mask; - } while(android_atomic_cmpxchg(oldValue, newValue, &(lcblk->swapState))); - } - mResizeTransactionDone = false; - recomputeVisibleRegions = true; - this->contentDirty = true; - } - } + // FIXME: signal an event if we have more buffers waiting + // mFlinger->signalEvent(); - reloadTexture(dirty); - - return dirty; -} - -Point Layer::getPhysicalSize() const -{ - sp<const Buffer> front(frontBuffer().getBuffer()); - Point size(front->getWidth(), front->getHeight()); - if ((size.x | size.y) == 0) { - // if we don't have a buffer yet, just use the state's size. - size = LayerBase::getPhysicalSize(); - } - return size; + reloadTexture( mPostedDirtyRegion ); } void Layer::unlockPageFlip( @@ -622,21 +369,15 @@ void Layer::unlockPageFlip( // is in screen space as well). dirtyRegion.andSelf(visibleRegionScreen); outDirtyRegion.orSelf(dirtyRegion); - - // client could be blocked, so signal them so they get a - // chance to reevaluate their condition. - scheduleBroadcast(); } } void Layer::finishPageFlip() { - if (LIKELY(!(lcblk->swapState & eInvalidSurface))) { - LOGE_IF(!(lcblk->swapState & eBusy), - "layer %p wasn't locked!", this); - android_atomic_and(~eBusy, &(lcblk->swapState)); - } - scheduleBroadcast(); + status_t err = lcblk->unlock( mFrontBufferIndex ); + LOGE_IF(err!=NO_ERROR, + "layer %p, buffer=%d wasn't locked!", + this, mFrontBufferIndex); } // --------------------------------------------------------------------------- @@ -651,12 +392,16 @@ Layer::SurfaceLayer::~SurfaceLayer() { } -sp<SurfaceBuffer> Layer::SurfaceLayer::getBuffer(int usage) +sp<SurfaceBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) { - sp<SurfaceBuffer> buffer = 0; + sp<SurfaceBuffer> buffer; sp<Layer> owner(getOwner()); if (owner != 0) { - buffer = owner->peekBuffer(usage); + LOGE_IF(uint32_t(index)>=NUM_BUFFERS, + "getBuffer() index (%d) out of range", index); + if (uint32_t(index) < NUM_BUFFERS) { + buffer = owner->requestBuffer(index, usage); + } } return buffer; } |