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