VirtualBox

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

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

wddm: compile fix

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