VirtualBox

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

Last change on this file since 42091 was 38112, checked in by vboxsync, 13 years ago

wddm/3d: 1. fix invalid visible rectreporting on swapchain destruction 2. single context for wine (disabled so far), 3 wine & 3d driver bugfixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: VBoxMPCm.cpp 38112 2011-07-22 13:26:19Z vboxsync $ */
2
3/** @file
4 * VBox WDDM Miniport driver
5 */
6
7/*
8 * Copyright (C) 2011 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 FAST_MUTEX Mutex;
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 ExAcquireFastMutex(&pSession->Mutex);
185
186 InsertHeadList(&pSession->CommandsList, &pHdr->QueueList);
187 if (pSession->bEventNeeded)
188 {
189 pSession->bEventNeeded = false;
190 bSignalEvent = true;
191 }
192
193 ExReleaseFastMutex(&pSession->Mutex);
194
195 if (bSignalEvent)
196 KeSetEvent(pSession->pUmEvent, 0, FALSE);
197}
198
199void vboxVideoCmCmdRetain(void *pvCmd)
200{
201 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
202 vboxVideoCmCmdRetainByHdr(pHdr);
203}
204
205void vboxVideoCmCmdRelease(void *pvCmd)
206{
207 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
208 vboxVideoCmCmdReleaseByHdr(pHdr);
209}
210
211/**
212 * @param pvCmd memory buffer returned by vboxVideoCmCmdCreate
213 * @param cbSize should be <= cbSize posted to vboxVideoCmCmdCreate on command creation
214 */
215void vboxVideoCmCmdSubmit(void *pvCmd, uint32_t cbSize)
216{
217 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
218 vboxVideoCmCmdPostByHdr(pHdr->pContext->pSession, pHdr, cbSize);
219}
220
221NTSTATUS vboxVideoCmCmdVisit(PVBOXVIDEOCM_CTX pContext, BOOLEAN bEntireSession, PFNVBOXVIDEOCMCMDVISITOR pfnVisitor, PVOID pvVisitor)
222{
223 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
224 PLIST_ENTRY pCurEntry = NULL;
225 PVBOXVIDEOCM_CMD_DR pHdr;
226
227 ExAcquireFastMutex(&pSession->Mutex);
228
229 pCurEntry = pSession->CommandsList.Blink;
230 do
231 {
232 if (pCurEntry != &pSession->CommandsList)
233 {
234 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
235 pCurEntry = pHdr->QueueList.Blink;
236 if (bEntireSession || pHdr->pContext == pContext)
237 {
238 if (pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM)
239 {
240 void * pvBody = VBOXVIDEOCM_BODY(pHdr, void);
241 UINT fRet = pfnVisitor(pHdr->pContext, pvBody, pHdr->CmdHdr.cbCmd, pvVisitor);
242 if (fRet & VBOXVIDEOCMCMDVISITOR_RETURN_RMCMD)
243 {
244 RemoveEntryList(&pHdr->QueueList);
245 }
246 if ((fRet & VBOXVIDEOCMCMDVISITOR_RETURN_BREAK))
247 break;
248 }
249 else
250 {
251 WARN(("non-um cmd on visit, skipping"));
252 }
253 }
254 }
255 else
256 {
257 break;
258 }
259 } while (1);
260
261
262 ExReleaseFastMutex(&pSession->Mutex);
263
264 return STATUS_SUCCESS;
265}
266
267void vboxVideoCmCtxInitEmpty(PVBOXVIDEOCM_CTX pContext)
268{
269 InitializeListHead(&pContext->SessionEntry);
270 pContext->pSession = NULL;
271 pContext->u64UmData = 0ULL;
272}
273
274static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
275{
276 InsertHeadList(&pSession->ContextList, &pContext->SessionEntry);
277 pContext->pSession = pSession;
278}
279
280void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
281{
282 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
283 ExAcquireFastMutex(&pSession->Mutex);
284 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
285 ExReleaseFastMutex(&pSession->Mutex);
286
287}
288
289static void vboxVideoCmSessionDestroyLocked(PVBOXVIDEOCM_SESSION pSession)
290{
291 /* signal event so that user-space client can figure out the context is destroyed
292 * in case the context destroyal is caused by Graphics device reset or miniport driver update */
293 KeSetEvent(pSession->pUmEvent, 0, FALSE);
294 ObDereferenceObject(pSession->pUmEvent);
295 Assert(IsListEmpty(&pSession->ContextList));
296 Assert(IsListEmpty(&pSession->CommandsList));
297 Assert(IsListEmpty(&pSession->PpCommandsList));
298 RemoveEntryList(&pSession->QueueEntry);
299 vboxWddmMemFree(pSession);
300}
301
302static void vboxVideoCmSessionCtxPpList(PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pHead)
303{
304 LIST_ENTRY *pCur;
305 for (pCur = pHead->Flink; pCur != pHead; pCur = pHead->Flink)
306 {
307 RemoveEntryList(pCur);
308 PVBOXVIDEOCM_CMD_DR pHdr = VBOXCMENTRY_2_CMD(pCur);
309 PVBOXVIDEOCM_CMD_CTL_KM pCmd = VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM);
310 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
311 }
312}
313
314static void vboxVideoCmSessionCtxDetachCmdsLocked(PLIST_ENTRY pEntriesHead, PVBOXVIDEOCM_CTX pContext, PLIST_ENTRY pDstHead)
315{
316 LIST_ENTRY *pCur;
317 LIST_ENTRY *pPrev;
318 pCur = pEntriesHead->Flink;
319 pPrev = pEntriesHead;
320 while (pCur != pEntriesHead)
321 {
322 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
323 if (pCmd->pContext == pContext)
324 {
325 RemoveEntryList(pCur);
326 InsertTailList(pDstHead, pCur);
327 pCur = pPrev;
328 /* pPrev - remains unchanged */
329 }
330 else
331 {
332 pPrev = pCur;
333 }
334 pCur = pCur->Flink;
335 }
336}
337/**
338 * @return true iff the given session is destroyed
339 */
340bool vboxVideoCmSessionCtxRemoveLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
341{
342 bool bDestroy;
343 LIST_ENTRY RemainedList;
344 LIST_ENTRY RemainedPpList;
345 LIST_ENTRY *pCur;
346 InitializeListHead(&RemainedList);
347 InitializeListHead(&RemainedPpList);
348 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
349 ExAcquireFastMutex(&pSession->Mutex);
350 pContext->pSession = NULL;
351 RemoveEntryList(&pContext->SessionEntry);
352 bDestroy = !!(IsListEmpty(&pSession->ContextList));
353 /* ensure there are no commands left for the given context */
354 if (bDestroy)
355 {
356 vboxVideoLeDetach(&pSession->CommandsList, &RemainedList);
357 vboxVideoLeDetach(&pSession->PpCommandsList, &RemainedPpList);
358 }
359 else
360 {
361 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->CommandsList, pContext, &RemainedList);
362 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &RemainedPpList);
363 }
364 ExReleaseFastMutex(&pSession->Mutex);
365
366 for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink)
367 {
368 RemoveEntryList(pCur);
369 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
370 vboxVideoCmCmdCancel(pCmd);
371 }
372
373 vboxVideoCmSessionCtxPpList(pContext, &RemainedPpList);
374
375 if (bDestroy)
376 {
377 vboxVideoCmSessionDestroyLocked(pSession);
378 }
379
380 return bDestroy;
381}
382
383/* the session gets destroyed once the last context is removed from it */
384NTSTATUS vboxVideoCmSessionCreateLocked(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESSION *ppSession, PKEVENT pUmEvent, PVBOXVIDEOCM_CTX pContext)
385{
386 NTSTATUS Status = STATUS_UNSUCCESSFUL;
387 PVBOXVIDEOCM_SESSION pSession = (PVBOXVIDEOCM_SESSION)vboxWddmMemAllocZero(sizeof (VBOXVIDEOCM_SESSION));
388 Assert(pSession);
389 if (pSession)
390 {
391 InitializeListHead(&pSession->ContextList);
392 InitializeListHead(&pSession->CommandsList);
393 InitializeListHead(&pSession->PpCommandsList);
394 pSession->pUmEvent = pUmEvent;
395 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
396 ExInitializeFastMutex(&pSession->Mutex);
397 pSession->bEventNeeded = true;
398 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
399 InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry);
400 *ppSession = pSession;
401 return STATUS_SUCCESS;
402// vboxWddmMemFree(pSession);
403 }
404 else
405 {
406 Status = STATUS_NO_MEMORY;
407 }
408 return Status;
409}
410
411#define VBOXCMENTRY_2_SESSION(_pE) ((PVBOXVIDEOCM_SESSION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXVIDEOCM_SESSION, QueueEntry)))
412
413NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HANDLE hUmEvent, uint64_t u64UmData)
414{
415 PKEVENT pUmEvent = NULL;
416 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
417 NTSTATUS Status = ObReferenceObjectByHandle(hUmEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
418 (PVOID*)&pUmEvent,
419 NULL);
420 Assert(Status == STATUS_SUCCESS);
421 if (Status == STATUS_SUCCESS)
422 {
423 Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
424 FALSE, /* BOOLEAN Alertable */
425 NULL /* PLARGE_INTEGER Timeout */
426 );
427 Assert(Status == STATUS_SUCCESS);
428 if (Status == STATUS_SUCCESS)
429 {
430 bool bFound = false;
431 PVBOXVIDEOCM_SESSION pSession = NULL;
432 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
433 {
434 pSession = VBOXCMENTRY_2_SESSION(pEntry);
435 if (pSession->pUmEvent == pUmEvent)
436 {
437 bFound = true;
438 break;
439 }
440 }
441
442 pContext->u64UmData = u64UmData;
443
444 if (!bFound)
445 {
446 Status = vboxVideoCmSessionCreateLocked(pMgr, &pSession, pUmEvent, pContext);
447 Assert(Status == STATUS_SUCCESS);
448 }
449 else
450 {
451 /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext);
452 /*Assert(Status == STATUS_SUCCESS);*/
453 }
454 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
455 Assert(!tstL);
456
457 if (Status == STATUS_SUCCESS)
458 {
459 return STATUS_SUCCESS;
460 }
461 }
462
463 ObDereferenceObject(pUmEvent);
464 }
465 return Status;
466}
467
468NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext)
469{
470 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
471 if (!pSession)
472 return STATUS_SUCCESS;
473
474 NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
475 FALSE, /* BOOLEAN Alertable */
476 NULL /* PLARGE_INTEGER Timeout */
477 );
478 Assert(Status == STATUS_SUCCESS);
479 if (Status == STATUS_SUCCESS)
480 {
481 vboxVideoCmSessionCtxRemoveLocked(pSession, pContext);
482 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
483 Assert(!tstL);
484 }
485
486 return Status;
487}
488
489NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr)
490{
491 KeInitializeEvent(&pMgr->SynchEvent, SynchronizationEvent, TRUE);
492 InitializeListHead(&pMgr->SessionList);
493 return STATUS_SUCCESS;
494}
495
496NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr)
497{
498 Assert(IsListEmpty(&pMgr->SessionList));
499 return STATUS_SUCCESS;
500}
501
502VOID vboxVideoCmProcessKm(PVBOXVIDEOCM_CTX pContext, PVBOXVIDEOCM_CMD_CTL_KM pCmd)
503{
504 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
505
506 switch (pCmd->enmType)
507 {
508 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_PRE_INVOKE:
509 {
510 pCmd->pfnCb(pContext, pCmd, pCmd->pvCb);
511 break;
512 }
513
514 case VBOXVIDEOCM_CMD_CTL_KM_TYPE_POST_INVOKE:
515 {
516 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pCmd);
517 ExAcquireFastMutex(&pSession->Mutex);
518 InsertTailList(&pSession->PpCommandsList, &pHdr->QueueList);
519 ExReleaseFastMutex(&pSession->Mutex);
520 break;
521 }
522
523 default:
524 {
525 WARN(("unsupported cmd type %d", pCmd->enmType));
526 break;
527 }
528 }
529}
530
531NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd)
532{
533 Assert(cbCmd >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD));
534 if (cbCmd < sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD))
535 return STATUS_BUFFER_TOO_SMALL;
536
537 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
538 PVBOXVIDEOCM_CMD_DR pHdr;
539 LIST_ENTRY DetachedList;
540 LIST_ENTRY DetachedPpList;
541 PLIST_ENTRY pCurEntry = NULL;
542 uint32_t cbCmdsReturned = 0;
543 uint32_t cbRemainingCmds = 0;
544 uint32_t cbRemainingFirstCmd = 0;
545 uint32_t cbData = cbCmd - sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
546 uint8_t * pvData = ((uint8_t *)pCmd) + sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
547 bool bDetachMode = true;
548 InitializeListHead(&DetachedList);
549 InitializeListHead(&DetachedPpList);
550// PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd
551
552 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
553 ExAcquireFastMutex(&pSession->Mutex);
554
555 vboxVideoCmSessionCtxDetachCmdsLocked(&pSession->PpCommandsList, pContext, &DetachedPpList);
556
557 do
558 {
559 if (bDetachMode)
560 {
561 if (!IsListEmpty(&pSession->CommandsList))
562 {
563 Assert(!pCurEntry);
564 pHdr = VBOXCMENTRY_2_CMD(pSession->CommandsList.Blink);
565 Assert(pHdr->CmdHdr.cbCmd);
566 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
567 if (cbData >= cbUserCmd)
568 {
569 RemoveEntryList(&pHdr->QueueList);
570 InsertHeadList(&DetachedList, &pHdr->QueueList);
571 cbData -= cbUserCmd;
572 }
573 else
574 {
575 Assert(cbUserCmd);
576 cbRemainingFirstCmd = cbUserCmd;
577 cbRemainingCmds = cbUserCmd;
578 pCurEntry = pHdr->QueueList.Blink;
579 bDetachMode = false;
580 }
581 }
582 else
583 {
584 pSession->bEventNeeded = true;
585 break;
586 }
587 }
588 else
589 {
590 Assert(pCurEntry);
591 if (pCurEntry != &pSession->CommandsList)
592 {
593 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
594 uint32_t cbUserCmd = pHdr->CmdHdr.enmType == VBOXVIDEOCM_CMD_TYPE_UM ? pHdr->CmdHdr.cbCmd : 0;
595 Assert(cbRemainingFirstCmd);
596 cbRemainingCmds += cbUserCmd;
597 pCurEntry = pHdr->QueueList.Blink;
598 }
599 else
600 {
601 Assert(cbRemainingFirstCmd);
602 Assert(cbRemainingCmds);
603 break;
604 }
605 }
606 } while (1);
607
608 ExReleaseFastMutex(&pSession->Mutex);
609
610 vboxVideoCmSessionCtxPpList(pContext, &DetachedPpList);
611
612 pCmd->Hdr.cbCmdsReturned = 0;
613 for (pCurEntry = DetachedList.Blink; pCurEntry != &DetachedList; pCurEntry = DetachedList.Blink)
614 {
615 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
616 RemoveEntryList(pCurEntry);
617 switch (pHdr->CmdHdr.enmType)
618 {
619 case VBOXVIDEOCM_CMD_TYPE_UM:
620 {
621 memcpy(pvData, &pHdr->CmdHdr, pHdr->CmdHdr.cbCmd);
622 pvData += pHdr->CmdHdr.cbCmd;
623 pCmd->Hdr.cbCmdsReturned += pHdr->CmdHdr.cbCmd;
624 vboxVideoCmCmdReleaseByHdr(pHdr);
625 break;
626 }
627
628 case VBOXVIDEOCM_CMD_TYPE_CTL_KM:
629 {
630 vboxVideoCmProcessKm(pContext, VBOXVIDEOCM_BODY(pHdr, VBOXVIDEOCM_CMD_CTL_KM));
631 break;
632 }
633
634 default:
635 {
636 WARN(("unsupported cmd type %d", pHdr->CmdHdr.enmType));
637 break;
638 }
639 }
640 }
641
642 pCmd->Hdr.cbRemainingCmds = cbRemainingCmds;
643 pCmd->Hdr.cbRemainingFirstCmd = cbRemainingFirstCmd;
644 pCmd->Hdr.u32Reserved = 0;
645
646 return STATUS_SUCCESS;
647}
648
649VOID vboxVideoCmLock(PVBOXVIDEOCM_CTX pContext)
650{
651 ExAcquireFastMutex(&pContext->pSession->Mutex);
652}
653
654VOID vboxVideoCmUnlock(PVBOXVIDEOCM_CTX pContext)
655{
656 ExReleaseFastMutex(&pContext->pSession->Mutex);
657}
658
659static BOOLEAN vboxVideoCmHasUncompletedCmdsLocked(PVBOXVIDEOCM_MGR pMgr)
660{
661 PVBOXVIDEOCM_SESSION pSession = NULL;
662 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
663 {
664 pSession = VBOXCMENTRY_2_SESSION(pEntry);
665 ExAcquireFastMutex(&pSession->Mutex);
666 if (pSession->bEventNeeded)
667 {
668 /* commands still being processed */
669 ExReleaseFastMutex(&pSession->Mutex);
670 return TRUE;
671 }
672 ExReleaseFastMutex(&pSession->Mutex);
673 }
674 return FALSE;
675}
676
677/* waits for all outstanding commands to completed by client
678 * assumptions here are:
679 * 1. no new commands are submitted while we are waiting
680 * 2. it is assumed that a client completes all previously received commands
681 * once it queries for the new set of commands */
682NTSTATUS vboxVideoCmWaitCompletedCmds(PVBOXVIDEOCM_MGR pMgr, uint32_t msTimeout)
683{
684 LARGE_INTEGER Timeout;
685 PLARGE_INTEGER pTimeout;
686 uint32_t cIters;
687
688 if (msTimeout != RT_INDEFINITE_WAIT)
689 {
690 uint32_t msIter = 2;
691 cIters = msTimeout/msIter;
692 if (!cIters)
693 {
694 msIter = msTimeout;
695 cIters = 1;
696 }
697 Timeout.QuadPart = -(int64_t) msIter /* ms */ * 10000;
698 pTimeout = &Timeout;
699 }
700 else
701 {
702 pTimeout = NULL;
703 cIters = 1;
704 }
705
706 Assert(cIters);
707 do
708 {
709 NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
710 FALSE, /* BOOLEAN Alertable */
711 pTimeout /* PLARGE_INTEGER Timeout */
712 );
713 if (Status == STATUS_TIMEOUT)
714 {
715 --cIters;
716 }
717 else
718 {
719 if (!NT_SUCCESS(Status))
720 {
721 WARN(("KeWaitForSingleObject failed with Status (0x%x)", Status));
722 return Status;
723 }
724
725 /* succeeded */
726 if (!vboxVideoCmHasUncompletedCmdsLocked(pMgr))
727 {
728 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
729 Assert(!tstL);
730 return STATUS_SUCCESS;
731 }
732
733 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
734 Assert(!tstL);
735 }
736
737 if (!cIters)
738 break;
739
740 KeDelayExecutionThread(KernelMode, FALSE, pTimeout);
741 --cIters;
742 if (!cIters)
743 break;
744 } while (0);
745
746 return STATUS_TIMEOUT;
747}
748
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