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