VirtualBox

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

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