VirtualBox

Changeset 94622 in vbox for trunk


Ignore:
Timestamp:
Apr 16, 2022 2:32:45 PM (3 years ago)
Author:
vboxsync
Message:

WDDM: Initial code for command buffers. bugref:9845

Location:
trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.cpp

    r93834 r94622  
    2727#include <iprt/memobj.h>
    2828
    29 static NTSTATUS SvgaCmdBufSubmit(VBOXWDDM_EXT_VMSVGA *pSvga, uint32_t cbSubmit, uint32_t idx)
    30 {
    31     AssertReturn(idx < pSvga->u32NumCmdBufs, VERR_INVALID_PARAMETER);
    32     AssertReturn(cbSubmit <= PAGE_SIZE, VERR_INVALID_PARAMETER);
    33     int rc = STATUS_SUCCESS;
    34     SVGACBHeader *pHdr = &((SVGACBHeader *)pSvga->pvR0Hdr)[idx];
    35     RTHCPHYS paHdr = pSvga->paHdr + idx * sizeof(SVGACBHeader);
    36 
    37     pHdr->status = SVGA_CB_STATUS_NONE;
    38     pHdr->errorOffset = 0;
    39     pHdr->id = 0;
    40     pHdr->flags = SVGA_CB_FLAG_NO_IRQ;
    41     pHdr->length = cbSubmit;
    42     pHdr->ptr.pa = pSvga->paCmd;
    43 
    44     SVGARegWrite(pSvga, SVGA_REG_COMMAND_HIGH, (uint32_t)(paHdr >> 32));
    45     SVGARegWrite(pSvga, SVGA_REG_COMMAND_LOW, (uint32_t)paHdr | SVGA_CB_CONTEXT_0);
    46 
    47     return rc;
    48 }
    49 
    50 static NTSTATUS SvgaCmdBufCtxInit(VBOXWDDM_EXT_VMSVGA *pSvga, bool enable)
    51 {
    52     int rc = STATUS_SUCCESS;
    53 
    54     AssertReturn(enable == (pSvga->hMemObj == NIL_RTR0MEMOBJ), STATUS_INVALID_PARAMETER);
    55 
    56     if (enable)
    57     {
    58         pSvga->u32NumCmdBufs = 8;
    59 
    60         rc = RTR0MemObjAllocPageTag(&pSvga->hMemObj, 2 * PAGE_SIZE,
    61                                 false /* executable R0 mapping */, "WDDMGA");
    62 
    63         pSvga->pvR0Hdr = RTR0MemObjAddress(pSvga->hMemObj);
    64         pSvga->paHdr   = RTR0MemObjGetPagePhysAddr(pSvga->hMemObj, 0/*iPage*/);
    65         memset(pSvga->pvR0Hdr, 0, PAGE_SIZE);
    66 
    67         pSvga->pvR0Cmd = (uint8_t *)pSvga->pvR0Hdr + PAGE_SIZE;
    68         pSvga->paCmd   = RTR0MemObjGetPagePhysAddr(pSvga->hMemObj, 1/*iPage*/);
    69         memset(pSvga->pvR0Cmd, 0, PAGE_SIZE);
    70     }
    71 
    72     SVGACBHeader *pHdr = (SVGACBHeader *)pSvga->pvR0Hdr;
    73 
    74     pHdr->status = SVGA_CB_STATUS_NONE;
    75     pHdr->errorOffset = 0;
    76     pHdr->id = 0;
    77     pHdr->flags = SVGA_CB_FLAG_NO_IRQ;
    78     pHdr->length = sizeof(uint32_t) + sizeof(SVGADCCmdStartStop);
    79     pHdr->ptr.pa = pSvga->paCmd;
    80 
    81     uint32_t *pu32Id = (uint32_t *)pSvga->pvR0Cmd;
    82     SVGADCCmdStartStop *pCommand = (SVGADCCmdStartStop *)&pu32Id[1];
    83 
    84     *pu32Id = SVGA_DC_CMD_START_STOP_CONTEXT;
    85     pCommand->enable = enable;
    86     pCommand->context = SVGA_CB_CONTEXT_0;
    87 
    88     SVGARegWrite(pSvga, SVGA_REG_COMMAND_HIGH, (uint32_t)(pSvga->paHdr >> 32));
    89     SVGARegWrite(pSvga, SVGA_REG_COMMAND_LOW, (uint32_t)pSvga->paHdr | 0x3f);
    90 
    91     if (!enable)
    92     {
    93         rc = RTR0MemObjFree(pSvga->hMemObj, true);
    94         pSvga->hMemObj = NIL_RTR0MEMOBJ;
    95     }
    96     else
    97     {
    98         uint32_t idx;
    99 
    100         for(idx = 0; idx < pSvga->u32NumCmdBufs; idx++)
    101         {
    102             pHdr->status = SVGA_CB_STATUS_COMPLETED;
    103             pHdr->errorOffset = 0;
    104             pHdr->id = 0;
    105             pHdr->flags = SVGA_CB_FLAG_NO_IRQ;
    106             pHdr->length = 0;
    107             pHdr->ptr.pa = 0;
    108 
    109             pHdr++;
    110         }
    111     }
    112 
    113     AssertRC(rc);
    114     return rc;
    115 }
    116 
    117 static uint32_t SvgaCmdBufReserve(VBOXWDDM_EXT_VMSVGA *pSvga)
    118 {
    119     SVGACBHeader *pHdr = (SVGACBHeader *)pSvga->pvR0Hdr;
    120     uint32_t idx;
    121 
    122     for(idx = 0; idx < pSvga->u32NumCmdBufs; idx++)
    123     {
    124         if (ASMAtomicCmpXchgU32((volatile uint32_t *)&pHdr->status, SVGA_CB_STATUS_NONE, SVGA_CB_STATUS_COMPLETED))
    125         {
    126             return idx;
    127         }
    128 
    129         pHdr++;
    130     }
    131 
    132     return UINT32_MAX;
    133 }
    134 
    13529/** @todo The size of each Object Table should not be hardcoded but estimated using some VMSVGA device limits **/
    136 static NTSTATUS SvgaObjectTablesInit(VBOXWDDM_EXT_VMSVGA *pSvga, bool enable)
    137 {
    138     uint32_t idCmdHdr = UINT32_MAX;
    139     void *pvCmd = NULL;
    140     int rc = STATUS_SUCCESS;
    141 
    142     if (enable)
    143     {
    144         rc = RTR0MemObjAllocPageTag(&pSvga->hMemObjOTables, (SVGA_OTABLE_DXCONTEXT + 1) * PAGE_SIZE,
    145                                 false /* executable R0 mapping */, "WDDMGA");
    146     }
    147     else
    148     {
    149         rc = RTR0MemObjFree(pSvga->hMemObjOTables, true);
    150         pSvga->hMemObjOTables = NIL_RTR0MEMOBJ;
    151         return rc;
    152     }
    153 
    154     idCmdHdr = SvgaCmdBufReserve(pSvga);
    155 
    156     if (idCmdHdr < pSvga->u32NumCmdBufs)
    157     {
    158         pvCmd = pSvga->pvR0Cmd;
    159     }
    160     else
    161     {
    162         GALOGREL(32, ("WDDM: SvgaCmdBufReserve failed\n"));
    163         return STATUS_INSUFFICIENT_RESOURCES;
    164     }
    165 
    166     SVGA3dCmdHeader *pHeader = (SVGA3dCmdHeader *)pvCmd;
    167     SVGA3dCmdSetOTableBase64 *pCommand = (SVGA3dCmdSetOTableBase64 *)&pHeader[1];
    168     uint32_t cbSubmit = 0;
    169     uint32_t idOTable;
    170 
    171     for(idOTable = 0; idOTable <= SVGA_OTABLE_DXCONTEXT; idOTable++)
     30static NTSTATUS SvgaObjectTablesInit(VBOXWDDM_EXT_VMSVGA *pSvga)
     31{
     32    int rc = RTR0MemObjAllocPageTag(&pSvga->hMemObjOTables, (SVGA_OTABLE_DXCONTEXT + 1) * PAGE_SIZE,
     33                                    false /* executable R0 mapping */, "WDDMGA");
     34    AssertRCReturn(rc, STATUS_INSUFFICIENT_RESOURCES);
     35
     36    for (uint32_t idOTable = 0; idOTable < SVGA_OTABLE_DX_MAX; idOTable++)
    17237    {
    17338        RTHCPHYS paOT = RTR0MemObjGetPagePhysAddr(pSvga->hMemObjOTables, idOTable);
    17439
    175         pHeader->id = SVGA_3D_CMD_SET_OTABLE_BASE64;
    176         pHeader->size = sizeof(SVGA3dCmdSetOTableBase64);
    177         pCommand->type = (SVGAOTableType)idOTable;
    178         pCommand->baseAddress = paOT >> 12;
    179         pCommand->sizeInBytes = PAGE_SIZE;
    180         pCommand->validSizeInBytes = 0;
    181         pCommand->ptDepth = SVGA3D_MOBFMT_PTDEPTH64_0;
    182 
    183         cbSubmit += sizeof(SVGA3dCmdHeader) + sizeof(SVGA3dCmdSetOTableBase64);
    184 
    185         pHeader = (SVGA3dCmdHeader *)&pCommand[1];
    186         pCommand = (SVGA3dCmdSetOTableBase64 *)&pHeader[1];
    187     }
    188 
    189     SvgaCmdBufSubmit(pSvga, cbSubmit, idCmdHdr);
    190 
    191     AssertRC(rc);
    192     return rc;
    193 }
     40        void *pvCmd = SvgaCmdBuf3dCmdReserve(pSvga, SVGA_3D_CMD_SET_OTABLE_BASE64, sizeof(SVGA3dCmdSetOTableBase64), SVGA3D_INVALID_ID);
     41        AssertBreak(pvCmd);
     42
     43        SVGA3dCmdSetOTableBase64 *pCmd = (SVGA3dCmdSetOTableBase64 *)pvCmd;
     44        pCmd->type             = (SVGAOTableType)idOTable;
     45        pCmd->baseAddress      = paOT >> 12;
     46        pCmd->sizeInBytes      = PAGE_SIZE;
     47        pCmd->validSizeInBytes = 0;
     48        pCmd->ptDepth          = SVGA3D_MOBFMT_PTDEPTH64_0;
     49
     50        SvgaCmdBufCommit(pSvga, sizeof(SVGA3dCmdSetOTableBase64));
     51    }
     52
     53    SvgaCmdBufFlush(pSvga);
     54    return STATUS_SUCCESS;
     55}
     56
     57
     58static NTSTATUS svgaCBContextEnable(VBOXWDDM_EXT_VMSVGA *pSvga, SVGACBContext CBContext, bool fEnable)
     59{
     60    struct {
     61        uint32 id;
     62        SVGADCCmdStartStop body;
     63    } cmd;
     64    cmd.id = SVGA_DC_CMD_START_STOP_CONTEXT;
     65    cmd.body.enable = fEnable;
     66    cmd.body.context = CBContext;
     67    NTSTATUS Status = SvgaCmdBufDeviceCommand(pSvga, &cmd, sizeof(cmd));
     68    AssertReturn(NT_SUCCESS(Status), Status);
     69    return STATUS_SUCCESS;
     70}
     71
    19472
    19573static NTSTATUS svgaHwInit(VBOXWDDM_EXT_VMSVGA *pSvga)
     
    229107
    230108    NTSTATUS Status = SvgaFifoInit(pSvga);
    231     if (NT_SUCCESS(Status))
    232     {
    233         /* Enable SVGA device. */
    234         SVGARegWrite(pSvga, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE);
    235         SVGARegWrite(pSvga, SVGA_REG_IRQMASK, SVGA_IRQFLAG_ANY_FENCE);
    236     }
     109    AssertReturn(NT_SUCCESS(Status), Status);
    237110
    238111    if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
    239112    {
    240         SvgaCmdBufCtxInit(pSvga, true);
    241         SvgaObjectTablesInit(pSvga, true);
    242     }
    243 
    244     return Status;
     113        Status = SvgaCmdBufInit(pSvga);
     114        AssertReturn(NT_SUCCESS(Status), Status);
     115    }
     116
     117    /* Enable SVGA device. */
     118    SVGARegWrite(pSvga, SVGA_REG_ENABLE, SVGA_REG_ENABLE_ENABLE);
     119
     120    if (pSvga->pCBState)
     121    {
     122        svgaCBContextEnable(pSvga, SVGA_CB_CONTEXT_0, true);
     123        AssertReturn(NT_SUCCESS(Status), Status);
     124    }
     125
     126    if (pSvga->u32Caps & SVGA_CAP_GBOBJECTS)
     127    {
     128        /** @todo DX contexts are available if SVGA_CAP_GBOBJECTS, SVGA_CAP_DX and SVGA3D_DEVCAP_DXCONTEXT are all enabled. */
     129        Status = SvgaObjectTablesInit(pSvga);
     130        AssertReturn(NT_SUCCESS(Status), Status);
     131    }
     132
     133    uint32_t u32IRQMask = SVGA_IRQFLAG_ANY_FENCE;
     134    if (pSvga->pCBState)
     135        u32IRQMask |= SVGA_IRQFLAG_COMMAND_BUFFER;
     136    SVGARegWrite(pSvga, SVGA_REG_IRQMASK, u32IRQMask);
     137
     138    return STATUS_SUCCESS;
    245139}
    246140
     
    269163        }
    270164
     165        /** @todo svgaHwStop(VBOXWDDM_EXT_VMSVGA *pSvga) to undo svgaHwInit */
    271166        if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
    272167        {
    273             SvgaObjectTablesInit(pSvga, false);
    274             SvgaCmdBufCtxInit(pSvga, false);
     168            /// @todo SvgaObjectTablesDestroy(pSvga);
     169            SvgaCmdBufDestroy(pSvga);
    275170        }
    276171
     
    12241119}
    12251120
     1121void *SvgaReserve(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbReserve, uint32_t idDXContext)
     1122{
     1123    if (pSvga->pCBState)
     1124        return SvgaCmdBufReserve(pSvga, cbReserve, idDXContext);
     1125    return SvgaFifoReserve(pSvga, cbReserve);
     1126}
     1127
     1128void SvgaCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual)
     1129{
     1130    if (pSvga->pCBState)
     1131    {
     1132        SvgaCmdBufCommit(pSvga, cbActual);
     1133        return;
     1134    }
     1135    SvgaFifoCommit(pSvga, cbActual);
     1136}
     1137
     1138void SvgaFlush(PVBOXWDDM_EXT_VMSVGA pSvga)
     1139{
     1140    if (pSvga->pCBState)
     1141        SvgaCmdBufFlush(pSvga);
     1142}
     1143
    12261144NTSTATUS SvgaBlitGMRFBToScreen(PVBOXWDDM_EXT_VMSVGA pSvga,
    12271145                               uint32_t idDstScreen,
     
    12321150    NTSTATUS Status = STATUS_SUCCESS;
    12331151    uint32_t cbSubmit = 0;
    1234     uint32_t idx = UINT32_MAX;
    12351152    void *pvCmd = NULL;
    12361153
     
    12381155                             NULL, 0, &cbSubmit);
    12391156
    1240     if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
    1241     {
    1242         idx = SvgaCmdBufReserve(pSvga);
    1243 
    1244         if (idx < pSvga->u32NumCmdBufs)
    1245         {
    1246             pvCmd = pSvga->pvR0Cmd;
    1247         }
    1248         else
    1249         {
    1250             GALOGREL(32, ("WDDM: SvgaCmdBufReserve failed\n"));
    1251         }
    1252     }
    1253     else
    1254     {
    1255         pvCmd = SvgaFifoReserve(pSvga, cbSubmit);
    1256     }
    1257 
     1157    pvCmd = SvgaReserve(pSvga, cbSubmit, SVGA3D_INVALID_ID);
    12581158    if (pvCmd)
    12591159    {
     
    12621162        Assert(Status == STATUS_SUCCESS);
    12631163
    1264         if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS)
    1265         {
    1266             SvgaCmdBufSubmit(pSvga, cbSubmit, idx);
    1267         }
    1268         else
    1269         {
    1270             SvgaFifoCommit(pSvga, cbSubmit);
    1271         }
     1164        SvgaCommit(pSvga, cbSubmit);
     1165        SvgaFlush(pSvga);
    12721166    }
    12731167    else
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.h

    r93834 r94622  
    5959} VMSVGAFIFO;
    6060typedef VMSVGAFIFO *PVMSVGAFIFO;
     61
     62/*
     63 * Command buffers.
     64 */
     65typedef struct VMSVGACBPAGE
     66{
     67    RTR0MEMOBJ           hMemObj;
     68    RTR0PTR              pvR0;
     69    RTHCPHYS             PhysAddr;
     70} VMSVGACBPAGE, *PVMSVGACBPAGE;
     71
     72typedef int32_t VMSVGACBHEADERHANDLE;
     73#define VMSVGACBHEADER_NIL (-1)
     74
     75typedef enum VMSVGACBTYPE
     76{
     77    VMSVGACB_INVALID  = 0,
     78    VMSVGACB_CONTEXT_DEVICE = 1,
     79    VMSVGACB_MINIPORT = 2,
     80    VMSVGACB_UMD = 3
     81} VMSVGACBTYPE;
     82
     83/* Information about a command buffer. */
     84typedef struct VMSVGACB
     85{
     86    RTLISTNODE           nodeQueue;                /* For a queue where the buffer is currently resides. */
     87    VMSVGACBTYPE         enmType;                  /* Type of the buffer. */
     88    uint32_t             idDXContext;              /* DX context of the buffer or SVGA3D_INVALID_ID. */
     89    uint32_t             cbBuffer;                 /* Total size. */
     90    uint32_t             cbCommand;                /* Size of commands. */
     91    uint32_t             cbReservedCmdHeader;      /* Reserved for the command header. */
     92    uint32_t             cbReservedCmd;            /* Reserved for the current command without the header. */
     93    uint32_t             u32ReservedCmd;           /* The current command. */
     94    VMSVGACBHEADERHANDLE hHeader;                  /* Handle of the header (index in the header pool array). */
     95    SVGACBHeader        *pCBHeader;                /* Pointer to the header. */
     96    PHYSICAL_ADDRESS     CBHeaderPhysAddr;
     97    union                                          /* Command data. */
     98    {
     99        VMSVGACBPAGE     page;                     /* VMSVGACB_CONTEXT_DEVICE and VMSVGACB_MINIPORT */
     100        PHYSICAL_ADDRESS DmaBufferPhysicalAddress; /* VMSVGACB_UMD */
     101    } commands;
     102} VMSVGACB, *PVMSVGACB;
     103
     104/* Buffer headers are allocated for submitted buffers, which sometimes are not immediately passed to the host.
     105 * Therefore the pool must be a bit larger than SVGA_CB_MAX_QUEUED_PER_CONTEXT * SVGA_CB_CONTEXT_MAX
     106 */
     107#define VMSVGA_CB_HEADER_POOL_NUM_PAGES         2
     108#define VMSVGA_CB_HEADER_POOL_HANDLES_PER_PAGE (PAGE_SIZE / sizeof(SVGACBHeader))
     109#define VMSVGA_CB_HEADER_POOL_NUM_HANDLES      (VMSVGA_CB_HEADER_POOL_NUM_PAGES * VMSVGA_CB_HEADER_POOL_HANDLES_PER_PAGE)
     110
     111typedef struct VMSVGACBHEADERPOOL
     112{
     113    KSPIN_LOCK           SpinLock;
     114    VMSVGACBPAGE         aHeaderPoolPages[VMSVGA_CB_HEADER_POOL_NUM_PAGES];
     115    uint32_t             au32HeaderBits[VMSVGA_CB_HEADER_POOL_NUM_HANDLES / 32];
     116} VMSVGACBHEADERPOOL, *PVMSVGACBHEADERPOOL;
     117
     118typedef struct VMSVGACBCONTEXT
     119{
     120    RTLISTANCHOR         QueuePending;             /* Buffers which will be submitted to the host. */
     121    RTLISTANCHOR         QueueSubmitted;           /* Buffers which are being processed by the host. */
     122    RTLISTANCHOR         QueuePreempted;           /* Preempted buffers. */
     123    uint32_t             cSubmitted;               /* How many buffers were submitted to the host.
     124                                                    * Less than SVGA_CB_MAX_QUEUED_PER_CONTEXT */
     125} VMSVGACBCONTEXT, *PVMSVGACBCONTEXT;
     126
     127typedef struct VMSVGACBSTATE
     128{
     129    VMSVGACBCONTEXT      aCBContexts[SVGA_CB_CONTEXT_MAX]; /* Command buffer contexts. */
     130    VMSVGACBHEADERPOOL   HeaderPool;               /* Array of buffer headers. */
     131    PVMSVGACB            pCBCurrent;               /* Current buffer for miniport commands. */
     132    FAST_MUTEX           CBCurrentMutex;           /* Access pCBCurrent.  KGUARDED_MUTEX? */
     133    KSPIN_LOCK           SpinLock;                 /* Lock for aCBContexts. */
     134} VMSVGACBSTATE, *PVMSVGACBSTATE;
    61135
    62136/* VMSVGA specific part of Gallium device extension. */
     
    94168    /** Fifo state. */
    95169    VMSVGAFIFO fifo;
     170
     171    /** Command buffers state. */
     172    PVMSVGACBSTATE pCBState;
     173    bool volatile fCommandBufferIrq;
    96174
    97175    /** For atomic hardware access. */
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.cpp

    r93115 r94622  
    2222
    2323#include <iprt/alloc.h>
     24#include <iprt/errcore.h>
     25#include <iprt/memobj.h>
     26#include <iprt/string.h>
    2427#include <iprt/thread.h>
     28#include <iprt/x86.h>
    2529
    2630NTSTATUS SvgaFifoInit(PVBOXWDDM_EXT_VMSVGA pSvga)
     
    238242    ExReleaseFastMutex(&pFifo->FifoMutex);
    239243}
     244
     245
     246/*
     247 * Command buffers are supported by the host if SVGA_CAP_COMMAND_BUFFERS is set.
     248 *
     249 * A command buffer consists of command data and a buffer header (SVGACBHeader), which contains
     250 * buffer physical address. The memory is allocated from non paged pool.
     251 *
     252 * The guest submits a command buffer by writing 64 bit physical address in
     253 * SVGA_REG_COMMAND_HIGH and SVGA_REG_COMMAND_LOW registers.
     254 *
     255 * The physical address of the header must be 64 bytes aligned and the lower 6 bits
     256 * contain command buffer context id. Each command buffer context is a queue of submitted
     257 * buffers. Id 0x3f is SVGA_CB_CONTEXT_DEVICE, which is used to send synchronous commands
     258 * to the host, which are used to setup and control other buffer contexts (queues).
     259 *
     260 * The miniport driver submits buffers in one of 3 case (VMSVGACBTYPE):
     261 * 1) SVGA_CB_CONTEXT_DEVICE commands.
     262 *      Small amount of memory.
     263 *      Synchronous.
     264 * 2) Submitting commands from the miniport.
     265 *      Memory for the command data must be allocated.
     266 *      The host processes the buffer asynchronously, updated the buffer status and generates an interrupt.
     267 * 3) Submitting command buffers generated by the user mode driver.
     268 *      Memory for the commands is provided by WDDM (DXGKARG_SUBMITCOMMAND::DmaBufferPhysicalAddress).
     269 *      Asynchronous processing.
     270 *
     271 * A pool of command headers is used to avoid allocation of command headers.
     272 * The pool space is allocate page by page as necessary. Each page is an array of SVGACBHeader.
     273 * A bitmask is used in order to track headers. Headers are allocated only for submitted comamnd buffers,
     274 * in order to minimize consumption.
     275 *
     276 * Total size of command buffers must not exceed SVGA_CB_MAX_SIZE.
     277 * One buffer can be up to SVGA_CB_MAX_COMMAND_SIZE.
     278 * Up to SVGA_CB_MAX_QUEUED_PER_CONTEXT buffers cane be queued for one command buffer context simultaneously.
     279 *
     280 * The miniport allocates page size memory buffers for VMSVGACB_CONTEXT_DEVICE and VMSVGACB_MINIPORT.
     281 * Initially the memory is allocated on demand and free upom buffer completion.
     282 * Later a growing and automatically shrinking pool can be used.
     283 *
     284 * Command buffer can be tied to a DX context, which the driver creates on the host. I.e. all commands
     285 * are submitted for this DX context. In this case SVGA_CB_FLAG_DX_CONTEXT bit is set in the header 'flags'
     286 * and 'dxContext' field is set to the DX context id.
     287 */
     288
     289static NTSTATUS svgaCBFreePage(PVMSVGACBPAGE pPage)
     290{
     291    if (pPage->hMemObj != NIL_RTR0MEMOBJ)
     292    {
     293        int rc = RTR0MemObjFree(pPage->hMemObj, /* fFreeMappings */ true);
     294        AssertReturn(RT_SUCCESS(rc), STATUS_INVALID_PARAMETER);
     295    }
     296    RT_ZERO(*pPage);
     297    return STATUS_SUCCESS;
     298}
     299
     300
     301static NTSTATUS svgaCBAllocPage(PVMSVGACBPAGE pPage)
     302{
     303    int rc = RTR0MemObjAllocPageTag(&pPage->hMemObj, PAGE_SIZE,
     304                                    /* fExecutable */ false, "WDDMGA");
     305    AssertReturn(RT_SUCCESS(rc), STATUS_INSUFFICIENT_RESOURCES);
     306
     307    pPage->pvR0     = RTR0MemObjAddress(pPage->hMemObj);
     308    pPage->PhysAddr = RTR0MemObjGetPagePhysAddr(pPage->hMemObj, /* iPage */ 0);
     309    return STATUS_SUCCESS;
     310}
     311
     312
     313static void svgaCBHeaderPoolDestroy(PVMSVGACBHEADERPOOL pHeaderPool)
     314{
     315    for (unsigned i = 0; i < RT_ELEMENTS(pHeaderPool->aHeaderPoolPages); ++i)
     316        svgaCBFreePage(&pHeaderPool->aHeaderPoolPages[i]);
     317
     318    RT_ZERO(*pHeaderPool);
     319}
     320
     321
     322static NTSTATUS svgaCBHeaderPoolInit(PVMSVGACBHEADERPOOL pHeaderPool)
     323{
     324    /* The pool is already initialized to 0 be the caller. */
     325    NTSTATUS Status = STATUS_SUCCESS;
     326    for (unsigned i = 0; i < RT_ELEMENTS(pHeaderPool->aHeaderPoolPages); ++i)
     327    {
     328        Status = svgaCBAllocPage(&pHeaderPool->aHeaderPoolPages[i]);
     329        AssertBreak(NT_SUCCESS(Status));
     330    }
     331
     332    if (NT_SUCCESS(Status))
     333        KeInitializeSpinLock(&pHeaderPool->SpinLock);
     334    else
     335        svgaCBHeaderPoolDestroy(pHeaderPool);
     336
     337    return Status;
     338}
     339
     340
     341static void svgaCBHeaderPoolFree(PVMSVGACBHEADERPOOL pHeaderPool,
     342                                 VMSVGACBHEADERHANDLE hHeader)
     343{
     344    if (hHeader != VMSVGACBHEADER_NIL)
     345    {
     346        KIRQL OldIrql;
     347        KeAcquireSpinLock(&pHeaderPool->SpinLock, &OldIrql);
     348        NTSTATUS Status = GaIdFree(pHeaderPool->au32HeaderBits, sizeof(pHeaderPool->au32HeaderBits),
     349                                   VMSVGA_CB_HEADER_POOL_NUM_HANDLES, hHeader);
     350        KeReleaseSpinLock(&pHeaderPool->SpinLock, OldIrql);
     351        Assert(NT_SUCCESS(Status)); RT_NOREF(Status);
     352    }
     353}
     354
     355static NTSTATUS svgaCBHeaderPoolAlloc(PVMSVGACBHEADERPOOL pHeaderPool,
     356                                      VMSVGACBHEADERHANDLE *phHeader,
     357                                      SVGACBHeader **ppCBHeader,
     358                                      PHYSICAL_ADDRESS *pPhysAddr)
     359{
     360    NTSTATUS Status;
     361    uint32_t id;
     362
     363    KIRQL OldIrql;
     364    KeAcquireSpinLock(&pHeaderPool->SpinLock, &OldIrql);
     365    Status = GaIdAlloc(pHeaderPool->au32HeaderBits, sizeof(pHeaderPool->au32HeaderBits),
     366                       VMSVGA_CB_HEADER_POOL_NUM_HANDLES, &id);
     367    KeReleaseSpinLock(&pHeaderPool->SpinLock, OldIrql);
     368    AssertReturn(NT_SUCCESS(Status), Status);
     369
     370    int const idxPage = id / VMSVGA_CB_HEADER_POOL_HANDLES_PER_PAGE;
     371    Assert(idxPage < RT_ELEMENTS(pHeaderPool->aHeaderPoolPages));
     372
     373    PVMSVGACBPAGE pPage = &pHeaderPool->aHeaderPoolPages[idxPage];
     374    Assert(pPage->hMemObj != NIL_RTR0MEMOBJ);
     375
     376    uint32_t const offPage = (id - idxPage * VMSVGA_CB_HEADER_POOL_HANDLES_PER_PAGE) * sizeof(SVGACBHeader);
     377    *ppCBHeader = (SVGACBHeader *)((uint8_t *)pPage->pvR0 + offPage);
     378    (*pPhysAddr).QuadPart = pPage->PhysAddr + offPage;
     379    *phHeader = id;
     380    return Status;
     381}
     382
     383
     384static NTSTATUS svgaCBFree(PVMSVGACBSTATE pCBState, PVMSVGACB pCB)
     385{
     386    if (pCB->enmType != VMSVGACB_UMD)
     387        svgaCBFreePage(&pCB->commands.page);
     388
     389    svgaCBHeaderPoolFree(&pCBState->HeaderPool, pCB->hHeader);
     390
     391    GaMemFree(pCB);
     392    return STATUS_SUCCESS;
     393}
     394
     395
     396/** Allocate one command buffer.
     397 * @param pCBState    Command buffers manager.
     398 * @param enmType     Kind of the buffer.
     399 * @param idDXContext DX context of the commands in the buffer.
     400 * @param ppCB        Where to store the allocated buffer pointer.
     401 */
     402static NTSTATUS svgaCBAlloc(PVMSVGACBSTATE pCBState, VMSVGACBTYPE enmType, uint32_t idDXContext, PVMSVGACB *ppCB)
     403{
     404    RT_NOREF(pCBState);
     405
     406    PVMSVGACB pCB = (PVMSVGACB)GaMemAllocZero(sizeof(VMSVGACB));
     407    AssertReturn(pCB, STATUS_INSUFFICIENT_RESOURCES);
     408
     409    NTSTATUS Status;
     410
     411    RT_ZERO(pCB->nodeQueue);
     412    pCB->enmType = enmType;
     413    pCB->idDXContext = idDXContext;
     414    pCB->cbReservedCmdHeader = 0;
     415    pCB->cbReservedCmd = 0;
     416    pCB->u32ReservedCmd = 0;
     417    if (enmType != VMSVGACB_UMD)
     418    {
     419        pCB->cbBuffer = PAGE_SIZE;
     420        pCB->cbCommand = 0;
     421        Status = svgaCBAllocPage(&pCB->commands.page);
     422        AssertReturnStmt(NT_SUCCESS(Status),
     423                         GaMemFree(pCB),
     424                         STATUS_INSUFFICIENT_RESOURCES);
     425    }
     426    else
     427    {
     428        pCB->cbBuffer = 0;
     429        pCB->cbCommand = 0;
     430        pCB->commands.DmaBufferPhysicalAddress.QuadPart = 0;
     431    }
     432
     433    /* Buffer header is not allocated. */
     434    pCB->hHeader = VMSVGACBHEADER_NIL;
     435
     436    *ppCB = pCB;
     437    return STATUS_SUCCESS;
     438}
     439
     440static void svgaCBSubmitHeader(PVBOXWDDM_EXT_VMSVGA pSvga, PHYSICAL_ADDRESS CBHeaderPhysAddr, SVGACBContext CBContext)
     441{
     442    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     443
     444    KIRQL OldIrql;
     445    KeAcquireSpinLock(&pCBState->SpinLock, &OldIrql);
     446
     447    SVGARegWrite(pSvga, SVGA_REG_COMMAND_HIGH, CBHeaderPhysAddr.HighPart);
     448    SVGARegWrite(pSvga, SVGA_REG_COMMAND_LOW, CBHeaderPhysAddr.LowPart | CBContext);
     449
     450    KeReleaseSpinLock(&pCBState->SpinLock, OldIrql);
     451}
     452
     453static NTSTATUS svgaCBSubmit(PVBOXWDDM_EXT_VMSVGA pSvga, PVMSVGACB pCB)
     454{
     455    NTSTATUS Status;
     456
     457    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     458
     459    /* Allocate a header for the buffer. */
     460    Status = svgaCBHeaderPoolAlloc(&pCBState->HeaderPool, &pCB->hHeader, &pCB->pCBHeader, &pCB->CBHeaderPhysAddr);
     461    AssertReturn(NT_SUCCESS(Status), Status);
     462
     463    /* Initialize the header. */
     464    SVGACBHeader *pCBHeader = pCB->pCBHeader;
     465    pCBHeader->status      = SVGA_CB_STATUS_NONE;
     466    pCBHeader->errorOffset = 0;
     467    pCBHeader->id          = 0;
     468    if (pCB->idDXContext != SVGA3D_INVALID_ID)
     469        pCBHeader->flags   = SVGA_CB_FLAG_DX_CONTEXT;
     470    else
     471        pCBHeader->flags   = SVGA_CB_FLAG_NONE;
     472    pCBHeader->length      = pCB->cbCommand;
     473    if (pCB->enmType != VMSVGACB_UMD)
     474        pCBHeader->ptr.pa  = pCB->commands.page.PhysAddr;
     475    else
     476        pCBHeader->ptr.pa  = pCB->commands.DmaBufferPhysicalAddress.QuadPart;
     477    pCBHeader->offset      = 0;
     478    pCBHeader->dxContext   = pCB->idDXContext;
     479    RT_ZERO(pCBHeader->mustBeZero);
     480
     481    /* Select appropriate comamnd buffer context. */
     482    SVGACBContext CBContext;
     483    if (pCB->enmType != VMSVGACB_CONTEXT_DEVICE)
     484    {
     485        CBContext = SVGA_CB_CONTEXT_0;
     486
     487        KIRQL OldIrql;
     488        KeAcquireSpinLock(&pCBState->SpinLock, &OldIrql);
     489
     490        PVMSVGACBCONTEXT pCBCtx = &pCBState->aCBContexts[CBContext];
     491        if (pCBCtx->cSubmitted >= SVGA_CB_MAX_QUEUED_PER_CONTEXT - 1)
     492        {
     493            /* Can't submit the buffer. Put it into pending queue. */
     494            RTListAppend(&pCBCtx->QueuePending, &pCB->nodeQueue);
     495
     496            KeReleaseSpinLock(&pCBState->SpinLock, OldIrql);
     497            return STATUS_SUCCESS;
     498        }
     499
     500        RTListAppend(&pCBCtx->QueueSubmitted, &pCB->nodeQueue);
     501        ++pCBCtx->cSubmitted;
     502
     503        KeReleaseSpinLock(&pCBState->SpinLock, OldIrql);
     504    }
     505    else
     506        CBContext = SVGA_CB_CONTEXT_DEVICE;
     507
     508    svgaCBSubmitHeader(pSvga, pCB->CBHeaderPhysAddr, CBContext);
     509    return STATUS_SUCCESS;
     510}
     511
     512NTSTATUS SvgaCmdBufDeviceCommand(PVBOXWDDM_EXT_VMSVGA pSvga, void const *pvCmd, uint32_t cbCmd)
     513{
     514    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     515
     516    PVMSVGACB pCB;
     517    NTSTATUS Status = svgaCBAlloc(pCBState, VMSVGACB_CONTEXT_DEVICE, SVGA3D_INVALID_ID, &pCB);
     518    AssertReturn(NT_SUCCESS(Status), Status);
     519
     520    memcpy(pCB->commands.page.pvR0, pvCmd, cbCmd);
     521    pCB->cbCommand = cbCmd;
     522
     523    Status = svgaCBSubmit(pSvga, pCB);
     524    if (NT_SUCCESS(Status))
     525    {
     526        if (pCB->pCBHeader->status != SVGA_CB_STATUS_COMPLETED)
     527            Status = STATUS_INVALID_PARAMETER;
     528    }
     529    svgaCBFree(pCBState, pCB);
     530    return Status;
     531}
     532
     533
     534/** Reserve space for a command in the current miniport command buffer.
     535 * The current buffer will be submitted to the host if either the command does not fit
     536 * or if the command is for another DX context than the commands in the buffer.
     537 *
     538 * @param pSvga            The device instance.
     539 * @param u32CmdId         Command identifier.
     540 * @param cbReserveHeader  Size of the command header.
     541 * @param cbReserveCmd     Expected size of the command data.
     542 * @param idDXContext      DX context of the command.
     543 * @return Pointer to the command data.
     544 */
     545static void *svgaCBReserve(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t u32CmdId, uint32_t cbReserveHeader, uint32_t cbReserveCmd, uint32_t idDXContext)
     546{
     547    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     548    NTSTATUS Status;
     549
     550    /* Required space for the command header and the command. */
     551    uint32_t const cbRequired = cbReserveHeader + cbReserveCmd;
     552
     553    /* Current command buffer is locked until SvgaCmdBufCommit is called. */
     554    ExAcquireFastMutex(&pCBState->CBCurrentMutex);
     555
     556    PVMSVGACB pCB = pCBState->pCBCurrent;
     557    if (   pCB
     558        && (   pCB->cbBuffer - pCB->cbCommand < cbRequired
     559            || idDXContext != pCB->idDXContext))
     560    {
     561        /* If the command does not fit or is for a different context, then submit the current buffer. */
     562        Status = svgaCBSubmit(pSvga, pCB);
     563        Assert(NT_SUCCESS(Status));
     564
     565        /* A new current buffer must be allocated. */
     566        pCB = NULL;
     567    }
     568
     569    if (!pCB)
     570    {
     571        /* Allocate a new command buffer. */
     572        Status = svgaCBAlloc(pCBState, VMSVGACB_MINIPORT, idDXContext, &pCBState->pCBCurrent);
     573        AssertReturnStmt(NT_SUCCESS(Status), ExReleaseFastMutex(&pCBState->CBCurrentMutex), NULL);
     574        pCB = pCBState->pCBCurrent;
     575    }
     576
     577    /* Remember the size and id of the command. */
     578    pCB->cbReservedCmdHeader = cbReserveHeader;
     579    pCB->cbReservedCmd = cbReserveCmd;
     580    pCB->u32ReservedCmd = u32CmdId;
     581
     582    /* Return pointer to the command data. */
     583    return (uint8_t *)pCB->commands.page.pvR0 + pCB->cbCommand + cbReserveHeader;
     584}
     585
     586
     587/** Reserve space for a 3D command in the current miniport command buffer.
     588 * This function reserves space for a command header and for the command.
     589 *
     590 * @param pSvga            The device instance.
     591 * @param enmCmd           Command identifier.
     592 * @param cbReserve        Expected size of the command data.
     593 * @param idDXContext      DX context of the command.
     594 * @return Pointer to the command data.
     595 */
     596void *SvgaCmdBuf3dCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifo3dCmdId enmCmd, uint32_t cbReserve, uint32_t idDXContext)
     597{
     598    return svgaCBReserve(pSvga, enmCmd, sizeof(SVGA3dCmdHeader), cbReserve, idDXContext);
     599}
     600
     601
     602/** Reserve space for a FIFO command in the current miniport command buffer.
     603 * This function reserves space for the command id and for the command.
     604 *
     605 * @param pSvga            The device instance.
     606 * @param enmCmd           Command identifier.
     607 * @param cbReserve        Expected size of the command data.
     608 * @return Pointer to the command data.
     609 */
     610void *SvgaCmdBufFifoCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifoCmdId enmCmd, uint32_t cbReserve)
     611{
     612    return svgaCBReserve(pSvga, enmCmd, sizeof(uint32_t), cbReserve, SVGA3D_INVALID_ID);
     613}
     614
     615
     616/** Reserve space for a raw command in the current miniport command buffer.
     617 * The command already includes any headers.
     618 *
     619 * @param pSvga            The device instance.
     620 * @param cbReserve        Expected size of the command data.
     621 * @return Pointer to the command data.
     622 */
     623void *SvgaCmdBufReserve(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbReserve, uint32_t idDXContext)
     624{
     625    return svgaCBReserve(pSvga, SVGA_CMD_INVALID_CMD, 0, cbReserve, idDXContext);
     626}
     627
     628
     629/** Commit space for the current command in the current miniport command buffer.
     630 *
     631 * @param pSvga            The device instance.
     632 * @param cbActual         Actual size of the command data. Must be not greater than the reserved size.
     633 */
     634void SvgaCmdBufCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual)
     635{
     636    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     637
     638    PVMSVGACB pCB = pCBState->pCBCurrent;
     639    AssertReturnVoidStmt(pCB, ExReleaseFastMutex(&pCBState->CBCurrentMutex));
     640
     641    Assert(cbActual <= pCB->cbReservedCmd);
     642    cbActual = RT_MIN(cbActual, pCB->cbReservedCmd);
     643
     644    /* Initialize the command header. */
     645    if (pCB->cbReservedCmdHeader == sizeof(SVGA3dCmdHeader))
     646    {
     647        SVGA3dCmdHeader *pHeader = (SVGA3dCmdHeader *)((uint8_t *)pCB->commands.page.pvR0 + pCB->cbCommand);
     648        pHeader->id = pCB->u32ReservedCmd;
     649        pHeader->size = cbActual;
     650    }
     651    else if (pCB->cbReservedCmdHeader == sizeof(uint32_t))
     652    {
     653        uint32_t *pHeader = (uint32_t *)((uint8_t *)pCB->commands.page.pvR0 + pCB->cbCommand);
     654        *pHeader = pCB->u32ReservedCmd;
     655    }
     656    else
     657        Assert(pCB->cbReservedCmdHeader == 0);
     658
     659    pCB->cbCommand += pCB->cbReservedCmdHeader + cbActual;
     660    pCB->cbReservedCmdHeader = 0;
     661    pCB->cbReservedCmd = 0;
     662    pCB->u32ReservedCmd = 0;
     663
     664    ExReleaseFastMutex(&pCBState->CBCurrentMutex);
     665}
     666
     667
     668/** Submit the current miniport command buffer to the host.
     669 * If the buffer contains no command data, then this function does nothing.
     670 *
     671 * @param pSvga            The device instance.
     672 */
     673void SvgaCmdBufFlush(PVBOXWDDM_EXT_VMSVGA pSvga)
     674{
     675    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     676
     677    ExAcquireFastMutex(&pCBState->CBCurrentMutex);
     678
     679    PVMSVGACB pCB = pCBState->pCBCurrent;
     680    if (pCB && pCB->cbCommand)
     681    {
     682        NTSTATUS Status = svgaCBSubmit(pSvga, pCB);
     683        Assert(NT_SUCCESS(Status)); RT_NOREF(Status);
     684
     685        pCBState->pCBCurrent = NULL;
     686    }
     687
     688    ExReleaseFastMutex(&pCBState->CBCurrentMutex);
     689}
     690
     691
     692/** Process command buffers processed by the host at DPC level.
     693 *
     694 * @param pSvga            The device instance.
     695 */
     696void SvgaCmdBufProcess(PVBOXWDDM_EXT_VMSVGA pSvga)
     697{
     698    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     699
     700    /* Look at submitted queue for buffers which has been completed by the host. */
     701    RTLISTANCHOR listCompleted;
     702    RTListInit(&listCompleted);
     703
     704    KIRQL OldIrql;
     705    KeAcquireSpinLock(&pCBState->SpinLock, &OldIrql);
     706    for (unsigned i = 0; i < RT_ELEMENTS(pCBState->aCBContexts); ++i)
     707    {
     708        PVMSVGACBCONTEXT pCBCtx = &pCBState->aCBContexts[i];
     709        PVMSVGACB pIter, pNext;
     710        RTListForEachSafe(&pCBCtx->QueueSubmitted, pIter, pNext, VMSVGACB, nodeQueue)
     711        {
     712            /* Buffers are processed sequentially, so if this one has not been processed,
     713             * then the consequent buffers are too.
     714             */
     715            if (pIter->pCBHeader->status == SVGA_CB_STATUS_NONE)
     716                break;
     717
     718            /* Remove the command buffer from the submitted queue and add to the local queue. */
     719            RTListNodeRemove(&pIter->nodeQueue);
     720            RTListAppend(&listCompleted, &pIter->nodeQueue);
     721            --pCBCtx->cSubmitted;
     722        }
     723    }
     724    KeReleaseSpinLock(&pCBState->SpinLock, OldIrql);
     725
     726    /* Process the completed buffers without the spinlock. */
     727    PVMSVGACB pIter, pNext;
     728    RTListForEachSafe(&listCompleted, pIter, pNext, VMSVGACB, nodeQueue)
     729    {
     730        switch (pIter->pCBHeader->status)
     731        {
     732            case SVGA_CB_STATUS_COMPLETED:
     733                /* Just delete the buffer. */
     734                RTListNodeRemove(&pIter->nodeQueue);
     735                svgaCBFree(pCBState, pIter);
     736                break;
     737
     738            case SVGA_CB_STATUS_NONE:
     739            case SVGA_CB_STATUS_QUEUE_FULL:
     740            case SVGA_CB_STATUS_COMMAND_ERROR:
     741            case SVGA_CB_STATUS_CB_HEADER_ERROR:
     742            case SVGA_CB_STATUS_PREEMPTED:
     743            case SVGA_CB_STATUS_SUBMISSION_ERROR:
     744            case SVGA_CB_STATUS_PARTIAL_COMPLETE:
     745            default:
     746                /** @todo Figure this out later. */
     747                AssertFailed();
     748
     749                /* Just delete the buffer. */
     750                RTListNodeRemove(&pIter->nodeQueue);
     751                svgaCBFree(pCBState, pIter);
     752                break;
     753        }
     754    }
     755}
     756
     757
     758NTSTATUS SvgaCmdBufDestroy(PVBOXWDDM_EXT_VMSVGA pSvga)
     759{
     760    /** @todo implement */
     761    PVMSVGACBSTATE pCBState = pSvga->pCBState;
     762    if (pCBState == NULL)
     763        return STATUS_SUCCESS;
     764    pSvga->pCBState = NULL;
     765
     766    GaMemFree(pCBState);
     767    return STATUS_SUCCESS;
     768}
     769
     770NTSTATUS SvgaCmdBufInit(PVBOXWDDM_EXT_VMSVGA pSvga)
     771{
     772    NTSTATUS Status;
     773
     774    PVMSVGACBSTATE pCBState = (PVMSVGACBSTATE)GaMemAllocZero(sizeof(VMSVGACBSTATE));
     775    AssertReturn(pCBState, STATUS_INSUFFICIENT_RESOURCES);
     776    pSvga->pCBState = pCBState;
     777
     778    for (unsigned i = 0; i < RT_ELEMENTS(pCBState->aCBContexts); ++i)
     779    {
     780        PVMSVGACBCONTEXT pCBCtx = &pCBState->aCBContexts[i];
     781        RTListInit(&pCBCtx->QueuePending);
     782        RTListInit(&pCBCtx->QueueSubmitted);
     783        RTListInit(&pCBCtx->QueuePreempted);
     784        //pCBCtx->cSubmitted = 0;
     785    }
     786
     787    Status = svgaCBHeaderPoolInit(&pCBState->HeaderPool);
     788    AssertReturn(NT_SUCCESS(Status), Status);
     789
     790    ExInitializeFastMutex(&pCBState->CBCurrentMutex);
     791    KeInitializeSpinLock(&pCBState->SpinLock);
     792    return STATUS_SUCCESS;
     793}
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.h

    r93115 r94622  
    2929void SvgaFifoCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual);
    3030
     31NTSTATUS SvgaCmdBufInit(PVBOXWDDM_EXT_VMSVGA pSvga);
     32NTSTATUS SvgaCmdBufDestroy(PVBOXWDDM_EXT_VMSVGA pSvga);
     33
     34NTSTATUS SvgaCmdBufDeviceCommand(PVBOXWDDM_EXT_VMSVGA pSvga, void const *pvCmd, uint32_t cbCmd);
     35
     36void *SvgaCmdBuf3dCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifo3dCmdId enmCmd, uint32_t cbReserve, uint32_t idDXContext);
     37void *SvgaCmdBufFifoCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifoCmdId enmCmd, uint32_t cbReserve);
     38void *SvgaCmdBufReserve(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbReserve, uint32_t idDXContext);
     39void  SvgaCmdBufCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual);
     40void  SvgaCmdBufFlush(PVBOXWDDM_EXT_VMSVGA pSvga);
     41void  SvgaCmdBufProcess(PVBOXWDDM_EXT_VMSVGA pSvga);
     42
    3143#endif /* !GA_INCLUDED_SRC_WINNT_Graphics_Video_mp_wddm_gallium_SvgaFifo_h */
  • trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/VBoxMPGaWddm.cpp

    r93115 r94622  
    14471447    }
    14481448
     1449    if (u32IrqStatus & (SVGA_IRQFLAG_COMMAND_BUFFER | SVGA_IRQFLAG_ERROR))
     1450        ASMAtomicWriteBool(&pSvga->fCommandBufferIrq, true);
     1451
    14491452    pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle);
    14501453
     
    15341537        }
    15351538    }
     1539
     1540    if (ASMAtomicCmpXchgBool(&pSvga->fCommandBufferIrq, false, true) && pSvga->pCBState)
     1541        SvgaCmdBufProcess(pSvga);
    15361542}
    15371543
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette