VirtualBox

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

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

Additions/common/VBoxVideo: additional modesetting APIs for saving and restoring modes

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

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