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 
36 typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
37 
38 namespace android {
39 
RingBufferConsumer(const sp<IGraphicBufferConsumer> & consumer,uint32_t consumerUsage,int bufferCount)40 RingBufferConsumer::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 
~RingBufferConsumer()53 RingBufferConsumer::~RingBufferConsumer() {
54 }
55 
setName(const String8 & name)56 void RingBufferConsumer::setName(const String8& name) {
57     Mutex::Autolock _l(mMutex);
58     mName = name;
59     mConsumer->setConsumerName(name);
60 }
61 
pinSelectedBuffer(const RingBufferComparator & filter,bool waitForFence)62 sp<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 
clear()120 status_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 
getLatestTimestamp()156 nsecs_t RingBufferConsumer::getLatestTimestamp() {
157     Mutex::Autolock _l(mMutex);
158     if (mBufferItemList.size() == 0) {
159         return 0;
160     }
161     return mLatestTimestamp;
162 }
163 
pinBufferLocked(const BufferItem & item)164 void 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 
releaseOldestBufferLocked(size_t * pinnedFrames)187 status_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 
onFrameAvailable(const BufferItem & item)271 void RingBufferConsumer::onFrameAvailable(const BufferItem& item) {
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(item);
325 }
326 
unpinBuffer(const BufferItem & item)327 void 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 
setDefaultBufferSize(uint32_t w,uint32_t h)363 status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
364     Mutex::Autolock _l(mMutex);
365     return mConsumer->setDefaultBufferSize(w, h);
366 }
367 
setDefaultBufferFormat(uint32_t defaultFormat)368 status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
369     Mutex::Autolock _l(mMutex);
370     return mConsumer->setDefaultBufferFormat(defaultFormat);
371 }
372 
setConsumerUsage(uint32_t usage)373 status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
374     Mutex::Autolock _l(mMutex);
375     return mConsumer->setConsumerUsageBits(usage);
376 }
377 
378 } // namespace android
379