VirtualBox

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

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

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