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