VirtualBox

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

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

wddm/3d: auto-resize & fullscreen working for Aero

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

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