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