<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Mar 20, 2017 at 2:01 PM, Frediano Ziglio <span dir="ltr"><<a href="mailto:fziglio@redhat.com" target="_blank">fziglio@redhat.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail-HOEnZb"><div class="gmail-h5">><br>
> Create rendering thread upon device start and terminate it upon<br>
> stop. The dedicated thread is normally pending for display commands<br>
> to be sent to the host. Currently only single NULL (termination)<br>
> command is placed to the ring where the thread consumes events from.<br>
><br>
> Signed-off-by: Javier Celaya <<a href="mailto:javier.celaya@flexvdi.com">javier.celaya@flexvdi.com</a>><br>
> Signed-off-by: Yuri Benditovich <<a href="mailto:yuri.benditovich@daynix.com">yuri.benditovich@daynix.com</a>><br>
> ---<br>
> qxldod/QxlDod.cpp | 114<br>
> ++++++++++++++++++++++++++++++<wbr>++++++++++++++++++++++++<br>
> qxldod/QxlDod.h | 16 ++++++++<br>
> 2 files changed, 130 insertions(+)<br>
><br>
> diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp<br>
> index 9175300..b952bf9 100755<br>
> --- a/qxldod/QxlDod.cpp<br>
> +++ b/qxldod/QxlDod.cpp<br>
> @@ -3062,6 +3062,7 @@ QxlDevice::QxlDevice(_In_ QxlDod* pQxlDod)<br>
> m_CustomMode = 0;<br>
> m_FreeOutputs = 0;<br>
> m_Pending = 0;<br>
> + m_PresentThread = NULL;<br>
> }<br>
><br>
> QxlDevice::~QxlDevice(void)<br>
> @@ -3441,6 +3442,29 @@ NTSTATUS QxlDevice::HWInit(PCM_<wbr>RESOURCE_LIST pResList,<br>
> DXGK_DISPLAY_INFORMATION*<br>
> return QxlInit(pDispInfo);<br>
> }<br>
><br>
> +NTSTATUS QxlDevice::StartPresentThread(<wbr>)<br>
> +{<br>
> + PAGED_CODE();<br>
> + OBJECT_ATTRIBUTES ObjectAttributes;<br>
> + NTSTATUS Status;<br>
> +<br>
> + KeClearEvent(&m_<wbr>PresentThreadReadyEvent);<br>
> +<br>
> + InitializeObjectAttributes(&<wbr>ObjectAttributes, NULL, OBJ_KERNEL_HANDLE,<br>
> NULL, NULL);<br>
> + Status = PsCreateSystemThread(<br>
> + &m_PresentThread,<br>
> + THREAD_ALL_ACCESS,<br>
> + &ObjectAttributes,<br>
> + NULL,<br>
> + NULL,<br>
> + PresentThreadRoutineWrapper,<br>
> + this);<br>
> +<br>
> + WaitForObject(&m_<wbr>PresentThreadReadyEvent, NULL);<br>
> +<br>
<br>
</div></div>Why we need to wait here? Same above, no much need to clear the event.<br>
<div><div class="gmail-h5"><br></div></div></blockquote><div>Wait is not mandatory - it is here to have predictable timing and ensure the thread is ready before first 'Present' command.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="gmail-h5">
> + return Status;<br>
> +}<br>
> +<br>
> NTSTATUS QxlDevice::QxlInit(DXGK_<wbr>DISPLAY_INFORMATION* pDispInfo)<br>
> {<br>
> PAGED_CODE();<br>
> @@ -3467,12 +3491,17 @@ NTSTATUS QxlDevice::QxlInit(DXGK_<wbr>DISPLAY_INFORMATION*<br>
> pDispInfo)<br>
> InitDeviceMemoryResources();<br>
> InitMonitorConfig();<br>
> Status = AcquireDisplayInfo(*(<wbr>pDispInfo));<br>
> + if (NT_SUCCESS(Status))<br>
> + {<br>
> + Status = StartPresentThread();<br>
> + }<br>
> return Status;<br>
> }<br>
><br>
> void QxlDevice::QxlClose()<br>
> {<br>
> PAGED_CODE();<br>
> + StopPresentThread();<br>
> DestroyMemSlots();<br>
> }<br>
><br>
> @@ -3609,6 +3638,12 @@ BOOL QxlDevice::CreateEvents()<br>
> KeInitializeEvent(&m_<wbr>IoCmdEvent,<br>
> SynchronizationEvent,<br>
> FALSE);<br>
> + KeInitializeEvent(&m_<wbr>PresentEvent,<br>
> + SynchronizationEvent,<br>
> + FALSE);<br>
> + KeInitializeEvent(&m_<wbr>PresentThreadReadyEvent,<br>
> + SynchronizationEvent,<br>
> + FALSE);<br>
> KeInitializeMutex(&m_MemLock,<wbr>1);<br>
> KeInitializeMutex(&m_CmdLock,<wbr>1);<br>
> KeInitializeMutex(&m_IoLock,1)<wbr>;<br>
> @@ -3625,6 +3660,7 @@ BOOL QxlDevice::CreateRings()<br>
> m_CommandRing = &(m_RamHdr->cmd_ring);<br>
> m_CursorRing = &(m_RamHdr->cursor_ring);<br>
> m_ReleaseRing = &(m_RamHdr->release_ring);<br>
> + SPICE_RING_INIT(m_PresentRing)<wbr>;<br>
> DbgPrint(TRACE_LEVEL_VERBOSE, ("<--- %s\n", __FUNCTION__));<br>
> return TRUE;<br>
> }<br>
> @@ -4907,6 +4943,7 @@ UINT SpiceFromPixelFormat(<wbr>D3DDDIFORMAT Format)<br>
><br>
> NTSTATUS HwDeviceInterface::<wbr>AcquireDisplayInfo(DXGK_<wbr>DISPLAY_INFORMATION&<br>
> DispInfo)<br>
> {<br>
> + PAGED_CODE();<br>
> NTSTATUS Status = STATUS_SUCCESS;<br>
> if (GetId() == 0)<br>
> {<br>
> @@ -4996,3 +5033,80 @@ QXL_NON_PAGED VOID QxlDod::VsyncTimerProcGate(_<wbr>In_<br>
> _KDPC *dpc, _In_ PVOID contex<br>
> QxlDod* pQxl = reinterpret_cast<QxlDod*>(<wbr>context);<br>
> pQxl->VsyncTimerProc();<br>
> }<br>
> +<br>
> +void QxlDevice::StopPresentThread()<br>
> +{<br>
> + PAGED_CODE();<br>
> + PVOID pDispatcherObject;<br>
> + if (m_PresentThread)<br>
> + {<br>
> + DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("---> %s\n", __FUNCTION__));<br>
> + NTSTATUS Status = ObReferenceObjectByHandle(<br>
> + m_PresentThread, 0, NULL, KernelMode, &pDispatcherObject, NULL);<br>
> + if (NT_SUCCESS(Status))<br>
> + {<br>
> + PostToWorkerThread(NULL);<br>
<br>
</div></div>In the unluckily event that ObReferenceObjectByHandle failed would<br>
be better to do this call anyway, so we have a chance the thread<br>
will be destroyed before system potentially free from memory<br>
the thread code and data.<br>
<div><div class="gmail-h5"><br>
> + WaitForObject(<wbr>pDispatcherObject, NULL);<br>
> + ObDereferenceObject(<wbr>pDispatcherObject);<br>
> + }<br>
> + ZwClose(m_PresentThread);<br>
> + m_PresentThread = NULL;<br>
> + DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("<--- %s\n", __FUNCTION__));<br>
> + }<br>
> +}<br>
> +<br>
> +void QxlDevice::<wbr>PresentThreadRoutine()<br>
> +{<br>
> + PAGED_CODE();<br>
> + int wait;<br>
> + int notify;<br>
> + QXLDrawable** drawables;<br>
> +<br>
> + DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("--->%s\n", __FUNCTION__));<br>
> +<br>
> + KeSetEvent(&m_<wbr>PresentThreadReadyEvent, 0, FALSE);<br>
> +<br>
> + while (1)<br>
> + {<br>
> + // Pop a drawables list from the ring<br>
> + // No need for a mutex, only one consumer thread<br>
> + SPICE_RING_CONS_WAIT(m_<wbr>PresentRing, wait);<br>
> + while (wait) {<br>
> + WaitForObject(&m_PresentEvent, NULL);<br>
> + SPICE_RING_CONS_WAIT(m_<wbr>PresentRing, wait);<br>
> + }<br>
> + drawables = *SPICE_RING_CONS_ITEM(m_<wbr>PresentRing);<br>
> + SPICE_RING_POP(m_PresentRing, notify);<br>
> + if (notify) {<br>
> + KeSetEvent(&m_<wbr>PresentThreadReadyEvent, 0, FALSE);<br>
> + }<br>
> +<br>
> + if (drawables) {<br>
> + for (UINT i = 0; drawables[i]; ++i)<br>
> + PushDrawable(drawables[i]);<br>
> + delete[] reinterpret_cast<BYTE*>(<wbr>drawables);<br>
<br>
</div></div>why all these reinterpret_cast ?<br>
Just<br>
<br>
delete[] drawables;<br>
<br>
is enough (obviously allocation should the changed too).<br>
<div><div class="gmail-h5"><br>
> + }<br>
> + else {<br>
> + DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n",<br>
> __FUNCTION__));<br>
> + break;<br>
> + }<br>
> + }<br>
> +}<br>
> +<br>
> +void QxlDevice::PostToWorkerThread(<wbr>QXLDrawable** drawables)<br>
> +{<br>
> + PAGED_CODE();<br>
> + // Push drawables into PresentRing and notify worker thread<br>
> + int notify, wait;<br>
> + SPICE_RING_PROD_WAIT(m_<wbr>PresentRing, wait);<br>
> + while (wait) {<br>
> + WaitForObject(&m_<wbr>PresentThreadReadyEvent, NULL);<br>
> + SPICE_RING_PROD_WAIT(m_<wbr>PresentRing, wait);<br>
> + }<br>
> + *SPICE_RING_PROD_ITEM(m_<wbr>PresentRing) = drawables;<br>
> + SPICE_RING_PUSH(m_PresentRing, notify);<br>
> + if (notify) {<br>
> + KeSetEvent(&m_PresentEvent, 0, FALSE);<br>
> + }<br>
> + DbgPrint(TRACE_LEVEL_<wbr>INFORMATION, ("<--- %s\n", __FUNCTION__));<br>
> +}<br>
> diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h<br>
> index 9cfb6de..4a62680 100755<br>
> --- a/qxldod/QxlDod.h<br>
> +++ b/qxldod/QxlDod.h<br>
> @@ -456,6 +456,10 @@ typedef struct DpcCbContext {<br>
> #define MAX(x, y) (((x) >= (y)) ? (x) : (y))<br>
> #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))<br>
><br>
> +#include "start-packed.h"<br>
> +SPICE_RING_DECLARE(<wbr>QXLPresentOnlyRing, QXLDrawable**, 1024);<br>
> +#include "end-packed.h"<br>
> +<br>
<br>
</div></div>Not a regression, however this structure cannot be byte-packed.<br>
This would cause potentially problems like 255+1 == 0.<br>
<div class="gmail-HOEnZb"><div class="gmail-h5"><br>
</div></div></blockquote><div>I do not see how this can cause problem.</div><div>Packing at byte boundary is not needed here, but the alternative is (ugly) to use #define SPICE_ATTR_PACKED before declaration and #undef SPICE_ATTR_PACKED after.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="gmail-HOEnZb"><div class="gmail-h5">> class QxlDevice :<br>
> public HwDeviceInterface<br>
> {<br>
> @@ -559,6 +563,13 @@ private:<br>
> NTSTATUS UpdateChildStatus(BOOLEAN connect);<br>
> NTSTATUS SetCustomDisplay(<wbr>QXLEscapeSetCustomDisplay* custom_display);<br>
> void SetMonitorConfig(QXLHead* monitor_config);<br>
> + NTSTATUS StartPresentThread();<br>
> + void StopPresentThread();<br>
> + void PresentThreadRoutine();<br>
> + static void PresentThreadRoutineWrapper(<wbr>HANDLE dev) {<br>
> + ((QxlDevice *)dev)->PresentThreadRoutine()<wbr>;<br>
> + }<br>
> + void PostToWorkerThread(<wbr>QXLDrawable** drawables);<br>
><br>
> static LONG GetMaxSourceMappingHeight(<wbr>RECT* DirtyRects, ULONG<br>
> NumDirtyRects);<br>
><br>
> @@ -594,6 +605,8 @@ private:<br>
> KEVENT m_DisplayEvent;<br>
> KEVENT m_CursorEvent;<br>
> KEVENT m_IoCmdEvent;<br>
> + KEVENT m_PresentEvent;<br>
> + KEVENT m_PresentThreadReadyEvent;<br>
><br>
> PUCHAR m_LogPort;<br>
> PUCHAR m_LogBuf;<br>
> @@ -609,6 +622,9 @@ private:<br>
><br>
> QXLMonitorsConfig* m_monitor_config;<br>
> QXLPHYSICAL* m_monitor_config_pa;<br>
> +<br>
> + QXLPresentOnlyRing m_PresentRing[1];<br>
> + HANDLE m_PresentThread;<br>
> };<br>
><br>
> class QxlDod {<br>
<br>
</div></div><span class="gmail-HOEnZb"><font color="#888888">Frediano<br>
</font></span></blockquote></div><br></div></div>