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 <yuri.benditovich@daynix.com>
Acked-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
yuri.benditovich@daynix.com 2017-04-08 13:46:55 +03:00 committed by Frediano Ziglio
parent 043f4f275a
commit 8fb1b0a23e
2 changed files with 103 additions and 8 deletions

View File

@ -4224,6 +4224,13 @@ void QxlDevice::DrawableAddRes(QXLDrawable *drawable, Resource *res)
AddRes(output, 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) void QxlDevice::CursorCmdAddRes(QXLCursorCmd *cmd, Resource *res)
{ {
PAGED_CODE(); 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[1] = - 1;
drawable->surfaces_dest[2] = -1; drawable->surfaces_dest[2] = -1;
CopyRect(&drawable->bbox, area); CopyRect(&drawable->bbox, area);
InitializeListHead(DelayedList(drawable));
if (!SetClip(clip, drawable)) { if (!SetClip(clip, drawable)) {
DbgPrint(TRACE_LEVEL_VERBOSE, ("%s: set clip failed\n", __FUNCTION__)); 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; Resource *image_res;
InternalImage *internal; InternalImage *internal;
QXLDataChunk *chunk; QXLDataChunk *chunk;
PLIST_ENTRY pDelayedList = NULL; PLIST_ENTRY pDelayedList = bForce ? NULL : DelayedList(drawable);
UINT8* dest, *dest_end; UINT8* dest, *dest_end;
height = drawable->u.copy.src_area.bottom; 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) { for (; src != src_end; src -= pitch, alloc_size -= line_size) {
BOOLEAN b = PutBytesAlign(&chunk, &dest, &dest_end, src, line_size, alloc_size, pDelayedList); if (!PutBytesAlign(&chunk, &dest, &dest_end, src, line_size, alloc_size, pDelayedList)) {
if (!b) { if (pitch < 0 && bForce) {
DbgPrint(TRACE_LEVEL_WARNING, ("%s: aborting copy of lines\n", __FUNCTION__)); 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; return FALSE;
} }
} }
@ -4551,7 +4562,13 @@ QXLDrawable *QxlDevice::PrepareBltBits (
UINT8* src_end = src - pSrc->Pitch; UINT8* src_end = src - pSrc->Pitch;
src += pSrc->Pitch * (height - 1); 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<BYTE*>(pdc);
}
ReleaseOutput(drawable->release_info.id); ReleaseOutput(drawable->release_info.id);
drawable = NULL; drawable = NULL;
} else { } 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<BYTE*>(pdc);
}
if (bFail) {
ReleaseOutput(drawable->release_info.id);
drawable = NULL;
}
return n;
}
void QxlDevice::PresentThreadRoutine() void QxlDevice::PresentThreadRoutine()
{ {
PAGED_CODE(); PAGED_CODE();
int wait; int wait;
int notify; int notify;
ULONG delayed = 0;
QXLDrawable** drawables; QXLDrawable** drawables;
DbgPrint(TRACE_LEVEL_INFORMATION, ("--->%s\n", __FUNCTION__)); DbgPrint(TRACE_LEVEL_INFORMATION, ("--->%s\n", __FUNCTION__));
@ -5206,13 +5288,23 @@ void QxlDevice::PresentThreadRoutine()
if (drawables) { if (drawables) {
for (UINT i = 0; drawables[i]; ++i) 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; delete[] drawables;
} } else {
else {
DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n", __FUNCTION__)); DbgPrint(TRACE_LEVEL_WARNING, ("%s is being terminated\n", __FUNCTION__));
break; break;
} }
if (delayed) {
DbgPrint(TRACE_LEVEL_WARNING, ("%s: %d delayed chunks\n", __FUNCTION__, delayed));
delayed = 0;
}
} }
} }

View File

@ -473,6 +473,7 @@ ReleaseMutex(
#define MAX_OUTPUT_RES 6 #define MAX_OUTPUT_RES 6
typedef struct QXLOutput { typedef struct QXLOutput {
LIST_ENTRY list;
UINT32 num_res; UINT32 num_res;
#ifdef DBG #ifdef DBG
UINT32 type; UINT32 type;
@ -611,6 +612,8 @@ private:
BOOLEAN PutBytesAlign(QXLDataChunk **chunk_ptr, UINT8 **now_ptr, BOOLEAN PutBytesAlign(QXLDataChunk **chunk_ptr, UINT8 **now_ptr,
UINT8 **end_ptr, UINT8 *src, int size, UINT8 **end_ptr, UINT8 *src, int size,
size_t alloc_size, PLIST_ENTRY pDelayed); size_t alloc_size, PLIST_ENTRY pDelayed);
QXLDataChunk *MakeChunk(DelayedChunk *pdc);
ULONG PrepareDrawable(QXLDrawable*& drawable);
void AsyncIo(UCHAR Port, UCHAR Value); void AsyncIo(UCHAR Port, UCHAR Value);
void SyncIo(UCHAR Port, UCHAR Value); void SyncIo(UCHAR Port, UCHAR Value);
NTSTATUS UpdateChildStatus(BOOLEAN connect); NTSTATUS UpdateChildStatus(BOOLEAN connect);