summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2015-04-16 17:28:43 -0700
committerDan Stoza <stoza@google.com>2015-04-23 15:28:12 -0700
commit9de7293b0a1b01ebe6fb1ab4a498f144adc8029f (patch)
treef8ee5b60b00fb545ea324e94fdb4b246b0943f16 /libs
parent0de7ea752900b5da29ad19c2799040235477f3c5 (diff)
downloadframeworks_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.cpp3
-rw-r--r--libs/gui/BufferQueueProducer.cpp68
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp23
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp36
-rw-r--r--libs/ui/GraphicBuffer.cpp10
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)
{