qxl-wddm-dod: Prepare system thread for rendering

Create rendering thread upon device start and terminate it upon
stop. The dedicated thread is normally pending for display commands
to be sent to the host. Currently only single NULL (termination)
command is placed to the ring where the thread consumes events from.

Signed-off-by: Javier Celaya <javier.celaya@flexvdi.com>
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-04-01 19:40:28 +03:00 committed by Frediano Ziglio
parent c0506bcf5d
commit 7ca13f4f48
2 changed files with 124 additions and 0 deletions

View File

@ -3062,6 +3062,7 @@ QxlDevice::QxlDevice(_In_ QxlDod* pQxlDod)
m_CustomMode = 0; m_CustomMode = 0;
m_FreeOutputs = 0; m_FreeOutputs = 0;
m_Pending = 0; m_Pending = 0;
m_PresentThread = NULL;
} }
QxlDevice::~QxlDevice(void) QxlDevice::~QxlDevice(void)
@ -3441,6 +3442,25 @@ NTSTATUS QxlDevice::HWInit(PCM_RESOURCE_LIST pResList, DXGK_DISPLAY_INFORMATION*
return QxlInit(pDispInfo); return QxlInit(pDispInfo);
} }
NTSTATUS QxlDevice::StartPresentThread()
{
PAGED_CODE();
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status;
InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(
&m_PresentThread,
THREAD_ALL_ACCESS,
&ObjectAttributes,
NULL,
NULL,
PresentThreadRoutineWrapper,
this);
return Status;
}
NTSTATUS QxlDevice::QxlInit(DXGK_DISPLAY_INFORMATION* pDispInfo) NTSTATUS QxlDevice::QxlInit(DXGK_DISPLAY_INFORMATION* pDispInfo)
{ {
PAGED_CODE(); PAGED_CODE();
@ -3467,12 +3487,17 @@ NTSTATUS QxlDevice::QxlInit(DXGK_DISPLAY_INFORMATION* pDispInfo)
InitDeviceMemoryResources(); InitDeviceMemoryResources();
InitMonitorConfig(); InitMonitorConfig();
Status = AcquireDisplayInfo(*(pDispInfo)); Status = AcquireDisplayInfo(*(pDispInfo));
if (NT_SUCCESS(Status))
{
Status = StartPresentThread();
}
return Status; return Status;
} }
void QxlDevice::QxlClose() void QxlDevice::QxlClose()
{ {
PAGED_CODE(); PAGED_CODE();
StopPresentThread();
DestroyMemSlots(); DestroyMemSlots();
} }
@ -3609,6 +3634,12 @@ BOOL QxlDevice::CreateEvents()
KeInitializeEvent(&m_IoCmdEvent, KeInitializeEvent(&m_IoCmdEvent,
SynchronizationEvent, SynchronizationEvent,
FALSE); FALSE);
KeInitializeEvent(&m_PresentEvent,
SynchronizationEvent,
FALSE);
KeInitializeEvent(&m_PresentThreadReadyEvent,
SynchronizationEvent,
FALSE);
KeInitializeMutex(&m_MemLock,1); KeInitializeMutex(&m_MemLock,1);
KeInitializeMutex(&m_CmdLock,1); KeInitializeMutex(&m_CmdLock,1);
KeInitializeMutex(&m_IoLock,1); KeInitializeMutex(&m_IoLock,1);
@ -3625,6 +3656,7 @@ BOOL QxlDevice::CreateRings()
m_CommandRing = &(m_RamHdr->cmd_ring); m_CommandRing = &(m_RamHdr->cmd_ring);
m_CursorRing = &(m_RamHdr->cursor_ring); m_CursorRing = &(m_RamHdr->cursor_ring);
m_ReleaseRing = &(m_RamHdr->release_ring); m_ReleaseRing = &(m_RamHdr->release_ring);
SPICE_RING_INIT(m_PresentRing);
DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__)); DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));
return TRUE; return TRUE;
} }
@ -4907,6 +4939,7 @@ UINT SpiceFromPixelFormat(D3DDDIFORMAT Format)
NTSTATUS HwDeviceInterface::AcquireDisplayInfo(DXGK_DISPLAY_INFORMATION& DispInfo) NTSTATUS HwDeviceInterface::AcquireDisplayInfo(DXGK_DISPLAY_INFORMATION& DispInfo)
{ {
PAGED_CODE();
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
if (GetId() == 0) if (GetId() == 0)
{ {
@ -4996,3 +5029,78 @@ QXL_NON_PAGED VOID QxlDod::VsyncTimerProcGate(_In_ _KDPC *dpc, _In_ PVOID contex
QxlDod* pQxl = reinterpret_cast<QxlDod*>(context); QxlDod* pQxl = reinterpret_cast<QxlDod*>(context);
pQxl->VsyncTimerProc(); pQxl->VsyncTimerProc();
} }
void QxlDevice::StopPresentThread()
{
PAGED_CODE();
PVOID pDispatcherObject;
if (m_PresentThread)
{
DbgPrint(TRACE_LEVEL_INFORMATION, ("---> %s\n", __FUNCTION__));
PostToWorkerThread(NULL);
NTSTATUS Status = ObReferenceObjectByHandle(
m_PresentThread, 0, NULL, KernelMode, &pDispatcherObject, NULL);
if (NT_SUCCESS(Status))
{
WaitForObject(pDispatcherObject, NULL);
ObDereferenceObject(pDispatcherObject);
}
ZwClose(m_PresentThread);
m_PresentThread = NULL;
DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
}
}
void QxlDevice::PresentThreadRoutine()
{
PAGED_CODE();
int wait;
int notify;
QXLDrawable** drawables;
DbgPrint(TRACE_LEVEL_INFORMATION, ("--->%s\n", __FUNCTION__));
while (1)
{
// Pop a drawables list from the ring
// No need for a mutex, only one consumer thread
SPICE_RING_CONS_WAIT(m_PresentRing, wait);
while (wait) {
WaitForObject(&m_PresentEvent, NULL);
SPICE_RING_CONS_WAIT(m_PresentRing, wait);
}
drawables = *SPICE_RING_CONS_ITEM(m_PresentRing);
SPICE_RING_POP(m_PresentRing, notify);
if (notify) {
KeSetEvent(&m_PresentThreadReadyEvent, 0, FALSE);
}
if (drawables) {
for (UINT i = 0; drawables[i]; ++i)
PushDrawable(drawables[i]);
delete[] drawables;
}
else {
DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n", __FUNCTION__));
break;
}
}
}
void QxlDevice::PostToWorkerThread(QXLDrawable** drawables)
{
PAGED_CODE();
// Push drawables into PresentRing and notify worker thread
int notify, wait;
SPICE_RING_PROD_WAIT(m_PresentRing, wait);
while (wait) {
WaitForObject(&m_PresentThreadReadyEvent, NULL);
SPICE_RING_PROD_WAIT(m_PresentRing, wait);
}
*SPICE_RING_PROD_ITEM(m_PresentRing) = drawables;
SPICE_RING_PUSH(m_PresentRing, notify);
if (notify) {
KeSetEvent(&m_PresentEvent, 0, FALSE);
}
DbgPrint(TRACE_LEVEL_INFORMATION, ("<--- %s\n", __FUNCTION__));
}

View File

@ -456,6 +456,10 @@ typedef struct DpcCbContext {
#define MAX(x, y) (((x) >= (y)) ? (x) : (y)) #define MAX(x, y) (((x) >= (y)) ? (x) : (y))
#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
#include "start-packed.h"
SPICE_RING_DECLARE(QXLPresentOnlyRing, QXLDrawable**, 1024);
#include "end-packed.h"
class QxlDevice : class QxlDevice :
public HwDeviceInterface public HwDeviceInterface
{ {
@ -559,6 +563,13 @@ private:
NTSTATUS UpdateChildStatus(BOOLEAN connect); NTSTATUS UpdateChildStatus(BOOLEAN connect);
NTSTATUS SetCustomDisplay(QXLEscapeSetCustomDisplay* custom_display); NTSTATUS SetCustomDisplay(QXLEscapeSetCustomDisplay* custom_display);
void SetMonitorConfig(QXLHead* monitor_config); void SetMonitorConfig(QXLHead* monitor_config);
NTSTATUS StartPresentThread();
void StopPresentThread();
void PresentThreadRoutine();
static void PresentThreadRoutineWrapper(HANDLE dev) {
((QxlDevice *)dev)->PresentThreadRoutine();
}
void PostToWorkerThread(QXLDrawable** drawables);
static LONG GetMaxSourceMappingHeight(RECT* DirtyRects, ULONG NumDirtyRects); static LONG GetMaxSourceMappingHeight(RECT* DirtyRects, ULONG NumDirtyRects);
@ -594,6 +605,8 @@ private:
KEVENT m_DisplayEvent; KEVENT m_DisplayEvent;
KEVENT m_CursorEvent; KEVENT m_CursorEvent;
KEVENT m_IoCmdEvent; KEVENT m_IoCmdEvent;
KEVENT m_PresentEvent;
KEVENT m_PresentThreadReadyEvent;
PUCHAR m_LogPort; PUCHAR m_LogPort;
PUCHAR m_LogBuf; PUCHAR m_LogBuf;
@ -609,6 +622,9 @@ private:
QXLMonitorsConfig* m_monitor_config; QXLMonitorsConfig* m_monitor_config;
QXLPHYSICAL* m_monitor_config_pa; QXLPHYSICAL* m_monitor_config_pa;
QXLPresentOnlyRing m_PresentRing[1];
HANDLE m_PresentThread;
}; };
class QxlDod { class QxlDod {