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(); }
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp<IGraphicBufferProducer>& sink, const sp<IGraphicBufferProducer>& bqProducer, const sp<IGraphicBufferConsumer>& bqConsumer, const String8& name) : ConsumerBase(bqConsumer), mHwc(hwc), mDisplayId(dispId), mDisplayName(name), mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), mProducerSlotSource(0), mDbgState(DBG_STATE_IDLE), mDbgLastCompositionType(COMPOSITION_UNKNOWN), mMustRecompose(false) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; resetPerFrameState(); int sinkWidth, sinkHeight; sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); mSinkBufferWidth = sinkWidth; mSinkBufferHeight = sinkHeight; // Pick the buffer format to request from the sink when not rendering to it // with GLES. If the consumer needs CPU access, use the default format // set by the consumer. Otherwise allow gralloc to decide the format based // on usage bits. int sinkUsage; sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { int sinkFormat; sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); mDefaultOutputFormat = sinkFormat; } else { mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; } mOutputFormat = mDefaultOutputFormat; ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); mConsumer->setConsumerName(ConsumerBase::mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); mConsumer->setDefaultMaxBufferCount(2); }
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(); }
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t &hwcDisplayId, const sp<IGraphicBufferProducer>& sink, const sp<IGraphicBufferProducer>& bqProducer, const sp<IGraphicBufferConsumer>& bqConsumer, const String8& name, bool secure) : ConsumerBase(bqConsumer), mHwc(hwc), mDisplayId(NO_MEMORY), mDisplayName(name), mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), mProducerSlotSource(0), mDbgState(DBG_STATE_IDLE), mDbgLastCompositionType(COMPOSITION_UNKNOWN), mMustRecompose(false), mForceHwcCopy(false), mSecure(false) { mSource[SOURCE_SINK] = sink; mSource[SOURCE_SCRATCH] = bqProducer; int sinkWidth, sinkHeight, sinkFormat, sinkUsage; sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); mSinkBufferWidth = sinkWidth; mSinkBufferHeight = sinkHeight; // Pick the buffer format to request from the sink when not rendering to it // with GLES. If the consumer needs CPU access, use the default format // set by the consumer. Otherwise allow gralloc to decide the format based // on usage bits. mDefaultOutputFormat = sinkFormat; if((sinkUsage & GRALLOC_USAGE_HW_VIDEO_ENCODER) #ifdef QCOM_BSP && (sinkUsage & GRALLOC_USAGE_PRIVATE_WFD) #endif ) { mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; mForceHwcCopy = true; //Set secure flag only if the session requires HW protection, currently //there is no other way to distinguish different security protection levels //This allows Level-3 sessions(eg.simulated displayes) to get //buffers from IOMMU heap and not MM (secure) heap. mSecure = secure; } // XXX: With this debug property we can allow screenrecord to be composed // via HWC. This is useful for debugging purposes, for example when WFD // is not working on a particular build. char value[PROPERTY_VALUE_MAX]; if( (property_get("debug.hwc.screenrecord", value, NULL) > 0) && ((!strncmp(value, "1", strlen("1"))) || !strncasecmp(value, "true", strlen("true")))) { mForceHwcCopy = true; } // Once the mForceHwcCopy flag is set, we can freely allocate an HWC // display ID. if (mForceHwcCopy && mHwc.isVDSEnabled()) mDisplayId = mHwc.allocateDisplayId(); hwcDisplayId = mDisplayId; //update display id for device creation in SF mOutputFormat = mDefaultOutputFormat; // TODO: need to add the below logs as part of dumpsys output VDS_LOGV("creation: sinkFormat: 0x%x sinkUsage: 0x%x mForceHwcCopy: %d", mOutputFormat, sinkUsage, mForceHwcCopy); setOutputUsage(); resetPerFrameState(); ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); mConsumer->setConsumerName(ConsumerBase::mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); mConsumer->setDefaultMaxBufferCount(2); }