VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/wddm/VBoxMPCm.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.6 KB
Line 
1/* $Id: VBoxMPCm.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox WDDM Miniport driver
4 */
5
6/*
7 * Copyright (C) 2011-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPWddm.h"
19
20typedef struct VBOXVIDEOCM_CMD_DR
21{
22 LIST_ENTRY QueueList;
23 PVBOXVIDEOCM_CTX pContext;
24 uint32_t cbMaxCmdSize;
25 volatile uint32_t cRefs;
26
27 VBOXVIDEOCM_CMD_HDR CmdHdr;
28} VBOXVIDEOCM_CMD_DR, *PVBOXVIDEOCM_CMD_DR;
29
30typedef enum
31{
32 VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE = 1,
33 VBOXVIDEOCM_CMD_CTL_KM_TYPE_PRE_INVOKE,
34 VBOXVIDEOCM_CMD_CTL_KM_TYPE_DUMMY_32BIT = 0x7fffffff
35} VBOXVIDEOCM_CMD_CTL_KM_TYPE;
36
37typedef DECLCALLBACK(VOID) FNVBOXVIDEOCM_CMD_CB(PVBOXVIDEOCM_CTX pContext, struct VBOXVIDEOCM_CMD_CTL_KM *pCmd, PVOID pvContext);
38typedef FNVBOXVIDEOCM_CMD_CB *PFNVBOXVIDEOCM_CMD_CB;
39
40typedef struct VBOXVIDEOCM_CMD_CTL_KM
41{
42 VBOXVIDEOCM_CMD_CTL_KM_TYPE enmType;
43 uint32_t u32Reserved;
44 PFNVBOXVIDEOCM_CMD_CB pfnCb;
45 PVOID pvCb;
46} VBOXVIDEOCM_CMD_CTL_KM, *PVBOXVIDEOCM_CMD_CTL_KM;
47
48AssertCompile(VBOXWDDM_ROUNDBOUND(RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr), 8) == RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr));
49
50#define VBOXVIDEOCM_HEADER_SIZE() (VBOXWDDM_ROUNDBOUND(sizeof (VBOXVIDEOCM_CMD_DR), 8))
51#define VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) (VBOXVIDEOCM_HEADER_SIZE() + (_s))
52//#define VBOXVIDEOCM_SIZE(_t) (VBOXVIDEOCM_SIZE_FROMBODYSIZE(sizeof (_t)))
53#define VBOXVIDEOCM_BODY(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + VBOXVIDEOCM_HEADER_SIZE()) )
54#define VBOXVIDEOCM_HEAD(_pCmd) ( (PVBOXVIDEOCM_CMD_DR)(((uint8_t*)(_pCmd)) - VBOXVIDEOCM_HEADER_SIZE()) )
55
56#define VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(_s) ( VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) - RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr))
57
58//#define VBOXVIDEOCM_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)( VBOXVIDEOCM_BODY(0, uint8_t) + RT_OFFSETOF(_t, _f) ) )
59
60typedef struct VBOXVIDEOCM_SESSION
61{
62 /* contexts in this session */
63 LIST_ENTRY QueueEntry;
64 /* contexts in this session */
65 LIST_ENTRY ContextList;
66 /* commands list */
67 LIST_ENTRY CommandsList;
68 /* post process commands list */
69 LIST_ENTRY PpCommandsList;
70 /* event used to notify UMD about pending commands */
71 PKEVENT pUmEvent;
72 /* sync lock */
73 KSPIN_LOCK SynchLock;
74 /* indicates whether event signaling is needed on cmd add */
75 bool bEventNeeded;
76} VBOXVIDEOCM_SESSION, *PVBOXVIDEOCM_SESSION;
77
78#define VBOXCMENTRY_2_CMD(_pE) ((PVBOXVIDEOCM_CMD_DR)((uint8_t*)(_pE) - RT_UOFFSETOF(VBOXVIDEOCM_CMD_DR, QueueList)))
79
80void* vboxVideoCmCmdReinitForContext(void *pvCmd, PVBOXVIDEOCM_CTX pContext)
81{
82 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
83 pHdr->pContext = pContext;
84 pHdr->CmdHdr.u64UmData = pContext->u64UmData;
85 return pvCmd;
86}
87
88void* vboxVideoCmCmdCreate(PVBOXVIDEOCM_CTX pContext, uint32_t cbSize)
89{
90 Assert(cbSize);
91 if (!cbSize)
92 return NULL;
93
94 Assert(VBOXWDDM_ROUNDBOUND(cbSize, 8) == cbSize);
95 cbSize = VBOXWDDM_ROUNDBOUND(cbSize, 8);
96
97 Assert(pContext->pSession);
98 if (!pContext->pSession)
99 return NULL;
100
101 uint32_t cbCmd = VBOXVIDEOCM_SIZE_FROMBODYSIZE(cbSize);
102 PVBOXVIDEOCM_CMD_DR pCmd = (PVBOXVIDEOCM_CMD_DR)vboxWddmMemAllocZero(cbCmd);
103 Assert(pCmd);
104 if (pCmd)
105 {
106 InitializeListHead(&pCmd->QueueList);
107 pCmd->pContext = pContext;
108 pCmd->cbMaxCmdSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
109 pCmd->cRefs = 1;
110 pCmd->CmdHdr.u64UmData = pContext->u64UmData;
111 pCmd->CmdHdr.cbCmd = pCmd->cbMaxCmdSize;
112 }
113 return VBOXVIDEOCM_BODY(pCmd, void);
114}
115
116static PVBOXVIDEOCM_CMD_CTL_KM vboxVideoCmCmdCreateKm(PVBOXVIDEOCM_CTX pContext, VBOXVIDEOCM_CMD_CTL_KM_TYPE enmType,
117 PFNVBOXVIDEOCM_CMD_CB pfnCb, PVOID pvCb,
118 uint32_t cbSize)
119{
120 PVBOXVIDEOCM_CMD_CTL_KM pCmd = (PVBOXVIDEOCM_CMD_CTL_KM)vboxVideoCmCmdCreate(pContext, cbSize + sizeof (*pCmd));
121 pCmd->enmType = enmType;
122 pCmd->pfnCb = pfnCb;
123 pCmd->pvCb = pvCb;
124 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd);
125 pHdr->CmdHdr.enmType = VBOXVIDEOCM_CMD_TYPE_CTL_KM;
126 return pCmd;
127}
128
129static DECLCALLBACK(VOID) vboxVideoCmCmdCbSetEventAndDereference(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd,
130 PVOID pvContext)
131{
132 RT_NOREF(pContext);
133 PKEVENT pEvent = (PKEVENT)pvContext;
134 KeSetEvent(pEvent, 0, FALSE);
135 ObDereferenceObject(pEvent);
136 vboxVideoCmCmdRelease(pCmd);
137}
138
139NTSTATUS vboxVideoCmCmdSubmitCompleteEvent(PVBOXVIDEOCM_CTX pContext, PKEVENT pEvent)
140{
141 Assert(pEvent);
142 PVBOXVIDEOCM_CMD_CTL_KM pCmd = vboxVideoCmCmdCreateKm(pContext, VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE,
143 vboxVideoCmCmdCbSetEventAndDereference, pEvent, 0);
144 if (!pCmd)
145 {
146 WARN(("vboxVideoCmCmdCreateKm failed"));
147 return STATUS_NO_MEMORY;
148 }
149
150 vboxVideoCmCmdSubmit(pCmd, VBOXVIDEOCM_SUBMITSIZE_DEFAULT);
151
152 return STATUS_SUCCESS;
153}
154
155DECLINLINE(void) vboxVideoCmCmdRetainByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
156{
157 ASMAtomicIncU32(&pHdr->cRefs);
158}
159
160DECLINLINE(void) vboxVideoCmCmdReleaseByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
161{
162 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
163 Assert(cRefs < UINT32_MAX/2);
164 if (!cRefs)
165 vboxWddmMemFree(pHdr);
166}
167
168static void vboxVideoCmCmdCancel(PVBOXVIDEOCM_CMD_DR pHdr)
169{
170 InitializeListHead(&pHdr->QueueList);
171 vboxVideoCmCmdReleaseByHdr(pHdr);
172}
173
174static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CMD_DR pHdr, uint32_t cbSize)
175{
176 bool bSignalEvent = false;
177 if (cbSize != VBOXVIDEOCM_SUBMITSIZE_DEFAULT)
178 {
179 cbSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
180 Assert(cbSize <= pHdr->cbMaxCmdSize);
181 pHdr->CmdHdr.cbCmd = cbSize;
182 }
183
184 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
185
186 KIRQL OldIrql;
187 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
188
189 InsertHeadList(&pSession->CommandsList, &pHdr->QueueList);
190 if (pSession->bEventNeeded)
191 {
192 pSession->bEventNeeded = false;
193 bSignalEvent = true;
194 }
195
196 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
197
198 if (bSignalEvent)
199 KeSetEvent(pSession->pUmEvent, 0, FALSE);
200}
201
202void vboxVideoCmCmdRetain(void *pvCmd)
203{
204 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
205 vboxVideoCmCmdRetainByHdr(pHdr);
206}
207
208void vboxVideoCmCmdRelease(void *pvCmd)
209{
210 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
211 vboxVideoCmCmdReleaseByHdr(pHdr);
212}
213
214/**
215 * @param pvCmd memory buffer returned by vboxVideoCmCmdCreate
216 * @param cbSize should be <= cbSize posted to vboxVideoCmCmdCreate on command creation
217 */
218void vboxVideoCmCmdSubmit(void *pvCmd, uint32_t cbSize)
219{
220 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
221 vboxVideoCmCmdPostByHdr(pHdr->pContext->pSession, pHdr, cbSize);
222}
223
224NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, PFNVBOXVIDEOCMCMDVISITOR pfnVisitor,
225 PVOID pvVisitor)
226{
227 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
228 PLIST_ENTRY pCurEntry = NULL;
229 PVBOXVIDEOCM_CMD_DR pHdr;
230
231 KIRQL OldIrql;
232 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
233
234 pCurEntry = pSession->CommandsList.Blink;
235 do
236 {
237 if (pCurEntry != &pSession->CommandsList)
238 {
239 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
240 pCurEntry = pHdr->QueueList.Blink;
241 if (bEntireSession || pHdr->pContext == pContext)
242 {
243 if (pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM)
244 {
245 void * pvBody = VBOXVIDEOCM_BODY(pHdr, void);
246 UINT fRet = pfnVisitor(pHdr->pContext, pvBody, pHdr->CmdHdr.cbCmd, pvVisitor);
247 if (fRet & VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD)
248 {
249 RemoveEntryList(&pHdr->QueueList);
250 }
251 if ((fRet & VBOXVIDEOCMCMDVISITOR_RETURN_BREAK))
252 break;
253 }
254 else
255 {
256 WARN(("non-um cmd on visit, skipping"));
257 }
258 }
259 }
260 else
261 {
262 break;
263 }
264 } while (1);
265
266
267 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
268
269 return STATUS_SUCCESS;
270}
271
272void vboxVideoCmCtxInitEmpty(PVBOXVIDEOCM_CTX pContext)
273{
274 InitializeListHead(&pContext->SessionEntry);
275 pContext->pSession = NULL;
276 pContext->u64UmData = 0ULL;
277}
278
279static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
280{
281 InsertHeadList(&pSession->ContextList, &pContext->SessionEntry);
282 pContext->pSession = pSession;
283}
284
285void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
286{
287 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
288 KIRQL OldIrql;
289 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
290
291 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
292
293 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
294}
295
296void vboxVideoCmSessionSignalEvent(PVBOXVIDEOCM_SESSION pSession)
297{
298 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
299 if (pSession->pUmEvent)
300 KeSetEvent(pSession->pUmEvent, 0, FALSE);
301}
302
303static void vboxVideoCmSessionDestroyLocked(PVBOXVIDEOCM_SESSION pSession)
304{
305 /* signal event so that user-space client can figure out the context is destroyed
306 * in case the context destroyal is caused by Graphics device reset or miniport driver update */
307 KeSetEvent(pSession->pUmEvent, 0, FALSE);
308 ObDereferenceObject(pSession->pUmEvent);
309 Assert(IsListEmpty(&pSession->ContextList));
310 Assert(IsListEmpty(&pSession->CommandsList));
311 Assert(IsListEmpty(&pSession->PpCommandsList));
312 RemoveEntryList(&pSession->QueueEntry);
313 vboxWddmMemFree(pSession);
314}
315
316static void vboxVideoCmSessionCtxPpList(PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pHead)
317{
318 LIST_ENTRY *pCur;
319 for (pCur = pHead->Flink; pCur != pHead; pCur = pHead->Flink)
320 {
321 RemoveEntryList(pCur);
322 PVBOXVIDEOCM_CMD_DR pHdr = VBOXCMENTRY_2_CMD(pCur);
323 PVBOXVIDEOCM_CMD_CTL_KM pCmd = VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM);
324 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
325 }
326}
327
328static void vboxVideoCmSessionCtxDetachCmdsLocked(PLIST_ENTRY pEntriesHead, PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pDstHead)
329{
330 LIST_ENTRY *pCur;
331 LIST_ENTRY *pPrev;
332 pCur = pEntriesHead->Flink;
333 pPrev = pEntriesHead;
334 while (pCur != pEntriesHead)
335 {
336 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
337 if (pCmd->pContext == pContext)
338 {
339 RemoveEntryList(pCur);
340 InsertTailList(pDstHead, pCur);
341 pCur = pPrev;
342 /* pPrev - remains unchanged */
343 }
344 else
345 {
346 pPrev = pCur;
347 }
348 pCur = pCur->Flink;
349 }
350}
351/**
352 * @return true iff the given session is destroyed
353 */
354bool vboxVideoCmSessionCtxRemoveLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
355{
356 bool bDestroy;
357 LIST_ENTRY RemainedList;
358 LIST_ENTRY RemainedPpList;
359 LIST_ENTRY *pCur;
360 InitializeListHead(&RemainedList);
361 InitializeListHead(&RemainedPpList);
362 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
363 KIRQL OldIrql;
364 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
365
366 pContext->pSession = NULL;
367 RemoveEntryList(&pContext->SessionEntry);
368 bDestroy = !!(IsListEmpty(&pSession->ContextList));
369 /* ensure there are no commands left for the given context */
370 if (bDestroy)
371 {
372 vboxVideoLeDetach(&pSession->CommandsList, &RemainedList);
373 vboxVideoLeDetach(&pSession->PpCommandsList, &RemainedPpList);
374 }
375 else
376 {
377 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->CommandsList, pContext, &RemainedList);
378 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &RemainedPpList);
379 }
380
381 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
382
383 for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink)
384 {
385 RemoveEntryList(pCur);
386 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
387 vboxVideoCmCmdCancel(pCmd);
388 }
389
390 vboxVideoCmSessionCtxPpList(pContext, &RemainedPpList);
391
392 if (bDestroy)
393 {
394 vboxVideoCmSessionDestroyLocked(pSession);
395 }
396
397 return bDestroy;
398}
399
400/* the session gets destroyed once the last context is removed from it */
401NTSTATUS vboxVideoCmSessionCreateLocked(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESSION *ppSession, PKEVENT pUmEvent,
402 PVBOXVIDEOCM_CTX pContext)
403{
404 NTSTATUS Status = STATUS_UNSUCCESSFUL;
405 PVBOXVIDEOCM_SESSION pSession = (PVBOXVIDEOCM_SESSION)vboxWddmMemAllocZero(sizeof (VBOXVIDEOCM_SESSION));
406 Assert(pSession);
407 if (pSession)
408 {
409 InitializeListHead(&pSession->ContextList);
410 InitializeListHead(&pSession->CommandsList);
411 InitializeListHead(&pSession->PpCommandsList);
412 pSession->pUmEvent = pUmEvent;
413 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
414 KeInitializeSpinLock(&pSession->SynchLock);
415 pSession->bEventNeeded = true;
416 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
417 InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry);
418 *ppSession = pSession;
419 return STATUS_SUCCESS;
420// vboxWddmMemFree(pSession);
421 }
422 else
423 {
424 Status = STATUS_NO_MEMORY;
425 }
426 return Status;
427}
428
429#define VBOXCMENTRY_2_SESSION(_pE) ((PVBOXVIDEOCM_SESSION)((uint8_t*)(_pE) - RT_UOFFSETOF(VBOXVIDEOCM_SESSION, QueueEntry)))
430
431NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HANDLE hUmEvent, uint64_t u64UmData)
432{
433 PKEVENT pUmEvent = NULL;
434 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
435 NTSTATUS Status = ObReferenceObjectByHandle(hUmEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
436 (PVOID*)&pUmEvent,
437 NULL);
438 AssertNtStatusSuccess(Status);
439 if (Status == STATUS_SUCCESS)
440 {
441 KIRQL OldIrql;
442 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
443
444 bool bFound = false;
445 PVBOXVIDEOCM_SESSION pSession = NULL;
446 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
447 {
448 pSession = VBOXCMENTRY_2_SESSION(pEntry);
449 if (pSession->pUmEvent == pUmEvent)
450 {
451 bFound = true;
452 break;
453 }
454 }
455
456 pContext->u64UmData = u64UmData;
457
458 if (!bFound)
459 {
460 Status = vboxVideoCmSessionCreateLocked(pMgr, &pSession, pUmEvent, pContext);
461 AssertNtStatusSuccess(Status);
462 }
463 else
464 {
465 /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext);
466 /*AssertNtStatusSuccess(Status);*/
467 }
468
469 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
470
471 if (Status == STATUS_SUCCESS)
472 {
473 return STATUS_SUCCESS;
474 }
475
476 ObDereferenceObject(pUmEvent);
477 }
478 return Status;
479}
480
481NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext)
482{
483 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
484 if (!pSession)
485 return STATUS_SUCCESS;
486
487 KIRQL OldIrql;
488 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
489
490 vboxVideoCmSessionCtxRemoveLocked(pSession, pContext);
491
492 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
493
494 return STATUS_SUCCESS;
495}
496
497NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr)
498{
499 KeInitializeSpinLock(&pMgr->SynchLock);
500 InitializeListHead(&pMgr->SessionList);
501 return STATUS_SUCCESS;
502}
503
504NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr)
505{
506 RT_NOREF(pMgr);
507 Assert(IsListEmpty(&pMgr->SessionList));
508 return STATUS_SUCCESS;
509}
510
511NTSTATUS vboxVideoCmSignalEvents(PVBOXVIDEOCM_MGR pMgr)
512{
513 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
514 PVBOXVIDEOCM_SESSION pSession = NULL;
515
516 KIRQL OldIrql;
517 KeAcquireSpinLock(&pMgr->SynchLock, &OldIrql);
518
519 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
520 {
521 pSession = VBOXCMENTRY_2_SESSION(pEntry);
522 vboxVideoCmSessionSignalEvent(pSession);
523 }
524
525 KeReleaseSpinLock(&pMgr->SynchLock, OldIrql);
526
527 return STATUS_SUCCESS;
528}
529
530VOID vboxVideoCmProcessKm(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd)
531{
532 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
533
534 switch (pCmd->enmType)
535 {
536 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_PRE_INVOKE:
537 {
538 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
539 break;
540 }
541
542 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE:
543 {
544 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd);
545 KIRQL OldIrql;
546 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
547 InsertTailList(&pSession->PpCommandsList, &pHdr->QueueList);
548 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
549 break;
550 }
551
552 default:
553 {
554 WARN(("unsupported cmd type %d", pCmd->enmType));
555 break;
556 }
557 }
558}
559
560NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd)
561{
562 Assert(cbCmd >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD));
563 if (cbCmd < sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD))
564 return STATUS_BUFFER_TOO_SMALL;
565
566 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
567 PVBOXVIDEOCM_CMD_DR pHdr;
568 LIST_ENTRY DetachedList;
569 LIST_ENTRY DetachedPpList;
570 PLIST_ENTRY pCurEntry = NULL;
571 uint32_t cbRemainingCmds = 0;
572 uint32_t cbRemainingFirstCmd = 0;
573 uint32_t cbData = cbCmd - sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
574 uint8_t * pvData = ((uint8_t *)pCmd) + sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
575 bool bDetachMode = true;
576 InitializeListHead(&DetachedList);
577 InitializeListHead(&DetachedPpList);
578// PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd
579
580 Assert(KeGetCurrentIrql() <= DISPATCH_LEVEL);
581 KIRQL OldIrql;
582 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
583
584 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &DetachedPpList);
585
586 do
587 {
588 if (bDetachMode)
589 {
590 if (!IsListEmpty(&pSession->CommandsList))
591 {
592 Assert(!pCurEntry);
593 pHdr = VBOXCMENTRY_2_CMD(pSession->CommandsList.Blink);
594 Assert(pHdr->CmdHdr.cbCmd);
595 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
596 if (cbData >= cbUserCmd)
597 {
598 RemoveEntryList(&pHdr->QueueList);
599 InsertHeadList(&DetachedList, &pHdr->QueueList);
600 cbData -= cbUserCmd;
601 }
602 else
603 {
604 Assert(cbUserCmd);
605 cbRemainingFirstCmd = cbUserCmd;
606 cbRemainingCmds = cbUserCmd;
607 pCurEntry = pHdr->QueueList.Blink;
608 bDetachMode = false;
609 }
610 }
611 else
612 {
613 pSession->bEventNeeded = true;
614 break;
615 }
616 }
617 else
618 {
619 Assert(pCurEntry);
620 if (pCurEntry != &pSession->CommandsList)
621 {
622 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
623 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
624 Assert(cbRemainingFirstCmd);
625 cbRemainingCmds += cbUserCmd;
626 pCurEntry = pHdr->QueueList.Blink;
627 }
628 else
629 {
630 Assert(cbRemainingFirstCmd);
631 Assert(cbRemainingCmds);
632 break;
633 }
634 }
635 } while (1);
636
637 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
638
639 vboxVideoCmSessionCtxPpList(pContext, &DetachedPpList);
640
641 pCmd->Hdr.cbCmdsReturned = 0;
642 for (pCurEntry = DetachedList.Blink; pCurEntry != &DetachedList; pCurEntry = DetachedList.Blink)
643 {
644 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
645 RemoveEntryList(pCurEntry);
646 switch (pHdr->CmdHdr.enmType)
647 {
648 case VBOXVIDEOCM_CMD_TYPE_UM:
649 {
650 memcpy(pvData, &pHdr->CmdHdr, pHdr->CmdHdr.cbCmd);
651 pvData += pHdr->CmdHdr.cbCmd;
652 pCmd->Hdr.cbCmdsReturned += pHdr->CmdHdr.cbCmd;
653 vboxVideoCmCmdReleaseByHdr(pHdr);
654 break;
655 }
656
657 case VBOXVIDEOCM_CMD_TYPE_CTL_KM:
658 {
659 vboxVideoCmProcessKm(pContext, VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM));
660 break;
661 }
662
663 default:
664 {
665 WARN(("unsupported cmd type %d", pHdr->CmdHdr.enmType));
666 break;
667 }
668 }
669 }
670
671 pCmd->Hdr.cbRemainingCmds = cbRemainingCmds;
672 pCmd->Hdr.cbRemainingFirstCmd = cbRemainingFirstCmd;
673 pCmd->Hdr.u32Reserved = 0;
674
675 return STATUS_SUCCESS;
676}
677
678static BOOLEAN vboxVideoCmHasUncompletedCmdsLocked(PVBOXVIDEOCM_MGR pMgr)
679{
680 PVBOXVIDEOCM_SESSION pSession = NULL;
681 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
682 {
683 pSession = VBOXCMENTRY_2_SESSION(pEntry);
684 KIRQL OldIrql;
685 KeAcquireSpinLock(&pSession->SynchLock, &OldIrql);
686
687 if (pSession->bEventNeeded)
688 {
689 /* commands still being processed */
690 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
691 return TRUE;
692 }
693 KeReleaseSpinLock(&pSession->SynchLock, OldIrql);
694 }
695 return FALSE;
696}
Note: See TracBrowser for help on using the repository browser.

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