VirtualBox

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

Last change on this file since 30508 was 30505, checked in by vboxsync, 14 years ago

wddm/3d: visible regions working (more debug still needed)

  • 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 return pvCmd;
62}
63
64void* vboxVideoCmCmdCreate(PVBOXVIDEOCM_CTX pContext, uint32_t cbSize)
65{
66 Assert(cbSize);
67 if (!cbSize)
68 return NULL;
69
70 Assert(VBOXWDDM_ROUNDBOUND(cbSize, 8) == cbSize);
71 cbSize = VBOXWDDM_ROUNDBOUND(cbSize, 8);
72
73 Assert(pContext->pSession);
74 if (!pContext->pSession)
75 return NULL;
76
77 uint32_t cbCmd = VBOXVIDEOCM_SIZE_FROMBODYSIZE(cbSize);
78 PVBOXVIDEOCM_CMD_DR pCmd = (PVBOXVIDEOCM_CMD_DR)vboxWddmMemAllocZero(cbCmd);
79 Assert(pCmd);
80 if (pCmd)
81 {
82 InitializeListHead(&pCmd->QueueList);
83 pCmd->pContext = pContext;
84 pCmd->cbMaxCmdSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
85 pCmd->cRefs = 1;
86 pCmd->CmdHdr.u64UmData = pContext->u64UmData;
87 pCmd->CmdHdr.cbCmd = pCmd->cbMaxCmdSize;
88 }
89 return VBOXVIDEOCM_BODY(pCmd, void);
90}
91
92DECLINLINE(void) vboxVideoCmCmdRetainByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
93{
94 ASMAtomicIncU32(&pHdr->cRefs);
95}
96
97DECLINLINE(void) vboxVideoCmCmdReleaseByHdr(PVBOXVIDEOCM_CMD_DR pHdr)
98{
99 uint32_t cRefs = ASMAtomicDecU32(&pHdr->cRefs);
100 Assert(cRefs < UINT32_MAX/2);
101 if (!cRefs)
102 vboxWddmMemFree(pHdr);
103}
104
105static void vboxVideoCmCmdCancel(PVBOXVIDEOCM_CMD_DR pHdr)
106{
107 InitializeListHead(&pHdr->QueueList);
108 vboxVideoCmCmdReleaseByHdr(pHdr);
109}
110
111static void vboxVideoCmCmdPostByHdr(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CMD_DR pHdr, uint32_t cbSize)
112{
113 bool bSignalEvent = false;
114 if (cbSize != VBOXVIDEOCM_SUBMITSIZE_DEFAULT)
115 {
116 cbSize = VBOXVIDEOCM_SENDSIZE_FROMBODYSIZE(cbSize);
117 Assert(cbSize <= pHdr->cbMaxCmdSize);
118 pHdr->CmdHdr.cbCmd = cbSize;
119 }
120
121 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
122 ExAcquireFastMutex(&pSession->Mutex);
123
124 InsertHeadList(&pSession->CommandsList, &pHdr->QueueList);
125 if (pSession->bEventNeeded)
126 {
127 pSession->bEventNeeded = false;
128 bSignalEvent = true;
129 }
130
131 ExReleaseFastMutex(&pSession->Mutex);
132
133 if (bSignalEvent)
134 KeSetEvent(pSession->pUmEvent, 0, FALSE);
135}
136
137void vboxVideoCmCmdRetain(void *pvCmd)
138{
139 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
140 vboxVideoCmCmdRetainByHdr(pHdr);
141}
142
143void vboxVideoCmCmdRelease(void *pvCmd)
144{
145 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
146 vboxVideoCmCmdReleaseByHdr(pHdr);
147}
148
149/**
150 * @param pvCmd memory byffer returned by vboxVideoCmCmdCreate
151 * @param cbSize should be <= cbSize posted to vboxVideoCmCmdCreate on command creation
152 */
153void vboxVideoCmCmdSubmit(void *pvCmd, uint32_t cbSize)
154{
155 PVBOXVIDEOCM_CMD_DR pHdr = VBOXVIDEOCM_HEAD(pvCmd);
156 vboxVideoCmCmdPostByHdr(pHdr->pContext->pSession, pHdr, cbSize);
157}
158
159void vboxVideoCmCtxInitEmpty(PVBOXVIDEOCM_CTX pContext)
160{
161 InitializeListHead(&pContext->SessionEntry);
162 pContext->pSession = NULL;
163 pContext->u64UmData = 0ULL;
164}
165
166static void vboxVideoCmSessionCtxAddLocked(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
167{
168 InsertHeadList(&pSession->ContextList, &pContext->SessionEntry);
169 pContext->pSession = pSession;
170}
171
172void vboxVideoCmSessionCtxAdd(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
173{
174 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
175 ExAcquireFastMutex(&pSession->Mutex);
176 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
177 ExReleaseFastMutex(&pSession->Mutex);
178
179}
180
181static void vboxVideoCmSessionDestroy(PVBOXVIDEOCM_SESSION pSession)
182{
183 ObDereferenceObject(pSession->pUmEvent);
184 Assert(IsListEmpty(&pSession->ContextList));
185 Assert(IsListEmpty(&pSession->CommandsList));
186 RemoveEntryList(&pSession->QueueEntry);
187 vboxWddmMemFree(pSession);
188}
189
190/**
191 * @return true iff the given session is destroyed
192 */
193bool vboxVideoCmSessionCtxRemove(PVBOXVIDEOCM_SESSION pSession, PVBOXVIDEOCM_CTX pContext)
194{
195 bool bDestroy;
196 LIST_ENTRY RemainedList;
197 LIST_ENTRY *pCur;
198 LIST_ENTRY *pPrev;
199 InitializeListHead(&RemainedList);
200 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
201 ExAcquireFastMutex(&pSession->Mutex);
202 pContext->pSession = NULL;
203 RemoveEntryList(&pContext->SessionEntry);
204 bDestroy = !!(IsListEmpty(&pSession->ContextList));
205 /* ensure there are no commands left for the given context */
206 if (bDestroy)
207 {
208 vboxVideoLeDetach(&pSession->CommandsList, &RemainedList);
209 }
210 else
211 {
212 pCur = pSession->CommandsList.Flink;
213 pPrev = &pSession->CommandsList;
214 while (pCur != &pSession->CommandsList)
215 {
216 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
217 if (pCmd->pContext == pContext)
218 {
219 RemoveEntryList(pCur);
220 InsertHeadList(&RemainedList, pCur);
221 pCur = pPrev;
222 /* pPrev - remains unchanged */
223 }
224 else
225 {
226 pPrev = pCur;
227 }
228 pCur = pCur->Flink;
229 }
230 }
231 ExReleaseFastMutex(&pSession->Mutex);
232
233 for (pCur = RemainedList.Flink; pCur != &RemainedList; pCur = RemainedList.Flink)
234 {
235 RemoveEntryList(pCur);
236 PVBOXVIDEOCM_CMD_DR pCmd = VBOXCMENTRY_2_CMD(pCur);
237 vboxVideoCmCmdCancel(pCmd);
238 }
239
240 if (bDestroy)
241 {
242 vboxVideoCmSessionDestroy(pSession);
243 }
244
245 return bDestroy;
246}
247
248/* the session gets destroyed once the last context is removed from it */
249NTSTATUS vboxVideoCmSessionCreate(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_SESSION *ppSession, PKEVENT pUmEvent, PVBOXVIDEOCM_CTX pContext)
250{
251 PVBOXVIDEOCM_SESSION pSession = (PVBOXVIDEOCM_SESSION)vboxWddmMemAllocZero(sizeof (VBOXVIDEOCM_SESSION));
252 Assert(pSession);
253 if (pSession)
254 {
255 InitializeListHead(&pSession->ContextList);
256 InitializeListHead(&pSession->CommandsList);
257 pSession->pUmEvent = pUmEvent;
258 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
259 ExInitializeFastMutex(&pSession->Mutex);
260 pSession->bEventNeeded = true;
261 vboxVideoCmSessionCtxAddLocked(pSession, pContext);
262 InsertHeadList(&pMgr->SessionList, &pSession->QueueEntry);
263 *ppSession = pSession;
264 return STATUS_SUCCESS;
265 }
266 return STATUS_NO_MEMORY;
267}
268
269#define VBOXCMENTRY_2_SESSION(_pE) ((PVBOXVIDEOCM_SESSION)((uint8_t*)(_pE) - RT_OFFSETOF(VBOXVIDEOCM_SESSION, QueueEntry)))
270
271NTSTATUS vboxVideoCmCtxAdd(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext, HANDLE hUmEvent, uint64_t u64UmData)
272{
273 PKEVENT pUmEvent = NULL;
274 Assert(KeGetCurrentIrql() == PASSIVE_LEVEL);
275 NTSTATUS Status = ObReferenceObjectByHandle(hUmEvent, EVENT_MODIFY_STATE, *ExEventObjectType, UserMode,
276 (PVOID*)&pUmEvent,
277 NULL);
278 Assert(Status == STATUS_SUCCESS);
279 if (Status == STATUS_SUCCESS)
280 {
281 Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
282 FALSE, /* BOOLEAN Alertable */
283 NULL /* PLARGE_INTEGER Timeout */
284 );
285 Assert(Status == STATUS_SUCCESS);
286 if (Status == STATUS_SUCCESS)
287 {
288 bool bFound = false;
289 PVBOXVIDEOCM_SESSION pSession = NULL;
290 for (PLIST_ENTRY pEntry = pMgr->SessionList.Flink; pEntry != &pMgr->SessionList; pEntry = pEntry->Flink)
291 {
292 pSession = VBOXCMENTRY_2_SESSION(pEntry);
293 if (pSession->pUmEvent == pUmEvent)
294 {
295 bFound = true;
296 break;
297 }
298 }
299
300 pContext->u64UmData = u64UmData;
301
302 if (!bFound)
303 {
304 Status = vboxVideoCmSessionCreate(pMgr, &pSession, pUmEvent, pContext);
305 Assert(Status == STATUS_SUCCESS);
306 }
307 else
308 {
309 /* Status = */vboxVideoCmSessionCtxAdd(pSession, pContext);
310 /*Assert(Status == STATUS_SUCCESS);*/
311 }
312 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
313 Assert(!tstL);
314
315 if (Status == STATUS_SUCCESS)
316 {
317 return STATUS_SUCCESS;
318 }
319 }
320
321 ObDereferenceObject(pUmEvent);
322 }
323 return Status;
324}
325
326NTSTATUS vboxVideoCmCtxRemove(PVBOXVIDEOCM_MGR pMgr, PVBOXVIDEOCM_CTX pContext)
327{
328 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
329 if (!pSession)
330 return STATUS_SUCCESS;
331
332 NTSTATUS Status = KeWaitForSingleObject(&pMgr->SynchEvent, Executive, KernelMode,
333 FALSE, /* BOOLEAN Alertable */
334 NULL /* PLARGE_INTEGER Timeout */
335 );
336 Assert(Status == STATUS_SUCCESS);
337 if (Status == STATUS_SUCCESS)
338 {
339 vboxVideoCmSessionCtxRemove(pSession, pContext);
340 LONG tstL = KeSetEvent(&pMgr->SynchEvent, 0, FALSE);
341 Assert(!tstL);
342 }
343
344 return Status;
345}
346
347NTSTATUS vboxVideoCmInit(PVBOXVIDEOCM_MGR pMgr)
348{
349 KeInitializeEvent(&pMgr->SynchEvent, SynchronizationEvent, TRUE);
350 InitializeListHead(&pMgr->SessionList);
351 return STATUS_SUCCESS;
352}
353
354NTSTATUS vboxVideoCmTerm(PVBOXVIDEOCM_MGR pMgr)
355{
356 Assert(IsListEmpty(&pMgr->SessionList));
357 return STATUS_SUCCESS;
358}
359
360NTSTATUS vboxVideoCmEscape(PVBOXVIDEOCM_CTX pContext, PVBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD pCmd, uint32_t cbCmd)
361{
362 Assert(cbCmd >= sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD));
363 if (cbCmd < sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD))
364 return STATUS_BUFFER_TOO_SMALL;
365
366 PVBOXVIDEOCM_SESSION pSession = pContext->pSession;
367 PVBOXVIDEOCM_CMD_DR pHdr;
368 LIST_ENTRY DetachedList;
369 PLIST_ENTRY pCurEntry = NULL;
370 uint32_t cbCmdsReturned = 0;
371 uint32_t cbRemainingCmds = 0;
372 uint32_t cbRemainingFirstCmd = 0;
373 uint32_t cbData = cbCmd - sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
374 uint8_t * pvData = ((uint8_t *)pCmd) + sizeof (VBOXDISPIFESCAPE_GETVBOXVIDEOCMCMD);
375 bool bDetachMode = true;
376 InitializeListHead(&DetachedList);
377// PVBOXWDDM_GETVBOXVIDEOCMCMD_HDR *pvCmd
378
379 Assert(KeGetCurrentIrql() < DISPATCH_LEVEL);
380 ExAcquireFastMutex(&pSession->Mutex);
381
382 do
383 {
384 if (bDetachMode)
385 {
386 if (!IsListEmpty(&pSession->CommandsList))
387 {
388 Assert(!pCurEntry);
389 pHdr = VBOXCMENTRY_2_CMD(pSession->CommandsList.Blink);
390 Assert(pHdr->CmdHdr.cbCmd);
391 if (cbData >= pHdr->CmdHdr.cbCmd)
392 {
393 RemoveEntryList(&pHdr->QueueList);
394 InsertHeadList(&DetachedList, &pHdr->QueueList);
395 cbData -= pHdr->CmdHdr.cbCmd;
396 }
397 else
398 {
399 cbRemainingFirstCmd = pHdr->CmdHdr.cbCmd;
400 cbRemainingCmds = pHdr->CmdHdr.cbCmd;
401 pCurEntry = pHdr->QueueList.Blink;
402 bDetachMode = false;
403 }
404 }
405 else
406 {
407 pSession->bEventNeeded = true;
408 break;
409 }
410 }
411 else
412 {
413 Assert(pCurEntry);
414 if (pCurEntry != &pSession->CommandsList)
415 {
416 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
417 Assert(cbRemainingFirstCmd);
418 cbRemainingCmds += pHdr->CmdHdr.cbCmd;
419 pCurEntry = pHdr->QueueList.Blink;
420 }
421 else
422 {
423 pSession->bEventNeeded = false;
424 break;
425 }
426 }
427 } while (1);
428
429 ExReleaseFastMutex(&pSession->Mutex);
430
431 pCmd->Hdr.cbCmdsReturned = 0;
432 for (pCurEntry = DetachedList.Blink; pCurEntry != &DetachedList; pCurEntry = DetachedList.Blink)
433 {
434 pHdr = VBOXCMENTRY_2_CMD(pCurEntry);
435 memcpy(pvData, &pHdr->CmdHdr, pHdr->CmdHdr.cbCmd);
436 pvData += pHdr->CmdHdr.cbCmd;
437 pCmd->Hdr.cbCmdsReturned += pHdr->CmdHdr.cbCmd;
438 RemoveEntryList(pCurEntry);
439 vboxVideoCmCmdReleaseByHdr(pHdr);
440 }
441
442 pCmd->Hdr.cbRemainingCmds = cbRemainingCmds;
443 pCmd->Hdr.cbRemainingFirstCmd = cbRemainingFirstCmd;
444 pCmd->Hdr.u32Reserved = 0;
445
446 return STATUS_SUCCESS;
447}
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