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

Submitted by Yuri Benditovich on Feb. 16, 2017, 2:31 p.m.

Details

Message ID 1487255462-171824-6-git-send-email-yuri.benditovich@daynix.com
State New
Headers show
Series "qxl-wddm-dod: Preparation to pass HLK tests" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Yuri Benditovich Feb. 16, 2017, 2:31 p.m.
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@daynix.com>
---
 qxldod/QxlDod.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qxldod/QxlDod.h   | 14 ++++++++++
 2 files changed, 96 insertions(+)

Patch hide | download patch | download mbox

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;
 
             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()
+{
+    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;
+}
+
+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

Comments

> 
> 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@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.

>              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).

> +}
> +
> +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.

Frediano
On Thu, Feb 16, 2017 at 5:54 PM, Frediano Ziglio <fziglio@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@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.DxgkCbAcquirePostDisplayOwners
> hip(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.
>
> Frediano
>
> On Thu, Feb 16, 2017 at 5:54 PM, Frediano Ziglio < fziglio@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@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@redhat.com> 

Frediano