VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring

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