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