Merge "BufferQueue: Add allocateBuffers method"

This commit is contained in:
Dan Stoza 2014-06-30 17:38:44 +00:00 committed by Android (Google) Code Review
commit dc56bf721a
10 changed files with 129 additions and 0 deletions

View File

@ -169,6 +169,10 @@ public:
// handle if any.
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
// See IGraphicBufferProducer::allocateBuffers
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage);
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);

View File

@ -429,6 +429,19 @@ public:
// Passing NULL or a different stream handle will detach the previous
// handle if any.
virtual status_t setSidebandStream(const sp<NativeHandle>& stream) = 0;
// Allocates buffers based on the given dimensions/format.
//
// This function will allocate up to the maximum number of buffers
// permitted by the current BufferQueue configuration. It will use the
// given format, dimensions, and usage bits, which are interpreted in the
// same way as for dequeueBuffer, and the async flag must be set the same
// way as for dequeueBuffer to ensure that the correct number of buffers are
// allocated. This is most useful to avoid an allocation delay during
// dequeueBuffer. If there are already the maximum number of buffers
// allocated, this function has no effect.
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage) = 0;
};
// ----------------------------------------------------------------------------

View File

@ -91,6 +91,16 @@ public:
*/
void setSidebandStream(const sp<NativeHandle>& stream);
/* Allocates buffers based on the current dimensions/format.
*
* This function will allocate up to the maximum number of buffers
* permitted by the current BufferQueue configuration. It will use the
* default format and dimensions. This is most useful to avoid an allocation
* delay during dequeueBuffer. If there are already the maximum number of
* buffers allocated, this function has no effect.
*/
void allocateBuffers();
protected:
virtual ~Surface();

View File

@ -331,6 +331,7 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
status_t error;
BQ_LOGV("dequeueBuffer: allocating a new buffer for slot %d", *outSlot);
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &error));
if (graphicBuffer == NULL) {
@ -852,6 +853,60 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream)
return NO_ERROR;
}
void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
uint32_t height, uint32_t format, uint32_t usage) {
Vector<int> freeSlots;
Mutex::Autolock lock(mCore->mMutex);
int currentBufferCount = 0;
for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
if (mSlots[slot].mGraphicBuffer != NULL) {
++currentBufferCount;
} else {
if (mSlots[slot].mBufferState != BufferSlot::FREE) {
BQ_LOGE("allocateBuffers: slot %d without buffer is not FREE",
slot);
continue;
}
freeSlots.push_front(slot);
}
}
int maxBufferCount = mCore->getMaxBufferCountLocked(async);
BQ_LOGV("allocateBuffers: allocating from %d buffers up to %d buffers",
currentBufferCount, maxBufferCount);
for (; currentBufferCount < maxBufferCount; ++currentBufferCount) {
if (freeSlots.empty()) {
BQ_LOGE("allocateBuffers: ran out of free slots");
return;
}
width = width > 0 ? width : mCore->mDefaultWidth;
height = height > 0 ? height : mCore->mDefaultHeight;
format = format != 0 ? format : mCore->mDefaultBufferFormat;
usage |= mCore->mConsumerUsageBits;
status_t result = NO_ERROR;
sp<GraphicBuffer> graphicBuffer(mCore->mAllocator->createGraphicBuffer(
width, height, format, usage, &result));
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %u)", width, height, format, usage);
return;
}
int slot = freeSlots[freeSlots.size() - 1];
mCore->freeBufferLocked(slot); // Clean up the slot first
mSlots[slot].mGraphicBuffer = graphicBuffer;
mSlots[slot].mFrameNumber = 0;
mSlots[slot].mFence = Fence::NO_FENCE;
BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
freeSlots.pop();
}
}
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove

View File

@ -45,6 +45,7 @@ enum {
CONNECT,
DISCONNECT,
SET_SIDEBAND_STREAM,
ALLOCATE_BUFFERS,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@ -252,6 +253,21 @@ public:
}
return result;
}
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(static_cast<int32_t>(async));
data.writeInt32(static_cast<int32_t>(width));
data.writeInt32(static_cast<int32_t>(height));
data.writeInt32(static_cast<int32_t>(format));
data.writeInt32(static_cast<int32_t>(usage));
status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply);
if (result != NO_ERROR) {
ALOGE("allocateBuffers failed to transact: %d", result);
}
}
};
IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
@ -394,6 +410,15 @@ status_t BnGraphicBufferProducer::onTransact(
reply->writeInt32(result);
return NO_ERROR;
} break;
case ALLOCATE_BUFFERS:
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = static_cast<bool>(data.readInt32());
uint32_t width = static_cast<uint32_t>(data.readInt32());
uint32_t height = static_cast<uint32_t>(data.readInt32());
uint32_t format = static_cast<uint32_t>(data.readInt32());
uint32_t usage = static_cast<uint32_t>(data.readInt32());
allocateBuffers(async, width, height, format, usage);
return NO_ERROR;
}
return BBinder::onTransact(code, data, reply, flags);
}

View File

@ -91,6 +91,13 @@ void Surface::setSidebandStream(const sp<NativeHandle>& stream) {
mGraphicBufferProducer->setSidebandStream(stream);
}
void Surface::allocateBuffers() {
uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
mGraphicBufferProducer->allocateBuffers(mSwapIntervalZero, mReqWidth,
mReqHeight, mReqFormat, mReqUsage);
}
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
return c->setSwapInterval(interval);

View File

@ -486,6 +486,12 @@ status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stre
return INVALID_OPERATION;
}
void VirtualDisplaySurface::allocateBuffers(bool /* async */,
uint32_t /* width */, uint32_t /* height */, uint32_t /* format */,
uint32_t /* usage */) {
// TODO: Should we actually allocate buffers for a virtual display?
}
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;

View File

@ -112,6 +112,8 @@ private:
int api, bool producerControlledByApp, QueueBufferOutput* output);
virtual status_t disconnect(int api);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage);
//
// Utility methods

View File

@ -105,6 +105,11 @@ status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) {
return mProducer->setSidebandStream(stream);
}
void MonitoredProducer::allocateBuffers(bool async, uint32_t width,
uint32_t height, uint32_t format, uint32_t usage) {
mProducer->allocateBuffers(async, width, height, format, usage);
}
IBinder* MonitoredProducer::onAsBinder() {
return mProducer->asBinder().get();
}

View File

@ -51,6 +51,8 @@ public:
bool producerControlledByApp, QueueBufferOutput* output);
virtual status_t disconnect(int api);
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
uint32_t format, uint32_t usage);
virtual IBinder* onAsBinder();
private: