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