diff options
author | Mathias Agopian <mathias@google.com> | 2009-09-07 16:32:45 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2009-09-07 16:32:45 -0700 |
commit | 9779b221e999583ff89e0dfc40e56398737adbb3 (patch) | |
tree | 76b185d252b95b05e8d74e7a1644b843f8839725 /libs/surfaceflinger/Layer.cpp | |
parent | a4eb91da03bd785bc91bed0d25a9efaa9baba1c1 (diff) | |
download | frameworks_base-9779b221e999583ff89e0dfc40e56398737adbb3.zip frameworks_base-9779b221e999583ff89e0dfc40e56398737adbb3.tar.gz frameworks_base-9779b221e999583ff89e0dfc40e56398737adbb3.tar.bz2 |
fix [2068105] implement queueBuffer/lockBuffer/dequeueBuffer properly
Rewrote SurfaceFlinger's buffer management from the ground-up.
The design now support an arbitrary number of buffers per surface, however the current implementation is limited to four. Currently only 2 buffers are used in practice.
The main new feature is to be able to dequeue all buffers at once (very important when there are only two).
A client can dequeue all buffers until there are none available, it can lock all buffers except the last one that is used for composition. The client will block then, until a new buffer is enqueued.
The current implementation requires that buffers are locked in the same order they are dequeued and enqueued in the same order they are locked. Only one buffer can be locked at a time.
eg. Allowed sequence: DQ, DQ, LOCK, Q, LOCK, Q
eg. Forbidden sequence: DQ, DQ, LOCK, LOCK, Q, Q
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 6f92515..ecb6b32 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; } |