• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2013 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_NDEBUG 0
18#define LOG_TAG "RingBufferConsumer"
19#define ATRACE_TAG ATRACE_TAG_GRAPHICS
20
21#include <com_android_graphics_libgui_flags.h>
22#include <inttypes.h>
23
24#include <utils/Log.h>
25
26#include <camera/StringUtils.h>
27#include <com_android_graphics_libgui_flags.h>
28#include <gui/RingBufferConsumer.h>
29#include <gui/Flags.h>
30
31#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
32#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
33#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
34#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
35#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
36
37#undef assert
38#define assert(x) ALOG_ASSERT((x), #x)
39
40typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
41
42namespace android {
43
44#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
45RingBufferConsumer::RingBufferConsumer(uint64_t consumerUsage, int bufferCount)
46    :
47    ConsumerBase(), mBufferCount(bufferCount), mLatestTimestamp(0) {
48#else
49RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
50                                       uint64_t consumerUsage, int bufferCount)
51    :
52    ConsumerBase(consumer), mBufferCount(bufferCount), mLatestTimestamp(0) {
53#endif  // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
54    mConsumer->setConsumerUsageBits(consumerUsage);
55    mConsumer->setMaxAcquiredBufferCount(bufferCount);
56    assert(bufferCount > 0);
57}
58
59RingBufferConsumer::~RingBufferConsumer() {
60}
61
62void RingBufferConsumer::setName(const std::string& name) {
63    Mutex::Autolock _l(mMutex);
64    mName = toString8(name);
65    mConsumer->setConsumerName(mName);
66}
67
68sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
69        const RingBufferComparator& filter,
70        bool waitForFence) {
71
72    sp<PinnedBufferItem> pinnedBuffer;
73
74    {
75        List<RingBufferItem>::iterator it, end, accIt;
76        BufferInfo acc, cur;
77        BufferInfo* accPtr = NULL;
78
79        Mutex::Autolock _l(mMutex);
80
81        for (it = mBufferItemList.begin(), end = mBufferItemList.end();
82             it != end;
83             ++it) {
84
85            const RingBufferItem& item = *it;
86
87            cur.mCrop = item.mCrop;
88            cur.mTransform = item.mTransform;
89            cur.mScalingMode = item.mScalingMode;
90            cur.mTimestamp = item.mTimestamp;
91            cur.mFrameNumber = item.mFrameNumber;
92            cur.mPinned = item.mPinCount > 0;
93
94            int ret = filter.compare(accPtr, &cur);
95
96            if (ret == 0) {
97                accPtr = NULL;
98            } else if (ret > 0) {
99                acc = cur;
100                accPtr = &acc;
101                accIt = it;
102            } // else acc = acc
103        }
104
105        if (!accPtr) {
106            return NULL;
107        }
108
109        pinnedBuffer = new PinnedBufferItem(this, *accIt);
110        pinBufferLocked(pinnedBuffer->getBufferItem());
111
112    } // end scope of mMutex autolock
113
114    if (waitForFence) {
115        status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
116                "RingBufferConsumer::pinSelectedBuffer");
117        if (err != OK) {
118            BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
119                    strerror(-err), err);
120        }
121    }
122
123    return pinnedBuffer;
124}
125
126status_t RingBufferConsumer::clear() {
127
128    status_t err;
129    Mutex::Autolock _l(mMutex);
130
131    BI_LOGV("%s", __FUNCTION__);
132
133    // Avoid annoying log warnings by returning early
134    if (mBufferItemList.size() == 0) {
135        return OK;
136    }
137
138    do {
139        size_t pinnedFrames = 0;
140        err = releaseOldestBufferLocked(&pinnedFrames);
141
142        if (err == NO_BUFFER_AVAILABLE) {
143            assert(pinnedFrames == mBufferItemList.size());
144            break;
145        }
146
147        if (err == NOT_ENOUGH_DATA) {
148            // Fine. Empty buffer item list.
149            break;
150        }
151
152        if (err != OK) {
153            BI_LOGE("Clear failed, could not release buffer");
154            return err;
155        }
156
157    } while(true);
158
159    return OK;
160}
161
162nsecs_t RingBufferConsumer::getLatestTimestamp() {
163    Mutex::Autolock _l(mMutex);
164    if (mBufferItemList.size() == 0) {
165        return 0;
166    }
167    return mLatestTimestamp;
168}
169
170void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
171    List<RingBufferItem>::iterator it, end;
172
173    for (it = mBufferItemList.begin(), end = mBufferItemList.end();
174         it != end;
175         ++it) {
176
177        RingBufferItem& find = *it;
178        if (item.mGraphicBuffer == find.mGraphicBuffer) {
179            find.mPinCount++;
180            break;
181        }
182    }
183
184    if (it == end) {
185        BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
186                 item.mTimestamp, item.mFrameNumber);
187    } else {
188        BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")",
189                item.mFrameNumber, item.mTimestamp);
190    }
191}
192
193status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
194    status_t err = OK;
195
196    List<RingBufferItem>::iterator it, end, accIt;
197
198    it = mBufferItemList.begin();
199    end = mBufferItemList.end();
200    accIt = end;
201
202    if (it == end) {
203        /**
204         * This is fine. We really care about being able to acquire a buffer
205         * successfully after this function completes, not about it releasing
206         * some buffer.
207         */
208        BI_LOGV("%s: No buffers yet acquired, can't release anything",
209              __FUNCTION__);
210        return NOT_ENOUGH_DATA;
211    }
212
213    for (; it != end; ++it) {
214        RingBufferItem& find = *it;
215
216        if (find.mPinCount > 0) {
217            if (pinnedFrames != NULL) {
218                ++(*pinnedFrames);
219            }
220            // Filter out pinned frame when searching for buffer to release
221            continue;
222        }
223
224        if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
225            accIt = it;
226        }
227    }
228
229    if (accIt != end) {
230        RingBufferItem& item = *accIt;
231
232        // In case the object was never pinned, pass the acquire fence
233        // back to the release fence. If the fence was already waited on,
234        // it'll just be a no-op to wait on it again.
235
236        // item.mGraphicBuffer was populated with the proper graphic-buffer
237        // at acquire even if it was previously acquired
238        err = addReleaseFenceLocked(item.mSlot,
239                item.mGraphicBuffer, item.mFence);
240
241        if (err != OK) {
242            BI_LOGE("Failed to add release fence to buffer "
243                    "(timestamp %" PRId64 ", framenumber %" PRIu64,
244                    item.mTimestamp, item.mFrameNumber);
245            return err;
246        }
247
248        BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64,
249                item.mTimestamp, item.mFrameNumber);
250
251        // item.mGraphicBuffer was populated with the proper graphic-buffer
252        // at acquire even if it was previously acquired
253        err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer);
254        if (err != OK) {
255            BI_LOGE("Failed to release buffer: %s (%d)",
256                    strerror(-err), err);
257            return err;
258        }
259
260        BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted",
261                item.mTimestamp, item.mFrameNumber);
262
263        mBufferItemList.erase(accIt);
264    } else {
265        BI_LOGW("All buffers pinned, could not find any to release");
266        return NO_BUFFER_AVAILABLE;
267
268    }
269
270    return OK;
271}
272
273void RingBufferConsumer::onFrameAvailable(const BufferItem& item) {
274    status_t err;
275
276    {
277        Mutex::Autolock _l(mMutex);
278
279        /**
280         * Release oldest frame
281         */
282        if (mBufferItemList.size() >= (size_t)mBufferCount) {
283            err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
284            assert(err != NOT_ENOUGH_DATA);
285
286            // TODO: implement the case for NO_BUFFER_AVAILABLE
287            assert(err != NO_BUFFER_AVAILABLE);
288            if (err != OK) {
289                return;
290            }
291            // TODO: in unpinBuffer rerun this routine if we had buffers
292            // we could've locked but didn't because there was no space
293        }
294
295        RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
296                                                       RingBufferItem());
297
298        /**
299         * Acquire new frame
300         */
301        err = acquireBufferLocked(&item, 0);
302        if (err != OK) {
303            if (err != NO_BUFFER_AVAILABLE) {
304                BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
305            }
306
307            mBufferItemList.erase(--mBufferItemList.end());
308            return;
309        }
310
311        BI_LOGV("New buffer acquired (timestamp %" PRId64 "), "
312                "buffer items %zu out of %d",
313                item.mTimestamp,
314                mBufferItemList.size(), mBufferCount);
315
316        if (item.mTimestamp < mLatestTimestamp) {
317            BI_LOGE("Timestamp  decreases from %" PRId64 " to %" PRId64,
318                    mLatestTimestamp, item.mTimestamp);
319        }
320
321        mLatestTimestamp = item.mTimestamp;
322
323        item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
324    } // end of mMutex lock
325
326    ConsumerBase::onFrameAvailable(item);
327}
328
329void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
330    Mutex::Autolock _l(mMutex);
331
332    List<RingBufferItem>::iterator it, end, accIt;
333
334    for (it = mBufferItemList.begin(), end = mBufferItemList.end();
335         it != end;
336         ++it) {
337
338        RingBufferItem& find = *it;
339        if (item.mGraphicBuffer == find.mGraphicBuffer) {
340            status_t res = addReleaseFenceLocked(item.mSlot,
341                    item.mGraphicBuffer, item.mFence);
342
343            if (res != OK) {
344                BI_LOGE("Failed to add release fence to buffer "
345                        "(timestamp %" PRId64 ", framenumber %" PRIu64,
346                        item.mTimestamp, item.mFrameNumber);
347                return;
348            }
349
350            find.mPinCount--;
351            break;
352        }
353    }
354
355    if (it == end) {
356        // This should never happen. If it happens, we have a bug.
357        BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
358                 item.mTimestamp, item.mFrameNumber);
359    } else {
360        BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
361                 item.mTimestamp, item.mFrameNumber);
362    }
363}
364
365status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
366    Mutex::Autolock _l(mMutex);
367    return mConsumer->setDefaultBufferSize(w, h);
368}
369
370status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
371    Mutex::Autolock _l(mMutex);
372    return mConsumer->setDefaultBufferFormat(defaultFormat);
373}
374
375status_t RingBufferConsumer::setConsumerUsage(uint64_t usage) {
376    Mutex::Autolock _l(mMutex);
377    return mConsumer->setConsumerUsageBits(usage);
378}
379
380} // namespace android