blob: 1b2a717ae60c005677a2fd786d7edc8797598443 [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
17#undef NDEBUG
18#include <cassert>
19
20//#define LOG_NDEBUG 0
21#define LOG_TAG "RingBufferConsumer"
22#define ATRACE_TAG ATRACE_TAG_GRAPHICS
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
33typedef 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
104 if (pinnedBuffer != 0) {
105 BI_LOGV("Pinned buffer frame %lld, timestamp %lld",
106 pinnedBuffer->getBufferItem().mFrameNumber,
107 pinnedBuffer->getBufferItem().mTimestamp);
108 }
109
110 if (waitForFence) {
111 status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(1000,
112 "RingBufferConsumer::pinSelectedBuffer");
113 if (err != OK) {
114 BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
115 strerror(-err), err);
116 }
117 }
118
119 return pinnedBuffer;
120}
121
122status_t RingBufferConsumer::clear() {
123
124 status_t err;
125 Mutex::Autolock _l(mMutex);
126
127 BI_LOGV("%s", __FUNCTION__);
128
129 // Avoid annoying log warnings by returning early
130 if (mBufferItemList.size() == 0) {
131 return OK;
132 }
133
134 do {
135 size_t pinnedFrames = 0;
136 err = releaseOldestBufferLocked(&pinnedFrames);
137
138 if (err == NO_BUFFER_AVAILABLE) {
139 assert(pinnedFrames == mBufferItemList.size());
140 break;
141 }
142
143 if (err == NOT_ENOUGH_DATA) {
144 // Fine. Empty buffer item list.
145 break;
146 }
147
148 if (err != OK) {
149 BI_LOGE("Clear failed, could not release buffer");
150 return err;
151 }
152
153 } while(true);
154
155 return OK;
156}
157
158void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
159 List<RingBufferItem>::iterator it, end;
160
161 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
162 it != end;
163 ++it) {
164
165 RingBufferItem& find = *it;
166 if (item.mGraphicBuffer == find.mGraphicBuffer) {
167 find.mPinCount++;
168 break;
169 }
170 }
171
172 if (it == end) {
173 BI_LOGE("Failed to pin buffer (timestamp %lld, framenumber %lld)",
174 item.mTimestamp, item.mFrameNumber);
175 }
176}
177
178status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
179 status_t err = OK;
180
181 List<RingBufferItem>::iterator it, end, accIt;
182
183 it = mBufferItemList.begin();
184 end = mBufferItemList.end();
185 accIt = it;
186
187 if (it == end) {
188 /**
189 * This is fine. We really care about being able to acquire a buffer
190 * successfully after this function completes, not about it releasing
191 * some buffer.
192 */
193 BI_LOGV("%s: No buffers yet acquired, can't release anything",
194 __FUNCTION__);
195 return NOT_ENOUGH_DATA;
196 }
197
198 for (; it != end; ++it) {
199 RingBufferItem& find = *it;
200 if (find.mTimestamp < accIt->mTimestamp && find.mPinCount <= 0) {
201 accIt = it;
202 }
203
204 if (find.mPinCount > 0 && pinnedFrames != NULL) {
205 ++(*pinnedFrames);
206 }
207 }
208
209 if (accIt != end) {
210 RingBufferItem& item = *accIt;
211
212 // In case the object was never pinned, pass the acquire fence
213 // back to the release fence. If the fence was already waited on,
214 // it'll just be a no-op to wait on it again.
215 err = addReleaseFenceLocked(item.mBuf, item.mFence);
216
217 if (err != OK) {
218 BI_LOGE("Failed to add release fence to buffer "
219 "(timestamp %lld, framenumber %lld",
220 item.mTimestamp, item.mFrameNumber);
221 return err;
222 }
223
224 BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld",
225 item.mTimestamp, item.mFrameNumber);
226
227 err = releaseBufferLocked(item.mBuf,
228 EGL_NO_DISPLAY,
229 EGL_NO_SYNC_KHR);
230 if (err != OK) {
231 BI_LOGE("Failed to release buffer: %s (%d)",
232 strerror(-err), err);
233 return err;
234 }
235
236 BI_LOGV("Buffer timestamp %lld, frame %lld evicted",
237 item.mTimestamp, item.mFrameNumber);
238
239 size_t currentSize = mBufferItemList.size();
240 mBufferItemList.erase(accIt);
241 assert(mBufferItemList.size() == currentSize - 1);
242 } else {
243 BI_LOGW("All buffers pinned, could not find any to release");
244 return NO_BUFFER_AVAILABLE;
245
246 }
247
248 return OK;
249}
250
251void RingBufferConsumer::onFrameAvailable() {
252 status_t err;
253
254 {
255 Mutex::Autolock _l(mMutex);
256
257 /**
258 * Release oldest frame
259 */
260 if (mBufferItemList.size() >= (size_t)mBufferCount) {
261 err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
262 assert(err != NOT_ENOUGH_DATA);
263
264 // TODO: implement the case for NO_BUFFER_AVAILABLE
265 assert(err != NO_BUFFER_AVAILABLE);
266 if (err != OK) {
267 return;
268 }
269 // TODO: in unpinBuffer rerun this routine if we had buffers
270 // we could've locked but didn't because there was no space
271 }
272
273 RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
274 RingBufferItem());
275
276 /**
277 * Acquire new frame
278 */
279 err = acquireBufferLocked(&item);
280 if (err != OK) {
281 if (err != NO_BUFFER_AVAILABLE) {
282 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
283 }
284
285 mBufferItemList.erase(--mBufferItemList.end());
286 return;
287 }
288
289 BI_LOGV("New buffer acquired (timestamp %lld), "
290 "buffer items %u out of %d",
291 item.mTimestamp,
292 mBufferItemList.size(), mBufferCount);
293
294 item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
295 } // end of mMutex lock
296
297 ConsumerBase::onFrameAvailable();
298}
299
300void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
301 Mutex::Autolock _l(mMutex);
302
303 List<RingBufferItem>::iterator it, end, accIt;
304
305 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
306 it != end;
307 ++it) {
308
309 RingBufferItem& find = *it;
310 if (item.mGraphicBuffer == find.mGraphicBuffer) {
311 status_t res = addReleaseFenceLocked(item.mBuf, item.mFence);
312
313 if (res != OK) {
314 BI_LOGE("Failed to add release fence to buffer "
315 "(timestamp %lld, framenumber %lld",
316 item.mTimestamp, item.mFrameNumber);
317 return;
318 }
319
320 find.mPinCount--;
321 break;
322 }
323 }
324
325 if (it == end) {
326 BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld",
327 item.mTimestamp, item.mFrameNumber);
328 }
329}
330
331status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
332 Mutex::Autolock _l(mMutex);
333 return mBufferQueue->setDefaultBufferSize(w, h);
334}
335
336status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
337 Mutex::Autolock _l(mMutex);
338 return mBufferQueue->setDefaultBufferFormat(defaultFormat);
339}
340
341status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
342 Mutex::Autolock _l(mMutex);
343 return mBufferQueue->setConsumerUsageBits(usage);
344}
345
346} // namespace android