status_t GonkNativeWindow::acquireBuffer(BufferItem *item, bool waitForFence) { status_t err; if (!item) return BAD_VALUE; Mutex::Autolock _l(mMutex); err = acquireBufferLocked(item); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); } return err; } if (waitForFence) { err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); if (err != OK) { BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); return err; } } item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; return OK; }
void RingBufferConsumer::unpinBuffer(const BufferItem& item) { Mutex::Autolock _l(mMutex); List<RingBufferItem>::iterator it, end, accIt; for (it = mBufferItemList.begin(), end = mBufferItemList.end(); it != end; ++it) { RingBufferItem& find = *it; if (item.mGraphicBuffer == find.mGraphicBuffer) { status_t res = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, item.mFence); if (res != OK) { BI_LOGE("Failed to add release fence to buffer " "(timestamp %lld, framenumber %lld", item.mTimestamp, item.mFrameNumber); return; } find.mPinCount--; break; } } if (it == end) { // This should never happen. If it happens, we have a bug. BI_LOGE("Failed to unpin buffer (timestamp %lld, framenumber %lld)", item.mTimestamp, item.mFrameNumber); } else { BI_LOGV("Unpinned buffer (timestamp %lld, framenumber %lld)", item.mTimestamp, item.mFrameNumber); } }
void RingBufferConsumer::onFrameAvailable(const BufferItem& item) { status_t err; { Mutex::Autolock _l(mMutex); /** * Release oldest frame */ if (mBufferItemList.size() >= (size_t)mBufferCount) { err = releaseOldestBufferLocked(/*pinnedFrames*/NULL); assert(err != NOT_ENOUGH_DATA); // TODO: implement the case for NO_BUFFER_AVAILABLE assert(err != NO_BUFFER_AVAILABLE); if (err != OK) { return; } // TODO: in unpinBuffer rerun this routine if we had buffers // we could've locked but didn't because there was no space } RingBufferItem& item = *mBufferItemList.insert(mBufferItemList.end(), RingBufferItem()); /** * Acquire new frame */ err = acquireBufferLocked(&item, 0); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); } mBufferItemList.erase(--mBufferItemList.end()); return; } BI_LOGV("New buffer acquired (timestamp %" PRId64 "), " "buffer items %zu out of %d", item.mTimestamp, mBufferItemList.size(), mBufferCount); if (item.mTimestamp < mLatestTimestamp) { BI_LOGE("Timestamp decreases from %" PRId64 " to %" PRId64, mLatestTimestamp, item.mTimestamp); } mLatestTimestamp = item.mTimestamp; item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer; } // end of mMutex lock ConsumerBase::onFrameAvailable(item); }
status_t RingBufferConsumer::clear() { status_t err; Mutex::Autolock _l(mMutex); BI_LOGV("%s", __FUNCTION__); // Avoid annoying log warnings by returning early if (mBufferItemList.size() == 0) { return OK; } do { size_t pinnedFrames = 0; err = releaseOldestBufferLocked(&pinnedFrames); if (err == NO_BUFFER_AVAILABLE) { assert(pinnedFrames == mBufferItemList.size()); break; } if (err == NOT_ENOUGH_DATA) { // Fine. Empty buffer item list. break; } if (err != OK) { BI_LOGE("Clear failed, could not release buffer"); return err; } } while(true); return OK; }
sp<PinnedBufferItem> RingBufferConsumer::pinSelectedBuffer( const RingBufferComparator& filter, bool waitForFence) { sp<PinnedBufferItem> pinnedBuffer; { List<RingBufferItem>::iterator it, end, accIt; BufferInfo acc, cur; BufferInfo* accPtr = NULL; Mutex::Autolock _l(mMutex); for (it = mBufferItemList.begin(), end = mBufferItemList.end(); it != end; ++it) { const RingBufferItem& item = *it; cur.mCrop = item.mCrop; cur.mTransform = item.mTransform; cur.mScalingMode = item.mScalingMode; cur.mTimestamp = item.mTimestamp; cur.mFrameNumber = item.mFrameNumber; cur.mPinned = item.mPinCount > 0; int ret = filter.compare(accPtr, &cur); if (ret == 0) { accPtr = NULL; } else if (ret > 0) { acc = cur; accPtr = &acc; accIt = it; } // else acc = acc } if (!accPtr) { return NULL; } pinnedBuffer = new PinnedBufferItem(this, *accIt); pinBufferLocked(pinnedBuffer->getBufferItem()); } // end scope of mMutex autolock if (waitForFence) { status_t err = pinnedBuffer->getBufferItem().mFence->waitForever( "RingBufferConsumer::pinSelectedBuffer"); if (err != OK) { BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); } } return pinnedBuffer; }
status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence) { status_t err; Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mBuf, releaseFence); err = releaseBufferLocked(item.mBuf); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } return err; }
status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence) { status_t err; Mutex::Autolock _l(mMutex); err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); } return err; }
void RingBufferConsumer::pinBufferLocked(const BufferItem& item) { List<RingBufferItem>::iterator it, end; for (it = mBufferItemList.begin(), end = mBufferItemList.end(); it != end; ++it) { RingBufferItem& find = *it; if (item.mGraphicBuffer == find.mGraphicBuffer) { find.mPinCount++; break; } } if (it == end) { BI_LOGE("Failed to pin buffer (timestamp %lld, framenumber %lld)", item.mTimestamp, item.mFrameNumber); } else { BI_LOGV("Pinned buffer (frame %lld, timestamp %lld)", item.mFrameNumber, item.mTimestamp); } }
status_t RingBufferConsumer::releaseOldestBufferLocked(size_t* pinnedFrames) { status_t err = OK; List<RingBufferItem>::iterator it, end, accIt; it = mBufferItemList.begin(); end = mBufferItemList.end(); accIt = end; if (it == end) { /** * This is fine. We really care about being able to acquire a buffer * successfully after this function completes, not about it releasing * some buffer. */ BI_LOGV("%s: No buffers yet acquired, can't release anything", __FUNCTION__); return NOT_ENOUGH_DATA; } for (; it != end; ++it) { RingBufferItem& find = *it; if (find.mPinCount > 0) { if (pinnedFrames != NULL) { ++(*pinnedFrames); } // Filter out pinned frame when searching for buffer to release continue; } if (find.mTimestamp < accIt->mTimestamp || accIt == end) { accIt = it; } } if (accIt != end) { RingBufferItem& item = *accIt; // In case the object was never pinned, pass the acquire fence // back to the release fence. If the fence was already waited on, // it'll just be a no-op to wait on it again. // item.mGraphicBuffer was populated with the proper graphic-buffer // at acquire even if it was previously acquired err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, item.mFence); if (err != OK) { BI_LOGE("Failed to add release fence to buffer " "(timestamp %lld, framenumber %lld", item.mTimestamp, item.mFrameNumber); return err; } BI_LOGV("Attempting to release buffer timestamp %lld, frame %lld", item.mTimestamp, item.mFrameNumber); // item.mGraphicBuffer was populated with the proper graphic-buffer // at acquire even if it was previously acquired err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); return err; } BI_LOGV("Buffer timestamp %lld, frame %lld evicted", item.mTimestamp, item.mFrameNumber); size_t currentSize = mBufferItemList.size(); mBufferItemList.erase(accIt); assert(mBufferItemList.size() == currentSize - 1); } else { BI_LOGW("All buffers pinned, could not find any to release"); return NO_BUFFER_AVAILABLE; } return OK; }