[Spice-devel] [PATCH v3 5/6] qxl-wddm-dod: Timer-based VSync interrupt indication

Frediano Ziglio fziglio at redhat.com
Wed Feb 22 12:18:20 UTC 2017


> On Thu, Feb 16, 2017 at 5:54 PM, Frediano Ziglio < fziglio at redhat.com >
> wrote:

> > >
> 
> > > In case the driver supports VSync control feature, it
> 
> > > maintains timer for VSync interrupt indication.
> 
> > > In further commits this timer will be started upon
> 
> > > class driver request. The interrupt notification and
> 
> > > related DPC do not access device registers.
> 
> > >
> 
> > > Signed-off-by: Yuri Benditovich < yuri.benditovich at daynix.com >
> 
> > > ---
> 
> > > qxldod/QxlDod.cpp | 82
> 
> > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 
> > > qxldod/QxlDod.h | 14 ++++++++++
> 
> > > 2 files changed, 96 insertions(+)
> 
> > >
> 
> > > diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp
> 
> > > index cd22446..9175300 100755
> 
> > > --- a/qxldod/QxlDod.cpp
> 
> > > +++ b/qxldod/QxlDod.cpp
> 
> > > @@ -82,6 +82,12 @@ QxlDod::QxlDod(_In_ DEVICE_OBJECT*
> > > pPhysicalDeviceObject)
> 
> > > : m_pPhysicalDevice(pP
> 
> > > RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
> 
> > > RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape));
> 
> > > m_pHWDevice = NULL;
> 
> > > +
> 
> > > + KeInitializeDpc(&m_VsyncTimerDpc, VsyncTimerProcGate, this);
> 
> > > + KeInitializeTimer(&m_VsyncTimer);
> 
> > > + m_VsyncFiredCounter = 0;
> 
> > > + m_bVsyncEnabled = FALSE;
> 
> > > +
> 
> > > DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
> 
> > > }
> 
> > >
> 
> > > @@ -198,6 +204,7 @@ NTSTATUS QxlDod::StopDevice(VOID)
> 
> > > {
> 
> > > PAGED_CODE();
> 
> > > m_Flags.DriverStarted = FALSE;
> 
> > > + EnableVsync(FALSE);
> 
> > > return STATUS_SUCCESS;
> 
> > > }
> 
> > >
> 
> > > @@ -518,6 +525,7 @@ NTSTATUS QxlDod::QueryAdapterInfo(_In_ CONST
> 
> > > DXGKARG_QUERYADAPTERINFO* pQueryAda
> 
> > > pDriverCaps->PointerCaps.Color = 1;
> 
> > >
> 
> > > pDriverCaps->SupportNonVGA = m_pHWDevice->IsBIOSCompatible();
> 
> > > + pDriverCaps->SchedulingCaps.VSyncPowerSaveAware =
> 
> > > g_bSupportVSync;
> 
> > >
> 

> > I think we could set this to TRUE. If OS supports VSync will deactivate
> 
> > if not should do nothing or try to deactivate.
> 
> > Could be if set to FALSE that OS still expect VSync coming or don't
> 
> > enable some energy saving policy.
> 

> Setting it to TRUE when VSync is not supported may create some side-effect in
> Windows,
> as this combination is not expected. Setting it to FALSE when VSync is
> supported also does
> not make too much sense as then the driver will send indications also when
> the system
> is completely inactive. So, only meaningful choice for us is to keep it equal
> to VSync control.

> > > DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__));
> 
> > > return STATUS_SUCCESS;
> 
> > > @@ -4813,6 +4821,14 @@ BOOLEAN QxlDevice::InterruptRoutine(_In_
> 
> > > PDXGKRNL_INTERFACE pDxgkInterface, _In_
> 
> > > }
> 
> > >
> 
> > > QXL_NON_PAGED
> 
> > > +VOID QxlDevice::VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE
> 
> > > pDxgkInterface)
> 
> > > +{
> 
> > > + if (!pDxgkInterface->DxgkCbQueueDpc(pDxgkInterface->DeviceHandle)) {
> 
> > > + DbgPrint(TRACE_LEVEL_WARNING, ("---> %s can't enqueue DPC, pending
> 
> > > interrupts %X\n", __FUNCTION__, m_Pending));
> 
> > > + }
> 
> > > +}
> 
> > > +
> 
> > > +QXL_NON_PAGED
> 
> > > VOID QxlDevice::DpcRoutine(PVOID)
> 
> > > {
> 
> > > LONG intStatus = InterlockedExchange(&m_Pending, 0);
> 
> > > @@ -4914,3 +4930,69 @@ NTSTATUS
> 
> > > HwDeviceInterface::AcquireDisplayInfo(DXGK_DISPLAY_INFORMATION& DispInf
> 
> > > }
> 
> > > return Status;
> 
> > > }
> 
> > > +
> 
> > > +// Vga device does not generate interrupts
> 
> > > +QXL_NON_PAGED VOID VgaDevice::VSyncInterruptPostProcess(_In_
> 
> > > PDXGKRNL_INTERFACE pxface)
> 
> > > +{
> 
> > > + pxface->DxgkCbQueueDpc(pxface->DeviceHandle);
> 
> > > +}
> 
> > > +
> 
> > > +QXL_NON_PAGED VOID QxlDod::IndicateVSyncInterrupt()
> 
> > > +{
> 

> > Maybe is more flexible if this function returns BOOLEAN.
> 

> > > + DXGKARGCB_NOTIFY_INTERRUPT_DATA data = {};
> 
> > > + data.InterruptType = DXGK_INTERRUPT_DISPLAYONLY_VSYNC;
> 
> > > + m_DxgkInterface.DxgkCbNotifyInterrupt(m_DxgkInterface.DeviceHandle,
> 
> > > &data);
> 
> > > + m_pHWDevice->VSyncInterruptPostProcess(&m_DxgkInterface);
> 
> > > +}
> 
> > > +
> 
> > > +QXL_NON_PAGED BOOLEAN QxlDod::VsyncTimerSynchRoutine(PVOID context)
> 
> > > +{
> 
> > > + QxlDod* pQxl = reinterpret_cast<QxlDod*>(context);
> 
> > > + pQxl->IndicateVSyncInterrupt();
> 
> > > + return FALSE;
> 

> > Here would be
> 

> > return pQxl->IndicateVSyncInterrupt();
> 

> > so we could handle the return value from the member function (if needed
> 
> > in the future).
> 

> This procedure currently returns boolean just because Windows
> synch routine prototype defined such a way without any reason.
> There is no meaningful information that we can pass back on this boolean.
> When synch procedure needs to return something little bigger than boolean,
> local context passed to the routine does the job.

> > > +}
> 
> > > +
> 
> > > +QXL_NON_PAGED VOID QxlDod::VsyncTimerProc()
> 
> > > +{
> 
> > > + BOOLEAN bDummy;
> 
> > > + DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
> 
> > > + if (m_bVsyncEnabled && m_AdapterPowerState == PowerDeviceD0)
> 
> > > + {
> 
> > > + m_DxgkInterface.DxgkCbSynchronizeExecution(
> 
> > > + m_DxgkInterface.DeviceHandle,
> 
> > > + VsyncTimerSynchRoutine,
> 
> > > + this,
> 
> > > + 0,
> 
> > > + &bDummy
> 
> > > + );
> 
> > > + INCREMENT_VSYNC_COUNTER(&m_VsyncFiredCounter);
> 
> > > + }
> 
> > > +}
> 
> > > +
> 
> > > +VOID QxlDod::EnableVsync(BOOLEAN bEnable)
> 
> > > +{
> 
> > > + PAGED_CODE();
> 
> > > + if (g_bSupportVSync)
> 
> > > + {
> 
> > > + m_bVsyncEnabled = bEnable;
> 
> > > + if (!m_bVsyncEnabled)
> 
> > > + {
> 
> > > + DbgPrint(TRACE_LEVEL_WARNING, ("Disabled VSync(fired %d)\n",
> 
> > > InterlockedExchange(&m_VsyncFiredCounter, 0)));
> 
> > > + KeCancelTimer(&m_VsyncTimer);
> 
> > > + }
> 
> > > + else
> 
> > > + {
> 
> > > + LARGE_INTEGER li;
> 
> > > + LONG period = 1000 / VSYNC_RATE;
> 
> > > + DbgPrint(TRACE_LEVEL_WARNING, ("Enabled VSync(fired %d)\n",
> 
> > > m_VsyncFiredCounter));
> 
> > > + li.QuadPart = -10000000 / VSYNC_RATE;
> 
> > > + KeSetTimerEx(&m_VsyncTimer, li, period, &m_VsyncTimerDpc);
> 
> > > + }
> 
> > > + }
> 
> > > +}
> 
> > > +
> 
> > > +QXL_NON_PAGED VOID QxlDod::VsyncTimerProcGate(_In_ _KDPC *dpc, _In_
> > > PVOID
> 
> > > context, _In_ PVOID arg1, _In_ PVOID arg2)
> 
> > > +{
> 
> > > + QxlDod* pQxl = reinterpret_cast<QxlDod*>(context);
> 
> > > + pQxl->VsyncTimerProc();
> 
> > > +}
> 
> > > diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h
> 
> > > index 53724e8..9cfb6de 100755
> 
> > > --- a/qxldod/QxlDod.h
> 
> > > +++ b/qxldod/QxlDod.h
> 
> > > @@ -239,6 +239,7 @@ public:
> 
> > > QXL_NON_PAGED virtual BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE
> 
> > > pDxgkInterface, _In_ ULONG MessageNumber) = 0;
> 
> > > QXL_NON_PAGED virtual VOID DpcRoutine(PVOID) = 0;
> 
> > > QXL_NON_PAGED virtual VOID ResetDevice(void) = 0;
> 
> > > + QXL_NON_PAGED virtual VOID VSyncInterruptPostProcess(_In_
> 
> > > PDXGKRNL_INTERFACE) = 0;
> 
> > > virtual NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode) {
> 
> > > return STATUS_SUCCESS; }
> 
> > > virtual NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode) {
> 
> > > return STATUS_SUCCESS; }
> 
> > >
> 
> > > @@ -306,6 +307,7 @@ public:
> 
> > > QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE
> 
> > > pDxgkInterface, _In_ ULONG MessageNumber);
> 
> > > QXL_NON_PAGED VOID DpcRoutine(PVOID);
> 
> > > QXL_NON_PAGED VOID ResetDevice(VOID);
> 
> > > + QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
> 
> > > NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
> 
> > > NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
> 
> > > NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE*
> 
> > > pSetPointerShape);
> 
> > > @@ -358,8 +360,10 @@ enum {
> 
> > >
> 
> > > #ifdef DBG
> 
> > > #define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
> 
> > > +#define INCREMENT_VSYNC_COUNTER(counter) InterlockedIncrement(counter)
> 
> > > #else
> 
> > > #define RESOURCE_TYPE(res, val)
> 
> > > +#define INCREMENT_VSYNC_COUNTER(counter)
> 
> > > #endif
> 
> > >
> 
> > > typedef struct Resource Resource;
> 
> > > @@ -480,6 +484,7 @@ public:
> 
> > > QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE
> 
> > > pDxgkInterface, _In_ ULONG MessageNumber);
> 
> > > QXL_NON_PAGED VOID DpcRoutine(PVOID);
> 
> > > QXL_NON_PAGED VOID ResetDevice(VOID);
> 
> > > + QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
> 
> > > NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE*
> 
> > > pSetPointerShape);
> 
> > > NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION*
> 
> > > pSetPointerPosition);
> 
> > > NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscap);
> 
> > > @@ -622,6 +627,10 @@ private:
> 
> > > DXGKARG_SETPOINTERSHAPE m_PointerShape;
> 
> > >
> 
> > > HwDeviceInterface* m_pHWDevice;
> 
> > > + KTIMER m_VsyncTimer;
> 
> > > + KDPC m_VsyncTimerDpc;
> 
> > > + BOOLEAN m_bVsyncEnabled;
> 
> > > + LONG m_VsyncFiredCounter;
> 
> > > public:
> 
> > > QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);
> 
> > > ~QxlDod(void);
> 
> > > @@ -719,6 +728,7 @@ public:
> 
> > > {
> 
> > > return
> 
> > > m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle,
> 
> > > &DispInfo);
> 
> > > }
> 
> > > + VOID EnableVsync(BOOLEAN bEnable);
> 
> > > private:
> 
> > > VOID CleanUp(VOID);
> 
> > > NTSTATUS CheckHardware();
> 
> > > @@ -744,6 +754,10 @@ private:
> 
> > > NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE*
> 
> > > pSourceMode) const;
> 
> > > NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath)
> 
> > > const;
> 
> > > NTSTATUS RegisterHWInfo(_In_ ULONG Id);
> 
> > > + QXL_NON_PAGED VOID VsyncTimerProc();
> 
> > > + static QXL_NON_PAGED VOID VsyncTimerProcGate(_In_ _KDPC *dpc, _In_
> > > PVOID
> 
> > > context, _In_ PVOID arg1, _In_ PVOID arg2);
> 
> > > + QXL_NON_PAGED VOID IndicateVSyncInterrupt();
> 
> > > + static QXL_NON_PAGED BOOLEAN VsyncTimerSynchRoutine(PVOID context);
> 
> > > };
> 
> > >
> 
> > > NTSTATUS
> 

> > Otherwise looks good.
> 

Acked-by: Frediano Ziglio <fziglio at redhat.com> 

Frediano 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20170222/120f89d3/attachment.html>


More information about the Spice-devel mailing list