VirtualBox

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

Last change on this file since 31884 was 31873, checked in by vboxsync, 15 years ago

VBoxVideo: When unmapping adapter memory, make sure interrupt handler will not blow up.

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

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