VirtualBox

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

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

wddm: autoresize fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 185.9 KB
Line 
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.virtualbox.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
2843void VBoxVideoCmnPortWriteUchar(RTIOPORT Port, uint8_t Value)
2844{
2845#ifndef VBOX_WITH_WDDM
2846 VideoPortWritePortUchar((PUCHAR)Port,Value);
2847#else
2848 WRITE_PORT_UCHAR((PUCHAR)Port,Value);
2849#endif
2850}
2851
2852void VBoxVideoCmnPortWriteUshort(RTIOPORT Port, uint16_t Value)
2853{
2854#ifndef VBOX_WITH_WDDM
2855 VideoPortWritePortUshort((PUSHORT)Port,Value);
2856#else
2857 WRITE_PORT_USHORT((PUSHORT)Port,Value);
2858#endif
2859}
2860
2861void VBoxVideoCmnPortWriteUlong(RTIOPORT Port, uint32_t Value)
2862{
2863#ifndef VBOX_WITH_WDDM
2864 VideoPortWritePortUlong((PULONG)Port,Value);
2865#else
2866 WRITE_PORT_ULONG((PULONG)Port,Value);
2867#endif
2868}
2869
2870uint8_t VBoxVideoCmnPortReadUchar(RTIOPORT Port)
2871{
2872#ifndef VBOX_WITH_WDDM
2873 return VideoPortReadPortUchar((PUCHAR)Port);
2874#else
2875 return READ_PORT_UCHAR((PUCHAR)Port);
2876#endif
2877}
2878
2879uint16_t VBoxVideoCmnPortReadUshort(RTIOPORT Port)
2880{
2881#ifndef VBOX_WITH_WDDM
2882 return VideoPortReadPortUshort((PUSHORT)Port);
2883#else
2884 return READ_PORT_USHORT((PUSHORT)Port);
2885#endif
2886}
2887
2888uint32_t VBoxVideoCmnPortReadUlong(RTIOPORT Port)
2889{
2890#ifndef VBOX_WITH_WDDM
2891 return VideoPortReadPortUlong((PULONG)Port);
2892#else
2893 return READ_PORT_ULONG((PULONG)Port);
2894#endif
2895}
2896
2897int VBoxMapAdapterMemory (PVBOXVIDEO_COMMON pCommon, void **ppv, uint32_t ulOffset, uint32_t ulSize)
2898{
2899 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2900 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
2901
2902 if (!ulSize)
2903 {
2904 dprintf(("Illegal length 0!\n"));
2905 return ERROR_INVALID_PARAMETER;
2906 }
2907
2908 PHYSICAL_ADDRESS FrameBuffer;
2909 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
2910
2911 PVOID VideoRamBase = NULL;
2912 ULONG VideoRamLength = ulSize;
2913 VP_STATUS Status;
2914#ifndef VBOX_WITH_WDDM
2915 ULONG inIoSpace = 0;
2916
2917 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
2918 &VideoRamLength, &inIoSpace,
2919 &VideoRamBase);
2920#else
2921 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
2922 FrameBuffer,
2923 VideoRamLength,
2924 FALSE, /* IN BOOLEAN InIoSpace */
2925 FALSE, /* IN BOOLEAN MapToUserMode */
2926 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
2927 &VideoRamBase /*OUT PVOID *VirtualAddress*/
2928 );
2929 Assert(ntStatus == STATUS_SUCCESS);
2930 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
2931#endif
2932
2933 if (Status == NO_ERROR)
2934 {
2935 *ppv = VideoRamBase;
2936 }
2937
2938 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
2939
2940 return Status;
2941}
2942
2943bool VBoxSyncToVideoIRQ(PVBOXVIDEO_COMMON pCommon, PFNVIDEOIRQSYNC pfnSync,
2944 void *pvUser)
2945{
2946 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2947 PMINIPORT_SYNCHRONIZE_ROUTINE pfnSyncMiniport;
2948 pfnSyncMiniport = (PMINIPORT_SYNCHRONIZE_ROUTINE) pfnSync;
2949#ifndef VBOX_WITH_WDDM
2950 return !!VideoPortSynchronizeExecution(PrimaryExtension, VpMediumPriority,
2951 pfnSyncMiniport, pvUser);
2952#else
2953 BOOLEAN fRet;
2954 DXGKCB_SYNCHRONIZE_EXECUTION pfnDxgkCbSync =
2955 PrimaryExtension->u.primary.DxgkInterface.DxgkCbSynchronizeExecution;
2956 HANDLE hDev = PrimaryExtension->u.primary.DxgkInterface.DeviceHandle;
2957 NTSTATUS ntStatus = pfnDxgkCbSync(hDev, pfnSyncMiniport, pvUser, 0, &fRet);
2958 AssertReturn(ntStatus == STATUS_SUCCESS, false);
2959 return !!fRet;
2960#endif
2961}
2962
2963void VBoxUnmapAdapterMemory (PVBOXVIDEO_COMMON pCommon, void **ppv)
2964{
2965 dprintf(("VBoxVideo::VBoxUnmapAdapterMemory\n"));
2966
2967 PDEVICE_EXTENSION PrimaryExtension = commonToPrimaryExt(pCommon);
2968
2969 if (*ppv)
2970 {
2971#ifndef VBOX_WITH_WDDM
2972 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
2973#else
2974 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
2975 *ppv);
2976 Assert(ntStatus == STATUS_SUCCESS);
2977#endif
2978 }
2979
2980 *ppv = NULL;
2981}
2982
2983
2984void vboxVideoInitCustomVideoModes(PDEVICE_EXTENSION pDevExt)
2985{
2986 VP_STATUS status;
2987 VBOXCMNREG Reg;
2988
2989 VBoxVideoCmnRegInit(pDevExt, &Reg);
2990
2991 dprintf(("VBoxVideo::vboxVideoInitCustomVideoModes\n"));
2992
2993#ifndef VBOX_WITH_MULTIMONITOR_FIX
2994 /*
2995 * Get the last custom resolution
2996 */
2997 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &gCustomXRes);
2998 if (status != NO_ERROR)
2999 gCustomXRes = 0;
3000
3001 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &gCustomYRes);
3002 if (status != NO_ERROR)
3003 gCustomYRes = 0;
3004 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &gCustomBPP);
3005 if (status != NO_ERROR)
3006 gCustomBPP = 0;
3007
3008 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
3009#else
3010 /* Initialize all custom modes to the 800x600x32. */
3011 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
3012
3013 int iCustomMode;
3014 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
3015 {
3016 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
3017 }
3018
3019 /* Load stored custom resolution from the registry. */
3020 for (iCustomMode = 0;
3021#ifdef VBOX_WITH_WDDM
3022 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
3023#else
3024 iCustomMode < commonFromDeviceExt(pDevExt)->cDisplays;
3025#endif
3026 iCustomMode++)
3027 {
3028 /*
3029 * Get the last custom resolution
3030 */
3031 uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
3032
3033 if (iCustomMode == 0)
3034 {
3035 /* Name without a suffix */
3036 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &CustomXRes);
3037 if (status != NO_ERROR)
3038 CustomXRes = 0;
3039 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &CustomYRes);
3040 if (status != NO_ERROR)
3041 CustomYRes = 0;
3042 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &CustomBPP);
3043 if (status != NO_ERROR)
3044 CustomBPP = 0;
3045 }
3046 else
3047 {
3048 wchar_t keyname[32];
3049 swprintf(keyname, L"CustomXRes%d", iCustomMode);
3050 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomXRes);
3051 if (status != NO_ERROR)
3052 CustomXRes = 0;
3053 swprintf(keyname, L"CustomYRes%d", iCustomMode);
3054 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomYRes);
3055 if (status != NO_ERROR)
3056 CustomYRes = 0;
3057 swprintf(keyname, L"CustomBPP%d", iCustomMode);
3058 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomBPP);
3059 if (status != NO_ERROR)
3060 CustomBPP = 0;
3061 }
3062
3063 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
3064
3065 if (CustomXRes || CustomYRes || CustomBPP)
3066 {
3067 if (CustomXRes == 0)
3068 {
3069 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
3070 }
3071 if (CustomYRes == 0)
3072 {
3073 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
3074 }
3075 if (CustomBPP == 0)
3076 {
3077 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
3078 }
3079
3080 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
3081 }
3082 }
3083#endif /* VBOX_WITH_MULTIMONITOR_FIX */
3084
3085 VBoxVideoCmnRegFini(Reg);
3086}
3087
3088#ifndef VBOX_WITH_WDDM
3089static int vbvaInitInfoDisplay (void *pvData, VBVAINFOVIEW *p)
3090{
3091 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION) pvData;
3092
3093 int i;
3094 PDEVICE_EXTENSION Extension;
3095
3096 for (i = 0, Extension = PrimaryExtension;
3097 i < commonFromDeviceExt(PrimaryExtension)->cDisplays && Extension;
3098 i++, Extension = Extension->pNext)
3099 {
3100 p[i].u32ViewIndex = Extension->iDevice;
3101 p[i].u32ViewOffset = Extension->ulFrameBufferOffset;
3102 p[i].u32ViewSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
3103
3104 /* How much VRAM should be reserved for the guest drivers to use VBVA. */
3105 const uint32_t cbReservedVRAM = VBVA_DISPLAY_INFORMATION_SIZE + VBVA_MIN_BUFFER_SIZE;
3106
3107 p[i].u32MaxScreenSize = p[i].u32ViewSize > cbReservedVRAM?
3108 p[i].u32ViewSize - cbReservedVRAM:
3109 0;
3110 }
3111
3112 if (i == commonFromDeviceExt(PrimaryExtension)->cDisplays && Extension == NULL)
3113 {
3114 return VINF_SUCCESS;
3115 }
3116
3117 AssertFailed ();
3118 return VERR_INTERNAL_ERROR;
3119}
3120
3121
3122static VOID VBoxCreateDisplaysXPDM(PDEVICE_EXTENSION PrimaryExtension,
3123 PVIDEO_PORT_CONFIG_INFO pConfigInfo)
3124{
3125 VP_STATUS rc;
3126
3127 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
3128 {
3129 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
3130 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
3131
3132 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
3133 if (vboxQueryWinVersion() > WINNT4)
3134 {
3135 /* This bluescreens on NT4, hence the above version check */
3136 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
3137 (PrimaryExtension,
3138 (PUCHAR)"VideoPortCreateSecondaryDisplay");
3139 }
3140
3141 if (!pfnCreateSecondaryDisplay)
3142 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
3143 else
3144 {
3145 PDEVICE_EXTENSION pPrev = PrimaryExtension;
3146
3147 ULONG iDisplay;
3148 ULONG cDisplays = commonFromDeviceExt(PrimaryExtension)->cDisplays;
3149 commonFromDeviceExt(PrimaryExtension)->cDisplays = 1;
3150 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
3151 {
3152 PDEVICE_EXTENSION SecondaryExtension = NULL;
3153 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
3154
3155 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
3156 rc, SecondaryExtension));
3157
3158 if (rc != NO_ERROR)
3159 {
3160 break;
3161 }
3162
3163 SecondaryExtension->pNext = NULL;
3164 SecondaryExtension->pPrimary = PrimaryExtension;
3165 SecondaryExtension->iDevice = iDisplay;
3166 SecondaryExtension->ulFrameBufferOffset = 0;
3167 SecondaryExtension->ulFrameBufferSize = 0;
3168 SecondaryExtension->u.secondary.bEnabled = FALSE;
3169
3170 /* Update the list pointers. */
3171 pPrev->pNext = SecondaryExtension;
3172 pPrev = SecondaryExtension;
3173
3174 /* Take the successfully created display into account. */
3175 commonFromDeviceExt(PrimaryExtension)->cDisplays++;
3176 }
3177 }
3178
3179 /* Failure to create secondary displays is not fatal */
3180 rc = NO_ERROR;
3181 }
3182
3183 /* Now when the number of monitors is known and extensions are created,
3184 * calculate the layout of framebuffers.
3185 */
3186 VBoxComputeFrameBufferSizes (PrimaryExtension);
3187 /* in case of WDDM we do not control the framebuffer location,
3188 * i.e. it is assigned by Video Memory Manager,
3189 * The FB information should be passed to guest from our
3190 * DxgkDdiSetVidPnSourceAddress callback */
3191
3192 if (commonFromDeviceExt(PrimaryExtension)->bHGSMI)
3193 {
3194 if (RT_SUCCESS(rc))
3195 {
3196 rc = VBoxHGSMISendViewInfo (commonFromDeviceExt(PrimaryExtension),
3197 commonFromDeviceExt(PrimaryExtension)->cDisplays,
3198 vbvaInitInfoDisplay,
3199 (void *) PrimaryExtension);
3200 AssertRC(rc);
3201 }
3202
3203 if (RT_FAILURE (rc))
3204 {
3205 commonFromDeviceExt(PrimaryExtension)->bHGSMI = FALSE;
3206 }
3207 }
3208}
3209
3210VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
3211 IN PVOID HwContext, IN PWSTR ArgumentString,
3212 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
3213 OUT PUCHAR Again)
3214{
3215 VP_STATUS rc;
3216 USHORT DispiId;
3217 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
3218
3219 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
3220
3221 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
3222
3223 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
3224 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
3225 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
3226 if (DispiId == VBE_DISPI_ID2)
3227 {
3228 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
3229 /*
3230 * Write some hardware information to registry, so that
3231 * it's visible in Windows property dialog.
3232 */
3233
3234 rc = VideoPortSetRegistryParameters(
3235 HwDeviceExtension,
3236 L"HardwareInformation.ChipType",
3237 VBoxChipType,
3238 sizeof(VBoxChipType));
3239
3240 rc = VideoPortSetRegistryParameters(
3241 HwDeviceExtension,
3242 L"HardwareInformation.DacType",
3243 VBoxDACType,
3244 sizeof(VBoxDACType));
3245
3246 /*
3247 * Query the adapter's memory size. It's a bit of a hack, we just read
3248 * an ULONG from the data port without setting an index before.
3249 */
3250 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
3251 rc = VideoPortSetRegistryParameters(
3252 HwDeviceExtension,
3253 L"HardwareInformation.MemorySize",
3254 &AdapterMemorySize,
3255 sizeof(ULONG));
3256
3257 rc = VideoPortSetRegistryParameters(
3258 HwDeviceExtension,
3259 L"HardwareInformation.AdapterString",
3260 VBoxAdapterString,
3261 sizeof(VBoxAdapterString));
3262
3263 rc = VideoPortSetRegistryParameters(
3264 HwDeviceExtension,
3265 L"HardwareInformation.BiosString",
3266 VBoxBiosString,
3267 sizeof(VBoxBiosString));
3268
3269 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
3270
3271 VIDEO_ACCESS_RANGE tmpRanges[4];
3272 ULONG slot = 0;
3273
3274 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
3275
3276 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
3277 VP_STATUS status;
3278 if (vboxQueryWinVersion() == WINNT4)
3279 {
3280 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
3281 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
3282 */
3283 ULONG vendorId = 0x80EE;
3284 ULONG deviceId = 0xBEEF;
3285 status = VideoPortGetAccessRanges(HwDeviceExtension,
3286 0,
3287 NULL,
3288 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
3289 tmpRanges,
3290 &vendorId,
3291 &deviceId,
3292 &slot);
3293 }
3294 else
3295 {
3296 status = VideoPortGetAccessRanges(HwDeviceExtension,
3297 0,
3298 NULL,
3299 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
3300 tmpRanges,
3301 NULL,
3302 NULL,
3303 &slot);
3304 }
3305 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
3306
3307 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
3308 rc = VbglInit ();
3309 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
3310
3311 /* Preinitialize the primary extension.
3312 */
3313 ((PDEVICE_EXTENSION)HwDeviceExtension)->pNext = NULL;
3314 ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary = (PDEVICE_EXTENSION)HwDeviceExtension;
3315 ((PDEVICE_EXTENSION)HwDeviceExtension)->iDevice = 0;
3316 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferOffset = 0;
3317 ((PDEVICE_EXTENSION)HwDeviceExtension)->ulFrameBufferSize = 0;
3318 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.ulVbvaEnabled = 0;
3319 VBoxVideoCmnMemZero(&((PDEVICE_EXTENSION)HwDeviceExtension)->areaDisplay, sizeof(HGSMIAREA));
3320 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
3321 * code will be ifdef'ed and later removed.
3322 * The host will however support both old and new interface to keep compatibility
3323 * with old guest additions.
3324 */
3325 VBoxSetupDisplaysHGSMI(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension),
3326 AdapterMemorySize, 0);
3327
3328 if (commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension)->bHGSMI)
3329 {
3330 LogRel(("VBoxVideo: using HGSMI\n"));
3331 VBoxCreateDisplaysXPDM((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo);
3332 }
3333
3334 // pretend success to make the driver work.
3335 rc = NO_ERROR;
3336 } else
3337 {
3338 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
3339 rc = ERROR_DEV_NOT_EXIST;
3340 }
3341 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
3342 return rc;
3343}
3344
3345/**
3346 * VBoxVideoInitialize
3347 *
3348 * Performs the first initialization of the adapter, after the HAL has given
3349 * up control of the video hardware to the video port driver.
3350 */
3351BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
3352{
3353 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
3354
3355 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3356 USHORT DispiId;
3357
3358 /* Initialize the request pointer. */
3359 pDevExt->u.primary.pvReqFlush = NULL;
3360
3361 /* Check if the chip restricts horizontal resolution or not. */
3362 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
3363 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
3364 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
3365 if (DispiId == VBE_DISPI_ID_ANYX)
3366 pDevExt->fAnyX = TRUE;
3367 else
3368 pDevExt->fAnyX = FALSE;
3369
3370 vboxVideoInitCustomVideoModes(pDevExt);
3371
3372 return TRUE;
3373}
3374
3375# ifdef VBOX_WITH_VIDEOHWACCEL
3376
3377static VOID VBoxVideoHGSMIDpc(
3378 IN PVOID HwDeviceExtension,
3379 IN PVOID Context
3380 )
3381{
3382 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
3383
3384 hgsmiProcessHostCommandQueue(commonFromDeviceExt(PrimaryExtension));
3385}
3386
3387BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
3388{
3389 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3390 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
3391 if (PrimaryExtension)
3392 {
3393 if (commonFromDeviceExt(PrimaryExtension)->pHostFlags) /* If HGSMI is enabled at all. */
3394 {
3395 uint32_t flags = commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags;
3396 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
3397 {
3398 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
3399 {
3400 /* schedule a DPC*/
3401 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, NULL);
3402 Assert(bResult);
3403 }
3404 /* clear the IRQ */
3405 HGSMIClearIrq (commonFromDeviceExt(PrimaryExtension));
3406 return TRUE;
3407 }
3408 }
3409 }
3410 return FALSE;
3411}
3412# endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
3413#endif /* #ifndef VBOX_WITH_WDDM */
3414/**
3415 * Send a request to the host to make the absolute pointer visible
3416 */
3417static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
3418{
3419 BOOLEAN Result = TRUE;
3420
3421 /* Use primary device extension, because the show pointer request should be processed
3422 * in vboxUpdatePointerShape regardless of the device. */
3423#ifndef VBOX_WITH_WDDM
3424 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
3425#else
3426 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
3427#endif
3428
3429 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
3430 {
3431 // tell the host to use the guest's pointer
3432 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3433
3434 /* Visible and No Shape means Show the pointer.
3435 * It is enough to init only this field.
3436 */
3437 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
3438
3439 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt(PrimaryExtension), &PointerAttributes, sizeof (PointerAttributes));
3440
3441 if (Result)
3442 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
3443 else
3444 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
3445 }
3446 return Result;
3447}
3448
3449#ifndef VBOX_WITH_WDDM
3450/**
3451 * VBoxVideoStartIO
3452 *
3453 * Processes the specified Video Request Packet.
3454 */
3455BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
3456 PVIDEO_REQUEST_PACKET RequestPacket)
3457{
3458 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
3459
3460 BOOLEAN Result;
3461
3462// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
3463
3464 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3465
3466 switch (RequestPacket->IoControlCode)
3467 {
3468 case IOCTL_VIDEO_SET_CURRENT_MODE:
3469 {
3470 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
3471 {
3472 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3473 return TRUE;
3474 }
3475 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
3476 (PVIDEO_MODE)RequestPacket->InputBuffer,
3477 RequestPacket->StatusBlock);
3478 break;
3479 }
3480
3481 case IOCTL_VIDEO_RESET_DEVICE:
3482 {
3483 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
3484 RequestPacket->StatusBlock);
3485 break;
3486 }
3487
3488 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
3489 {
3490 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
3491 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
3492 {
3493 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3494 return TRUE;
3495 }
3496 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
3497 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
3498 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
3499 RequestPacket->StatusBlock);
3500 break;
3501 }
3502
3503 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
3504 {
3505 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
3506 {
3507 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3508 return TRUE;
3509 }
3510 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
3511 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
3512 RequestPacket->StatusBlock);
3513 break;
3514 }
3515
3516 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
3517 {
3518 PVIDEO_SHARE_MEMORY pShareMemory;
3519 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
3520 PHYSICAL_ADDRESS shareAddress;
3521 PVOID virtualAddress = NULL;
3522 ULONG sharedViewSize;
3523 ULONG inIoSpace = 0;
3524 VP_STATUS status;
3525
3526 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
3527
3528 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
3529 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
3530
3531 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
3532 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3533 Result = FALSE;
3534 break;
3535 }
3536
3537 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
3538
3539 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
3540 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
3541
3542 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));
3543 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
3544 Result = FALSE;
3545 break;
3546 }
3547
3548 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
3549
3550 virtualAddress = pShareMemory->ProcessHandle;
3551 sharedViewSize = pShareMemory->ViewSize;
3552
3553 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
3554
3555 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
3556 if (status != NO_ERROR)
3557 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
3558 Result = (status == NO_ERROR);
3559
3560 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
3561 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
3562 pShareMemoryInformation->VirtualAddress = virtualAddress;
3563 pShareMemoryInformation->SharedViewSize = sharedViewSize;
3564 break;
3565 }
3566
3567 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
3568 {
3569 PVIDEO_SHARE_MEMORY pShareMemory;
3570 VP_STATUS status;
3571
3572 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
3573
3574 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
3575 {
3576 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
3577 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3578 Result = FALSE;
3579 break;
3580 }
3581
3582 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
3583
3584 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
3585 if (status != NO_ERROR)
3586 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
3587 Result = (status == NO_ERROR);
3588 break;
3589 }
3590
3591 /*
3592 * The display driver asks us how many video modes we support
3593 * so that it can supply an appropriate buffer for the next call.
3594 */
3595 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
3596 {
3597 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
3598 {
3599 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3600 return TRUE;
3601 }
3602 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
3603 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
3604 RequestPacket->StatusBlock);
3605 break;
3606 }
3607
3608 /*
3609 * The display driver asks us to provide a list of supported video modes
3610 * into a buffer it has allocated.
3611 */
3612 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
3613 {
3614 if (RequestPacket->OutputBufferLength <
3615 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
3616 {
3617 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3618 return TRUE;
3619 }
3620 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
3621 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
3622 RequestPacket->StatusBlock);
3623 break;
3624 }
3625
3626 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
3627 {
3628 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
3629 RequestPacket->InputBufferLength <
3630 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
3631 sizeof(VIDEO_CLUT))
3632 {
3633 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3634 return TRUE;
3635 }
3636 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
3637 (PVIDEO_CLUT)RequestPacket->InputBuffer,
3638 RequestPacket->StatusBlock);
3639 break;
3640 }
3641
3642 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
3643 {
3644 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
3645 {
3646 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3647 return TRUE;
3648 }
3649 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
3650 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
3651 RequestPacket->StatusBlock);
3652 break;
3653 }
3654
3655 // show the pointer
3656 case IOCTL_VIDEO_ENABLE_POINTER:
3657 {
3658 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
3659 // find out whether the host wants absolute positioning
3660 /// @todo this is now obsolete - remove it?
3661 if (vboxQueryHostWantsAbsolute())
3662 Result = ShowPointer(HwDeviceExtension);
3663 else
3664 {
3665 // fallback to software pointer
3666 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3667 Result = FALSE;
3668 }
3669 break;
3670 }
3671
3672 // hide the pointer
3673 case IOCTL_VIDEO_DISABLE_POINTER:
3674 {
3675 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
3676 // find out whether the host wants absolute positioning
3677 if (vboxQueryHostWantsAbsolute())
3678 {
3679 // tell the host to hide pointer
3680 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
3681
3682 /* Enable == 0 means no shape, not visible.
3683 * It is enough to init only this field.
3684 */
3685 PointerAttributes.Enable = 0;
3686
3687 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension), &PointerAttributes, sizeof (PointerAttributes));
3688
3689 if (Result)
3690 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
3691 else
3692 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
3693 } else
3694 {
3695 // fallback to software pointer
3696 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3697 Result = FALSE;
3698 }
3699 break;
3700 }
3701
3702 /*
3703 * Change the pointer shape
3704 */
3705 case IOCTL_VIDEO_SET_POINTER_ATTR:
3706 {
3707 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
3708 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
3709 {
3710 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
3711 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3712 return TRUE;
3713 }
3714 // find out whether the host wants absolute positioning
3715 if (vboxQueryHostWantsAbsolute())
3716 {
3717 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
3718#if 0
3719 dprintf(("Pointer shape information:\n"
3720 "\tFlags: %d\n"
3721 "\tWidth: %d\n"
3722 "\tHeight: %d\n"
3723 "\tWidthInBytes: %d\n"
3724 "\tEnable: %d\n"
3725 "\tColumn: %d\n"
3726 "\tRow: %d\n",
3727 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
3728 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
3729 pPointerAttributes->Row));
3730 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
3731#endif
3732 Result = vboxUpdatePointerShapeWrap(commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension), pPointerAttributes, RequestPacket->InputBufferLength);
3733 if (!Result)
3734 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
3735 } else
3736 {
3737 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
3738 // fallback to software pointer
3739 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3740 Result = FALSE;
3741 }
3742 break;
3743 }
3744
3745 // query pointer information
3746 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
3747 {
3748 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
3749 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3750 Result = FALSE;
3751 break;
3752 }
3753
3754 // set the pointer position
3755 case IOCTL_VIDEO_SET_POINTER_POSITION:
3756 {
3757 // find out whether the host wants absolute positioning
3758 /// @todo this is now obsolete - remove it?
3759 if (vboxQueryHostWantsAbsolute())
3760 Result = ShowPointer(HwDeviceExtension);
3761 else
3762 {
3763 // fallback to software pointer
3764 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3765 Result = FALSE;
3766 }
3767 break;
3768 }
3769
3770 // query the pointer position
3771 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
3772 {
3773 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
3774 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
3775 {
3776 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
3777 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3778 return TRUE;
3779 }
3780 Result = FALSE;
3781 uint16_t mousePosX;
3782 uint16_t mousePosY;
3783 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
3784 {
3785 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
3786 PVIDEO_MODE_INFORMATION ModeInfo;
3787 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
3788 // map from 0xFFFF to the current resolution
3789 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
3790 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
3791 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
3792 Result = TRUE;
3793 }
3794 if (!Result)
3795 {
3796 // fallback to software pointer
3797 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3798 }
3799 break;
3800 }
3801
3802 // Determine hardware cursor capabilities. We will always report that we are
3803 // very capable even though the host might not want to do pointer integration.
3804 // This is done because we can still return errors on the actual calls later to
3805 // make the display driver go to the fallback routines.
3806 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
3807 {
3808 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
3809 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
3810 {
3811 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
3812 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3813 return TRUE;
3814 }
3815 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
3816 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
3817 VIDEO_MODE_COLOR_POINTER |
3818 VIDEO_MODE_MONO_POINTER;
3819 // for now we go with 64x64 cursors
3820 pCaps->MaxWidth = 64;
3821 pCaps->MaxHeight = 64;
3822 // that doesn't seem to be relevant, VBoxDisp doesn't use it
3823 pCaps->HWPtrBitmapStart = -1;
3824 pCaps->HWPtrBitmapEnd = -1;
3825 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
3826 Result = TRUE;
3827 break;
3828 }
3829
3830 /* Attach/detach DualView devices */
3831 case IOCTL_VIDEO_SWITCH_DUALVIEW:
3832 {
3833 ULONG ulAttach;
3834
3835 ulAttach = *((PULONG)RequestPacket->InputBuffer);
3836 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
3837
3838 if (pDevExt->iDevice > 0)
3839 {
3840 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
3841 }
3842 Result = TRUE;
3843 break;
3844 }
3845
3846 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
3847 {
3848 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
3849 /* Pre-HGSMI IOCTL */
3850 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3851 Result = false;
3852 break;
3853 }
3854
3855
3856 case IOCTL_VIDEO_VBVA_ENABLE:
3857 {
3858 int rc;
3859 ULONG ulEnable;
3860
3861 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
3862
3863 if (RequestPacket->InputBufferLength < sizeof(ULONG))
3864 {
3865 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
3866 RequestPacket->InputBufferLength, sizeof(ULONG)));
3867 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3868 return FALSE;
3869 }
3870
3871 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
3872 {
3873 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3874 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
3875 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3876 return FALSE;
3877 }
3878
3879 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
3880 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
3881
3882 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
3883 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
3884
3885 if (RT_FAILURE (rc))
3886 {
3887 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
3888 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3889 return FALSE;
3890 }
3891
3892 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
3893 Result = TRUE;
3894
3895 break;
3896 }
3897
3898 /* Private ioctls */
3899 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
3900 {
3901 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
3902 int rc;
3903
3904 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
3905 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
3906 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
3907 {
3908 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
3909 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
3910 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3911 return FALSE;
3912 }
3913 /*
3914 * Inform the host about the visible region
3915 */
3916 VMMDevVideoSetVisibleRegion *req = NULL;
3917
3918 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3919 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
3920 VMMDevReq_VideoSetVisibleRegion);
3921
3922 if (RT_SUCCESS(rc))
3923 {
3924 req->cRect = cRect;
3925 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
3926
3927 rc = VbglGRPerform (&req->header);
3928
3929 if (RT_SUCCESS(rc))
3930 {
3931 Result = TRUE;
3932 break;
3933 }
3934 }
3935
3936 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
3937 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3938 return FALSE;
3939 }
3940
3941 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
3942 {
3943 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
3944
3945 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
3946 {
3947 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3948 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
3949 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
3950 return FALSE;
3951 }
3952
3953 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
3954 {
3955 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
3956 return FALSE;
3957 }
3958
3959 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
3960
3961 pInfo->iDevice = pDevExt->iDevice;
3962 pInfo->ulFlags = 0;
3963
3964 /* Describes VRAM chunk for this display device. */
3965 pInfo->areaDisplay = pDevExt->areaDisplay;
3966
3967 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
3968 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
3969
3970 pInfo->IOPortGuestCommand = commonFromDeviceExt(pDevExt)->IOPortGuest;
3971
3972 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
3973 Result = TRUE;
3974
3975 break;
3976 }
3977 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
3978 {
3979 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
3980
3981 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
3982 {
3983 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
3984 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
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 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
3996
3997 pInfo->hContext = commonFromDeviceExt(pDevExt);
3998 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
3999 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
4000
4001 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
4002 Result = TRUE;
4003 break;
4004 }
4005 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
4006 {
4007 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
4008
4009 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
4010 {
4011 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
4012 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
4013 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
4014 return FALSE;
4015 }
4016
4017 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4018 {
4019 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4020 return FALSE;
4021 }
4022
4023 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
4024 pInfo->pContext = pDevExt->pPrimary;
4025 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
4026
4027 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
4028 Result = TRUE;
4029 break;
4030 }
4031 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
4032 {
4033 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
4034
4035 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
4036 {
4037 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
4038 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
4039 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
4040 return FALSE;
4041 }
4042
4043 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4044 {
4045 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4046 return FALSE;
4047 }
4048
4049 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
4050
4051 int rc = vboxVBVAChannelDisplayEnable(commonFromDeviceExt(pDevExt),
4052 pDevExt->iDevice,
4053 pInfo->u8Channel);
4054 if(RT_FAILURE(rc))
4055 {
4056 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
4057 }
4058 Result = TRUE;
4059 break;
4060 }
4061 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
4062 {
4063 /* TODO: implement */
4064 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4065 {
4066 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4067 return FALSE;
4068 }
4069 break;
4070 }
4071# ifdef VBOX_WITH_VIDEOHWACCEL
4072 case IOCTL_VIDEO_VHWA_QUERY_INFO:
4073 {
4074 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
4075 {
4076 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
4077 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
4078 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
4079 return FALSE;
4080 }
4081
4082 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
4083 {
4084 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4085 return FALSE;
4086 }
4087
4088 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
4089 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
4090 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
4091 Result = TRUE;
4092 break;
4093 }
4094# endif
4095 default:
4096 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
4097 RequestPacket->IoControlCode,
4098 (RequestPacket->IoControlCode >> 2) & 0xFFF,
4099 (RequestPacket->IoControlCode >> 2) & 0xFFF));
4100 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
4101 return FALSE;
4102 }
4103
4104 if (Result)
4105 RequestPacket->StatusBlock->Status = NO_ERROR;
4106 else
4107 RequestPacket->StatusBlock->Information = 0;
4108
4109// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
4110
4111 return TRUE;
4112}
4113
4114/**
4115 * VBoxVideoReset HW
4116 *
4117 * Resets the video hardware.
4118 */
4119BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
4120{
4121 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
4122
4123 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
4124
4125 if (pDevExt->iDevice > 0)
4126 {
4127 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
4128 pDevExt->iDevice));
4129 return TRUE;
4130 }
4131
4132 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
4133 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
4134
4135 if (pDevExt->u.primary.pvReqFlush != NULL)
4136 {
4137 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
4138 pDevExt->u.primary.pvReqFlush = NULL;
4139 }
4140
4141 VbglTerminate ();
4142
4143 VBoxFreeDisplaysHGSMI(commonFromDeviceExt(pDevExt));
4144 /** @note using this callback instead of doing things manually adds an
4145 * additional call to HGSMIHeapDestroy(). I assume that call was
4146 * merely forgotton in the first place. */
4147
4148 return TRUE;
4149}
4150
4151/**
4152 * VBoxVideoGetPowerState
4153 *
4154 * Queries whether the device can support the requested power state.
4155 */
4156VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
4157 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
4158{
4159 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
4160 return NO_ERROR;
4161}
4162
4163/**
4164 * VBoxVideoSetPowerState
4165 *
4166 * Sets the power state of the specified device
4167 */
4168VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
4169 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
4170{
4171 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
4172 return NO_ERROR;
4173}
4174#endif /* #ifndef VBOX_WITH_WDDM */
4175
4176/**
4177 * VBoxVideoSetGraphicsCap
4178 *
4179 * Tells the host whether or not we currently support graphics in the
4180 * additions
4181 */
4182BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
4183{
4184 VMMDevReqGuestCapabilities2 *req = NULL;
4185 int rc;
4186
4187 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4188 sizeof (VMMDevReqGuestCapabilities2),
4189 VMMDevReq_SetGuestCapabilities);
4190
4191 if (!RT_SUCCESS(rc))
4192 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
4193 else
4194 {
4195 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
4196 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
4197
4198 rc = VbglGRPerform (&req->header);
4199 if (RT_FAILURE(rc))
4200 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
4201 }
4202 if (req != NULL)
4203 VbglGRFree (&req->header);
4204 return RT_SUCCESS(rc);
4205}
4206
4207
4208BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
4209 USHORT width, USHORT height, USHORT bpp
4210#ifdef VBOX_WITH_WDDM
4211 , ULONG offDisplay
4212#endif
4213 )
4214{
4215 /* set the mode characteristics */
4216 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
4217 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, width);
4218 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
4219 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, height);
4220 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
4221 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, bpp);
4222 /* enable the mode */
4223 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
4224 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
4225#ifdef VBOX_WITH_WDDM
4226 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
4227 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
4228 ULONG xOffset = offDisplay % cbLine;
4229 if (bpp == 4)
4230 {
4231 xOffset <<= 1;
4232 }
4233 else
4234 {
4235 Assert(!(xOffset%((bpp + 7) >> 3)));
4236 xOffset /= ((bpp + 7) >> 3);
4237 }
4238 ULONG yOffset = offDisplay / cbLine;
4239 Assert(xOffset <= 0xffff);
4240 Assert(yOffset <= 0xffff);
4241 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
4242 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
4243 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
4244 VBoxVideoCmnPortWriteUshort(VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
4245#endif
4246 /** @todo read from the port to see if the mode switch was successful */
4247
4248 /* Tell the host that we now support graphics in the additions.
4249 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
4250 * mode switch and causes an OFF/ON sequence which is not handled by frontends
4251 * (for example Qt GUI debug build asserts when seamless is being enabled).
4252 */
4253 // VBoxVideoSetGraphicsCap(TRUE);
4254
4255 return TRUE;
4256}
4257
4258#ifndef VBOX_WITH_WDDM
4259
4260/**
4261 * VBoxVideoSetCurrentMode
4262 *
4263 * Sets the adapter to the specified operating mode.
4264 */
4265BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
4266 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
4267{
4268 PVIDEO_MODE_INFORMATION ModeInfo;
4269
4270 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
4271
4272 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
4273 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
4274 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
4275 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
4276
4277 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
4278 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
4279 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
4280
4281 if (DeviceExtension->iDevice > 0)
4282 {
4283 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
4284 DeviceExtension->iDevice));
4285 return TRUE;
4286 }
4287
4288 return VBoxVideoSetCurrentModePerform(DeviceExtension,
4289 (USHORT)ModeInfo->VisScreenWidth,
4290 (USHORT)ModeInfo->VisScreenHeight,
4291 (USHORT)ModeInfo->BitsPerPlane);
4292}
4293
4294/*
4295 * VBoxVideoResetDevice
4296 *
4297 * Resets the video hardware to the default mode, to which it was initialized
4298 * at system boot.
4299 */
4300
4301BOOLEAN FASTCALL VBoxVideoResetDevice(
4302 PDEVICE_EXTENSION DeviceExtension,
4303 PSTATUS_BLOCK StatusBlock)
4304{
4305 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
4306
4307 if (DeviceExtension->iDevice > 0)
4308 {
4309 /* If the device is the secondary display, however, it is recommended that no action be taken. */
4310 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
4311 DeviceExtension->iDevice));
4312 return TRUE;
4313 }
4314
4315#if 0
4316 /* Don't disable the extended video mode. This would only switch the video mode
4317 * to <current width> x <current height> x 0 bpp which is not what we want. And
4318 * even worse, it causes an disturbing additional mode switch */
4319 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
4320 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
4321#endif
4322
4323 /* Tell the host that we no longer support graphics in the additions
4324 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
4325 */
4326 // VBoxVideoSetGraphicsCap(FALSE);
4327 return TRUE;
4328}
4329
4330/**
4331 * VBoxVideoMapVideoMemory
4332 *
4333 * Maps the video hardware frame buffer and video RAM into the virtual address
4334 * space of the requestor.
4335 */
4336BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
4337 PVIDEO_MEMORY RequestedAddress,
4338 PVIDEO_MEMORY_INFORMATION MapInformation,
4339 PSTATUS_BLOCK StatusBlock)
4340{
4341 PHYSICAL_ADDRESS FrameBuffer;
4342 ULONG inIoSpace = 0;
4343 VP_STATUS Status;
4344
4345 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
4346
4347 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
4348
4349 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
4350 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
4351
4352 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
4353 &MapInformation->VideoRamLength, &inIoSpace,
4354 &MapInformation->VideoRamBase);
4355
4356 if (Status == NO_ERROR)
4357 {
4358 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
4359 MapInformation->FrameBufferLength =
4360 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
4361 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
4362 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
4363
4364 /* Save the new framebuffer size */
4365 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
4366 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
4367 MapInformation->FrameBufferBase,
4368 MapInformation->FrameBufferLength,
4369 DeviceExtension->ulFrameBufferOffset);
4370 return TRUE;
4371 }
4372
4373 return FALSE;
4374}
4375
4376/**
4377 * VBoxVideoUnmapVideoMemory
4378 *
4379 * Releases a mapping between the virtual address space and the adapter's
4380 * frame buffer and video RAM.
4381 */
4382BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
4383 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
4384{
4385 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
4386 HGSMIAreaClear (&DeviceExtension->areaDisplay);
4387 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
4388 return TRUE;
4389}
4390
4391/**
4392 * VBoxVideoQueryNumAvailModes
4393 *
4394 * Returns the number of video modes supported by the adapter and the size
4395 * in bytes of the video mode information, which can be used to allocate a
4396 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
4397 */
4398BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
4399 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
4400{
4401 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
4402 /* calculate the video modes table */
4403 VBoxBuildModesTable(DeviceExtension);
4404 Modes->NumModes = gNumVideoModes;
4405 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
4406 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
4407 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
4408 return TRUE;
4409}
4410
4411/**
4412 * VBoxVideoQueryAvailModes
4413 *
4414 * Returns information about each video mode supported by the adapter.
4415 */
4416BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
4417 PVIDEO_MODE_INFORMATION ReturnedModes,
4418 PSTATUS_BLOCK StatusBlock)
4419{
4420 ULONG Size;
4421
4422 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
4423
4424 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
4425 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
4426 StatusBlock->Information = Size;
4427
4428 return TRUE;
4429}
4430
4431/**
4432 * VBoxVideoQueryCurrentMode
4433 *
4434 * Returns information about current video mode.
4435 */
4436BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
4437 PVIDEO_MODE_INFORMATION VideoModeInfo,
4438 PSTATUS_BLOCK StatusBlock)
4439{
4440 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
4441
4442 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
4443 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
4444
4445 return TRUE;
4446}
4447#endif /* ifndef VBOX_WITH_WDDM */
4448/*
4449 * VBoxVideoSetColorRegisters
4450 *
4451 * Sets the adapter's color registers to the specified RGB values. There
4452 * are code paths in this function, one generic and one for VGA compatible
4453 * controllers. The latter is needed for Bochs, where the generic one isn't
4454 * yet implemented.
4455 */
4456
4457BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
4458 PDEVICE_EXTENSION DeviceExtension,
4459 PVIDEO_CLUT ColorLookUpTable,
4460 PSTATUS_BLOCK StatusBlock)
4461{
4462 LONG Entry;
4463
4464 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
4465
4466 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
4467 return FALSE;
4468
4469 for (Entry = ColorLookUpTable->FirstEntry;
4470 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
4471 Entry++)
4472 {
4473 VBoxVideoCmnPortWriteUchar(0x03c8, (UCHAR)Entry);
4474 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
4475 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
4476 VBoxVideoCmnPortWriteUchar(0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
4477 }
4478
4479 return TRUE;
4480}
4481
4482#ifndef VBOX_WITH_WDDM
4483
4484VP_STATUS VBoxVideoGetChildDescriptor(
4485 PVOID HwDeviceExtension,
4486 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
4487 PVIDEO_CHILD_TYPE VideoChildType,
4488 PUCHAR pChildDescriptor,
4489 PULONG pUId,
4490 PULONG pUnused)
4491{
4492 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
4493 HwDeviceExtension, ChildEnumInfo));
4494
4495 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
4496
4497 if (ChildEnumInfo->ChildIndex > 0)
4498 {
4499 if ((int)ChildEnumInfo->ChildIndex <= commonFromDeviceExt(pDevExt)->cDisplays)
4500 {
4501 *VideoChildType = Monitor;
4502 *pUId = ChildEnumInfo->ChildIndex;
4503
4504 return VIDEO_ENUM_MORE_DEVICES;
4505 }
4506 }
4507
4508 return ERROR_NO_MORE_DEVICES;
4509}
4510
4511
4512#ifndef VBOX_WITH_WDDM
4513VP_STATUS vboxWaitForSingleObjectVoid(IN PVOID HwDeviceExtension, IN PVOID Object, IN PLARGE_INTEGER Timeout OPTIONAL)
4514{
4515 return ERROR_INVALID_FUNCTION;
4516}
4517
4518LONG vboxSetEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4519{
4520 return 0;
4521}
4522
4523VOID vboxClearEventVoid (IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4524{
4525}
4526
4527VP_STATUS vboxCreateEventVoid(IN PVOID HwDeviceExtension, IN ULONG EventFlag, IN PVOID Unused, OUT PEVENT *ppEvent)
4528{
4529 return ERROR_INVALID_FUNCTION;
4530}
4531
4532VP_STATUS vboxDeleteEventVoid(IN PVOID HwDeviceExtension, IN PEVENT pEvent)
4533{
4534 return ERROR_INVALID_FUNCTION;
4535}
4536
4537PVOID vboxAllocatePoolVoid(IN PVOID HwDeviceExtension, IN VBOXVP_POOL_TYPE PoolType, IN size_t NumberOfBytes, IN ULONG Tag)
4538{
4539 return NULL;
4540}
4541
4542VOID vboxFreePoolVoid(IN PVOID HwDeviceExtension, IN PVOID Ptr)
4543{
4544}
4545
4546BOOLEAN vboxQueueDpcVoid(IN PVOID HwDeviceExtension, IN PMINIPORT_DPC_ROUTINE CallbackRoutine, IN PVOID Context)
4547{
4548 return FALSE;
4549}
4550
4551void VBoxSetupVideoPortFunctions(PDEVICE_EXTENSION PrimaryExtension, VBOXVIDEOPORTPROCS *pCallbacks, PVIDEO_PORT_CONFIG_INFO pConfigInfo)
4552{
4553 memset(pCallbacks, 0, sizeof(VBOXVIDEOPORTPROCS));
4554
4555 if (vboxQueryWinVersion() <= WINNT4)
4556 {
4557 /* VideoPortGetProcAddress is available for >= win2k */
4558 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
4559 pCallbacks->pfnSetEvent = vboxSetEventVoid;
4560 pCallbacks->pfnClearEvent = vboxClearEventVoid;
4561 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
4562 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
4563 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
4564 pCallbacks->pfnFreePool = vboxFreePoolVoid;
4565 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
4566 return;
4567 }
4568
4569 pCallbacks->pfnWaitForSingleObject = (PFNWAITFORSINGLEOBJECT)(pConfigInfo->VideoPortGetProcAddress)
4570 (PrimaryExtension,
4571 (PUCHAR)"VideoPortWaitForSingleObject");
4572 Assert(pCallbacks->pfnWaitForSingleObject);
4573
4574 pCallbacks->pfnSetEvent = (PFNSETEVENT)(pConfigInfo->VideoPortGetProcAddress)
4575 (PrimaryExtension,
4576 (PUCHAR)"VideoPortSetEvent");
4577 Assert(pCallbacks->pfnSetEvent);
4578
4579 pCallbacks->pfnClearEvent = (PFNCLEAREVENT)(pConfigInfo->VideoPortGetProcAddress)
4580 (PrimaryExtension,
4581 (PUCHAR)"VideoPortClearEvent");
4582 Assert(pCallbacks->pfnClearEvent);
4583
4584 pCallbacks->pfnCreateEvent = (PFNCREATEEVENT)(pConfigInfo->VideoPortGetProcAddress)
4585 (PrimaryExtension,
4586 (PUCHAR)"VideoPortCreateEvent");
4587 Assert(pCallbacks->pfnCreateEvent);
4588
4589 pCallbacks->pfnDeleteEvent = (PFNDELETEEVENT)(pConfigInfo->VideoPortGetProcAddress)
4590 (PrimaryExtension,
4591 (PUCHAR)"VideoPortDeleteEvent");
4592 Assert(pCallbacks->pfnDeleteEvent);
4593
4594 if(pCallbacks->pfnWaitForSingleObject
4595 && pCallbacks->pfnSetEvent
4596 && pCallbacks->pfnClearEvent
4597 && pCallbacks->pfnCreateEvent
4598 && pCallbacks->pfnDeleteEvent)
4599 {
4600 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_EVENT;
4601 }
4602 else
4603 {
4604 pCallbacks->pfnWaitForSingleObject = vboxWaitForSingleObjectVoid;
4605 pCallbacks->pfnSetEvent = vboxSetEventVoid;
4606 pCallbacks->pfnClearEvent = vboxClearEventVoid;
4607 pCallbacks->pfnCreateEvent = vboxCreateEventVoid;
4608 pCallbacks->pfnDeleteEvent = vboxDeleteEventVoid;
4609 }
4610
4611 pCallbacks->pfnAllocatePool = (PFNALLOCATEPOOL)(pConfigInfo->VideoPortGetProcAddress)
4612 (PrimaryExtension,
4613 (PUCHAR)"VideoPortAllocatePool");
4614 Assert(pCallbacks->pfnAllocatePool);
4615
4616 pCallbacks->pfnFreePool = (PFNFREEPOOL)(pConfigInfo->VideoPortGetProcAddress)
4617 (PrimaryExtension,
4618 (PUCHAR)"VideoPortFreePool");
4619 Assert(pCallbacks->pfnFreePool);
4620
4621 if(pCallbacks->pfnAllocatePool
4622 && pCallbacks->pfnFreePool)
4623 {
4624 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_POOL;
4625 }
4626 else
4627 {
4628 pCallbacks->pfnAllocatePool = vboxAllocatePoolVoid;
4629 pCallbacks->pfnFreePool = vboxFreePoolVoid;
4630 }
4631
4632 pCallbacks->pfnQueueDpc = (PFNQUEUEDPC)(pConfigInfo->VideoPortGetProcAddress)
4633 (PrimaryExtension,
4634 (PUCHAR)"VideoPortQueueDpc");
4635 Assert(pCallbacks->pfnQueueDpc);
4636
4637 if(pCallbacks->pfnQueueDpc)
4638 {
4639 pCallbacks->fSupportedTypes |= VBOXVIDEOPORTPROCS_DPC;
4640 }
4641 else
4642 {
4643 pCallbacks->pfnQueueDpc = vboxQueueDpcVoid;
4644 }
4645
4646#ifdef DEBUG_misha
4647 Assert(pCallbacks->fSupportedTypes & VBOXVIDEOPORTPROCS_EVENT);
4648#endif
4649}
4650#endif
4651
4652
4653static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
4654{
4655 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
4656 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
4657
4658 if (pPrimaryDevExt)
4659 {
4660 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
4661
4662 if (req)
4663 {
4664 int rc = VbglGRPerform (&req->header);
4665
4666 if (RT_FAILURE(rc))
4667 {
4668 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
4669 }
4670 }
4671 }
4672
4673 return;
4674}
4675
4676int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
4677{
4678 int rc = VINF_SUCCESS;
4679
4680 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
4681
4682 /*
4683 * Query the VMMDev memory pointer. There we need VBVAMemory.
4684 */
4685 VMMDevMemory *pVMMDevMemory = NULL;
4686
4687 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
4688
4689 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
4690
4691 if (pDevExt->iDevice > 0)
4692 {
4693 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
4694
4695 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
4696 pDevExt->iDevice));
4697
4698 if ( ulEnable
4699 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
4700 {
4701 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
4702 pVbvaResult->pfnFlush = vboxVbvaFlush;
4703 pVbvaResult->pvFlush = pDevExt;
4704 }
4705 else
4706 {
4707 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
4708 }
4709
4710 return rc;
4711 }
4712
4713 if (RT_SUCCESS(rc))
4714 {
4715 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
4716 if (pDevExt->u.primary.pvReqFlush == NULL)
4717 {
4718 VMMDevVideoAccelFlush *req = NULL;
4719
4720 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4721 sizeof (VMMDevVideoAccelFlush),
4722 VMMDevReq_VideoAccelFlush);
4723
4724 if (RT_SUCCESS (rc))
4725 {
4726 pDevExt->u.primary.pvReqFlush = req;
4727 }
4728 else
4729 {
4730 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
4731 }
4732 }
4733 }
4734 else
4735 {
4736 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
4737 }
4738
4739 if (RT_SUCCESS(rc))
4740 {
4741 ULONG ulEnabled = 0;
4742
4743 /*
4744 * Tell host that VBVA status is changed.
4745 */
4746 VMMDevVideoAccelEnable *req = NULL;
4747
4748 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
4749 sizeof (VMMDevVideoAccelEnable),
4750 VMMDevReq_VideoAccelEnable);
4751
4752 if (RT_SUCCESS(rc))
4753 {
4754 req->u32Enable = ulEnable;
4755 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
4756 req->fu32Status = 0;
4757
4758 rc = VbglGRPerform (&req->header);
4759
4760 if (RT_SUCCESS(rc))
4761 {
4762 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
4763 {
4764 /*
4765 * Initialize the result information and VBVA memory.
4766 */
4767 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
4768 {
4769 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
4770 pVbvaResult->pfnFlush = vboxVbvaFlush;
4771 pVbvaResult->pvFlush = pDevExt;
4772 ulEnabled = 1;
4773 }
4774 else
4775 {
4776 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
4777 }
4778
4779 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
4780 }
4781 else
4782 {
4783 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
4784
4785 /* Disable VBVA for old hosts. */
4786 req->u32Enable = 0;
4787 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
4788 req->fu32Status = 0;
4789
4790 VbglGRPerform (&req->header);
4791
4792 rc = VERR_NOT_SUPPORTED;
4793 }
4794 }
4795 else
4796 {
4797 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
4798 }
4799
4800 VbglGRFree (&req->header);
4801 }
4802 else
4803 {
4804 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
4805 }
4806
4807 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
4808 }
4809
4810 return rc;
4811}
4812#endif
Note: See TracBrowser for help on using the repository browser.

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