VirtualBox

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

Last change on this file since 30926 was 30169, checked in by vboxsync, 15 years ago

wddm: scanline info support basics, some tooling for complex vidpn topology handling

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