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 33 typedef android::RingBufferConsumer::PinnedBufferItem PinnedBufferItem; 34 35 namespace android { 36 37 RingBufferConsumer::RingBufferConsumer(const sp<IGraphicBufferConsumer>& consumer, 38 uint32_t consumerUsage, 39 int bufferCount) : 40 ConsumerBase(consumer), 41 mBufferCount(bufferCount) 42 { 43 mConsumer->setConsumerUsageBits(consumerUsage); 44 mConsumer->setMaxAcquiredBufferCount(bufferCount); 45 46 assert(bufferCount > 0); 47 } 48 49 RingBufferConsumer::~RingBufferConsumer() { 50 } 51 52 void RingBufferConsumer::setName(const String8& name) { 53 Mutex::Autolock _l(mMutex); 54 mName = name; 55 mConsumer->setConsumerName(name); 56 } 57 58 sp<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 116 status_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 152 void 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 175 status_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 218 // item.mGraphicBuffer was populated with the proper graphic-buffer 219 // at acquire even if it was previously acquired 220 err = addReleaseFenceLocked(item.mBuf, 221 item.mGraphicBuffer, item.mFence); 222 223 if (err != OK) { 224 BI_LOGE("Failed to add release fence to buffer " 225 "(timestamp %lld, framenumber %lld", 226 item.mTimestamp, item.mFrameNumber); 227 return err; 228 } 229 230 BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld", 231 item.mTimestamp, item.mFrameNumber); 232 233 // item.mGraphicBuffer was populated with the proper graphic-buffer 234 // at acquire even if it was previously acquired 235 err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, 236 EGL_NO_DISPLAY, 237 EGL_NO_SYNC_KHR); 238 if (err != OK) { 239 BI_LOGE("Failed to release buffer: %s (%d)", 240 strerror(-err), err); 241 return err; 242 } 243 244 BI_LOGV("Buffer timestamp %lld, frame %lld evicted", 245 item.mTimestamp, item.mFrameNumber); 246 247 size_t currentSize = mBufferItemList.size(); 248 mBufferItemList.erase(accIt); 249 assert(mBufferItemList.size() == currentSize - 1); 250 } else { 251 BI_LOGW("All buffers pinned, could not find any to release"); 252 return NO_BUFFER_AVAILABLE; 253 254 } 255 256 return OK; 257 } 258 259 void RingBufferConsumer::onFrameAvailable() { 260 status_t err; 261 262 { 263 Mutex::Autolock _l(mMutex); 264 265 /** 266 * Release oldest frame 267 */ 268 if (mBufferItemList.size() >= (size_t)mBufferCount) { 269 err = releaseOldestBufferLocked(/*pinnedFrames*/NULL); 270 assert(err != NOT_ENOUGH_DATA); 271 272 // TODO: implement the case for NO_BUFFER_AVAILABLE 273 assert(err != NO_BUFFER_AVAILABLE); 274 if (err != OK) { 275 return; 276 } 277 // TODO: in unpinBuffer rerun this routine if we had buffers 278 // we could've locked but didn't because there was no space 279 } 280 281 RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(), 282 RingBufferItem()); 283 284 /** 285 * Acquire new frame 286 */ 287 err = acquireBufferLocked(&item, 0); 288 if (err != OK) { 289 if (err != NO_BUFFER_AVAILABLE) { 290 BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); 291 } 292 293 mBufferItemList.erase(--mBufferItemList.end()); 294 return; 295 } 296 297 BI_LOGV("New buffer acquired (timestamp %lld), " 298 "buffer items %u out of %d", 299 item.mTimestamp, 300 mBufferItemList.size(), mBufferCount); 301 302 item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer; 303 } // end of mMutex lock 304 305 ConsumerBase::onFrameAvailable(); 306 } 307 308 void RingBufferConsumer::unpinBuffer(const BufferItem& item) { 309 Mutex::Autolock _l(mMutex); 310 311 List<RingBufferItem>::iterator it, end, accIt; 312 313 for (it = mBufferItemList.begin(), end = mBufferItemList.end(); 314 it != end; 315 ++it) { 316 317 RingBufferItem& find = *it; 318 if (item.mGraphicBuffer == find.mGraphicBuffer) { 319 status_t res = addReleaseFenceLocked(item.mBuf, 320 item.mGraphicBuffer, item.mFence); 321 322 if (res != OK) { 323 BI_LOGE("Failed to add release fence to buffer " 324 "(timestamp %lld, framenumber %lld", 325 item.mTimestamp, item.mFrameNumber); 326 return; 327 } 328 329 find.mPinCount--; 330 break; 331 } 332 } 333 334 if (it == end) { 335 // This should never happen. If it happens, we have a bug. 336 BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld)", 337 item.mTimestamp, item.mFrameNumber); 338 } else { 339 BI_LOGV("Unpinned buffer (timestamp %lld, framenumber %lld)", 340 item.mTimestamp, item.mFrameNumber); 341 } 342 } 343 344 status_t RingBufferConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { 345 Mutex::Autolock _l(mMutex); 346 return mConsumer->setDefaultBufferSize(w, h); 347 } 348 349 status_t RingBufferConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { 350 Mutex::Autolock _l(mMutex); 351 return mConsumer->setDefaultBufferFormat(defaultFormat); 352 } 353 354 status_t RingBufferConsumer::setConsumerUsage(uint32_t usage) { 355 Mutex::Autolock _l(mMutex); 356 return mConsumer->setConsumerUsageBits(usage); 357 } 358 359 } // namespace android 360