VirtualBox

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

Last change on this file since 62522 was 62522, checked in by vboxsync, 9 years ago

(C) 2016

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