blob: e4ec5fda8ebb7ddb56980e81ef78c3cf6d8df071 [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
Colin Crosse5729fa2014-03-21 15:04:25 -070020
21#include <inttypes.h>
22
Igor Murashkind4d52272013-04-29 10:31:06 -070023#include <utils/Log.h>
24
25#include <gui/RingBufferConsumer.h>
26
Bernhard Rosenkraenzercd4f9922013-07-30 01:18:18 +020027#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__)
Igor Murashkind4d52272013-04-29 10:31:06 -070032
Igor Murashkin8e2afd92013-05-14 16:17:12 -070033#undef assert
34#define assert(x) ALOG_ASSERT((x), #x)
35
Igor Murashkind4d52272013-04-29 10:31:06 -070036typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
37
38namespace android {
39
Mathias Agopiandeeef542013-08-02 01:50:59 -070040RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
41 uint32_t consumerUsage,
Igor Murashkind4d52272013-04-29 10:31:06 -070042 int bufferCount) :
Mathias Agopiandeeef542013-08-02 01:50:59 -070043 ConsumerBase(consumer),
Igor Murashkind4d52272013-04-29 10:31:06 -070044 mBufferCount(bufferCount)
45{
Mathias Agopiandeeef542013-08-02 01:50:59 -070046 mConsumer->setConsumerUsageBits(consumerUsage);
47 mConsumer->setMaxAcquiredBufferCount(bufferCount);
Igor Murashkind4d52272013-04-29 10:31:06 -070048
49 assert(bufferCount > 0);
50}
51
52RingBufferConsumer::~RingBufferConsumer() {
53}
54
55void RingBufferConsumer::setName(const String8& name) {
56 Mutex::Autolock _l(mMutex);
57 mName = name;
Mathias Agopiandeeef542013-08-02 01:50:59 -070058 mConsumer->setConsumerName(name);
Igor Murashkind4d52272013-04-29 10:31:06 -070059}
60
61sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
62 const RingBufferComparator& filter,
63 bool waitForFence) {
64
65 sp<PinnedBufferItem> pinnedBuffer;
66
67 {
68 List<RingBufferItem>::iterator it, end, accIt;
69 BufferInfo acc, cur;
70 BufferInfo* accPtr = NULL;
71
72 Mutex::Autolock _l(mMutex);
73
74 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
75 it != end;
76 ++it) {
77
78 const RingBufferItem& item = *it;
79
80 cur.mCrop = item.mCrop;
81 cur.mTransform = item.mTransform;
82 cur.mScalingMode = item.mScalingMode;
83 cur.mTimestamp = item.mTimestamp;
84 cur.mFrameNumber = item.mFrameNumber;
85 cur.mPinned = item.mPinCount > 0;
86
87 int ret = filter.compare(accPtr, &cur);
88
89 if (ret == 0) {
90 accPtr = NULL;
91 } else if (ret > 0) {
92 acc = cur;
93 accPtr = &acc;
94 accIt = it;
95 } // else acc = acc
96 }
97
98 if (!accPtr) {
99 return NULL;
100 }
101
102 pinnedBuffer = new PinnedBufferItem(this, *accIt);
103 pinBufferLocked(pinnedBuffer->getBufferItem());
104
105 } // end scope of mMutex autolock
106
Igor Murashkind4d52272013-04-29 10:31:06 -0700107 if (waitForFence) {
Mathias Agopiand7644242013-05-16 18:07:35 -0700108 status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
Igor Murashkind4d52272013-04-29 10:31:06 -0700109 "RingBufferConsumer::pinSelectedBuffer");
110 if (err != OK) {
111 BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
112 strerror(-err), err);
113 }
114 }
115
116 return pinnedBuffer;
117}
118
119status_t RingBufferConsumer::clear() {
120
121 status_t err;
122 Mutex::Autolock _l(mMutex);
123
124 BI_LOGV("%s", __FUNCTION__);
125
126 // Avoid annoying log warnings by returning early
127 if (mBufferItemList.size() == 0) {
128 return OK;
129 }
130
131 do {
132 size_t pinnedFrames = 0;
133 err = releaseOldestBufferLocked(&pinnedFrames);
134
135 if (err == NO_BUFFER_AVAILABLE) {
136 assert(pinnedFrames == mBufferItemList.size());
137 break;
138 }
139
140 if (err == NOT_ENOUGH_DATA) {
141 // Fine. Empty buffer item list.
142 break;
143 }
144
145 if (err != OK) {
146 BI_LOGE("Clear failed, could not release buffer");
147 return err;
148 }
149
150 } while(true);
151
152 return OK;
153}
154
155void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
156 List<RingBufferItem>::iterator it, end;
157
158 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
159 it != end;
160 ++it) {
161
162 RingBufferItem& find = *it;
163 if (item.mGraphicBuffer == find.mGraphicBuffer) {
164 find.mPinCount++;
165 break;
166 }
167 }
168
169 if (it == end) {
Colin Crosse5729fa2014-03-21 15:04:25 -0700170 BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700171 item.mTimestamp, item.mFrameNumber);
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700172 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700173 BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700174 item.mFrameNumber, item.mTimestamp);
Igor Murashkind4d52272013-04-29 10:31:06 -0700175 }
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();
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700185 accIt = end;
Igor Murashkind4d52272013-04-29 10:31:06 -0700186
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;
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700200
201 if (find.mPinCount > 0) {
202 if (pinnedFrames != NULL) {
203 ++(*pinnedFrames);
204 }
205 // Filter out pinned frame when searching for buffer to release
206 continue;
Igor Murashkind4d52272013-04-29 10:31:06 -0700207 }
208
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700209 if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
210 accIt = it;
Igor Murashkind4d52272013-04-29 10:31:06 -0700211 }
212 }
213
214 if (accIt != end) {
215 RingBufferItem& item = *accIt;
216
217 // In case the object was never pinned, pass the acquire fence
218 // back to the release fence. If the fence was already waited on,
219 // it'll just be a no-op to wait on it again.
Lajos Molnard0304472013-05-15 12:59:19 -0700220
221 // item.mGraphicBuffer was populated with the proper graphic-buffer
222 // at acquire even if it was previously acquired
223 err = addReleaseFenceLocked(item.mBuf,
224 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700225
226 if (err != OK) {
227 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700228 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700229 item.mTimestamp, item.mFrameNumber);
230 return err;
231 }
232
Colin Crosse5729fa2014-03-21 15:04:25 -0700233 BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700234 item.mTimestamp, item.mFrameNumber);
235
Lajos Molnard0304472013-05-15 12:59:19 -0700236 // item.mGraphicBuffer was populated with the proper graphic-buffer
237 // at acquire even if it was previously acquired
238 err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
Igor Murashkind4d52272013-04-29 10:31:06 -0700239 EGL_NO_DISPLAY,
240 EGL_NO_SYNC_KHR);
241 if (err != OK) {
242 BI_LOGE("Failed to release buffer: %s (%d)",
243 strerror(-err), err);
244 return err;
245 }
246
Colin Crosse5729fa2014-03-21 15:04:25 -0700247 BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted",
Igor Murashkind4d52272013-04-29 10:31:06 -0700248 item.mTimestamp, item.mFrameNumber);
249
250 size_t currentSize = mBufferItemList.size();
251 mBufferItemList.erase(accIt);
252 assert(mBufferItemList.size() == currentSize - 1);
253 } else {
254 BI_LOGW("All buffers pinned, could not find any to release");
255 return NO_BUFFER_AVAILABLE;
256
257 }
258
259 return OK;
260}
261
262void RingBufferConsumer::onFrameAvailable() {
263 status_t err;
264
265 {
266 Mutex::Autolock _l(mMutex);
267
268 /**
269 * Release oldest frame
270 */
271 if (mBufferItemList.size() >= (size_t)mBufferCount) {
272 err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
273 assert(err != NOT_ENOUGH_DATA);
274
275 // TODO: implement the case for NO_BUFFER_AVAILABLE
276 assert(err != NO_BUFFER_AVAILABLE);
277 if (err != OK) {
278 return;
279 }
280 // TODO: in unpinBuffer rerun this routine if we had buffers
281 // we could've locked but didn't because there was no space
282 }
283
284 RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
285 RingBufferItem());
286
287 /**
288 * Acquire new frame
289 */
Andy McFadden656e8622013-06-28 14:03:03 -0700290 err = acquireBufferLocked(&item, 0);
Igor Murashkind4d52272013-04-29 10:31:06 -0700291 if (err != OK) {
292 if (err != NO_BUFFER_AVAILABLE) {
293 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
294 }
295
296 mBufferItemList.erase(--mBufferItemList.end());
297 return;
298 }
299
Colin Crosse5729fa2014-03-21 15:04:25 -0700300 BI_LOGV("New buffer acquired (timestamp %" PRId64 "), "
301 "buffer items %zu out of %d",
Igor Murashkind4d52272013-04-29 10:31:06 -0700302 item.mTimestamp,
303 mBufferItemList.size(), mBufferCount);
304
305 item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
306 } // end of mMutex lock
307
308 ConsumerBase::onFrameAvailable();
309}
310
311void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
312 Mutex::Autolock _l(mMutex);
313
314 List<RingBufferItem>::iterator it, end, accIt;
315
316 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
317 it != end;
318 ++it) {
319
320 RingBufferItem& find = *it;
321 if (item.mGraphicBuffer == find.mGraphicBuffer) {
Lajos Molnard0304472013-05-15 12:59:19 -0700322 status_t res = addReleaseFenceLocked(item.mBuf,
323 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700324
325 if (res != OK) {
326 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700327 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700328 item.mTimestamp, item.mFrameNumber);
329 return;
330 }
331
332 find.mPinCount--;
333 break;
334 }
335 }
336
337 if (it == end) {
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700338 // This should never happen. If it happens, we have a bug.
Colin Crosse5729fa2014-03-21 15:04:25 -0700339 BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700340 item.mTimestamp, item.mFrameNumber);
341 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700342 BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700343 item.mTimestamp, item.mFrameNumber);
344 }
345}
346
347status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
348 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700349 return mConsumer->setDefaultBufferSize(w, h);
Igor Murashkind4d52272013-04-29 10:31:06 -0700350}
351
352status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
353 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700354 return mConsumer->setDefaultBufferFormat(defaultFormat);
Igor Murashkind4d52272013-04-29 10:31:06 -0700355}
356
357status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) {
358 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700359 return mConsumer->setConsumerUsageBits(usage);
Igor Murashkind4d52272013-04-29 10:31:06 -0700360}
361
362} // namespace android