diff options
-rw-r--r-- | include/gui/BufferQueueProducer.h | 4 | ||||
-rw-r--r-- | include/gui/IGraphicBufferProducer.h | 13 | ||||
-rw-r--r-- | include/gui/Surface.h | 10 | ||||
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 55 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferProducer.cpp | 25 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 7 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/MonitoredProducer.cpp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/MonitoredProducer.h | 2 |
10 files changed, 129 insertions, 0 deletions
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index 9df3633..fe8a308 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -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); diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index d9e116b..9b96b2b 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -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; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/Surface.h b/include/gui/Surface.h index d8e9756..dcfe74f 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -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(); 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); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c415560..3442c65 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -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; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 0ae9804..5c00ab4 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -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 diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index d0e81bc..8739682 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -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(); } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index f034e39..f6ccc51 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -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: |