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