VirtualBox

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

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

VBoxVideo: Streamlined init code, always call VideoPortGetAccessRanges.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 132.3 KB
Line 
1/*
2 * VirtualBox Video miniport driver for NT/2k/XP
3 *
4 * Based on DDK sample code.
5 *
6 * Copyright (C) 2006-2007 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxVideo.h"
18#include "Helper.h"
19
20#include <iprt/log.h>
21#include <VBox/VMMDev.h>
22#include <VBox/VBoxGuest.h>
23#include <VBox/VBoxVideo.h>
24
25#include <VBox/VBoxGuestLib.h>
26#include <VBoxDisplay.h>
27
28#if _MSC_VER >= 1400 /* bird: MS fixed swprintf to be standard-conforming... */
29#define _INC_SWPRINTF_INL_
30extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
31#endif
32#include <wchar.h>
33
34#include "vboxioctl.h"
35
36
37static WCHAR VBoxChipType[] = L"VBOX";
38static WCHAR VBoxDACType[] = L"Integrated RAMDAC";
39static WCHAR VBoxAdapterString[] = L"VirtualBox Video Adapter";
40static WCHAR VBoxBiosString[] = L"Version 0xB0C2 or later";
41
42VIDEO_ACCESS_RANGE VGARanges[] = {
43 { 0x000003B0, 0x00000000, 0x0000000C, 1, 1, 1, 0 }, /* 0x3B0-0x3BB */
44 { 0x000003C0, 0x00000000, 0x00000020, 1, 1, 1, 0 }, /* 0x3C0-0x3DF */
45 { 0x000A0000, 0x00000000, 0x00020000, 0, 0, 1, 0 }, /* 0xA0000-0xBFFFF */
46};
47/*
48 * Globals for the last custom resolution set. This is important
49 * for system startup so that we report the last currently set
50 * custom resolution and Windows can use it again.
51 */
52#ifndef VBOX_WITH_MULTIMONITOR_FIX
53ULONG gCustomXRes = 0;
54ULONG gCustomYRes = 0;
55ULONG gCustomBPP = 0;
56#endif /* !VBOX_WITH_MULTIMONITOR_FIX */
57
58int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult);
59
60#ifndef VBOXWDDM
61ULONG DriverEntry(IN PVOID Context1, IN PVOID Context2)
62{
63 VIDEO_HW_INITIALIZATION_DATA InitData;
64 ULONG rc;
65
66 dprintf(("VBoxVideo::DriverEntry. Built %s %s\n", __DATE__, __TIME__));
67
68 VideoPortZeroMemory(&InitData, sizeof(VIDEO_HW_INITIALIZATION_DATA));
69 InitData.HwInitDataSize = sizeof(VIDEO_HW_INITIALIZATION_DATA);
70 InitData.HwFindAdapter = VBoxVideoFindAdapter;
71 InitData.HwInitialize = VBoxVideoInitialize;
72#if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
73 InitData.HwInterrupt = VBoxVideoInterrupt;
74#else
75 InitData.HwInterrupt = NULL;
76#endif
77 InitData.HwStartIO = VBoxVideoStartIO;
78 InitData.HwResetHw = VBoxVideoResetHW;
79 InitData.HwDeviceExtensionSize = 0;
80 // nowhere documented but without the following line, NT4 SP0 will choke
81 InitData.AdapterInterfaceType = PCIBus;
82 InitData.HwGetPowerState = VBoxVideoGetPowerState;
83 InitData.HwSetPowerState = VBoxVideoSetPowerState;
84 InitData.HwGetVideoChildDescriptor = VBoxVideoGetChildDescriptor;
85 InitData.HwDeviceExtensionSize = sizeof(DEVICE_EXTENSION);
86 // report legacy VGA resource ranges
87 InitData.HwLegacyResourceList = VGARanges;
88 InitData.HwLegacyResourceCount = sizeof(VGARanges) / sizeof(VGARanges[0]);
89
90 // our DDK is at the Win2k3 level so we have to take special measures
91 // for backwards compatibility
92 switch (vboxQueryWinVersion())
93 {
94 case WINNT4:
95 dprintf(("VBoxVideo::DriverEntry: WINNT4\n"));
96 InitData.HwInitDataSize = SIZE_OF_NT4_VIDEO_HW_INITIALIZATION_DATA;
97 break;
98 case WIN2K:
99 dprintf(("VBoxVideo::DriverEntry: WIN2K\n"));
100 InitData.HwInitDataSize = SIZE_OF_W2K_VIDEO_HW_INITIALIZATION_DATA;
101 break;
102 }
103 rc = VideoPortInitialize(Context1, Context2, &InitData, NULL);
104
105 dprintf(("VBoxVideo::DriverEntry: returning with rc = 0x%x\n", rc));
106 return rc;
107}
108
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---*/
140VP_STATUS VBoxRegistryCallback(PVOID HwDeviceExtension, PVOID Context,
141 PWSTR ValueName, PVOID ValueData, ULONG ValueLength)
142{
143 //dprintf(("VBoxVideo::VBoxRegistryCallback: Context: %p, ValueName: %S, ValueData: %p, ValueLength: %d\n",
144 // Context, ValueName, ValueData, ValueLength));
145 if (ValueLength)
146 {
147 if (Context)
148 *(ULONG *)Context = *(PULONG)ValueData;
149 else if (*((PULONG)ValueData) != 0)
150 return ERROR_INVALID_PARAMETER;
151 return NO_ERROR;
152 }
153 else
154 return ERROR_INVALID_PARAMETER;
155}
156
157VP_STATUS VBoxVideoCmnRegQueryDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t *pVal)
158{
159 return VideoPortGetRegistryParameters(Reg, pName, FALSE, VBoxRegistryCallback, pVal);
160}
161
162VP_STATUS VBoxVideoCmnRegSetDword(IN VBOXCMNREG Reg, PWSTR pName, uint32_t Val)
163{
164 return VideoPortSetRegistryParameters(Reg, pName, &Val, sizeof(Val));
165}
166
167#endif /* #ifndef VBOXWDDM */
168
169/*
170 * Global list of supported standard video modes. It will be
171 * filled dynamically.
172 */
173#define MAX_VIDEO_MODES 128
174#ifndef VBOX_WITH_MULTIMONITOR_FIX
175static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 2] = { 0 };
176#else
177/*
178 * Additional space is reserved for custom video modes for 64 guest monitors.
179 * The custom video mode index is alternating and 2 indexes are reserved for the last custom mode.
180 */
181static VIDEO_MODE_INFORMATION VideoModes[MAX_VIDEO_MODES + 64 + 2] = { 0 };
182/* On the driver startup this is initialized from registry (replaces gCustom*). */
183static VIDEO_MODE_INFORMATION CustomVideoModes[64] = { 0 };
184#endif /* VBOX_WITH_MULTIMONITOR_FIX */
185/* number of available video modes, set by VBoxBuildModesTable */
186static uint32_t gNumVideoModes = 0;
187
188#ifdef VBOX_WITH_MULTIMONITOR_FIX
189static void initVideoModeInformation(VIDEO_MODE_INFORMATION *pVideoMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
190{
191 /*
192 * Build mode entry.
193 */
194 memset(pVideoMode, 0, sizeof(VIDEO_MODE_INFORMATION));
195
196 pVideoMode->Length = sizeof(VIDEO_MODE_INFORMATION);
197 pVideoMode->ModeIndex = index;
198 pVideoMode->VisScreenWidth = xres;
199 pVideoMode->VisScreenHeight = yres - yoffset;
200 pVideoMode->ScreenStride = xres * ((bpp + 7) / 8);
201 pVideoMode->NumberOfPlanes = 1;
202 pVideoMode->BitsPerPlane = bpp;
203 pVideoMode->Frequency = 60;
204 pVideoMode->XMillimeter = 320;
205 pVideoMode->YMillimeter = 240;
206 switch (bpp)
207 {
208#ifdef VBOX_WITH_8BPP_MODES
209 case 8:
210 pVideoMode->NumberRedBits = 6;
211 pVideoMode->NumberGreenBits = 6;
212 pVideoMode->NumberBlueBits = 6;
213 pVideoMode->RedMask = 0;
214 pVideoMode->GreenMask = 0;
215 pVideoMode->BlueMask = 0;
216 break;
217#endif
218 case 16:
219 pVideoMode->NumberRedBits = 5;
220 pVideoMode->NumberGreenBits = 6;
221 pVideoMode->NumberBlueBits = 5;
222 pVideoMode->RedMask = 0xF800;
223 pVideoMode->GreenMask = 0x7E0;
224 pVideoMode->BlueMask = 0x1F;
225 break;
226 case 24:
227 pVideoMode->NumberRedBits = 8;
228 pVideoMode->NumberGreenBits = 8;
229 pVideoMode->NumberBlueBits = 8;
230 pVideoMode->RedMask = 0xFF0000;
231 pVideoMode->GreenMask = 0xFF00;
232 pVideoMode->BlueMask = 0xFF;
233 break;
234 case 32:
235 pVideoMode->NumberRedBits = 8;
236 pVideoMode->NumberGreenBits = 8;
237 pVideoMode->NumberBlueBits = 8;
238 pVideoMode->RedMask = 0xFF0000;
239 pVideoMode->GreenMask = 0xFF00;
240 pVideoMode->BlueMask = 0xFF;
241 break;
242 }
243 pVideoMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
244#ifdef VBOX_WITH_8BPP_MODES
245 if (bpp == 8)
246 pVideoMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
247#endif
248 pVideoMode->VideoMemoryBitmapWidth = xres;
249 pVideoMode->VideoMemoryBitmapHeight = yres - yoffset;
250 pVideoMode->DriverSpecificAttributeFlags = 0;
251}
252#endif /* VBOX_WITH_MULTIMONITOR_FIX */
253
254#ifdef VBOXWDDM
255/* preferred mode index */
256static uint32_t gPreferredVideoMode = 0;
257
258static D3DKMDT_2DREGION g_VBoxWddmVideoResolutions[RT_ELEMENTS(VideoModes)];
259static uint32_t g_VBoxWddmNumResolutions;
260
261DECLINLINE(int) vboxWddmRectComparator(const D3DKMDT_2DREGION *pReg1, const D3DKMDT_2DREGION *pReg2)
262{
263 int tmp = pReg1->cx - pReg2->cx;
264 if(tmp)
265 return tmp;
266 tmp = pReg1->cy - pReg2->cy;
267 return tmp;
268}
269
270/* builds a g_VBoxWddmVideoResolutions given VideoModes info */
271VOID vboxWddmBuildResolutionTable()
272{
273 g_VBoxWddmNumResolutions = 0;
274
275 /* we don't care about the efficiency at this time */
276 for (uint32_t i = 0; i < gNumVideoModes; ++i)
277 {
278 VIDEO_MODE_INFORMATION *pMode = &VideoModes[i];
279 bool bFound = false;
280 for (uint32_t j = 0; j < g_VBoxWddmNumResolutions; ++j)
281 {
282 if (g_VBoxWddmVideoResolutions[j].cx == pMode->VisScreenWidth
283 && g_VBoxWddmVideoResolutions[j].cy == pMode->VisScreenHeight)
284 {
285 bFound = true;
286 break;
287 }
288 }
289
290 if (!bFound)
291 {
292 Assert(g_VBoxWddmNumResolutions < RT_ELEMENTS(g_VBoxWddmVideoResolutions));
293 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cx = pMode->VisScreenWidth;
294 g_VBoxWddmVideoResolutions[g_VBoxWddmNumResolutions].cy = pMode->VisScreenHeight;
295 ++g_VBoxWddmNumResolutions;
296 }
297 }
298}
299#endif
300
301static uint32_t g_xresNoVRAM = 0, g_yresNoVRAM = 0, g_bppNoVRAM = 0;
302
303/**
304 * Helper function to dynamically build our table of standard video
305 * modes. We take the amount of VRAM and create modes with standard
306 * geometries until we've either reached the maximum number of modes
307 * or the available VRAM does not allow for additional modes.
308 */
309VOID VBoxBuildModesTable(PDEVICE_EXTENSION DeviceExtension)
310{
311 /* we need this static counter to always have a new mode index for our */
312 /* custom video mode, otherwise Windows thinks there is no mode switch */
313 static int gInvocationCounter = 0;
314
315 VBOXCMNREG Reg;
316 VBoxVideoCmnRegInit(DeviceExtension, &Reg);
317
318 /* the resolution matrix */
319 struct
320 {
321 uint16_t xRes;
322 uint16_t yRes;
323 } resolutionMatrix[] =
324 {
325 /* standard modes */
326 { 640, 480 },
327 { 800, 600 },
328 { 1024, 768 },
329 { 1152, 864 },
330 { 1280, 960 },
331 { 1280, 1024 },
332 { 1400, 1050 },
333 { 1600, 1200 },
334 { 1920, 1440 },
335 /* multi screen modes with 1280x1024 */
336 { 2560, 1024 },
337 { 3840, 1024 },
338 { 5120, 1024 },
339 /* multi screen modes with 1600x1200 */
340 { 3200, 1200 },
341 { 4800, 1200 },
342 { 6400, 1200 },
343 };
344 size_t matrixSize = sizeof(resolutionMatrix) / sizeof(resolutionMatrix[0]);
345
346 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
347 size_t maxModesPerColorDepth = MAX_VIDEO_MODES / 2 / 4;
348
349 /* size of the VRAM in bytes */
350
351#ifndef VBOXWDDM
352 ULONG vramSize = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
353#else
354 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(DeviceExtension);
355#ifndef VBOXWDDM_RENDER_FROM_SHADOW
356 /* at least two surfaces will be needed: primary & shadow */
357 vramSize /= 2;
358#endif
359
360 gPreferredVideoMode = 0;
361#endif
362
363 gNumVideoModes = 0;
364
365 size_t numModesCurrentColorDepth;
366 size_t matrixIndex;
367 VP_STATUS status = 0;
368
369 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
370 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
371 * This resolution could be rejected by a low resolution host (netbooks, etc).
372 */
373 int cBytesPerPixel;
374 for (cBytesPerPixel = 1; cBytesPerPixel <= 4; cBytesPerPixel++)
375 {
376 int cBitsPerPixel = cBytesPerPixel * 8; /* 8, 16, 24, 32 */
377
378#ifndef VBOX_WITH_8BPP_MODES
379 if (cBitsPerPixel == 8)
380 {
381 continue;
382 }
383#endif /* !VBOX_WITH_8BPP_MODES */
384
385 /* does the mode fit into the VRAM? */
386 if (800 * 600 * cBytesPerPixel > (LONG)vramSize)
387 {
388 continue;
389 }
390
391 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
392 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
393 VideoModes[gNumVideoModes].VisScreenWidth = 800;
394 VideoModes[gNumVideoModes].VisScreenHeight = 600;
395 VideoModes[gNumVideoModes].ScreenStride = 800 * cBytesPerPixel;
396 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
397 VideoModes[gNumVideoModes].BitsPerPlane = cBitsPerPixel;
398 VideoModes[gNumVideoModes].Frequency = 60;
399 VideoModes[gNumVideoModes].XMillimeter = 320;
400 VideoModes[gNumVideoModes].YMillimeter = 240;
401 switch (cBytesPerPixel)
402 {
403 case 1:
404 {
405 VideoModes[gNumVideoModes].NumberRedBits = 6;
406 VideoModes[gNumVideoModes].NumberGreenBits = 6;
407 VideoModes[gNumVideoModes].NumberBlueBits = 6;
408 VideoModes[gNumVideoModes].RedMask = 0;
409 VideoModes[gNumVideoModes].GreenMask = 0;
410 VideoModes[gNumVideoModes].BlueMask = 0;
411 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
412 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
413 } break;
414 case 2:
415 {
416 VideoModes[gNumVideoModes].NumberRedBits = 5;
417 VideoModes[gNumVideoModes].NumberGreenBits = 6;
418 VideoModes[gNumVideoModes].NumberBlueBits = 5;
419 VideoModes[gNumVideoModes].RedMask = 0xF800;
420 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
421 VideoModes[gNumVideoModes].BlueMask = 0x1F;
422 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
423 } break;
424 case 3:
425 {
426 VideoModes[gNumVideoModes].NumberRedBits = 8;
427 VideoModes[gNumVideoModes].NumberGreenBits = 8;
428 VideoModes[gNumVideoModes].NumberBlueBits = 8;
429 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
430 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
431 VideoModes[gNumVideoModes].BlueMask = 0xFF;
432 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
433 } break;
434 default:
435 case 4:
436 {
437 VideoModes[gNumVideoModes].NumberRedBits = 8;
438 VideoModes[gNumVideoModes].NumberGreenBits = 8;
439 VideoModes[gNumVideoModes].NumberBlueBits = 8;
440 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
441 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
442 VideoModes[gNumVideoModes].BlueMask = 0xFF;
443 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
444#ifdef VBOXWDDM
445 gPreferredVideoMode = gNumVideoModes;
446#endif
447 } break;
448 }
449 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = 800;
450 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = 600;
451 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
452
453 /* a new mode has been filled in */
454 ++gNumVideoModes;
455 }
456
457 /*
458 * Query the y-offset from the host
459 */
460 ULONG yOffset = vboxGetHeightReduction();
461
462#ifdef VBOX_WITH_8BPP_MODES
463 /*
464 * 8 bit video modes
465 */
466 numModesCurrentColorDepth = 0;
467 matrixIndex = 0;
468 while (numModesCurrentColorDepth < maxModesPerColorDepth)
469 {
470 /* are there any modes left in the matrix? */
471 if (matrixIndex >= matrixSize)
472 break;
473
474 /* does the mode fit into the VRAM? */
475 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 1 > (LONG)vramSize)
476 {
477 ++matrixIndex;
478 continue;
479 }
480
481 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
482 {
483 /* This mode was already added. */
484 ++matrixIndex;
485 continue;
486 }
487
488 /* does the host like that mode? */
489#ifndef VBOXWDDM
490 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
491#else
492 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 8))
493#endif
494 {
495 ++matrixIndex;
496 continue;
497 }
498
499 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
500 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
501 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
502 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
503 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 1;
504 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
505 VideoModes[gNumVideoModes].BitsPerPlane = 8;
506 VideoModes[gNumVideoModes].Frequency = 60;
507 VideoModes[gNumVideoModes].XMillimeter = 320;
508 VideoModes[gNumVideoModes].YMillimeter = 240;
509 VideoModes[gNumVideoModes].NumberRedBits = 6;
510 VideoModes[gNumVideoModes].NumberGreenBits = 6;
511 VideoModes[gNumVideoModes].NumberBlueBits = 6;
512 VideoModes[gNumVideoModes].RedMask = 0;
513 VideoModes[gNumVideoModes].GreenMask = 0;
514 VideoModes[gNumVideoModes].BlueMask = 0;
515 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN |
516 VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
517 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
518 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
519 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
520
521 /* a new mode has been filled in */
522 ++gNumVideoModes;
523 ++numModesCurrentColorDepth;
524 /* advance to the next mode matrix entry */
525 ++matrixIndex;
526 }
527#endif /* VBOX_WITH_8BPP_MODES */
528
529 /*
530 * 16 bit video modes
531 */
532 numModesCurrentColorDepth = 0;
533 matrixIndex = 0;
534 while (numModesCurrentColorDepth < maxModesPerColorDepth)
535 {
536 /* are there any modes left in the matrix? */
537 if (matrixIndex >= matrixSize)
538 break;
539
540 /* does the mode fit into the VRAM? */
541 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 2 > (LONG)vramSize)
542 {
543 ++matrixIndex;
544 continue;
545 }
546
547 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
548 {
549 /* This mode was already added. */
550 ++matrixIndex;
551 continue;
552 }
553
554 /* does the host like that mode? */
555#ifndef VBOXWDDM
556 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
557#else
558 if (!vboxLikesVideoMode(0 /* @todo: */, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 16))
559#endif
560
561 {
562 ++matrixIndex;
563 continue;
564 }
565
566 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
567 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
568 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
569 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
570 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 2;
571 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
572 VideoModes[gNumVideoModes].BitsPerPlane = 16;
573 VideoModes[gNumVideoModes].Frequency = 60;
574 VideoModes[gNumVideoModes].XMillimeter = 320;
575 VideoModes[gNumVideoModes].YMillimeter = 240;
576 VideoModes[gNumVideoModes].NumberRedBits = 5;
577 VideoModes[gNumVideoModes].NumberGreenBits = 6;
578 VideoModes[gNumVideoModes].NumberBlueBits = 5;
579 VideoModes[gNumVideoModes].RedMask = 0xF800;
580 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
581 VideoModes[gNumVideoModes].BlueMask = 0x1F;
582 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
583 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
584 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
585 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
586
587 /* a new mode has been filled in */
588 ++gNumVideoModes;
589 ++numModesCurrentColorDepth;
590 /* advance to the next mode matrix entry */
591 ++matrixIndex;
592 }
593
594 /*
595 * 24 bit video modes
596 */
597 numModesCurrentColorDepth = 0;
598 matrixIndex = 0;
599 while (numModesCurrentColorDepth < maxModesPerColorDepth)
600 {
601 /* are there any modes left in the matrix? */
602 if (matrixIndex >= matrixSize)
603 break;
604
605 /* does the mode fit into the VRAM? */
606 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 3 > (LONG)vramSize)
607 {
608 ++matrixIndex;
609 continue;
610 }
611
612 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
613 {
614 /* This mode was already added. */
615 ++matrixIndex;
616 continue;
617 }
618
619 /* does the host like that mode? */
620#ifndef VBOXWDDM
621 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
622#else
623 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 24))
624#endif
625 {
626 ++matrixIndex;
627 continue;
628 }
629
630 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
631 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
632 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
633 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
634 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 3;
635 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
636 VideoModes[gNumVideoModes].BitsPerPlane = 24;
637 VideoModes[gNumVideoModes].Frequency = 60;
638 VideoModes[gNumVideoModes].XMillimeter = 320;
639 VideoModes[gNumVideoModes].YMillimeter = 240;
640 VideoModes[gNumVideoModes].NumberRedBits = 8;
641 VideoModes[gNumVideoModes].NumberGreenBits = 8;
642 VideoModes[gNumVideoModes].NumberBlueBits = 8;
643 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
644 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
645 VideoModes[gNumVideoModes].BlueMask = 0xFF;
646 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
647 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
648 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
649 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
650
651 /* a new mode has been filled in */
652 ++gNumVideoModes;
653 ++numModesCurrentColorDepth;
654 /* advance to the next mode matrix entry */
655 ++matrixIndex;
656 }
657
658 /*
659 * 32 bit video modes
660 */
661 numModesCurrentColorDepth = 0;
662 matrixIndex = 0;
663 while (numModesCurrentColorDepth < maxModesPerColorDepth)
664 {
665 /* are there any modes left in the matrix? */
666 if (matrixIndex >= matrixSize)
667 break;
668
669 /* does the mode fit into the VRAM? */
670 if (resolutionMatrix[matrixIndex].xRes * resolutionMatrix[matrixIndex].yRes * 4 > (LONG)vramSize)
671 {
672 ++matrixIndex;
673 continue;
674 }
675
676 if (yOffset == 0 && resolutionMatrix[matrixIndex].xRes == 800 && resolutionMatrix[matrixIndex].yRes == 600)
677 {
678 /* This mode was already added. */
679 ++matrixIndex;
680 continue;
681 }
682
683 /* does the host like that mode? */
684#ifndef VBOXWDDM
685 if (!vboxLikesVideoMode(DeviceExtension->iDevice, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
686#else
687 if (!vboxLikesVideoMode(0, resolutionMatrix[matrixIndex].xRes, resolutionMatrix[matrixIndex].yRes - yOffset, 32))
688#endif
689 {
690 ++matrixIndex;
691 continue;
692 }
693
694 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
695 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
696 VideoModes[gNumVideoModes].VisScreenWidth = resolutionMatrix[matrixIndex].xRes;
697 VideoModes[gNumVideoModes].VisScreenHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
698 VideoModes[gNumVideoModes].ScreenStride = resolutionMatrix[matrixIndex].xRes * 4;
699 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
700 VideoModes[gNumVideoModes].BitsPerPlane = 32;
701 VideoModes[gNumVideoModes].Frequency = 60;
702 VideoModes[gNumVideoModes].XMillimeter = 320;
703 VideoModes[gNumVideoModes].YMillimeter = 240;
704 VideoModes[gNumVideoModes].NumberRedBits = 8;
705 VideoModes[gNumVideoModes].NumberGreenBits = 8;
706 VideoModes[gNumVideoModes].NumberBlueBits = 8;
707 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
708 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
709 VideoModes[gNumVideoModes].BlueMask = 0xFF;
710 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
711 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = resolutionMatrix[matrixIndex].xRes;
712 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = resolutionMatrix[matrixIndex].yRes - yOffset;
713 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
714
715 /* a new mode has been filled in */
716 ++gNumVideoModes;
717 ++numModesCurrentColorDepth;
718 /* advance to the next mode matrix entry */
719 ++matrixIndex;
720 }
721
722 /*
723 * Next, check the registry for additional modes
724 */
725 int curKeyNo = 0;
726#ifdef VBOXWDDM
727 int fPreferredSet = 0;
728#endif
729 do
730 {
731 /* check if there is space in the mode list */
732 if (gNumVideoModes >= MAX_VIDEO_MODES)
733 break;
734
735 wchar_t keyname[24];
736 uint32_t xres, yres, bpp = 0;
737 swprintf(keyname, L"CustomMode%dWidth", curKeyNo);
738 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &xres);
739 /* upon the first error, we give up */
740 if (status != NO_ERROR)
741 break;
742 swprintf(keyname, L"CustomMode%dHeight", curKeyNo);
743 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &yres);
744 /* upon the first error, we give up */
745 if (status != NO_ERROR)
746 break;
747 swprintf(keyname, L"CustomMode%dBPP", curKeyNo);
748 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &bpp);
749 /* upon the first error, we give up */
750 if (status != NO_ERROR)
751 break;
752
753 dprintf(("VBoxVideo: custom mode %u returned: xres = %u, yres = %u, bpp = %u\n",
754 curKeyNo, xres, yres, bpp));
755
756 /* first test: do the values make sense? */
757 if ( (xres > (1 << 16))
758 || (yres > (1 << 16))
759 || ( (bpp != 16)
760 && (bpp != 24)
761 && (bpp != 32)))
762 break;
763
764 /* round down width to be a multiple of 8 */
765 xres &= 0xFFF8;
766
767 /* second test: does it fit within our VRAM? */
768 if (xres * yres * (bpp / 8) > vramSize)
769 break;
770
771 /* third test: does the host like the video mode? */
772#ifndef VBOXWDDM
773 if (!vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
774#else
775 if (!vboxLikesVideoMode(0, xres, yres, bpp))
776#endif
777 break;
778
779 dprintf(("VBoxVideo: adding mode from registry: xres = %d, yres = %d, bpp = %d\n", xres, yres, bpp));
780
781#ifdef VBOXWDDM
782 if (!fPreferredSet)
783 {
784 gPreferredVideoMode = gNumVideoModes;
785 fPreferredSet = 1;
786 }
787#endif
788 /*
789 * Build mode entry.
790 * Note that we have to apply the y offset for the custom mode.
791 */
792 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
793 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
794 VideoModes[gNumVideoModes].VisScreenWidth = xres;
795 VideoModes[gNumVideoModes].VisScreenHeight = yres - yOffset;
796 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
797 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
798 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
799 VideoModes[gNumVideoModes].Frequency = 60;
800 VideoModes[gNumVideoModes].XMillimeter = 320;
801 VideoModes[gNumVideoModes].YMillimeter = 240;
802 switch (bpp)
803 {
804 case 16:
805 VideoModes[gNumVideoModes].NumberRedBits = 5;
806 VideoModes[gNumVideoModes].NumberGreenBits = 6;
807 VideoModes[gNumVideoModes].NumberBlueBits = 5;
808 VideoModes[gNumVideoModes].RedMask = 0xF800;
809 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
810 VideoModes[gNumVideoModes].BlueMask = 0x1F;
811 break;
812 case 24:
813 VideoModes[gNumVideoModes].NumberRedBits = 8;
814 VideoModes[gNumVideoModes].NumberGreenBits = 8;
815 VideoModes[gNumVideoModes].NumberBlueBits = 8;
816 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
817 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
818 VideoModes[gNumVideoModes].BlueMask = 0xFF;
819 break;
820 case 32:
821 VideoModes[gNumVideoModes].NumberRedBits = 8;
822 VideoModes[gNumVideoModes].NumberGreenBits = 8;
823 VideoModes[gNumVideoModes].NumberBlueBits = 8;
824 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
825 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
826 VideoModes[gNumVideoModes].BlueMask = 0xFF;
827#ifdef VBOXWDDM
828 /* 32-bit mode is more preferable, select it if not yet */
829 if (fPreferredSet < 2)
830 {
831 gPreferredVideoMode = gNumVideoModes;
832 fPreferredSet = 2;
833 }
834#endif
835 break;
836 }
837 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
838 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
839 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres - yOffset;
840 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
841 ++gNumVideoModes;
842
843 /* next run */
844 curKeyNo++;
845 /* only support 128 modes for now */
846 if (curKeyNo >= 128)
847 break;
848
849 } while(1);
850
851 /*
852 * Now we ask the host for a display change request. If there's one,
853 * this will be appended as a special mode so that it can be used by
854 * the Additions service process. The mode table is guaranteed to have
855 * two spare entries for this mode (alternating index thus 2).
856 *
857 * ... or ...
858 *
859 * Also we check if we got an user-stored custom resolution in the adapter
860 * registry key add it to the modes table.
861 */
862
863#ifdef VBOX_WITH_MULTIMONITOR_FIX
864 /* Add custom resolutions for each display and then for the display change request, if exists.
865 */
866 BOOLEAN fDisplayChangeRequest = FALSE;
867
868 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
869 if ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
870 && (xres || yres || bpp))
871 {
872 /* There is a pending display change request. */
873 fDisplayChangeRequest = TRUE;
874 }
875 if (display > RT_ELEMENTS(CustomVideoModes))
876 {
877 display = RT_ELEMENTS(CustomVideoModes) - 1;
878 }
879
880 dprintf(("display = %d, DeviceExtension->iDevice = %d\n", display, DeviceExtension->iDevice));
881 if (display != DeviceExtension->iDevice)
882 {
883 /* No need to go through the custom mode logic. And no need to clear the custom mode
884 * entry in the next 'for' loop.
885 */
886 fDisplayChangeRequest = FALSE;
887 }
888
889 dprintf(("VBoxVideo: fDisplayChangeRequest = %d\n", fDisplayChangeRequest));
890
891 /*
892 * Reinsert custom video modes for all displays.
893 */
894 int iCustomMode;
895 for (iCustomMode = 0; iCustomMode < DeviceExtension->pPrimary->u.primary.cDisplays; iCustomMode++)
896 {
897 if (fDisplayChangeRequest && iCustomMode == display)
898 {
899 /* Do not keep info for this display, which received a video mode hint, to make sure that
900 * the new mode will be taken from the alternating index entries actually.
901 */
902 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
903 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
904 }
905 else
906 {
907 VideoModes[gNumVideoModes] = CustomVideoModes[iCustomMode];
908 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
909 }
910#ifdef LOG_ENABLED
911 dprintf(("Custom mode for %2d: %4d x %4d @ %2d\n",
912 iCustomMode, CustomVideoModes[iCustomMode].VisScreenWidth,
913 CustomVideoModes[iCustomMode].VisScreenHeight, CustomVideoModes[iCustomMode].BitsPerPlane));
914#endif
915 gNumVideoModes++;
916 }
917
918 if (display != DeviceExtension->iDevice)
919 {
920 /* The display change is for another monitor. Just add 2 standard modes to the table
921 * to make enough entries. This is not necessary if it is a first mode set (CurrentMode == 0),
922 * because these 2 entries will be added by "if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)"
923 * code branch.
924 */
925 if (DeviceExtension->CurrentMode != 0)
926 {
927 dprintf(("Filling custom mode entries.\n"));
928 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
929 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
930 gNumVideoModes++;
931 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
932 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
933 gNumVideoModes++;
934 }
935 }
936#endif /* VBOX_WITH_MULTIMONITOR_FIX */
937
938#ifndef VBOX_WITH_MULTIMONITOR_FIX
939 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
940 if ( ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
941 && (xres || yres || bpp))
942 || (gCustomXRes || gCustomYRes || gCustomBPP))
943#else
944 if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)
945#endif /* VBOX_WITH_MULTIMONITOR_FIX */
946 {
947#ifndef VBOXWDDM
948 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
949 /* handle the startup case */
950 if (DeviceExtension->CurrentMode == 0)
951#else
952 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
953#endif
954 {
955 /* Use the stored custom resolution values only if nothing was read from host.
956 * The custom mode might be not valid anymore and would block any hints from host.
957 */
958#ifndef VBOX_WITH_MULTIMONITOR_FIX
959 if (!xres)
960 xres = gCustomXRes;
961 if (!yres)
962 yres = gCustomYRes;
963 if (!bpp)
964 bpp = gCustomBPP;
965 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d\n", xres, yres, bpp));
966#else
967 if (!xres)
968 xres = CustomVideoModes[DeviceExtension->iDevice].VisScreenWidth;
969 if (!yres)
970 yres = CustomVideoModes[DeviceExtension->iDevice].VisScreenHeight;
971 if (!bpp)
972 bpp = CustomVideoModes[DeviceExtension->iDevice].BitsPerPlane;
973 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, DeviceExtension->iDevice));
974#endif /* VBOX_WITH_MULTIMONITOR_FIX */
975 }
976 /* round down to multiple of 8 */
977 if ((xres & 0xfff8) != xres)
978 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
979 xres &= 0xfff8;
980 /* take the current values for the fields that are not set */
981#ifndef VBOXWDDM
982 if (DeviceExtension->CurrentMode != 0)
983 {
984 if (!xres)
985 xres = DeviceExtension->CurrentModeWidth;
986 if (!yres)
987 yres = DeviceExtension->CurrentModeHeight;
988 if (!bpp)
989 bpp = DeviceExtension->CurrentModeBPP;
990 }
991#else
992 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
993 {
994 if (!xres)
995 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
996 if (!yres)
997 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
998 if (!bpp)
999 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
1000 }
1001#endif
1002
1003 /* Use a default value. */
1004 if (!bpp)
1005 bpp = 32;
1006
1007 /* does the host like that mode? */
1008#ifndef VBOXWDDM
1009 if (vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
1010#else
1011 if (vboxLikesVideoMode(0, xres, yres, bpp))
1012#endif
1013 {
1014 /* we must have a valid video mode by now and it must fit within the VRAM */
1015 if ( ( xres
1016 && yres
1017 && ( (bpp == 16)
1018#ifdef VBOX_WITH_8BPP_MODES
1019 || (bpp == 8)
1020#endif
1021 || (bpp == 24)
1022 || (bpp == 32)))
1023 && (xres * yres * (bpp / 8) < vramSize))
1024
1025 {
1026 /* we need an alternating index */
1027#ifdef VBOX_WITH_MULTIMONITOR_FIX
1028 /* Only alternate index if the new custom mode differs from the last one
1029 * (only resolution and bpp changes are important, a display change does not matter).
1030 * Always add 2 last entries to the mode array, so number of video modes
1031 * do not change.
1032 */
1033 BOOLEAN fNewInvocation = FALSE;
1034 static uint32_t sPrev_xres = 0;
1035 static uint32_t sPrev_yres = 0;
1036 static uint32_t sPrev_bpp = 0;
1037 if ( sPrev_xres != xres
1038 || sPrev_yres != yres
1039 || sPrev_bpp != bpp)
1040 {
1041 sPrev_xres = xres;
1042 sPrev_yres = yres;
1043 sPrev_bpp = bpp;
1044 fNewInvocation = TRUE;
1045 }
1046 BOOLEAN fAlternatedIndex = FALSE;
1047#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1048#ifndef VBOXWDDM
1049 if (DeviceExtension->CurrentMode != 0)
1050#else
1051 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
1052#endif
1053#ifndef VBOX_WITH_MULTIMONITOR_FIX
1054 {
1055 if (gInvocationCounter % 2)
1056 gNumVideoModes++;
1057 gInvocationCounter++;
1058 }
1059#else
1060 {
1061 if (fNewInvocation)
1062 gInvocationCounter++;
1063 if (gInvocationCounter % 2)
1064 {
1065 fAlternatedIndex = TRUE;
1066
1067 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1068 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1069 gNumVideoModes++;
1070 }
1071 }
1072 else
1073 {
1074 fNewInvocation = FALSE;
1075 }
1076#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1077
1078 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
1079#ifdef VBOX_WITH_MULTIMONITOR_FIX
1080 dprintf(("VBoxVideo: fNewInvocation = %d, fAlternatedIndex = %d\n", fNewInvocation, fAlternatedIndex));
1081#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1082#ifdef VBOXWDDM
1083 /* assign host-supplied as the most preferable */
1084 gPreferredVideoMode = gNumVideoModes;
1085#endif
1086 /*
1087 * Build mode entry.
1088 * Note that we do not apply the y offset for the custom mode. It is
1089 * only used for the predefined modes that the user can configure in
1090 * the display properties dialog.
1091 */
1092 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1093 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1094 VideoModes[gNumVideoModes].VisScreenWidth = xres;
1095 VideoModes[gNumVideoModes].VisScreenHeight = yres;
1096 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
1097 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1098 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
1099 VideoModes[gNumVideoModes].Frequency = 60;
1100 VideoModes[gNumVideoModes].XMillimeter = 320;
1101 VideoModes[gNumVideoModes].YMillimeter = 240;
1102 switch (bpp)
1103 {
1104#ifdef VBOX_WITH_8BPP_MODES
1105 case 8:
1106 VideoModes[gNumVideoModes].NumberRedBits = 6;
1107 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1108 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1109 VideoModes[gNumVideoModes].RedMask = 0;
1110 VideoModes[gNumVideoModes].GreenMask = 0;
1111 VideoModes[gNumVideoModes].BlueMask = 0;
1112 break;
1113#endif
1114 case 16:
1115 VideoModes[gNumVideoModes].NumberRedBits = 5;
1116 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1117 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1118 VideoModes[gNumVideoModes].RedMask = 0xF800;
1119 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1120 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1121 break;
1122 case 24:
1123 VideoModes[gNumVideoModes].NumberRedBits = 8;
1124 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1125 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1126 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1127 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1128 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1129 break;
1130 case 32:
1131 VideoModes[gNumVideoModes].NumberRedBits = 8;
1132 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1133 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1134 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1135 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1136 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1137 break;
1138 }
1139 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1140#ifdef VBOX_WITH_8BPP_MODES
1141 if (bpp == 8)
1142 VideoModes[gNumVideoModes].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1143#endif
1144 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
1145 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres;
1146 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1147#ifdef VBOX_WITH_MULTIMONITOR_FIX
1148 /* Save the mode in the list of custom modes for this display. */
1149 CustomVideoModes[DeviceExtension->iDevice] = VideoModes[gNumVideoModes];
1150#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1151 ++gNumVideoModes;
1152
1153 /* for the startup case, we need this mode twice due to the alternating mode number */
1154#ifndef VBOXWDDM
1155 if (DeviceExtension->CurrentMode == 0)
1156#else
1157 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
1158#endif
1159 {
1160 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1161 memcpy(&VideoModes[gNumVideoModes], &VideoModes[gNumVideoModes - 1], sizeof(VIDEO_MODE_INFORMATION));
1162 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1163 gNumVideoModes++;
1164 }
1165#ifdef VBOX_WITH_MULTIMONITOR_FIX
1166 else if (!fAlternatedIndex)
1167 {
1168 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1169 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1170 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1171 gNumVideoModes++;
1172 }
1173#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1174
1175#ifndef VBOX_WITH_MULTIMONITOR_FIX
1176 /* store this video mode as the last custom video mode */
1177 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1178 if (status != NO_ERROR)
1179 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1180 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1181 if (status != NO_ERROR)
1182 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1183 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1184 if (status != NO_ERROR)
1185 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1186#else
1187 /* Save the custom mode for this display. */
1188 if (DeviceExtension->iDevice == 0)
1189 {
1190 /* Name without a suffix */
1191 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1192 if (status != NO_ERROR)
1193 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1194 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1195 if (status != NO_ERROR)
1196 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1197 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1198 if (status != NO_ERROR)
1199 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1200 }
1201 else
1202 {
1203 wchar_t keyname[32];
1204 swprintf(keyname, L"CustomXRes%d", DeviceExtension->iDevice);
1205 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
1206 if (status != NO_ERROR)
1207 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, DeviceExtension->iDevice));
1208 swprintf(keyname, L"CustomYRes%d", DeviceExtension->iDevice);
1209 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
1210 if (status != NO_ERROR)
1211 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, DeviceExtension->iDevice));
1212 swprintf(keyname, L"CustomBPP%d", DeviceExtension->iDevice);
1213 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
1214 if (status != NO_ERROR)
1215 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, DeviceExtension->iDevice));
1216 }
1217#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1218 }
1219 else
1220 {
1221 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
1222 xres, yres, bpp, vramSize));
1223 if (xres * yres * (bpp / 8) >= vramSize
1224 && (xres != g_xresNoVRAM || yres != g_yresNoVRAM || bpp != g_bppNoVRAM))
1225 {
1226 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
1227 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
1228 g_xresNoVRAM = xres;
1229 g_yresNoVRAM = yres;
1230 g_bppNoVRAM = bpp;
1231 }
1232 }
1233 }
1234 else
1235 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
1236 xres, yres, bpp));
1237 }
1238#if defined(LOG_ENABLED)
1239 {
1240 int i;
1241#ifndef VBOXWDDM
1242 dprintf(("VBoxVideo: VideoModes (CurrentMode = %d, last #%d)\n", DeviceExtension->CurrentMode, gNumVideoModes));
1243#endif
1244 for (i = 0; i < RT_ELEMENTS(VideoModes); i++)
1245 {
1246 if ( VideoModes[i].VisScreenWidth
1247 || VideoModes[i].VisScreenHeight
1248 || VideoModes[i].BitsPerPlane)
1249 {
1250 dprintf((" %2d: #%d %4d x %4d @ %2d\n",
1251 i, VideoModes[i].ModeIndex, VideoModes[i].VisScreenWidth,
1252 VideoModes[i].VisScreenHeight, VideoModes[i].BitsPerPlane));
1253 }
1254 }
1255 }
1256#endif
1257
1258#ifdef VBOXWDDM
1259 vboxWddmBuildResolutionTable();
1260#endif
1261
1262 VBoxVideoCmnRegFini(Reg);
1263}
1264
1265#ifdef VBOXWDDM
1266static bool g_bModesTableInitialized = false;
1267/**
1268 * Helper function to dynamically build our table of standard video
1269 * modes. We take the amount of VRAM and create modes with standard
1270 * geometries until we've either reached the maximum number of modes
1271 * or the available VRAM does not allow for additional modes.
1272 */
1273VOID VBoxWddmGetModesTable(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1274 VIDEO_MODE_INFORMATION ** ppModes, uint32_t * pcModes, int32_t * pPreferrableMode,
1275 D3DKMDT_2DREGION **ppResolutions, uint32_t * pcResolutions)
1276{
1277 if(bRebuildTable || !g_bModesTableInitialized)
1278 {
1279 VBoxBuildModesTable(DeviceExtension);
1280 g_bModesTableInitialized = true;
1281 }
1282
1283 *ppModes = VideoModes;
1284 *pcModes = gNumVideoModes;
1285 *pPreferrableMode = (int32_t)gPreferredVideoMode;
1286 *ppResolutions = g_VBoxWddmVideoResolutions;
1287 *pcResolutions = g_VBoxWddmNumResolutions;
1288}
1289
1290VOID VBoxWddmInvalidateModesTable(PDEVICE_EXTENSION DeviceExtension)
1291{
1292 g_bModesTableInitialized = false;
1293}
1294
1295NTSTATUS VBoxWddmGetModesForResolution(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1296 D3DKMDT_2DREGION *pResolution,
1297 VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode)
1298{
1299 VIDEO_MODE_INFORMATION *pAllModes;
1300 uint32_t cAllModes, cAllResolutions;
1301 int32_t iPreferrableMode;
1302 D3DKMDT_2DREGION *pAllResolutions;
1303 VBoxWddmGetModesTable(DeviceExtension, bRebuildTable,
1304 &pAllModes, &cAllModes, &iPreferrableMode,
1305 &pAllResolutions, &cAllResolutions);
1306 NTSTATUS Status = STATUS_SUCCESS;
1307 uint32_t cFound = 0;
1308 int iFoundPreferrableMode = -1;
1309 for (uint32_t i = 0; i < cAllModes; ++i)
1310 {
1311 VIDEO_MODE_INFORMATION *pCur = &pAllModes[i];
1312 if (pResolution->cx == pAllModes[i].VisScreenWidth
1313 && pResolution->cy == pAllModes[i].VisScreenHeight)
1314 {
1315 if (pModes && cModes > cFound)
1316 memcpy(&pModes[cFound], pCur, sizeof (VIDEO_MODE_INFORMATION));
1317 else
1318 Status = STATUS_BUFFER_TOO_SMALL;
1319
1320 if (i == (uint32_t)iPreferrableMode)
1321 iFoundPreferrableMode = cFound;
1322
1323 ++cFound;
1324 }
1325 }
1326
1327 Assert(iFoundPreferrableMode < 0 || cFound > (uint32_t)iFoundPreferrableMode);
1328
1329 *pcModes = cFound;
1330 if (piPreferrableMode)
1331 *piPreferrableMode = iFoundPreferrableMode;
1332
1333 return Status;
1334}
1335
1336#else
1337
1338/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
1339void VBoxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
1340{
1341#ifndef VBOX_WITH_HGSMI
1342 ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
1343 - PrimaryExtension->u.primary.cbMiniportHeap
1344 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1345#else
1346 ULONG ulAvailable = PrimaryExtension->u.primary.cbVRAM
1347 - PrimaryExtension->u.primary.cbMiniportHeap
1348 - VBVA_ADAPTER_INFORMATION_SIZE;
1349#endif /* VBOX_WITH_HGSMI */
1350
1351 /* Size of a framebuffer. */
1352
1353 ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
1354
1355 /* Align down to 4096 bytes. */
1356 ulSize &= ~0xFFF;
1357
1358 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
1359 PrimaryExtension->u.primary.cbVRAM, PrimaryExtension->u.primary.cDisplays,
1360 ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
1361 ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
1362
1363#ifndef VBOX_WITH_HGSMI
1364 if (ulSize > VBOX_VIDEO_DISPLAY_INFORMATION_SIZE)
1365 {
1366 /* Compute the size of the framebuffer. */
1367 ulSize -= VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
1368 }
1369 else
1370 {
1371 /* Should not really get here. But still do it safely. */
1372 ulSize = 0;
1373 }
1374#endif /* !VBOX_WITH_HGSMI */
1375
1376 /* Update the primary info. */
1377 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
1378#ifndef VBOX_WITH_HGSMI
1379 PrimaryExtension->u.primary.ulDisplayInformationSize = VBOX_VIDEO_DISPLAY_INFORMATION_SIZE;
1380#endif /* !VBOX_WITH_HGSMI */
1381
1382 /* Update the per extension info. */
1383 PDEVICE_EXTENSION Extension = PrimaryExtension;
1384 ULONG ulFrameBufferOffset = 0;
1385 while (Extension)
1386 {
1387 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
1388 /* That is assigned when a video mode is set. */
1389 Extension->ulFrameBufferSize = 0;
1390
1391 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
1392 Extension->iDevice, ulFrameBufferOffset));
1393
1394#ifndef VBOX_WITH_HGSMI
1395 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize
1396 + PrimaryExtension->u.primary.ulDisplayInformationSize;
1397#else
1398 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1399#endif /* VBOX_WITH_HGSMI */
1400
1401 Extension = Extension->pNext;
1402 }
1403}
1404
1405#endif
1406
1407int VBoxMapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulOffset, ULONG ulSize)
1408{
1409 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
1410
1411 if (!ulSize)
1412 {
1413 dprintf(("Illegal length 0!\n"));
1414 return ERROR_INVALID_PARAMETER;
1415 }
1416
1417 PHYSICAL_ADDRESS FrameBuffer;
1418 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
1419
1420 PVOID VideoRamBase = NULL;
1421 ULONG VideoRamLength = ulSize;
1422 VP_STATUS Status;
1423#ifndef VBOXWDDM
1424 ULONG inIoSpace = 0;
1425
1426 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
1427 &VideoRamLength, &inIoSpace,
1428 &VideoRamBase);
1429#else
1430 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1431 FrameBuffer,
1432 VideoRamLength,
1433 FALSE, /* IN BOOLEAN InIoSpace */
1434 FALSE, /* IN BOOLEAN MapToUserMode */
1435 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
1436 &VideoRamBase /*OUT PVOID *VirtualAddress*/
1437 );
1438 Assert(ntStatus == STATUS_SUCCESS);
1439 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
1440#endif
1441
1442 if (Status == NO_ERROR)
1443 {
1444 *ppv = VideoRamBase;
1445 }
1446
1447 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
1448
1449 return Status;
1450}
1451
1452void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulSize)
1453{
1454 dprintf(("VBoxVideo::VBoxMapAdapterMemory\n"));
1455
1456 if (*ppv)
1457 {
1458#ifndef VBOXWDDM
1459 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
1460#else
1461 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1462 *ppv);
1463 Assert(ntStatus == STATUS_SUCCESS);
1464#endif
1465 }
1466
1467 *ppv = NULL;
1468}
1469
1470#ifndef VBOX_WITH_HGSMI
1471
1472# ifdef VBOXWDDM
1473/* sanity check */
1474# error WDDM is supported only for HGSMI-based driver
1475# endif
1476
1477static void vboxQueryConf (PDEVICE_EXTENSION PrimaryExtension, uint32_t u32Index, ULONG *pulValue)
1478{
1479 dprintf(("VBoxVideo::vboxQueryConf: u32Index = %d\n", u32Index));
1480
1481 typedef struct _VBOXVIDEOQCONF32
1482 {
1483 VBOXVIDEOINFOHDR hdrQuery;
1484 VBOXVIDEOINFOQUERYCONF32 query;
1485 VBOXVIDEOINFOHDR hdrEnd;
1486 } VBOXVIDEOQCONF32;
1487
1488 VBOXVIDEOQCONF32 *p = (VBOXVIDEOQCONF32 *)PrimaryExtension->u.primary.pvAdapterInformation;
1489
1490 p->hdrQuery.u8Type = VBOX_VIDEO_INFO_TYPE_QUERY_CONF32;
1491 p->hdrQuery.u8Reserved = 0;
1492 p->hdrQuery.u16Length = sizeof (VBOXVIDEOINFOQUERYCONF32);
1493
1494 p->query.u32Index = u32Index;
1495 p->query.u32Value = 0;
1496
1497 p->hdrEnd.u8Type = VBOX_VIDEO_INFO_TYPE_END;
1498 p->hdrEnd.u8Reserved = 0;
1499 p->hdrEnd.u16Length = 0;
1500
1501 /* Let the host to process the commands. */
1502 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1503 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1504
1505 *pulValue = (ULONG)p->query.u32Value;
1506
1507 dprintf(("VBoxVideo::vboxQueryConf: u32Value = %d\n", p->query.u32Value));
1508}
1509
1510static void vboxSetupAdapterInfo (PDEVICE_EXTENSION PrimaryExtension)
1511{
1512 dprintf(("VBoxVideo::vboxSetupAdapterInfo\n"));
1513
1514 VBOXVIDEOINFOHDR *pHdr;
1515
1516 uint8_t *pu8 = (uint8_t *)PrimaryExtension->u.primary.pvAdapterInformation;
1517
1518 PDEVICE_EXTENSION Extension = PrimaryExtension;
1519 while (Extension)
1520 {
1521 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1522 pu8 += sizeof (VBOXVIDEOINFOHDR);
1523
1524 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_DISPLAY;
1525 pHdr->u8Reserved = 0;
1526 pHdr->u16Length = sizeof (VBOXVIDEOINFODISPLAY);
1527
1528 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
1529 pu8 += sizeof (VBOXVIDEOINFODISPLAY);
1530
1531 pDisplay->u32Index = Extension->iDevice;
1532 pDisplay->u32Offset = Extension->ulFrameBufferOffset;
1533 pDisplay->u32FramebufferSize = PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1534 pDisplay->u32InformationSize = PrimaryExtension->u.primary.ulDisplayInformationSize;
1535
1536 Extension = Extension->pNext;
1537 }
1538
1539
1540 /* The heap description. */
1541 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1542 pu8 += sizeof (VBOXVIDEOINFOHDR);
1543
1544 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_NV_HEAP;
1545 pHdr->u8Reserved = 0;
1546 pHdr->u16Length = sizeof (VBOXVIDEOINFONVHEAP);
1547
1548 VBOXVIDEOINFONVHEAP *pHeap = (VBOXVIDEOINFONVHEAP *)pu8;
1549 pu8 += sizeof (VBOXVIDEOINFONVHEAP);
1550
1551 pHeap->u32HeapOffset = PrimaryExtension->u.primary.cbVRAM
1552 - PrimaryExtension->u.primary.cbMiniportHeap
1553 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1554 pHeap->u32HeapSize = PrimaryExtension->u.primary.cbMiniportHeap;
1555
1556
1557 /* The END marker. */
1558 pHdr = (VBOXVIDEOINFOHDR *)pu8;
1559 pu8 += sizeof (VBOXVIDEOINFOHDR);
1560
1561 pHdr->u8Type = VBOX_VIDEO_INFO_TYPE_END;
1562 pHdr->u8Reserved = 0;
1563 pHdr->u16Length = 0;
1564
1565 /* Inform the host about the display configuration. */
1566 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
1567 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY);
1568
1569 dprintf(("VBoxVideo::vboxSetupAdapterInfo finished\n"));
1570}
1571
1572/**
1573 * Helper function to register secondary displays (DualView). Note that this will not
1574 * be available on pre-XP versions, and some editions on XP will fail because they are
1575 * intentionally crippled.
1576 */
1577VOID VBoxSetupDisplays(PDEVICE_EXTENSION PrimaryExtension, PVIDEO_PORT_CONFIG_INFO pConfigInfo, ULONG AdapterMemorySize)
1578{
1579 VP_STATUS rc = NO_ERROR;
1580
1581 dprintf(("VBoxVideo::VBoxSetupDisplays: PrimaryExtension = %p\n",
1582 PrimaryExtension));
1583
1584 /* Preinitialize the primary extension. */
1585 PrimaryExtension->pNext = NULL;
1586 PrimaryExtension->pPrimary = PrimaryExtension;
1587 PrimaryExtension->iDevice = 0;
1588 PrimaryExtension->ulFrameBufferOffset = 0;
1589 PrimaryExtension->ulFrameBufferSize = 0;
1590 PrimaryExtension->u.primary.ulVbvaEnabled = 0;
1591 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1592 PrimaryExtension->u.primary.cDisplays = 1;
1593 PrimaryExtension->u.primary.cbVRAM = AdapterMemorySize;
1594 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1595 PrimaryExtension->u.primary.pvMiniportHeap = NULL;
1596 PrimaryExtension->u.primary.pvAdapterInformation = NULL;
1597 PrimaryExtension->u.primary.ulMaxFrameBufferSize = 0;
1598 PrimaryExtension->u.primary.ulDisplayInformationSize = 0;
1599
1600 /* Verify whether the HW supports VirtualBox extensions. */
1601 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1602 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_VBOX_VIDEO);
1603
1604 if (VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA) == VBE_DISPI_ID_VBOX_VIDEO)
1605 {
1606 PrimaryExtension->u.primary.bVBoxVideoSupported = TRUE;
1607 }
1608
1609 dprintf(("VBoxVideo::VBoxSetupDisplays: bVBoxVideoSupported = %d\n",
1610 PrimaryExtension->u.primary.bVBoxVideoSupported));
1611
1612 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1613 {
1614 /* Map the adapter information. It will be needed to query some configuration values. */
1615 rc = VBoxMapAdapterMemory (PrimaryExtension,
1616 &PrimaryExtension->u.primary.pvAdapterInformation,
1617 PrimaryExtension->u.primary.cbVRAM - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE,
1618 VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1619 );
1620 if (rc != NO_ERROR)
1621 {
1622 dprintf(("VBoxVideo::VBoxSetupDisplays: VBoxMapAdapterMemory pvAdapterInfoirrmation failed rc = %d\n",
1623 rc));
1624
1625 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1626 }
1627 }
1628
1629 /* Setup the non-volatile heap and the adapter memory. */
1630 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1631 {
1632 /* Query the size of the non-volatile heap. */
1633 ULONG cbMiniportHeap = 0;
1634 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE, &cbMiniportHeap);
1635
1636 /* Do not allow too big heap. 50% of VRAM should be enough. */
1637 ULONG cbMiniportHeapMaxSize = AdapterMemorySize / 2 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
1638
1639 if (cbMiniportHeap > cbMiniportHeapMaxSize)
1640 {
1641 cbMiniportHeap = cbMiniportHeapMaxSize;
1642 }
1643
1644 /* Round up to 4096. */
1645 PrimaryExtension->u.primary.cbMiniportHeap = (cbMiniportHeap + 0xFFF) & ~0xFFF;
1646
1647 dprintf(("VBoxVideo::VBoxSetupDisplays: cbMiniportHeap = 0x%08X, PrimaryExtension->u.primary.cbMiniportHeap = 0x%08X, cbMiniportHeapMaxSize = 0x%08X\n",
1648 cbMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap, cbMiniportHeapMaxSize));
1649
1650 /* Map the heap region and the adapter information area.
1651 *
1652 * Note: the heap will be used by display drivers, possibly by a few instances
1653 * in multimonitor configuration, but the memory is mapped here ones.
1654 * It is assumed that all display drivers and the miniport has the SAME
1655 * virtual address space.
1656 *
1657 */
1658 rc = VBoxMapAdapterMemory (PrimaryExtension,
1659 &PrimaryExtension->u.primary.pvMiniportHeap,
1660 PrimaryExtension->u.primary.cbVRAM
1661 - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE
1662 - PrimaryExtension->u.primary.cbMiniportHeap,
1663 PrimaryExtension->u.primary.cbMiniportHeap
1664 );
1665
1666 if (rc != NO_ERROR)
1667 {
1668 PrimaryExtension->u.primary.cbMiniportHeap = 0;
1669 PrimaryExtension->u.primary.bVBoxVideoSupported = FALSE;
1670 }
1671 }
1672
1673 /* Check whether the guest supports multimonitors. */
1674 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1675 {
1676 typedef VP_STATUS (*PFNCREATESECONDARYDISPLAY)(PVOID, PVOID *, ULONG);
1677 PFNCREATESECONDARYDISPLAY pfnCreateSecondaryDisplay = NULL;
1678
1679 /* Dynamically query the VideoPort import to be binary compatible across Windows versions */
1680 if (vboxQueryWinVersion() > WINNT4)
1681 {
1682 /* This bluescreens on NT4, hence the above version check */
1683 pfnCreateSecondaryDisplay = (PFNCREATESECONDARYDISPLAY)(pConfigInfo->VideoPortGetProcAddress)
1684 (PrimaryExtension,
1685 (PUCHAR)"VideoPortCreateSecondaryDisplay");
1686 }
1687
1688 if (pfnCreateSecondaryDisplay != NULL)
1689 {
1690 /* Query the configured number of displays. */
1691 ULONG cDisplays = 0;
1692 vboxQueryConf (PrimaryExtension, VBOX_VIDEO_QCI32_MONITOR_COUNT, &cDisplays);
1693
1694 dprintf(("VBoxVideo::VBoxSetupDisplays: cDisplays = %d\n",
1695 cDisplays));
1696
1697 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
1698 {
1699 /* Host reported some bad value. Continue in the 1 screen mode. */
1700 cDisplays = 1;
1701 }
1702
1703 PDEVICE_EXTENSION pPrev = PrimaryExtension;
1704
1705 ULONG iDisplay;
1706 for (iDisplay = 1; iDisplay < cDisplays; iDisplay++)
1707 {
1708 PDEVICE_EXTENSION SecondaryExtension = NULL;
1709 rc = pfnCreateSecondaryDisplay (PrimaryExtension, (PVOID*)&SecondaryExtension, VIDEO_DUALVIEW_REMOVABLE);
1710
1711 dprintf(("VBoxVideo::VBoxSetupDisplays: VideoPortCreateSecondaryDisplay returned %#x, SecondaryExtension = %p\n",
1712 rc, SecondaryExtension));
1713
1714 if (rc != NO_ERROR)
1715 {
1716 break;
1717 }
1718
1719 SecondaryExtension->pNext = NULL;
1720 SecondaryExtension->pPrimary = PrimaryExtension;
1721 SecondaryExtension->iDevice = iDisplay;
1722 SecondaryExtension->ulFrameBufferOffset = 0;
1723 SecondaryExtension->ulFrameBufferSize = 0;
1724 SecondaryExtension->u.secondary.bEnabled = FALSE;
1725
1726 /* Update the list pointers. */
1727 pPrev->pNext = SecondaryExtension;
1728 pPrev = SecondaryExtension;
1729
1730 /* Take the successfully created display into account. */
1731 PrimaryExtension->u.primary.cDisplays++;
1732 }
1733
1734 /* Failure to create secondary displays is not fatal */
1735 rc = NO_ERROR;
1736 }
1737 }
1738
1739 /* Now when the number of monitors is known and extensions are created,
1740 * calculate the layout of framebuffers.
1741 */
1742 VBoxComputeFrameBufferSizes (PrimaryExtension);
1743
1744 if (PrimaryExtension->u.primary.bVBoxVideoSupported)
1745 {
1746 /* Setup the information for the host. */
1747 vboxSetupAdapterInfo (PrimaryExtension);
1748 }
1749 else
1750 {
1751 /* Unmap the memory if VBoxVideo is not supported. */
1752 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvMiniportHeap, PrimaryExtension->u.primary.cbMiniportHeap);
1753 VBoxUnmapAdapterMemory (PrimaryExtension, &PrimaryExtension->u.primary.pvAdapterInformation, VBOX_VIDEO_ADAPTER_INFORMATION_SIZE);
1754 }
1755
1756 dprintf(("VBoxVideo::VBoxSetupDisplays: finished\n"));
1757}
1758#endif /* !VBOX_WITH_HGSMI */
1759
1760#ifndef VBOXWDDM
1761
1762VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1763 IN PVOID HwContext, IN PWSTR ArgumentString,
1764 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1765 OUT PUCHAR Again)
1766{
1767 VP_STATUS rc;
1768 USHORT DispiId;
1769 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1770
1771 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
1772
1773#ifdef VBOX_WITH_HGSMI
1774 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
1775#endif
1776
1777 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1778 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1779 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1780 if (DispiId == VBE_DISPI_ID2)
1781 {
1782 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1783 /*
1784 * Write some hardware information to registry, so that
1785 * it's visible in Windows property dialog.
1786 */
1787
1788 rc = VideoPortSetRegistryParameters(
1789 HwDeviceExtension,
1790 L"HardwareInformation.ChipType",
1791 VBoxChipType,
1792 sizeof(VBoxChipType));
1793
1794 rc = VideoPortSetRegistryParameters(
1795 HwDeviceExtension,
1796 L"HardwareInformation.DacType",
1797 VBoxDACType,
1798 sizeof(VBoxDACType));
1799
1800 /*
1801 * Query the adapter's memory size. It's a bit of a hack, we just read
1802 * an ULONG from the data port without setting an index before.
1803 */
1804 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1805 rc = VideoPortSetRegistryParameters(
1806 HwDeviceExtension,
1807 L"HardwareInformation.MemorySize",
1808 &AdapterMemorySize,
1809 sizeof(ULONG));
1810
1811 rc = VideoPortSetRegistryParameters(
1812 HwDeviceExtension,
1813 L"HardwareInformation.AdapterString",
1814 VBoxAdapterString,
1815 sizeof(VBoxAdapterString));
1816
1817 rc = VideoPortSetRegistryParameters(
1818 HwDeviceExtension,
1819 L"HardwareInformation.BiosString",
1820 VBoxBiosString,
1821 sizeof(VBoxBiosString));
1822
1823 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
1824
1825#ifdef VBOX_WITH_HGSMI
1826 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
1827 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
1828#endif /* VBOX_WITH_HGSMI */
1829
1830 VIDEO_ACCESS_RANGE tmpRanges[4];
1831 ULONG slot = 0;
1832
1833 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
1834
1835 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
1836 VP_STATUS status;
1837 if (vboxQueryWinVersion() == WINNT4)
1838 {
1839 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
1840 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
1841 */
1842 ULONG vendorId = 0x80EE;
1843 ULONG deviceId = 0xBEEF;
1844 status = VideoPortGetAccessRanges(HwDeviceExtension,
1845 0,
1846 NULL,
1847 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1848 tmpRanges,
1849 &vendorId,
1850 &deviceId,
1851 &slot);
1852 }
1853 else
1854 {
1855 status = VideoPortGetAccessRanges(HwDeviceExtension,
1856 0,
1857 NULL,
1858 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1859 tmpRanges,
1860 NULL,
1861 NULL,
1862 &slot);
1863 }
1864 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
1865
1866 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
1867 rc = VbglInit ();
1868 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1869
1870#ifndef VBOX_WITH_HGSMI
1871 /* Setup the Device Extension and if possible secondary displays. */
1872 VBoxSetupDisplays((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1873#else
1874 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1875 * code will be ifdef'ed and later removed.
1876 * The host will however support both old and new interface to keep compatibility
1877 * with old guest additions.
1878 */
1879 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize);
1880
1881 if (((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.bHGSMI)
1882 {
1883 LogRel(("VBoxVideo: using HGSMI\n"));
1884 }
1885#endif /* VBOX_WITH_HGSMI */
1886
1887 // pretend success to make the driver work.
1888 rc = NO_ERROR;
1889 } else
1890 {
1891 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1892 rc = ERROR_DEV_NOT_EXIST;
1893 }
1894 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1895 return rc;
1896}
1897
1898/**
1899 * VBoxVideoInitialize
1900 *
1901 * Performs the first initialization of the adapter, after the HAL has given
1902 * up control of the video hardware to the video port driver.
1903 */
1904BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1905{
1906 VP_STATUS status;
1907
1908 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1909
1910 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1911
1912 /* Initialize the request pointer. */
1913 pDevExt->u.primary.pvReqFlush = NULL;
1914
1915#ifndef VBOX_WITH_MULTIMONITOR_FIX
1916 /*
1917 * Get the last custom resolution
1918 */
1919 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1920 L"CustomXRes",
1921 FALSE,
1922 VBoxRegistryCallback,
1923 &gCustomXRes);
1924 if (status != NO_ERROR)
1925 gCustomXRes = 0;
1926 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1927 L"CustomYRes",
1928 FALSE,
1929 VBoxRegistryCallback,
1930 &gCustomYRes);
1931 if (status != NO_ERROR)
1932 gCustomYRes = 0;
1933 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1934 L"CustomBPP",
1935 FALSE,
1936 VBoxRegistryCallback,
1937 &gCustomBPP);
1938 if (status != NO_ERROR)
1939 gCustomBPP = 0;
1940
1941 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1942#else
1943 /* Initialize all custom modes to the 800x600x32. */
1944 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
1945
1946 int iCustomMode;
1947 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
1948 {
1949 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
1950 }
1951
1952 /* Load stored custom resolution from the registry. */
1953 PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
1954 for (iCustomMode = 0; iCustomMode < DeviceExtension->pPrimary->u.primary.cDisplays; iCustomMode++)
1955 {
1956 /*
1957 * Get the last custom resolution
1958 */
1959 ULONG CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
1960
1961 if (iCustomMode == 0)
1962 {
1963 /* Name without a suffix */
1964 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1965 L"CustomXRes",
1966 FALSE,
1967 VBoxRegistryCallback,
1968 &CustomXRes);
1969 if (status != NO_ERROR)
1970 CustomXRes = 0;
1971 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1972 L"CustomYRes",
1973 FALSE,
1974 VBoxRegistryCallback,
1975 &CustomYRes);
1976 if (status != NO_ERROR)
1977 CustomYRes = 0;
1978 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1979 L"CustomBPP",
1980 FALSE,
1981 VBoxRegistryCallback,
1982 &CustomBPP);
1983 if (status != NO_ERROR)
1984 CustomBPP = 0;
1985 }
1986 else
1987 {
1988 wchar_t keyname[32];
1989 swprintf(keyname, L"CustomXRes%d", iCustomMode);
1990 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1991 keyname,
1992 FALSE,
1993 VBoxRegistryCallback,
1994 &CustomXRes);
1995 if (status != NO_ERROR)
1996 CustomXRes = 0;
1997 swprintf(keyname, L"CustomYRes%d", iCustomMode);
1998 status = VideoPortGetRegistryParameters(HwDeviceExtension,
1999 keyname,
2000 FALSE,
2001 VBoxRegistryCallback,
2002 &CustomYRes);
2003 if (status != NO_ERROR)
2004 CustomYRes = 0;
2005 swprintf(keyname, L"CustomBPP%d", iCustomMode);
2006 status = VideoPortGetRegistryParameters(HwDeviceExtension,
2007 keyname,
2008 FALSE,
2009 VBoxRegistryCallback,
2010 &CustomBPP);
2011 if (status != NO_ERROR)
2012 CustomBPP = 0;
2013 }
2014
2015 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
2016
2017 if (CustomXRes || CustomYRes || CustomBPP)
2018 {
2019 if (CustomXRes == 0)
2020 {
2021 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
2022 }
2023 if (CustomYRes == 0)
2024 {
2025 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
2026 }
2027 if (CustomBPP == 0)
2028 {
2029 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
2030 }
2031
2032 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
2033 }
2034 }
2035#endif /* VBOX_WITH_MULTIMONITOR_FIX */
2036
2037 return TRUE;
2038}
2039
2040# if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL)
2041
2042BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
2043{
2044 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2045 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
2046 if (PrimaryExtension)
2047 {
2048 if (PrimaryExtension->u.primary.pHostFlags) /* If HGSMI is enabled at all. */
2049 {
2050 uint32_t flags = PrimaryExtension->u.primary.pHostFlags->u32HostFlags;
2051 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
2052 {
2053 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
2054 {
2055 /* schedule a DPC*/
2056 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
2057 Assert(bResult);
2058 }
2059 /* clear the IRQ */
2060 HGSMIClearIrq (PrimaryExtension);
2061 return TRUE;
2062 }
2063 }
2064 }
2065 return FALSE;
2066}
2067# endif /* #if defined(VBOX_WITH_HGSMI) && defined(VBOX_WITH_VIDEOHWACCEL) */
2068#endif /* #ifndef VBOXWDDM */
2069/**
2070 * Send a request to the host to make the absolute pointer visible
2071 */
2072static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
2073{
2074 BOOLEAN Result = TRUE;
2075
2076 /* Use primary device extension, because the show pointer request should be processed
2077 * in vboxUpdatePointerShape regardless of the device. */
2078#ifndef VBOXWDDM
2079 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
2080#else
2081 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
2082#endif
2083
2084 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
2085 {
2086 // tell the host to use the guest's pointer
2087 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2088
2089 /* Visible and No Shape means Show the pointer.
2090 * It is enough to init only this field.
2091 */
2092 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
2093
2094#ifndef VBOX_WITH_HGSMI
2095 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
2096#else
2097 Result = vboxUpdatePointerShape(PrimaryExtension, &PointerAttributes, sizeof (PointerAttributes));
2098#endif /* VBOX_WITH_HGSMI */
2099
2100 if (Result)
2101 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
2102 else
2103 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
2104 }
2105 return Result;
2106}
2107
2108#ifndef VBOXWDDM
2109/**
2110 * VBoxVideoStartIO
2111 *
2112 * Processes the specified Video Request Packet.
2113 */
2114BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
2115 PVIDEO_REQUEST_PACKET RequestPacket)
2116{
2117 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2118
2119 BOOLEAN Result;
2120
2121// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
2122
2123 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2124
2125 switch (RequestPacket->IoControlCode)
2126 {
2127 case IOCTL_VIDEO_SET_CURRENT_MODE:
2128 {
2129 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
2130 {
2131 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2132 return TRUE;
2133 }
2134 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2135 (PVIDEO_MODE)RequestPacket->InputBuffer,
2136 RequestPacket->StatusBlock);
2137 break;
2138 }
2139
2140 case IOCTL_VIDEO_RESET_DEVICE:
2141 {
2142 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
2143 RequestPacket->StatusBlock);
2144 break;
2145 }
2146
2147 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
2148 {
2149 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
2150 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
2151 {
2152 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2153 return TRUE;
2154 }
2155 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
2156 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
2157 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
2158 RequestPacket->StatusBlock);
2159 break;
2160 }
2161
2162 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
2163 {
2164 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
2165 {
2166 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2167 return TRUE;
2168 }
2169 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
2170 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
2171 RequestPacket->StatusBlock);
2172 break;
2173 }
2174
2175 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
2176 {
2177 PVIDEO_SHARE_MEMORY pShareMemory;
2178 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
2179 PHYSICAL_ADDRESS shareAddress;
2180 PVOID virtualAddress = NULL;
2181 ULONG sharedViewSize;
2182 ULONG inIoSpace = 0;
2183 VP_STATUS status;
2184
2185 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
2186
2187 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
2188 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
2189
2190 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
2191 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2192 Result = FALSE;
2193 break;
2194 }
2195
2196 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
2197
2198 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
2199 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
2200
2201 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));
2202 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
2203 Result = FALSE;
2204 break;
2205 }
2206
2207 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
2208
2209 virtualAddress = pShareMemory->ProcessHandle;
2210 sharedViewSize = pShareMemory->ViewSize;
2211
2212 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
2213
2214 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
2215 if (status != NO_ERROR)
2216 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
2217 Result = (status == NO_ERROR);
2218
2219 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
2220 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
2221 pShareMemoryInformation->VirtualAddress = virtualAddress;
2222 pShareMemoryInformation->SharedViewSize = sharedViewSize;
2223 break;
2224 }
2225
2226 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
2227 {
2228 PVIDEO_SHARE_MEMORY pShareMemory;
2229 VP_STATUS status;
2230
2231 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
2232
2233 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
2234 {
2235 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
2236 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2237 Result = FALSE;
2238 break;
2239 }
2240
2241 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
2242
2243 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
2244 if (status != NO_ERROR)
2245 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
2246 Result = (status == NO_ERROR);
2247 break;
2248 }
2249
2250 /*
2251 * The display driver asks us how many video modes we support
2252 * so that it can supply an appropriate buffer for the next call.
2253 */
2254 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
2255 {
2256 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
2257 {
2258 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2259 return TRUE;
2260 }
2261 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
2262 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
2263 RequestPacket->StatusBlock);
2264 break;
2265 }
2266
2267 /*
2268 * The display driver asks us to provide a list of supported video modes
2269 * into a buffer it has allocated.
2270 */
2271 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
2272 {
2273 if (RequestPacket->OutputBufferLength <
2274 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
2275 {
2276 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2277 return TRUE;
2278 }
2279 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
2280 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2281 RequestPacket->StatusBlock);
2282 break;
2283 }
2284
2285 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
2286 {
2287 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
2288 RequestPacket->InputBufferLength <
2289 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
2290 sizeof(VIDEO_CLUT))
2291 {
2292 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2293 return TRUE;
2294 }
2295 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
2296 (PVIDEO_CLUT)RequestPacket->InputBuffer,
2297 RequestPacket->StatusBlock);
2298 break;
2299 }
2300
2301 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
2302 {
2303 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
2304 {
2305 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2306 return TRUE;
2307 }
2308 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2309 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2310 RequestPacket->StatusBlock);
2311 break;
2312 }
2313
2314 // show the pointer
2315 case IOCTL_VIDEO_ENABLE_POINTER:
2316 {
2317 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
2318 // find out whether the host wants absolute positioning
2319 /// @todo this is now obsolete - remove it?
2320 if (vboxQueryHostWantsAbsolute())
2321 Result = ShowPointer(HwDeviceExtension);
2322 else
2323 {
2324 // fallback to software pointer
2325 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2326 Result = FALSE;
2327 }
2328 break;
2329 }
2330
2331 // hide the pointer
2332 case IOCTL_VIDEO_DISABLE_POINTER:
2333 {
2334 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
2335 // find out whether the host wants absolute positioning
2336 if (vboxQueryHostWantsAbsolute())
2337 {
2338 // tell the host to hide pointer
2339 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2340
2341 /* Enable == 0 means no shape, not visible.
2342 * It is enough to init only this field.
2343 */
2344 PointerAttributes.Enable = 0;
2345
2346#ifndef VBOX_WITH_HGSMI
2347 Result = vboxUpdatePointerShape(&PointerAttributes, sizeof (PointerAttributes));
2348#else
2349 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
2350#endif /* VBOX_WITH_HGSMI */
2351
2352 if (Result)
2353 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
2354 else
2355 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
2356 } else
2357 {
2358 // fallback to software pointer
2359 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2360 Result = FALSE;
2361 }
2362 break;
2363 }
2364
2365 /*
2366 * Change the pointer shape
2367 */
2368 case IOCTL_VIDEO_SET_POINTER_ATTR:
2369 {
2370 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
2371 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
2372 {
2373 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
2374 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2375 return TRUE;
2376 }
2377 // find out whether the host wants absolute positioning
2378 if (vboxQueryHostWantsAbsolute())
2379 {
2380 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
2381#if 0
2382 dprintf(("Pointer shape information:\n"
2383 "\tFlags: %d\n"
2384 "\tWidth: %d\n"
2385 "\tHeight: %d\n"
2386 "\tWidthInBytes: %d\n"
2387 "\tEnable: %d\n"
2388 "\tColumn: %d\n"
2389 "\tRow: %d\n",
2390 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
2391 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
2392 pPointerAttributes->Row));
2393 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
2394#endif
2395#ifndef VBOX_WITH_HGSMI
2396 Result = vboxUpdatePointerShape(pPointerAttributes, RequestPacket->InputBufferLength);
2397#else
2398 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
2399#endif /* VBOX_WITH_HGSMI */
2400 if (!Result)
2401 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
2402 } else
2403 {
2404 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
2405 // fallback to software pointer
2406 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2407 Result = FALSE;
2408 }
2409 break;
2410 }
2411
2412 // query pointer information
2413 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
2414 {
2415 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
2416 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2417 Result = FALSE;
2418 break;
2419 }
2420
2421 // set the pointer position
2422 case IOCTL_VIDEO_SET_POINTER_POSITION:
2423 {
2424 // find out whether the host wants absolute positioning
2425 /// @todo this is now obsolete - remove it?
2426 if (vboxQueryHostWantsAbsolute())
2427 Result = ShowPointer(HwDeviceExtension);
2428 else
2429 {
2430 // fallback to software pointer
2431 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2432 Result = FALSE;
2433 }
2434 break;
2435 }
2436
2437 // query the pointer position
2438 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
2439 {
2440 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
2441 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
2442 {
2443 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2444 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2445 return TRUE;
2446 }
2447 Result = FALSE;
2448 uint16_t mousePosX;
2449 uint16_t mousePosY;
2450 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
2451 {
2452 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
2453 PVIDEO_MODE_INFORMATION ModeInfo;
2454 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
2455 // map from 0xFFFF to the current resolution
2456 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
2457 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
2458 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
2459 Result = TRUE;
2460 }
2461 if (!Result)
2462 {
2463 // fallback to software pointer
2464 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2465 }
2466 break;
2467 }
2468
2469 // Determine hardware cursor capabilities. We will always report that we are
2470 // very capable even though the host might not want to do pointer integration.
2471 // This is done because we can still return errors on the actual calls later to
2472 // make the display driver go to the fallback routines.
2473 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
2474 {
2475 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
2476 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
2477 {
2478 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2479 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2480 return TRUE;
2481 }
2482 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
2483 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
2484 VIDEO_MODE_COLOR_POINTER |
2485 VIDEO_MODE_MONO_POINTER;
2486 // for now we go with 64x64 cursors
2487 pCaps->MaxWidth = 64;
2488 pCaps->MaxHeight = 64;
2489 // that doesn't seem to be relevant, VBoxDisp doesn't use it
2490 pCaps->HWPtrBitmapStart = -1;
2491 pCaps->HWPtrBitmapEnd = -1;
2492 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
2493 Result = TRUE;
2494 break;
2495 }
2496
2497 /* Attach/detach DualView devices */
2498 case IOCTL_VIDEO_SWITCH_DUALVIEW:
2499 {
2500 ULONG ulAttach;
2501
2502 ulAttach = *((PULONG)RequestPacket->InputBuffer);
2503 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
2504
2505 if (pDevExt->iDevice > 0)
2506 {
2507 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
2508 }
2509 Result = TRUE;
2510 break;
2511 }
2512
2513 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
2514 {
2515 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
2516
2517 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
2518 {
2519 /* The display driver must have prepared the monitor information. */
2520 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
2521 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
2522 }
2523 else
2524 {
2525 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2526 }
2527 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
2528 break;
2529 }
2530
2531#ifndef VBOX_WITH_HGSMI
2532 case IOCTL_VIDEO_QUERY_DISPLAY_INFO:
2533 {
2534 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_DISPLAY_INFO\n"));
2535
2536 if (RequestPacket->OutputBufferLength < sizeof(QUERYDISPLAYINFORESULT))
2537 {
2538 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2539 RequestPacket->OutputBufferLength, sizeof(QUERYDISPLAYINFORESULT)));
2540 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2541 return FALSE;
2542 }
2543
2544 QUERYDISPLAYINFORESULT *pDispInfo = (QUERYDISPLAYINFORESULT *)RequestPacket->OutputBuffer;
2545
2546 pDispInfo->iDevice = pDevExt->iDevice;
2547 pDispInfo->u32DisplayInfoSize = pDevExt->pPrimary->u.primary.ulDisplayInformationSize;
2548
2549 RequestPacket->StatusBlock->Information = sizeof(QUERYDISPLAYINFORESULT);
2550 Result = TRUE;
2551
2552 break;
2553 }
2554#endif /* !VBOX_WITH_HGSMI */
2555
2556 case IOCTL_VIDEO_VBVA_ENABLE:
2557 {
2558 int rc;
2559 ULONG ulEnable;
2560
2561 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2562
2563 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2564 {
2565 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2566 RequestPacket->InputBufferLength, sizeof(ULONG)));
2567 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2568 return FALSE;
2569 }
2570
2571 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2572 {
2573 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2574 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2575 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2576 return FALSE;
2577 }
2578
2579 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2580 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2581
2582 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2583 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2584
2585 if (RT_FAILURE (rc))
2586 {
2587 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2588 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2589 return FALSE;
2590 }
2591
2592 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2593 Result = TRUE;
2594
2595 break;
2596 }
2597
2598 /* Private ioctls */
2599 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2600 {
2601 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2602 int rc;
2603
2604 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2605 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2606 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2607 {
2608 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2609 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2610 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2611 return FALSE;
2612 }
2613 /*
2614 * Inform the host about the visible region
2615 */
2616 VMMDevVideoSetVisibleRegion *req = NULL;
2617
2618 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2619 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2620 VMMDevReq_VideoSetVisibleRegion);
2621
2622 if (RT_SUCCESS(rc))
2623 {
2624 req->cRect = cRect;
2625 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2626
2627 rc = VbglGRPerform (&req->header);
2628
2629 if (RT_SUCCESS(rc))
2630 {
2631 Result = TRUE;
2632 break;
2633 }
2634 }
2635
2636 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
2637 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2638 return FALSE;
2639 }
2640
2641#ifdef VBOX_WITH_HGSMI
2642 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2643 {
2644 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2645
2646 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2647 {
2648 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2649 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2650 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2651 return FALSE;
2652 }
2653
2654 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2655 {
2656 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2657 return FALSE;
2658 }
2659
2660 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2661
2662 pInfo->iDevice = pDevExt->iDevice;
2663 pInfo->ulFlags = 0;
2664
2665 /* Describes VRAM chunk for this display device. */
2666 pInfo->areaDisplay = pDevExt->areaDisplay;
2667
2668 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2669 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2670
2671 pInfo->IOPortGuestCommand = pDevExt->pPrimary->u.primary.IOPortGuest;
2672
2673 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2674 Result = TRUE;
2675
2676 break;
2677 }
2678 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2679 {
2680 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2681
2682 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2683 {
2684 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2685 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2686 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2687 return FALSE;
2688 }
2689
2690 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2691 {
2692 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2693 return FALSE;
2694 }
2695
2696 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2697
2698 pInfo->hContext = pDevExt;
2699 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2700 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2701
2702 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2703 Result = TRUE;
2704 break;
2705 }
2706 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2707 {
2708 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2709
2710 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2711 {
2712 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2713 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2714 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2715 return FALSE;
2716 }
2717
2718 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2719 {
2720 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2721 return FALSE;
2722 }
2723
2724 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2725 pInfo->pContext = pDevExt->pPrimary;
2726 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2727
2728 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2729 Result = TRUE;
2730 break;
2731 }
2732 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2733 {
2734 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2735
2736 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2737 {
2738 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2739 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2740 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2741 return FALSE;
2742 }
2743
2744 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2745 {
2746 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2747 return FALSE;
2748 }
2749
2750 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2751
2752 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2753 pDevExt->iDevice,
2754 pInfo->u8Channel);
2755 if(RT_FAILURE(rc))
2756 {
2757 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2758 }
2759 Result = TRUE;
2760 break;
2761 }
2762 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2763 {
2764 /* TODO: implement */
2765 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2766 {
2767 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2768 return FALSE;
2769 }
2770 break;
2771 }
2772# ifdef VBOX_WITH_VIDEOHWACCEL
2773 case IOCTL_VIDEO_VHWA_QUERY_INFO:
2774 {
2775 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
2776 {
2777 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2778 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
2779 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2780 return FALSE;
2781 }
2782
2783 if (!pDevExt->pPrimary->u.primary.bHGSMI)
2784 {
2785 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2786 return FALSE;
2787 }
2788
2789 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
2790 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
2791 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
2792 Result = TRUE;
2793 break;
2794 }
2795# endif
2796#endif /* VBOX_WITH_HGSMI */
2797 default:
2798 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2799 RequestPacket->IoControlCode,
2800 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2801 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2802 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2803 return FALSE;
2804 }
2805
2806 if (Result)
2807 RequestPacket->StatusBlock->Status = NO_ERROR;
2808 else
2809 RequestPacket->StatusBlock->Information = 0;
2810
2811// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2812
2813 return TRUE;
2814}
2815
2816/**
2817 * VBoxVideoReset HW
2818 *
2819 * Resets the video hardware.
2820 */
2821BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2822{
2823 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2824
2825 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2826
2827 if (pDevExt->iDevice > 0)
2828 {
2829 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2830 pDevExt->iDevice));
2831 return TRUE;
2832 }
2833
2834 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2835 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2836
2837 if (pDevExt->u.primary.pvReqFlush != NULL)
2838 {
2839 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2840 pDevExt->u.primary.pvReqFlush = NULL;
2841 }
2842
2843 VbglTerminate ();
2844
2845 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvMiniportHeap, pDevExt->u.primary.cbMiniportHeap);
2846 VBoxUnmapAdapterMemory (pDevExt, &pDevExt->u.primary.pvAdapterInformation, VBVA_ADAPTER_INFORMATION_SIZE);
2847
2848 return TRUE;
2849}
2850
2851/**
2852 * VBoxVideoGetPowerState
2853 *
2854 * Queries whether the device can support the requested power state.
2855 */
2856VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2857 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2858{
2859 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2860 return NO_ERROR;
2861}
2862
2863/**
2864 * VBoxVideoSetPowerState
2865 *
2866 * Sets the power state of the specified device
2867 */
2868VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2869 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2870{
2871 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2872 return NO_ERROR;
2873}
2874#endif /* #ifndef VBOXWDDM */
2875
2876/**
2877 * VBoxVideoSetGraphicsCap
2878 *
2879 * Tells the host whether or not we currently support graphics in the
2880 * additions
2881 */
2882BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2883{
2884 VMMDevReqGuestCapabilities2 *req = NULL;
2885 int rc;
2886
2887 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2888 sizeof (VMMDevReqGuestCapabilities2),
2889 VMMDevReq_SetGuestCapabilities);
2890
2891 if (!RT_SUCCESS(rc))
2892 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2893 else
2894 {
2895 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2896 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2897
2898 rc = VbglGRPerform (&req->header);
2899 if (RT_FAILURE(rc))
2900 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
2901 }
2902 if (req != NULL)
2903 VbglGRFree (&req->header);
2904 return RT_SUCCESS(rc);
2905}
2906
2907
2908BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
2909 USHORT width, USHORT height, USHORT bpp
2910#ifdef VBOXWDDM
2911 , ULONG offDisplay
2912#endif
2913 )
2914{
2915 /* set the mode characteristics */
2916 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2917 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, width);
2918 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2919 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, height);
2920 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2921 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, bpp);
2922 /* enable the mode */
2923 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2924 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2925#ifdef VBOXWDDM
2926 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
2927 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
2928 ULONG xOffset = offDisplay % cbLine;
2929 ULONG yOffset = offDisplay / cbLine;
2930 Assert(xOffset <= 0xffff);
2931 Assert(yOffset <= 0xffff);
2932 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
2933 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
2934 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
2935 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
2936#endif
2937 /** @todo read from the port to see if the mode switch was successful */
2938
2939 /* Tell the host that we now support graphics in the additions.
2940 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2941 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2942 * (for example Qt GUI debug build asserts when seamless is being enabled).
2943 */
2944 // VBoxVideoSetGraphicsCap(TRUE);
2945
2946 return TRUE;
2947}
2948
2949#ifndef VBOXWDDM
2950
2951/**
2952 * VBoxVideoSetCurrentMode
2953 *
2954 * Sets the adapter to the specified operating mode.
2955 */
2956BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2957 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2958{
2959 PVIDEO_MODE_INFORMATION ModeInfo;
2960
2961 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2962
2963 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2964 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2965 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2966 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2967
2968 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2969 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2970 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2971
2972 if (DeviceExtension->iDevice > 0)
2973 {
2974 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
2975 DeviceExtension->iDevice));
2976 return TRUE;
2977 }
2978
2979 return VBoxVideoSetCurrentModePerform(DeviceExtension,
2980 (USHORT)ModeInfo->VisScreenWidth,
2981 (USHORT)ModeInfo->VisScreenHeight,
2982 (USHORT)ModeInfo->BitsPerPlane);
2983}
2984
2985/*
2986 * VBoxVideoResetDevice
2987 *
2988 * Resets the video hardware to the default mode, to which it was initialized
2989 * at system boot.
2990 */
2991
2992BOOLEAN FASTCALL VBoxVideoResetDevice(
2993 PDEVICE_EXTENSION DeviceExtension,
2994 PSTATUS_BLOCK StatusBlock)
2995{
2996 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2997
2998 if (DeviceExtension->iDevice > 0)
2999 {
3000 /* If the device is the secondary display, however, it is recommended that no action be taken. */
3001 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
3002 DeviceExtension->iDevice));
3003 return TRUE;
3004 }
3005
3006#if 0
3007 /* Don't disable the extended video mode. This would only switch the video mode
3008 * to <current width> x <current height> x 0 bpp which is not what we want. And
3009 * even worse, it causes an disturbing additional mode switch */
3010 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
3011 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
3012#endif
3013
3014 /* Tell the host that we no longer support graphics in the additions
3015 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
3016 */
3017 // VBoxVideoSetGraphicsCap(FALSE);
3018 return TRUE;
3019}
3020
3021/**
3022 * VBoxVideoMapVideoMemory
3023 *
3024 * Maps the video hardware frame buffer and video RAM into the virtual address
3025 * space of the requestor.
3026 */
3027BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
3028 PVIDEO_MEMORY RequestedAddress,
3029 PVIDEO_MEMORY_INFORMATION MapInformation,
3030 PSTATUS_BLOCK StatusBlock)
3031{
3032 PHYSICAL_ADDRESS FrameBuffer;
3033 ULONG inIoSpace = 0;
3034 VP_STATUS Status;
3035
3036 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
3037
3038 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
3039
3040 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
3041#ifndef VBOX_WITH_HGSMI
3042 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize
3043 + DeviceExtension->pPrimary->u.primary.ulDisplayInformationSize;
3044#else
3045 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
3046#endif /* VBOX_WITH_HGSMI */
3047
3048 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
3049 &MapInformation->VideoRamLength, &inIoSpace,
3050 &MapInformation->VideoRamBase);
3051
3052 if (Status == NO_ERROR)
3053 {
3054 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
3055 MapInformation->FrameBufferLength =
3056 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
3057 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
3058 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
3059
3060 /* Save the new framebuffer size */
3061 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
3062#ifdef VBOX_WITH_HGSMI
3063 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
3064 MapInformation->FrameBufferBase,
3065 MapInformation->FrameBufferLength,
3066 DeviceExtension->ulFrameBufferOffset);
3067#endif /* VBOX_WITH_HGSMI */
3068 return TRUE;
3069 }
3070
3071 return FALSE;
3072}
3073
3074/**
3075 * VBoxVideoUnmapVideoMemory
3076 *
3077 * Releases a mapping between the virtual address space and the adapter's
3078 * frame buffer and video RAM.
3079 */
3080BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
3081 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
3082{
3083 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
3084#ifdef VBOX_WITH_HGSMI
3085 HGSMIAreaClear (&DeviceExtension->areaDisplay);
3086#endif /* VBOX_WITH_HGSMI */
3087 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
3088 return TRUE;
3089}
3090
3091/**
3092 * VBoxVideoQueryNumAvailModes
3093 *
3094 * Returns the number of video modes supported by the adapter and the size
3095 * in bytes of the video mode information, which can be used to allocate a
3096 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
3097 */
3098BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
3099 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
3100{
3101 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
3102 /* calculate the video modes table */
3103 VBoxBuildModesTable(DeviceExtension);
3104 Modes->NumModes = gNumVideoModes;
3105 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
3106 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
3107 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
3108 return TRUE;
3109}
3110
3111/**
3112 * VBoxVideoQueryAvailModes
3113 *
3114 * Returns information about each video mode supported by the adapter.
3115 */
3116BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
3117 PVIDEO_MODE_INFORMATION ReturnedModes,
3118 PSTATUS_BLOCK StatusBlock)
3119{
3120 ULONG Size;
3121
3122 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
3123
3124 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
3125 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
3126 StatusBlock->Information = Size;
3127
3128 return TRUE;
3129}
3130
3131/**
3132 * VBoxVideoQueryCurrentMode
3133 *
3134 * Returns information about current video mode.
3135 */
3136BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
3137 PVIDEO_MODE_INFORMATION VideoModeInfo,
3138 PSTATUS_BLOCK StatusBlock)
3139{
3140 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
3141
3142 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
3143 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
3144
3145 return TRUE;
3146}
3147#endif /* ifndef VBOXWDDM */
3148/*
3149 * VBoxVideoSetColorRegisters
3150 *
3151 * Sets the adapter's color registers to the specified RGB values. There
3152 * are code paths in this function, one generic and one for VGA compatible
3153 * controllers. The latter is needed for Bochs, where the generic one isn't
3154 * yet implemented.
3155 */
3156
3157BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
3158 PDEVICE_EXTENSION DeviceExtension,
3159 PVIDEO_CLUT ColorLookUpTable,
3160 PSTATUS_BLOCK StatusBlock)
3161{
3162 LONG Entry;
3163
3164 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
3165
3166 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
3167 return FALSE;
3168
3169 for (Entry = ColorLookUpTable->FirstEntry;
3170 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
3171 Entry++)
3172 {
3173 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
3174 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
3175 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
3176 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
3177 }
3178
3179 return TRUE;
3180}
3181
3182#ifndef VBOXWDDM
3183
3184VP_STATUS VBoxVideoGetChildDescriptor(
3185 PVOID HwDeviceExtension,
3186 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
3187 PVIDEO_CHILD_TYPE VideoChildType,
3188 PUCHAR pChildDescriptor,
3189 PULONG pUId,
3190 PULONG pUnused)
3191{
3192 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
3193 HwDeviceExtension, ChildEnumInfo));
3194
3195 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
3196
3197 if (ChildEnumInfo->ChildIndex > 0)
3198 {
3199 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
3200 {
3201 *VideoChildType = Monitor;
3202 *pUId = ChildEnumInfo->ChildIndex;
3203
3204 return VIDEO_ENUM_MORE_DEVICES;
3205 }
3206 }
3207
3208 return ERROR_NO_MORE_DEVICES;
3209}
3210
3211
3212static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
3213{
3214 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
3215 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
3216
3217 if (pPrimaryDevExt)
3218 {
3219 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
3220
3221 if (req)
3222 {
3223 int rc = VbglGRPerform (&req->header);
3224
3225 if (RT_FAILURE(rc))
3226 {
3227 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
3228 }
3229 }
3230 }
3231
3232 return;
3233}
3234
3235int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
3236{
3237 int rc = VINF_SUCCESS;
3238
3239 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
3240
3241 /*
3242 * Query the VMMDev memory pointer. There we need VBVAMemory.
3243 */
3244 VMMDevMemory *pVMMDevMemory = NULL;
3245
3246 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
3247
3248 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
3249
3250 if (pDevExt->iDevice > 0)
3251 {
3252 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
3253
3254 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
3255 pDevExt->iDevice));
3256
3257 if ( ulEnable
3258 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
3259 {
3260 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
3261 pVbvaResult->pfnFlush = vboxVbvaFlush;
3262 pVbvaResult->pvFlush = pDevExt;
3263 }
3264 else
3265 {
3266 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
3267 }
3268
3269 return rc;
3270 }
3271
3272 if (RT_SUCCESS(rc))
3273 {
3274 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
3275 if (pDevExt->u.primary.pvReqFlush == NULL)
3276 {
3277 VMMDevVideoAccelFlush *req = NULL;
3278
3279 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3280 sizeof (VMMDevVideoAccelFlush),
3281 VMMDevReq_VideoAccelFlush);
3282
3283 if (RT_SUCCESS (rc))
3284 {
3285 pDevExt->u.primary.pvReqFlush = req;
3286 }
3287 else
3288 {
3289 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
3290 }
3291 }
3292 }
3293 else
3294 {
3295 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
3296 }
3297
3298 if (RT_SUCCESS(rc))
3299 {
3300 ULONG ulEnabled = 0;
3301
3302 /*
3303 * Tell host that VBVA status is changed.
3304 */
3305 VMMDevVideoAccelEnable *req = NULL;
3306
3307 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
3308 sizeof (VMMDevVideoAccelEnable),
3309 VMMDevReq_VideoAccelEnable);
3310
3311 if (RT_SUCCESS(rc))
3312 {
3313 req->u32Enable = ulEnable;
3314 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3315 req->fu32Status = 0;
3316
3317 rc = VbglGRPerform (&req->header);
3318
3319 if (RT_SUCCESS(rc))
3320 {
3321 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
3322 {
3323 /*
3324 * Initialize the result information and VBVA memory.
3325 */
3326 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
3327 {
3328 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
3329 pVbvaResult->pfnFlush = vboxVbvaFlush;
3330 pVbvaResult->pvFlush = pDevExt;
3331 ulEnabled = 1;
3332 }
3333 else
3334 {
3335 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
3336 }
3337
3338 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
3339 }
3340 else
3341 {
3342 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
3343
3344 /* Disable VBVA for old hosts. */
3345 req->u32Enable = 0;
3346 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3347 req->fu32Status = 0;
3348
3349 VbglGRPerform (&req->header);
3350
3351 rc = VERR_NOT_SUPPORTED;
3352 }
3353 }
3354 else
3355 {
3356 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
3357 }
3358
3359 VbglGRFree (&req->header);
3360 }
3361 else
3362 {
3363 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
3364 }
3365
3366 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
3367 }
3368
3369 return rc;
3370}
3371#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