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