VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideoHGSMI.cpp@ 33116

Last change on this file since 33116 was 33085, checked in by vboxsync, 15 years ago

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.2 KB
Line 
1/* $Id: VBoxVideoHGSMI.cpp 33085 2010-10-12 23:10:48Z vboxsync $ */
2/** @file
3 * VirtualBox Video miniport driver for NT/2k/XP - HGSMI related functions.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19#include "VBoxVideo.h"
20#include "Helper.h"
21
22#include <iprt/asm.h>
23#include <iprt/log.h>
24#include <iprt/thread.h>
25#include <VBox/VMMDev.h>
26#include <VBox/VBoxGuest.h>
27#include <VBox/VBoxVideo.h>
28
29#include <VBoxDisplay.h>
30
31#include "vboxioctl.h"
32
33#define MEM_TAG 'HVBV'
34
35void HGSMINotifyHostCmdComplete (PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offt)
36{
37 VBoxHGSMIHostWrite(pCommon, offt);
38}
39
40void HGSMIClearIrq (PVBOXVIDEO_COMMON pCommon)
41{
42 VBoxHGSMIHostWrite(pCommon, HGSMIOFFSET_VOID);
43}
44
45static void HGSMIHostCmdComplete (PVBOXVIDEO_COMMON pCommon, void * pvMem)
46{
47 HGSMIOFFSET offMem = HGSMIPointerToOffset (&pCommon->areaHostHeap, HGSMIBufferHeaderFromData (pvMem));
48 Assert(offMem != HGSMIOFFSET_VOID);
49 if(offMem != HGSMIOFFSET_VOID)
50 {
51 HGSMINotifyHostCmdComplete (pCommon, offMem);
52 }
53}
54
55static void hgsmiHostCmdProcess(PVBOXVIDEO_COMMON pCommon, HGSMIOFFSET offBuffer)
56{
57 int rc = HGSMIBufferProcess (&pCommon->areaHostHeap,
58 &pCommon->channels,
59 offBuffer);
60 Assert(!RT_FAILURE(rc));
61 if(RT_FAILURE(rc))
62 {
63 /* failure means the command was not submitted to the handler for some reason
64 * it's our responsibility to notify its completion in this case */
65 HGSMINotifyHostCmdComplete(pCommon, offBuffer);
66 }
67 /* if the cmd succeeded it's responsibility of the callback to complete it */
68}
69
70static HGSMIOFFSET hgsmiGetHostBuffer (PVBOXVIDEO_COMMON pCommon)
71{
72 return VBoxHGSMIHostRead(pCommon);
73}
74
75static void hgsmiHostCommandQueryProcess (PVBOXVIDEO_COMMON pCommon)
76{
77 HGSMIOFFSET offset = hgsmiGetHostBuffer (pCommon);
78 Assert(offset != HGSMIOFFSET_VOID);
79 if(offset != HGSMIOFFSET_VOID)
80 {
81 hgsmiHostCmdProcess(pCommon, offset);
82 }
83}
84
85#define VBOX_HGSMI_LOCK(_pe, _plock, _dpc, _pold) \
86 do { \
87 if(_dpc) \
88 { \
89 VBoxVideoCmnSpinLockAcquireAtDpcLevel(_pe, _plock); \
90 } \
91 else \
92 {\
93 VBoxVideoCmnSpinLockAcquire(_pe, _plock, _pold); \
94 }\
95 } while(0)
96
97#define VBOX_HGSMI_UNLOCK(_pe, _plock, _dpc, _pold) \
98 do { \
99 if(_dpc) \
100 { \
101 VBoxVideoCmnSpinLockReleaseFromDpcLevel(_pe, _plock); \
102 } \
103 else \
104 {\
105 VBoxVideoCmnSpinLockRelease(_pe, _plock, _pold); \
106 }\
107 } while(0)
108
109VOID VBoxVideoHGSMIDpc(
110 IN PVOID HwDeviceExtension,
111 IN PVOID Context
112 )
113{
114 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
115 uint32_t flags = (uint32_t)Context;
116 bool bProcessing = false;
117 VBOXVCMNIRQL OldIrql;
118 /* we check if another thread is processing the queue and exit if so */
119 do
120 {
121 bool bLock = false;
122 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
123 {
124 if(!bProcessing)
125 {
126 break;
127 }
128 VBOX_HGSMI_LOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, &OldIrql);
129 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING))
130 {
131 Assert(commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
132 commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing = false;
133 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
134 break;
135 }
136 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
137 }
138 else
139 {
140 if(!bProcessing)
141 {
142 VBOX_HGSMI_LOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, &OldIrql);
143 if(!(commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING)
144 || commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing)
145 {
146 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
147 break;
148 }
149 Assert(!commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
150 commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing = true;
151 VBOX_HGSMI_UNLOCK(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock, flags, OldIrql);
152 bProcessing = true;
153 }
154 }
155
156 Assert(bProcessing);
157 Assert(commonFromDeviceExt(PrimaryExtension)->bHostCmdProcessing);
158 Assert((commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0);
159 bProcessing = true;
160
161 hgsmiHostCommandQueryProcess (commonFromDeviceExt(PrimaryExtension));
162 } while(true/*!PrimaryExtension->u.primary.bPollingStop*/);
163}
164
165/* Detect whether HGSMI is supported by the host. */
166BOOLEAN VBoxHGSMIIsSupported (void)
167{
168 USHORT DispiId;
169
170 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
171 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_HGSMI);
172
173 DispiId = VBoxVideoCmnPortReadUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
174
175 return (DispiId == VBE_DISPI_ID_HGSMI);
176}
177
178typedef int FNHGSMICALLINIT (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
179typedef FNHGSMICALLINIT *PFNHGSMICALLINIT;
180
181typedef int FNHGSMICALLFINALIZE (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData);
182typedef FNHGSMICALLFINALIZE *PFNHGSMICALLFINALIZE;
183
184void* vboxHGSMIBufferAlloc(PVBOXVIDEO_COMMON pCommon,
185 HGSMISIZE cbData,
186 uint8_t u8Ch,
187 uint16_t u16Op)
188{
189#ifdef VBOX_WITH_WDDM
190 /* @todo: add synchronization */
191#endif
192 return HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
193}
194
195void vboxHGSMIBufferFree (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
196{
197#ifdef VBOX_WITH_WDDM
198 /* @todo: add synchronization */
199#endif
200 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, pvBuffer);
201}
202
203int vboxHGSMIBufferSubmit (PVBOXVIDEO_COMMON pCommon, void *pvBuffer)
204{
205 /* Initialize the buffer and get the offset for port IO. */
206 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap, pvBuffer);
207
208 Assert(offBuffer != HGSMIOFFSET_VOID);
209 if (offBuffer != HGSMIOFFSET_VOID)
210 {
211 /* Submit the buffer to the host. */
212 VBoxHGSMIGuestWrite(pCommon, offBuffer);
213 return VINF_SUCCESS;
214 }
215
216 return VERR_INVALID_PARAMETER;
217}
218
219static int vboxCallChannel (PVBOXVIDEO_COMMON pCommon,
220 uint8_t u8Ch,
221 uint16_t u16Op,
222 HGSMISIZE cbData,
223 PFNHGSMICALLINIT pfnInit,
224 PFNHGSMICALLFINALIZE pfnFinalize,
225 void *pvContext)
226{
227 int rc = VINF_SUCCESS;
228
229 /* Allocate the IO buffer. */
230 void *p = HGSMIHeapAlloc (&pCommon->hgsmiAdapterHeap, cbData, u8Ch, u16Op);
231
232 if (!p)
233 {
234 rc = VERR_NO_MEMORY;
235 }
236 else
237 {
238 /* Prepare data to be sent to the host. */
239 if (pfnInit)
240 {
241 rc = pfnInit (pCommon, pvContext, p);
242 }
243
244 if (RT_SUCCESS (rc))
245 {
246 /* Initialize the buffer and get the offset for port IO. */
247 HGSMIOFFSET offBuffer = HGSMIHeapBufferOffset (&pCommon->hgsmiAdapterHeap,
248 p);
249
250 /* Submit the buffer to the host. */
251 VBoxHGSMIGuestWrite(pCommon, offBuffer);
252
253 if (pfnFinalize)
254 {
255 rc = pfnFinalize (pCommon, pvContext, p);
256 }
257 }
258 else
259 {
260 AssertFailed ();
261 rc = VERR_INTERNAL_ERROR;
262 }
263
264 /* Free the IO buffer. */
265 HGSMIHeapFree (&pCommon->hgsmiAdapterHeap, p);
266 }
267
268 return rc;
269}
270
271static int vboxCallVBVA (PVBOXVIDEO_COMMON pCommon,
272 uint16_t u16Op,
273 HGSMISIZE cbData,
274 PFNHGSMICALLINIT pfnInit,
275 PFNHGSMICALLFINALIZE pfnFinalize,
276 void *pvContext)
277{
278 return vboxCallChannel (pCommon,
279 HGSMI_CH_VBVA,
280 u16Op,
281 cbData,
282 pfnInit,
283 pfnFinalize,
284 pvContext);
285}
286
287typedef struct _QUERYCONFCTX
288{
289 uint32_t u32Index;
290 ULONG *pulValue;
291} QUERYCONFCTX;
292
293static int vbvaInitQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
294{
295 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
296 VBVACONF32 *p = (VBVACONF32 *)pvData;
297
298 p->u32Index = pCtx->u32Index;
299 p->u32Value = 0;
300
301 return VINF_SUCCESS;
302}
303
304static int vbvaFinalizeQueryConf (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
305{
306 QUERYCONFCTX *pCtx = (QUERYCONFCTX *)pvContext;
307 VBVACONF32 *p = (VBVACONF32 *)pvData;
308
309 if (pCtx->pulValue)
310 {
311 *pCtx->pulValue = p->u32Value;
312 }
313
314 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->u32Value));
315 return VINF_SUCCESS;
316}
317
318static int vboxQueryConfHGSMI (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
319{
320 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
321
322 QUERYCONFCTX context;
323
324 context.u32Index = u32Index;
325 context.pulValue = pulValue;
326
327 int rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
328 VBVA_QUERY_CONF32,
329 sizeof (VBVACONF32),
330 vbvaInitQueryConf,
331 vbvaFinalizeQueryConf,
332 &context);
333
334 dprintf(("VBoxVideo::vboxQueryConf: rc = %d\n", rc));
335
336 return rc;
337}
338
339int VBoxHGSMISendViewInfo(PVBOXVIDEO_COMMON pCommon, uint32_t u32Count, PFNHGSMIFILLVIEWINFO pfnFill, void *pvData)
340{
341 int rc;
342 /* Issue the screen info command. */
343 void *p = vboxHGSMIBufferAlloc (pCommon, sizeof(VBVAINFOVIEW) * u32Count,
344 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
345 Assert(p);
346 if (p)
347 {
348 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
349 rc = pfnFill(pvData, pInfo);
350 if (RT_SUCCESS(rc))
351 vboxHGSMIBufferSubmit (pCommon, p);
352 vboxHGSMIBufferFree (pCommon, p);
353 }
354 else
355 rc = VERR_NO_MEMORY;
356 return rc;
357}
358
359#ifndef VBOX_WITH_WDDM
360static int vbvaInitInfoDisplay (void *pvData, VBVAINFOVIEW *p)
361{
362 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION) pvData;
363
364 int i;
365 PDEVICE_EXTENSION Extension;
366
367 for (i = 0, Extension = PrimaryExtension;
368 i < PrimaryExtension->u.primary.cDisplays && Extension;
369 i++, Extension = Extension->pNext)
370 {
371 p[i].u32ViewIndex = Extension->iDevice;
372 p[i].u32ViewOffset = Extension->ulFrameBufferOffset;
373 p[i].u32ViewSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
374
375 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
376 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
377
378 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
379 p[i].u32ViewSize - cbReservedVRAM:
380 0;
381 }
382
383 if (i == PrimaryExtension->u.primary.cDisplays && Extension == NULL)
384 {
385 return VINF_SUCCESS;
386 }
387
388 AssertFailed ();
389 return VERR_INTERNAL_ERROR;
390}
391#else
392int vbvaInitInfoCaps (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
393{
394 VBVACAPS *pCaps = (VBVACAPS*)pvData;
395 pCaps->rc = VERR_NOT_IMPLEMENTED;
396 pCaps->fCaps = VBVACAPS_COMPLETEGCMD_BY_IOREAD | VBVACAPS_IRQ;
397 return VINF_SUCCESS;
398}
399
400
401int vbvaFinalizeInfoCaps (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
402{
403 VBVACAPS *pCaps = (VBVACAPS*)pvData;
404 AssertRC(pCaps->rc);
405 return pCaps->rc;
406}
407#endif
408
409static int vbvaInitInfoHeap (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
410{
411 NOREF (pvContext);
412 VBVAINFOHEAP *p = (VBVAINFOHEAP *)pvData;
413
414 p->u32HeapOffset = pCommon->cbVRAM
415 - pCommon->cbMiniportHeap
416 - VBVA_ADAPTER_INFORMATION_SIZE;
417 p->u32HeapSize = pCommon->cbMiniportHeap;
418
419 return VINF_SUCCESS;
420}
421
422static int hgsmiInitFlagsLocation (PVBOXVIDEO_COMMON pCommon, void *pvContext, void *pvData)
423{
424 NOREF (pvContext);
425 HGSMIBUFFERLOCATION *p = (HGSMIBUFFERLOCATION *)pvData;
426
427 p->offLocation = pCommon->cbVRAM - sizeof (HGSMIHOSTFLAGS);
428 p->cbLocation = sizeof (HGSMIHOSTFLAGS);
429
430 return VINF_SUCCESS;
431}
432
433
434static int vboxSetupAdapterInfoHGSMI (PDEVICE_EXTENSION PrimaryExtension)
435{
436 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
437
438 /* setup the flags first to ensure they are initialized by the time the host heap is ready */
439 int rc = vboxCallChannel(commonFromDeviceExt(PrimaryExtension),
440 HGSMI_CH_HGSMI,
441 HGSMI_CC_HOST_FLAGS_LOCATION,
442 sizeof (HGSMIBUFFERLOCATION),
443 hgsmiInitFlagsLocation,
444 NULL,
445 NULL);
446 AssertRC(rc);
447 if(RT_SUCCESS (rc))
448 {
449#ifndef VBOX_WITH_WDDM
450 rc = VBoxHGSMISendViewInfo (commonFromDeviceExt(PrimaryExtension),
451 PrimaryExtension->u.primary.cDisplays,
452 vbvaInitInfoDisplay,
453 (void *) PrimaryExtension);
454 AssertRC(rc);
455 if (RT_SUCCESS (rc))
456#else
457 /* in case of WDDM we do not control the framebuffer location,
458 * i.e. it is assigned by Video Memory Manager,
459 * The FB information should be passed to guest from our DxgkDdiSetVidPnSourceAddress callback */
460
461 /* Inform about caps */
462 rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
463 VBVA_INFO_CAPS,
464 sizeof (VBVACAPS),
465 vbvaInitInfoCaps,
466 vbvaFinalizeInfoCaps,
467 NULL);
468 AssertRC(rc);
469 if (RT_SUCCESS (rc))
470#endif
471 {
472 /* Report the host heap location. */
473 rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
474 VBVA_INFO_HEAP,
475 sizeof (VBVAINFOHEAP),
476 vbvaInitInfoHeap,
477 NULL,
478 NULL);
479 AssertRC(rc);
480 }
481 }
482
483
484 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished rc = %d\n", rc));
485
486 return rc;
487}
488
489#ifndef VBOX_WITH_WDDM
490VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
491{
492 return ERROR_INVALID_FUNCTION;
493}
494
495LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
496{
497 return 0;
498}
499
500VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
501{
502}
503
504VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
505{
506 return ERROR_INVALID_FUNCTION;
507}
508
509VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
510{
511 return ERROR_INVALID_FUNCTION;
512}
513
514VP_STATUS vboxCreateSpinLockVoid (IN PVOID HwDeviceExtension, OUT PSPIN_LOCK *SpinLock)
515{
516 return ERROR_INVALID_FUNCTION;
517}
518
519VP_STATUS vboxDeleteSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
520{
521 return ERROR_INVALID_FUNCTION;
522}
523
524VOID vboxAcquireSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, OUT PUCHAR OldIrql)
525{
526}
527
528VOID vboxReleaseSpinLockVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock, IN UCHAR NewIrql)
529{
530}
531
532VOID vboxAcquireSpinLockAtDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
533{
534}
535
536VOID vboxReleaseSpinLockFromDpcLevelVoid (IN PVOID HwDeviceExtension, IN PSPIN_LOCK SpinLock)
537{
538}
539
540PVOID vboxAllocatePoolVoid(IN PVOID HwDeviceExtension, IN VBOXVP_POOL_TYPE PoolType, IN size_t NumberOfBytes, IN ULONG Tag)
541{
542 return NULL;
543}
544
545VOID vboxFreePoolVoid(IN PVOID HwDeviceExtension, IN PVOID Ptr)
546{
547}
548
549BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
550{
551 return FALSE;
552}
553
554void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
555{
556 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
557
558 if (vboxQueryWinVersion() <= WINNT4)
559 {
560 /* VideoPortGetProcAddress is available for >= win2k */
561 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
562 pCallbacks->pfnSetEvent = vboxSetEventVoid;
563 pCallbacks->pfnClearEvent = vboxClearEventVoid;
564 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
565 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
566 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
567 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
568 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
569 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
570 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
571 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
572 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
573 pCallbacks->pfnFreePool = vboxFreePoolVoid;
574 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
575 return;
576 }
577
578 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
579 (PrimaryExtension,
580 (PUCHAR)"VideoPortWaitForSingleObject");
581 Assert(pCallbacks->pfnWaitForSingleObject);
582
583 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
584 (PrimaryExtension,
585 (PUCHAR)"VideoPortSetEvent");
586 Assert(pCallbacks->pfnSetEvent);
587
588 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
589 (PrimaryExtension,
590 (PUCHAR)"VideoPortClearEvent");
591 Assert(pCallbacks->pfnClearEvent);
592
593 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
594 (PrimaryExtension,
595 (PUCHAR)"VideoPortCreateEvent");
596 Assert(pCallbacks->pfnCreateEvent);
597
598 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
599 (PrimaryExtension,
600 (PUCHAR)"VideoPortDeleteEvent");
601 Assert(pCallbacks->pfnDeleteEvent);
602
603 if(pCallbacks->pfnWaitForSingleObject
604 && pCallbacks->pfnSetEvent
605 && pCallbacks->pfnClearEvent
606 && pCallbacks->pfnCreateEvent
607 && pCallbacks->pfnDeleteEvent)
608 {
609 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
610 }
611 else
612 {
613 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
614 pCallbacks->pfnSetEvent = vboxSetEventVoid;
615 pCallbacks->pfnClearEvent = vboxClearEventVoid;
616 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
617 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
618 }
619
620 pCallbacks->pfnCreateSpinLock = (PFNCREATESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
621 (PrimaryExtension,
622 (PUCHAR)"VideoPortCreateSpinLock");
623 Assert(pCallbacks->pfnCreateSpinLock);
624
625 pCallbacks->pfnDeleteSpinLock = (PFNDELETESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
626 (PrimaryExtension,
627 (PUCHAR)"VideoPortDeleteSpinLock");
628 Assert(pCallbacks->pfnDeleteSpinLock);
629
630 pCallbacks->pfnAcquireSpinLock = (PFNACQUIRESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
631 (PrimaryExtension,
632 (PUCHAR)"VideoPortAcquireSpinLock");
633 Assert(pCallbacks->pfnAcquireSpinLock);
634
635 pCallbacks->pfnReleaseSpinLock = (PFNRELEASESPINLOCK)(pConfigInfo->VideoPortGetProcAddress)
636 (PrimaryExtension,
637 (PUCHAR)"VideoPortReleaseSpinLock");
638 Assert(pCallbacks->pfnReleaseSpinLock);
639
640 pCallbacks->pfnAcquireSpinLockAtDpcLevel = (PFNACQUIRESPINLOCKATDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
641 (PrimaryExtension,
642 (PUCHAR)"VideoPortAcquireSpinLockAtDpcLevel");
643 Assert(pCallbacks->pfnAcquireSpinLockAtDpcLevel);
644
645 pCallbacks->pfnReleaseSpinLockFromDpcLevel = (PFNRELEASESPINLOCKFROMDPCLEVEL)(pConfigInfo->VideoPortGetProcAddress)
646 (PrimaryExtension,
647 (PUCHAR)"VideoPortReleaseSpinLockFromDpcLevel");
648 Assert(pCallbacks->pfnReleaseSpinLockFromDpcLevel);
649
650 if(pCallbacks->pfnCreateSpinLock
651 && pCallbacks->pfnDeleteSpinLock
652 && pCallbacks->pfnAcquireSpinLock
653 && pCallbacks->pfnReleaseSpinLock
654 && pCallbacks->pfnAcquireSpinLockAtDpcLevel
655 && pCallbacks->pfnReleaseSpinLockFromDpcLevel)
656 {
657 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_SPINLOCK;
658 }
659 else
660 {
661 pCallbacks->pfnCreateSpinLock = vboxCreateSpinLockVoid;
662 pCallbacks->pfnDeleteSpinLock = vboxDeleteSpinLockVoid;
663 pCallbacks->pfnAcquireSpinLock = vboxAcquireSpinLockVoid;
664 pCallbacks->pfnReleaseSpinLock = vboxReleaseSpinLockVoid;
665 pCallbacks->pfnAcquireSpinLockAtDpcLevel = vboxAcquireSpinLockAtDpcLevelVoid;
666 pCallbacks->pfnReleaseSpinLockFromDpcLevel = vboxReleaseSpinLockFromDpcLevelVoid;
667 }
668
669 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
670 (PrimaryExtension,
671 (PUCHAR)"VideoPortAllocatePool");
672 Assert(pCallbacks->pfnAllocatePool);
673
674 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
675 (PrimaryExtension,
676 (PUCHAR)"VideoPortFreePool");
677 Assert(pCallbacks->pfnFreePool);
678
679 if(pCallbacks->pfnAllocatePool
680 && pCallbacks->pfnFreePool)
681 {
682 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
683 }
684 else
685 {
686 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
687 pCallbacks->pfnFreePool = vboxFreePoolVoid;
688 }
689
690 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
691 (PrimaryExtension,
692 (PUCHAR)"VideoPortQueueDpc");
693 Assert(pCallbacks->pfnQueueDpc);
694
695 if(pCallbacks->pfnQueueDpc)
696 {
697 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
698 }
699 else
700 {
701 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
702 }
703
704#ifdef DEBUG_misha
705 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
706 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_SPINLOCK);
707#endif
708}
709#endif
710
711/**
712 * Helper function to register secondary displays (DualView). Note that this will not
713 * be available on pre-XP versions, and some editions on XP will fail because they are
714 * intentionally crippled.
715 *
716 * HGSMI variant is a bit different because it uses only HGSMI interface (VBVA channel)
717 * to talk to the host.
718 */
719VOID VBoxSetupDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension,
720#ifndef VBOX_WITH_WDDM
721 PVIDEO_PORT_CONFIG_INFO pConfigInfo,
722#endif
723 ULONG AdapterMemorySize)
724{
725 VP_STATUS rc = NO_ERROR;
726
727 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
728 PrimaryExtension));
729
730 /* Preinitialize the primary extension.
731 * Note: bVBoxVideoSupported is set to FALSE, because HGSMI is active instead.
732 * Note 2: shouldn't be needed for WDDM.
733 */
734 PrimaryExtension->pNext = NULL;
735#ifndef VBOX_WITH_WDDM
736 PrimaryExtension->pPrimary = PrimaryExtension;
737 PrimaryExtension->iDevice = 0;
738 PrimaryExtension->ulFrameBufferOffset = 0;
739 PrimaryExtension->ulFrameBufferSize = 0;
740#endif
741 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
742 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
743#ifndef VBOX_WITH_WDDM
744 PrimaryExtension->u.primary.cDisplays = 1;
745#endif
746 commonFromDeviceExt(PrimaryExtension)->cbVRAM = AdapterMemorySize;
747 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
748 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
749 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation = NULL;
750 commonFromDeviceExt(PrimaryExtension)->pHostFlags = NULL;
751 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
752 commonFromDeviceExt(PrimaryExtension)->bHGSMI = VBoxHGSMIIsSupported ();
753 VBoxVideoCmnMemZero(&commonFromDeviceExt(PrimaryExtension)->areaHostHeap, sizeof(HGSMIAREA));
754 VBoxVideoCmnMemZero(&PrimaryExtension->areaDisplay, sizeof(HGSMIAREA));
755
756 if (commonFromDeviceExt(PrimaryExtension)->IOPortGuest == 0)
757 {
758 commonFromDeviceExt(PrimaryExtension)->bHGSMI = false;
759 }
760
761 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
762 {
763 /* Map the adapter information. It will be needed for HGSMI IO. */
764 rc = VBoxMapAdapterMemory (PrimaryExtension,
765 &commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
766 commonFromDeviceExt(PrimaryExtension)->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
767 VBVA_ADAPTER_INFORMATION_SIZE
768 );
769 if (rc != NO_ERROR)
770 {
771 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
772 rc));
773
774 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
775 }
776 else
777 {
778 /* Setup a HGSMI heap within the adapter information area. */
779 rc = HGSMIHeapSetup (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap,
780 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation,
781 VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS),
782 commonFromDeviceExt(PrimaryExtension)->cbVRAM - VBVA_ADAPTER_INFORMATION_SIZE,
783 false /*fOffsetBased*/);
784
785 if (RT_FAILURE (rc))
786 {
787 dprintf(("VBoxVideo::VBoxSetupDisplays: HGSMIHeapSetup failed rc = %d\n",
788 rc));
789
790 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
791 }
792 else
793 {
794 commonFromDeviceExt(PrimaryExtension)->pHostFlags = (HGSMIHOSTFLAGS*)(((uint8_t*)commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation)
795 + VBVA_ADAPTER_INFORMATION_SIZE - sizeof(HGSMIHOSTFLAGS));
796 }
797 }
798 }
799
800 /* Setup the host heap and the adapter memory. */
801 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
802 {
803 /* The miniport heap is used for the host buffers. */
804 ULONG cbMiniportHeap = 0;
805 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_HOST_HEAP_SIZE, &cbMiniportHeap);
806
807 if (cbMiniportHeap != 0)
808 {
809 /* Do not allow too big heap. No more than 25% of VRAM is allowed. */
810 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 4;
811
812 if (cbMiniportHeapMaxSize >= VBVA_ADAPTER_INFORMATION_SIZE)
813 {
814 cbMiniportHeapMaxSize -= VBVA_ADAPTER_INFORMATION_SIZE;
815 }
816
817 if (cbMiniportHeap > cbMiniportHeapMaxSize)
818 {
819 cbMiniportHeap = cbMiniportHeapMaxSize;
820 }
821
822 /* Round up to 4096 bytes. */
823 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
824
825 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
826 cbMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap, cbMiniportHeapMaxSize));
827
828 /* Map the heap region.
829 *
830 * Note: the heap will be used for the host buffers submitted to the guest.
831 * The miniport driver is responsible for reading FIFO and notifying
832 * display drivers.
833 */
834 rc = VBoxMapAdapterMemory (PrimaryExtension,
835 &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
836 commonFromDeviceExt(PrimaryExtension)->cbVRAM
837 - VBVA_ADAPTER_INFORMATION_SIZE
838 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
839 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
840 );
841 if (rc != NO_ERROR)
842 {
843 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
844 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
845 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
846 }
847 else
848 {
849 HGSMIOFFSET offBase = commonFromDeviceExt(PrimaryExtension)->cbVRAM
850 - VBVA_ADAPTER_INFORMATION_SIZE
851 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap;
852
853 /* Init the host hap area. Buffers from the host will be placed there. */
854 HGSMIAreaInitialize (&commonFromDeviceExt(PrimaryExtension)->areaHostHeap,
855 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap,
856 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap,
857 offBase);
858 }
859 }
860 else
861 {
862 /* Host has not requested a heap. */
863 commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap = NULL;
864 commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap = 0;
865 }
866 }
867
868 /* Check whether the guest supports multimonitors. */
869 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
870 {
871#ifndef VBOX_WITH_WDDM
872 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
873 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
874
875 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
876 if (vboxQueryWinVersion() > WINNT4)
877 {
878 /* This bluescreens on NT4, hence the above version check */
879 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
880 (PrimaryExtension,
881 (PUCHAR)"VideoPortCreateSecondaryDisplay");
882 }
883
884 if (pfnCreateSecondaryDisplay != NULL)
885#endif
886 {
887 /* Query the configured number of displays. */
888 ULONG cDisplays = 0;
889 vboxQueryConfHGSMI (PrimaryExtension, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
890
891 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
892 cDisplays));
893
894 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
895 {
896 /* Host reported some bad value. Continue in the 1 screen mode. */
897 cDisplays = 1;
898 }
899
900#ifndef VBOX_WITH_WDDM
901 PDEVICE_EXTENSION pPrev = PrimaryExtension;
902
903 ULONG iDisplay;
904 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
905 {
906 PDEVICE_EXTENSION SecondaryExtension = NULL;
907 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
908
909 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
910 rc, SecondaryExtension));
911
912 if (rc != NO_ERROR)
913 {
914 break;
915 }
916
917 SecondaryExtension->pNext = NULL;
918 SecondaryExtension->pPrimary = PrimaryExtension;
919 SecondaryExtension->iDevice = iDisplay;
920 SecondaryExtension->ulFrameBufferOffset = 0;
921 SecondaryExtension->ulFrameBufferSize = 0;
922 SecondaryExtension->u.secondary.bEnabled = FALSE;
923
924 /* Update the list pointers. */
925 pPrev->pNext = SecondaryExtension;
926 pPrev = SecondaryExtension;
927
928 /* Take the successfully created display into account. */
929 PrimaryExtension->u.primary.cDisplays++;
930 }
931#else
932 /* simply store the number of monitors, we will deal with VidPN stuff later */
933 PrimaryExtension->u.primary.cDisplays = cDisplays;
934#endif
935 }
936
937 /* Failure to create secondary displays is not fatal */
938 rc = NO_ERROR;
939 }
940
941#ifndef VBOX_WITH_WDDM
942 /* Now when the number of monitors is known and extensions are created,
943 * calculate the layout of framebuffers.
944 */
945 VBoxComputeFrameBufferSizes (PrimaryExtension);
946#endif
947
948 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
949 {
950 /* Setup the information for the host. */
951 rc = vboxSetupAdapterInfoHGSMI (PrimaryExtension);
952
953 if (RT_FAILURE (rc))
954 {
955 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
956 }
957 }
958
959#ifdef VBOX_WITH_WDDM
960 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
961 {
962 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
963 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
964 - VBVA_ADAPTER_INFORMATION_SIZE;
965
966 ULONG ulSize;
967 ULONG offset;
968#ifdef VBOX_WITH_VDMA
969 ulSize = ulAvailable / 2;
970 if (ulSize > VBOXWDDM_C_VDMA_BUFFER_SIZE)
971 ulSize = VBOXWDDM_C_VDMA_BUFFER_SIZE;
972
973 /* Align down to 4096 bytes. */
974 ulSize &= ~0xFFF;
975 offset = ulAvailable - ulSize;
976
977 Assert(!(offset & 0xFFF));
978#else
979 offset = ulAvailable;
980#endif
981 rc = vboxVdmaCreate (PrimaryExtension, &PrimaryExtension->u.primary.Vdma
982#ifdef VBOX_WITH_VDMA
983 , offset, ulSize
984#endif
985 );
986 AssertRC(rc);
987 if (RT_SUCCESS(rc))
988 {
989 /* can enable it right away since the host does not need any screen/FB info
990 * for basic DMA functionality */
991 rc = vboxVdmaEnable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
992 AssertRC(rc);
993 if (RT_FAILURE(rc))
994 vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
995 }
996
997#ifdef VBOXWDDM_RENDER_FROM_SHADOW
998 if (RT_SUCCESS(rc))
999 {
1000 ulAvailable = offset;
1001 ulSize = ulAvailable / 2;
1002 ulSize /= PrimaryExtension->u.primary.cDisplays;
1003 Assert(ulSize > VBVA_MIN_BUFFER_SIZE);
1004 if (ulSize > VBVA_MIN_BUFFER_SIZE)
1005 {
1006 ULONG ulRatio = ulSize/VBVA_MIN_BUFFER_SIZE;
1007 ulRatio >>= 4; /* /= 16; */
1008 if (ulRatio)
1009 ulSize = VBVA_MIN_BUFFER_SIZE * ulRatio;
1010 else
1011 ulSize = VBVA_MIN_BUFFER_SIZE;
1012 }
1013 else
1014 {
1015 /* todo: ?? */
1016 }
1017
1018 ulSize &= ~0xFFF;
1019 Assert(ulSize);
1020
1021 Assert(ulSize * PrimaryExtension->u.primary.cDisplays < ulAvailable);
1022
1023 for (int i = PrimaryExtension->u.primary.cDisplays-1; i >= 0; --i)
1024 {
1025 offset -= ulSize;
1026 rc = vboxVbvaCreate(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva, offset, ulSize, i);
1027 AssertRC(rc);
1028 if (RT_SUCCESS(rc))
1029 {
1030 rc = vboxVbvaEnable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1031 AssertRC(rc);
1032 if (RT_FAILURE(rc))
1033 {
1034 /* @todo: de-initialize */
1035 }
1036 }
1037 }
1038 }
1039#endif
1040
1041 rc = VBoxMapAdapterMemory(PrimaryExtension, (void**)&PrimaryExtension->pvVisibleVram,
1042 0,
1043 vboxWddmVramCpuVisibleSize(PrimaryExtension));
1044 Assert(rc == VINF_SUCCESS);
1045 if (rc != VINF_SUCCESS)
1046 PrimaryExtension->pvVisibleVram = NULL;
1047
1048 if (RT_FAILURE(rc))
1049 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
1050 }
1051#endif
1052
1053 if (!commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1054 {
1055 /* Unmap the memory if VBoxVideo is not supported. */
1056 VBoxUnmapAdapterMemory (PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1057 VBoxUnmapAdapterInformation (PrimaryExtension);
1058
1059 HGSMIHeapDestroy (&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1060 }
1061
1062 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
1063 {
1064 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pSynchLock);
1065 }
1066
1067 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1068}
1069
1070#ifdef VBOX_WITH_WDDM
1071int VBoxFreeDisplaysHGSMI(PDEVICE_EXTENSION PrimaryExtension)
1072{
1073 int rc = VINF_SUCCESS;
1074
1075 Assert(PrimaryExtension->pvVisibleVram);
1076 if (PrimaryExtension->pvVisibleVram)
1077 VBoxUnmapAdapterMemory(PrimaryExtension, (void**)&PrimaryExtension->pvVisibleVram, vboxWddmVramCpuVisibleSize(PrimaryExtension));
1078
1079 for (int i = PrimaryExtension->u.primary.cDisplays-1; i >= 0; --i)
1080 {
1081 rc = vboxVbvaDisable(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1082 AssertRC(rc);
1083 if (RT_SUCCESS(rc))
1084 {
1085 rc = vboxVbvaDestroy(PrimaryExtension, &PrimaryExtension->aSources[i].Vbva);
1086 AssertRC(rc);
1087 if (RT_FAILURE(rc))
1088 {
1089 /* @todo: */
1090 }
1091 }
1092 }
1093
1094 rc = vboxVdmaDisable(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1095 AssertRC(rc);
1096 if (RT_SUCCESS(rc))
1097 {
1098 rc = vboxVdmaDestroy(PrimaryExtension, &PrimaryExtension->u.primary.Vdma);
1099 AssertRC(rc);
1100 if (RT_SUCCESS(rc))
1101 {
1102 /*rc = */VBoxUnmapAdapterMemory(PrimaryExtension, &commonFromDeviceExt(PrimaryExtension)->pvMiniportHeap, commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap);
1103/*
1104 AssertRC(rc);
1105 if (RT_SUCCESS(rc))
1106*/
1107 {
1108 HGSMIHeapDestroy(&commonFromDeviceExt(PrimaryExtension)->hgsmiAdapterHeap);
1109
1110 /* Map the adapter information. It will be needed for HGSMI IO. */
1111 /*rc = */VBoxUnmapAdapterInformation(PrimaryExtension);
1112/*
1113 AssertRC(rc);
1114 if (RT_FAILURE(rc))
1115 drprintf((__FUNCTION__"VBoxUnmapAdapterMemory PrimaryExtension->u.primary.pvAdapterInformation failed, rc(%d)\n", rc));
1116*/
1117
1118 }
1119 }
1120 }
1121
1122 return rc;
1123}
1124#endif
1125
1126/*
1127 * Send the pointer shape to the host.
1128 */
1129typedef struct _MOUSEPOINTERSHAPECTX
1130{
1131 VIDEO_POINTER_ATTRIBUTES *pPointerAttr;
1132 uint32_t cbData;
1133 int32_t i32Result;
1134} MOUSEPOINTERSHAPECTX;
1135
1136static int vbvaInitMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1137{
1138 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1139 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1140
1141 /* Will be updated by the host. */
1142 p->i32Result = VINF_SUCCESS;
1143
1144 /* We have our custom flags in the field */
1145 p->fu32Flags = pCtx->pPointerAttr->Enable & 0x0000FFFF;
1146
1147 p->u32HotX = (pCtx->pPointerAttr->Enable >> 16) & 0xFF;
1148 p->u32HotY = (pCtx->pPointerAttr->Enable >> 24) & 0xFF;
1149 p->u32Width = pCtx->pPointerAttr->Width;
1150 p->u32Height = pCtx->pPointerAttr->Height;
1151
1152 if (p->fu32Flags & VBOX_MOUSE_POINTER_SHAPE)
1153 {
1154 /* If shape is supplied, then alway create the pointer visible.
1155 * See comments in 'vboxUpdatePointerShape'
1156 */
1157 p->fu32Flags |= VBOX_MOUSE_POINTER_VISIBLE;
1158
1159 /* Copy the actual pointer data. */
1160 memcpy (p->au8Data, pCtx->pPointerAttr->Pixels, pCtx->cbData);
1161 }
1162
1163 return VINF_SUCCESS;
1164}
1165
1166static int vbvaFinalizeMousePointerShape (PVBOXVIDEO_COMMON, void *pvContext, void *pvData)
1167{
1168 MOUSEPOINTERSHAPECTX *pCtx = (MOUSEPOINTERSHAPECTX *)pvContext;
1169 VBVAMOUSEPOINTERSHAPE *p = (VBVAMOUSEPOINTERSHAPE *)pvData;
1170
1171 pCtx->i32Result = p->i32Result;
1172
1173 return VINF_SUCCESS;
1174}
1175
1176BOOLEAN vboxUpdatePointerShape (PDEVICE_EXTENSION DeviceExtension,
1177 PVIDEO_POINTER_ATTRIBUTES pointerAttr,
1178 uint32_t cbLength)
1179{
1180#ifndef VBOX_WITH_WDDM
1181 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension->pPrimary;
1182
1183 /* In multimonitor case the HW mouse pointer is the same on all screens,
1184 * and Windows calls each display driver with the same pointer data: visible for
1185 * the screen where the pointer is and invisible for other screens.
1186 *
1187 * This driver passes the shape to the host only from primary screen and makes
1188 * the pointer always visible (in vbvaInitMousePointerShape).
1189 *
1190 * The simple solution makes it impossible to create the shape and keep the mouse
1191 * pointer invisible. New shapes will be created visible.
1192 * But:
1193 * 1) VBox frontends actually ignore the visibility flag if VBOX_MOUSE_POINTER_SHAPE
1194 * is set and always create new pointers visible.
1195 * 2) Windows uses DrvMovePointer to hide the pointer, which will still work.
1196 */
1197
1198 if (DeviceExtension->iDevice != PrimaryExtension->iDevice)
1199 {
1200 dprintf(("vboxUpdatePointerShape: ignore non primary device %d(%d)\n",
1201 DeviceExtension->iDevice, PrimaryExtension->iDevice));
1202 /* Success. */
1203 return TRUE;
1204 }
1205#else
1206 PDEVICE_EXTENSION PrimaryExtension = DeviceExtension;
1207#endif
1208
1209 uint32_t cbData = 0;
1210
1211 if (pointerAttr->Enable & VBOX_MOUSE_POINTER_SHAPE)
1212 {
1213 /* Size of the pointer data: sizeof (AND mask) + sizeof (XOR_MASK) */
1214 cbData = ((((pointerAttr->Width + 7) / 8) * pointerAttr->Height + 3) & ~3)
1215 + pointerAttr->Width * 4 * pointerAttr->Height;
1216 }
1217
1218#ifndef DEBUG_misha
1219 dprintf(("vboxUpdatePointerShape: cbData %d, %dx%d\n",
1220 cbData, pointerAttr->Width, pointerAttr->Height));
1221#endif
1222
1223 if (cbData > cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES))
1224 {
1225 dprintf(("vboxUpdatePointerShape: calculated pointer data size is too big (%d bytes, limit %d)\n",
1226 cbData, cbLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
1227 return FALSE;
1228 }
1229
1230 MOUSEPOINTERSHAPECTX ctx;
1231
1232 ctx.pPointerAttr = pointerAttr;
1233 ctx.cbData = cbData;
1234 ctx.i32Result = VERR_NOT_SUPPORTED;
1235
1236 int rc = vboxCallVBVA (commonFromDeviceExt(PrimaryExtension),
1237 VBVA_MOUSE_POINTER_SHAPE,
1238 sizeof (VBVAMOUSEPOINTERSHAPE) + cbData,
1239 vbvaInitMousePointerShape,
1240 vbvaFinalizeMousePointerShape,
1241 &ctx);
1242#ifndef DEBUG_misha
1243 dprintf(("VBoxVideo::vboxMousePointerShape: rc %d, i32Result = %d\n", rc, ctx.i32Result));
1244#endif
1245
1246 return RT_SUCCESS(rc) && RT_SUCCESS(ctx.i32Result);
1247}
1248
1249typedef struct _VBVAMINIPORT_CHANNELCONTEXT
1250{
1251 PFNHGSMICHANNELHANDLER pfnChannelHandler;
1252 void *pvChannelHandler;
1253}VBVAMINIPORT_CHANNELCONTEXT;
1254
1255typedef struct _VBVADISP_CHANNELCONTEXT
1256{
1257 struct _VBVAHOSTCMD * pFirstCmd;
1258 struct _VBVAHOSTCMD * pLastCmd;
1259 VBOXVCMNSPIN_LOCK pSynchLock;
1260#ifdef DEBUG
1261 int cCmds;
1262#endif
1263 bool bValid;
1264}VBVADISP_CHANNELCONTEXT;
1265
1266#ifdef DEBUG
1267void dbgCheckListLocked(const VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1268{
1269 int counter = 0;
1270 for(struct _VBVAHOSTCMD * pCur = pList->pFirstCmd; pCur; pCur=pCur->u.pNext)
1271 {
1272 Assert(pCur != pCmd);
1273 if(pCur == pList->pLastCmd)
1274 {
1275 Assert(pCur->u.pNext == NULL);
1276 }
1277 if(pCur->u.pNext == NULL)
1278 {
1279 Assert(pCur == pList->pLastCmd);
1280 }
1281 counter++;
1282 }
1283
1284 Assert(counter == pList->cCmds);
1285}
1286
1287void dbgCheckList(PDEVICE_EXTENSION PrimaryExtension, VBVADISP_CHANNELCONTEXT *pList, struct _VBVAHOSTCMD * pCmd)
1288{
1289 VBOXVCMNIRQL oldIrql;
1290 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pList->pSynchLock, &oldIrql);
1291
1292 dbgCheckListLocked(pList, pCmd);
1293
1294 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pList->pSynchLock, oldIrql);
1295}
1296
1297#define DBG_CHECKLIST_LOCKED(_pl, pc) dbgCheckListLocked(_pl, pc)
1298#define DBG_CHECKLIST(_pe, _pl, pc) dbgCheckList(_pe, _pl, pc)
1299
1300#else
1301#define DBG_CHECKLIST_LOCKED(_pl, pc) do{}while(0)
1302#define DBG_CHECKLIST(_pe, _pl, pc) do{}while(0)
1303#endif
1304
1305
1306typedef struct _VBVA_CHANNELCONTEXTS
1307{
1308 PDEVICE_EXTENSION PrimaryExtension;
1309 uint32_t cUsed;
1310 uint32_t cContexts;
1311 VBVAMINIPORT_CHANNELCONTEXT mpContext;
1312 VBVADISP_CHANNELCONTEXT aContexts[1];
1313}VBVA_CHANNELCONTEXTS;
1314
1315static int vboxVBVADeleteChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS * pContext)
1316{
1317 VBoxVideoCmnMemFree(PrimaryExtension,pContext);
1318 return VINF_SUCCESS;
1319}
1320
1321static int vboxVBVACreateChannelContexts(PDEVICE_EXTENSION PrimaryExtension, VBVA_CHANNELCONTEXTS ** ppContext)
1322{
1323#ifndef VBOX_WITH_WDDM
1324 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1325#else
1326 uint32_t cDisplays = (uint32_t)PrimaryExtension->u.primary.cDisplays;
1327#endif
1328 const size_t size = RT_OFFSETOF(VBVA_CHANNELCONTEXTS, aContexts[cDisplays]);
1329 VBVA_CHANNELCONTEXTS * pContext = (VBVA_CHANNELCONTEXTS*)VBoxVideoCmnMemAllocNonPaged(PrimaryExtension, size, MEM_TAG);
1330 if(pContext)
1331 {
1332 memset(pContext, 0, size);
1333 pContext->cContexts = cDisplays;
1334 pContext->PrimaryExtension = PrimaryExtension;
1335 *ppContext = pContext;
1336 return VINF_SUCCESS;
1337 }
1338 return VERR_GENERAL_FAILURE;
1339}
1340
1341static VBVADISP_CHANNELCONTEXT* vboxVBVAFindHandlerInfo(VBVA_CHANNELCONTEXTS *pCallbacks, int iId)
1342{
1343 if(iId < 0)
1344 {
1345 return NULL;
1346 }
1347 else if(pCallbacks->cContexts > (uint32_t)iId)
1348 {
1349 return &pCallbacks->aContexts[iId];
1350 }
1351 return NULL;
1352}
1353
1354#ifndef VBOX_WITH_WDDM
1355DECLCALLBACK(void) hgsmiHostCmdComplete (HVBOXVIDEOHGSMI hHGSMI, struct _VBVAHOSTCMD * pCmd)
1356{
1357 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)hHGSMI)->pPrimary;
1358 HGSMIHostCmdComplete (commonFromDeviceExt(PrimaryExtension), pCmd);
1359}
1360
1361DECLCALLBACK(int) hgsmiHostCmdRequest (HVBOXVIDEOHGSMI hHGSMI, uint8_t u8Channel, struct _VBVAHOSTCMD ** ppCmd)
1362{
1363// if(display < 0)
1364// return VERR_INVALID_PARAMETER;
1365 if(!ppCmd)
1366 return VERR_INVALID_PARAMETER;
1367
1368 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)hHGSMI;
1369 PDEVICE_EXTENSION PrimaryExtension = pDevExt->pPrimary;
1370
1371 /* pick up the host commands */
1372 VBoxVideoHGSMIDpc(PrimaryExtension, NULL);
1373
1374 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1375 if(pChannel)
1376 {
1377 VBVA_CHANNELCONTEXTS * pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1378 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, pDevExt->iDevice);
1379 Assert(pDispContext);
1380 if(pDispContext)
1381 {
1382 UCHAR oldIrql;
1383 VBoxVideoCmnSpinLockAcquire(PrimaryExtension, &pDispContext->pSynchLock, &oldIrql);
1384
1385 DBG_CHECKLIST_LOCKED(pDispContext, NULL);
1386
1387 *ppCmd = pDispContext->pFirstCmd;
1388 pDispContext->pFirstCmd = NULL;
1389 pDispContext->pLastCmd = NULL;
1390#ifdef DEBUG
1391 pDispContext->cCmds = 0;
1392#endif
1393 VBoxVideoCmnSpinLockRelease(PrimaryExtension, &pDispContext->pSynchLock, oldIrql);
1394
1395 DBG_CHECKLIST(PrimaryExtension, pDispContext, NULL);
1396
1397 return VINF_SUCCESS;
1398 }
1399 }
1400
1401 return VERR_INVALID_PARAMETER;
1402}
1403#endif
1404
1405static DECLCALLBACK(int) vboxVBVAChannelGenericHandler(void *pvHandler, uint16_t u16ChannelInfo, void *pvBuffer, HGSMISIZE cbBuffer)
1406{
1407 VBVA_CHANNELCONTEXTS *pCallbacks = (VBVA_CHANNELCONTEXTS*)pvHandler;
1408// Assert(0);
1409 Assert(cbBuffer > VBVAHOSTCMD_HDRSIZE);
1410 if(cbBuffer > VBVAHOSTCMD_HDRSIZE)
1411 {
1412 VBVAHOSTCMD *pHdr = (VBVAHOSTCMD*)pvBuffer;
1413 Assert(pHdr->iDstID >= 0);
1414 if(pHdr->iDstID >= 0)
1415 {
1416 VBVADISP_CHANNELCONTEXT* pHandler = vboxVBVAFindHandlerInfo(pCallbacks, pHdr->iDstID);
1417 Assert(pHandler && pHandler->bValid);
1418 if(pHandler && pHandler->bValid)
1419 {
1420 VBVAHOSTCMD *pFirst = NULL, *pLast = NULL;
1421 for(VBVAHOSTCMD *pCur = pHdr; pCur; )
1422 {
1423 Assert(!pCur->u.Data);
1424 Assert(!pFirst);
1425 Assert(!pLast);
1426
1427 switch(u16ChannelInfo)
1428 {
1429 case VBVAHG_DISPLAY_CUSTOM:
1430 {
1431 if(pLast)
1432 {
1433 pLast->u.pNext = pCur;
1434 pLast = pCur;
1435 }
1436 else
1437 {
1438 pFirst = pCur;
1439 pLast = pCur;
1440 }
1441 Assert(!pCur->u.Data);
1442 //TODO: use offset here
1443 pCur = pCur->u.pNext;
1444 Assert(!pCur);
1445 Assert(pFirst);
1446 Assert(pFirst == pLast);
1447 break;
1448 }
1449 case VBVAHG_EVENT:
1450 {
1451 VBVAHOSTCMDEVENT *pEventCmd = VBVAHOSTCMD_BODY(pCur, VBVAHOSTCMDEVENT);
1452#ifndef VBOX_WITH_WDDM
1453 PEVENT pEvent = (PEVENT)pEventCmd->pEvent;
1454 pCallbacks->PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(
1455 pCallbacks->PrimaryExtension,
1456 pEvent);
1457#else
1458 PKEVENT pEvent = (PKEVENT)pEventCmd->pEvent;
1459 KeSetEvent(pEvent, 0, FALSE);
1460#endif
1461 }
1462 default:
1463 {
1464 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pCur);
1465 Assert(u16ChannelInfo==VBVAHG_EVENT);
1466 Assert(!pCur->u.Data);
1467 //TODO: use offset here
1468 if(pLast)
1469 pLast->u.pNext = pCur->u.pNext;
1470 VBVAHOSTCMD * pNext = pCur->u.pNext;
1471 pCur->u.pNext = NULL;
1472 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pCur);
1473 pCur = pNext;
1474 Assert(!pCur);
1475 Assert(!pFirst);
1476 Assert(pFirst == pLast);
1477 break;
1478 }
1479 }
1480 }
1481
1482 DBG_CHECKLIST(pCallbacks->PrimaryExtension, pHandler, pFirst);
1483
1484 /* we do not support lists currently */
1485 Assert(pFirst == pLast);
1486 if(pLast)
1487 {
1488 Assert(pLast->u.pNext == NULL);
1489 }
1490
1491 if(pFirst)
1492 {
1493 Assert(pLast);
1494 UCHAR oldIrql;
1495 VBoxVideoCmnSpinLockAcquire(pCallbacks->PrimaryExtension,
1496 &pHandler->pSynchLock,
1497 &oldIrql);
1498
1499 DBG_CHECKLIST_LOCKED(pHandler, pFirst);
1500
1501 if(pHandler->pLastCmd)
1502 {
1503 pHandler->pLastCmd->u.pNext = pFirst;
1504 Assert(pHandler->pFirstCmd);
1505 }
1506 else
1507 {
1508 Assert(!pHandler->pFirstCmd);
1509 pHandler->pFirstCmd = pFirst;
1510 }
1511 pHandler->pLastCmd = pLast;
1512#ifdef DEBUG
1513 pHandler->cCmds++;
1514#endif
1515 DBG_CHECKLIST_LOCKED(pHandler, NULL);
1516
1517 VBoxVideoCmnSpinLockRelease(pCallbacks->PrimaryExtension,
1518 &pHandler->pSynchLock,
1519 oldIrql);
1520 }
1521 else
1522 {
1523 Assert(!pLast);
1524 }
1525 return VINF_SUCCESS;
1526 }
1527 }
1528 else
1529 {
1530 //TODO: impl
1531// HGSMIMINIPORT_CHANNELCONTEXT *pHandler = vboxVideoHGSMIFindHandler;
1532// if(pHandler && pHandler->pfnChannelHandler)
1533// {
1534// pHandler->pfnChannelHandler(pHandler->pvChannelHandler, u16ChannelInfo, pHdr, cbBuffer);
1535//
1536// return VINF_SUCCESS;
1537// }
1538 }
1539 }
1540 /* no handlers were found, need to complete the command here */
1541 HGSMIHostCmdComplete(commonFromDeviceExt(pCallbacks->PrimaryExtension), pvBuffer);
1542 return VINF_SUCCESS;
1543}
1544
1545static HGSMICHANNELHANDLER g_OldHandler;
1546
1547int vboxVBVAChannelDisplayEnable(PDEVICE_EXTENSION PrimaryExtension,
1548 int iDisplay, /* negative would mean this is a miniport handler */
1549 uint8_t u8Channel)
1550{
1551 VBVA_CHANNELCONTEXTS * pContexts;
1552 HGSMICHANNEL * pChannel = HGSMIChannelFindById (&commonFromDeviceExt(PrimaryExtension)->channels, u8Channel);
1553 if(!pChannel)
1554 {
1555 int rc = vboxVBVACreateChannelContexts(PrimaryExtension, &pContexts);
1556 if(RT_FAILURE(rc))
1557 {
1558 return rc;
1559 }
1560 }
1561 else
1562 {
1563 pContexts = (VBVA_CHANNELCONTEXTS *)pChannel->handler.pvHandler;
1564 }
1565
1566 VBVADISP_CHANNELCONTEXT *pDispContext = vboxVBVAFindHandlerInfo(pContexts, iDisplay);
1567 Assert(pDispContext);
1568 if(pDispContext)
1569 {
1570#ifdef DEBUGVHWASTRICT
1571 Assert(!pDispContext->bValid);
1572#endif
1573 Assert(!pDispContext->pFirstCmd);
1574 Assert(!pDispContext->pLastCmd);
1575 if(!pDispContext->bValid)
1576 {
1577 pDispContext->bValid = true;
1578 pDispContext->pFirstCmd = NULL;
1579 pDispContext->pLastCmd= NULL;
1580#ifdef DEBUG
1581 pDispContext->cCmds = 0;
1582#endif
1583
1584 VBoxVideoCmnSpinLockCreate(PrimaryExtension, &pDispContext->pSynchLock);
1585
1586 int rc = VINF_SUCCESS;
1587 if(!pChannel)
1588 {
1589 rc = HGSMIChannelRegister (&commonFromDeviceExt(PrimaryExtension)->channels,
1590 u8Channel,
1591 "VGA Miniport HGSMI channel",
1592 vboxVBVAChannelGenericHandler,
1593 pContexts,
1594 &g_OldHandler);
1595 }
1596
1597 if(RT_SUCCESS(rc))
1598 {
1599 pContexts->cUsed++;
1600 return VINF_SUCCESS;
1601 }
1602 }
1603 }
1604
1605 if(!pChannel)
1606 {
1607 vboxVBVADeleteChannelContexts(PrimaryExtension, pContexts);
1608 }
1609
1610 return VERR_GENERAL_FAILURE;
1611}
1612
1613/** @todo Mouse pointer position to be read from VMMDev memory, address of the memory region
1614 * can be queried from VMMDev via an IOCTL. This VMMDev memory region will contain
1615 * host information which is needed by the guest.
1616 *
1617 * Reading will not cause a switch to the host.
1618 *
1619 * Have to take into account:
1620 * * synchronization: host must write to the memory only from EMT,
1621 * large structures must be read under flag, which tells the host
1622 * that the guest is currently reading the memory (OWNER flag?).
1623 * * guest writes: may be allocate a page for the host info and make
1624 * the page readonly for the guest.
1625 * * the information should be available only for additions drivers.
1626 * * VMMDev additions driver will inform the host which version of the info it expects,
1627 * host must support all versions.
1628 *
1629 */
1630
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette