blob: 5dbfb36c7c465d8f0b57018a1a905a871303c903 [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>
Austin Borger0fb3ad92023-06-01 16:51:35 -070026#include <camera/StringUtils.h>
Igor Murashkind4d52272013-04-29 10:31:06 -070027
Tomasz Wasilczyk12b04a52023-08-11 15:52:22 +000028#define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
29#define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__)
30#define BI_LOGI(x, ...) ALOGI("[%s] " x, mName.c_str(), ##__VA_ARGS__)
31#define BI_LOGW(x, ...) ALOGW("[%s] " x, mName.c_str(), ##__VA_ARGS__)
32#define BI_LOGE(x, ...) ALOGE("[%s] " x, mName.c_str(), ##__VA_ARGS__)
Igor Murashkind4d52272013-04-29 10:31:06 -070033
Igor Murashkin8e2afd92013-05-14 16:17:12 -070034#undef assert
35#define assert(x) ALOG_ASSERT((x), #x)
36
Igor Murashkind4d52272013-04-29 10:31:06 -070037typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem;
38
39namespace android {
40
Mathias Agopiandeeef542013-08-02 01:50:59 -070041RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer,
Emilian Peev050f5dc2017-05-18 14:43:56 +010042 uint64_t consumerUsage,
Igor Murashkind4d52272013-04-29 10:31:06 -070043 int bufferCount) :
Mathias Agopiandeeef542013-08-02 01:50:59 -070044 ConsumerBase(consumer),
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -070045 mBufferCount(bufferCount),
46 mLatestTimestamp(0)
Igor Murashkind4d52272013-04-29 10:31:06 -070047{
Mathias Agopiandeeef542013-08-02 01:50:59 -070048 mConsumer->setConsumerUsageBits(consumerUsage);
49 mConsumer->setMaxAcquiredBufferCount(bufferCount);
Igor Murashkind4d52272013-04-29 10:31:06 -070050
51 assert(bufferCount > 0);
52}
53
54RingBufferConsumer::~RingBufferConsumer() {
55}
56
Austin Borger0fb3ad92023-06-01 16:51:35 -070057void RingBufferConsumer::setName(const std::string& name) {
Igor Murashkind4d52272013-04-29 10:31:06 -070058 Mutex::Autolock _l(mMutex);
Austin Borger0fb3ad92023-06-01 16:51:35 -070059 mName = toString8(name);
60 mConsumer->setConsumerName(mName);
Igor Murashkind4d52272013-04-29 10:31:06 -070061}
62
63sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer(
64 const RingBufferComparator& filter,
65 bool waitForFence) {
66
67 sp<PinnedBufferItem> pinnedBuffer;
68
69 {
70 List<RingBufferItem>::iterator it, end, accIt;
71 BufferInfo acc, cur;
72 BufferInfo* accPtr = NULL;
73
74 Mutex::Autolock _l(mMutex);
75
76 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
77 it != end;
78 ++it) {
79
80 const RingBufferItem& item = *it;
81
82 cur.mCrop = item.mCrop;
83 cur.mTransform = item.mTransform;
84 cur.mScalingMode = item.mScalingMode;
85 cur.mTimestamp = item.mTimestamp;
86 cur.mFrameNumber = item.mFrameNumber;
87 cur.mPinned = item.mPinCount > 0;
88
89 int ret = filter.compare(accPtr, &cur);
90
91 if (ret == 0) {
92 accPtr = NULL;
93 } else if (ret > 0) {
94 acc = cur;
95 accPtr = &acc;
96 accIt = it;
97 } // else acc = acc
98 }
99
100 if (!accPtr) {
101 return NULL;
102 }
103
104 pinnedBuffer = new PinnedBufferItem(this, *accIt);
105 pinBufferLocked(pinnedBuffer->getBufferItem());
106
107 } // end scope of mMutex autolock
108
Igor Murashkind4d52272013-04-29 10:31:06 -0700109 if (waitForFence) {
Mathias Agopiand7644242013-05-16 18:07:35 -0700110 status_t err = pinnedBuffer->getBufferItem().mFence->waitForever(
Igor Murashkind4d52272013-04-29 10:31:06 -0700111 "RingBufferConsumer::pinSelectedBuffer");
112 if (err != OK) {
113 BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
114 strerror(-err), err);
115 }
116 }
117
118 return pinnedBuffer;
119}
120
121status_t RingBufferConsumer::clear() {
122
123 status_t err;
124 Mutex::Autolock _l(mMutex);
125
126 BI_LOGV("%s", __FUNCTION__);
127
128 // Avoid annoying log warnings by returning early
129 if (mBufferItemList.size() == 0) {
130 return OK;
131 }
132
133 do {
134 size_t pinnedFrames = 0;
135 err = releaseOldestBufferLocked(&pinnedFrames);
136
137 if (err == NO_BUFFER_AVAILABLE) {
138 assert(pinnedFrames == mBufferItemList.size());
139 break;
140 }
141
142 if (err == NOT_ENOUGH_DATA) {
143 // Fine. Empty buffer item list.
144 break;
145 }
146
147 if (err != OK) {
148 BI_LOGE("Clear failed, could not release buffer");
149 return err;
150 }
151
152 } while(true);
153
154 return OK;
155}
156
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -0700157nsecs_t RingBufferConsumer::getLatestTimestamp() {
158 Mutex::Autolock _l(mMutex);
159 if (mBufferItemList.size() == 0) {
160 return 0;
161 }
162 return mLatestTimestamp;
163}
164
Igor Murashkind4d52272013-04-29 10:31:06 -0700165void RingBufferConsumer::pinBufferLocked(const BufferItem& item) {
166 List<RingBufferItem>::iterator it, end;
167
168 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
169 it != end;
170 ++it) {
171
172 RingBufferItem& find = *it;
173 if (item.mGraphicBuffer == find.mGraphicBuffer) {
174 find.mPinCount++;
175 break;
176 }
177 }
178
179 if (it == end) {
Colin Crosse5729fa2014-03-21 15:04:25 -0700180 BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700181 item.mTimestamp, item.mFrameNumber);
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700182 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700183 BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700184 item.mFrameNumber, item.mTimestamp);
Igor Murashkind4d52272013-04-29 10:31:06 -0700185 }
186}
187
188status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) {
189 status_t err = OK;
190
191 List<RingBufferItem>::iterator it, end, accIt;
192
193 it = mBufferItemList.begin();
194 end = mBufferItemList.end();
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700195 accIt = end;
Igor Murashkind4d52272013-04-29 10:31:06 -0700196
197 if (it == end) {
198 /**
199 * This is fine. We really care about being able to acquire a buffer
200 * successfully after this function completes, not about it releasing
201 * some buffer.
202 */
203 BI_LOGV("%s: No buffers yet acquired, can't release anything",
204 __FUNCTION__);
205 return NOT_ENOUGH_DATA;
206 }
207
208 for (; it != end; ++it) {
209 RingBufferItem& find = *it;
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700210
211 if (find.mPinCount > 0) {
212 if (pinnedFrames != NULL) {
213 ++(*pinnedFrames);
214 }
215 // Filter out pinned frame when searching for buffer to release
216 continue;
Igor Murashkind4d52272013-04-29 10:31:06 -0700217 }
218
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700219 if (find.mTimestamp < accIt->mTimestamp || accIt == end) {
220 accIt = it;
Igor Murashkind4d52272013-04-29 10:31:06 -0700221 }
222 }
223
224 if (accIt != end) {
225 RingBufferItem& item = *accIt;
226
227 // In case the object was never pinned, pass the acquire fence
228 // back to the release fence. If the fence was already waited on,
229 // it'll just be a no-op to wait on it again.
Lajos Molnard0304472013-05-15 12:59:19 -0700230
231 // item.mGraphicBuffer was populated with the proper graphic-buffer
232 // at acquire even if it was previously acquired
Pablo Ceballose361bc02015-08-07 15:13:49 -0700233 err = addReleaseFenceLocked(item.mSlot,
Lajos Molnard0304472013-05-15 12:59:19 -0700234 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700235
236 if (err != OK) {
237 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700238 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700239 item.mTimestamp, item.mFrameNumber);
240 return err;
241 }
242
Colin Crosse5729fa2014-03-21 15:04:25 -0700243 BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700244 item.mTimestamp, item.mFrameNumber);
245
Lajos Molnard0304472013-05-15 12:59:19 -0700246 // item.mGraphicBuffer was populated with the proper graphic-buffer
247 // at acquire even if it was previously acquired
Pablo Ceballose361bc02015-08-07 15:13:49 -0700248 err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
Igor Murashkind4d52272013-04-29 10:31:06 -0700249 EGL_NO_DISPLAY,
250 EGL_NO_SYNC_KHR);
251 if (err != OK) {
252 BI_LOGE("Failed to release buffer: %s (%d)",
253 strerror(-err), err);
254 return err;
255 }
256
Colin Crosse5729fa2014-03-21 15:04:25 -0700257 BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted",
Igor Murashkind4d52272013-04-29 10:31:06 -0700258 item.mTimestamp, item.mFrameNumber);
259
Igor Murashkind4d52272013-04-29 10:31:06 -0700260 mBufferItemList.erase(accIt);
Igor Murashkind4d52272013-04-29 10:31:06 -0700261 } else {
262 BI_LOGW("All buffers pinned, could not find any to release");
263 return NO_BUFFER_AVAILABLE;
264
265 }
266
267 return OK;
268}
269
Dan Stoza549e7352015-03-12 15:21:16 -0700270void RingBufferConsumer::onFrameAvailable(const BufferItem& item) {
Igor Murashkind4d52272013-04-29 10:31:06 -0700271 status_t err;
272
273 {
274 Mutex::Autolock _l(mMutex);
275
276 /**
277 * Release oldest frame
278 */
279 if (mBufferItemList.size() >= (size_t)mBufferCount) {
280 err = releaseOldestBufferLocked(/*pinnedFrames*/NULL);
281 assert(err != NOT_ENOUGH_DATA);
282
283 // TODO: implement the case for NO_BUFFER_AVAILABLE
284 assert(err != NO_BUFFER_AVAILABLE);
285 if (err != OK) {
286 return;
287 }
288 // TODO: in unpinBuffer rerun this routine if we had buffers
289 // we could've locked but didn't because there was no space
290 }
291
292 RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(),
293 RingBufferItem());
294
295 /**
296 * Acquire new frame
297 */
Andy McFadden656e8622013-06-28 14:03:03 -0700298 err = acquireBufferLocked(&item, 0);
Igor Murashkind4d52272013-04-29 10:31:06 -0700299 if (err != OK) {
300 if (err != NO_BUFFER_AVAILABLE) {
301 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
302 }
303
304 mBufferItemList.erase(--mBufferItemList.end());
305 return;
306 }
307
Colin Crosse5729fa2014-03-21 15:04:25 -0700308 BI_LOGV("New buffer acquired (timestamp %" PRId64 "), "
309 "buffer items %zu out of %d",
Igor Murashkind4d52272013-04-29 10:31:06 -0700310 item.mTimestamp,
311 mBufferItemList.size(), mBufferCount);
312
Yin-Chia Yeh6b7a2292014-09-09 13:31:46 -0700313 if (item.mTimestamp < mLatestTimestamp) {
314 BI_LOGE("Timestamp decreases from %" PRId64 " to %" PRId64,
315 mLatestTimestamp, item.mTimestamp);
316 }
317
318 mLatestTimestamp = item.mTimestamp;
319
Pablo Ceballose361bc02015-08-07 15:13:49 -0700320 item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
Igor Murashkind4d52272013-04-29 10:31:06 -0700321 } // end of mMutex lock
322
Dan Stoza04f101c2014-11-04 11:32:52 -0800323 ConsumerBase::onFrameAvailable(item);
Igor Murashkind4d52272013-04-29 10:31:06 -0700324}
325
326void RingBufferConsumer::unpinBuffer(const BufferItem& item) {
327 Mutex::Autolock _l(mMutex);
328
329 List<RingBufferItem>::iterator it, end, accIt;
330
331 for (it = mBufferItemList.begin(), end = mBufferItemList.end();
332 it != end;
333 ++it) {
334
335 RingBufferItem& find = *it;
336 if (item.mGraphicBuffer == find.mGraphicBuffer) {
Pablo Ceballose361bc02015-08-07 15:13:49 -0700337 status_t res = addReleaseFenceLocked(item.mSlot,
Lajos Molnard0304472013-05-15 12:59:19 -0700338 item.mGraphicBuffer, item.mFence);
Igor Murashkind4d52272013-04-29 10:31:06 -0700339
340 if (res != OK) {
341 BI_LOGE("Failed to add release fence to buffer "
Colin Crosse5729fa2014-03-21 15:04:25 -0700342 "(timestamp %" PRId64 ", framenumber %" PRIu64,
Igor Murashkind4d52272013-04-29 10:31:06 -0700343 item.mTimestamp, item.mFrameNumber);
344 return;
345 }
346
347 find.mPinCount--;
348 break;
349 }
350 }
351
352 if (it == end) {
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700353 // This should never happen. If it happens, we have a bug.
Colin Crosse5729fa2014-03-21 15:04:25 -0700354 BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkinefb0fd22013-05-22 15:54:57 -0700355 item.mTimestamp, item.mFrameNumber);
356 } else {
Colin Crosse5729fa2014-03-21 15:04:25 -0700357 BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")",
Igor Murashkind4d52272013-04-29 10:31:06 -0700358 item.mTimestamp, item.mFrameNumber);
359 }
360}
361
362status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
363 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700364 return mConsumer->setDefaultBufferSize(w, h);
Igor Murashkind4d52272013-04-29 10:31:06 -0700365}
366
367status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
368 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700369 return mConsumer->setDefaultBufferFormat(defaultFormat);
Igor Murashkind4d52272013-04-29 10:31:06 -0700370}
371
Emilian Peev050f5dc2017-05-18 14:43:56 +0100372status_t RingBufferConsumer::setConsumerUsage(uint64_t usage) {
Igor Murashkind4d52272013-04-29 10:31:06 -0700373 Mutex::Autolock _l(mMutex);
Mathias Agopiandeeef542013-08-02 01:50:59 -0700374 return mConsumer->setConsumerUsageBits(usage);
Igor Murashkind4d52272013-04-29 10:31:06 -0700375}
376
377} // namespace android