VirtualBox

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

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

wddm/3d: visible regions reporting API & impl (not tested enough yet)

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