- Timestamp:
- Apr 16, 2022 2:32:45 PM (3 years ago)
- 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 27 27 #include <iprt/memobj.h> 28 28 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 else97 {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 135 29 /** @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++) 30 static 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++) 172 37 { 173 38 RTHCPHYS paOT = RTR0MemObjGetPagePhysAddr(pSvga->hMemObjOTables, idOTable); 174 39 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 58 static 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 194 72 195 73 static NTSTATUS svgaHwInit(VBOXWDDM_EXT_VMSVGA *pSvga) … … 229 107 230 108 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); 237 110 238 111 if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS) 239 112 { 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; 245 139 } 246 140 … … 269 163 } 270 164 165 /** @todo svgaHwStop(VBOXWDDM_EXT_VMSVGA *pSvga) to undo svgaHwInit */ 271 166 if (pSvga->u32Caps & SVGA_CAP_COMMAND_BUFFERS) 272 167 { 273 SvgaObjectTablesInit(pSvga, false);274 SvgaCmdBuf CtxInit(pSvga, false);168 /// @todo SvgaObjectTablesDestroy(pSvga); 169 SvgaCmdBufDestroy(pSvga); 275 170 } 276 171 … … 1224 1119 } 1225 1120 1121 void *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 1128 void 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 1138 void SvgaFlush(PVBOXWDDM_EXT_VMSVGA pSvga) 1139 { 1140 if (pSvga->pCBState) 1141 SvgaCmdBufFlush(pSvga); 1142 } 1143 1226 1144 NTSTATUS SvgaBlitGMRFBToScreen(PVBOXWDDM_EXT_VMSVGA pSvga, 1227 1145 uint32_t idDstScreen, … … 1232 1150 NTSTATUS Status = STATUS_SUCCESS; 1233 1151 uint32_t cbSubmit = 0; 1234 uint32_t idx = UINT32_MAX;1235 1152 void *pvCmd = NULL; 1236 1153 … … 1238 1155 NULL, 0, &cbSubmit); 1239 1156 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); 1258 1158 if (pvCmd) 1259 1159 { … … 1262 1162 Assert(Status == STATUS_SUCCESS); 1263 1163 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); 1272 1166 } 1273 1167 else -
trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/Svga.h
r93834 r94622 59 59 } VMSVGAFIFO; 60 60 typedef VMSVGAFIFO *PVMSVGAFIFO; 61 62 /* 63 * Command buffers. 64 */ 65 typedef struct VMSVGACBPAGE 66 { 67 RTR0MEMOBJ hMemObj; 68 RTR0PTR pvR0; 69 RTHCPHYS PhysAddr; 70 } VMSVGACBPAGE, *PVMSVGACBPAGE; 71 72 typedef int32_t VMSVGACBHEADERHANDLE; 73 #define VMSVGACBHEADER_NIL (-1) 74 75 typedef 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. */ 84 typedef 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 111 typedef 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 118 typedef 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 127 typedef 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; 61 135 62 136 /* VMSVGA specific part of Gallium device extension. */ … … 94 168 /** Fifo state. */ 95 169 VMSVGAFIFO fifo; 170 171 /** Command buffers state. */ 172 PVMSVGACBSTATE pCBState; 173 bool volatile fCommandBufferIrq; 96 174 97 175 /** For atomic hardware access. */ -
trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/gallium/SvgaFifo.cpp
r93115 r94622 22 22 23 23 #include <iprt/alloc.h> 24 #include <iprt/errcore.h> 25 #include <iprt/memobj.h> 26 #include <iprt/string.h> 24 27 #include <iprt/thread.h> 28 #include <iprt/x86.h> 25 29 26 30 NTSTATUS SvgaFifoInit(PVBOXWDDM_EXT_VMSVGA pSvga) … … 238 242 ExReleaseFastMutex(&pFifo->FifoMutex); 239 243 } 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 289 static 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 301 static 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 313 static 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 322 static 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 341 static 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 355 static 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 384 static 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 */ 402 static 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 440 static 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 453 static 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 512 NTSTATUS 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 */ 545 static 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 */ 596 void *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 */ 610 void *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 */ 623 void *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 */ 634 void 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 */ 673 void 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 */ 696 void 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 758 NTSTATUS 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 770 NTSTATUS 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 29 29 void SvgaFifoCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual); 30 30 31 NTSTATUS SvgaCmdBufInit(PVBOXWDDM_EXT_VMSVGA pSvga); 32 NTSTATUS SvgaCmdBufDestroy(PVBOXWDDM_EXT_VMSVGA pSvga); 33 34 NTSTATUS SvgaCmdBufDeviceCommand(PVBOXWDDM_EXT_VMSVGA pSvga, void const *pvCmd, uint32_t cbCmd); 35 36 void *SvgaCmdBuf3dCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifo3dCmdId enmCmd, uint32_t cbReserve, uint32_t idDXContext); 37 void *SvgaCmdBufFifoCmdReserve(PVBOXWDDM_EXT_VMSVGA pSvga, SVGAFifoCmdId enmCmd, uint32_t cbReserve); 38 void *SvgaCmdBufReserve(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbReserve, uint32_t idDXContext); 39 void SvgaCmdBufCommit(PVBOXWDDM_EXT_VMSVGA pSvga, uint32_t cbActual); 40 void SvgaCmdBufFlush(PVBOXWDDM_EXT_VMSVGA pSvga); 41 void SvgaCmdBufProcess(PVBOXWDDM_EXT_VMSVGA pSvga); 42 31 43 #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 1447 1447 } 1448 1448 1449 if (u32IrqStatus & (SVGA_IRQFLAG_COMMAND_BUFFER | SVGA_IRQFLAG_ERROR)) 1450 ASMAtomicWriteBool(&pSvga->fCommandBufferIrq, true); 1451 1449 1452 pDevExt->u.primary.DxgkInterface.DxgkCbQueueDpc(pDevExt->u.primary.DxgkInterface.DeviceHandle); 1450 1453 … … 1534 1537 } 1535 1538 } 1539 1540 if (ASMAtomicCmpXchgBool(&pSvga->fCommandBufferIrq, false, true) && pSvga->pCBState) 1541 SvgaCmdBufProcess(pSvga); 1536 1542 } 1537 1543
Note:
See TracChangeset
for help on using the changeset viewer.