diff options
author | Mathias Agopian <mathias@google.com> | 2010-05-21 17:24:35 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2010-05-24 18:26:01 -0700 |
commit | a138f89c5e78b7e8994823e97d6e860869762837 (patch) | |
tree | 9d11e5f9ee406798070a5cb335390147ae1dffa5 /libs | |
parent | a0b3f1d2eb796eb90a7576c13890ab8df8516d9d (diff) | |
download | frameworks_native-a138f89c5e78b7e8994823e97d6e860869762837.zip frameworks_native-a138f89c5e78b7e8994823e97d6e860869762837.tar.gz frameworks_native-a138f89c5e78b7e8994823e97d6e860869762837.tar.bz2 |
added the notion of fixed-size buffers
the new native_window_set_buffers_geometry allows
to specify a size and format for all buffers to be
dequeued. the buffer will be scalled to the window's
size.
Change-Id: I2c378b85c88d29cdd827a5f319d5c704d79ba381
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaceflinger/Layer.cpp | 113 | ||||
-rw-r--r-- | libs/surfaceflinger/Layer.h | 13 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.cpp | 3 | ||||
-rw-r--r-- | libs/surfaceflinger/LayerBase.h | 3 | ||||
-rw-r--r-- | libs/surfaceflinger_client/ISurface.cpp | 13 | ||||
-rw-r--r-- | libs/surfaceflinger_client/SharedBufferStack.cpp | 16 | ||||
-rw-r--r-- | libs/surfaceflinger_client/Surface.cpp | 141 |
7 files changed, 216 insertions, 86 deletions
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 621b7e3..84584aa 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -55,7 +55,8 @@ Layer::Layer(SurfaceFlinger* flinger, DisplayID display, mNeedsBlending(true), mNeedsDithering(false), mTextureManager(mFlags), - mBufferManager(mTextureManager) + mBufferManager(mTextureManager), + mWidth(0), mHeight(0), mFixedSize(false) { // no OpenGL operation is possible here, since we might not be // in the OpenGL thread. @@ -227,10 +228,18 @@ status_t Layer::setBufferCount(int bufferCount) return err; } -sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) +sp<GraphicBuffer> Layer::requestBuffer(int index, + uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat, + uint32_t usage) { sp<GraphicBuffer> buffer; + if ((reqWidth | reqHeight | reqFormat) < 0) + return buffer; + + if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight)) + return buffer; + // this ensures our client doesn't go away while we're accessing // the shared area. sp<Client> ourClient(client.promote()); @@ -256,23 +265,33 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) return buffer; } - uint32_t w, h; + uint32_t w, h, f; { // scope for the lock Mutex::Autolock _l(mLock); - w = mWidth; - h = mHeight; + const bool fixedSizeChanged = mFixedSize != (reqWidth && reqHeight); + const bool formatChanged = mReqFormat != reqFormat; + mReqWidth = reqWidth; + mReqHeight = reqHeight; + mReqFormat = reqFormat; + mFixedSize = reqWidth && reqHeight; + w = reqWidth ? reqWidth : mWidth; + h = reqHeight ? reqHeight : mHeight; + f = reqFormat ? reqFormat : mFormat; buffer = mBufferManager.detachBuffer(index); + if (fixedSizeChanged || formatChanged) { + lcblk->reallocateAllExcept(index); + } } const uint32_t effectiveUsage = getEffectiveUsage(usage); if (buffer!=0 && buffer->getStrongCount() == 1) { - err = buffer->reallocate(w, h, mFormat, effectiveUsage); + err = buffer->reallocate(w, h, f, effectiveUsage); } 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 GraphicBuffer(w, h, mFormat, effectiveUsage); + buffer = new GraphicBuffer(w, h, f, effectiveUsage); err = buffer->initCheck(); } @@ -288,12 +307,7 @@ sp<GraphicBuffer> Layer::requestBuffer(int index, int usage) if (err == NO_ERROR && buffer->handle != 0) { Mutex::Autolock _l(mLock); - if (mWidth && mHeight) { - mBufferManager.attachBuffer(index, buffer); - } else { - // oops we got killed while we were allocating the buffer - buffer.clear(); - } + mBufferManager.attachBuffer(index, buffer); } return buffer; } @@ -330,39 +344,46 @@ uint32_t Layer::doTransaction(uint32_t flags) const Layer::State& front(drawingState()); const Layer::State& temp(currentState()); - if ((front.requested_w != temp.requested_w) || - (front.requested_h != temp.requested_h)) { + const bool sizeChanged = (front.requested_w != temp.requested_w) || + (front.requested_h != temp.requested_h); + + if (sizeChanged) { // the size changed, we need to ask our client to request a new buffer LOGD_IF(DEBUG_RESIZE, - "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", - this, - int(temp.requested_w), int(temp.requested_h), - int(front.requested_w), int(front.requested_h)); - - // 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(); + "resize (layer=%p), requested (%dx%d), drawing (%d,%d)", + this, + int(temp.requested_w), int(temp.requested_h), + int(front.requested_w), int(front.requested_h)); + + if (!isFixedSize()) { + // 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(); + } } - } - // this will make sure LayerBase::doTransaction doesn't update - // the drawing state's size - Layer::State& editDraw(mDrawingState); - editDraw.requested_w = temp.requested_w; - editDraw.requested_h = temp.requested_h; + // this will make sure LayerBase::doTransaction doesn't update + // the drawing state's size + Layer::State& editDraw(mDrawingState); + editDraw.requested_w = temp.requested_w; + editDraw.requested_h = temp.requested_h; - // record the new size, form this point on, when the client request a - // buffer, it'll get the new size. - setDrawingSize(temp.requested_w, temp.requested_h); + // record the new size, form this point on, when the client request + // a buffer, it'll get the new size. + setBufferSize(temp.requested_w, temp.requested_h); - // all buffers need reallocation - lcblk->reallocate(); + // all buffers need reallocation + lcblk->reallocateAll(); + } else { + // record the new size + setBufferSize(temp.requested_w, temp.requested_h); + } } if (temp.sequence != front.sequence) { @@ -376,12 +397,17 @@ uint32_t Layer::doTransaction(uint32_t flags) return LayerBase::doTransaction(flags); } -void Layer::setDrawingSize(uint32_t w, uint32_t h) { +void Layer::setBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock _l(mLock); mWidth = w; mHeight = h; } +bool Layer::isFixedSize() const { + Mutex::Autolock _l(mLock); + return mFixedSize; +} + // ---------------------------------------------------------------------------- // pageflip handling... // ---------------------------------------------------------------------------- @@ -677,7 +703,8 @@ Layer::SurfaceLayer::~SurfaceLayer() { } -sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) +sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { sp<GraphicBuffer> buffer; sp<Layer> owner(getOwner()); @@ -687,7 +714,7 @@ sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index, int usage) * as it could cause a dead-lock, since it may have to wait * on conditions updated my the main thread. */ - buffer = owner->requestBuffer(index, usage); + buffer = owner->requestBuffer(index, w, h, format, usage); } return buffer; } diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 247748b..10b5910 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -57,7 +57,8 @@ public: status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags=0); - void setDrawingSize(uint32_t w, uint32_t h); + void setBufferSize(uint32_t w, uint32_t h); + bool isFixedSize() const; virtual void onDraw(const Region& clip) const; virtual uint32_t doTransaction(uint32_t transactionFlags); @@ -88,7 +89,8 @@ private: uint32_t getEffectiveUsage(uint32_t usage) const; - sp<GraphicBuffer> requestBuffer(int index, int usage); + sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); status_t setBufferCount(int bufferCount); class SurfaceLayer : public LayerBaseClient::Surface { @@ -97,7 +99,8 @@ private: SurfaceID id, const sp<Layer>& owner); ~SurfaceLayer(); private: - virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); virtual status_t setBufferCount(int bufferCount); sp<Layer> getOwner() const { return static_cast<Layer*>(Surface::getOwner().get()); @@ -181,6 +184,10 @@ private: mutable Mutex mLock; uint32_t mWidth; uint32_t mHeight; + uint32_t mReqWidth; + uint32_t mReqHeight; + uint32_t mReqFormat; + bool mFixedSize; }; // --------------------------------------------------------------------------- diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index 63b9520..51673ff 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -616,7 +616,8 @@ status_t LayerBaseClient::Surface::onTransact( return BnSurface::onTransact(code, data, reply, flags); } -sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int index, int usage) +sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { return NULL; } diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index 53b848f..569b0ff 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -301,7 +301,8 @@ public: sp<LayerBaseClient> getOwner() const; private: - virtual sp<GraphicBuffer> requestBuffer(int index, int usage); + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage); virtual status_t setBufferCount(int bufferCount); virtual status_t registerBuffers(const ISurface::BufferHeap& buffers); diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp index c5d0c0e..7049d9e 100644 --- a/libs/surfaceflinger_client/ISurface.cpp +++ b/libs/surfaceflinger_client/ISurface.cpp @@ -71,11 +71,15 @@ public: { } - virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) + virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); data.writeInt32(bufferIdx); + data.writeInt32(w); + data.writeInt32(h); + data.writeInt32(format); data.writeInt32(usage); remote()->transact(REQUEST_BUFFER, data, &reply); sp<GraphicBuffer> buffer = new GraphicBuffer(); @@ -150,8 +154,11 @@ status_t BnSurface::onTransact( case REQUEST_BUFFER: { CHECK_INTERFACE(ISurface, data, reply); int bufferIdx = data.readInt32(); - int usage = data.readInt32(); - sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage)); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + uint32_t format = data.readInt32(); + uint32_t usage = data.readInt32(); + sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage)); if (buffer == NULL) return BAD_VALUE; return reply->write(*buffer); diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp index 8681b59..b452259 100644 --- a/libs/surfaceflinger_client/SharedBufferStack.cpp +++ b/libs/surfaceflinger_client/SharedBufferStack.cpp @@ -527,13 +527,25 @@ void SharedBufferServer::setStatus(status_t status) } } -status_t SharedBufferServer::reallocate() +status_t SharedBufferServer::reallocateAll() { RWLock::AutoRLock _l(mLock); SharedBufferStack& stack( *mSharedStack ); uint32_t mask = mBufferList.getMask(); - android_atomic_or(mask, &stack.reallocMask); + android_atomic_or(mask, &stack.reallocMask); + return NO_ERROR; +} + +status_t SharedBufferServer::reallocateAllExcept(int buffer) +{ + RWLock::AutoRLock _l(mLock); + + SharedBufferStack& stack( *mSharedStack ); + BufferList temp(mBufferList); + temp.remove(buffer); + uint32_t mask = temp.getMask(); + android_atomic_or(mask, &stack.reallocMask); return NO_ERROR; } diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp index 5f42af0..71504fa 100644 --- a/libs/surfaceflinger_client/Surface.cpp +++ b/libs/surfaceflinger_client/Surface.cpp @@ -349,15 +349,18 @@ void Surface::init() const_cast<int&>(android_native_window_t::maxSwapInterval) = 1; const_cast<uint32_t&>(android_native_window_t::flags) = 0; // be default we request a hardware surface - mUsage = GRALLOC_USAGE_HW_RENDER; mConnected = 0; + // two buffers by default + mBuffers.setCapacity(2); + mBuffers.insertAt(0, 2); } Surface::~Surface() { // this is a client-side operation, the surface is destroyed, unmap // its buffers in this process. - for (int i=0 ; i<2 ; i++) { + size_t size = mBuffers.size(); + for (size_t i=0 ; i<size ; i++) { if (mBuffers[i] != 0 && mBuffers[i]->handle != 0) { getBufferMapper().unregisterBuffer(mBuffers[i]->handle); } @@ -365,6 +368,7 @@ Surface::~Surface() // clear all references and trigger an IPC now, to make sure things // happen without delay, since these resources are quite heavy. + mBuffers.clear(); mClient.clear(); mSurface.clear(); delete mSharedBufferClient; @@ -463,6 +467,22 @@ int Surface::perform(android_native_window_t* window, // ---------------------------------------------------------------------------- +bool Surface::needNewBuffer(int bufIdx, + uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const +{ + Mutex::Autolock _l(mSurfaceLock); + + // Always call needNewBuffer(), since it clears the needed buffers flags + bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); + bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]); + bool newNeewBuffer = needNewBuffer || !validBuffer; + if (newNeewBuffer) { + mBufferInfo.get(pWidth, pHeight, pFormat, pUsage); + } + return newNeewBuffer; +} + int Surface::dequeueBuffer(android_native_buffer_t** buffer) { sp<SurfaceComposerClient> client(getClient()); @@ -476,27 +496,28 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer) return bufIdx; } - // below we make sure we AT LEAST have the usage flags we want - const uint32_t usage(getUsage()); - const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); + // grow the buffer array if needed + const size_t size = mBuffers.size(); + const size_t needed = bufIdx+1; + if (size < needed) { + mBuffers.insertAt(size, needed-size); + } - // Always call needNewBuffer(), since it clears the needed buffers flags - bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx); - if (backBuffer == 0 || - ((uint32_t(backBuffer->usage) & usage) != usage) || - needNewBuffer) - { - err = getBufferLocked(bufIdx, usage); - LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)", - bufIdx, usage, strerror(-err)); + uint32_t w, h, format, usage; + if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) { + err = getBufferLocked(bufIdx, w, h, format, usage); + LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)", + bufIdx, w, h, format, usage, strerror(-err)); if (err == NO_ERROR) { // reset the width/height with the what we get from the buffer + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); mWidth = uint32_t(backBuffer->width); mHeight = uint32_t(backBuffer->height); } } // if we still don't have a buffer here, we probably ran out of memory + const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]); if (!err && backBuffer==0) { err = NO_MEMORY; } @@ -614,12 +635,17 @@ int Surface::dispatch_set_buffer_count(va_list args) { size_t bufferCount = va_arg(args, size_t); return setBufferCount(bufferCount); } - +int Surface::dispatch_set_buffers_geometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + return setBuffersGeometry(w, h, f); +} void Surface::setUsage(uint32_t reqUsage) { Mutex::Autolock _l(mSurfaceLock); - mUsage = reqUsage; + mBufferInfo.set(reqUsage); } int Surface::connect(int api) @@ -660,18 +686,6 @@ int Surface::disconnect(int api) return err; } -uint32_t Surface::getUsage() const -{ - Mutex::Autolock _l(mSurfaceLock); - return mUsage; -} - -int Surface::getConnectedApi() const -{ - Mutex::Autolock _l(mSurfaceLock); - return mConnected; -} - int Surface::crop(Rect const* rect) { Mutex::Autolock _l(mSurfaceLock); @@ -700,6 +714,26 @@ int Surface::setBufferCount(int bufferCount) return err; } +int Surface::setBuffersGeometry(int w, int h, int format) +{ + if (w<0 || h<0 || format<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock _l(mSurfaceLock); + mBufferInfo.set(w, h, format); + return NO_ERROR; +} + +// ---------------------------------------------------------------------------- + +int Surface::getConnectedApi() const +{ + Mutex::Autolock _l(mSurfaceLock); + return mConnected; +} // ---------------------------------------------------------------------------- @@ -830,7 +864,8 @@ int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const return buffer->getIndex(); } -status_t Surface::getBufferLocked(int index, int usage) +status_t Surface::getBufferLocked(int index, + uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { sp<ISurface> s(mSurface); if (s == 0) return NO_INIT; @@ -838,20 +873,21 @@ status_t Surface::getBufferLocked(int index, int usage) status_t err = NO_MEMORY; // free the current buffer - sp<GraphicBuffer>& currentBuffer(mBuffers[index]); + sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index)); if (currentBuffer != 0) { getBufferMapper().unregisterBuffer(currentBuffer->handle); currentBuffer.clear(); } - sp<GraphicBuffer> buffer = s->requestBuffer(index, usage); + sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage); LOGE_IF(buffer==0, "ISurface::getBuffer(%d, %08x) returned NULL", index, usage); if (buffer != 0) { // this should never happen by construction LOGE_IF(buffer->handle == NULL, - "Surface (identity=%d) requestBuffer(%d, %08x) returned" - "a buffer with a null handle", mIdentity, index, usage); + "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) " + "returned a buffer with a null handle", + mIdentity, index, w, h, format, usage); err = mSharedBufferClient->getStatus(); LOGE_IF(err, "Surface (identity=%d) state = %d", mIdentity, err); if (!err && buffer->handle != NULL) { @@ -869,5 +905,44 @@ status_t Surface::getBufferLocked(int index, int usage) return err; } +// ---------------------------------------------------------------------------- +Surface::BufferInfo::BufferInfo() + : mWidth(0), mHeight(0), mFormat(0), + mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0) +{ +} + +void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) { + if ((mWidth != w) || (mHeight != h) || (mFormat != format)) { + mWidth = w; + mHeight = h; + mFormat = format; + mDirty |= GEOMETRY; + } +} + +void Surface::BufferInfo::set(uint32_t usage) { + mUsage = usage; +} + +void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight, + uint32_t *pFormat, uint32_t *pUsage) const { + *pWidth = mWidth; + *pHeight = mHeight; + *pFormat = mFormat; + *pUsage = mUsage; +} + +bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const { + // make sure we AT LEAST have the usage flags we want + if (mDirty || buffer==0 || + ((buffer->usage & mUsage) != mUsage)) { + mDirty = 0; + return false; + } + return true; +} + +// ---------------------------------------------------------------------------- }; // namespace android |