2 * Copyright 2014 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #define LOG_TAG "BufferQueueCore"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 //#define LOG_NDEBUG 0
21 #define EGL_EGLEXT_PROTOTYPES
24 #define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0)
26 #define VALIDATE_CONSISTENCY()
31 #include <cutils/properties.h>
32 #include <cutils/atomic.h>
34 #include <gui/BufferItem.h>
35 #include <gui/BufferQueueCore.h>
36 #include <gui/IConsumerListener.h>
37 #include <gui/IProducerListener.h>
38 #include <gui/ISurfaceComposer.h>
39 #include <private/gui/ComposerService.h>
41 #include <system/window.h>
45 static String8 getUniqueName() {
46 static volatile int32_t counter = 0;
47 return String8::format("unnamed-%d-%d", getpid(),
48 android_atomic_inc(&counter));
51 static uint64_t getUniqueId() {
52 static std::atomic<uint32_t> counter{0};
53 static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
54 return id | counter++;
57 BufferQueueCore::BufferQueueCore() :
60 mConsumerControlledByApp(false),
61 mConsumerName(getUniqueName()),
63 mConsumerUsageBits(0),
64 mConsumerIsProtected(false),
65 mConnectedApi(NO_CONNECTED_API),
67 mConnectedProducerListener(),
75 mDequeueBufferCannotBlock(false),
76 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
79 mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
80 mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
81 mMaxAcquiredBufferCount(1),
82 mMaxDequeuedBufferCount(1),
83 mBufferHasBeenQueued(false),
87 mIsAllocatingCondition(),
88 mAllowAllocation(true),
92 mSharedBufferMode(false),
94 mSharedBufferSlot(INVALID_BUFFER_SLOT),
95 mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
96 HAL_DATASPACE_UNKNOWN),
97 mLastQueuedSlot(INVALID_BUFFER_SLOT),
98 mUniqueId(getUniqueId())
100 int numStartingBuffers = getMaxBufferCountLocked();
101 for (int s = 0; s < numStartingBuffers; s++) {
102 mFreeSlots.insert(s);
104 for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
106 mUnusedSlots.push_front(s);
110 BufferQueueCore::~BufferQueueCore() {}
112 void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
113 Mutex::Autolock lock(mMutex);
115 outResult->appendFormat("%s- BufferQueue ", prefix.string());
116 outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
117 mMaxAcquiredBufferCount, mMaxDequeuedBufferCount);
118 outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(),
119 mDequeueBufferCannotBlock, mAsyncMode);
120 outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
121 mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
122 outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
125 outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
126 Fifo::const_iterator current(mQueue.begin());
127 while (current != mQueue.end()) {
128 double timestamp = current->mTimestamp / 1e9;
129 outResult->appendFormat("%s %02d:%p ", prefix.string(), current->mSlot,
130 current->mGraphicBuffer.get());
131 outResult->appendFormat("crop=[%d,%d,%d,%d] ", current->mCrop.left, current->mCrop.top,
132 current->mCrop.right, current->mCrop.bottom);
133 outResult->appendFormat("xform=0x%02x time=%.4f scale=%s\n", current->mTransform, timestamp,
134 BufferItem::scalingModeName(current->mScalingMode));
138 outResult->appendFormat("%sSlots:\n", prefix.string());
139 for (int s : mActiveBuffers) {
140 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
141 // A dequeued buffer might be null if it's still being allocated
143 outResult->appendFormat("%s %s[%02d:%p] ", prefix.string(),
144 (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
146 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
147 buffer->handle, mSlots[s].mFrameNumber);
148 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
149 buffer->stride, buffer->format);
151 outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
152 outResult->appendFormat("state=%-8s frame=%" PRIu64 "\n",
153 mSlots[s].mBufferState.string(), mSlots[s].mFrameNumber);
156 for (int s : mFreeBuffers) {
157 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
158 outResult->appendFormat("%s [%02d:%p] ", prefix.string(), s, buffer.get());
159 outResult->appendFormat("state=%-8s %p frame=%" PRIu64, mSlots[s].mBufferState.string(),
160 buffer->handle, mSlots[s].mFrameNumber);
161 outResult->appendFormat(" [%4ux%4u:%4u,%3X]\n", buffer->width, buffer->height,
162 buffer->stride, buffer->format);
165 for (int s : mFreeSlots) {
166 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
167 outResult->appendFormat("%s [%02d:%p] state=%-8s\n", prefix.string(), s, buffer.get(),
168 mSlots[s].mBufferState.string());
172 int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
173 // If dequeueBuffer is allowed to error out, we don't have to add an
175 if (mAsyncMode || mDequeueBufferCannotBlock) {
176 return mMaxAcquiredBufferCount + 1;
179 return mMaxAcquiredBufferCount;
182 int BufferQueueCore::getMinMaxBufferCountLocked() const {
183 return getMinUndequeuedBufferCountLocked() + 1;
186 int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode,
187 bool dequeueBufferCannotBlock, int maxBufferCount) const {
188 int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
189 ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0);
190 maxCount = std::min(maxBufferCount, maxCount);
194 int BufferQueueCore::getMaxBufferCountLocked() const {
195 int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
196 ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
198 // limit maxBufferCount by mMaxBufferCount always
199 maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
201 return maxBufferCount;
204 void BufferQueueCore::clearBufferSlotLocked(int slot) {
205 BQ_LOGV("clearBufferSlotLocked: slot %d", slot);
207 mSlots[slot].mGraphicBuffer.clear();
208 mSlots[slot].mBufferState.reset();
209 mSlots[slot].mRequestBufferCalled = false;
210 mSlots[slot].mFrameNumber = 0;
211 mSlots[slot].mAcquireCalled = false;
212 mSlots[slot].mNeedsReallocation = true;
214 // Destroy fence as BufferQueue now takes ownership
215 if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
216 eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
217 mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
219 mSlots[slot].mFence = Fence::NO_FENCE;
220 mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
222 if (mLastQueuedSlot == slot) {
223 mLastQueuedSlot = INVALID_BUFFER_SLOT;
227 void BufferQueueCore::freeAllBuffersLocked() {
228 for (int s : mFreeSlots) {
229 clearBufferSlotLocked(s);
232 for (int s : mFreeBuffers) {
233 mFreeSlots.insert(s);
234 clearBufferSlotLocked(s);
236 mFreeBuffers.clear();
238 for (int s : mActiveBuffers) {
239 mFreeSlots.insert(s);
240 clearBufferSlotLocked(s);
242 mActiveBuffers.clear();
244 for (auto& b : mQueue) {
247 // We set this to false to force the BufferQueue to resend the buffer
248 // handle upon acquire, since if we're here due to a producer
249 // disconnect, the consumer will have been told to purge its cache of
250 // slot-to-buffer-handle mappings and will not be able to otherwise
251 // obtain a valid buffer handle.
252 b.mAcquireCalled = false;
255 VALIDATE_CONSISTENCY();
258 void BufferQueueCore::discardFreeBuffersLocked() {
259 for (int s : mFreeBuffers) {
260 mFreeSlots.insert(s);
261 clearBufferSlotLocked(s);
263 mFreeBuffers.clear();
265 VALIDATE_CONSISTENCY();
268 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
270 // If we're going to fail, do so before modifying anything
271 if (delta > static_cast<int>(mUnusedSlots.size())) {
275 if (mUnusedSlots.empty()) {
278 int slot = mUnusedSlots.back();
279 mUnusedSlots.pop_back();
280 mFreeSlots.insert(slot);
284 // If we're going to fail, do so before modifying anything
285 if (-delta > static_cast<int>(mFreeSlots.size() +
286 mFreeBuffers.size())) {
290 if (!mFreeSlots.empty()) {
291 auto slot = mFreeSlots.begin();
292 clearBufferSlotLocked(*slot);
293 mUnusedSlots.push_back(*slot);
294 mFreeSlots.erase(slot);
295 } else if (!mFreeBuffers.empty()) {
296 int slot = mFreeBuffers.back();
297 clearBufferSlotLocked(slot);
298 mUnusedSlots.push_back(slot);
299 mFreeBuffers.pop_back();
309 void BufferQueueCore::waitWhileAllocatingLocked() const {
311 while (mIsAllocating) {
312 mIsAllocatingCondition.wait(mMutex);
317 void BufferQueueCore::validateConsistencyLocked() const {
318 static const useconds_t PAUSE_TIME = 0;
319 int allocatedSlots = 0;
320 for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
321 bool isInFreeSlots = mFreeSlots.count(slot) != 0;
322 bool isInFreeBuffers =
323 std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
325 bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
326 bool isInUnusedSlots =
327 std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
330 if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
334 if (isInUnusedSlots) {
336 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
339 if (isInFreeBuffers) {
340 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
343 if (isInActiveBuffers) {
344 BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
348 if (!mSlots[slot].mBufferState.isFree()) {
349 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
352 if (mSlots[slot].mGraphicBuffer != NULL) {
353 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
357 } else if (isInFreeSlots) {
358 if (isInUnusedSlots) {
359 BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
362 if (isInFreeBuffers) {
363 BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
366 if (isInActiveBuffers) {
367 BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
370 if (!mSlots[slot].mBufferState.isFree()) {
371 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
374 if (mSlots[slot].mGraphicBuffer != NULL) {
375 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
379 } else if (isInFreeBuffers) {
380 if (isInUnusedSlots) {
381 BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
385 BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
388 if (isInActiveBuffers) {
389 BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
393 if (!mSlots[slot].mBufferState.isFree()) {
394 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
397 if (mSlots[slot].mGraphicBuffer == NULL) {
398 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
401 } else if (isInActiveBuffers) {
402 if (isInUnusedSlots) {
403 BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
408 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
411 if (isInFreeBuffers) {
412 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
416 if (mSlots[slot].mBufferState.isFree() &&
417 !mSlots[slot].mBufferState.isShared()) {
418 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
421 if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
422 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
426 BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
427 "mFreeBuffers, or mActiveBuffers", slot);
432 if (allocatedSlots != getMaxBufferCountLocked()) {
433 BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
434 "Should be %d (%zu free slots, %zu free buffers, "
435 "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
436 getMaxBufferCountLocked(), mFreeSlots.size(),
437 mFreeBuffers.size(), mActiveBuffers.size(),
438 mUnusedSlots.size());
443 } // namespace android