void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, dbgStateStr()); VDS_LOGV("cancelBuffer pslot=%d", pslot); Source source = fbSourceForCompositionType(mCompositionType); return mSource[source]->cancelBuffer( mapProducer2SourceSlot(source, pslot), 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 VirtualDisplaySurface::queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output) { if (mDisplayId < 0) return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, "Unexpected queueBuffer(pslot=%d) in %s state", pslot, dbgStateStr()); mDbgState = DBG_STATE_GLES_DONE; VDS_LOGV("queueBuffer pslot=%d", pslot); status_t result; if (mCompositionType == COMPOSITION_MIXED) { // Queue the buffer back into the scratch pool QueueBufferOutput scratchQBO; int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO); if (result != NO_ERROR) return result; // Now acquire the buffer from the scratch pool -- should be the same // slot and fence as we just queued. Mutex::Autolock lock(mMutex); BufferItem item; result = acquireBufferLocked(&item, 0); if (result != NO_ERROR) return result; VDS_LOGW_IF(item.mBuf != sslot, "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", item.mBuf, sslot); mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf); mFbFence = mSlots[item.mBuf].mFence; } else { LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES, "Unexpected queueBuffer in state %s for compositionType %s", dbgStateStr(), dbgCompositionTypeStr(mCompositionType)); // Extract the GLES release fence for HWC to acquire int64_t timestamp; bool isAutoTimestamp; android_dataspace dataSpace; Rect crop; int scalingMode; uint32_t transform; bool async; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &async, &mFbFence); mFbProducerSlot = pslot; mOutputFence = mFbFence; } *output = mQueueBufferOutput; return NO_ERROR; }
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 VirtualDisplaySurface::refreshOutputBuffer() { if (mOutputProducerSlot >= 0) { mSource[SOURCE_SINK]->cancelBuffer( mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot), mOutputFence); } int sslot; status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage, &sslot, &mOutputFence); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); // On GLES-only frames, we don't have the right output buffer acquire fence // until after GLES calls queueBuffer(). So here we just set the buffer // (for use in HWC prepare) but not the fence; we'll call this again with // the proper fence once we have it. result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE, mProducerBuffers[mOutputProducerSlot]); return result; }