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