summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorDan Stoza <stoza@google.com>2014-06-20 13:13:57 -0700
committerDan Stoza <stoza@google.com>2014-06-20 13:13:57 -0700
commit29a3e90879fd96404c971e7187cd0e05927bbce0 (patch)
tree024503f644be306ea3eb99e14b8847d454bdbf51 /libs
parenta317f27b7bf49e2e7b2b443223c07fb8c7c3ac3f (diff)
downloadframeworks_native-29a3e90879fd96404c971e7187cd0e05927bbce0.zip
frameworks_native-29a3e90879fd96404c971e7187cd0e05927bbce0.tar.gz
frameworks_native-29a3e90879fd96404c971e7187cd0e05927bbce0.tar.bz2
BufferQueue: Add allocateBuffers method
This adds an allocateBuffers method to BufferQueue, which instructs it to allocate up to the maximum number of buffers allowed by the current configuration. The goal is that this method can be called ahead of render time, which will prevent dequeueBuffers from blocking in allocation and inducing jank. This interface is also plumbed up to the native Surface (and, in another change, up to the Java Surface and ThreadedRenderer). Bug: 11792166 Change-Id: I4aa96b4351ea1c95ed5db228ca3ef98303229c74
Diffstat (limited to 'libs')
-rw-r--r--libs/gui/BufferQueueProducer.cpp55
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp25
-rw-r--r--libs/gui/Surface.cpp7
3 files changed, 87 insertions, 0 deletions
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 7017ddf..70c3ff3 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -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
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index aa6acb9..8d9a800 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -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);
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 88c45b2..8cb9189 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -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);