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); } }
status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { Mutex::Autolock lock(mMutex); // [MTK] {{{ // remember that a release fence is set by non-gl module mNonGLFenceIsSet[slot] = true; // [MTK] }}} return addReleaseFenceLocked(slot, fence); }
void VirtualDisplaySurface::onFrameCommitted() { if (mDisplayId < 0) return; VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId); if (mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); // Allow queuing to sink buffer if mMustRecompose is true or // mForceHwcCopy is true. This is required to support Miracast WFD Sink // Initiatied Pause/Resume feature support if (mForceHwcCopy || mMustRecompose) { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( systemTime(), false /* isAutoTimestamp */, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, true /* async*/, outFence), &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); } } else { // If the surface hadn't actually been updated, then we only went // through the motions of updating the display to keep our state // machine happy. We cancel the buffer to avoid triggering another // re-composition and causing an infinite loop. mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); } } resetPerFrameState(); }
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 GonkNativeWindow::returnBuffer(TextureClient* client) { BI_LOGD("GonkNativeWindow::returnBuffer"); Mutex::Autolock lock(mMutex); int index = mBufferQueue->getSlotFromTextureClientLocked(client); if (index < 0) { } sp<Fence> fence = client->GetReleaseFenceHandle().mFence; if (!fence.get()) { fence = Fence::NO_FENCE; } status_t err; err = addReleaseFenceLocked(index, fence); err = releaseBufferLocked(index); }
bool GonkNativeWindow::returnBuffer(uint32_t index, uint32_t generation, const sp<Fence>& fence) { BI_LOGD("GonkNativeWindow::returnBuffer: slot=%d (generation=%d)", index, generation); Mutex::Autolock lock(mMutex); if (generation != mBufferQueue->getGeneration()) { BI_LOGD("returnBuffer: buffer is from generation %d (current is %d)", generation, mBufferQueue->getGeneration()); return false; } status_t err; err = addReleaseFenceLocked(index, fence); err = releaseBufferLocked(index); if (err != NO_ERROR) { return false; } return true; }
void VirtualDisplaySurface::onFrameCommitted() { if (mDisplayId < 0) return; VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, "Unexpected onFrameCommitted() in %s state", dbgStateStr()); mDbgState = DBG_STATE_IDLE; sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId); if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { // release the scratch buffer back to the pool Mutex::Autolock lock(mMutex); int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } if (mOutputProducerSlot >= 0) { int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); QueueBufferOutput qbo; sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput( systemTime(), false /* isAutoTimestamp */, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, true /* async*/, outFence), &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); } } resetPerFrameState(); }
status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) { status_t err; int fd = -1; err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd); if (err != OK) { CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__, lockedIdx); return err; } int buf = mAcquiredBuffers[lockedIdx].mSlot; if (CC_LIKELY(fd != -1)) { sp<Fence> fence(new Fence(fd)); addReleaseFenceLocked( mAcquiredBuffers[lockedIdx].mSlot, mSlots[buf].mGraphicBuffer, fence); } // release the buffer if it hasn't already been freed by the BufferQueue. // This can happen, for example, when the producer of this buffer // disconnected after this buffer was acquired. if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == mSlots[buf].mGraphicBuffer)) { releaseBufferLocked( buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; ab.mBufferPointer = NULL; ab.mGraphicBuffer.clear(); mCurrentLockedBuffers--; return OK; }
status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { ST_LOGV("syncForReleaseLocked"); if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { if (useNativeFenceSync) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); eglDestroySyncKHR(dpy, sync); if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { ST_LOGE("syncForReleaseLocked: error dup'ing native fence " "fd: %#x", eglGetError()); return UNKNOWN_ERROR; } sp<Fence> fence(new Fence(fenceFd)); status_t err = addReleaseFenceLocked(mCurrentTexture, fence); if (err != OK) { ST_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); return err; } } else if (mUseFenceSync) { EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to // wait on that before replacing it with another fence to // ensure that all outstanding buffer accesses have completed // before the producer accesses it. EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); if (result == EGL_FALSE) { ST_LOGE("syncForReleaseLocked: error waiting for previous " "fence: %#x", eglGetError()); return UNKNOWN_ERROR; } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { ST_LOGE("syncForReleaseLocked: timeout waiting for previous " "fence"); return TIMED_OUT; } eglDestroySyncKHR(dpy, fence); } // Create a fence for the outstanding accesses in the current // OpenGL ES context. fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL); if (fence == EGL_NO_SYNC_KHR) { ST_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); return UNKNOWN_ERROR; } glFlush(); mEglSlots[mCurrentTexture].mEglFence = fence; } } return OK; }
status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { Mutex::Autolock lock(mMutex); return addReleaseFenceLocked(slot, fence); }
status_t GonkConsumerBase::addReleaseFence(int slot, const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { Mutex::Autolock lock(mMutex); return addReleaseFenceLocked(slot, graphicBuffer, fence); }
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; }