blob: ee018c3cc8bc0740715796e5d154a242d17a313c [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,
Emilian Peev050f5dc2017-05-18 14:43:56 +010041 uint64_t consumerUsage,
Igor Murashkind4d52272013-04-29 10:31:06 -070042 int bufferCount) :
Mathias Agopiandeeef542013-08-02 01:50:59 -070043 ConsumerBase(consumer),
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -070044 mBufferCount(bufferCount),
45 mLatestTimestamp(0)
Igor Murashkind4d52272013-04-29 10:31:06 -070046{
Mathias Agopiandeeef542013-08-02 01:50:59 -070047 mConsumer->setConsumerUsageBits(consumerUsage);
48 mConsumer->setMaxAcquiredBufferCount(bufferCount);
Igor Murashkind4d52272013-04-29 10:31:06 -070049
50 assert(bufferCount > 0);
51}
52
53RingBufferConsumer::~RingBufferConsumer() {
54}
55
56void RingBufferConsumer::setName(const String8& name) {
57 Mutex::Autolock _l(mMutex);
58 mName = name;
Mathias Agopiandeeef542013-08-02 01:50:59 -070059 mConsumer->setConsumerName(name);
Igor Murashkind4d52272013-04-29 10:31:06 -070060}
61
62sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
63 const RingBufferComparator& filter,
64 bool waitForFence) {
65
66 sp<PinnedBufferItem> pinnedBuffer;
67
68 {
69 List<RingBufferItem>::iterator it, end, accIt;
70 BufferInfo acc, cur;
71 BufferInfo* accPtr = NULL;
72
73 Mutex::Autolock _l(mMutex);
74
75 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
76 it != end;
77 ++it) {
78
79 const RingBufferItem& item = *it;
80
81 cur.mCrop = item.mCrop;
82 cur.mTransform = item.mTransform;
83 cur.mScalingMode = item.mScalingMode;
84 cur.mTimestamp = item.mTimestamp;
85 cur.mFrameNumber = item.mFrameNumber;
86 cur.mPinned = item.mPinCount > 0;
87
88 int ret = filter.compare(accPtr, &cur);
89
90 if (ret == 0) {
91 accPtr = NULL;
92 } else if (ret > 0) {
93 acc = cur;
94 accPtr = &acc;
95 accIt = it;
96 } // else acc = acc
97 }
98
99 if (!accPtr) {
100 return NULL;
101 }
102
103 pinnedBuffer = new PinnedBufferItem(this, *accIt);
104 pinBufferLocked(pinnedBuffer->getBufferItem());
105
106 } // end scope of mMutex autolock
107
Igor Murashkind4d52272013-04-29 10:31:06 -0700108 if (waitForFence) {
Mathias Agopiand7644242013-05-16 18:07:35 -0700109 status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
Igor Murashkind4d52272013-04-29 10:31:06 -0700110 "RingBufferConsumer::pinSelectedBuffer");
111 if (err != OK) {
112 BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
113 strerror(-err), err);
114 }
115 }
116
117 return pinnedBuffer;
118}
119
120status_t RingBufferConsumer::clear() {
121
122 status_t err;
123 Mutex::Autolock _l(mMutex);
124
125 BI_LOGV("%s", __FUNCTION__);
126
127 // Avoid annoying log warnings by returning early
128 if (mBufferItemList.size() == 0) {
129 return OK;
130 }
131
132 do {
133 size_t pinnedFrames = 0;
134 err = releaseOldestBufferLocked(&pinnedFrames);
135
136 if (err == NO_BUFFER_AVAILABLE) {
137 assert(pinnedFrames == mBufferItemList.size());
138 break;
139 }
140
141 if (err == NOT_ENOUGH_DATA) {
142 // Fine. Empty buffer item list.
143 break;
144 }
145
146 if (err != OK) {
147 BI_LOGE("Clear failed, could not release buffer");
148 return err;
149 }
150
151 } while(true);
152
153 return OK;
154}
155
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -0700156nsecs_t RingBufferConsumer::getLatestTimestamp() {
157 Mutex::Autolock _l(mMutex);
158 if (mBufferItemList.size() == 0) {
159 return 0;
160 }
161 return mLatestTimestamp;
162}
163
Igor Murashkind4d52272013-04-29 10:31:06 -0700164void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
165 List<RingBufferItem>::iterator it, end;
166
167 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
168 it != end;
169 ++it) {
170
171 RingBufferItem& find = *it;
172 if (item.mGraphicBuffer == find.mGraphicBuffer) {
173 find.mPinCount++;
174 break;
175 }
176 }
177
178 if (it == end) {
Colin Crosse5729fa2014-03-21 15:04:25 -0700179 BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700180 item.mTimestamp, item.mFrameNumber);
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700181 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700182 BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700183 item.mFrameNumber, item.mTimestamp);
Igor Murashkind4d52272013-04-29 10:31:06 -0700184 }
185}
186
187status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
188 status_t err = OK;
189
190 List<RingBufferItem>::iterator it, end, accIt;
191
192 it = mBufferItemList.begin();
193 end = mBufferItemList.end();
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700194 accIt = end;
Igor Murashkind4d52272013-04-29 10:31:06 -0700195
196 if (it == end) {
197 /**
198 * This is fine. We really care about being able to acquire a buffer
199 * successfully after this function completes, not about it releasing
200 * some buffer.
201 */
202 BI_LOGV("%s: No buffers yet acquired, can't release anything",
203 __FUNCTION__);
204 return NOT_ENOUGH_DATA;
205 }
206
207 for (; it != end; ++it) {
208 RingBufferItem& find = *it;
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700209
210 if (find.mPinCount > 0) {
211 if (pinnedFrames != NULL) {
212 ++(*pinnedFrames);
213 }
214 // Filter out pinned frame when searching for buffer to release
215 continue;
Igor Murashkind4d52272013-04-29 10:31:06 -0700216 }
217
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700218 if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
219 accIt = it;
Igor Murashkind4d52272013-04-29 10:31:06 -0700220 }
221 }
222
223 if (accIt != end) {
224 RingBufferItem& item = *accIt;
225
226 // In case the object was never pinned, pass the acquire fence
227 // back to the release fence. If the fence was already waited on,
228 // it'll just be a no-op to wait on it again.
Lajos Molnard0304472013-05-15 12:59:19 -0700229
230 // item.mGraphicBuffer was populated with the proper graphic-buffer
231 // at acquire even if it was previously acquired
Pablo Ceballose361bc02015-08-07 15:13:49 -0700232 err = addReleaseFenceLocked(item.mSlot,
Lajos Molnard0304472013-05-15 12:59:19 -0700233 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700234
235 if (err != OK) {
236 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700237 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700238 item.mTimestamp, item.mFrameNumber);
239 return err;
240 }
241
Colin Crosse5729fa2014-03-21 15:04:25 -0700242 BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700243 item.mTimestamp, item.mFrameNumber);
244
Lajos Molnard0304472013-05-15 12:59:19 -0700245 // item.mGraphicBuffer was populated with the proper graphic-buffer
246 // at acquire even if it was previously acquired
Pablo Ceballose361bc02015-08-07 15:13:49 -0700247 err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
Igor Murashkind4d52272013-04-29 10:31:06 -0700248 EGL_NO_DISPLAY,
249 EGL_NO_SYNC_KHR);
250 if (err != OK) {
251 BI_LOGE("Failed to release buffer: %s (%d)",
252 strerror(-err), err);
253 return err;
254 }
255
Colin Crosse5729fa2014-03-21 15:04:25 -0700256 BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted",
Igor Murashkind4d52272013-04-29 10:31:06 -0700257 item.mTimestamp, item.mFrameNumber);
258
Igor Murashkind4d52272013-04-29 10:31:06 -0700259 mBufferItemList.erase(accIt);
Igor Murashkind4d52272013-04-29 10:31:06 -0700260 } else {
261 BI_LOGW("All buffers pinned, could not find any to release");
262 return NO_BUFFER_AVAILABLE;
263
264 }
265
266 return OK;
267}
268
Dan Stoza549e7352015-03-12 15:21:16 -0700269void RingBufferConsumer::onFrameAvailable(const BufferItem& item) {
Igor Murashkind4d52272013-04-29 10:31:06 -0700270 status_t err;
271
272 {
273 Mutex::Autolock _l(mMutex);
274
275 /**
276 * Release oldest frame
277 */
278 if (mBufferItemList.size() >= (size_t)mBufferCount) {
279 err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
280 assert(err != NOT_ENOUGH_DATA);
281
282 // TODO: implement the case for NO_BUFFER_AVAILABLE
283 assert(err != NO_BUFFER_AVAILABLE);
284 if (err != OK) {
285 return;
286 }
287 // TODO: in unpinBuffer rerun this routine if we had buffers
288 // we could've locked but didn't because there was no space
289 }
290
291 RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
292 RingBufferItem());
293
294 /**
295 * Acquire new frame
296 */
Andy McFadden656e8622013-06-28 14:03:03 -0700297 err = acquireBufferLocked(&item, 0);
Igor Murashkind4d52272013-04-29 10:31:06 -0700298 if (err != OK) {
299 if (err != NO_BUFFER_AVAILABLE) {
300 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
301 }
302
303 mBufferItemList.erase(--mBufferItemList.end());
304 return;
305 }
306
Colin Crosse5729fa2014-03-21 15:04:25 -0700307 BI_LOGV("New buffer acquired (timestamp %" PRId64 "), "
308 "buffer items %zu out of %d",
Igor Murashkind4d52272013-04-29 10:31:06 -0700309 item.mTimestamp,
310 mBufferItemList.size(), mBufferCount);
311
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -0700312 if (item.mTimestamp < mLatestTimestamp) {
313 BI_LOGE("Timestamp decreases from %" PRId64 " to %" PRId64,
314 mLatestTimestamp, item.mTimestamp);
315 }
316
317 mLatestTimestamp = item.mTimestamp;
318
Pablo Ceballose361bc02015-08-07 15:13:49 -0700319 item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
Igor Murashkind4d52272013-04-29 10:31:06 -0700320 } // end of mMutex lock
321
Dan Stoza04f101c2014-11-04 11:32:52 -0800322 ConsumerBase::onFrameAvailable(item);
Igor Murashkind4d52272013-04-29 10:31:06 -0700323}
324
325void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
326 Mutex::Autolock _l(mMutex);
327
328 List<RingBufferItem>::iterator it, end, accIt;
329
330 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
331 it != end;
332 ++it) {
333
334 RingBufferItem& find = *it;
335 if (item.mGraphicBuffer == find.mGraphicBuffer) {
Pablo Ceballose361bc02015-08-07 15:13:49 -0700336 status_t res = addReleaseFenceLocked(item.mSlot,
Lajos Molnard0304472013-05-15 12:59:19 -0700337 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700338
339 if (res != OK) {
340 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700341 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700342 item.mTimestamp, item.mFrameNumber);
343 return;
344 }
345
346 find.mPinCount--;
347 break;
348 }
349 }
350
351 if (it == end) {
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700352 // This should never happen. If it happens, we have a bug.
Colin Crosse5729fa2014-03-21 15:04:25 -0700353 BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700354 item.mTimestamp, item.mFrameNumber);
355 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700356 BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700357 item.mTimestamp, item.mFrameNumber);
358 }
359}
360
361status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
362 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700363 return mConsumer->setDefaultBufferSize(w, h);
Igor Murashkind4d52272013-04-29 10:31:06 -0700364}
365
366status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
367 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700368 return mConsumer->setDefaultBufferFormat(defaultFormat);
Igor Murashkind4d52272013-04-29 10:31:06 -0700369}
370
Emilian Peev050f5dc2017-05-18 14:43:56 +0100371status_t RingBufferConsumer::setConsumerUsage(uint64_t usage) {
Igor Murashkind4d52272013-04-29 10:31:06 -0700372 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700373 return mConsumer->setConsumerUsageBits(usage);
Igor Murashkind4d52272013-04-29 10:31:06 -0700374}
375
376} // namespace android