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