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