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
39namespace android {
40
41static String8 getUniqueName() {
42    static volatile int32_t counter = 0;
43    return String8::format("unnamed-%d-%d", getpid(),
44            android_atomic_inc(&counter));
45}
46
47static 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
53BufferQueueCore::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
112BufferQueueCore::~BufferQueueCore() {}
113
114void 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
168int 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
178int BufferQueueCore::getMinMaxBufferCountLocked() const {
179    return getMinUndequeuedBufferCountLocked() + 1;
180}
181
182int 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
190int 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
200void 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
223void 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
247bool BufferQueueCore::adjustAvailableSlotsLocked(int delta) {
248    if (delta >= 0) {
249        // If we're going to fail, do so before modifying anything
250        if (delta > static_cast<int>(mUnusedSlots.size())) {
251            return false;
252        }
253        while (delta > 0) {
254            if (mUnusedSlots.empty()) {
255                return false;
256            }
257            int slot = mUnusedSlots.back();
258            mUnusedSlots.pop_back();
259            mFreeSlots.insert(slot);
260            delta--;
261        }
262    } else {
263        // If we're going to fail, do so before modifying anything
264        if (-delta > static_cast<int>(mFreeSlots.size() +
265                mFreeBuffers.size())) {
266            return false;
267        }
268        while (delta < 0) {
269            if (!mFreeSlots.empty()) {
270                auto slot = mFreeSlots.begin();
271                clearBufferSlotLocked(*slot);
272                mUnusedSlots.push_back(*slot);
273                mFreeSlots.erase(slot);
274            } else if (!mFreeBuffers.empty()) {
275                int slot = mFreeBuffers.back();
276                clearBufferSlotLocked(slot);
277                mUnusedSlots.push_back(slot);
278                mFreeBuffers.pop_back();
279            } else {
280                return false;
281            }
282            delta++;
283        }
284    }
285    return true;
286}
287
288void BufferQueueCore::waitWhileAllocatingLocked() const {
289    ATRACE_CALL();
290    while (mIsAllocating) {
291        mIsAllocatingCondition.wait(mMutex);
292    }
293}
294
295#if DEBUG_ONLY_CODE
296void BufferQueueCore::validateConsistencyLocked() const {
297    static const useconds_t PAUSE_TIME = 0;
298    int allocatedSlots = 0;
299    for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
300        bool isInFreeSlots = mFreeSlots.count(slot) != 0;
301        bool isInFreeBuffers =
302                std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
303                mFreeBuffers.cend();
304        bool isInActiveBuffers = mActiveBuffers.count(slot) != 0;
305        bool isInUnusedSlots =
306                std::find(mUnusedSlots.cbegin(), mUnusedSlots.cend(), slot) !=
307                mUnusedSlots.cend();
308
309        if (isInFreeSlots || isInFreeBuffers || isInActiveBuffers) {
310            allocatedSlots++;
311        }
312
313        if (isInUnusedSlots) {
314            if (isInFreeSlots) {
315                BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeSlots", slot);
316                usleep(PAUSE_TIME);
317            }
318            if (isInFreeBuffers) {
319                BQ_LOGE("Slot %d is in mUnusedSlots and in mFreeBuffers", slot);
320                usleep(PAUSE_TIME);
321            }
322            if (isInActiveBuffers) {
323                BQ_LOGE("Slot %d is in mUnusedSlots and in mActiveBuffers",
324                        slot);
325                usleep(PAUSE_TIME);
326            }
327            if (!mSlots[slot].mBufferState.isFree()) {
328                BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
329                usleep(PAUSE_TIME);
330            }
331            if (mSlots[slot].mGraphicBuffer != NULL) {
332                BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
333                        slot);
334                usleep(PAUSE_TIME);
335            }
336        } else if (isInFreeSlots) {
337            if (isInUnusedSlots) {
338                BQ_LOGE("Slot %d is in mFreeSlots and in mUnusedSlots", slot);
339                usleep(PAUSE_TIME);
340            }
341            if (isInFreeBuffers) {
342                BQ_LOGE("Slot %d is in mFreeSlots and in mFreeBuffers", slot);
343                usleep(PAUSE_TIME);
344            }
345            if (isInActiveBuffers) {
346                BQ_LOGE("Slot %d is in mFreeSlots and in mActiveBuffers", slot);
347                usleep(PAUSE_TIME);
348            }
349            if (!mSlots[slot].mBufferState.isFree()) {
350                BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
351                usleep(PAUSE_TIME);
352            }
353            if (mSlots[slot].mGraphicBuffer != NULL) {
354                BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
355                        slot);
356                usleep(PAUSE_TIME);
357            }
358        } else if (isInFreeBuffers) {
359            if (isInUnusedSlots) {
360                BQ_LOGE("Slot %d is in mFreeBuffers and in mUnusedSlots", slot);
361                usleep(PAUSE_TIME);
362            }
363            if (isInFreeSlots) {
364                BQ_LOGE("Slot %d is in mFreeBuffers and in mFreeSlots", slot);
365                usleep(PAUSE_TIME);
366            }
367            if (isInActiveBuffers) {
368                BQ_LOGE("Slot %d is in mFreeBuffers and in mActiveBuffers",
369                        slot);
370                usleep(PAUSE_TIME);
371            }
372            if (!mSlots[slot].mBufferState.isFree()) {
373                BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
374                usleep(PAUSE_TIME);
375            }
376            if (mSlots[slot].mGraphicBuffer == NULL) {
377                BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
378                usleep(PAUSE_TIME);
379            }
380        } else if (isInActiveBuffers) {
381            if (isInUnusedSlots) {
382                BQ_LOGE("Slot %d is in mActiveBuffers and in mUnusedSlots",
383                        slot);
384                usleep(PAUSE_TIME);
385            }
386            if (isInFreeSlots) {
387                BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeSlots", slot);
388                usleep(PAUSE_TIME);
389            }
390            if (isInFreeBuffers) {
391                BQ_LOGE("Slot %d is in mActiveBuffers and in mFreeBuffers",
392                        slot);
393                usleep(PAUSE_TIME);
394            }
395            if (mSlots[slot].mBufferState.isFree() &&
396                    !mSlots[slot].mBufferState.isShared()) {
397                BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
398                usleep(PAUSE_TIME);
399            }
400            if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
401                BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
402                usleep(PAUSE_TIME);
403            }
404        } else {
405            BQ_LOGE("Slot %d isn't in any of mUnusedSlots, mFreeSlots, "
406                    "mFreeBuffers, or mActiveBuffers", slot);
407            usleep(PAUSE_TIME);
408        }
409    }
410
411    if (allocatedSlots != getMaxBufferCountLocked()) {
412        BQ_LOGE("Number of allocated slots is incorrect. Allocated = %d, "
413                "Should be %d (%zu free slots, %zu free buffers, "
414                "%zu activeBuffers, %zu unusedSlots)", allocatedSlots,
415                getMaxBufferCountLocked(), mFreeSlots.size(),
416                mFreeBuffers.size(), mActiveBuffers.size(),
417                mUnusedSlots.size());
418    }
419}
420#endif
421
422} // namespace android
423