VirtualBox

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

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

Additions/WINNT/Graphics: more refactorings

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