From 8fb1b0a23ef52155db142e0c140b8fc87a60e8a6 Mon Sep 17 00:00:00 2001 From: "yuri.benditovich@daynix.com" Date: Sat, 8 Apr 2017 13:46:55 +0300 Subject: [PATCH] qxl-wddm-dod: Non-forced memory allocations with VSync In case of VSync is active (for the driver this means it shall take in account watchdog policy and ensure fast execution of PresentDisplayOnly callback) allocate bitmaps for drawable objects using non-forced requests. If immediate allocation is not possible, place entire bitmap into memory chunk allocated from the OS. If bitmap is allocated from device memory, but one of later chunks can't be allocated, allocate this and further chunks from OS memory. All these 'delayed' allocations placed into linked list which root entry is part of QXLOutput structure. >From separate thread, before sending drawable objects down, review the list of delayed chunks and allocate device memory (forced) to all of them. The cost of solution is 2 pointers added to each drawable or cursor object. Cursor commands currently do not use them; in future we have an option to offload also cursor commands. Signed-off-by: Yuri Benditovich Acked-by: Frediano Ziglio --- qxldod/QxlDod.cpp | 108 ++++++++++++++++++++++++++++++++++++++++++---- qxldod/QxlDod.h | 3 ++ 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp index 9c3cf42..66e5d21 100755 --- a/qxldod/QxlDod.cpp +++ b/qxldod/QxlDod.cpp @@ -4224,6 +4224,13 @@ void QxlDevice::DrawableAddRes(QXLDrawable *drawable, Resource *res) AddRes(output, res); } +static FORCEINLINE PLIST_ENTRY DelayedList(QXLDrawable *pd) +{ + QXLOutput *output; + output = (QXLOutput *)((UINT8 *)pd - sizeof(QXLOutput)); + return &output->list; +} + void QxlDevice::CursorCmdAddRes(QXLCursorCmd *cmd, Resource *res) { PAGED_CODE(); @@ -4331,6 +4338,7 @@ QXLDrawable *QxlDevice::Drawable(UINT8 type, CONST RECT *area, CONST RECT *clip, drawable->surfaces_dest[1] = - 1; drawable->surfaces_dest[2] = -1; CopyRect(&drawable->bbox, area); + InitializeListHead(DelayedList(drawable)); if (!SetClip(clip, drawable)) { DbgPrint(TRACE_LEVEL_VERBOSE, ("%s: set clip failed\n", __FUNCTION__)); @@ -4425,7 +4433,7 @@ BOOLEAN QxlDevice::AttachNewBitmap(QXLDrawable *drawable, UINT8 *src, UINT8 *src Resource *image_res; InternalImage *internal; QXLDataChunk *chunk; - PLIST_ENTRY pDelayedList = NULL; + PLIST_ENTRY pDelayedList = bForce ? NULL : DelayedList(drawable); UINT8* dest, *dest_end; height = drawable->u.copy.src_area.bottom; @@ -4494,9 +4502,12 @@ BOOLEAN QxlDevice::AttachNewBitmap(QXLDrawable *drawable, UINT8 *src, UINT8 *src } for (; src != src_end; src -= pitch, alloc_size -= line_size) { - BOOLEAN b = PutBytesAlign(&chunk, &dest, &dest_end, src, line_size, alloc_size, pDelayedList); - if (!b) { - DbgPrint(TRACE_LEVEL_WARNING, ("%s: aborting copy of lines\n", __FUNCTION__)); + if (!PutBytesAlign(&chunk, &dest, &dest_end, src, line_size, alloc_size, pDelayedList)) { + if (pitch < 0 && bForce) { + DbgPrint(TRACE_LEVEL_WARNING, ("%s: aborting copy of lines (forced)\n", __FUNCTION__)); + } else { + DbgPrint(TRACE_LEVEL_WARNING, ("%s: unexpected aborting copy of lines (force %d, pitch %d)\n", __FUNCTION__, bForce, pitch)); + } return FALSE; } } @@ -4551,7 +4562,13 @@ QXLDrawable *QxlDevice::PrepareBltBits ( UINT8* src_end = src - pSrc->Pitch; src += pSrc->Pitch * (height - 1); - if (!AttachNewBitmap(drawable, src, src_end, (INT)pSrc->Pitch, TRUE)) { + if (!AttachNewBitmap(drawable, src, src_end, (INT)pSrc->Pitch, !g_bSupportVSync)) { + PLIST_ENTRY pDelayedList = DelayedList(drawable); + // if some delayed chunks were allocated, free them + while (!IsListEmpty(pDelayedList)) { + DelayedChunk *pdc = (DelayedChunk *)RemoveHeadList(pDelayedList); + delete[] reinterpret_cast(pdc); + } ReleaseOutput(drawable->release_info.id); drawable = NULL; } else { @@ -5179,11 +5196,76 @@ void QxlDevice::StopPresentThread() } } +QXLDataChunk *QxlDevice::MakeChunk(DelayedChunk *pdc) +{ + PAGED_CODE(); + QXLDataChunk *chunk = (QXLDataChunk *)AllocMem(MSPACE_TYPE_VRAM, pdc->chunk.data_size + sizeof(QXLDataChunk), TRUE); + if (chunk) + { + chunk->data_size = pdc->chunk.data_size; + chunk->next_chunk = 0; + RtlCopyMemory(chunk->data, pdc->chunk.data, chunk->data_size); + } + return chunk; +} + +ULONG QxlDevice::PrepareDrawable(QXLDrawable*& drawable) +{ + PAGED_CODE(); + ULONG n = 0; + BOOLEAN bFail; + PLIST_ENTRY pe = DelayedList(drawable); + QXLDataChunk *chunk, *lastchunk = NULL; + + bFail = !m_bActive; + + while (!IsListEmpty(pe)) { + DelayedChunk *pdc = (DelayedChunk *)RemoveHeadList(pe); + if (!lastchunk) { + lastchunk = (QXLDataChunk *)pdc->chunk.prev_chunk; + } + if (!bFail && !lastchunk) { + // bitmap was not allocated, this is single delayed chunk + QXL_ASSERT(IsListEmpty(pe)); + + if (AttachNewBitmap( + drawable, + pdc->chunk.data, + pdc->chunk.data + pdc->chunk.data_size, + -(drawable->u.copy.src_area.right * 4), + TRUE)) { + ++n; + } else { + bFail = TRUE; + } + } + if (!bFail && lastchunk) { + // some chunks were not allocated + chunk = MakeChunk(pdc); + if (chunk) { + chunk->prev_chunk = PA(lastchunk, m_SurfaceMemSlot); + lastchunk->next_chunk = PA(chunk, m_SurfaceMemSlot); + lastchunk = chunk; + ++n; + } else { + bFail = TRUE; + } + } + delete[] reinterpret_cast(pdc); + } + if (bFail) { + ReleaseOutput(drawable->release_info.id); + drawable = NULL; + } + return n; +} + void QxlDevice::PresentThreadRoutine() { PAGED_CODE(); int wait; int notify; + ULONG delayed = 0; QXLDrawable** drawables; DbgPrint(TRACE_LEVEL_INFORMATION, ("--->%s\n", __FUNCTION__)); @@ -5206,13 +5288,23 @@ void QxlDevice::PresentThreadRoutine() if (drawables) { for (UINT i = 0; drawables[i]; ++i) - PushDrawable(drawables[i]); + { + ULONG n = PrepareDrawable(drawables[i]); + // only reason why drawables[i] is zeroed is stop flow + if (drawables[i]) { + delayed += n; + PushDrawable(drawables[i]); + } + } delete[] drawables; - } - else { + } else { DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n", __FUNCTION__)); break; } + if (delayed) { + DbgPrint(TRACE_LEVEL_WARNING, ("%s: %d delayed chunks\n", __FUNCTION__, delayed)); + delayed = 0; + } } } diff --git a/qxldod/QxlDod.h b/qxldod/QxlDod.h index 7428f40..6e5beee 100755 --- a/qxldod/QxlDod.h +++ b/qxldod/QxlDod.h @@ -473,6 +473,7 @@ ReleaseMutex( #define MAX_OUTPUT_RES 6 typedef struct QXLOutput { + LIST_ENTRY list; UINT32 num_res; #ifdef DBG UINT32 type; @@ -611,6 +612,8 @@ private: BOOLEAN PutBytesAlign(QXLDataChunk **chunk_ptr, UINT8 **now_ptr, UINT8 **end_ptr, UINT8 *src, int size, size_t alloc_size, PLIST_ENTRY pDelayed); + QXLDataChunk *MakeChunk(DelayedChunk *pdc); + ULONG PrepareDrawable(QXLDrawable*& drawable); void AsyncIo(UCHAR Port, UCHAR Value); void SyncIo(UCHAR Port, UCHAR Value); NTSTATUS UpdateChildStatus(BOOLEAN connect);