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);
}