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