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
This commit is contained in:
Mathias Agopian 2010-05-21 17:24:35 -07:00
parent a0b3f1d2eb
commit a138f89c5e
11 changed files with 274 additions and 94 deletions

View File

@ -279,7 +279,8 @@ public:
ssize_t retireAndLock();
status_t unlock(int buffer);
void setStatus(status_t status);
status_t reallocate();
status_t reallocateAll();
status_t reallocateAllExcept(int buffer);
status_t assertReallocate(int buffer);
int32_t getQueuedCount() const;
Region getDirtyRegion(int buffer) const;

View File

@ -53,7 +53,8 @@ protected:
public:
DECLARE_META_INTERFACE(Surface);
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage) = 0;
virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
virtual status_t setBufferCount(int bufferCount) = 0;
class BufferHeap {

View File

@ -36,6 +36,7 @@ namespace android {
// ---------------------------------------------------------------------------
class GraphicBuffer;
class GraphicBufferMapper;
class IOMX;
class Rect;
@ -213,12 +214,14 @@ private:
int dispatch_disconnect(va_list args);
int dispatch_crop(va_list args);
int dispatch_set_buffer_count(va_list args);
int dispatch_set_buffers_geometry(va_list args);
void setUsage(uint32_t reqUsage);
int connect(int api);
int disconnect(int api);
int crop(Rect const* rect);
int setBufferCount(int bufferCount);
int setBuffersGeometry(int w, int h, int format);
/*
* private stuff...
@ -231,12 +234,34 @@ private:
inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
status_t getBufferLocked(int index, int usage);
status_t getBufferLocked(int index,
uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
uint32_t getUsage() const;
int getConnectedApi() const;
bool needNewBuffer(int bufIdx,
uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const;
class BufferInfo {
uint32_t mWidth;
uint32_t mHeight;
uint32_t mFormat;
uint32_t mUsage;
mutable uint32_t mDirty;
enum {
GEOMETRY = 0x01
};
public:
BufferInfo();
void set(uint32_t w, uint32_t h, uint32_t format);
void set(uint32_t usage);
void get(uint32_t *pWidth, uint32_t *pHeight,
uint32_t *pFormat, uint32_t *pUsage) const;
bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
};
// constants
sp<SurfaceComposerClient> mClient;
sp<ISurface> mSurface;
@ -249,13 +274,12 @@ private:
// protected by mSurfaceLock
Rect mSwapRectangle;
uint32_t mUsage;
int mConnected;
Rect mNextBufferCrop;
BufferInfo mBufferInfo;
// protected by mSurfaceLock. These are also used from lock/unlock
// but in that case, they must be called form the same thread.
sp<GraphicBuffer> mBuffers[2];
mutable Region mDirtyRegion;
// must be used from the lock/unlock thread
@ -264,6 +288,9 @@ private:
mutable Region mOldDirtyRegion;
bool mReserved;
// only used from dequeueBuffer()
Vector< sp<GraphicBuffer> > mBuffers;
// query() must be called from dequeueBuffer() thread
uint32_t mWidth;
uint32_t mHeight;

View File

@ -82,6 +82,7 @@ enum {
NATIVE_WINDOW_DISCONNECT,
NATIVE_WINDOW_SET_CROP,
NATIVE_WINDOW_SET_BUFFER_COUNT,
NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
};
/* parameter for NATIVE_WINDOW_[DIS]CONNECT */
@ -192,6 +193,7 @@ typedef struct android_native_window_t
* NATIVE_WINDOW_DISCONNECT
* NATIVE_WINDOW_SET_CROP
* NATIVE_WINDOW_SET_BUFFER_COUNT
* NATIVE_WINDOW_SET_BUFFERS_GEOMETRY
*
*/
@ -273,6 +275,25 @@ static inline int native_window_set_buffer_count(
return window->perform(window, NATIVE_WINDOW_SET_BUFFER_COUNT, bufferCount);
}
/*
* native_window_set_buffers_geometry(..., int w, int h, int format)
* All buffers dequeued after this call will have the geometry specified.
* In particular, all buffers will have a fixed-size, independent form the
* native-window size. They will be appropriately scaled to the window-size
* upon composition.
*
* If all parameters are 0, the normal behavior is restored. That is,
* dequeued buffers following this call will be sized to the window's size.
*
*/
static inline int native_window_set_buffers_geometry(
android_native_window_t* window,
int w, int h, int format)
{
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_GEOMETRY,
w, h, format);
}
// ---------------------------------------------------------------------------
/* FIXME: this is legacy for pixmaps */

View File

@ -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();
}
}
return buffer;
}
@ -330,8 +344,10 @@ 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)",
@ -339,6 +355,7 @@ uint32_t Layer::doTransaction(uint32_t flags)
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
@ -357,12 +374,16 @@ uint32_t Layer::doTransaction(uint32_t flags)
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();
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;
}

View File

@ -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;
};
// ---------------------------------------------------------------------------

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -527,7 +527,7 @@ void SharedBufferServer::setStatus(status_t status)
}
}
status_t SharedBufferServer::reallocate()
status_t SharedBufferServer::reallocateAll()
{
RWLock::AutoRLock _l(mLock);
@ -537,6 +537,18 @@ status_t SharedBufferServer::reallocate()
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;
}
int32_t SharedBufferServer::getQueuedCount() const
{
SharedBufferStack& stack( *mSharedStack );

View File

@ -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