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 23#include <utils/Log.h> 24 25#include <gui/RingBufferConsumer.h> 26 27#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__) 32 33#undef assert 34#define assert(x) ALOG_ASSERT((x), #x) 35 36typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; 37 38namespace android { 39 40RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, 41 uint64_t consumerUsage, 42 int bufferCount) : 43 ConsumerBase(consumer), 44 mBufferCount(bufferCount), 45 mLatestTimestamp(0) 46{ 47 mConsumer->setConsumerUsageBits(consumerUsage); 48 mConsumer->setMaxAcquiredBufferCount(bufferCount); 49 50 assert(bufferCount > 0); 51} 52 53RingBufferConsumer::~RingBufferConsumer() { 54} 55 56void RingBufferConsumer::setName(const String8& name) { 57 Mutex::Autolock _l(mMutex); 58 mName = name; 59 mConsumer->setConsumerName(name); 60} 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 108 if (waitForFence) { 109 status_t err = pinnedBuffer->getBufferItem().mFence->waitForever( 110 "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 156nsecs_t RingBufferConsumer::getLatestTimestamp() { 157 Mutex::Autolock _l(mMutex); 158 if (mBufferItemList.size() == 0) { 159 return 0; 160 } 161 return mLatestTimestamp; 162} 163 164void 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) { 179 BI_LOGE("Failed to pin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")", 180 item.mTimestamp, item.mFrameNumber); 181 } else { 182 BI_LOGV("Pinned buffer (frame %" PRIu64 ", timestamp %" PRId64 ")", 183 item.mFrameNumber, item.mTimestamp); 184 } 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(); 194 accIt = end; 195 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; 209 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; 216 } 217 218 if (find.mTimestamp < accIt->mTimestamp || accIt == end) { 219 accIt = it; 220 } 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. 229 230 // item.mGraphicBuffer was populated with the proper graphic-buffer 231 // at acquire even if it was previously acquired 232 err = addReleaseFenceLocked(item.mSlot, 233 item.mGraphicBuffer, item.mFence); 234 235 if (err != OK) { 236 BI_LOGE("Failed to add release fence to buffer " 237 "(timestamp %" PRId64 ", framenumber %" PRIu64, 238 item.mTimestamp, item.mFrameNumber); 239 return err; 240 } 241 242 BI_LOGV("Attempting to release buffer timestamp %" PRId64 ", frame %" PRIu64, 243 item.mTimestamp, item.mFrameNumber); 244 245 // item.mGraphicBuffer was populated with the proper graphic-buffer 246 // at acquire even if it was previously acquired 247 err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, 248 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 256 BI_LOGV("Buffer timestamp %" PRId64 ", frame %" PRIu64 " evicted", 257 item.mTimestamp, item.mFrameNumber); 258 259 mBufferItemList.erase(accIt); 260 } 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 269void RingBufferConsumer::onFrameAvailable(const BufferItem& item) { 270 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 */ 297 err = acquireBufferLocked(&item, 0); 298 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 307 BI_LOGV("New buffer acquired (timestamp %" PRId64 "), " 308 "buffer items %zu out of %d", 309 item.mTimestamp, 310 mBufferItemList.size(), mBufferCount); 311 312 if (item.mTimestamp < mLatestTimestamp) { 313 BI_LOGE("Timestamp decreases from %" PRId64 " to %" PRId64, 314 mLatestTimestamp, item.mTimestamp); 315 } 316 317 mLatestTimestamp = item.mTimestamp; 318 319 item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer; 320 } // end of mMutex lock 321 322 ConsumerBase::onFrameAvailable(item); 323} 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) { 336 status_t res = addReleaseFenceLocked(item.mSlot, 337 item.mGraphicBuffer, item.mFence); 338 339 if (res != OK) { 340 BI_LOGE("Failed to add release fence to buffer " 341 "(timestamp %" PRId64 ", framenumber %" PRIu64, 342 item.mTimestamp, item.mFrameNumber); 343 return; 344 } 345 346 find.mPinCount--; 347 break; 348 } 349 } 350 351 if (it == end) { 352 // This should never happen. If it happens, we have a bug. 353 BI_LOGE("Failed to unpin buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")", 354 item.mTimestamp, item.mFrameNumber); 355 } else { 356 BI_LOGV("Unpinned buffer (timestamp %" PRId64 ", framenumber %" PRIu64 ")", 357 item.mTimestamp, item.mFrameNumber); 358 } 359} 360 361status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { 362 Mutex::Autolock _l(mMutex); 363 return mConsumer->setDefaultBufferSize(w, h); 364} 365 366status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { 367 Mutex::Autolock _l(mMutex); 368 return mConsumer->setDefaultBufferFormat(defaultFormat); 369} 370 371status_t RingBufferConsumer::setConsumerUsage(uint64_t usage) { 372 Mutex::Autolock _l(mMutex); 373 return mConsumer->setConsumerUsageBits(usage); 374} 375 376} // namespace android 377