qxl-wddm-dod: Timer-based VSync interrupt indication

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>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
yuri.benditovich@daynix.com 2017-02-16 16:31:01 +02:00 committed by Frediano Ziglio
parent a2b58d1557
commit db40bfd439
2 changed files with 96 additions and 0 deletions

View File

@ -82,6 +82,12 @@ QxlDod::QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject) : m_pPhysicalDevice(pP
RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes)); RtlZeroMemory(m_CurrentModes, sizeof(m_CurrentModes));
RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape)); RtlZeroMemory(&m_PointerShape, sizeof(m_PointerShape));
m_pHWDevice = NULL; m_pHWDevice = NULL;
KeInitializeDpc(&m_VsyncTimerDpc, VsyncTimerProcGate, this);
KeInitializeTimer(&m_VsyncTimer);
m_VsyncFiredCounter = 0;
m_bVsyncEnabled = FALSE;
DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__)); DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
} }
@ -198,6 +204,7 @@ NTSTATUS QxlDod::StopDevice(VOID)
{ {
PAGED_CODE(); PAGED_CODE();
m_Flags.DriverStarted = FALSE; m_Flags.DriverStarted = FALSE;
EnableVsync(FALSE);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -518,6 +525,7 @@ NTSTATUS QxlDod::QueryAdapterInfo(_In_ CONST DXGKARG_QUERYADAPTERINFO* pQueryAda
pDriverCaps->PointerCaps.Color = 1; pDriverCaps->PointerCaps.Color = 1;
pDriverCaps->SupportNonVGA = m_pHWDevice->IsBIOSCompatible(); pDriverCaps->SupportNonVGA = m_pHWDevice->IsBIOSCompatible();
pDriverCaps->SchedulingCaps.VSyncPowerSaveAware = g_bSupportVSync;
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__)); DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s 1\n", __FUNCTION__));
return STATUS_SUCCESS; return STATUS_SUCCESS;
@ -4812,6 +4820,14 @@ BOOLEAN QxlDevice::InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_
return TRUE; return TRUE;
} }
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 QXL_NON_PAGED
VOID QxlDevice::DpcRoutine(PVOID) VOID QxlDevice::DpcRoutine(PVOID)
{ {
@ -4914,3 +4930,69 @@ NTSTATUS HwDeviceInterface::AcquireDisplayInfo(DXGK_DISPLAY_INFORMATION& DispInf
} }
return Status; 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();
}

View File

@ -239,6 +239,7 @@ public:
QXL_NON_PAGED virtual BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber) = 0; 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 DpcRoutine(PVOID) = 0;
QXL_NON_PAGED virtual VOID ResetDevice(void) = 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 AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode) { return STATUS_SUCCESS; }
virtual NTSTATUS ReleaseFrameBuffer(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 BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber);
QXL_NON_PAGED VOID DpcRoutine(PVOID); QXL_NON_PAGED VOID DpcRoutine(PVOID);
QXL_NON_PAGED VOID ResetDevice(VOID); QXL_NON_PAGED VOID ResetDevice(VOID);
QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode); NTSTATUS AcquireFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode); NTSTATUS ReleaseFrameBuffer(CURRENT_BDD_MODE* pCurrentBddMode);
NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
@ -358,8 +360,10 @@ enum {
#ifdef DBG #ifdef DBG
#define RESOURCE_TYPE(res, val) do { res->type = val; } while (0) #define RESOURCE_TYPE(res, val) do { res->type = val; } while (0)
#define INCREMENT_VSYNC_COUNTER(counter) InterlockedIncrement(counter)
#else #else
#define RESOURCE_TYPE(res, val) #define RESOURCE_TYPE(res, val)
#define INCREMENT_VSYNC_COUNTER(counter)
#endif #endif
typedef struct Resource Resource; typedef struct Resource Resource;
@ -480,6 +484,7 @@ public:
QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber); QXL_NON_PAGED BOOLEAN InterruptRoutine(_In_ PDXGKRNL_INTERFACE pDxgkInterface, _In_ ULONG MessageNumber);
QXL_NON_PAGED VOID DpcRoutine(PVOID); QXL_NON_PAGED VOID DpcRoutine(PVOID);
QXL_NON_PAGED VOID ResetDevice(VOID); QXL_NON_PAGED VOID ResetDevice(VOID);
QXL_NON_PAGED VOID VSyncInterruptPostProcess(_In_ PDXGKRNL_INTERFACE);
NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape); NTSTATUS SetPointerShape(_In_ CONST DXGKARG_SETPOINTERSHAPE* pSetPointerShape);
NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition); NTSTATUS SetPointerPosition(_In_ CONST DXGKARG_SETPOINTERPOSITION* pSetPointerPosition);
NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscap); NTSTATUS Escape(_In_ CONST DXGKARG_ESCAPE* pEscap);
@ -622,6 +627,10 @@ private:
DXGKARG_SETPOINTERSHAPE m_PointerShape; DXGKARG_SETPOINTERSHAPE m_PointerShape;
HwDeviceInterface* m_pHWDevice; HwDeviceInterface* m_pHWDevice;
KTIMER m_VsyncTimer;
KDPC m_VsyncTimerDpc;
BOOLEAN m_bVsyncEnabled;
LONG m_VsyncFiredCounter;
public: public:
QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject); QxlDod(_In_ DEVICE_OBJECT* pPhysicalDeviceObject);
~QxlDod(void); ~QxlDod(void);
@ -719,6 +728,7 @@ public:
{ {
return m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &DispInfo); return m_DxgkInterface.DxgkCbAcquirePostDisplayOwnership(m_DxgkInterface.DeviceHandle, &DispInfo);
} }
VOID EnableVsync(BOOLEAN bEnable);
private: private:
VOID CleanUp(VOID); VOID CleanUp(VOID);
NTSTATUS CheckHardware(); NTSTATUS CheckHardware();
@ -744,6 +754,10 @@ private:
NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const; NTSTATUS IsVidPnSourceModeFieldsValid(CONST D3DKMDT_VIDPN_SOURCE_MODE* pSourceMode) const;
NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const; NTSTATUS IsVidPnPathFieldsValid(CONST D3DKMDT_VIDPN_PRESENT_PATH* pPath) const;
NTSTATUS RegisterHWInfo(_In_ ULONG Id); 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 NTSTATUS