Merge "libgui: Allow an IGBProducer to disable allocation"
This commit is contained in:
commit
958f501189
@ -266,6 +266,10 @@ private:
|
|||||||
// mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
|
// mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
|
||||||
// becomes false.
|
// becomes false.
|
||||||
mutable Condition mIsAllocatingCondition;
|
mutable Condition mIsAllocatingCondition;
|
||||||
|
|
||||||
|
// mAllowAllocation determines whether dequeueBuffer is allowed to allocate
|
||||||
|
// new buffers
|
||||||
|
bool mAllowAllocation;
|
||||||
}; // class BufferQueueCore
|
}; // class BufferQueueCore
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
@ -172,6 +172,9 @@ public:
|
|||||||
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
||||||
PixelFormat format, uint32_t usage);
|
PixelFormat format, uint32_t usage);
|
||||||
|
|
||||||
|
// See IGraphicBufferProducer::allowAllocation
|
||||||
|
virtual status_t allowAllocation(bool allow);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This is required by the IBinder::DeathRecipient interface
|
// This is required by the IBinder::DeathRecipient interface
|
||||||
virtual void binderDied(const wp<IBinder>& who);
|
virtual void binderDied(const wp<IBinder>& who);
|
||||||
|
@ -458,6 +458,18 @@ public:
|
|||||||
// allocated, this function has no effect.
|
// allocated, this function has no effect.
|
||||||
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
||||||
PixelFormat format, uint32_t usage) = 0;
|
PixelFormat format, uint32_t usage) = 0;
|
||||||
|
|
||||||
|
// Sets whether dequeueBuffer is allowed to allocate new buffers.
|
||||||
|
//
|
||||||
|
// Normally dequeueBuffer does not discriminate between free slots which
|
||||||
|
// already have an allocated buffer and those which do not, and will
|
||||||
|
// allocate a new buffer if the slot doesn't have a buffer or if the slot's
|
||||||
|
// buffer doesn't match the requested size, format, or usage. This method
|
||||||
|
// allows the producer to restrict the eligible slots to those which already
|
||||||
|
// have an allocated buffer of the correct size, format, and usage. If no
|
||||||
|
// eligible slot is available, dequeueBuffer will block or return an error
|
||||||
|
// as usual.
|
||||||
|
virtual status_t allowAllocation(bool allow) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -97,6 +97,9 @@ public:
|
|||||||
status_t reallocate(uint32_t inWidth, uint32_t inHeight,
|
status_t reallocate(uint32_t inWidth, uint32_t inHeight,
|
||||||
PixelFormat inFormat, uint32_t inUsage);
|
PixelFormat inFormat, uint32_t inUsage);
|
||||||
|
|
||||||
|
bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
|
||||||
|
PixelFormat inFormat, uint32_t inUsage);
|
||||||
|
|
||||||
status_t lock(uint32_t inUsage, void** vaddr);
|
status_t lock(uint32_t inUsage, void** vaddr);
|
||||||
status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
|
status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
|
||||||
// For HAL_PIXEL_FORMAT_YCbCr_420_888
|
// For HAL_PIXEL_FORMAT_YCbCr_420_888
|
||||||
|
@ -69,7 +69,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
|
|||||||
mFrameCounter(0),
|
mFrameCounter(0),
|
||||||
mTransformHint(0),
|
mTransformHint(0),
|
||||||
mIsAllocating(false),
|
mIsAllocating(false),
|
||||||
mIsAllocatingCondition()
|
mIsAllocatingCondition(),
|
||||||
|
mAllowAllocation(true)
|
||||||
{
|
{
|
||||||
if (allocator == NULL) {
|
if (allocator == NULL) {
|
||||||
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
|
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
|
||||||
|
@ -219,7 +219,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
|
|||||||
auto slot = mCore->mFreeBuffers.begin();
|
auto slot = mCore->mFreeBuffers.begin();
|
||||||
*found = *slot;
|
*found = *slot;
|
||||||
mCore->mFreeBuffers.erase(slot);
|
mCore->mFreeBuffers.erase(slot);
|
||||||
} else if (!mCore->mFreeSlots.empty()) {
|
} else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) {
|
||||||
auto slot = mCore->mFreeSlots.begin();
|
auto slot = mCore->mFreeSlots.begin();
|
||||||
// Only return free slots up to the max buffer count
|
// Only return free slots up to the max buffer count
|
||||||
if (*slot < maxBufferCount) {
|
if (*slot < maxBufferCount) {
|
||||||
@ -285,17 +285,39 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
|
|||||||
// Enable the usage bits the consumer requested
|
// Enable the usage bits the consumer requested
|
||||||
usage |= mCore->mConsumerUsageBits;
|
usage |= mCore->mConsumerUsageBits;
|
||||||
|
|
||||||
int found;
|
const bool useDefaultSize = !width && !height;
|
||||||
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
|
if (useDefaultSize) {
|
||||||
&found, &returnFlags);
|
width = mCore->mDefaultWidth;
|
||||||
if (status != NO_ERROR) {
|
height = mCore->mDefaultHeight;
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should not happen
|
int found = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
|
while (found == BufferItem::INVALID_BUFFER_SLOT) {
|
||||||
BQ_LOGE("dequeueBuffer: no available buffer slots");
|
status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
|
||||||
return -EBUSY;
|
&found, &returnFlags);
|
||||||
|
if (status != NO_ERROR) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should not happen
|
||||||
|
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
|
||||||
|
BQ_LOGE("dequeueBuffer: no available buffer slots");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
|
||||||
|
|
||||||
|
// If we are not allowed to allocate new buffers,
|
||||||
|
// waitForFreeSlotThenRelock must have returned a slot containing a
|
||||||
|
// buffer. If this buffer would require reallocation to meet the
|
||||||
|
// requested attributes, we free it and attempt to get another one.
|
||||||
|
if (!mCore->mAllowAllocation) {
|
||||||
|
if (buffer->needsReallocation(width, height, format, usage)) {
|
||||||
|
mCore->freeBufferLocked(found);
|
||||||
|
found = BufferItem::INVALID_BUFFER_SLOT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*outSlot = found;
|
*outSlot = found;
|
||||||
@ -303,20 +325,11 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot,
|
|||||||
|
|
||||||
attachedByConsumer = mSlots[found].mAttachedByConsumer;
|
attachedByConsumer = mSlots[found].mAttachedByConsumer;
|
||||||
|
|
||||||
const bool useDefaultSize = !width && !height;
|
|
||||||
if (useDefaultSize) {
|
|
||||||
width = mCore->mDefaultWidth;
|
|
||||||
height = mCore->mDefaultHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
|
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
|
||||||
|
|
||||||
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
|
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
|
||||||
if ((buffer == NULL) ||
|
if ((buffer == NULL) ||
|
||||||
(static_cast<uint32_t>(buffer->width) != width) ||
|
buffer->needsReallocation(width, height, format, usage))
|
||||||
(static_cast<uint32_t>(buffer->height) != height) ||
|
|
||||||
(buffer->format != format) ||
|
|
||||||
((static_cast<uint32_t>(buffer->usage) & usage) != usage))
|
|
||||||
{
|
{
|
||||||
mSlots[found].mAcquireCalled = false;
|
mSlots[found].mAcquireCalled = false;
|
||||||
mSlots[found].mGraphicBuffer = NULL;
|
mSlots[found].mGraphicBuffer = NULL;
|
||||||
@ -933,6 +946,12 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
|
|||||||
Mutex::Autolock lock(mCore->mMutex);
|
Mutex::Autolock lock(mCore->mMutex);
|
||||||
mCore->waitWhileAllocatingLocked();
|
mCore->waitWhileAllocatingLocked();
|
||||||
|
|
||||||
|
if (!mCore->mAllowAllocation) {
|
||||||
|
BQ_LOGE("allocateBuffers: allocation is not allowed for this "
|
||||||
|
"BufferQueue");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int currentBufferCount = 0;
|
int currentBufferCount = 0;
|
||||||
for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
|
||||||
if (mSlots[slot].mGraphicBuffer != NULL) {
|
if (mSlots[slot].mGraphicBuffer != NULL) {
|
||||||
@ -1027,6 +1046,15 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t BufferQueueProducer::allowAllocation(bool allow) {
|
||||||
|
ATRACE_CALL();
|
||||||
|
BQ_LOGV("allowAllocation: %s", allow ? "true" : "false");
|
||||||
|
|
||||||
|
Mutex::Autolock lock(mCore->mMutex);
|
||||||
|
mCore->mAllowAllocation = allow;
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
|
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
|
||||||
// If we're here, it means that a producer we were connected to died.
|
// 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
|
// We're guaranteed that we are still connected to it because we remove
|
||||||
|
@ -46,6 +46,7 @@ enum {
|
|||||||
DISCONNECT,
|
DISCONNECT,
|
||||||
SET_SIDEBAND_STREAM,
|
SET_SIDEBAND_STREAM,
|
||||||
ALLOCATE_BUFFERS,
|
ALLOCATE_BUFFERS,
|
||||||
|
ALLOW_ALLOCATION,
|
||||||
};
|
};
|
||||||
|
|
||||||
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
|
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
|
||||||
@ -271,6 +272,18 @@ public:
|
|||||||
ALOGE("allocateBuffers failed to transact: %d", result);
|
ALOGE("allocateBuffers failed to transact: %d", result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual status_t allowAllocation(bool allow) {
|
||||||
|
Parcel data, reply;
|
||||||
|
data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
|
||||||
|
data.writeInt32(static_cast<int32_t>(allow));
|
||||||
|
status_t result = remote()->transact(ALLOW_ALLOCATION, data, &reply);
|
||||||
|
if (result != NO_ERROR) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = reply.readInt32();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Out-of-line virtual method definition to trigger vtable emission in this
|
// Out-of-line virtual method definition to trigger vtable emission in this
|
||||||
@ -418,7 +431,7 @@ status_t BnGraphicBufferProducer::onTransact(
|
|||||||
reply->writeInt32(result);
|
reply->writeInt32(result);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
case ALLOCATE_BUFFERS:
|
case ALLOCATE_BUFFERS: {
|
||||||
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
|
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
|
||||||
bool async = static_cast<bool>(data.readInt32());
|
bool async = static_cast<bool>(data.readInt32());
|
||||||
uint32_t width = data.readUint32();
|
uint32_t width = data.readUint32();
|
||||||
@ -427,6 +440,14 @@ status_t BnGraphicBufferProducer::onTransact(
|
|||||||
uint32_t usage = data.readUint32();
|
uint32_t usage = data.readUint32();
|
||||||
allocateBuffers(async, width, height, format, usage);
|
allocateBuffers(async, width, height, format, usage);
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
case ALLOW_ALLOCATION: {
|
||||||
|
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
|
||||||
|
bool allow = static_cast<bool>(data.readInt32());
|
||||||
|
status_t result = allowAllocation(allow);
|
||||||
|
reply->writeInt32(result);
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return BBinder::onTransact(code, data, reply, flags);
|
return BBinder::onTransact(code, data, reply, flags);
|
||||||
}
|
}
|
||||||
|
@ -366,4 +366,40 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) {
|
|||||||
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
|
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(BufferQueueTest, TestDisallowingAllocation) {
|
||||||
|
createBufferQueue();
|
||||||
|
sp<DummyConsumer> dc(new DummyConsumer);
|
||||||
|
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
|
||||||
|
IGraphicBufferProducer::QueueBufferOutput output;
|
||||||
|
ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
|
||||||
|
NATIVE_WINDOW_API_CPU, true, &output));
|
||||||
|
|
||||||
|
static const uint32_t WIDTH = 320;
|
||||||
|
static const uint32_t HEIGHT = 240;
|
||||||
|
|
||||||
|
ASSERT_EQ(OK, mConsumer->setDefaultBufferSize(WIDTH, HEIGHT));
|
||||||
|
|
||||||
|
int slot;
|
||||||
|
sp<Fence> fence;
|
||||||
|
sp<GraphicBuffer> buffer;
|
||||||
|
// This should return an error since it would require an allocation
|
||||||
|
ASSERT_EQ(OK, mProducer->allowAllocation(false));
|
||||||
|
ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0,
|
||||||
|
0, GRALLOC_USAGE_SW_WRITE_OFTEN));
|
||||||
|
|
||||||
|
// This should succeed, now that we've lifted the prohibition
|
||||||
|
ASSERT_EQ(OK, mProducer->allowAllocation(true));
|
||||||
|
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
|
||||||
|
mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
|
||||||
|
GRALLOC_USAGE_SW_WRITE_OFTEN));
|
||||||
|
|
||||||
|
// Release the previous buffer back to the BufferQueue
|
||||||
|
mProducer->cancelBuffer(slot, fence);
|
||||||
|
|
||||||
|
// This should fail since we're requesting a different size
|
||||||
|
ASSERT_EQ(OK, mProducer->allowAllocation(false));
|
||||||
|
ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false,
|
||||||
|
WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
@ -152,6 +152,16 @@ status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight,
|
|||||||
return initSize(inWidth, inHeight, inFormat, inUsage);
|
return initSize(inWidth, inHeight, inFormat, inUsage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
|
||||||
|
PixelFormat inFormat, uint32_t inUsage)
|
||||||
|
{
|
||||||
|
if (static_cast<int>(inWidth) != width) return true;
|
||||||
|
if (static_cast<int>(inHeight) != height) return true;
|
||||||
|
if (inFormat != format) return true;
|
||||||
|
if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
|
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
|
||||||
PixelFormat inFormat, uint32_t inUsage)
|
PixelFormat inFormat, uint32_t inUsage)
|
||||||
{
|
{
|
||||||
|
@ -526,6 +526,10 @@ void VirtualDisplaySurface::allocateBuffers(bool /* async */,
|
|||||||
// TODO: Should we actually allocate buffers for a virtual display?
|
// TODO: Should we actually allocate buffers for a virtual display?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) {
|
||||||
|
return INVALID_OPERATION;
|
||||||
|
}
|
||||||
|
|
||||||
void VirtualDisplaySurface::updateQueueBufferOutput(
|
void VirtualDisplaySurface::updateQueueBufferOutput(
|
||||||
const QueueBufferOutput& qbo) {
|
const QueueBufferOutput& qbo) {
|
||||||
uint32_t w, h, transformHint, numPendingBuffers;
|
uint32_t w, h, transformHint, numPendingBuffers;
|
||||||
|
@ -115,6 +115,7 @@ private:
|
|||||||
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
|
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
|
||||||
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
||||||
PixelFormat format, uint32_t usage);
|
PixelFormat format, uint32_t usage);
|
||||||
|
virtual status_t allowAllocation(bool allow);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Utility methods
|
// Utility methods
|
||||||
|
@ -110,6 +110,10 @@ void MonitoredProducer::allocateBuffers(bool async, uint32_t width,
|
|||||||
mProducer->allocateBuffers(async, width, height, format, usage);
|
mProducer->allocateBuffers(async, width, height, format, usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t MonitoredProducer::allowAllocation(bool allow) {
|
||||||
|
return mProducer->allowAllocation(allow);
|
||||||
|
}
|
||||||
|
|
||||||
IBinder* MonitoredProducer::onAsBinder() {
|
IBinder* MonitoredProducer::onAsBinder() {
|
||||||
return IInterface::asBinder(mProducer).get();
|
return IInterface::asBinder(mProducer).get();
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ public:
|
|||||||
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
|
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
|
||||||
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
|
||||||
PixelFormat format, uint32_t usage);
|
PixelFormat format, uint32_t usage);
|
||||||
|
virtual status_t allowAllocation(bool allow);
|
||||||
virtual IBinder* onAsBinder();
|
virtual IBinder* onAsBinder();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user