diff options
author | Dan Stoza <stoza@google.com> | 2015-04-16 17:28:43 -0700 |
---|---|---|
committer | Dan Stoza <stoza@google.com> | 2015-04-23 15:28:12 -0700 |
commit | 9de7293b0a1b01ebe6fb1ab4a498f144adc8029f (patch) | |
tree | f8ee5b60b00fb545ea324e94fdb4b246b0943f16 /libs | |
parent | 0de7ea752900b5da29ad19c2799040235477f3c5 (diff) | |
download | frameworks_native-9de7293b0a1b01ebe6fb1ab4a498f144adc8029f.zip frameworks_native-9de7293b0a1b01ebe6fb1ab4a498f144adc8029f.tar.gz frameworks_native-9de7293b0a1b01ebe6fb1ab4a498f144adc8029f.tar.bz2 |
libgui: Allow an IGBProducer to disable allocation
Adds a new method IGBP::allowAllocation, which controls whether
dequeueBuffer is permitted to allocate a new buffer. If allocation is
disallowed, dequeueBuffer will block or return an error as it
normally would (as controlled by *ControlledByApp).
If there are free buffers, but they are not of the correct dimensions,
format, or usage, they may be freed if a more suitable buffer is not
found first.
Bug: 19801715
Change-Id: I0d604958b78b2fd775c2547690301423f9a52165
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/BufferQueueCore.cpp | 3 | ||||
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 68 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferProducer.cpp | 23 | ||||
-rw-r--r-- | libs/gui/tests/BufferQueue_test.cpp | 36 | ||||
-rw-r--r-- | libs/ui/GraphicBuffer.cpp | 10 |
5 files changed, 118 insertions, 22 deletions
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 29415c9..bc75ca7 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -69,7 +69,8 @@ BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : mFrameCounter(0), mTransformHint(0), mIsAllocating(false), - mIsAllocatingCondition() + mIsAllocatingCondition(), + mAllowAllocation(true) { if (allocator == NULL) { sp<ISurfaceComposer> composer(ComposerService::getComposerService()); diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index a27d5f0..86e45c8 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -219,7 +219,7 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, auto slot = mCore->mFreeBuffers.begin(); *found = *slot; mCore->mFreeBuffers.erase(slot); - } else if (!mCore->mFreeSlots.empty()) { + } else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) { auto slot = mCore->mFreeSlots.begin(); // Only return free slots up to the max buffer count if (*slot < maxBufferCount) { @@ -285,17 +285,39 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, // Enable the usage bits the consumer requested usage |= mCore->mConsumerUsageBits; - int found; - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; + const bool useDefaultSize = !width && !height; + if (useDefaultSize) { + width = mCore->mDefaultWidth; + height = mCore->mDefaultHeight; } - // This should not happen - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; + int found = BufferItem::INVALID_BUFFER_SLOT; + while (found == BufferItem::INVALID_BUFFER_SLOT) { + status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, + &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; @@ -303,20 +325,11 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, attachedByConsumer = mSlots[found].mAttachedByConsumer; - const bool useDefaultSize = !width && !height; - if (useDefaultSize) { - width = mCore->mDefaultWidth; - height = mCore->mDefaultHeight; - } - mSlots[found].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); if ((buffer == NULL) || - (static_cast<uint32_t>(buffer->width) != width) || - (static_cast<uint32_t>(buffer->height) != height) || - (buffer->format != format) || - ((static_cast<uint32_t>(buffer->usage) & usage) != usage)) + buffer->needsReallocation(width, height, format, usage)) { mSlots[found].mAcquireCalled = false; mSlots[found].mGraphicBuffer = NULL; @@ -933,6 +946,12 @@ void BufferQueueProducer::allocateBuffers(bool async, uint32_t width, Mutex::Autolock lock(mCore->mMutex); mCore->waitWhileAllocatingLocked(); + if (!mCore->mAllowAllocation) { + BQ_LOGE("allocateBuffers: allocation is not allowed for this " + "BufferQueue"); + return; + } + int currentBufferCount = 0; for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) { 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 */) { // 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 diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index b7982a9..7093ffa 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -46,6 +46,7 @@ enum { DISCONNECT, SET_SIDEBAND_STREAM, ALLOCATE_BUFFERS, + ALLOW_ALLOCATION, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -271,6 +272,18 @@ public: 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 @@ -418,7 +431,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } - case ALLOCATE_BUFFERS: + case ALLOCATE_BUFFERS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool async = static_cast<bool>(data.readInt32()); uint32_t width = data.readUint32(); @@ -427,6 +440,14 @@ status_t BnGraphicBufferProducer::onTransact( uint32_t usage = data.readUint32(); allocateBuffers(async, width, height, format, usage); 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); } diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index c38c797..112dcb9 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -364,4 +364,40 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { 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 diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 638ac62..d51d514 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -152,6 +152,16 @@ status_t GraphicBuffer::reallocate(uint32_t inWidth, uint32_t inHeight, 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, PixelFormat inFormat, uint32_t inUsage) { |