1 /*
2 * Copyright 2014 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17 #define LOG_TAG "BufferQueueCore"
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19 //#define LOG_NDEBUG 0
20
21 #define EGL_EGLEXT_PROTOTYPES
22
23 #if DEBUG_ONLY_CODE
24 #define VALIDATE_CONSISTENCY() do { validateConsistencyLocked(); } while (0)
25 #else
26 #define VALIDATE_CONSISTENCY()
27 #endif
28
29 #include <inttypes.h>
30
31 #include <gui/BufferItem.h>
32 #include <gui/BufferQueueCore.h>
33 #include <gui/IConsumerListener.h>
34 #include <gui/IGraphicBufferAlloc.h>
35 #include <gui/IProducerListener.h>
36 #include <gui/ISurfaceComposer.h>
37 #include <private/gui/ComposerService.h>
38
39 namespace android {
40
getUniqueName()41 static String8 getUniqueName() {
42 static volatile int32_t counter = 0;
43 return String8::format("unnamed-%d-%d", getpid(),
44 android_atomic_inc(&counter));
45 }
46
getUniqueId()47 static uint64_t getUniqueId() {
48 static std::atomic<uint32_t> counter{0};
49 static uint64_t id = static_cast<uint64_t>(getpid()) << 32;
50 return id | counter++;
51 }
52
BufferQueueCore(const sp<IGraphicBufferAlloc> & allocator)53 BufferQueueCore::BufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) :
54 mAllocator(allocator),
55 mMutex(),
56 mIsAbandoned(false),
57 mConsumerControlledByApp(false),
58 mConsumerName(getUniqueName()),
59 mConsumerListener(),
60 mConsumerUsageBits(0),
61 mConnectedApi(NO_CONNECTED_API),
62 mConnectedProducerListener(),
63 mSlots(),
64 mQueue(),
65 mFreeSlots(),
66 mFreeBuffers(),
67 mUnusedSlots(),
68 mActiveBuffers(),
69 mDequeueCondition(),
70 mDequeueBufferCannotBlock(false),
71 mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
72 mDefaultWidth(1),
73 mDefaultHeight(1),
74 mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
75 mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
76 mMaxAcquiredBufferCount(1),
77 mMaxDequeuedBufferCount(1),
78 mBufferHasBeenQueued(false),
79 mFrameCounter(0),
80 mTransformHint(0),
81 mIsAllocating(false),
82 mIsAllocatingCondition(),
83 mAllowAllocation(true),
84 mBufferAge(0),
85 mGenerationNumber(0),
86 mAsyncMode(false),
87 mSharedBufferMode(false),
88 mAutoRefresh(false),
89 mSharedBufferSlot(INVALID_BUFFER_SLOT),
90 mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
91 HAL_DATASPACE_UNKNOWN),
92 mUniqueId(getUniqueId())
93 {
94 if (allocator == NULL) {
95 sp<ISurfaceComposer> composer(ComposerService::getComposerService());
96 mAllocator = composer->createGraphicBufferAlloc();
97 if (mAllocator == NULL) {
98 BQ_LOGE("createGraphicBufferAlloc failed");
99 }
100 }
101
102 int numStartingBuffers = getMaxBufferCountLocked();
103 for (int s = 0; s < numStartingBuffers; s++) {
104 mFreeSlots.insert(s);
105 }
106 for (int s = numStartingBuffers; s < BufferQueueDefs::NUM_BUFFER_SLOTS;
107 s++) {
108 mUnusedSlots.push_front(s);
109 }
110 }
111
~BufferQueueCore()112 BufferQueueCore::~BufferQueueCore() {}
113
dump(String8 & result,const char * prefix) const114 void BufferQueueCore::dump(String8& result, const char* prefix) const {
115 Mutex::Autolock lock(mMutex);
116
117 String8 fifo;
118 Fifo::const_iterator current(mQueue.begin());
119 while (current != mQueue.end()) {
120 fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
121 "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n",
122 current->mSlot, current->mGraphicBuffer.get(),
123 current->mCrop.left, current->mCrop.top, current->mCrop.right,
124 current->mCrop.bottom, current->mTransform, current->mTimestamp,
125 BufferItem::scalingModeName(current->mScalingMode));
126 ++current;
127 }
128
129 result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
130 "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d "
131 "mAsyncMode=%d, default-size=[%dx%d], default-format=%d, "
132 "transform-hint=%02x, FIFO(%zu)={%s}\n", prefix,
133 mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
134 mDequeueBufferCannotBlock, mAsyncMode, mDefaultWidth,
135 mDefaultHeight, mDefaultBufferFormat, mTransformHint, mQueue.size(),
136 fifo.string());
137
138 for (int s : mActiveBuffers) {
139 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
140 // A dequeued buffer might be null if it's still being allocated
141 if (buffer.get()) {
142 result.appendFormat("%s%s[%02d:%p] state=%-8s, %p "
143 "[%4ux%4u:%4u,%3X]\n", prefix,
144 (mSlots[s].mBufferState.isAcquired()) ? ">" : " ", s,
145 buffer.get(), mSlots[s].mBufferState.string(),
146 buffer->handle, buffer->width, buffer->height,
147 buffer->stride, buffer->format);
148 } else {
149 result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
150 buffer.get(), mSlots[s].mBufferState.string());
151 }
152 }
153 for (int s : mFreeBuffers) {
154 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
155 result.appendFormat("%s [%02d:%p] state=%-8s, %p [%4ux%4u:%4u,%3X]\n",
156 prefix, s, buffer.get(), mSlots[s].mBufferState.string(),
157 buffer->handle, buffer->width, buffer->height, buffer->stride,
158 buffer->format);
159 }
160
161 for (int s : mFreeSlots) {
162 const sp<GraphicBuffer>& buffer(mSlots[s].mGraphicBuffer);
163 result.appendFormat("%s [%02d:%p] state=%-8s\n", prefix, s,
164 buffer.get(), mSlots[s].mBufferState.string());
165 }
166 }
167
getMinUndequeuedBufferCountLocked() const168 int BufferQueueCore::getMinUndequeuedBufferCountLocked() const {
169 // If dequeueBuffer is allowed to error out, we don't have to add an
170 // extra buffer.
171 if (mAsyncMode || mDequeueBufferCannotBlock) {
172 return mMaxAcquiredBufferCount + 1;
173 }
174
175 return mMaxAcquiredBufferCount;
176 }
177
getMinMaxBufferCountLocked() const178 int BufferQueueCore::getMinMaxBufferCountLocked() const {
179 return getMinUndequeuedBufferCountLocked() + 1;
180 }
181
getMaxBufferCountLocked(bool asyncMode,bool dequeueBufferCannotBlock,int maxBufferCount) const182 int BufferQueueCore::getMaxBufferCountLocked(bool asyncMode,
183 bool dequeueBufferCannotBlock, int maxBufferCount) const {
184 int maxCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
185 ((asyncMode || dequeueBufferCannotBlock) ? 1 : 0);
186 maxCount = std::min(maxBufferCount, maxCount);
187 return maxCount;
188 }
189
getMaxBufferCountLocked() const190 int BufferQueueCore::getMaxBufferCountLocked() const {
191 int maxBufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
192 ((mAsyncMode || mDequeueBufferCannotBlock) ? 1 : 0);
193
194 // limit maxBufferCount by mMaxBufferCount always
195 maxBufferCount = std::min(mMaxBufferCount, maxBufferCount);
196
197 return maxBufferCount;
198 }
199
clearBufferSlotLocked(int slot)200 void BufferQueueCore::clearBufferSlotLocked(int slot) {
201 BQ_LOGV("clearBufferSlotLocked: slot %d", slot);
202
203 mSlots[slot].mGraphicBuffer.clear();
204 mSlots[slot].mBufferState.reset();
205 mSlots[slot].mRequestBufferCalled = false;
206 mSlots[slot].mFrameNumber = 0;
207 mSlots[slot].mAcquireCalled = false;
208 mSlots[slot].mNeedsReallocation = true;
209
210 // Destroy fence as BufferQueue now takes ownership
211 if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
212 eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
213 mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
214 }
215 mSlots[slot].mFence = Fence::NO_FENCE;
216 mSlots[slot].mEglDisplay = EGL_NO_DISPLAY;
217
218 if (mLastQueuedSlot == slot) {
219 mLastQueuedSlot = INVALID_BUFFER_SLOT;
220 }
221 }
222
freeAllBuffersLocked()223 void BufferQueueCore::freeAllBuffersLocked() {
224 for (int s : mFreeSlots) {
225 clearBufferSlotLocked(s);
226 }
227
228 for (int s : mFreeBuffers) {
229 mFreeSlots.insert(s);
230 clearBufferSlotLocked(s);
231 }
232 mFreeBuffers.clear();
233
234 for (int s : mActiveBuffers) {
235 mFreeSlots.insert(s);
236 clearBufferSlotLocked(s);
237 }
238 mActiveBuffers.clear();
239
240 for (auto& b : mQueue) {
241 b.mIsStale = true;
242 }
243
244 VALIDATE_CONSISTENCY();
245 }
246
discardFreeBuffersLocked()247 void BufferQueueCore::discardFreeBuffersLocked() {
248 for (int s : mFreeBuffers) {
249 mFreeSlots.insert(s);
250 clearBufferSlotLocked(s);
251 }
252 mFreeBuffers.clear();
253
254 VALIDATE_CONSISTENCY();
255 }
256
adjustAvailableSlotsLocked(int delta)257 bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
258 if (delta >= 0) {
259 // If we're going to fail, do so before modifying anything
260 if (delta > static_cast<int>(mUnusedSlots.size())) {
261 return false;
262 }
263 while (delta > 0) {
264 if (mUnusedSlots.empty()) {
265 return false;
266 }
267 int slot = mUnusedSlots.back();
268 mUnusedSlots.pop_back();
269 mFreeSlots.insert(slot);
270 delta--;
271 }
272 } else {
273 // If we're going to fail, do so before modifying anything
274 if (-delta > static_cast<int>(mFreeSlots.size() +
275 mFreeBuffers.size())) {
276 return false;
277 }
278 while (delta < 0) {
279 if (!mFreeSlots.empty()) {
280 auto slot = mFreeSlots.begin();
281 clearBufferSlotLocked(*slot);
282 mUnusedSlots.push_back(*slot);
283 mFreeSlots.erase(slot);
284 } else if (!mFreeBuffers.empty()) {
285 int slot = mFreeBuffers.back();
286 clearBufferSlotLocked(slot);
287 mUnusedSlots.push_back(slot);
288 mFreeBuffers.pop_back();
289 } else {
290 return false;
291 }
292 delta++;
293 }
294 }
295 return true;
296 }
297
waitWhileAllocatingLocked() const298 void BufferQueueCore::waitWhileAllocatingLocked() const {
299 ATRACE_CALL();
300 while (mIsAllocating) {
301 mIsAllocatingCondition.wait(mMutex);
302 }
303 }
304
305 #if DEBUG_ONLY_CODE
validateConsistencyLocked() const306 void BufferQueueCore::validateConsistencyLocked() const {
307 static const useconds_t PAUSE_TIME = 0;
308 int allocatedSlots = 0;
309 for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
310 bool isInFreeSlots = mFreeSlots.count(slot) != 0;
311 bool isInFreeBuffers =
312 std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
313 mFreeBuffers.cend();
314 bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
315 bool isInUnusedSlots =
316 std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
317 mUnusedSlots.cend();
318
319 if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
320 allocatedSlots++;
321 }
322
323 if (isInUnusedSlots) {
324 if (isInFreeSlots) {
325 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
326 usleep(PAUSE_TIME);
327 }
328 if (isInFreeBuffers) {
329 BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
330 usleep(PAUSE_TIME);
331 }
332 if (isInActiveBuffers) {
333 BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
334 slot);
335 usleep(PAUSE_TIME);
336 }
337 if (!mSlots[slot].mBufferState.isFree()) {
338 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
339 usleep(PAUSE_TIME);
340 }
341 if (mSlots[slot].mGraphicBuffer != NULL) {
342 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
343 slot);
344 usleep(PAUSE_TIME);
345 }
346 } else if (isInFreeSlots) {
347 if (isInUnusedSlots) {
348 BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
349 usleep(PAUSE_TIME);
350 }
351 if (isInFreeBuffers) {
352 BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
353 usleep(PAUSE_TIME);
354 }
355 if (isInActiveBuffers) {
356 BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
357 usleep(PAUSE_TIME);
358 }
359 if (!mSlots[slot].mBufferState.isFree()) {
360 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
361 usleep(PAUSE_TIME);
362 }
363 if (mSlots[slot].mGraphicBuffer != NULL) {
364 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
365 slot);
366 usleep(PAUSE_TIME);
367 }
368 } else if (isInFreeBuffers) {
369 if (isInUnusedSlots) {
370 BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
371 usleep(PAUSE_TIME);
372 }
373 if (isInFreeSlots) {
374 BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
375 usleep(PAUSE_TIME);
376 }
377 if (isInActiveBuffers) {
378 BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
379 slot);
380 usleep(PAUSE_TIME);
381 }
382 if (!mSlots[slot].mBufferState.isFree()) {
383 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
384 usleep(PAUSE_TIME);
385 }
386 if (mSlots[slot].mGraphicBuffer == NULL) {
387 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
388 usleep(PAUSE_TIME);
389 }
390 } else if (isInActiveBuffers) {
391 if (isInUnusedSlots) {
392 BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
393 slot);
394 usleep(PAUSE_TIME);
395 }
396 if (isInFreeSlots) {
397 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
398 usleep(PAUSE_TIME);
399 }
400 if (isInFreeBuffers) {
401 BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
402 slot);
403 usleep(PAUSE_TIME);
404 }
405 if (mSlots[slot].mBufferState.isFree() &&
406 !mSlots[slot].mBufferState.isShared()) {
407 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
408 usleep(PAUSE_TIME);
409 }
410 if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
411 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
412 usleep(PAUSE_TIME);
413 }
414 } else {
415 BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
416 "mFreeBuffers, or mActiveBuffers", slot);
417 usleep(PAUSE_TIME);
418 }
419 }
420
421 if (allocatedSlots != getMaxBufferCountLocked()) {
422 BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
423 "Should be %d (%zu free slots, %zu free buffers, "
424 "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
425 getMaxBufferCountLocked(), mFreeSlots.size(),
426 mFreeBuffers.size(), mActiveBuffers.size(),
427 mUnusedSlots.size());
428 }
429 }
430 #endif
431
432 } // namespace android
433