[Spice-devel] [PATCH 12/12] qxl-wddm-dod: Non-forced memory allocations with VSync

Jonathon Jongsma jjongsma at redhat.com
Mon Mar 27 20:22:41 UTC 2017


On Sun, 2017-03-12 at 10:45 +0200, Yuri Benditovich wrote:
> In case of VSync is active 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 separated thread, before send drawable objects down, we review

separated -> separate
send -> sending

> the list of delayed chunks and allocate device memory (forced) to
> all of them.
> The cost is 2 pointers added to each drawable or cursor object.
> Cursor commands currently do not make use of them; in future
> we have an option to offload also cursor commands.
> 
> Signed-off-by: Yuri Benditovich <yuri.benditovich at daynix.com>
> ---
>  qxldod/QxlDod.cpp | 110
> +++++++++++++++++++++++++++++++++++++++++++++++++++---
>  qxldod/QxlDod.h   |   3 ++
>  2 files changed, 108 insertions(+), 5 deletions(-)
> 
> diff --git a/qxldod/QxlDod.cpp b/qxldod/QxlDod.cpp
> index efc1fb3..0061d4c 100755
> --- a/qxldod/QxlDod.cpp
> +++ b/qxldod/QxlDod.cpp
> @@ -4263,6 +4263,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();
> @@ -4371,6 +4378,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__));
> @@ -4464,7 +4472,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;
> @@ -4544,8 +4552,17 @@ BOOLEAN QxlDevice::AttachNewBitmap(QXLDrawable
> *drawable, UINT8 *src, UINT8 *src
>          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__));
> -            return FALSE;
> +            if (pitch < 0 && bForce)
> +            {
> +                DbgPrint(TRACE_LEVEL_WARNING, ("%s: aborting copy of
> lines (forced)\n", __FUNCTION__));
> +                return FALSE;
> +            }
> +            else
> +            {
> +                DbgPrint(TRACE_LEVEL_WARNING, ("%s: unexpected
> aborting copy of lines (force %d, pitch %d)\n", __FUNCTION__, bForce,
> pitch));
> +                return FALSE;
> +            }
> +            break;
>          }
>      }
>      return TRUE;
> @@ -4599,7 +4616,7 @@ QXLDrawable *QxlDevice::BltBits (
>      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))
>      {
>          ReleaseOutputUnderLock(drawable->release_info.id);
>          drawable = NULL;
> @@ -5239,11 +5256,81 @@ void QxlDevice::StopPresentThread()
>      }
>  }
>  
> +QXLDataChunk *QxlDevice::MakeChunk(QXL_DELAYED_CHUNK *pdc)
> +{
> +    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)
> +{
> +    ULONG n = 0;
> +    BOOLEAN bFail = FALSE;
> +    PLIST_ENTRY pe = DelayedList(drawable);
> +    QXLDataChunk *chunk, *lastchunk = NULL;
> +    if (IsListEmpty(pe))
> +        return 0;
> +
> +    while (!IsListEmpty(pe))
> +    {
> +        QXL_DELAYED_CHUNK *pdc = (QXL_DELAYED_CHUNK
> *)RemoveHeadList(pe);
> +        if (!lastchunk)
> +            lastchunk = (QXLDataChunk *)pdc->chunk.prev_chunk;
> +        if (!lastchunk)
> +        {
> +            // bitmap was not allocated, this is single delayed
> chunk
> +            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 (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)
> +    {
> +        ReleaseOutputUnderLock(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__));
> @@ -5268,13 +5355,26 @@ 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[] reinterpret_cast<BYTE*>(drawables);
>          }
>          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 b2f0e0c..5544a8c 100755
> --- a/qxldod/QxlDod.h
> +++ b/qxldod/QxlDod.h
> @@ -474,6 +474,7 @@ ReleaseMutex(
>  #define MAX_OUTPUT_RES 6
>  
>  typedef struct QXLOutput {
> +    LIST_ENTRY list;
>      UINT32 num_res;
>  #ifdef DBG
>      UINT32 type;
> @@ -613,6 +614,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(QXL_DELAYED_CHUNK *pdc);
> +    ULONG PrepareDrawable(QXLDrawable*& drawable);
>      void AsyncIo(UCHAR  Port, UCHAR Value);
>      void SyncIo(UCHAR  Port, UCHAR Value);
>      NTSTATUS UpdateChildStatus(BOOLEAN connect);


More information about the Spice-devel mailing list