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; }
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { if (mDisplayId < 0) return NO_ERROR; VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, "Unexpected prepareFrame() in %s state", dbgStateStr()); mDbgState = DBG_STATE_PREPARED; mCompositionType = compositionType; if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) { // Some hardware can do RGB->YUV conversion more efficiently in hardware // controlled by HWC than in hardware controlled by the video encoder. // Forcing GLES-composed frames to go through an extra copy by the HWC // allows the format conversion to happen there, rather than passing RGB // directly to the consumer. // // On the other hand, when the consumer prefers RGB or can consume RGB // inexpensively, this forces an unnecessary copy. mCompositionType = COMPOSITION_MIXED; } if (mCompositionType != mDbgLastCompositionType) { VDS_LOGV("prepareFrame: composition type changed to %s", dbgCompositionTypeStr(mCompositionType)); mDbgLastCompositionType = mCompositionType; } if (mCompositionType != COMPOSITION_GLES && (mOutputFormat != mDefaultOutputFormat || mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { // We must have just switched from GLES-only to MIXED or HWC // composition. Stop using the format and usage requested by the GLES // driver; they may be suboptimal when HWC is writing to the output // buffer. For example, if the output is going to a video encoder, and // HWC can write directly to YUV, some hardware can skip a // memory-to-memory RGB-to-YUV conversion step. // // If we just switched *to* GLES-only mode, we'll change the // format/usage and get a new buffer when the GLES driver calls // dequeueBuffer(). mOutputFormat = mDefaultOutputFormat; mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; refreshOutputBuffer(); } return NO_ERROR; }