VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp@ 35036

最後變更 在這個檔案從35036是 34686,由 vboxsync 提交於 14 年 前

Additions/common/VBoxVideo and Additions/WINNT/Graphics: modesetting clean-up

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 183.7 KB
 
1/*
2 * VirtualBox Video miniport driver for NT/2k/XP
3 *
4 * Based on DDK sample code.
5 *
6 * Copyright (C) 2006-2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.alldomusa.eu.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxVideo-win.h"
18#include "Helper.h"
19#ifdef VBOX_WITH_WDDM
20#include "wddm/VBoxVideoMisc.h"
21#endif
22
23#include <iprt/log.h>
24#include <VBox/VMMDev.h>
25#include <VBox/VBoxGuest.h>
26#include <VBox/VBoxVideo.h>
27
28#include <VBox/VBoxGuestLib.h>
29#include <VBoxDisplay.h>
30
31#if _MSC_VER >= 1400 /* bird: MS fixed swprintf to be standard-conforming... */
32#define _INC_SWPRINTF_INL_
33extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
34#endif
35#include <wchar.h>
36
37#include "vboxioctl.h"
38
39
40static WCHAR VBoxChipType[] = L"VBOX";
41static WCHAR VBoxDACType[] = L"Integrated RAMDAC";
42static WCHAR VBoxAdapterString[] = L"VirtualBox Video Adapter";
43static WCHAR VBoxBiosString[] = L"Version 0xB0C2 or later";
44
45VIDEO_ACCESS_RANGE VGARanges[] = {
46 { 0x000003B0, 0x00000000, 0x0000000C, 1, 1, 1, 0 }, /* 0x3B0-0x3BB */
47 { 0x000003C0, 0x00000000, 0x00000020, 1, 1, 1, 0 }, /* 0x3C0-0x3DF */
48 { 0x000A0000, 0x00000000, 0x00020000, 0, 0, 1, 0 }, /* 0xA0000-0xBFFFF */
49};
50/*
51 * Globals for the last custom resolution set. This is important
52 * for system startup so that we report the last currently set
53 * custom resolution and Windows can use it again.
54 */
55#ifndef VBOX_WITH_MULTIMONITOR_FIX
56uint32_t gCustomXRes = 0;
57uint32_t gCustomYRes = 0;
58uint32_t gCustomBPP = 0;
59#endif /* !VBOX_WITH_MULTIMONITOR_FIX */
60
61/*******************************************************************************
62* Structures and Typedefs *
63*******************************************************************************/
64
65#ifndef VBOX_WITH_WDDM
66typedef struct _DEVICE_EXTENSION * VBOXCMNREG;
67#else
68typedef HANDLE VBOXCMNREG;
69#endif
70
71/*******************************************************************************
72* Internal Functions *
73*******************************************************************************/
74
75int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult);
76
77static VP_STATUS VBoxVideoFindAdapter(
78 IN PVOID HwDeviceExtension,
79 IN PVOID HwContext,
80 IN PWSTR ArgumentString,
81 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
82 OUT PUCHAR Again);
83
84static BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension);
85
86static BOOLEAN VBoxVideoStartIO(
87 PVOID HwDeviceExtension,
88 PVIDEO_REQUEST_PACKET RequestPacket);
89
90#ifdef VBOX_WITH_VIDEOHWACCEL
91static BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension);
92#endif
93
94
95static BOOLEAN VBoxVideoResetHW(
96 PVOID HwDeviceExtension,
97 ULONG Columns,
98 ULONG Rows);
99
100static VP_STATUS VBoxVideoGetPowerState(
101 PVOID HwDeviceExtension,
102 ULONG HwId,
103 PVIDEO_POWER_MANAGEMENT VideoPowerControl);
104
105static VP_STATUS VBoxVideoSetPowerState(
106 PVOID HwDeviceExtension,
107 ULONG HwId,
108 PVIDEO_POWER_MANAGEMENT VideoPowerControl);
109
110static VP_STATUS VBoxVideoGetChildDescriptor(
111 PVOID HwDeviceExtension,
112 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
113 PVIDEO_CHILD_TYPE VideoChildType,
114 PUCHAR pChildDescriptor,
115 PULONG pUId,
116 PULONG pUnused);
117
118#ifndef VBOX_WITH_WDDM
119/*+++
120
121Routine Description:
122
123 This routine is used to read back various registry values.
124
125Arguments:
126
127 HwDeviceExtension
128 Supplies a pointer to the miniport's device extension.
129
130 Context
131 Context value passed to the get registry parameters routine.
132 If this is not null assume it's a ULONG* and save the data value in it.
133
134 ValueName
135 Name of the value requested.
136
137 ValueData
138 Pointer to the requested data.
139
140 ValueLength
141 Length of the requested data.
142
143Return Value:
144
145 If the variable doesn't exist return an error,
146 else if a context is supplied assume it's a PULONG and fill in the value
147 and return no error, else if the value is non-zero return an error.
148
149---*/
150static VP_STATUS VBoxRegistryCallback(PVOID HwDeviceExtension, PVOID Context,
151 PWSTR ValueName, PVOID ValueData,
152 ULONG ValueLength)
153{
154 //dprintf(("VBoxVideo::VBoxRegistryCallback: Context: %p, ValueName: %S, ValueData: %p, ValueLength: %d\n",
155 // Context, ValueName, ValueData, ValueLength));
156 if (ValueLength)
157 {
158 if (Context)
159 *(ULONG *)Context = *(PULONG)ValueData;
160 else if (*((PULONG)ValueData) != 0)
161 return ERROR_INVALID_PARAMETER;
162 return NO_ERROR;
163 }
164 else
165 return ERROR_INVALID_PARAMETER;
166}
167#endif /* #ifndef VBOX_WITH_WDDM */
168
169static VP_STATUS VBoxVideoCmnRegQueryDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t *pVal)
170{
171#ifndef VBOX_WITH_WDDM
172 return VideoPortGetRegistryParameters(Reg, pName, FALSE, VBoxRegistryCallback, pVal);
173#else
174 if(!Reg)
175 return ERROR_INVALID_PARAMETER;
176 NTSTATUS Status = vboxWddmRegQueryValueDword(Reg, pName, (PDWORD)pVal);
177 return Status == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER;
178#endif
179}
180
181static VP_STATUS VBoxVideoCmnRegSetDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t Val)
182{
183#ifndef VBOX_WITH_WDDM
184 return VideoPortSetRegistryParameters(Reg, pName, &Val, sizeof(Val));
185#else
186 if(!Reg)
187 return ERROR_INVALID_PARAMETER;
188 NTSTATUS Status = vboxWddmRegSetValueDword(Reg, pName, Val);
189 return Status == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER;
190#endif
191}
192
193static VP_STATUS VBoxVideoCmnRegInit(IN PDEVICE_EXTENSION pDeviceExtension, OUT VBOXCMNREG *pReg)
194{
195#ifndef VBOX_WITH_WDDM
196 *pReg = pDeviceExtension->pPrimary;
197 return NO_ERROR;
198#else
199 WCHAR Buf[512];
200 ULONG cbBuf = sizeof(Buf);
201 NTSTATUS Status = vboxWddmRegQueryDrvKeyName(pDeviceExtension, cbBuf, Buf, &cbBuf);
202 Assert(Status == STATUS_SUCCESS);
203 if (Status == STATUS_SUCCESS)
204 {
205 Status = vboxWddmRegOpenKey(pReg, Buf, GENERIC_READ | GENERIC_WRITE);
206 Assert(Status == STATUS_SUCCESS);
207 if(Status == STATUS_SUCCESS)
208 return NO_ERROR;
209 }
210
211 /* fall-back to make the subsequent VBoxVideoCmnRegXxx calls treat the fail accordingly
212 * basically needed to make as less modifications to the current XPDM code as possible */
213 *pReg = NULL;
214
215 return ERROR_INVALID_PARAMETER;
216#endif
217}
218
219static VP_STATUS VBoxVideoCmnRegFini(IN VBOXCMNREG Reg)
220{
221#ifndef VBOX_WITH_WDDM
222 return NO_ERROR;
223#else
224 if(!Reg)
225 return ERROR_INVALID_PARAMETER;
226
227 NTSTATUS Status = ZwClose(Reg);
228 return Status == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER;
229#endif
230}
231
232void VBoxVideoCmnSignalEvent(PVBOXVIDEO_COMMON pCommon, uint64_t pvEvent)
233{
234 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
235#ifndef VBOX_WITH_WDDM
236 PEVENT pEvent = (PEVENT)pvEvent;
237 PrimaryExtension->u.primary.VideoPortProcs.pfnSetEvent(PrimaryExtension,
238 pEvent);
239#else
240 PKEVENT pEvent = (PKEVENT)pvEvent;
241 KeSetEvent(pEvent, 0, FALSE);
242#endif
243}
244
245
246#define MEM_TAG 'HVBV'
247
248void *VBoxVideoCmnMemAllocDriver(PVBOXVIDEO_COMMON pCommon, size_t cb)
249{
250 ULONG Tag = MEM_TAG;
251#ifndef VBOX_WITH_WDDM
252 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
253 return PrimaryExtension->u.primary.VideoPortProcs.pfnAllocatePool(PrimaryExtension, (VBOXVP_POOL_TYPE)VpNonPagedPool, cb, Tag);
254#else
255 return ExAllocatePoolWithTag(NonPagedPool, cb, Tag);
256#endif
257}
258
259
260void VBoxVideoCmnMemFreeDriver(PVBOXVIDEO_COMMON pCommon, void *pv)
261{
262#ifndef VBOX_WITH_WDDM
263 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
264 PrimaryExtension->u.primary.VideoPortProcs.pfnFreePool(PrimaryExtension,
265 pv);
266#else
267 ExFreePool(pv);
268#endif
269}
270
271static VOID VBoxVideoCmnMemZero(PVOID pvMem, ULONG cbMem)
272{
273#ifndef VBOX_WITH_WDDM
274 VideoPortZeroMemory(pvMem, cbMem);
275#else
276 memset(pvMem, 0, cbMem);
277#endif
278}
279
280
281#ifndef VBOX_WITH_WDDM
282static void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension,
283 VBOXVIDEOPORTPROCS *pCallbacks,
284 PVIDEO_PORT_CONFIG_INFO pConfigInfo);
285
286ULONG DriverEntry(IN PVOID Context1, IN PVOID Context2)
287{
288 VIDEO_HW_INITIALIZATION_DATA InitData;
289 ULONG rc;
290
291 dprintf(("VBoxVideo::DriverEntry. Built %s %s\n", __DATE__, __TIME__));
292
293 VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
294 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
295 InitData.HwFindAdapter = VBoxVideoFindAdapter;
296 InitData.HwInitialize = VBoxVideoInitialize;
297#ifdef VBOX_WITH_VIDEOHWACCEL
298 InitData.HwInterrupt = VBoxVideoInterrupt;
299#else
300 InitData.HwInterrupt = NULL;
301#endif
302 InitData.HwStartIO = VBoxVideoStartIO;
303 InitData.HwResetHw = VBoxVideoResetHW;
304 InitData.HwDeviceExtensionSize = 0;
305 // nowhere documented but without the following line, NT4 SP0 will choke
306 InitData.AdapterInterfaceType = PCIBus;
307 InitData.HwGetPowerState = VBoxVideoGetPowerState;
308 InitData.HwSetPowerState = VBoxVideoSetPowerState;
309 InitData.HwGetVideoChildDescriptor = VBoxVideoGetChildDescriptor;
310 InitData.HwDeviceExtensionSize = sizeof(DEVICE_EXTENSION);
311 // report legacy VGA resource ranges
312 InitData.HwLegacyResourceList = VGARanges;
313 InitData.HwLegacyResourceCount = sizeof(VGARanges) / sizeof(VGARanges[0]);
314
315 // our DDK is at the Win2k3 level so we have to take special measures
316 // for backwards compatibility
317 switch (vboxQueryWinVersion())
318 {
319 case WINNT4:
320 dprintf(("VBoxVideo::DriverEntry: WINNT4\n"));
321 InitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
322 break;
323 case WIN2K:
324 dprintf(("VBoxVideo::DriverEntry: WIN2K\n"));
325 InitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
326 break;
327 }
328 rc = VideoPortInitialize(Context1, Context2, &InitData, NULL);
329
330 dprintf(("VBoxVideo::DriverEntry: returning with rc = 0x%x\n", rc));
331 return rc;
332}
333#endif
334
335#ifdef VBOX_WITH_GENERIC_MULTIMONITOR
336
337/* builds a g_VBoxWddmVideoResolutions given VideoModes info */
338static int vboxVideoBuildResolutionTable(VIDEO_MODE_INFORMATION *VideoModes, uint32_t cNumVideoModes, SIZE *pResolutions, uint32_t * pcResolutions)
339{
340 uint32_t cResolutionsArray = *pcResolutions;
341 uint32_t cResolutions = 0;
342 int rc = VINF_SUCCESS;
343
344 /* we don't care about the efficiency at this time */
345 for (uint32_t i = 0; i < cNumVideoModes; ++i)
346 {
347 VIDEO_MODE_INFORMATION *pMode = &VideoModes[i];
348 bool bFound = false;
349 for (uint32_t j = 0; j < cResolutions; ++j)
350 {
351 if (pResolutions[j].cx == pMode->VisScreenWidth
352 && pResolutions[j].cy == pMode->VisScreenHeight)
353 {
354 bFound = true;
355 break;
356 }
357 }
358
359 if (!bFound)
360 {
361 if (cResolutions >= cResolutionsArray)
362 {
363 rc = VERR_BUFFER_OVERFLOW;
364 break;
365 }
366
367 pResolutions[cResolutions].cx = pMode->VisScreenWidth;
368 pResolutions[cResolutions].cy = pMode->VisScreenHeight;
369 ++cResolutions;
370 }
371 }
372
373 *pcResolutions = cResolutions;
374 return rc;
375}
376
377/* On the driver startup this is initialized from registry (replaces gCustom*). */
378static VIDEO_MODE_INFORMATION CustomVideoModes[64] = { 0 };
379
380static bool vboxVideoIsVideoModeSupported(PDEVICE_EXTENSION DeviceExtension, int iDisplay, ULONG vramSize,
381 uint32_t xres, uint32_t yres, uint32_t bpp)
382{
383 static uint32_t xresNoVRAM = 0;
384 static uint32_t yresNoVRAM = 0;
385 static uint32_t bppNoVRAM = 0;
386 if (!(( xres
387 && yres
388 && ( (bpp == 16)
389#ifdef VBOX_WITH_8BPP_MODES
390 || (bpp == 8)
391#endif
392 || (bpp == 24)
393 || (bpp == 32)))
394 && (xres * yres * (bpp / 8) < vramSize)))
395 {
396 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
397 xres, yres, bpp, vramSize));
398 if (xres * yres * (bpp / 8) >= vramSize
399 && (xres != xresNoVRAM || yres != yresNoVRAM || bpp != bppNoVRAM))
400 {
401 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
402 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
403 xresNoVRAM = xres;
404 yresNoVRAM = yres;
405 bppNoVRAM = bpp;
406 }
407 return false;
408 }
409
410 /* does the host like that mode? */
411 if (!vboxLikesVideoMode(iDisplay, xres, yres, bpp))
412 {
413 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
414 xres, yres, bpp));
415 return false;
416 }
417
418 return true;
419}
420
421/*
422 * @return index for the changed mode, or -1 of none
423 */
424static int vboxVideoUpdateCustomVideoModes(PDEVICE_EXTENSION DeviceExtension, VBOXCMNREG Reg)
425{
426 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
427 if (!vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
428 && (xres || yres || bpp))
429 return -1;
430
431 if (display > RT_ELEMENTS(CustomVideoModes))
432 return -1;
433
434#ifndef VBOX_WITH_WDDM
435 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
436 /* handle the startup case */
437 if (DeviceExtension->CurrentMode == 0)
438#else
439 if (!commonFromDeviceExt(DeviceExtension)->cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
440#endif
441 {
442 /* Use the stored custom resolution values only if nothing was read from host.
443 * The custom mode might be not valid anymore and would block any hints from host.
444 */
445 if (!xres)
446 xres = CustomVideoModes[display].VisScreenWidth;
447 if (!yres)
448 yres = CustomVideoModes[display].VisScreenHeight;
449 if (!bpp)
450 bpp = CustomVideoModes[display].BitsPerPlane;
451 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, display));
452 }
453
454 /* round down to multiple of 8 if necessary */
455 if (!DeviceExtension->fAnyX) {
456 if ((xres & 0xfff8) != xres)
457 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
458 xres &= 0xfff8;
459 }
460
461 /* take the current values for the fields that are not set */
462#ifndef VBOX_WITH_WDDM
463 if (DeviceExtension->CurrentMode != 0)
464 {
465 if (!xres)
466 xres = DeviceExtension->CurrentModeWidth;
467 if (!yres)
468 yres = DeviceExtension->CurrentModeHeight;
469 if (!bpp)
470 bpp = DeviceExtension->CurrentModeBPP;
471 }
472#else
473 if (commonFromDeviceExt(DeviceExtension)->cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
474 {
475 if (!xres)
476 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
477 if (!yres)
478 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
479 if (!bpp)
480 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
481 }
482#endif
483
484 /* Use a default value. */
485 if (!bpp)
486 bpp = 32;
487
488#ifndef VBOX_WITH_WDDM
489 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
490#else
491 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
492 /* at least two surfaces will be needed: primary & shadow */
493 vramSize /= 2 * DeviceExtension->u.primary.commonInfo.cDisplays;
494#endif
495
496 if (!vboxVideoIsVideoModeSupported(DeviceExtension, display, vramSize, xres, yres, bpp))
497 {
498 return -1;
499 }
500
501 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
502 /*
503 * Build mode entry.
504 * Note that we do not apply the y offset for the custom mode. It is
505 * only used for the predefined modes that the user can configure in
506 * the display properties dialog.
507 */
508 CustomVideoModes[display].Length = sizeof(VIDEO_MODE_INFORMATION);
509 CustomVideoModes[display].ModeIndex = display + 1; /* ensure it is not zero, zero means the mode is loaded from registry and needs verification */
510 CustomVideoModes[display].VisScreenWidth = xres;
511 CustomVideoModes[display].VisScreenHeight = yres;
512 CustomVideoModes[display].ScreenStride = xres * (bpp / 8);
513 CustomVideoModes[display].NumberOfPlanes = 1;
514 CustomVideoModes[display].BitsPerPlane = bpp;
515 CustomVideoModes[display].Frequency = 60;
516 CustomVideoModes[display].XMillimeter = 320;
517 CustomVideoModes[display].YMillimeter = 240;
518
519 switch (bpp)
520 {
521#ifdef VBOX_WITH_8BPP_MODES
522 case 8:
523 CustomVideoModes[display].NumberRedBits = 6;
524 CustomVideoModes[display].NumberGreenBits = 6;
525 CustomVideoModes[display].NumberBlueBits = 6;
526 CustomVideoModes[display].RedMask = 0;
527 CustomVideoModes[display].GreenMask = 0;
528 CustomVideoModes[display].BlueMask = 0;
529 break;
530#endif
531 case 16:
532 CustomVideoModes[display].NumberRedBits = 5;
533 CustomVideoModes[display].NumberGreenBits = 6;
534 CustomVideoModes[display].NumberBlueBits = 5;
535 CustomVideoModes[display].RedMask = 0xF800;
536 CustomVideoModes[display].GreenMask = 0x7E0;
537 CustomVideoModes[display].BlueMask = 0x1F;
538 break;
539 case 24:
540 CustomVideoModes[display].NumberRedBits = 8;
541 CustomVideoModes[display].NumberGreenBits = 8;
542 CustomVideoModes[display].NumberBlueBits = 8;
543 CustomVideoModes[display].RedMask = 0xFF0000;
544 CustomVideoModes[display].GreenMask = 0xFF00;
545 CustomVideoModes[display].BlueMask = 0xFF;
546 break;
547 case 32:
548 CustomVideoModes[display].NumberRedBits = 8;
549 CustomVideoModes[display].NumberGreenBits = 8;
550 CustomVideoModes[display].NumberBlueBits = 8;
551 CustomVideoModes[display].RedMask = 0xFF0000;
552 CustomVideoModes[display].GreenMask = 0xFF00;
553 CustomVideoModes[display].BlueMask = 0xFF;
554 break;
555 }
556 CustomVideoModes[display].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
557#ifdef VBOX_WITH_8BPP_MODES
558 if (bpp == 8)
559 CustomVideoModes[display].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
560#endif
561 CustomVideoModes[display].VideoMemoryBitmapWidth = xres;
562 CustomVideoModes[display].VideoMemoryBitmapHeight = yres;
563 CustomVideoModes[display].DriverSpecificAttributeFlags = 0;
564
565 VP_STATUS status = 0;
566
567 /* Save the custom mode for this display. */
568 if (display)
569 {
570 /* Name without a suffix */
571 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
572 if (status != NO_ERROR)
573 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
574 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
575 if (status != NO_ERROR)
576 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
577 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
578 if (status != NO_ERROR)
579 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
580 }
581 else
582 {
583 wchar_t keyname[32];
584 swprintf(keyname, L"CustomXRes%d", display);
585 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
586 if (status != NO_ERROR)
587 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, display));
588 swprintf(keyname, L"CustomYRes%d", display);
589 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
590 if (status != NO_ERROR)
591 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, display));
592 swprintf(keyname, L"CustomBPP%d", display);
593 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
594 if (status != NO_ERROR)
595 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, display));
596 }
597
598 return display;
599}
600
601#ifdef VBOX_WITH_WDDM
602
603static bool vboxVideoModesMatch(const VIDEO_MODE_INFORMATION *pMode1, const VIDEO_MODE_INFORMATION *pMode2)
604{
605 return pMode1->VisScreenHeight == pMode2->VisScreenHeight
606 && pMode1->VisScreenWidth == pMode2->VisScreenWidth
607 && pMode1->BitsPerPlane == pMode2->BitsPerPlane;
608}
609
610int vboxVideoModeFind(const VIDEO_MODE_INFORMATION *pModes, int cModes, const VIDEO_MODE_INFORMATION *pM)
611{
612 for (int i = 0; i < cModes; ++i)
613 {
614 const VIDEO_MODE_INFORMATION *pMode = &pModes[i];
615 if (vboxVideoModesMatch(pMode, pM))
616 return i;
617 }
618 return -1;
619}
620
621static DECLINLINE(int) vboxVideoCheckModeAdd(VIDEO_MODE_INFORMATION *pModes, int *pcNumModes, int *piPreferred)
622{
623 const int cNumModes = *pcNumModes;
624 for (int i = 0; i < cNumModes; ++i)
625 {
626 if (vboxVideoModesMatch(&pModes[i], &pModes[cNumModes]))
627 {
628 if (piPreferred && *piPreferred == cNumModes)
629 {
630 *piPreferred = i;
631 }
632 return i;
633 }
634 }
635 ++(*pcNumModes);
636 return cNumModes;
637}
638
639static bool vboxVideoModeAdjustCheckSupported(PDEVICE_EXTENSION pDevExt, int iDisplay, VIDEO_MODE_INFORMATION *pMode)
640{
641 /* round down to multiple of 8 if necessary */
642 if (!pDevExt->fAnyX) {
643 if ((pMode->VisScreenWidth & 0xfff8) != pMode->VisScreenWidth)
644 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", pMode->VisScreenWidth, pMode->VisScreenWidth & 0xfff8));
645 pMode->VisScreenWidth &= 0xfff8;
646 }
647
648 if (vboxLikesVideoMode(iDisplay, pMode->VisScreenWidth, pMode->VisScreenHeight, pMode->BitsPerPlane))
649 return true;
650 return false;
651}
652
653static int vboxVideoModeAdd(VIDEO_MODE_INFORMATION *pModes, uint32_t cModes, uint32_t *pcNumModes, const VIDEO_MODE_INFORMATION *pMode)
654{
655 const uint32_t cNumModes = *pcNumModes;
656 for (uint32_t i = 0; i < cNumModes; ++i)
657 {
658 if (vboxVideoModesMatch(&pModes[i], pMode))
659 {
660 return (int)i;
661 }
662 }
663
664 if (cNumModes < cModes)
665 {
666 pModes[cNumModes] = *pMode;
667 pModes[cNumModes].ModeIndex = cNumModes;
668 ++(*pcNumModes);
669 return (int)cNumModes;
670 }
671
672 return -1;
673}
674
675
676# define VBOXVIDEOMODE_ADDED(_aModes, _pcModes, _piPreferred) vboxVideoCheckModeAdd(_aModes, _pcModes, _piPreferred)
677#else
678# define VBOXVIDEOMODE_ADDED(_aModes, _pcModes, _piPreferred) ((*(_pcModes))++)
679#endif
680
681static void vboxVideoInitMode(VIDEO_MODE_INFORMATION *pVideoMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
682{
683 /*
684 * Build mode entry.
685 */
686 memset(pVideoMode, 0, sizeof(VIDEO_MODE_INFORMATION));
687
688 pVideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
689 pVideoMode->ModeIndex = index;
690 pVideoMode->VisScreenWidth = xres;
691 pVideoMode->VisScreenHeight = yres - yoffset;
692 pVideoMode->ScreenStride = xres * ((bpp + 7) / 8);
693 pVideoMode->NumberOfPlanes = 1;
694 pVideoMode->BitsPerPlane = bpp;
695 pVideoMode->Frequency = 60;
696 pVideoMode->XMillimeter = 320;
697 pVideoMode->YMillimeter = 240;
698 switch (bpp)
699 {
700#ifdef VBOX_WITH_8BPP_MODES
701 case 8:
702 pVideoMode->NumberRedBits = 6;
703 pVideoMode->NumberGreenBits = 6;
704 pVideoMode->NumberBlueBits = 6;
705 pVideoMode->RedMask = 0;
706 pVideoMode->GreenMask = 0;
707 pVideoMode->BlueMask = 0;
708 break;
709#endif
710 case 16:
711 pVideoMode->NumberRedBits = 5;
712 pVideoMode->NumberGreenBits = 6;
713 pVideoMode->NumberBlueBits = 5;
714 pVideoMode->RedMask = 0xF800;
715 pVideoMode->GreenMask = 0x7E0;
716 pVideoMode->BlueMask = 0x1F;
717 break;
718 case 24:
719 pVideoMode->NumberRedBits = 8;
720 pVideoMode->NumberGreenBits = 8;
721 pVideoMode->NumberBlueBits = 8;
722 pVideoMode->RedMask = 0xFF0000;
723 pVideoMode->GreenMask = 0xFF00;
724 pVideoMode->BlueMask = 0xFF;
725 break;
726 case 32:
727 pVideoMode->NumberRedBits = 8;
728 pVideoMode->NumberGreenBits = 8;
729 pVideoMode->NumberBlueBits = 8;
730 pVideoMode->RedMask = 0xFF0000;
731 pVideoMode->GreenMask = 0xFF00;
732 pVideoMode->BlueMask = 0xFF;
733 break;
734 }
735 pVideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
736#ifdef VBOX_WITH_8BPP_MODES
737 if (bpp == 8)
738 pVideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
739#endif
740 pVideoMode->VideoMemoryBitmapWidth = xres;
741 pVideoMode->VideoMemoryBitmapHeight = yres - yoffset;
742 pVideoMode->DriverSpecificAttributeFlags = 0;
743}
744
745static int vboxVideoBuildModesTable(PDEVICE_EXTENSION DeviceExtension, int iDisplay,
746 VIDEO_MODE_INFORMATION * VideoModes, uint32_t * pcVideoModes, int32_t * pPreferrableMode)
747{
748 int iPreferredVideoMode = 0;
749 int cNumVideoModes = 0;
750 int cModesTable = *pcVideoModes;
751 int rc = VINF_SUCCESS;
752
753 VBOXCMNREG Reg;
754 VBoxVideoCmnRegInit(DeviceExtension, &Reg);
755
756 /* the resolution matrix */
757 struct
758 {
759 uint16_t xRes;
760 uint16_t yRes;
761 } resolutionMatrix[] =
762 {
763 /* standard modes */
764 { 640, 480 },
765 { 800, 600 },
766 { 1024, 768 },
767 { 1152, 864 },
768 { 1280, 960 },
769 { 1280, 1024 },
770 { 1400, 1050 },
771 { 1600, 1200 },
772 { 1920, 1440 },
773#ifndef VBOX_WITH_WDDM
774 /* multi screen modes with 1280x1024 */
775 { 2560, 1024 },
776 { 3840, 1024 },
777 { 5120, 1024 },
778 /* multi screen modes with 1600x1200 */
779 { 3200, 1200 },
780 { 4800, 1200 },
781 { 6400, 1200 },
782#endif
783 };
784 size_t matrixSize = sizeof(resolutionMatrix) / sizeof(resolutionMatrix[0]);
785
786 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
787 size_t maxModesPerColorDepth = cModesTable / 2 / 4;
788
789 /* size of the VRAM in bytes */
790
791#ifndef VBOX_WITH_WDDM
792 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
793#else
794 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
795 /* at least two surfaces will be needed: primary & shadow */
796 vramSize /= 2 * DeviceExtension->u.primary.commonInfo.cDisplays;
797#endif
798
799 size_t numModesCurrentColorDepth;
800 size_t matrixIndex;
801 VP_STATUS status = 0;
802
803 do
804 {
805 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
806 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
807 * This resolution could be rejected by a low resolution host (netbooks, etc).
808 */
809 int cBytesPerPixel;
810 for (cBytesPerPixel = 1; cBytesPerPixel <= 4; cBytesPerPixel++)
811 {
812 int cBitsPerPixel = cBytesPerPixel * 8; /* 8, 16, 24, 32 */
813
814 #ifndef VBOX_WITH_8BPP_MODES
815 if (cBitsPerPixel == 8)
816 {
817 continue;
818 }
819 #endif /* !VBOX_WITH_8BPP_MODES */
820
821 /* does the mode fit into the VRAM? */
822 if (800 * 600 * cBytesPerPixel > (LONG)vramSize)
823 {
824 continue;
825 }
826
827 if (cModesTable <= cNumVideoModes)
828 {
829 rc = VERR_BUFFER_OVERFLOW;
830 break;
831 }
832
833 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
834 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
835 VideoModes[cNumVideoModes].VisScreenWidth = 800;
836 VideoModes[cNumVideoModes].VisScreenHeight = 600;
837 VideoModes[cNumVideoModes].ScreenStride = 800 * cBytesPerPixel;
838 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
839 VideoModes[cNumVideoModes].BitsPerPlane = cBitsPerPixel;
840 VideoModes[cNumVideoModes].Frequency = 60;
841 VideoModes[cNumVideoModes].XMillimeter = 320;
842 VideoModes[cNumVideoModes].YMillimeter = 240;
843 switch (cBytesPerPixel)
844 {
845 case 1:
846 {
847 VideoModes[cNumVideoModes].NumberRedBits = 6;
848 VideoModes[cNumVideoModes].NumberGreenBits = 6;
849 VideoModes[cNumVideoModes].NumberBlueBits = 6;
850 VideoModes[cNumVideoModes].RedMask = 0;
851 VideoModes[cNumVideoModes].GreenMask = 0;
852 VideoModes[cNumVideoModes].BlueMask = 0;
853 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
854 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
855 } break;
856 case 2:
857 {
858 VideoModes[cNumVideoModes].NumberRedBits = 5;
859 VideoModes[cNumVideoModes].NumberGreenBits = 6;
860 VideoModes[cNumVideoModes].NumberBlueBits = 5;
861 VideoModes[cNumVideoModes].RedMask = 0xF800;
862 VideoModes[cNumVideoModes].GreenMask = 0x7E0;
863 VideoModes[cNumVideoModes].BlueMask = 0x1F;
864 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
865 } break;
866 case 3:
867 {
868 VideoModes[cNumVideoModes].NumberRedBits = 8;
869 VideoModes[cNumVideoModes].NumberGreenBits = 8;
870 VideoModes[cNumVideoModes].NumberBlueBits = 8;
871 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
872 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
873 VideoModes[cNumVideoModes].BlueMask = 0xFF;
874 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
875 } break;
876 default:
877 case 4:
878 {
879 VideoModes[cNumVideoModes].NumberRedBits = 8;
880 VideoModes[cNumVideoModes].NumberGreenBits = 8;
881 VideoModes[cNumVideoModes].NumberBlueBits = 8;
882 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
883 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
884 VideoModes[cNumVideoModes].BlueMask = 0xFF;
885 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
886 iPreferredVideoMode = cNumVideoModes;
887 } break;
888 }
889 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = 800;
890 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = 600;
891 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
892
893 /* a new mode has been filled in */
894 ++cNumVideoModes;
895 }
896
897 if (RT_FAILURE(rc))
898 break;
899
900 /*
901 * Query the y-offset from the host
902 */
903 ULONG yOffset = vboxGetHeightReduction();
904
905#ifdef VBOX_WITH_8BPP_MODES
906 /*
907 * 8 bit video modes
908 */
909 numModesCurrentColorDepth = 0;
910 matrixIndex = 0;
911 while (numModesCurrentColorDepth < maxModesPerColorDepth)
912 {
913 /* are there any modes left in the matrix? */
914 if (matrixIndex >= matrixSize)
915 break;
916
917 /* does the mode fit into the VRAM? */
918 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 1 > (LONG)vramSize)
919 {
920 ++matrixIndex;
921 continue;
922 }
923
924 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
925 {
926 /* This mode was already added. */
927 ++matrixIndex;
928 continue;
929 }
930
931 /* does the host like that mode? */
932 if (!vboxLikesVideoMode(iDisplay, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
933 {
934 ++matrixIndex;
935 continue;
936 }
937
938 if (cModesTable <= cNumVideoModes)
939 {
940 rc = VERR_BUFFER_OVERFLOW;
941 break;
942 }
943
944 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
945 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
946 VideoModes[cNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
947 VideoModes[cNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
948 VideoModes[cNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 1;
949 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
950 VideoModes[cNumVideoModes].BitsPerPlane = 8;
951 VideoModes[cNumVideoModes].Frequency = 60;
952 VideoModes[cNumVideoModes].XMillimeter = 320;
953 VideoModes[cNumVideoModes].YMillimeter = 240;
954 VideoModes[cNumVideoModes].NumberRedBits = 6;
955 VideoModes[cNumVideoModes].NumberGreenBits = 6;
956 VideoModes[cNumVideoModes].NumberBlueBits = 6;
957 VideoModes[cNumVideoModes].RedMask = 0;
958 VideoModes[cNumVideoModes].GreenMask = 0;
959 VideoModes[cNumVideoModes].BlueMask = 0;
960 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
961 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
962 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
963 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
964 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
965
966 /* a new mode has been filled in */
967 ++cNumVideoModes;
968 ++numModesCurrentColorDepth;
969 /* advance to the next mode matrix entry */
970 ++matrixIndex;
971 }
972
973 if (RT_FAILURE(rc))
974 break;
975
976#endif /* VBOX_WITH_8BPP_MODES */
977
978 /*
979 * 16 bit video modes
980 */
981 numModesCurrentColorDepth = 0;
982 matrixIndex = 0;
983 while (numModesCurrentColorDepth < maxModesPerColorDepth)
984 {
985 /* are there any modes left in the matrix? */
986 if (matrixIndex >= matrixSize)
987 break;
988
989 /* does the mode fit into the VRAM? */
990 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 2 > (LONG)vramSize)
991 {
992 ++matrixIndex;
993 continue;
994 }
995
996 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
997 {
998 /* This mode was already added. */
999 ++matrixIndex;
1000 continue;
1001 }
1002
1003 /* does the host like that mode? */
1004 if (!vboxLikesVideoMode(iDisplay, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
1005 {
1006 ++matrixIndex;
1007 continue;
1008 }
1009
1010 if (cModesTable <= cNumVideoModes)
1011 {
1012 rc = VERR_BUFFER_OVERFLOW;
1013 break;
1014 }
1015
1016 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1017 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
1018 VideoModes[cNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1019 VideoModes[cNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1020 VideoModes[cNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 2;
1021 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
1022 VideoModes[cNumVideoModes].BitsPerPlane = 16;
1023 VideoModes[cNumVideoModes].Frequency = 60;
1024 VideoModes[cNumVideoModes].XMillimeter = 320;
1025 VideoModes[cNumVideoModes].YMillimeter = 240;
1026 VideoModes[cNumVideoModes].NumberRedBits = 5;
1027 VideoModes[cNumVideoModes].NumberGreenBits = 6;
1028 VideoModes[cNumVideoModes].NumberBlueBits = 5;
1029 VideoModes[cNumVideoModes].RedMask = 0xF800;
1030 VideoModes[cNumVideoModes].GreenMask = 0x7E0;
1031 VideoModes[cNumVideoModes].BlueMask = 0x1F;
1032 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1033 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1034 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1035 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
1036
1037 /* a new mode has been filled in */
1038 ++cNumVideoModes;
1039 ++numModesCurrentColorDepth;
1040 /* advance to the next mode matrix entry */
1041 ++matrixIndex;
1042 }
1043
1044 if (RT_FAILURE(rc))
1045 break;
1046
1047 /*
1048 * 24 bit video modes
1049 */
1050 numModesCurrentColorDepth = 0;
1051 matrixIndex = 0;
1052 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1053 {
1054 /* are there any modes left in the matrix? */
1055 if (matrixIndex >= matrixSize)
1056 break;
1057
1058 /* does the mode fit into the VRAM? */
1059 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 3 > (LONG)vramSize)
1060 {
1061 ++matrixIndex;
1062 continue;
1063 }
1064
1065 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1066 {
1067 /* This mode was already added. */
1068 ++matrixIndex;
1069 continue;
1070 }
1071
1072 /* does the host like that mode? */
1073 if (!vboxLikesVideoMode(iDisplay, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
1074 {
1075 ++matrixIndex;
1076 continue;
1077 }
1078
1079 if (cModesTable <= cNumVideoModes)
1080 {
1081 rc = VERR_BUFFER_OVERFLOW;
1082 break;
1083 }
1084
1085 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1086 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
1087 VideoModes[cNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1088 VideoModes[cNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1089 VideoModes[cNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 3;
1090 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
1091 VideoModes[cNumVideoModes].BitsPerPlane = 24;
1092 VideoModes[cNumVideoModes].Frequency = 60;
1093 VideoModes[cNumVideoModes].XMillimeter = 320;
1094 VideoModes[cNumVideoModes].YMillimeter = 240;
1095 VideoModes[cNumVideoModes].NumberRedBits = 8;
1096 VideoModes[cNumVideoModes].NumberGreenBits = 8;
1097 VideoModes[cNumVideoModes].NumberBlueBits = 8;
1098 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
1099 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
1100 VideoModes[cNumVideoModes].BlueMask = 0xFF;
1101 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1102 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1103 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1104 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
1105
1106 /* a new mode has been filled in */
1107 ++cNumVideoModes;
1108 ++numModesCurrentColorDepth;
1109 /* advance to the next mode matrix entry */
1110 ++matrixIndex;
1111 }
1112
1113 if (RT_FAILURE(rc))
1114 break;
1115
1116 /*
1117 * 32 bit video modes
1118 */
1119 numModesCurrentColorDepth = 0;
1120 matrixIndex = 0;
1121 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1122 {
1123 /* are there any modes left in the matrix? */
1124 if (matrixIndex >= matrixSize)
1125 break;
1126
1127 /* does the mode fit into the VRAM? */
1128 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 4 > (LONG)vramSize)
1129 {
1130 ++matrixIndex;
1131 continue;
1132 }
1133
1134 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1135 {
1136 /* This mode was already added. */
1137 ++matrixIndex;
1138 continue;
1139 }
1140
1141 /* does the host like that mode? */
1142 if (!vboxLikesVideoMode(iDisplay, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
1143 {
1144 ++matrixIndex;
1145 continue;
1146 }
1147
1148 if (cModesTable <= cNumVideoModes)
1149 {
1150 rc = VERR_BUFFER_OVERFLOW;
1151 break;
1152 }
1153
1154 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1155 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
1156 VideoModes[cNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1157 VideoModes[cNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1158 VideoModes[cNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 4;
1159 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
1160 VideoModes[cNumVideoModes].BitsPerPlane = 32;
1161 VideoModes[cNumVideoModes].Frequency = 60;
1162 VideoModes[cNumVideoModes].XMillimeter = 320;
1163 VideoModes[cNumVideoModes].YMillimeter = 240;
1164 VideoModes[cNumVideoModes].NumberRedBits = 8;
1165 VideoModes[cNumVideoModes].NumberGreenBits = 8;
1166 VideoModes[cNumVideoModes].NumberBlueBits = 8;
1167 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
1168 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
1169 VideoModes[cNumVideoModes].BlueMask = 0xFF;
1170 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1171 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1172 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1173 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
1174
1175 /* a new mode has been filled in */
1176 ++cNumVideoModes;
1177 ++numModesCurrentColorDepth;
1178 /* advance to the next mode matrix entry */
1179 ++matrixIndex;
1180 }
1181
1182 if (RT_FAILURE(rc))
1183 break;
1184
1185 /*
1186 * Next, check the registry for additional modes
1187 */
1188 int curKeyNo = 0;
1189 int fPreferredSet = 0;
1190 do
1191 {
1192 wchar_t keyname[24];
1193 uint32_t xres, yres, bpp = 0;
1194 swprintf(keyname, L"CustomMode%dWidth", curKeyNo);
1195 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &xres);
1196 /* upon the first error, we give up */
1197 if (status != NO_ERROR)
1198 break;
1199 swprintf(keyname, L"CustomMode%dHeight", curKeyNo);
1200 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &yres);
1201 /* upon the first error, we give up */
1202 if (status != NO_ERROR)
1203 break;
1204 swprintf(keyname, L"CustomMode%dBPP", curKeyNo);
1205 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &bpp);
1206 /* upon the first error, we give up */
1207 if (status != NO_ERROR)
1208 break;
1209
1210 dprintf(("VBoxVideo: custom mode %u returned: xres = %u, yres = %u, bpp = %u\n",
1211 curKeyNo, xres, yres, bpp));
1212
1213 /* first test: do the values make sense? */
1214 if ( (xres > (1 << 16))
1215 || (yres > (1 << 16))
1216 || ( (bpp != 16)
1217 && (bpp != 24)
1218 && (bpp != 32)))
1219 break;
1220
1221 /* round down width to be a multiple of 8 if necessary */
1222 if (!DeviceExtension->fAnyX)
1223 xres &= 0xFFF8;
1224
1225 /* second test: does it fit within our VRAM? */
1226 if (xres * yres * (bpp / 8) > vramSize)
1227 break;
1228
1229 /* third test: does the host like the video mode? */
1230 if (!vboxLikesVideoMode(iDisplay, xres, yres, bpp))
1231 break;
1232
1233 if (cModesTable <= cNumVideoModes)
1234 {
1235 rc = VERR_BUFFER_OVERFLOW;
1236 break;
1237 }
1238
1239 dprintf(("VBoxVideo: adding mode from registry: xres = %d, yres = %d, bpp = %d\n", xres, yres, bpp));
1240
1241 if (!fPreferredSet)
1242 {
1243 iPreferredVideoMode = cNumVideoModes;
1244 fPreferredSet = 1;
1245 }
1246
1247 /*
1248 * Build mode entry.
1249 * Note that we have to apply the y offset for the custom mode.
1250 */
1251 VideoModes[cNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1252 VideoModes[cNumVideoModes].ModeIndex = cNumVideoModes + 1;
1253 VideoModes[cNumVideoModes].VisScreenWidth = xres;
1254 VideoModes[cNumVideoModes].VisScreenHeight = yres - yOffset;
1255 VideoModes[cNumVideoModes].ScreenStride = xres * (bpp / 8);
1256 VideoModes[cNumVideoModes].NumberOfPlanes = 1;
1257 VideoModes[cNumVideoModes].BitsPerPlane = bpp;
1258 VideoModes[cNumVideoModes].Frequency = 60;
1259 VideoModes[cNumVideoModes].XMillimeter = 320;
1260 VideoModes[cNumVideoModes].YMillimeter = 240;
1261 switch (bpp)
1262 {
1263 case 16:
1264 VideoModes[cNumVideoModes].NumberRedBits = 5;
1265 VideoModes[cNumVideoModes].NumberGreenBits = 6;
1266 VideoModes[cNumVideoModes].NumberBlueBits = 5;
1267 VideoModes[cNumVideoModes].RedMask = 0xF800;
1268 VideoModes[cNumVideoModes].GreenMask = 0x7E0;
1269 VideoModes[cNumVideoModes].BlueMask = 0x1F;
1270 break;
1271 case 24:
1272 VideoModes[cNumVideoModes].NumberRedBits = 8;
1273 VideoModes[cNumVideoModes].NumberGreenBits = 8;
1274 VideoModes[cNumVideoModes].NumberBlueBits = 8;
1275 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
1276 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
1277 VideoModes[cNumVideoModes].BlueMask = 0xFF;
1278 break;
1279 case 32:
1280 VideoModes[cNumVideoModes].NumberRedBits = 8;
1281 VideoModes[cNumVideoModes].NumberGreenBits = 8;
1282 VideoModes[cNumVideoModes].NumberBlueBits = 8;
1283 VideoModes[cNumVideoModes].RedMask = 0xFF0000;
1284 VideoModes[cNumVideoModes].GreenMask = 0xFF00;
1285 VideoModes[cNumVideoModes].BlueMask = 0xFF;
1286 /* 32-bit mode is more preferable, select it if not yet */
1287 if (fPreferredSet < 2)
1288 {
1289 iPreferredVideoMode = cNumVideoModes;
1290 fPreferredSet = 2;
1291 }
1292 break;
1293 }
1294 VideoModes[cNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1295 VideoModes[cNumVideoModes].VideoMemoryBitmapWidth = xres;
1296 VideoModes[cNumVideoModes].VideoMemoryBitmapHeight = yres - yOffset;
1297 VideoModes[cNumVideoModes].DriverSpecificAttributeFlags = 0;
1298
1299 VBOXVIDEOMODE_ADDED(VideoModes, &cNumVideoModes, &iPreferredVideoMode);
1300
1301 /* next run */
1302 curKeyNo++;
1303 /* only support 128 modes for now */
1304 if (curKeyNo >= 128)
1305 break;
1306
1307 } while(1);
1308
1309 if (RT_FAILURE(rc))
1310 break;
1311
1312 /*
1313 * Now we ask the host for a display change request. If there's one,
1314 * this will be appended as a special mode so that it can be used by
1315 * the Additions service process. The mode table is guaranteed to have
1316 * two spare entries for this mode (alternating index thus 2).
1317 *
1318 * ... or ...
1319 *
1320 * Also we check if we got an user-stored custom resolution in the adapter
1321 * registry key add it to the modes table.
1322 */
1323
1324 /* Add custom resolutions for each display and then for the display change request, if exists.
1325 */
1326 vboxVideoUpdateCustomVideoModes(DeviceExtension, Reg);
1327 /* check if the mode is verified */
1328 if (!CustomVideoModes[iDisplay].ModeIndex)
1329 {
1330 /* the mode is loaded from registry and not verified yet */
1331 if (vboxVideoIsVideoModeSupported(DeviceExtension, iDisplay, vramSize,
1332 CustomVideoModes[iDisplay].VideoMemoryBitmapWidth,
1333 CustomVideoModes[iDisplay].VideoMemoryBitmapHeight,
1334 CustomVideoModes[iDisplay].BitsPerPlane))
1335 {
1336 CustomVideoModes[iDisplay].ModeIndex = iDisplay;
1337 }
1338 }
1339
1340
1341 if (CustomVideoModes[iDisplay].ModeIndex)
1342 {
1343 if (cModesTable <= cNumVideoModes)
1344 {
1345 rc = VERR_BUFFER_OVERFLOW;
1346 break;
1347 }
1348 CustomVideoModes[iDisplay].ModeIndex = cNumVideoModes;
1349 VideoModes[cNumVideoModes] = CustomVideoModes[iDisplay];
1350 iPreferredVideoMode = cNumVideoModes;
1351
1352 VBOXVIDEOMODE_ADDED(VideoModes, &cNumVideoModes, &iPreferredVideoMode);
1353
1354 for (UINT i = 32; i >= 8; i/=2 )
1355 {
1356 if (cModesTable <= cNumVideoModes)
1357 {
1358 rc = VERR_BUFFER_OVERFLOW;
1359 break;
1360 }
1361
1362 if (VideoModes[iPreferredVideoMode].BitsPerPlane != i)
1363 {
1364 vboxVideoInitMode(&VideoModes[cNumVideoModes],
1365 VideoModes[iPreferredVideoMode].VisScreenWidth,
1366 VideoModes[iPreferredVideoMode].VisScreenHeight,
1367 i /* bpp*/ ,
1368 cNumVideoModes /* index*/,
1369 0 /* yoffset*/);
1370 VBOXVIDEOMODE_ADDED(VideoModes, &cNumVideoModes, NULL);
1371 }
1372 }
1373 }
1374
1375 } while(0);
1376
1377 *pcVideoModes = cNumVideoModes;
1378 *pPreferrableMode = iPreferredVideoMode;
1379
1380 VBoxVideoCmnRegFini(Reg);
1381
1382 return rc;
1383}
1384#else /* if !(defined VBOX_WITH_GENERIC_MULTIMONITOR) */
1385/*
1386 * Global list of supported standard video modes. It will be
1387 * filled dynamically.
1388 */
1389#define MAX_VIDEO_MODES 128
1390#ifndef VBOX_WITH_MULTIMONITOR_FIX
1391static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 2] = { 0 };
1392#else
1393/*
1394 * Additional space is reserved for custom video modes for 64 guest monitors.
1395 * The custom video mode index is alternating and 2 indexes are reserved for the last custom mode.
1396 */
1397static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 64 + 2] = { 0 };
1398/* On the driver startup this is initialized from registry (replaces gCustom*). */
1399static VIDEO_MODE_INFORMATION CustomVideoModes[64] = { 0 };
1400#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1401/* number of available video modes, set by VBoxBuildModesTable */
1402static uint32_t gNumVideoModes = 0;
1403
1404#ifdef VBOX_WITH_MULTIMONITOR_FIX
1405static void initVideoModeInformation(VIDEO_MODE_INFORMATION *pVideoMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
1406{
1407 /*
1408 * Build mode entry.
1409 */
1410 memset(pVideoMode, 0, sizeof(VIDEO_MODE_INFORMATION));
1411
1412 pVideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
1413 pVideoMode->ModeIndex = index;
1414 pVideoMode->VisScreenWidth = xres;
1415 pVideoMode->VisScreenHeight = yres - yoffset;
1416 pVideoMode->ScreenStride = xres * ((bpp + 7) / 8);
1417 pVideoMode->NumberOfPlanes = 1;
1418 pVideoMode->BitsPerPlane = bpp;
1419 pVideoMode->Frequency = 60;
1420 pVideoMode->XMillimeter = 320;
1421 pVideoMode->YMillimeter = 240;
1422 switch (bpp)
1423 {
1424#ifdef VBOX_WITH_8BPP_MODES
1425 case 8:
1426 pVideoMode->NumberRedBits = 6;
1427 pVideoMode->NumberGreenBits = 6;
1428 pVideoMode->NumberBlueBits = 6;
1429 pVideoMode->RedMask = 0;
1430 pVideoMode->GreenMask = 0;
1431 pVideoMode->BlueMask = 0;
1432 break;
1433#endif
1434 case 16:
1435 pVideoMode->NumberRedBits = 5;
1436 pVideoMode->NumberGreenBits = 6;
1437 pVideoMode->NumberBlueBits = 5;
1438 pVideoMode->RedMask = 0xF800;
1439 pVideoMode->GreenMask = 0x7E0;
1440 pVideoMode->BlueMask = 0x1F;
1441 break;
1442 case 24:
1443 pVideoMode->NumberRedBits = 8;
1444 pVideoMode->NumberGreenBits = 8;
1445 pVideoMode->NumberBlueBits = 8;
1446 pVideoMode->RedMask = 0xFF0000;
1447 pVideoMode->GreenMask = 0xFF00;
1448 pVideoMode->BlueMask = 0xFF;
1449 break;
1450 case 32:
1451 pVideoMode->NumberRedBits = 8;
1452 pVideoMode->NumberGreenBits = 8;
1453 pVideoMode->NumberBlueBits = 8;
1454 pVideoMode->RedMask = 0xFF0000;
1455 pVideoMode->GreenMask = 0xFF00;
1456 pVideoMode->BlueMask = 0xFF;
1457 break;
1458 }
1459 pVideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1460#ifdef VBOX_WITH_8BPP_MODES
1461 if (bpp == 8)
1462 pVideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1463#endif
1464 pVideoMode->VideoMemoryBitmapWidth = xres;
1465 pVideoMode->VideoMemoryBitmapHeight = yres - yoffset;
1466 pVideoMode->DriverSpecificAttributeFlags = 0;
1467}
1468#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1469
1470
1471static uint32_t g_xresNoVRAM = 0, g_yresNoVRAM = 0, g_bppNoVRAM = 0;
1472
1473/**
1474 * Helper function to dynamically build our table of standard video
1475 * modes. We take the amount of VRAM and create modes with standard
1476 * geometries until we've either reached the maximum number of modes
1477 * or the available VRAM does not allow for additional modes.
1478 */
1479VOID VBoxBuildModesTable(PDEVICE_EXTENSION DeviceExtension)
1480{
1481 /* we need this static counter to always have a new mode index for our */
1482 /* custom video mode, otherwise Windows thinks there is no mode switch */
1483 static int gInvocationCounter = 0;
1484
1485 VBOXCMNREG Reg;
1486 VBoxVideoCmnRegInit(DeviceExtension, &Reg);
1487
1488 /* the resolution matrix */
1489 struct
1490 {
1491 uint16_t xRes;
1492 uint16_t yRes;
1493 } resolutionMatrix[] =
1494 {
1495 /* standard modes */
1496 { 640, 480 },
1497 { 800, 600 },
1498 { 1024, 768 },
1499 { 1152, 864 },
1500 { 1280, 960 },
1501 { 1280, 1024 },
1502 { 1400, 1050 },
1503 { 1600, 1200 },
1504 { 1920, 1440 },
1505#ifndef VBOX_WITH_WDDM
1506 /* multi screen modes with 1280x1024 */
1507 { 2560, 1024 },
1508 { 3840, 1024 },
1509 { 5120, 1024 },
1510 /* multi screen modes with 1600x1200 */
1511 { 3200, 1200 },
1512 { 4800, 1200 },
1513 { 6400, 1200 },
1514#endif
1515 };
1516 size_t matrixSize = sizeof(resolutionMatrix) / sizeof(resolutionMatrix[0]);
1517
1518 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
1519 size_t maxModesPerColorDepth = MAX_VIDEO_MODES / 2 / 4;
1520
1521 /* size of the VRAM in bytes */
1522
1523#ifndef VBOX_WITH_WDDM
1524 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
1525#else
1526 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
1527 /* at least two surfaces will be needed: primary & shadow */
1528 vramSize /= 2 * DeviceExtension->u.primary.commonInfo.cDisplays;
1529
1530 gPreferredVideoMode = 0;
1531#endif
1532
1533 gNumVideoModes = 0;
1534
1535 size_t numModesCurrentColorDepth;
1536 size_t matrixIndex;
1537 VP_STATUS status = 0;
1538
1539 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
1540 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
1541 * This resolution could be rejected by a low resolution host (netbooks, etc).
1542 */
1543 int cBytesPerPixel;
1544 for (cBytesPerPixel = 1; cBytesPerPixel <= 4; cBytesPerPixel++)
1545 {
1546 int cBitsPerPixel = cBytesPerPixel * 8; /* 8, 16, 24, 32 */
1547
1548#ifndef VBOX_WITH_8BPP_MODES
1549 if (cBitsPerPixel == 8)
1550 {
1551 continue;
1552 }
1553#endif /* !VBOX_WITH_8BPP_MODES */
1554
1555 /* does the mode fit into the VRAM? */
1556 if (800 * 600 * cBytesPerPixel > (LONG)vramSize)
1557 {
1558 continue;
1559 }
1560
1561 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1562 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1563 VideoModes[gNumVideoModes].VisScreenWidth = 800;
1564 VideoModes[gNumVideoModes].VisScreenHeight = 600;
1565 VideoModes[gNumVideoModes].ScreenStride = 800 * cBytesPerPixel;
1566 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1567 VideoModes[gNumVideoModes].BitsPerPlane = cBitsPerPixel;
1568 VideoModes[gNumVideoModes].Frequency = 60;
1569 VideoModes[gNumVideoModes].XMillimeter = 320;
1570 VideoModes[gNumVideoModes].YMillimeter = 240;
1571 switch (cBytesPerPixel)
1572 {
1573 case 1:
1574 {
1575 VideoModes[gNumVideoModes].NumberRedBits = 6;
1576 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1577 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1578 VideoModes[gNumVideoModes].RedMask = 0;
1579 VideoModes[gNumVideoModes].GreenMask = 0;
1580 VideoModes[gNumVideoModes].BlueMask = 0;
1581 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
1582 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1583 } break;
1584 case 2:
1585 {
1586 VideoModes[gNumVideoModes].NumberRedBits = 5;
1587 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1588 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1589 VideoModes[gNumVideoModes].RedMask = 0xF800;
1590 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1591 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1592 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1593 } break;
1594 case 3:
1595 {
1596 VideoModes[gNumVideoModes].NumberRedBits = 8;
1597 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1598 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1599 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1600 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1601 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1602 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1603 } break;
1604 default:
1605 case 4:
1606 {
1607 VideoModes[gNumVideoModes].NumberRedBits = 8;
1608 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1609 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1610 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1611 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1612 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1613 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1614#ifdef VBOX_WITH_WDDM
1615 gPreferredVideoMode = gNumVideoModes;
1616#endif
1617 } break;
1618 }
1619 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = 800;
1620 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = 600;
1621 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1622
1623 /* a new mode has been filled in */
1624 ++gNumVideoModes;
1625 }
1626
1627 /*
1628 * Query the y-offset from the host
1629 */
1630 ULONG yOffset = vboxGetHeightReduction();
1631
1632#ifdef VBOX_WITH_8BPP_MODES
1633 /*
1634 * 8 bit video modes
1635 */
1636 numModesCurrentColorDepth = 0;
1637 matrixIndex = 0;
1638 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1639 {
1640 /* are there any modes left in the matrix? */
1641 if (matrixIndex >= matrixSize)
1642 break;
1643
1644 /* does the mode fit into the VRAM? */
1645 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 1 > (LONG)vramSize)
1646 {
1647 ++matrixIndex;
1648 continue;
1649 }
1650
1651 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1652 {
1653 /* This mode was already added. */
1654 ++matrixIndex;
1655 continue;
1656 }
1657
1658 /* does the host like that mode? */
1659#ifndef VBOX_WITH_WDDM
1660 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
1661#else
1662 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
1663#endif
1664 {
1665 ++matrixIndex;
1666 continue;
1667 }
1668
1669 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1670 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1671 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1672 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1673 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 1;
1674 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1675 VideoModes[gNumVideoModes].BitsPerPlane = 8;
1676 VideoModes[gNumVideoModes].Frequency = 60;
1677 VideoModes[gNumVideoModes].XMillimeter = 320;
1678 VideoModes[gNumVideoModes].YMillimeter = 240;
1679 VideoModes[gNumVideoModes].NumberRedBits = 6;
1680 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1681 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1682 VideoModes[gNumVideoModes].RedMask = 0;
1683 VideoModes[gNumVideoModes].GreenMask = 0;
1684 VideoModes[gNumVideoModes].BlueMask = 0;
1685 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
1686 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1687 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1688 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1689 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1690
1691 /* a new mode has been filled in */
1692 ++gNumVideoModes;
1693 ++numModesCurrentColorDepth;
1694 /* advance to the next mode matrix entry */
1695 ++matrixIndex;
1696 }
1697#endif /* VBOX_WITH_8BPP_MODES */
1698
1699 /*
1700 * 16 bit video modes
1701 */
1702 numModesCurrentColorDepth = 0;
1703 matrixIndex = 0;
1704 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1705 {
1706 /* are there any modes left in the matrix? */
1707 if (matrixIndex >= matrixSize)
1708 break;
1709
1710 /* does the mode fit into the VRAM? */
1711 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 2 > (LONG)vramSize)
1712 {
1713 ++matrixIndex;
1714 continue;
1715 }
1716
1717 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1718 {
1719 /* This mode was already added. */
1720 ++matrixIndex;
1721 continue;
1722 }
1723
1724 /* does the host like that mode? */
1725#ifndef VBOX_WITH_WDDM
1726 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
1727#else
1728 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
1729#endif
1730
1731 {
1732 ++matrixIndex;
1733 continue;
1734 }
1735
1736 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1737 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1738 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1739 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1740 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 2;
1741 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1742 VideoModes[gNumVideoModes].BitsPerPlane = 16;
1743 VideoModes[gNumVideoModes].Frequency = 60;
1744 VideoModes[gNumVideoModes].XMillimeter = 320;
1745 VideoModes[gNumVideoModes].YMillimeter = 240;
1746 VideoModes[gNumVideoModes].NumberRedBits = 5;
1747 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1748 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1749 VideoModes[gNumVideoModes].RedMask = 0xF800;
1750 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1751 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1752 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1753 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1754 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1755 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1756
1757 /* a new mode has been filled in */
1758 ++gNumVideoModes;
1759 ++numModesCurrentColorDepth;
1760 /* advance to the next mode matrix entry */
1761 ++matrixIndex;
1762 }
1763
1764 /*
1765 * 24 bit video modes
1766 */
1767 numModesCurrentColorDepth = 0;
1768 matrixIndex = 0;
1769 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1770 {
1771 /* are there any modes left in the matrix? */
1772 if (matrixIndex >= matrixSize)
1773 break;
1774
1775 /* does the mode fit into the VRAM? */
1776 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 3 > (LONG)vramSize)
1777 {
1778 ++matrixIndex;
1779 continue;
1780 }
1781
1782 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1783 {
1784 /* This mode was already added. */
1785 ++matrixIndex;
1786 continue;
1787 }
1788
1789 /* does the host like that mode? */
1790#ifndef VBOX_WITH_WDDM
1791 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
1792#else
1793 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
1794#endif
1795 {
1796 ++matrixIndex;
1797 continue;
1798 }
1799
1800 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1801 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1802 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1803 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1804 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 3;
1805 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1806 VideoModes[gNumVideoModes].BitsPerPlane = 24;
1807 VideoModes[gNumVideoModes].Frequency = 60;
1808 VideoModes[gNumVideoModes].XMillimeter = 320;
1809 VideoModes[gNumVideoModes].YMillimeter = 240;
1810 VideoModes[gNumVideoModes].NumberRedBits = 8;
1811 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1812 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1813 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1814 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1815 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1816 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1817 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1818 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1819 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1820
1821 /* a new mode has been filled in */
1822 ++gNumVideoModes;
1823 ++numModesCurrentColorDepth;
1824 /* advance to the next mode matrix entry */
1825 ++matrixIndex;
1826 }
1827
1828 /*
1829 * 32 bit video modes
1830 */
1831 numModesCurrentColorDepth = 0;
1832 matrixIndex = 0;
1833 while (numModesCurrentColorDepth < maxModesPerColorDepth)
1834 {
1835 /* are there any modes left in the matrix? */
1836 if (matrixIndex >= matrixSize)
1837 break;
1838
1839 /* does the mode fit into the VRAM? */
1840 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 4 > (LONG)vramSize)
1841 {
1842 ++matrixIndex;
1843 continue;
1844 }
1845
1846 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
1847 {
1848 /* This mode was already added. */
1849 ++matrixIndex;
1850 continue;
1851 }
1852
1853 /* does the host like that mode? */
1854#ifndef VBOX_WITH_WDDM
1855 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
1856#else
1857 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
1858#endif
1859 {
1860 ++matrixIndex;
1861 continue;
1862 }
1863
1864 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1865 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1866 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
1867 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1868 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 4;
1869 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1870 VideoModes[gNumVideoModes].BitsPerPlane = 32;
1871 VideoModes[gNumVideoModes].Frequency = 60;
1872 VideoModes[gNumVideoModes].XMillimeter = 320;
1873 VideoModes[gNumVideoModes].YMillimeter = 240;
1874 VideoModes[gNumVideoModes].NumberRedBits = 8;
1875 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1876 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1877 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1878 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1879 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1880 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1881 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
1882 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
1883 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1884
1885 /* a new mode has been filled in */
1886 ++gNumVideoModes;
1887 ++numModesCurrentColorDepth;
1888 /* advance to the next mode matrix entry */
1889 ++matrixIndex;
1890 }
1891
1892 /*
1893 * Next, check the registry for additional modes
1894 */
1895 int curKeyNo = 0;
1896#ifdef VBOX_WITH_WDDM
1897 int fPreferredSet = 0;
1898#endif
1899 do
1900 {
1901 /* check if there is space in the mode list */
1902 if (gNumVideoModes >= MAX_VIDEO_MODES)
1903 break;
1904
1905 wchar_t keyname[24];
1906 uint32_t xres, yres, bpp = 0;
1907 swprintf(keyname, L"CustomMode%dWidth", curKeyNo);
1908 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &xres);
1909 /* upon the first error, we give up */
1910 if (status != NO_ERROR)
1911 break;
1912 swprintf(keyname, L"CustomMode%dHeight", curKeyNo);
1913 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &yres);
1914 /* upon the first error, we give up */
1915 if (status != NO_ERROR)
1916 break;
1917 swprintf(keyname, L"CustomMode%dBPP", curKeyNo);
1918 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &bpp);
1919 /* upon the first error, we give up */
1920 if (status != NO_ERROR)
1921 break;
1922
1923 dprintf(("VBoxVideo: custom mode %u returned: xres = %u, yres = %u, bpp = %u\n",
1924 curKeyNo, xres, yres, bpp));
1925
1926 /* first test: do the values make sense? */
1927 if ( (xres > (1 << 16))
1928 || (yres > (1 << 16))
1929 || ( (bpp != 16)
1930 && (bpp != 24)
1931 && (bpp != 32)))
1932 break;
1933
1934 /* round down width to be a multiple of 8 if necessary */
1935 if (!DeviceExtension->fAnyX)
1936 xres &= 0xFFF8;
1937
1938 /* second test: does it fit within our VRAM? */
1939 if (xres * yres * (bpp / 8) > vramSize)
1940 break;
1941
1942 /* third test: does the host like the video mode? */
1943#ifndef VBOX_WITH_WDDM
1944 if (!vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
1945#else
1946 if (!vboxLikesVideoMode(0, xres, yres, bpp))
1947#endif
1948 break;
1949
1950 dprintf(("VBoxVideo: adding mode from registry: xres = %d, yres = %d, bpp = %d\n", xres, yres, bpp));
1951
1952#ifdef VBOX_WITH_WDDM
1953 if (!fPreferredSet)
1954 {
1955 gPreferredVideoMode = gNumVideoModes;
1956 fPreferredSet = 1;
1957 }
1958#endif
1959 /*
1960 * Build mode entry.
1961 * Note that we have to apply the y offset for the custom mode.
1962 */
1963 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1964 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1965 VideoModes[gNumVideoModes].VisScreenWidth = xres;
1966 VideoModes[gNumVideoModes].VisScreenHeight = yres - yOffset;
1967 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
1968 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1969 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
1970 VideoModes[gNumVideoModes].Frequency = 60;
1971 VideoModes[gNumVideoModes].XMillimeter = 320;
1972 VideoModes[gNumVideoModes].YMillimeter = 240;
1973 switch (bpp)
1974 {
1975 case 16:
1976 VideoModes[gNumVideoModes].NumberRedBits = 5;
1977 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1978 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1979 VideoModes[gNumVideoModes].RedMask = 0xF800;
1980 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1981 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1982 break;
1983 case 24:
1984 VideoModes[gNumVideoModes].NumberRedBits = 8;
1985 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1986 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1987 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1988 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1989 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1990 break;
1991 case 32:
1992 VideoModes[gNumVideoModes].NumberRedBits = 8;
1993 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1994 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1995 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1996 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1997 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1998#ifdef VBOX_WITH_WDDM
1999 /* 32-bit mode is more preferable, select it if not yet */
2000 if (fPreferredSet < 2)
2001 {
2002 gPreferredVideoMode = gNumVideoModes;
2003 fPreferredSet = 2;
2004 }
2005#endif
2006 break;
2007 }
2008 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
2009 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
2010 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres - yOffset;
2011 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
2012 ++gNumVideoModes;
2013
2014 /* next run */
2015 curKeyNo++;
2016 /* only support 128 modes for now */
2017 if (curKeyNo >= 128)
2018 break;
2019
2020 } while(1);
2021
2022 /*
2023 * Now we ask the host for a display change request. If there's one,
2024 * this will be appended as a special mode so that it can be used by
2025 * the Additions service process. The mode table is guaranteed to have
2026 * two spare entries for this mode (alternating index thus 2).
2027 *
2028 * ... or ...
2029 *
2030 * Also we check if we got an user-stored custom resolution in the adapter
2031 * registry key add it to the modes table.
2032 */
2033
2034#ifdef VBOX_WITH_MULTIMONITOR_FIX
2035 /* Add custom resolutions for each display and then for the display change request, if exists.
2036 */
2037 BOOLEAN fDisplayChangeRequest = FALSE;
2038
2039 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
2040 if ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
2041 && (xres || yres || bpp))
2042 {
2043 /* There is a pending display change request. */
2044 fDisplayChangeRequest = TRUE;
2045 }
2046 if (display > RT_ELEMENTS(CustomVideoModes))
2047 {
2048 display = RT_ELEMENTS(CustomVideoModes) - 1;
2049 }
2050
2051 dprintf(("display = %d, DeviceExtension->iDevice = %d\n", display, DeviceExtension->iDevice));
2052 if (display != DeviceExtension->iDevice)
2053 {
2054 /* No need to go through the custom mode logic. And no need to clear the custom mode
2055 * entry in the next 'for' loop.
2056 */
2057 fDisplayChangeRequest = FALSE;
2058 }
2059
2060 dprintf(("VBoxVideo: fDisplayChangeRequest = %d\n", fDisplayChangeRequest));
2061
2062 /*
2063 * Reinsert custom video modes for all displays.
2064 */
2065 int iCustomMode;
2066 for (iCustomMode = 0; iCustomMode < commonFromDeviceExt(DeviceExtension)->cDisplays; iCustomMode++)
2067 {
2068 if (fDisplayChangeRequest && iCustomMode == display)
2069 {
2070 /* Do not keep info for this display, which received a video mode hint, to make sure that
2071 * the new mode will be taken from the alternating index entries actually.
2072 */
2073 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
2074 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2075 }
2076 else
2077 {
2078 VideoModes[gNumVideoModes] = CustomVideoModes[iCustomMode];
2079 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2080 }
2081#ifdef LOG_ENABLED
2082 dprintf(("Custom mode for %2d: %4d x %4d @ %2d\n",
2083 iCustomMode, CustomVideoModes[iCustomMode].VisScreenWidth,
2084 CustomVideoModes[iCustomMode].VisScreenHeight, CustomVideoModes[iCustomMode].BitsPerPlane));
2085#endif
2086 gNumVideoModes++;
2087 }
2088
2089 if (display != DeviceExtension->iDevice)
2090 {
2091 /* The display change is for another monitor. Just add 2 standard modes to the table
2092 * to make enough entries. This is not necessary if it is a first mode set (CurrentMode == 0),
2093 * because these 2 entries will be added by "if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)"
2094 * code branch.
2095 */
2096 if (DeviceExtension->CurrentMode != 0)
2097 {
2098 dprintf(("Filling custom mode entries.\n"));
2099 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
2100 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2101 gNumVideoModes++;
2102 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
2103 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2104 gNumVideoModes++;
2105 }
2106 }
2107#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2108
2109#ifndef VBOX_WITH_MULTIMONITOR_FIX
2110 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
2111 if ( ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
2112 && (xres || yres || bpp))
2113 || (gCustomXRes || gCustomYRes || gCustomBPP))
2114#else
2115 if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)
2116#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2117 {
2118#ifndef VBOX_WITH_WDDM
2119 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
2120 /* handle the startup case */
2121 if (DeviceExtension->CurrentMode == 0)
2122#else
2123 if (!commonFromDeviceExt(DeviceExtension)->cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
2124#endif
2125 {
2126 /* Use the stored custom resolution values only if nothing was read from host.
2127 * The custom mode might be not valid anymore and would block any hints from host.
2128 */
2129#ifndef VBOX_WITH_MULTIMONITOR_FIX
2130 if (!xres)
2131 xres = gCustomXRes;
2132 if (!yres)
2133 yres = gCustomYRes;
2134 if (!bpp)
2135 bpp = gCustomBPP;
2136 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d\n", xres, yres, bpp));
2137#else
2138 if (!xres)
2139 xres = CustomVideoModes[DeviceExtension->iDevice].VisScreenWidth;
2140 if (!yres)
2141 yres = CustomVideoModes[DeviceExtension->iDevice].VisScreenHeight;
2142 if (!bpp)
2143 bpp = CustomVideoModes[DeviceExtension->iDevice].BitsPerPlane;
2144 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, DeviceExtension->iDevice));
2145#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2146 }
2147 /* round down to multiple of 8 if necessary */
2148 if (!DeviceExtension->fAnyX) {
2149 if ((xres & 0xfff8) != xres)
2150 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
2151 xres &= 0xfff8;
2152 }
2153 /* take the current values for the fields that are not set */
2154#ifndef VBOX_WITH_WDDM
2155 if (DeviceExtension->CurrentMode != 0)
2156 {
2157 if (!xres)
2158 xres = DeviceExtension->CurrentModeWidth;
2159 if (!yres)
2160 yres = DeviceExtension->CurrentModeHeight;
2161 if (!bpp)
2162 bpp = DeviceExtension->CurrentModeBPP;
2163 }
2164#else
2165 if (commonFromDeviceExt(DeviceExtension)->cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
2166 {
2167 if (!xres)
2168 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
2169 if (!yres)
2170 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
2171 if (!bpp)
2172 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
2173 }
2174#endif
2175
2176 /* Use a default value. */
2177 if (!bpp)
2178 bpp = 32;
2179
2180 /* does the host like that mode? */
2181#ifndef VBOX_WITH_WDDM
2182 if (vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
2183#else
2184 if (vboxLikesVideoMode(0, xres, yres, bpp))
2185#endif
2186 {
2187 /* we must have a valid video mode by now and it must fit within the VRAM */
2188 if ( ( xres
2189 && yres
2190 && ( (bpp == 16)
2191#ifdef VBOX_WITH_8BPP_MODES
2192 || (bpp == 8)
2193#endif
2194 || (bpp == 24)
2195 || (bpp == 32)))
2196 && (xres * yres * (bpp / 8) < vramSize))
2197
2198 {
2199 /* we need an alternating index */
2200#ifdef VBOX_WITH_MULTIMONITOR_FIX
2201 /* Only alternate index if the new custom mode differs from the last one
2202 * (only resolution and bpp changes are important, a display change does not matter).
2203 * Always add 2 last entries to the mode array, so number of video modes
2204 * do not change.
2205 */
2206 BOOLEAN fNewInvocation = FALSE;
2207 static uint32_t sPrev_xres = 0;
2208 static uint32_t sPrev_yres = 0;
2209 static uint32_t sPrev_bpp = 0;
2210 if ( sPrev_xres != xres
2211 || sPrev_yres != yres
2212 || sPrev_bpp != bpp)
2213 {
2214 sPrev_xres = xres;
2215 sPrev_yres = yres;
2216 sPrev_bpp = bpp;
2217 fNewInvocation = TRUE;
2218 }
2219 BOOLEAN fAlternatedIndex = FALSE;
2220#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2221#ifndef VBOX_WITH_WDDM
2222 if (DeviceExtension->CurrentMode != 0)
2223#else
2224 if (commonFromDeviceExt(DeviceExtension)->cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
2225#endif
2226#ifndef VBOX_WITH_MULTIMONITOR_FIX
2227 {
2228 if (gInvocationCounter % 2)
2229 gNumVideoModes++;
2230 gInvocationCounter++;
2231 }
2232#else
2233 {
2234 if (fNewInvocation)
2235 gInvocationCounter++;
2236 if (gInvocationCounter % 2)
2237 {
2238 fAlternatedIndex = TRUE;
2239
2240 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
2241 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2242 gNumVideoModes++;
2243 }
2244 }
2245 else
2246 {
2247 fNewInvocation = FALSE;
2248 }
2249#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2250
2251 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
2252#ifdef VBOX_WITH_MULTIMONITOR_FIX
2253 dprintf(("VBoxVideo: fNewInvocation = %d, fAlternatedIndex = %d\n", fNewInvocation, fAlternatedIndex));
2254#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2255#ifdef VBOX_WITH_WDDM
2256 /* assign host-supplied as the most preferable */
2257 gPreferredVideoMode = gNumVideoModes;
2258#endif
2259 /*
2260 * Build mode entry.
2261 * Note that we do not apply the y offset for the custom mode. It is
2262 * only used for the predefined modes that the user can configure in
2263 * the display properties dialog.
2264 */
2265 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
2266 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2267 VideoModes[gNumVideoModes].VisScreenWidth = xres;
2268 VideoModes[gNumVideoModes].VisScreenHeight = yres;
2269 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
2270 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
2271 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
2272 VideoModes[gNumVideoModes].Frequency = 60;
2273 VideoModes[gNumVideoModes].XMillimeter = 320;
2274 VideoModes[gNumVideoModes].YMillimeter = 240;
2275 switch (bpp)
2276 {
2277#ifdef VBOX_WITH_8BPP_MODES
2278 case 8:
2279 VideoModes[gNumVideoModes].NumberRedBits = 6;
2280 VideoModes[gNumVideoModes].NumberGreenBits = 6;
2281 VideoModes[gNumVideoModes].NumberBlueBits = 6;
2282 VideoModes[gNumVideoModes].RedMask = 0;
2283 VideoModes[gNumVideoModes].GreenMask = 0;
2284 VideoModes[gNumVideoModes].BlueMask = 0;
2285 break;
2286#endif
2287 case 16:
2288 VideoModes[gNumVideoModes].NumberRedBits = 5;
2289 VideoModes[gNumVideoModes].NumberGreenBits = 6;
2290 VideoModes[gNumVideoModes].NumberBlueBits = 5;
2291 VideoModes[gNumVideoModes].RedMask = 0xF800;
2292 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
2293 VideoModes[gNumVideoModes].BlueMask = 0x1F;
2294 break;
2295 case 24:
2296 VideoModes[gNumVideoModes].NumberRedBits = 8;
2297 VideoModes[gNumVideoModes].NumberGreenBits = 8;
2298 VideoModes[gNumVideoModes].NumberBlueBits = 8;
2299 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
2300 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
2301 VideoModes[gNumVideoModes].BlueMask = 0xFF;
2302 break;
2303 case 32:
2304 VideoModes[gNumVideoModes].NumberRedBits = 8;
2305 VideoModes[gNumVideoModes].NumberGreenBits = 8;
2306 VideoModes[gNumVideoModes].NumberBlueBits = 8;
2307 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
2308 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
2309 VideoModes[gNumVideoModes].BlueMask = 0xFF;
2310 break;
2311 }
2312 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
2313#ifdef VBOX_WITH_8BPP_MODES
2314 if (bpp == 8)
2315 VideoModes[gNumVideoModes].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
2316#endif
2317 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
2318 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres;
2319 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
2320#ifdef VBOX_WITH_MULTIMONITOR_FIX
2321 /* Save the mode in the list of custom modes for this display. */
2322 CustomVideoModes[DeviceExtension->iDevice] = VideoModes[gNumVideoModes];
2323#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2324 ++gNumVideoModes;
2325
2326 /* for the startup case, we need this mode twice due to the alternating mode number */
2327#ifndef VBOX_WITH_WDDM
2328 if (DeviceExtension->CurrentMode == 0)
2329#else
2330 if (!commonFromDeviceExt(DeviceExtension)->cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
2331#endif
2332 {
2333 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
2334 memcpy(&VideoModes[gNumVideoModes], &VideoModes[gNumVideoModes - 1], sizeof(VIDEO_MODE_INFORMATION));
2335 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2336 gNumVideoModes++;
2337 }
2338#ifdef VBOX_WITH_MULTIMONITOR_FIX
2339 else if (!fAlternatedIndex)
2340 {
2341 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
2342 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
2343 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
2344 gNumVideoModes++;
2345 }
2346#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2347
2348#ifndef VBOX_WITH_MULTIMONITOR_FIX
2349 /* store this video mode as the last custom video mode */
2350 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
2351 if (status != NO_ERROR)
2352 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
2353 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
2354 if (status != NO_ERROR)
2355 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
2356 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
2357 if (status != NO_ERROR)
2358 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
2359#else
2360 /* Save the custom mode for this display. */
2361 if (DeviceExtension->iDevice == 0)
2362 {
2363 /* Name without a suffix */
2364 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
2365 if (status != NO_ERROR)
2366 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
2367 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
2368 if (status != NO_ERROR)
2369 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
2370 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
2371 if (status != NO_ERROR)
2372 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
2373 }
2374 else
2375 {
2376 wchar_t keyname[32];
2377 swprintf(keyname, L"CustomXRes%d", DeviceExtension->iDevice);
2378 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
2379 if (status != NO_ERROR)
2380 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, DeviceExtension->iDevice));
2381 swprintf(keyname, L"CustomYRes%d", DeviceExtension->iDevice);
2382 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
2383 if (status != NO_ERROR)
2384 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, DeviceExtension->iDevice));
2385 swprintf(keyname, L"CustomBPP%d", DeviceExtension->iDevice);
2386 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
2387 if (status != NO_ERROR)
2388 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, DeviceExtension->iDevice));
2389 }
2390#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2391 }
2392 else
2393 {
2394 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
2395 xres, yres, bpp, vramSize));
2396 if (xres * yres * (bpp / 8) >= vramSize
2397 && (xres != g_xresNoVRAM || yres != g_yresNoVRAM || bpp != g_bppNoVRAM))
2398 {
2399 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
2400 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
2401 g_xresNoVRAM = xres;
2402 g_yresNoVRAM = yres;
2403 g_bppNoVRAM = bpp;
2404 }
2405 }
2406 }
2407 else
2408 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
2409 xres, yres, bpp));
2410 }
2411#if defined(LOG_ENABLED)
2412 {
2413 int i;
2414#ifndef VBOX_WITH_WDDM
2415 dprintf(("VBoxVideo: VideoModes (CurrentMode = %d, last #%d)\n", DeviceExtension->CurrentMode, gNumVideoModes));
2416#endif
2417 for (i = 0; i < RT_ELEMENTS(VideoModes); i++)
2418 {
2419 if ( VideoModes[i].VisScreenWidth
2420 || VideoModes[i].VisScreenHeight
2421 || VideoModes[i].BitsPerPlane)
2422 {
2423 dprintf((" %2d: #%d %4d x %4d @ %2d\n",
2424 i, VideoModes[i].ModeIndex, VideoModes[i].VisScreenWidth,
2425 VideoModes[i].VisScreenHeight, VideoModes[i].BitsPerPlane));
2426 }
2427 }
2428 }
2429#endif
2430
2431#ifdef VBOX_WITH_WDDM
2432 vboxWddmBuildResolutionTable();
2433#endif
2434
2435 VBoxVideoCmnRegFini(Reg);
2436}
2437
2438#endif
2439
2440#ifdef VBOX_WITH_WDDM
2441/**
2442 * Helper function to dynamically build our table of standard video
2443 * modes. We take the amount of VRAM and create modes with standard
2444 * geometries until we've either reached the maximum number of modes
2445 * or the available VRAM does not allow for additional modes.
2446 */
2447
2448AssertCompile(sizeof (SIZE) == sizeof (D3DKMDT_2DREGION));
2449AssertCompile(RT_OFFSETOF(SIZE, cx) == RT_OFFSETOF(D3DKMDT_2DREGION, cx));
2450AssertCompile(RT_OFFSETOF(SIZE, cy) == RT_OFFSETOF(D3DKMDT_2DREGION, cy));
2451static VOID vboxWddmBuildVideoModesInfo(PDEVICE_EXTENSION DeviceExtension, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId,
2452 PVBOXWDDM_VIDEOMODES_INFO pModes, VIDEO_MODE_INFORMATION *paAddlModes, UINT cAddlModes)
2453{
2454 pModes->cModes = RT_ELEMENTS(pModes->aModes);
2455 pModes->cResolutions = RT_ELEMENTS(pModes->aResolutions);
2456 vboxVideoBuildModesTable(DeviceExtension, VidPnTargetId, pModes->aModes, &pModes->cModes, &pModes->iPreferredMode);
2457 for (UINT i = 0; i < cAddlModes; ++i)
2458 {
2459 if (vboxVideoModeAdjustCheckSupported(DeviceExtension, VidPnTargetId, &paAddlModes[i]))
2460 {
2461 int iDx = vboxVideoModeAdd(pModes->aModes, RT_ELEMENTS(pModes->aModes), &pModes->cModes, &paAddlModes[i]);
2462 Assert(iDx >= 0);
2463 if (iDx >= 0)
2464 pModes->iPreferredMode = iDx;
2465 }
2466 }
2467#if 0
2468 if (pModes->cPrevModes == pModes->cModes)
2469 {
2470 Assert(pModes->cModes < RT_ELEMENTS(pModes->aModes));
2471 if (pModes->cModes < RT_ELEMENTS(pModes->aModes))
2472 {
2473 ULONG w = pModes->aModes[0].VisScreenWidth;
2474 ULONG h = pModes->aModes[0].VisScreenHeight;
2475 w += 8;
2476 h += 8;
2477
2478 if (vboxWddmFillMode(&pModes->aModes[pModes->cModes], D3DDDIFMT_A8R8G8B8, w, h))
2479 {
2480 pModes->aModes[pModes->cModes].ModeIndex = pModes->cModes;
2481 ++pModes->cModes;
2482 }
2483 else
2484 {
2485 Assert(0);
2486 }
2487 }
2488 VIDEO_MODE_INFORMATION TmpMode = pModes->aModes[1];
2489 pModes->aModes[1] = pModes->aModes[2];
2490 pModes->aModes[2] = TmpMode;
2491 }
2492#endif
2493 pModes->cPrevModes = pModes->cModes;
2494 vboxVideoBuildResolutionTable(pModes->aModes, pModes->cModes, (SIZE*)((void*)pModes->aResolutions), &pModes->cResolutions);
2495}
2496
2497NTSTATUS vboxWddmGetModesForResolution(VIDEO_MODE_INFORMATION *pAllModes, uint32_t cAllModes, int iSearchPreferredMode,
2498 const D3DKMDT_2DREGION *pResolution, VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode)
2499{
2500 NTSTATUS Status = STATUS_SUCCESS;
2501 uint32_t cFound = 0;
2502 int iFoundPreferrableMode = -1;
2503 for (uint32_t i = 0; i < cAllModes; ++i)
2504 {
2505 VIDEO_MODE_INFORMATION *pCur = &pAllModes[i];
2506 if (pResolution->cx == pCur->VisScreenWidth
2507 && pResolution->cy == pCur->VisScreenHeight)
2508 {
2509 if (pModes && cModes > cFound)
2510 memcpy(&pModes[cFound], pCur, sizeof (VIDEO_MODE_INFORMATION));
2511 else
2512 Status = STATUS_BUFFER_TOO_SMALL;
2513
2514 if (i == iSearchPreferredMode)
2515 iFoundPreferrableMode = cFound;
2516
2517 ++cFound;
2518 }
2519 }
2520
2521 Assert(iFoundPreferrableMode < 0 || cFound > (uint32_t)iFoundPreferrableMode);
2522
2523 *pcModes = cFound;
2524 if (piPreferrableMode)
2525 *piPreferrableMode = iFoundPreferrableMode;
2526
2527 return Status;
2528}
2529
2530int vboxWddmVideoResolutionFind(const D3DKMDT_2DREGION *pResolutions, int cResolutions, const D3DKMDT_2DREGION *pRes)
2531{
2532 for (int i = 0; i < cResolutions; ++i)
2533 {
2534 const D3DKMDT_2DREGION *pResolution = &pResolutions[i];
2535 if (pResolution->cx == pRes->cx && pResolution->cy == pRes->cy)
2536 return i;
2537 }
2538 return -1;
2539}
2540
2541bool vboxWddmVideoResolutionsMatch(const D3DKMDT_2DREGION *pResolutions1, const D3DKMDT_2DREGION *pResolutions2, int cResolutions)
2542{
2543 for (int i = 0; i < cResolutions; ++i)
2544 {
2545 const D3DKMDT_2DREGION * pRes1 = &pResolutions1[i];
2546 int j = 0;
2547 for (;j < cResolutions; ++j)
2548 {
2549 const D3DKMDT_2DREGION * pRes2 = &pResolutions2[j];
2550 if (pRes1->cx == pRes2->cx && pRes1->cy == pRes2->cy)
2551 break;
2552 }
2553
2554 if (j == cResolutions)
2555 {
2556 return false;
2557 }
2558 }
2559 return true;
2560}
2561
2562bool vboxWddmVideoModesMatch(const VIDEO_MODE_INFORMATION *pModes1, const VIDEO_MODE_INFORMATION *pModes2, int cModes)
2563{
2564 for (int i = 0; i < cModes; ++i)
2565 {
2566 const VIDEO_MODE_INFORMATION *pM1 = &pModes1[i];
2567 int j = 0;
2568 for (;j < cModes; ++j)
2569 {
2570 const VIDEO_MODE_INFORMATION *pM2 = &pModes2[j];
2571
2572 if (pM1->VisScreenHeight == pM2->VisScreenHeight
2573 && pM1->VisScreenWidth == pM2->VisScreenWidth
2574 && pM1->BitsPerPlane == pM2->BitsPerPlane)
2575 break;
2576 }
2577
2578 if (j == cModes)
2579 {
2580 return false;
2581 }
2582 }
2583 return true;
2584}
2585
2586D3DDDIFORMAT vboxWddmCalcPixelFormat(const VIDEO_MODE_INFORMATION *pInfo)
2587{
2588 switch (pInfo->BitsPerPlane)
2589 {
2590 case 32:
2591 if(!(pInfo->AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN) && !(pInfo->AttributeFlags & VIDEO_MODE_MANAGED_PALETTE))
2592 {
2593 if (pInfo->RedMask == 0xFF0000 && pInfo->GreenMask == 0xFF00 && pInfo->BlueMask == 0xFF)
2594 return D3DDDIFMT_A8R8G8B8;
2595 drprintf((__FUNCTION__": unsupported format: bpp(%d), rmask(%d), gmask(%d), bmask(%d)\n", pInfo->BitsPerPlane, pInfo->RedMask, pInfo->GreenMask, pInfo->BlueMask));
2596 AssertBreakpoint();
2597 }
2598 else
2599 {
2600 drprintf((__FUNCTION__": unsupported AttributeFlags(0x%x)\n", pInfo->AttributeFlags));
2601 AssertBreakpoint();
2602 }
2603 break;
2604 case 24:
2605 if(!(pInfo->AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN) && !(pInfo->AttributeFlags & VIDEO_MODE_MANAGED_PALETTE))
2606 {
2607 if (pInfo->RedMask == 0xFF0000 && pInfo->GreenMask == 0xFF00 && pInfo->BlueMask == 0xFF)
2608 return D3DDDIFMT_R8G8B8;
2609 drprintf((__FUNCTION__": unsupported format: bpp(%d), rmask(%d), gmask(%d), bmask(%d)\n", pInfo->BitsPerPlane, pInfo->RedMask, pInfo->GreenMask, pInfo->BlueMask));
2610 AssertBreakpoint();
2611 }
2612 else
2613 {
2614 drprintf((__FUNCTION__": unsupported AttributeFlags(0x%x)\n", pInfo->AttributeFlags));
2615 AssertBreakpoint();
2616 }
2617 break;
2618 case 16:
2619 if(!(pInfo->AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN) && !(pInfo->AttributeFlags & VIDEO_MODE_MANAGED_PALETTE))
2620 {
2621 if (pInfo->RedMask == 0xF800 && pInfo->GreenMask == 0x7E0 && pInfo->BlueMask == 0x1F)
2622 return D3DDDIFMT_R5G6B5;
2623 drprintf((__FUNCTION__": unsupported format: bpp(%d), rmask(%d), gmask(%d), bmask(%d)\n", pInfo->BitsPerPlane, pInfo->RedMask, pInfo->GreenMask, pInfo->BlueMask));
2624 AssertBreakpoint();
2625 }
2626 else
2627 {
2628 drprintf((__FUNCTION__": unsupported AttributeFlags(0x%x)\n", pInfo->AttributeFlags));
2629 AssertBreakpoint();
2630 }
2631 break;
2632 case 8:
2633 if((pInfo->AttributeFlags & VIDEO_MODE_PALETTE_DRIVEN) && (pInfo->AttributeFlags & VIDEO_MODE_MANAGED_PALETTE))
2634 {
2635 return D3DDDIFMT_P8;
2636 }
2637 else
2638 {
2639 drprintf((__FUNCTION__": unsupported AttributeFlags(0x%x)\n", pInfo->AttributeFlags));
2640 AssertBreakpoint();
2641 }
2642 break;
2643 default:
2644 drprintf((__FUNCTION__": unsupported bpp(%d)\n", pInfo->BitsPerPlane));
2645 AssertBreakpoint();
2646 break;
2647 }
2648
2649 return D3DDDIFMT_UNKNOWN;
2650}
2651
2652bool vboxWddmFillMode(VIDEO_MODE_INFORMATION *pInfo, D3DDDIFORMAT enmFormat, ULONG w, ULONG h)
2653{
2654 pInfo->VisScreenWidth = w;
2655 pInfo->VisScreenHeight = h;
2656 pInfo->VideoMemoryBitmapWidth = w;
2657 pInfo->VideoMemoryBitmapHeight = h;
2658 pInfo->XMillimeter = 320;
2659 pInfo->YMillimeter = 240;
2660
2661 switch (enmFormat)
2662 {
2663 case D3DDDIFMT_A8R8G8B8:
2664 pInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
2665 pInfo->BitsPerPlane = 32;
2666 pInfo->RedMask = 0xFF0000;
2667 pInfo->GreenMask = 0xFF00;
2668 pInfo->BlueMask = 0xFF;
2669 pInfo->ScreenStride = pInfo->VisScreenWidth * pInfo->BitsPerPlane / 8;
2670 return true;
2671 case D3DDDIFMT_R8G8B8:
2672 pInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
2673 pInfo->BitsPerPlane = 24;
2674 pInfo->RedMask = 0xFF0000;
2675 pInfo->GreenMask = 0xFF00;
2676 pInfo->BlueMask = 0xFF;
2677 pInfo->ScreenStride = pInfo->VisScreenWidth * pInfo->BitsPerPlane / 8;
2678 return true;
2679 case D3DDDIFMT_R5G6B5:
2680 pInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
2681 pInfo->BitsPerPlane = 16;
2682 pInfo->RedMask = 0xF800;
2683 pInfo->GreenMask = 0x7E0;
2684 pInfo->BlueMask = 0x1F;
2685 pInfo->ScreenStride = pInfo->VisScreenWidth * pInfo->BitsPerPlane / 8;
2686 return true;
2687 case D3DDDIFMT_P8:
2688 pInfo->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN | VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
2689 pInfo->BitsPerPlane = 8;
2690 pInfo->RedMask = 0;
2691 pInfo->GreenMask = 0;
2692 pInfo->BlueMask = 0;
2693 pInfo->ScreenStride = pInfo->VisScreenWidth * pInfo->BitsPerPlane / 8;
2694 return true;
2695 default:
2696 drprintf((__FUNCTION__": unsupported enmFormat(%d)\n", enmFormat));
2697 AssertBreakpoint();
2698 break;
2699 }
2700
2701 return false;
2702}
2703
2704static VBOXWDDM_VIDEOMODES_INFO g_aVBoxVideoModeInfos[VBOX_VIDEO_MAX_SCREENS] = {0};
2705
2706PVBOXWDDM_VIDEOMODES_INFO vboxWddmGetVideoModesInfo(PDEVICE_EXTENSION DeviceExtension, D3DDDI_VIDEO_PRESENT_TARGET_ID VidPnTargetId)
2707{
2708 Assert(VidPnTargetId < (D3DDDI_VIDEO_PRESENT_TARGET_ID)commonFromDeviceExt(DeviceExtension)->cDisplays);
2709 if (VidPnTargetId >= (D3DDDI_VIDEO_PRESENT_TARGET_ID)commonFromDeviceExt(DeviceExtension)->cDisplays)
2710 {
2711 return NULL;
2712 }
2713
2714 PVBOXWDDM_VIDEOMODES_INFO pInfo = &g_aVBoxVideoModeInfos[VidPnTargetId];
2715
2716 if (!pInfo->cModes)
2717 {
2718 vboxWddmBuildVideoModesInfo(DeviceExtension, VidPnTargetId, pInfo, NULL, 0);
2719 Assert(pInfo->cModes);
2720 }
2721
2722 return pInfo;
2723}
2724
2725PVBOXWDDM_VIDEOMODES_INFO vboxWddmGetAllVideoModesInfos(PDEVICE_EXTENSION DeviceExtension)
2726{
2727 /* ensure all modes are initialized */
2728 for (int i = 0; i < commonFromDeviceExt(DeviceExtension)->cDisplays; ++i)
2729 {
2730 vboxWddmGetVideoModesInfo(DeviceExtension, (D3DDDI_VIDEO_PRESENT_TARGET_ID)i);
2731 }
2732
2733 return g_aVBoxVideoModeInfos;
2734}
2735
2736VOID vboxWddmInvalidateVideoModesInfo(PDEVICE_EXTENSION DeviceExtension)
2737{
2738 for (UINT i = 0; i < RT_ELEMENTS(g_aVBoxVideoModeInfos); ++i)
2739 {
2740 g_aVBoxVideoModeInfos[i].cModes = 0;
2741 }
2742}
2743
2744PVBOXWDDM_VIDEOMODES_INFO vboxWddmUpdateVideoModesInfo(PDEVICE_EXTENSION DeviceExtension, PVBOXWDDM_RECOMMENDVIDPN pVidPnInfo)
2745{
2746 vboxWddmInvalidateVideoModesInfo(DeviceExtension);
2747
2748 if (pVidPnInfo)
2749 {
2750 for (UINT i = 0; i < pVidPnInfo->cScreenInfos; ++i)
2751 {
2752 PVBOXWDDM_RECOMMENDVIDPN_SCREEN_INFO pScreenInfo = &pVidPnInfo->aScreenInfos[i];
2753 Assert(pScreenInfo->Id < (DWORD)commonFromDeviceExt(DeviceExtension)->cDisplays);
2754 if (pScreenInfo->Id < (DWORD)commonFromDeviceExt(DeviceExtension)->cDisplays)
2755 {
2756 PVBOXWDDM_VIDEOMODES_INFO pInfo = &g_aVBoxVideoModeInfos[pScreenInfo->Id];
2757 VIDEO_MODE_INFORMATION ModeInfo = {0};
2758 D3DDDIFORMAT enmFormat;
2759 switch (pScreenInfo->BitsPerPixel)
2760 {
2761 case 32:
2762 enmFormat = D3DDDIFMT_A8R8G8B8;
2763 break;
2764 case 24:
2765 enmFormat = D3DDDIFMT_R8G8B8;
2766 break;
2767 case 16:
2768 enmFormat = D3DDDIFMT_R5G6B5;
2769 break;
2770 case 8:
2771 enmFormat = D3DDDIFMT_P8;
2772 break;
2773 default:
2774 Assert(0);
2775 enmFormat = D3DDDIFMT_UNKNOWN;
2776 break;
2777 }
2778 if (enmFormat != D3DDDIFMT_UNKNOWN)
2779 {
2780 if (vboxWddmFillMode(&ModeInfo, enmFormat, pScreenInfo->Width, pScreenInfo->Height))
2781 {
2782 vboxWddmBuildVideoModesInfo(DeviceExtension, pScreenInfo->Id, pInfo, &ModeInfo, 1);
2783 }
2784 else
2785 {
2786 Assert(0);
2787 }
2788 }
2789 }
2790 }
2791 }
2792
2793 /* ensure we have all the rest populated */
2794 vboxWddmGetAllVideoModesInfos(DeviceExtension);
2795 return g_aVBoxVideoModeInfos;
2796}
2797
2798#else
2799
2800/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
2801void VBoxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
2802{
2803 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
2804 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
2805 - VBVA_ADAPTER_INFORMATION_SIZE;
2806
2807 /* Size of a framebuffer. */
2808
2809 ULONG ulSize = ulAvailable / commonFromDeviceExt(PrimaryExtension)->cDisplays;
2810
2811 /* Align down to 4096 bytes. */
2812 ulSize &= ~0xFFF;
2813
2814 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
2815 commonFromDeviceExt(PrimaryExtension)->cbVRAM, commonFromDeviceExt(PrimaryExtension)->cDisplays,
2816 ulSize, ulSize * commonFromDeviceExt(PrimaryExtension)->cDisplays,
2817 ulAvailable - ulSize * commonFromDeviceExt(PrimaryExtension)->cDisplays));
2818
2819
2820 /* Update the primary info. */
2821 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
2822
2823 /* Update the per extension info. */
2824 PDEVICE_EXTENSION Extension = PrimaryExtension;
2825 ULONG ulFrameBufferOffset = 0;
2826 while (Extension)
2827 {
2828 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
2829 /* That is assigned when a video mode is set. */
2830 Extension->ulFrameBufferSize = 0;
2831
2832 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
2833 Extension->iDevice, ulFrameBufferOffset));
2834
2835 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
2836
2837 Extension = Extension->pNext;
2838 }
2839}
2840
2841#endif
2842
2843int VBoxMapAdapterMemory (PVBOXVIDEO_COMMON pCommon, void **ppv, uint32_t ulOffset, uint32_t ulSize)
2844{
2845 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2846 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
2847
2848 if (!ulSize)
2849 {
2850 dprintf(("Illegal length 0!\n"));
2851 return ERROR_INVALID_PARAMETER;
2852 }
2853
2854 PHYSICAL_ADDRESS FrameBuffer;
2855 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
2856
2857 PVOID VideoRamBase = NULL;
2858 ULONG VideoRamLength = ulSize;
2859 VP_STATUS Status;
2860#ifndef VBOX_WITH_WDDM
2861 ULONG inIoSpace = 0;
2862
2863 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
2864 &VideoRamLength, &inIoSpace,
2865 &VideoRamBase);
2866#else
2867 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
2868 FrameBuffer,
2869 VideoRamLength,
2870 FALSE, /* IN BOOLEAN InIoSpace */
2871 FALSE, /* IN BOOLEAN MapToUserMode */
2872 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
2873 &VideoRamBase /*OUT PVOID *VirtualAddress*/
2874 );
2875 Assert(ntStatus == STATUS_SUCCESS);
2876 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
2877#endif
2878
2879 if (Status == NO_ERROR)
2880 {
2881 *ppv = VideoRamBase;
2882 }
2883
2884 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
2885
2886 return Status;
2887}
2888
2889bool VBoxSyncToVideoIRQ(PVBOXVIDEO_COMMON pCommon, PFNVIDEOIRQSYNC pfnSync,
2890 void *pvUser)
2891{
2892 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2893 PMINIPORT_SYNCHRONIZE_ROUTINE pfnSyncMiniport;
2894 pfnSyncMiniport = (PMINIPORT_SYNCHRONIZE_ROUTINE) pfnSync;
2895#ifndef VBOX_WITH_WDDM
2896 return !!VideoPortSynchronizeExecution(PrimaryExtension, VpMediumPriority,
2897 pfnSyncMiniport, pvUser);
2898#else
2899 BOOLEAN fRet;
2900 DXGKCB_SYNCHRONIZE_EXECUTION pfnDxgkCbSync =
2901 PrimaryExtension->u.primary.DxgkInterface.DxgkCbSynchronizeExecution;
2902 HANDLE hDev = PrimaryExtension->u.primary.DxgkInterface.DeviceHandle;
2903 NTSTATUS ntStatus = pfnDxgkCbSync(hDev, pfnSyncMiniport, pvUser, 0, &fRet);
2904 AssertReturn(ntStatus == STATUS_SUCCESS, false);
2905 return !!fRet;
2906#endif
2907}
2908
2909void VBoxUnmapAdapterMemory (PVBOXVIDEO_COMMON pCommon, void **ppv)
2910{
2911 dprintf(("VBoxVideo::VBoxUnmapAdapterMemory\n"));
2912
2913 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2914
2915 if (*ppv)
2916 {
2917#ifndef VBOX_WITH_WDDM
2918 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
2919#else
2920 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
2921 *ppv);
2922 Assert(ntStatus == STATUS_SUCCESS);
2923#endif
2924 }
2925
2926 *ppv = NULL;
2927}
2928
2929
2930void vboxVideoInitCustomVideoModes(PDEVICE_EXTENSION pDevExt)
2931{
2932 VP_STATUS status;
2933 VBOXCMNREG Reg;
2934
2935 VBoxVideoCmnRegInit(pDevExt, &Reg);
2936
2937 dprintf(("VBoxVideo::vboxVideoInitCustomVideoModes\n"));
2938
2939#ifndef VBOX_WITH_MULTIMONITOR_FIX
2940 /*
2941 * Get the last custom resolution
2942 */
2943 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &gCustomXRes);
2944 if (status != NO_ERROR)
2945 gCustomXRes = 0;
2946
2947 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &gCustomYRes);
2948 if (status != NO_ERROR)
2949 gCustomYRes = 0;
2950 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &gCustomBPP);
2951 if (status != NO_ERROR)
2952 gCustomBPP = 0;
2953
2954 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
2955#else
2956 /* Initialize all custom modes to the 800x600x32. */
2957 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
2958
2959 int iCustomMode;
2960 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
2961 {
2962 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
2963 }
2964
2965 /* Load stored custom resolution from the registry. */
2966 for (iCustomMode = 0;
2967#ifdef VBOX_WITH_WDDM
2968 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
2969#else
2970 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
2971#endif
2972 iCustomMode++)
2973 {
2974 /*
2975 * Get the last custom resolution
2976 */
2977 uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
2978
2979 if (iCustomMode == 0)
2980 {
2981 /* Name without a suffix */
2982 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &CustomXRes);
2983 if (status != NO_ERROR)
2984 CustomXRes = 0;
2985 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &CustomYRes);
2986 if (status != NO_ERROR)
2987 CustomYRes = 0;
2988 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &CustomBPP);
2989 if (status != NO_ERROR)
2990 CustomBPP = 0;
2991 }
2992 else
2993 {
2994 wchar_t keyname[32];
2995 swprintf(keyname, L"CustomXRes%d", iCustomMode);
2996 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomXRes);
2997 if (status != NO_ERROR)
2998 CustomXRes = 0;
2999 swprintf(keyname, L"CustomYRes%d", iCustomMode);
3000 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomYRes);
3001 if (status != NO_ERROR)
3002 CustomYRes = 0;
3003 swprintf(keyname, L"CustomBPP%d", iCustomMode);
3004 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomBPP);
3005 if (status != NO_ERROR)
3006 CustomBPP = 0;
3007 }
3008
3009 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
3010
3011 if (CustomXRes || CustomYRes || CustomBPP)
3012 {
3013 if (CustomXRes == 0)
3014 {
3015 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
3016 }
3017 if (CustomYRes == 0)
3018 {
3019 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
3020 }
3021 if (CustomBPP == 0)
3022 {
3023 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
3024 }
3025
3026 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
3027 }
3028 }
3029#endif /* VBOX_WITH_MULTIMONITOR_FIX */
3030
3031 VBoxVideoCmnRegFini(Reg);
3032}
3033
3034#ifndef VBOX_WITH_WDDM
3035DECLCALLBACK(int) vbvaInitInfoDisplay (void *pvData, struct VBVAINFOVIEW *p,
3036 uint32_t cViews)
3037{
3038 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION) pvData;
3039
3040 unsigned i;
3041 PDEVICE_EXTENSION Extension;
3042
3043 for (i = 0, Extension = PrimaryExtension; i < cViews && Extension;
3044 i++, Extension = Extension->pNext)
3045 {
3046 p[i].u32ViewIndex = Extension->iDevice;
3047 p[i].u32ViewOffset = Extension->ulFrameBufferOffset;
3048 p[i].u32ViewSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
3049
3050 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
3051 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
3052
3053 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
3054 p[i].u32ViewSize - cbReservedVRAM:
3055 0;
3056 }
3057
3058 if (i == commonFromDeviceExt(PrimaryExtension)->cDisplays && Extension == NULL)
3059 {
3060 return VINF_SUCCESS;
3061 }
3062
3063 AssertFailed ();
3064 return VERR_INTERNAL_ERROR;
3065}
3066
3067
3068static VOID VBoxCreateDisplaysXPDM(PDEVICE_EXTENSION PrimaryExtension,
3069 PVIDEO_PORT_CONFIG_INFO pConfigInfo)
3070{
3071 VP_STATUS rc;
3072
3073 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
3074 {
3075 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
3076 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
3077
3078 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
3079 if (vboxQueryWinVersion() > WINNT4)
3080 {
3081 /* This bluescreens on NT4, hence the above version check */
3082 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
3083 (PrimaryExtension,
3084 (PUCHAR)"VideoPortCreateSecondaryDisplay");
3085 }
3086
3087 if (!pfnCreateSecondaryDisplay)
3088 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
3089 else
3090 {
3091 PDEVICE_EXTENSION pPrev = PrimaryExtension;
3092
3093 ULONG iDisplay;
3094 ULONG cDisplays = commonFromDeviceExt(PrimaryExtension)->cDisplays;
3095 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
3096 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
3097 {
3098 PDEVICE_EXTENSION SecondaryExtension = NULL;
3099 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
3100
3101 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
3102 rc, SecondaryExtension));
3103
3104 if (rc != NO_ERROR)
3105 {
3106 break;
3107 }
3108
3109 SecondaryExtension->pNext = NULL;
3110 SecondaryExtension->pPrimary = PrimaryExtension;
3111 SecondaryExtension->iDevice = iDisplay;
3112 SecondaryExtension->ulFrameBufferOffset = 0;
3113 SecondaryExtension->ulFrameBufferSize = 0;
3114 SecondaryExtension->u.secondary.bEnabled = FALSE;
3115
3116 /* Update the list pointers. */
3117 pPrev->pNext = SecondaryExtension;
3118 pPrev = SecondaryExtension;
3119
3120 /* Take the successfully created display into account. */
3121 commonFromDeviceExt(PrimaryExtension)->cDisplays++;
3122 }
3123 }
3124
3125 /* Failure to create secondary displays is not fatal */
3126 rc = NO_ERROR;
3127 }
3128
3129 /* Now when the number of monitors is known and extensions are created,
3130 * calculate the layout of framebuffers.
3131 */
3132 VBoxComputeFrameBufferSizes (PrimaryExtension);
3133 /* in case of WDDM we do not control the framebuffer location,
3134 * i.e. it is assigned by Video Memory Manager,
3135 * The FB information should be passed to guest from our
3136 * DxgkDdiSetVidPnSourceAddress callback */
3137
3138 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
3139 {
3140 if (RT_SUCCESS(rc))
3141 {
3142 rc = VBoxHGSMISendViewInfo(&commonFromDeviceExt(PrimaryExtension)->guestCtx,
3143 commonFromDeviceExt(PrimaryExtension)->cDisplays,
3144 vbvaInitInfoDisplay,
3145 (void *) PrimaryExtension);
3146 AssertRC(rc);
3147 }
3148
3149 if (RT_FAILURE (rc))
3150 {
3151 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
3152 }
3153 }
3154}
3155
3156VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
3157 IN PVOID HwContext, IN PWSTR ArgumentString,
3158 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
3159 OUT PUCHAR Again)
3160{
3161 VP_STATUS rc;
3162 USHORT DispiId;
3163 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
3164
3165 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
3166
3167 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
3168
3169 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
3170 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
3171 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
3172 if (DispiId == VBE_DISPI_ID2)
3173 {
3174 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
3175 /*
3176 * Write some hardware information to registry, so that
3177 * it's visible in Windows property dialog.
3178 */
3179
3180 rc = VideoPortSetRegistryParameters(
3181 HwDeviceExtension,
3182 L"HardwareInformation.ChipType",
3183 VBoxChipType,
3184 sizeof(VBoxChipType));
3185
3186 rc = VideoPortSetRegistryParameters(
3187 HwDeviceExtension,
3188 L"HardwareInformation.DacType",
3189 VBoxDACType,
3190 sizeof(VBoxDACType));
3191
3192 /*
3193 * Query the adapter's memory size. It's a bit of a hack, we just read
3194 * an ULONG from the data port without setting an index before.
3195 */
3196 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
3197 rc = VideoPortSetRegistryParameters(
3198 HwDeviceExtension,
3199 L"HardwareInformation.MemorySize",
3200 &AdapterMemorySize,
3201 sizeof(ULONG));
3202
3203 rc = VideoPortSetRegistryParameters(
3204 HwDeviceExtension,
3205 L"HardwareInformation.AdapterString",
3206 VBoxAdapterString,
3207 sizeof(VBoxAdapterString));
3208
3209 rc = VideoPortSetRegistryParameters(
3210 HwDeviceExtension,
3211 L"HardwareInformation.BiosString",
3212 VBoxBiosString,
3213 sizeof(VBoxBiosString));
3214
3215 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
3216
3217 VIDEO_ACCESS_RANGE tmpRanges[4];
3218 ULONG slot = 0;
3219
3220 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
3221
3222 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
3223 VP_STATUS status;
3224 if (vboxQueryWinVersion() == WINNT4)
3225 {
3226 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
3227 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
3228 */
3229 ULONG vendorId = 0x80EE;
3230 ULONG deviceId = 0xBEEF;
3231 status = VideoPortGetAccessRanges(HwDeviceExtension,
3232 0,
3233 NULL,
3234 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
3235 tmpRanges,
3236 &vendorId,
3237 &deviceId,
3238 &slot);
3239 }
3240 else
3241 {
3242 status = VideoPortGetAccessRanges(HwDeviceExtension,
3243 0,
3244 NULL,
3245 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
3246 tmpRanges,
3247 NULL,
3248 NULL,
3249 &slot);
3250 }
3251 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
3252
3253 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
3254 rc = VbglInit ();
3255 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
3256
3257 /* Preinitialize the primary extension.
3258 */
3259 ((PDEVICE_EXTENSION)HwDeviceExtension)->pNext = NULL;
3260 ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary = (PDEVICE_EXTENSION)HwDeviceExtension;
3261 ((PDEVICE_EXTENSION)HwDeviceExtension)->iDevice = 0;
3262 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferOffset = 0;
3263 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferSize = 0;
3264 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.ulVbvaEnabled = 0;
3265 VBoxVideoCmnMemZero(&((PDEVICE_EXTENSION)HwDeviceExtension)->areaDisplay, sizeof(HGSMIAREA));
3266 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
3267 * code will be ifdef'ed and later removed.
3268 * The host will however support both old and new interface to keep compatibility
3269 * with old guest additions.
3270 */
3271 VBoxSetupDisplaysHGSMI(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension),
3272 AdapterMemorySize, 0);
3273
3274 if (commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension)->bHGSMI)
3275 {
3276 LogRel(("VBoxVideo: using HGSMI\n"));
3277 VBoxCreateDisplaysXPDM((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo);
3278 }
3279
3280 // pretend success to make the driver work.
3281 rc = NO_ERROR;
3282 } else
3283 {
3284 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
3285 rc = ERROR_DEV_NOT_EXIST;
3286 }
3287 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
3288 return rc;
3289}
3290
3291/**
3292 * VBoxVideoInitialize
3293 *
3294 * Performs the first initialization of the adapter, after the HAL has given
3295 * up control of the video hardware to the video port driver.
3296 */
3297BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
3298{
3299 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
3300
3301 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3302 USHORT DispiId;
3303
3304 /* Initialize the request pointer. */
3305 pDevExt->u.primary.pvReqFlush = NULL;
3306
3307 /* Check if the chip restricts horizontal resolution or not. */
3308 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
3309 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
3310 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
3311 if (DispiId == VBE_DISPI_ID_ANYX)
3312 pDevExt->fAnyX = TRUE;
3313 else
3314 pDevExt->fAnyX = FALSE;
3315
3316 vboxVideoInitCustomVideoModes(pDevExt);
3317
3318 return TRUE;
3319}
3320
3321# ifdef VBOX_WITH_VIDEOHWACCEL
3322
3323static VOID VBoxVideoHGSMIDpc(
3324 IN PVOID HwDeviceExtension,
3325 IN PVOID Context
3326 )
3327{
3328 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
3329
3330 VBoxHGSMIProcessHostQueue(&commonFromDeviceExt(PrimaryExtension)->hostCtx);
3331}
3332
3333BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
3334{
3335 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3336 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
3337 if (PrimaryExtension)
3338 {
3339 if (commonFromDeviceExt(PrimaryExtension)->hostCtx.pfHostFlags) /* If HGSMI is enabled at all. */
3340 {
3341 uint32_t flags = commonFromDeviceExt(PrimaryExtension)->hostCtx.pfHostFlags->u32HostFlags;
3342 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
3343 {
3344 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
3345 {
3346 /* schedule a DPC*/
3347 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, NULL);
3348 Assert(bResult);
3349 }
3350 /* clear the IRQ */
3351 VBoxHGSMIClearIrq(&commonFromDeviceExt(PrimaryExtension)->hostCtx);
3352 return TRUE;
3353 }
3354 }
3355 }
3356 return FALSE;
3357}
3358# endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
3359#endif /* #ifndef VBOX_WITH_WDDM */
3360/**
3361 * Send a request to the host to make the absolute pointer visible
3362 */
3363static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
3364{
3365 BOOLEAN Result = TRUE;
3366
3367 /* Use primary device extension, because the show pointer request should be processed
3368 * in vboxUpdatePointerShape regardless of the device. */
3369#ifndef VBOX_WITH_WDDM
3370 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
3371#else
3372 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
3373#endif
3374
3375 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
3376 {
3377 // tell the host to use the guest's pointer
3378 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3379
3380 /* Visible and No Shape means Show the pointer.
3381 * It is enough to init only this field.
3382 */
3383 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
3384
3385 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt(PrimaryExtension), &PointerAttributes, sizeof (PointerAttributes));
3386
3387 if (Result)
3388 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
3389 else
3390 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
3391 }
3392 return Result;
3393}
3394
3395#ifndef VBOX_WITH_WDDM
3396/**
3397 * VBoxVideoStartIO
3398 *
3399 * Processes the specified Video Request Packet.
3400 */
3401BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
3402 PVIDEO_REQUEST_PACKET RequestPacket)
3403{
3404 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3405
3406 BOOLEAN Result;
3407
3408// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
3409
3410 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3411
3412 switch (RequestPacket->IoControlCode)
3413 {
3414 case IOCTL_VIDEO_SET_CURRENT_MODE:
3415 {
3416 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
3417 {
3418 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3419 return TRUE;
3420 }
3421 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
3422 (PVIDEO_MODE)RequestPacket->InputBuffer,
3423 RequestPacket->StatusBlock);
3424 break;
3425 }
3426
3427 case IOCTL_VIDEO_RESET_DEVICE:
3428 {
3429 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
3430 RequestPacket->StatusBlock);
3431 break;
3432 }
3433
3434 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
3435 {
3436 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
3437 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
3438 {
3439 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3440 return TRUE;
3441 }
3442 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
3443 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
3444 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
3445 RequestPacket->StatusBlock);
3446 break;
3447 }
3448
3449 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
3450 {
3451 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
3452 {
3453 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3454 return TRUE;
3455 }
3456 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
3457 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
3458 RequestPacket->StatusBlock);
3459 break;
3460 }
3461
3462 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
3463 {
3464 PVIDEO_SHARE_MEMORY pShareMemory;
3465 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
3466 PHYSICAL_ADDRESS shareAddress;
3467 PVOID virtualAddress = NULL;
3468 ULONG sharedViewSize;
3469 ULONG inIoSpace = 0;
3470 VP_STATUS status;
3471
3472 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
3473
3474 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
3475 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
3476
3477 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
3478 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3479 Result = FALSE;
3480 break;
3481 }
3482
3483 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
3484
3485 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
3486 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
3487
3488 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY - ERROR_INVALID_PARAMETER %x:%x size %x\n", pShareMemory->ViewOffset, pShareMemory->ViewSize, pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize));
3489 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
3490 Result = FALSE;
3491 break;
3492 }
3493
3494 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
3495
3496 virtualAddress = pShareMemory->ProcessHandle;
3497 sharedViewSize = pShareMemory->ViewSize;
3498
3499 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
3500
3501 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
3502 if (status != NO_ERROR)
3503 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
3504 Result = (status == NO_ERROR);
3505
3506 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
3507 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
3508 pShareMemoryInformation->VirtualAddress = virtualAddress;
3509 pShareMemoryInformation->SharedViewSize = sharedViewSize;
3510 break;
3511 }
3512
3513 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
3514 {
3515 PVIDEO_SHARE_MEMORY pShareMemory;
3516 VP_STATUS status;
3517
3518 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
3519
3520 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
3521 {
3522 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
3523 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3524 Result = FALSE;
3525 break;
3526 }
3527
3528 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
3529
3530 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
3531 if (status != NO_ERROR)
3532 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
3533 Result = (status == NO_ERROR);
3534 break;
3535 }
3536
3537 /*
3538 * The display driver asks us how many video modes we support
3539 * so that it can supply an appropriate buffer for the next call.
3540 */
3541 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
3542 {
3543 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
3544 {
3545 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3546 return TRUE;
3547 }
3548 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
3549 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
3550 RequestPacket->StatusBlock);
3551 break;
3552 }
3553
3554 /*
3555 * The display driver asks us to provide a list of supported video modes
3556 * into a buffer it has allocated.
3557 */
3558 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
3559 {
3560 if (RequestPacket->OutputBufferLength <
3561 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
3562 {
3563 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3564 return TRUE;
3565 }
3566 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
3567 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
3568 RequestPacket->StatusBlock);
3569 break;
3570 }
3571
3572 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
3573 {
3574 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
3575 RequestPacket->InputBufferLength <
3576 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
3577 sizeof(VIDEO_CLUT))
3578 {
3579 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3580 return TRUE;
3581 }
3582 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
3583 (PVIDEO_CLUT)RequestPacket->InputBuffer,
3584 RequestPacket->StatusBlock);
3585 break;
3586 }
3587
3588 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
3589 {
3590 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
3591 {
3592 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3593 return TRUE;
3594 }
3595 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
3596 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
3597 RequestPacket->StatusBlock);
3598 break;
3599 }
3600
3601 // show the pointer
3602 case IOCTL_VIDEO_ENABLE_POINTER:
3603 {
3604 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
3605 // find out whether the host wants absolute positioning
3606 /// @todo this is now obsolete - remove it?
3607 if (vboxQueryHostWantsAbsolute())
3608 Result = ShowPointer(HwDeviceExtension);
3609 else
3610 {
3611 // fallback to software pointer
3612 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3613 Result = FALSE;
3614 }
3615 break;
3616 }
3617
3618 // hide the pointer
3619 case IOCTL_VIDEO_DISABLE_POINTER:
3620 {
3621 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
3622 // find out whether the host wants absolute positioning
3623 if (vboxQueryHostWantsAbsolute())
3624 {
3625 // tell the host to hide pointer
3626 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3627
3628 /* Enable == 0 means no shape, not visible.
3629 * It is enough to init only this field.
3630 */
3631 PointerAttributes.Enable = 0;
3632
3633 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension), &PointerAttributes, sizeof (PointerAttributes));
3634
3635 if (Result)
3636 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
3637 else
3638 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
3639 } else
3640 {
3641 // fallback to software pointer
3642 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3643 Result = FALSE;
3644 }
3645 break;
3646 }
3647
3648 /*
3649 * Change the pointer shape
3650 */
3651 case IOCTL_VIDEO_SET_POINTER_ATTR:
3652 {
3653 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
3654 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
3655 {
3656 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
3657 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3658 return TRUE;
3659 }
3660 // find out whether the host wants absolute positioning
3661 if (vboxQueryHostWantsAbsolute())
3662 {
3663 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
3664#if 0
3665 dprintf(("Pointer shape information:\n"
3666 "\tFlags: %d\n"
3667 "\tWidth: %d\n"
3668 "\tHeight: %d\n"
3669 "\tWidthInBytes: %d\n"
3670 "\tEnable: %d\n"
3671 "\tColumn: %d\n"
3672 "\tRow: %d\n",
3673 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
3674 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
3675 pPointerAttributes->Row));
3676 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
3677#endif
3678 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension), pPointerAttributes, RequestPacket->InputBufferLength);
3679 if (!Result)
3680 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
3681 } else
3682 {
3683 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
3684 // fallback to software pointer
3685 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3686 Result = FALSE;
3687 }
3688 break;
3689 }
3690
3691 // query pointer information
3692 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
3693 {
3694 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
3695 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3696 Result = FALSE;
3697 break;
3698 }
3699
3700 // set the pointer position
3701 case IOCTL_VIDEO_SET_POINTER_POSITION:
3702 {
3703 // find out whether the host wants absolute positioning
3704 /// @todo this is now obsolete - remove it?
3705 if (vboxQueryHostWantsAbsolute())
3706 Result = ShowPointer(HwDeviceExtension);
3707 else
3708 {
3709 // fallback to software pointer
3710 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3711 Result = FALSE;
3712 }
3713 break;
3714 }
3715
3716 // query the pointer position
3717 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
3718 {
3719 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
3720 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
3721 {
3722 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
3723 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3724 return TRUE;
3725 }
3726 Result = FALSE;
3727 uint16_t mousePosX;
3728 uint16_t mousePosY;
3729 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
3730 {
3731 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
3732 PVIDEO_MODE_INFORMATION ModeInfo;
3733 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
3734 // map from 0xFFFF to the current resolution
3735 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
3736 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
3737 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
3738 Result = TRUE;
3739 }
3740 if (!Result)
3741 {
3742 // fallback to software pointer
3743 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3744 }
3745 break;
3746 }
3747
3748 // Determine hardware cursor capabilities. We will always report that we are
3749 // very capable even though the host might not want to do pointer integration.
3750 // This is done because we can still return errors on the actual calls later to
3751 // make the display driver go to the fallback routines.
3752 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
3753 {
3754 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
3755 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
3756 {
3757 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
3758 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3759 return TRUE;
3760 }
3761 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
3762 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
3763 VIDEO_MODE_COLOR_POINTER |
3764 VIDEO_MODE_MONO_POINTER;
3765 // for now we go with 64x64 cursors
3766 pCaps->MaxWidth = 64;
3767 pCaps->MaxHeight = 64;
3768 // that doesn't seem to be relevant, VBoxDisp doesn't use it
3769 pCaps->HWPtrBitmapStart = -1;
3770 pCaps->HWPtrBitmapEnd = -1;
3771 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
3772 Result = TRUE;
3773 break;
3774 }
3775
3776 /* Attach/detach DualView devices */
3777 case IOCTL_VIDEO_SWITCH_DUALVIEW:
3778 {
3779 ULONG ulAttach;
3780
3781 ulAttach = *((PULONG)RequestPacket->InputBuffer);
3782 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
3783
3784 if (pDevExt->iDevice > 0)
3785 {
3786 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
3787 }
3788 Result = TRUE;
3789 break;
3790 }
3791
3792 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
3793 {
3794 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
3795 /* Pre-HGSMI IOCTL */
3796 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3797 Result = false;
3798 break;
3799 }
3800
3801
3802 case IOCTL_VIDEO_VBVA_ENABLE:
3803 {
3804 int rc;
3805 ULONG ulEnable;
3806
3807 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
3808
3809 if (RequestPacket->InputBufferLength < sizeof(ULONG))
3810 {
3811 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
3812 RequestPacket->InputBufferLength, sizeof(ULONG)));
3813 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3814 return FALSE;
3815 }
3816
3817 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
3818 {
3819 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3820 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
3821 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3822 return FALSE;
3823 }
3824
3825 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
3826 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
3827
3828 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
3829 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
3830
3831 if (RT_FAILURE (rc))
3832 {
3833 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
3834 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3835 return FALSE;
3836 }
3837
3838 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
3839 Result = TRUE;
3840
3841 break;
3842 }
3843
3844 /* Private ioctls */
3845 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
3846 {
3847 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
3848 int rc;
3849
3850 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
3851 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
3852 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
3853 {
3854 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
3855 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
3856 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3857 return FALSE;
3858 }
3859 /*
3860 * Inform the host about the visible region
3861 */
3862 VMMDevVideoSetVisibleRegion *req = NULL;
3863
3864 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3865 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
3866 VMMDevReq_VideoSetVisibleRegion);
3867
3868 if (RT_SUCCESS(rc))
3869 {
3870 req->cRect = cRect;
3871 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
3872
3873 rc = VbglGRPerform (&req->header);
3874
3875 if (RT_SUCCESS(rc))
3876 {
3877 Result = TRUE;
3878 break;
3879 }
3880 }
3881
3882 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
3883 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3884 return FALSE;
3885 }
3886
3887 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
3888 {
3889 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
3890
3891 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
3892 {
3893 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3894 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
3895 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3896 return FALSE;
3897 }
3898
3899 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
3900 {
3901 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3902 return FALSE;
3903 }
3904
3905 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
3906
3907 pInfo->iDevice = pDevExt->iDevice;
3908 pInfo->ulFlags = 0;
3909
3910 /* Describes VRAM chunk for this display device. */
3911 pInfo->areaDisplay = pDevExt->areaDisplay;
3912
3913 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
3914 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
3915
3916 pInfo->IOPortGuestCommand = commonFromDeviceExt(pDevExt)->guestCtx.port;
3917
3918 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
3919 Result = TRUE;
3920
3921 break;
3922 }
3923 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
3924 {
3925 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
3926
3927 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
3928 {
3929 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3930 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
3931 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3932 return FALSE;
3933 }
3934
3935 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
3936 {
3937 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3938 return FALSE;
3939 }
3940
3941 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
3942
3943 pInfo->hContext = commonFromDeviceExt(pDevExt);
3944 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
3945 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
3946
3947 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
3948 Result = TRUE;
3949 break;
3950 }
3951 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
3952 {
3953 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
3954
3955 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
3956 {
3957 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3958 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
3959 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3960 return FALSE;
3961 }
3962
3963 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
3964 {
3965 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3966 return FALSE;
3967 }
3968
3969 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
3970 pInfo->pContext = pDevExt->pPrimary;
3971 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
3972
3973 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
3974 Result = TRUE;
3975 break;
3976 }
3977 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
3978 {
3979 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
3980
3981 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
3982 {
3983 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3984 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
3985 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3986 return FALSE;
3987 }
3988
3989 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
3990 {
3991 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3992 return FALSE;
3993 }
3994
3995 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
3996
3997 int rc = vboxVBVAChannelDisplayEnable(commonFromDeviceExt(pDevExt),
3998 pDevExt->iDevice,
3999 pInfo->u8Channel);
4000 if(RT_FAILURE(rc))
4001 {
4002 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
4003 }
4004 Result = TRUE;
4005 break;
4006 }
4007 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
4008 {
4009 /* TODO: implement */
4010 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4011 {
4012 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4013 return FALSE;
4014 }
4015 break;
4016 }
4017# ifdef VBOX_WITH_VIDEOHWACCEL
4018 case IOCTL_VIDEO_VHWA_QUERY_INFO:
4019 {
4020 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
4021 {
4022 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
4023 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
4024 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
4025 return FALSE;
4026 }
4027
4028 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4029 {
4030 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4031 return FALSE;
4032 }
4033
4034 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
4035 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
4036 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
4037 Result = TRUE;
4038 break;
4039 }
4040# endif
4041 default:
4042 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
4043 RequestPacket->IoControlCode,
4044 (RequestPacket->IoControlCode >> 2) & 0xFFF,
4045 (RequestPacket->IoControlCode >> 2) & 0xFFF));
4046 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4047 return FALSE;
4048 }
4049
4050 if (Result)
4051 RequestPacket->StatusBlock->Status = NO_ERROR;
4052 else
4053 RequestPacket->StatusBlock->Information = 0;
4054
4055// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
4056
4057 return TRUE;
4058}
4059
4060/**
4061 * VBoxVideoReset HW
4062 *
4063 * Resets the video hardware.
4064 */
4065BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
4066{
4067 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
4068
4069 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
4070
4071 if (pDevExt->iDevice > 0)
4072 {
4073 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
4074 pDevExt->iDevice));
4075 return TRUE;
4076 }
4077
4078 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
4079 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
4080
4081 if (pDevExt->u.primary.pvReqFlush != NULL)
4082 {
4083 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
4084 pDevExt->u.primary.pvReqFlush = NULL;
4085 }
4086
4087 VbglTerminate ();
4088
4089 VBoxFreeDisplaysHGSMI(commonFromDeviceExt(pDevExt));
4090 /** @note using this callback instead of doing things manually adds an
4091 * additional call to HGSMIHeapDestroy(). I assume that call was
4092 * merely forgotton in the first place. */
4093
4094 return TRUE;
4095}
4096
4097/**
4098 * VBoxVideoGetPowerState
4099 *
4100 * Queries whether the device can support the requested power state.
4101 */
4102VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
4103 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
4104{
4105 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
4106 return NO_ERROR;
4107}
4108
4109/**
4110 * VBoxVideoSetPowerState
4111 *
4112 * Sets the power state of the specified device
4113 */
4114VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
4115 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
4116{
4117 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
4118 return NO_ERROR;
4119}
4120#endif /* #ifndef VBOX_WITH_WDDM */
4121
4122/**
4123 * VBoxVideoSetGraphicsCap
4124 *
4125 * Tells the host whether or not we currently support graphics in the
4126 * additions
4127 */
4128BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
4129{
4130 VMMDevReqGuestCapabilities2 *req = NULL;
4131 int rc;
4132
4133 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4134 sizeof (VMMDevReqGuestCapabilities2),
4135 VMMDevReq_SetGuestCapabilities);
4136
4137 if (!RT_SUCCESS(rc))
4138 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
4139 else
4140 {
4141 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
4142 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
4143
4144 rc = VbglGRPerform (&req->header);
4145 if (RT_FAILURE(rc))
4146 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
4147 }
4148 if (req != NULL)
4149 VbglGRFree (&req->header);
4150 return RT_SUCCESS(rc);
4151}
4152
4153
4154BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
4155 USHORT width, USHORT height, USHORT bpp
4156#ifdef VBOX_WITH_WDDM
4157 , ULONG offDisplay
4158#endif
4159 )
4160{
4161#ifdef VBOX_WITH_WDDM
4162 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
4163 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
4164 ULONG xOffset = offDisplay % cbLine;
4165 if (bpp == 4)
4166 {
4167 xOffset <<= 1;
4168 }
4169 else
4170 {
4171 Assert(!(xOffset%((bpp + 7) >> 3)));
4172 xOffset /= ((bpp + 7) >> 3);
4173 }
4174 ULONG yOffset = offDisplay / cbLine;
4175 Assert(xOffset <= 0xffff);
4176 Assert(yOffset <= 0xffff);
4177#else
4178 ULONG xOffset = 0, yOffset = 0;
4179#endif
4180 VBoxVideoSetModeRegisters(width, height, width, bpp, (uint16_t)xOffset,
4181 (uint16_t)yOffset);
4182 /** @todo read from the port to see if the mode switch was successful */
4183
4184 return TRUE;
4185}
4186
4187#ifndef VBOX_WITH_WDDM
4188
4189/**
4190 * VBoxVideoSetCurrentMode
4191 *
4192 * Sets the adapter to the specified operating mode.
4193 */
4194BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
4195 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
4196{
4197 PVIDEO_MODE_INFORMATION ModeInfo;
4198
4199 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
4200
4201 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
4202 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
4203 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
4204 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
4205
4206 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
4207 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
4208 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
4209
4210 if (DeviceExtension->iDevice > 0)
4211 {
4212 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
4213 DeviceExtension->iDevice));
4214 return TRUE;
4215 }
4216
4217 return VBoxVideoSetCurrentModePerform(DeviceExtension,
4218 (USHORT)ModeInfo->VisScreenWidth,
4219 (USHORT)ModeInfo->VisScreenHeight,
4220 (USHORT)ModeInfo->BitsPerPlane);
4221}
4222
4223/*
4224 * VBoxVideoResetDevice
4225 *
4226 * Resets the video hardware to the default mode, to which it was initialized
4227 * at system boot.
4228 */
4229
4230BOOLEAN FASTCALL VBoxVideoResetDevice(
4231 PDEVICE_EXTENSION DeviceExtension,
4232 PSTATUS_BLOCK StatusBlock)
4233{
4234 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
4235
4236 if (DeviceExtension->iDevice > 0)
4237 {
4238 /* If the device is the secondary display, however, it is recommended that no action be taken. */
4239 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
4240 DeviceExtension->iDevice));
4241 return TRUE;
4242 }
4243
4244#if 0
4245 /* Don't disable the extended video mode. This would only switch the video mode
4246 * to <current width> x <current height> x 0 bpp which is not what we want. And
4247 * even worse, it causes an disturbing additional mode switch */
4248 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
4249 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
4250#endif
4251
4252 /* Tell the host that we no longer support graphics in the additions
4253 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
4254 */
4255 // VBoxVideoSetGraphicsCap(FALSE);
4256 return TRUE;
4257}
4258
4259/**
4260 * VBoxVideoMapVideoMemory
4261 *
4262 * Maps the video hardware frame buffer and video RAM into the virtual address
4263 * space of the requestor.
4264 */
4265BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
4266 PVIDEO_MEMORY RequestedAddress,
4267 PVIDEO_MEMORY_INFORMATION MapInformation,
4268 PSTATUS_BLOCK StatusBlock)
4269{
4270 PHYSICAL_ADDRESS FrameBuffer;
4271 ULONG inIoSpace = 0;
4272 VP_STATUS Status;
4273
4274 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
4275
4276 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
4277
4278 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
4279 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
4280
4281 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
4282 &MapInformation->VideoRamLength, &inIoSpace,
4283 &MapInformation->VideoRamBase);
4284
4285 if (Status == NO_ERROR)
4286 {
4287 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
4288 MapInformation->FrameBufferLength =
4289 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
4290 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
4291 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
4292
4293 /* Save the new framebuffer size */
4294 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
4295 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
4296 MapInformation->FrameBufferBase,
4297 MapInformation->FrameBufferLength,
4298 DeviceExtension->ulFrameBufferOffset);
4299 return TRUE;
4300 }
4301
4302 return FALSE;
4303}
4304
4305/**
4306 * VBoxVideoUnmapVideoMemory
4307 *
4308 * Releases a mapping between the virtual address space and the adapter's
4309 * frame buffer and video RAM.
4310 */
4311BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
4312 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
4313{
4314 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
4315 HGSMIAreaClear (&DeviceExtension->areaDisplay);
4316 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
4317 return TRUE;
4318}
4319
4320/**
4321 * VBoxVideoQueryNumAvailModes
4322 *
4323 * Returns the number of video modes supported by the adapter and the size
4324 * in bytes of the video mode information, which can be used to allocate a
4325 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
4326 */
4327BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
4328 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
4329{
4330 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
4331 /* calculate the video modes table */
4332 VBoxBuildModesTable(DeviceExtension);
4333 Modes->NumModes = gNumVideoModes;
4334 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
4335 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
4336 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
4337 return TRUE;
4338}
4339
4340/**
4341 * VBoxVideoQueryAvailModes
4342 *
4343 * Returns information about each video mode supported by the adapter.
4344 */
4345BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
4346 PVIDEO_MODE_INFORMATION ReturnedModes,
4347 PSTATUS_BLOCK StatusBlock)
4348{
4349 ULONG Size;
4350
4351 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
4352
4353 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
4354 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
4355 StatusBlock->Information = Size;
4356
4357 return TRUE;
4358}
4359
4360/**
4361 * VBoxVideoQueryCurrentMode
4362 *
4363 * Returns information about current video mode.
4364 */
4365BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
4366 PVIDEO_MODE_INFORMATION VideoModeInfo,
4367 PSTATUS_BLOCK StatusBlock)
4368{
4369 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
4370
4371 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
4372 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
4373
4374 return TRUE;
4375}
4376#endif /* ifndef VBOX_WITH_WDDM */
4377/*
4378 * VBoxVideoSetColorRegisters
4379 *
4380 * Sets the adapter's color registers to the specified RGB values. There
4381 * are code paths in this function, one generic and one for VGA compatible
4382 * controllers. The latter is needed for Bochs, where the generic one isn't
4383 * yet implemented.
4384 */
4385
4386BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
4387 PDEVICE_EXTENSION DeviceExtension,
4388 PVIDEO_CLUT ColorLookUpTable,
4389 PSTATUS_BLOCK StatusBlock)
4390{
4391 LONG Entry;
4392
4393 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
4394
4395 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
4396 return FALSE;
4397
4398 for (Entry = ColorLookUpTable->FirstEntry;
4399 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
4400 Entry++)
4401 {
4402 VBoxVideoCmnPortWriteUchar(0x03c8, (UCHAR)Entry);
4403 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
4404 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
4405 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
4406 }
4407
4408 return TRUE;
4409}
4410
4411#ifndef VBOX_WITH_WDDM
4412
4413VP_STATUS VBoxVideoGetChildDescriptor(
4414 PVOID HwDeviceExtension,
4415 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
4416 PVIDEO_CHILD_TYPE VideoChildType,
4417 PUCHAR pChildDescriptor,
4418 PULONG pUId,
4419 PULONG pUnused)
4420{
4421 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
4422 HwDeviceExtension, ChildEnumInfo));
4423
4424 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
4425
4426 if (ChildEnumInfo->ChildIndex > 0)
4427 {
4428 if ((int)ChildEnumInfo->ChildIndex <= commonFromDeviceExt(pDevExt)->cDisplays)
4429 {
4430 *VideoChildType = Monitor;
4431 *pUId = ChildEnumInfo->ChildIndex;
4432
4433 return VIDEO_ENUM_MORE_DEVICES;
4434 }
4435 }
4436
4437 return ERROR_NO_MORE_DEVICES;
4438}
4439
4440
4441#ifndef VBOX_WITH_WDDM
4442VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
4443{
4444 return ERROR_INVALID_FUNCTION;
4445}
4446
4447LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4448{
4449 return 0;
4450}
4451
4452VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4453{
4454}
4455
4456VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
4457{
4458 return ERROR_INVALID_FUNCTION;
4459}
4460
4461VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4462{
4463 return ERROR_INVALID_FUNCTION;
4464}
4465
4466PVOID vboxAllocatePoolVoid(IN PVOID HwDeviceExtension, IN VBOXVP_POOL_TYPE PoolType, IN size_t NumberOfBytes, IN ULONG Tag)
4467{
4468 return NULL;
4469}
4470
4471VOID vboxFreePoolVoid(IN PVOID HwDeviceExtension, IN PVOID Ptr)
4472{
4473}
4474
4475BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
4476{
4477 return FALSE;
4478}
4479
4480void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
4481{
4482 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
4483
4484 if (vboxQueryWinVersion() <= WINNT4)
4485 {
4486 /* VideoPortGetProcAddress is available for >= win2k */
4487 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
4488 pCallbacks->pfnSetEvent = vboxSetEventVoid;
4489 pCallbacks->pfnClearEvent = vboxClearEventVoid;
4490 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
4491 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
4492 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
4493 pCallbacks->pfnFreePool = vboxFreePoolVoid;
4494 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
4495 return;
4496 }
4497
4498 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
4499 (PrimaryExtension,
4500 (PUCHAR)"VideoPortWaitForSingleObject");
4501 Assert(pCallbacks->pfnWaitForSingleObject);
4502
4503 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
4504 (PrimaryExtension,
4505 (PUCHAR)"VideoPortSetEvent");
4506 Assert(pCallbacks->pfnSetEvent);
4507
4508 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
4509 (PrimaryExtension,
4510 (PUCHAR)"VideoPortClearEvent");
4511 Assert(pCallbacks->pfnClearEvent);
4512
4513 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
4514 (PrimaryExtension,
4515 (PUCHAR)"VideoPortCreateEvent");
4516 Assert(pCallbacks->pfnCreateEvent);
4517
4518 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
4519 (PrimaryExtension,
4520 (PUCHAR)"VideoPortDeleteEvent");
4521 Assert(pCallbacks->pfnDeleteEvent);
4522
4523 if(pCallbacks->pfnWaitForSingleObject
4524 && pCallbacks->pfnSetEvent
4525 && pCallbacks->pfnClearEvent
4526 && pCallbacks->pfnCreateEvent
4527 && pCallbacks->pfnDeleteEvent)
4528 {
4529 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
4530 }
4531 else
4532 {
4533 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
4534 pCallbacks->pfnSetEvent = vboxSetEventVoid;
4535 pCallbacks->pfnClearEvent = vboxClearEventVoid;
4536 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
4537 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
4538 }
4539
4540 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
4541 (PrimaryExtension,
4542 (PUCHAR)"VideoPortAllocatePool");
4543 Assert(pCallbacks->pfnAllocatePool);
4544
4545 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
4546 (PrimaryExtension,
4547 (PUCHAR)"VideoPortFreePool");
4548 Assert(pCallbacks->pfnFreePool);
4549
4550 if(pCallbacks->pfnAllocatePool
4551 && pCallbacks->pfnFreePool)
4552 {
4553 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
4554 }
4555 else
4556 {
4557 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
4558 pCallbacks->pfnFreePool = vboxFreePoolVoid;
4559 }
4560
4561 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
4562 (PrimaryExtension,
4563 (PUCHAR)"VideoPortQueueDpc");
4564 Assert(pCallbacks->pfnQueueDpc);
4565
4566 if(pCallbacks->pfnQueueDpc)
4567 {
4568 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
4569 }
4570 else
4571 {
4572 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
4573 }
4574
4575#ifdef DEBUG_misha
4576 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
4577#endif
4578}
4579#endif
4580
4581
4582static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
4583{
4584 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
4585 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
4586
4587 if (pPrimaryDevExt)
4588 {
4589 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
4590
4591 if (req)
4592 {
4593 int rc = VbglGRPerform (&req->header);
4594
4595 if (RT_FAILURE(rc))
4596 {
4597 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
4598 }
4599 }
4600 }
4601
4602 return;
4603}
4604
4605int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
4606{
4607 int rc = VINF_SUCCESS;
4608
4609 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
4610
4611 /*
4612 * Query the VMMDev memory pointer. There we need VBVAMemory.
4613 */
4614 VMMDevMemory *pVMMDevMemory = NULL;
4615
4616 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
4617
4618 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
4619
4620 if (pDevExt->iDevice > 0)
4621 {
4622 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
4623
4624 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
4625 pDevExt->iDevice));
4626
4627 if ( ulEnable
4628 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
4629 {
4630 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
4631 pVbvaResult->pfnFlush = vboxVbvaFlush;
4632 pVbvaResult->pvFlush = pDevExt;
4633 }
4634 else
4635 {
4636 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
4637 }
4638
4639 return rc;
4640 }
4641
4642 if (RT_SUCCESS(rc))
4643 {
4644 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
4645 if (pDevExt->u.primary.pvReqFlush == NULL)
4646 {
4647 VMMDevVideoAccelFlush *req = NULL;
4648
4649 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4650 sizeof (VMMDevVideoAccelFlush),
4651 VMMDevReq_VideoAccelFlush);
4652
4653 if (RT_SUCCESS (rc))
4654 {
4655 pDevExt->u.primary.pvReqFlush = req;
4656 }
4657 else
4658 {
4659 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
4660 }
4661 }
4662 }
4663 else
4664 {
4665 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
4666 }
4667
4668 if (RT_SUCCESS(rc))
4669 {
4670 ULONG ulEnabled = 0;
4671
4672 /*
4673 * Tell host that VBVA status is changed.
4674 */
4675 VMMDevVideoAccelEnable *req = NULL;
4676
4677 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4678 sizeof (VMMDevVideoAccelEnable),
4679 VMMDevReq_VideoAccelEnable);
4680
4681 if (RT_SUCCESS(rc))
4682 {
4683 req->u32Enable = ulEnable;
4684 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
4685 req->fu32Status = 0;
4686
4687 rc = VbglGRPerform (&req->header);
4688
4689 if (RT_SUCCESS(rc))
4690 {
4691 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
4692 {
4693 /*
4694 * Initialize the result information and VBVA memory.
4695 */
4696 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
4697 {
4698 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
4699 pVbvaResult->pfnFlush = vboxVbvaFlush;
4700 pVbvaResult->pvFlush = pDevExt;
4701 ulEnabled = 1;
4702 }
4703 else
4704 {
4705 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
4706 }
4707
4708 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
4709 }
4710 else
4711 {
4712 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
4713
4714 /* Disable VBVA for old hosts. */
4715 req->u32Enable = 0;
4716 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
4717 req->fu32Status = 0;
4718
4719 VbglGRPerform (&req->header);
4720
4721 rc = VERR_NOT_SUPPORTED;
4722 }
4723 }
4724 else
4725 {
4726 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
4727 }
4728
4729 VbglGRFree (&req->header);
4730 }
4731 else
4732 {
4733 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
4734 }
4735
4736 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
4737 }
4738
4739 return rc;
4740}
4741#endif
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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