VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/wddm/VBoxVideoCm.cpp@ 32325

Last change on this file since 32325 was 30925, checked in by vboxsync, 14 years ago

wddm/3d: 1)visible regions fix. 2)export d3d extension function properly

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/*
2 * Copyright (C) 2010 Oracle Corporation
3 *
4 * This file is part of VirtualBox Open Source Edition (OSE), as
5 * available from http://www.virtualbox.org. This file is free software;
6 * you can redistribute it and/or modify it under the terms of the GNU
7 * General Public License (GPL) as published by the Free Software
8 * Foundation, in version 2 as it comes in the "COPYING" file of the
9 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
10 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
11 */
12#include "../VBoxVideo.h"
13#include "../Helper.h"
14
15#include <iprt/asm.h>
16
17typedef struct VBOXVIDEOCM_CMD_DR
18{
19 LIST_ENTRY QueueList;
20 PVBOXVIDEOCM_CTX pContext;
21 uint32_t cbMaxCmdSize;
22 volatile uint32_t cRefs;
23
24 VBOXVIDEOCM_CMD_HDR CmdHdr;
25} VBOXVIDEOCM_CMD_DR, *PVBOXVIDEOCM_CMD_DR;
26
27AssertCompile(VBOXWDDM_ROUNDBOUND(RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr), 8) == RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr));
28
29#define VBOXVIDEOCM_HEADER_SIZE() (VBOXWDDM_ROUNDBOUND(sizeof (VBOXVIDEOCM_CMD_DR), 8))
30#define VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) (VBOXVIDEOCM_HEADER_SIZE() + (_s))
31//#define VBOXVIDEOCM_SIZE(_t) (VBOXVIDEOCM_SIZE_FROMBODYSIZE(sizeof (_t)))
32#define VBOXVIDEOCM_BODY(_pCmd, _t) ( (_t*)(((uint8_t*)(_pCmd)) + VBOXVIDEOCM_HEADER_SIZE()) )
33#define VBOXVIDEOCM_HEAD(_pCmd) ( (PVBOXVIDEOCM_CMD_DR)(((uint8_t*)(_pCmd)) - VBOXVIDEOCM_HEADER_SIZE()) )
34
35#define VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(_s) ( VBOXVIDEOCM_SIZE_FROMBODYSIZE(_s) - RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, CmdHdr))
36
37//#define VBOXVIDEOCM_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)( VBOXVIDEOCM_BODY(0, uint8_t) + RT_OFFSETOF(_t, _f) ) )
38
39typedef struct VBOXVIDEOCM_SESSION
40{
41 /* contexts in this session */
42 LIST_ENTRY QueueEntry;
43 /* contexts in this session */
44 LIST_ENTRY ContextList;
45 /* commands list */
46 LIST_ENTRY CommandsList;
47 /* event used to notify UMD about penging commands */
48 PKEVENT pUmEvent;
49 /* synch lock */
50 FAST_MUTEX Mutex;
51 /* indicates whether event signaling is needed on cmd add */
52 bool bEventNeeded;
53} VBOXVIDEOCM_SESSION, *PVBOXVIDEOCM_SESSION;
54
55#define VBOXCMENTRY_2_CMD(_pE) ((PVBOXVIDEOCM_CMD_DR)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXVIDEOCM_CMD_DR, QueueList)))
56
57void* vboxVideoCmCmdReinitForContext(void *pvCmd, PVBOXVIDEOCM_CTX pContext)
58{
59 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
60 pHdr->pContext = pContext;
61 pHdr->CmdHdr.u64UmData = pContext->u64UmData;
62 return pvCmd;
63}
64
65void* vboxVideoCmCmdCreate(PVBOXVIDEOCM_CTX pContext, uint32_t cbSize)
66{
67 Assert(cbSize);
68 if (!cbSize)
69 return NULL;
70
71 Assert(VBOXWDDM_ROUNDBOUND(cbSize, 8) == cbSize);
72 cbSize = VBOXWDDM_ROUNDBOUND(cbSize, 8);
73
74 Assert(pContext->pSession);
75 if (!pContext->pSession)
76 return NULL;
77
78 uint32_t cbCmd = VBOXVIDEOCM_SIZE_FROMBODYSIZE(cbSize);
79 PVBOXVIDEOCM_CMD_DR pCmd = (PVBOXVIDEOCM_CMD_DR)vboxWddmMemAllocZero(cbCmd);
80 Assert(pCmd);
81 if (pCmd)
82 {
83 InitializeListHead(&pCmd->QueueList);
84 pCmd->pContext = pContext;
85 pCmd->cbMaxCmdSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
86 pCmd->cRefs = 1;
87 pCmd->CmdHdr.u64UmData = pContext->u64UmData;
88 pCmd->CmdHdr.cbCmd = pCmd->cbMaxCmdSize;
89 }
90 return VBOXVIDEOCM_BODY(pCmd, void);
91}
92
93DECLINLINE(void) vboxVideoCmCmdRetainByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
94{
95 ASMAtomicIncU32(&pHdr->cRefs);
96}
97
98DECLINLINE(void) vboxVideoCmCmdReleaseByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
99{
100 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
101 Assert(cRefs < UINT32_MAX/2);
102 if (!cRefs)
103 vboxWddmMemFree(pHdr);
104}
105
106static void vboxVideoCmCmdCancel(PVBOXVIDEOCM_CMD_DR pHdr)
107{
108 InitializeListHead(&pHdr->QueueList);
109 vboxVideoCmCmdReleaseByHdr(pHdr);
110}
111
112static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CMD_DR pHdr, uint32_t cbSize)
113{
114 bool bSignalEvent = false;
115 if (cbSize != VBOXVIDEOCM_SUBMITSIZE_DEFAULT)
116 {
117 cbSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
118 Assert(cbSize <= pHdr->cbMaxCmdSize);
119 pHdr->CmdHdr.cbCmd = cbSize;
120 }
121
122 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
123 ExAcquireFastMutex(&pSession->Mutex);
124
125 InsertHeadList(&pSession->CommandsList, &pHdr->QueueList);
126 if (pSession->bEventNeeded)
127 {
128 pSession->bEventNeeded = false;
129 bSignalEvent = true;
130 }
131
132 ExReleaseFastMutex(&pSession->Mutex);
133
134 if (bSignalEvent)
135 KeSetEvent(pSession->pUmEvent, 0, FALSE);
136}
137
138void vboxVideoCmCmdRetain(void *pvCmd)
139{
140 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
141 vboxVideoCmCmdRetainByHdr(pHdr);
142}
143
144void vboxVideoCmCmdRelease(void *pvCmd)
145{
146 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
147 vboxVideoCmCmdReleaseByHdr(pHdr);
148}
149
150/**
151 * @param pvCmd memory byffer returned by vboxVideoCmCmdCreate
152 * @param cbSize should be <= cbSize posted to vboxVideoCmCmdCreate on command creation
153 */
154void vboxVideoCmCmdSubmit(void *pvCmd, uint32_t cbSize)
155{
156 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
157 vboxVideoCmCmdPostByHdr(pHdr->pContext->pSession, pHdr, cbSize);
158}
159
160void vboxVideoCmCtxInitEmpty(PVBOXVIDEOCM_CTX pContext)
161{
162 InitializeListHead(&pContext->SessionEntry);
163 pContext->pSession = NULL;
164 pContext->u64UmData = 0ULL;
165}
166
167static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
168{
169 InsertHeadList(&pSession->ContextList, &pContext->SessionEntry);
170 pContext->pSession = pSession;
171}
172
173void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
174{
175 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
176 ExAcquireFastMutex(&pSession->Mutex);
177 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
178 ExReleaseFastMutex(&pSession->Mutex);
179
180}
181
182static void vboxVideoCmSessionDestroy(PVBOXVIDEOCM_SESSION pSession)
183{
184 ObDereferenceObject(pSession->pUmEvent);
185 Assert(IsListEmpty(&pSession->ContextList));
186 Assert(IsListEmpty(&pSession->CommandsList));
187 RemoveEntryList(&pSession->QueueEntry);
188 vboxWddmMemFree(pSession);
189}
190
191/**
192 * @return true iff the given session is destroyed
193 */
194bool vboxVideoCmSessionCtxRemove(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
195{
196 bool bDestroy;
197 LIST_ENTRY RemainedList;
198 LIST_ENTRY *pCur;
199 LIST_ENTRY *pPrev;
200 InitializeListHead(&RemainedList);
201 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
202 ExAcquireFastMutex(&pSession->Mutex);
203 pContext->pSession = NULL;
204 RemoveEntryList(&pContext->SessionEntry);
205 bDestroy = !!(IsListEmpty(&pSession->ContextList));
206 /* ensure there are no commands left for the given context */
207 if (bDestroy)
208 {
209 vboxVideoLeDetach(&pSession->CommandsList, &RemainedList);
210 }
211 else
212 {
213 pCur = pSession->CommandsList.Flink;
214 pPrev = &pSession->CommandsList;
215 while (pCur != &pSession->CommandsList)
216 {
217 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
218 if (pCmd->pContext == pContext)
219 {
220 RemoveEntryList(pCur);
221 InsertHeadList(&RemainedList, pCur);
222 pCur = pPrev;
223 /* pPrev - remains unchanged */
224 }
225 else
226 {
227 pPrev = pCur;
228 }
229 pCur = pCur->Flink;
230 }
231 }
232 ExReleaseFastMutex(&pSession->Mutex);
233
234 for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink)
235 {
236 RemoveEntryList(pCur);
237 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
238 vboxVideoCmCmdCancel(pCmd);
239 }
240
241 if (bDestroy)
242 {
243 vboxVideoCmSessionDestroy(pSession);
244 }
245
246 return bDestroy;
247}
248
249/* the session gets destroyed once the last context is removed from it */
250NTSTATUS vboxVideoCmSessionCreate(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESSION *ppSession, PKEVENT pUmEvent, PVBOXVIDEOCM_CTX pContext)
251{
252 PVBOXVIDEOCM_SESSION pSession = (PVBOXVIDEOCM_SESSION)vboxWddmMemAllocZero(sizeof (VBOXVIDEOCM_SESSION));
253 Assert(pSession);
254 if (pSession)
255 {
256 InitializeListHead(&pSession->ContextList);
257 InitializeListHead(&pSession->CommandsList);
258 pSession->pUmEvent = pUmEvent;
259 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
260 ExInitializeFastMutex(&pSession->Mutex);
261 pSession->bEventNeeded = true;
262 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
263 InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry);
264 *ppSession = pSession;
265 return STATUS_SUCCESS;
266 }
267 return STATUS_NO_MEMORY;
268}
269
270#define VBOXCMENTRY_2_SESSION(_pE) ((PVBOXVIDEOCM_SESSION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXVIDEOCM_SESSION, QueueEntry)))
271
272NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HANDLE hUmEvent, uint64_t u64UmData)
273{
274 PKEVENT pUmEvent = NULL;
275 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
276 NTSTATUS Status = ObReferenceObjectByHandle(hUmEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
277 (PVOID*)&pUmEvent,
278 NULL);
279 Assert(Status == STATUS_SUCCESS);
280 if (Status == STATUS_SUCCESS)
281 {
282 Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
283 FALSE, /* BOOLEAN Alertable */
284 NULL /* PLARGE_INTEGER Timeout */
285 );
286 Assert(Status == STATUS_SUCCESS);
287 if (Status == STATUS_SUCCESS)
288 {
289 bool bFound = false;
290 PVBOXVIDEOCM_SESSION pSession = NULL;
291 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
292 {
293 pSession = VBOXCMENTRY_2_SESSION(pEntry);
294 if (pSession->pUmEvent == pUmEvent)
295 {
296 bFound = true;
297 break;
298 }
299 }
300
301 pContext->u64UmData = u64UmData;
302
303 if (!bFound)
304 {
305 Status = vboxVideoCmSessionCreate(pMgr, &pSession, pUmEvent, pContext);
306 Assert(Status == STATUS_SUCCESS);
307 }
308 else
309 {
310 /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext);
311 /*Assert(Status == STATUS_SUCCESS);*/
312 }
313 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
314 Assert(!tstL);
315
316 if (Status == STATUS_SUCCESS)
317 {
318 return STATUS_SUCCESS;
319 }
320 }
321
322 ObDereferenceObject(pUmEvent);
323 }
324 return Status;
325}
326
327NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext)
328{
329 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
330 if (!pSession)
331 return STATUS_SUCCESS;
332
333 NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
334 FALSE, /* BOOLEAN Alertable */
335 NULL /* PLARGE_INTEGER Timeout */
336 );
337 Assert(Status == STATUS_SUCCESS);
338 if (Status == STATUS_SUCCESS)
339 {
340 vboxVideoCmSessionCtxRemove(pSession, pContext);
341 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
342 Assert(!tstL);
343 }
344
345 return Status;
346}
347
348NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr)
349{
350 KeInitializeEvent(&pMgr->SynchEvent, SynchronizationEvent, TRUE);
351 InitializeListHead(&pMgr->SessionList);
352 return STATUS_SUCCESS;
353}
354
355NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr)
356{
357 Assert(IsListEmpty(&pMgr->SessionList));
358 return STATUS_SUCCESS;
359}
360
361NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd)
362{
363 Assert(cbCmd >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD));
364 if (cbCmd < sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD))
365 return STATUS_BUFFER_TOO_SMALL;
366
367 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
368 PVBOXVIDEOCM_CMD_DR pHdr;
369 LIST_ENTRY DetachedList;
370 PLIST_ENTRY pCurEntry = NULL;
371 uint32_t cbCmdsReturned = 0;
372 uint32_t cbRemainingCmds = 0;
373 uint32_t cbRemainingFirstCmd = 0;
374 uint32_t cbData = cbCmd - sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
375 uint8_t * pvData = ((uint8_t *)pCmd) + sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
376 bool bDetachMode = true;
377 InitializeListHead(&DetachedList);
378// PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd
379
380 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
381 ExAcquireFastMutex(&pSession->Mutex);
382
383 do
384 {
385 if (bDetachMode)
386 {
387 if (!IsListEmpty(&pSession->CommandsList))
388 {
389 Assert(!pCurEntry);
390 pHdr = VBOXCMENTRY_2_CMD(pSession->CommandsList.Blink);
391 Assert(pHdr->CmdHdr.cbCmd);
392 if (cbData >= pHdr->CmdHdr.cbCmd)
393 {
394 RemoveEntryList(&pHdr->QueueList);
395 InsertHeadList(&DetachedList, &pHdr->QueueList);
396 cbData -= pHdr->CmdHdr.cbCmd;
397 }
398 else
399 {
400 cbRemainingFirstCmd = pHdr->CmdHdr.cbCmd;
401 cbRemainingCmds = pHdr->CmdHdr.cbCmd;
402 pCurEntry = pHdr->QueueList.Blink;
403 bDetachMode = false;
404 }
405 }
406 else
407 {
408 pSession->bEventNeeded = true;
409 break;
410 }
411 }
412 else
413 {
414 Assert(pCurEntry);
415 if (pCurEntry != &pSession->CommandsList)
416 {
417 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
418 Assert(cbRemainingFirstCmd);
419 cbRemainingCmds += pHdr->CmdHdr.cbCmd;
420 pCurEntry = pHdr->QueueList.Blink;
421 }
422 else
423 {
424 pSession->bEventNeeded = false;
425 break;
426 }
427 }
428 } while (1);
429
430 ExReleaseFastMutex(&pSession->Mutex);
431
432 pCmd->Hdr.cbCmdsReturned = 0;
433 for (pCurEntry = DetachedList.Blink; pCurEntry != &DetachedList; pCurEntry = DetachedList.Blink)
434 {
435 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
436 memcpy(pvData, &pHdr->CmdHdr, pHdr->CmdHdr.cbCmd);
437 pvData += pHdr->CmdHdr.cbCmd;
438 pCmd->Hdr.cbCmdsReturned += pHdr->CmdHdr.cbCmd;
439 RemoveEntryList(pCurEntry);
440 vboxVideoCmCmdReleaseByHdr(pHdr);
441 }
442
443 pCmd->Hdr.cbRemainingCmds = cbRemainingCmds;
444 pCmd->Hdr.cbRemainingFirstCmd = cbRemainingFirstCmd;
445 pCmd->Hdr.u32Reserved = 0;
446
447 return STATUS_SUCCESS;
448}
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