VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 117.7 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#ifdef 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 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
1344 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
1345 - VBVA_ADAPTER_INFORMATION_SIZE;
1346
1347 /* Size of a framebuffer. */
1348
1349 ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
1350
1351 /* Align down to 4096 bytes. */
1352 ulSize &= ~0xFFF;
1353
1354 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
1355 commonFromDeviceExt(PrimaryExtension)->cbVRAM, PrimaryExtension->u.primary.cDisplays,
1356 ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
1357 ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
1358
1359
1360 /* Update the primary info. */
1361 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
1362
1363 /* Update the per extension info. */
1364 PDEVICE_EXTENSION Extension = PrimaryExtension;
1365 ULONG ulFrameBufferOffset = 0;
1366 while (Extension)
1367 {
1368 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
1369 /* That is assigned when a video mode is set. */
1370 Extension->ulFrameBufferSize = 0;
1371
1372 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
1373 Extension->iDevice, ulFrameBufferOffset));
1374
1375 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1376
1377 Extension = Extension->pNext;
1378 }
1379}
1380
1381#endif
1382
1383int VBoxMapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulOffset, ULONG ulSize)
1384{
1385 dprintf(("VBoxVideo::VBoxMapAdapterMemory 0x%08X[0x%X]\n", ulOffset, ulSize));
1386
1387 if (!ulSize)
1388 {
1389 dprintf(("Illegal length 0!\n"));
1390 return ERROR_INVALID_PARAMETER;
1391 }
1392
1393 PHYSICAL_ADDRESS FrameBuffer;
1394 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + ulOffset;
1395
1396 PVOID VideoRamBase = NULL;
1397 ULONG VideoRamLength = ulSize;
1398 VP_STATUS Status;
1399#ifndef VBOX_WITH_WDDM
1400 ULONG inIoSpace = 0;
1401
1402 Status = VideoPortMapMemory (PrimaryExtension, FrameBuffer,
1403 &VideoRamLength, &inIoSpace,
1404 &VideoRamBase);
1405#else
1406 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbMapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1407 FrameBuffer,
1408 VideoRamLength,
1409 FALSE, /* IN BOOLEAN InIoSpace */
1410 FALSE, /* IN BOOLEAN MapToUserMode */
1411 MmNonCached, /* IN MEMORY_CACHING_TYPE CacheType */
1412 &VideoRamBase /*OUT PVOID *VirtualAddress*/
1413 );
1414 Assert(ntStatus == STATUS_SUCCESS);
1415 Status = ntStatus == STATUS_SUCCESS ? NO_ERROR : ERROR_INVALID_PARAMETER; /*<- this is what VideoPortMapMemory returns according to the docs */
1416#endif
1417
1418 if (Status == NO_ERROR)
1419 {
1420 *ppv = VideoRamBase;
1421 }
1422
1423 dprintf(("VBoxVideo::VBoxMapAdapterMemory rc = %d\n", Status));
1424
1425 return Status;
1426}
1427
1428BOOLEAN VBoxUnmapAdpInfoCallback(PVOID ext)
1429{
1430 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)ext;
1431 Assert(PrimaryExtension);
1432
1433 commonFromDeviceExt(PrimaryExtension)->pHostFlags = NULL;
1434 return TRUE;
1435}
1436
1437void VBoxUnmapAdapterInformation(PDEVICE_EXTENSION PrimaryExtension)
1438{
1439 void *ppv;
1440
1441 dprintf(("VBoxVideo::VBoxUnmapAdapterInformation\n"));
1442
1443 ppv = commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation;
1444 if (ppv)
1445 {
1446#ifndef VBOX_WITH_WDDM
1447 /* The pHostFlags field is mapped through pvAdapterInformation. It must be cleared first,
1448 * and it must be done in a way which avoids races with the interrupt handler.
1449 */
1450 VideoPortSynchronizeExecution(PrimaryExtension, VpMediumPriority,
1451 VBoxUnmapAdpInfoCallback, PrimaryExtension);
1452 VideoPortUnmapMemory(PrimaryExtension, ppv, NULL);
1453#else
1454 BOOLEAN bRet;
1455 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbSynchronizeExecution(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1456 VBoxUnmapAdpInfoCallback, PrimaryExtension,
1457 0, &bRet);
1458 Assert(ntStatus == STATUS_SUCCESS);
1459 ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1460 ppv);
1461 Assert(ntStatus == STATUS_SUCCESS);
1462#endif
1463 commonFromDeviceExt(PrimaryExtension)->pvAdapterInformation = NULL;
1464 }
1465}
1466
1467void VBoxUnmapAdapterMemory (PDEVICE_EXTENSION PrimaryExtension, void **ppv, ULONG ulSize)
1468{
1469 dprintf(("VBoxVideo::VBoxUnmapAdapterMemory\n"));
1470
1471 if (*ppv)
1472 {
1473#ifndef VBOX_WITH_WDDM
1474 VideoPortUnmapMemory(PrimaryExtension, *ppv, NULL);
1475#else
1476 NTSTATUS ntStatus = PrimaryExtension->u.primary.DxgkInterface.DxgkCbUnmapMemory(PrimaryExtension->u.primary.DxgkInterface.DeviceHandle,
1477 *ppv);
1478 Assert(ntStatus == STATUS_SUCCESS);
1479#endif
1480 }
1481
1482 *ppv = NULL;
1483}
1484
1485
1486void vboxVideoInitCustomVideoModes(PDEVICE_EXTENSION pDevExt)
1487{
1488 VP_STATUS status;
1489 VBOXCMNREG Reg;
1490
1491 VBoxVideoCmnRegInit(pDevExt, &Reg);
1492
1493 dprintf(("VBoxVideo::vboxVideoInitCustomVideoModes\n"));
1494
1495#ifndef VBOX_WITH_MULTIMONITOR_FIX
1496 /*
1497 * Get the last custom resolution
1498 */
1499 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &gCustomXRes);
1500 if (status != NO_ERROR)
1501 gCustomXRes = 0;
1502
1503 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &gCustomYRes);
1504 if (status != NO_ERROR)
1505 gCustomYRes = 0;
1506 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &gCustomBPP);
1507 if (status != NO_ERROR)
1508 gCustomBPP = 0;
1509
1510 dprintf(("VBoxVideo: got stored custom resolution %dx%dx%d\n", gCustomXRes, gCustomYRes, gCustomBPP));
1511#else
1512 /* Initialize all custom modes to the 800x600x32. */
1513 initVideoModeInformation(&CustomVideoModes[0], 800, 600, 32, 0, 0);
1514
1515 int iCustomMode;
1516 for (iCustomMode = 1; iCustomMode < RT_ELEMENTS(CustomVideoModes); iCustomMode++)
1517 {
1518 CustomVideoModes[iCustomMode] = CustomVideoModes[0];
1519 }
1520
1521 /* Load stored custom resolution from the registry. */
1522 for (iCustomMode = 0;
1523#ifdef VBOX_WITH_WDDM
1524 iCustomMode < pDevExt->u.primary.cDisplays;
1525#else
1526 iCustomMode < pDevExt->pPrimary->u.primary.cDisplays;
1527#endif
1528 iCustomMode++)
1529 {
1530 /*
1531 * Get the last custom resolution
1532 */
1533 uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
1534
1535 if (iCustomMode == 0)
1536 {
1537 /* Name without a suffix */
1538 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomXRes", &CustomXRes);
1539 if (status != NO_ERROR)
1540 CustomXRes = 0;
1541 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomYRes", &CustomYRes);
1542 if (status != NO_ERROR)
1543 CustomYRes = 0;
1544 status = VBoxVideoCmnRegQueryDword(Reg, L"CustomBPP", &CustomBPP);
1545 if (status != NO_ERROR)
1546 CustomBPP = 0;
1547 }
1548 else
1549 {
1550 wchar_t keyname[32];
1551 swprintf(keyname, L"CustomXRes%d", iCustomMode);
1552 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomXRes);
1553 if (status != NO_ERROR)
1554 CustomXRes = 0;
1555 swprintf(keyname, L"CustomYRes%d", iCustomMode);
1556 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomYRes);
1557 if (status != NO_ERROR)
1558 CustomYRes = 0;
1559 swprintf(keyname, L"CustomBPP%d", iCustomMode);
1560 status = VBoxVideoCmnRegQueryDword(Reg, keyname, &CustomBPP);
1561 if (status != NO_ERROR)
1562 CustomBPP = 0;
1563 }
1564
1565 dprintf(("VBoxVideo: got stored custom resolution[%d] %dx%dx%d\n", iCustomMode, CustomXRes, CustomYRes, CustomBPP));
1566
1567 if (CustomXRes || CustomYRes || CustomBPP)
1568 {
1569 if (CustomXRes == 0)
1570 {
1571 CustomXRes = CustomVideoModes[iCustomMode].VisScreenWidth;
1572 }
1573 if (CustomYRes == 0)
1574 {
1575 CustomYRes = CustomVideoModes[iCustomMode].VisScreenHeight;
1576 }
1577 if (CustomBPP == 0)
1578 {
1579 CustomBPP = CustomVideoModes[iCustomMode].BitsPerPlane;
1580 }
1581
1582 initVideoModeInformation(&CustomVideoModes[iCustomMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
1583 }
1584 }
1585#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1586
1587 VBoxVideoCmnRegFini(Reg);
1588}
1589
1590#ifndef VBOX_WITH_WDDM
1591
1592VP_STATUS VBoxVideoFindAdapter(IN PVOID HwDeviceExtension,
1593 IN PVOID HwContext, IN PWSTR ArgumentString,
1594 IN OUT PVIDEO_PORT_CONFIG_INFO ConfigInfo,
1595 OUT PUCHAR Again)
1596{
1597 VP_STATUS rc;
1598 USHORT DispiId;
1599 ULONG AdapterMemorySize = VBE_DISPI_TOTAL_VIDEO_MEMORY_BYTES;
1600
1601 dprintf(("VBoxVideo::VBoxVideoFindAdapter %p\n", HwDeviceExtension));
1602
1603 VBoxSetupVideoPortFunctions((PDEVICE_EXTENSION)HwDeviceExtension, &((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.VideoPortProcs, ConfigInfo);
1604
1605 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
1606 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID2);
1607 DispiId = VideoPortReadPortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA);
1608 if (DispiId == VBE_DISPI_ID2)
1609 {
1610 dprintf(("VBoxVideo::VBoxVideoFoundAdapter: found the VBE card\n"));
1611 /*
1612 * Write some hardware information to registry, so that
1613 * it's visible in Windows property dialog.
1614 */
1615
1616 rc = VideoPortSetRegistryParameters(
1617 HwDeviceExtension,
1618 L"HardwareInformation.ChipType",
1619 VBoxChipType,
1620 sizeof(VBoxChipType));
1621
1622 rc = VideoPortSetRegistryParameters(
1623 HwDeviceExtension,
1624 L"HardwareInformation.DacType",
1625 VBoxDACType,
1626 sizeof(VBoxDACType));
1627
1628 /*
1629 * Query the adapter's memory size. It's a bit of a hack, we just read
1630 * an ULONG from the data port without setting an index before.
1631 */
1632 AdapterMemorySize = VideoPortReadPortUlong((PULONG)VBE_DISPI_IOPORT_DATA);
1633 rc = VideoPortSetRegistryParameters(
1634 HwDeviceExtension,
1635 L"HardwareInformation.MemorySize",
1636 &AdapterMemorySize,
1637 sizeof(ULONG));
1638
1639 rc = VideoPortSetRegistryParameters(
1640 HwDeviceExtension,
1641 L"HardwareInformation.AdapterString",
1642 VBoxAdapterString,
1643 sizeof(VBoxAdapterString));
1644
1645 rc = VideoPortSetRegistryParameters(
1646 HwDeviceExtension,
1647 L"HardwareInformation.BiosString",
1648 VBoxBiosString,
1649 sizeof(VBoxBiosString));
1650
1651 dprintf(("VBoxVideo::VBoxVideoFindAdapter: calling VideoPortGetAccessRanges\n"));
1652
1653 /* pPrimary is not yet set */
1654 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.commonInfo.IOPortHost = (RTIOPORT)VGA_PORT_HGSMI_HOST;
1655 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.commonInfo.IOPortGuest = (RTIOPORT)VGA_PORT_HGSMI_GUEST;
1656
1657 VIDEO_ACCESS_RANGE tmpRanges[4];
1658 ULONG slot = 0;
1659
1660 VideoPortZeroMemory(tmpRanges, sizeof(tmpRanges));
1661
1662 /* need to call VideoPortGetAccessRanges to ensure interrupt info in ConfigInfo gets set up */
1663 VP_STATUS status;
1664 if (vboxQueryWinVersion() == WINNT4)
1665 {
1666 /* NT crashes if either of 'vendorId, 'deviceId' or 'slot' parameters is NULL,
1667 * and needs PCI ids for a successful VideoPortGetAccessRanges call.
1668 */
1669 ULONG vendorId = 0x80EE;
1670 ULONG deviceId = 0xBEEF;
1671 status = VideoPortGetAccessRanges(HwDeviceExtension,
1672 0,
1673 NULL,
1674 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1675 tmpRanges,
1676 &vendorId,
1677 &deviceId,
1678 &slot);
1679 }
1680 else
1681 {
1682 status = VideoPortGetAccessRanges(HwDeviceExtension,
1683 0,
1684 NULL,
1685 sizeof (tmpRanges)/sizeof (tmpRanges[0]),
1686 tmpRanges,
1687 NULL,
1688 NULL,
1689 &slot);
1690 }
1691 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VideoPortGetAccessRanges status 0x%x\n", status));
1692
1693 /* Initialize VBoxGuest library, which is used for requests which go through VMMDev. */
1694 rc = VbglInit ();
1695 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VbglInit returned 0x%x\n", rc));
1696
1697 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1698 * code will be ifdef'ed and later removed.
1699 * The host will however support both old and new interface to keep compatibility
1700 * with old guest additions.
1701 */
1702 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize, 0);
1703
1704 if (commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension)->bHGSMI)
1705 {
1706 LogRel(("VBoxVideo: using HGSMI\n"));
1707 }
1708
1709 // pretend success to make the driver work.
1710 rc = NO_ERROR;
1711 } else
1712 {
1713 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1714 rc = ERROR_DEV_NOT_EXIST;
1715 }
1716 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1717 return rc;
1718}
1719
1720/**
1721 * VBoxVideoInitialize
1722 *
1723 * Performs the first initialization of the adapter, after the HAL has given
1724 * up control of the video hardware to the video port driver.
1725 */
1726BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1727{
1728 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1729
1730 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1731
1732 /* Initialize the request pointer. */
1733 pDevExt->u.primary.pvReqFlush = NULL;
1734
1735 vboxVideoInitCustomVideoModes(pDevExt);
1736
1737 return TRUE;
1738}
1739
1740# ifdef VBOX_WITH_VIDEOHWACCEL
1741
1742BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
1743{
1744 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1745 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
1746 if (PrimaryExtension)
1747 {
1748 if (commonFromDeviceExt(PrimaryExtension)->pHostFlags) /* If HGSMI is enabled at all. */
1749 {
1750 uint32_t flags = commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags;
1751 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
1752 {
1753 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
1754 {
1755 /* schedule a DPC*/
1756 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
1757 Assert(bResult);
1758 }
1759 /* clear the IRQ */
1760 HGSMIClearIrq (commonFromDeviceExt(PrimaryExtension));
1761 return TRUE;
1762 }
1763 }
1764 }
1765 return FALSE;
1766}
1767# endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1768#endif /* #ifndef VBOX_WITH_WDDM */
1769/**
1770 * Send a request to the host to make the absolute pointer visible
1771 */
1772static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
1773{
1774 BOOLEAN Result = TRUE;
1775
1776 /* Use primary device extension, because the show pointer request should be processed
1777 * in vboxUpdatePointerShape regardless of the device. */
1778#ifndef VBOX_WITH_WDDM
1779 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
1780#else
1781 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
1782#endif
1783
1784 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
1785 {
1786 // tell the host to use the guest's pointer
1787 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1788
1789 /* Visible and No Shape means Show the pointer.
1790 * It is enough to init only this field.
1791 */
1792 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1793
1794 Result = vboxUpdatePointerShape(PrimaryExtension, &PointerAttributes, sizeof (PointerAttributes));
1795
1796 if (Result)
1797 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
1798 else
1799 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
1800 }
1801 return Result;
1802}
1803
1804#ifndef VBOX_WITH_WDDM
1805/**
1806 * VBoxVideoStartIO
1807 *
1808 * Processes the specified Video Request Packet.
1809 */
1810BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1811 PVIDEO_REQUEST_PACKET RequestPacket)
1812{
1813 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1814
1815 BOOLEAN Result;
1816
1817// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1818
1819 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1820
1821 switch (RequestPacket->IoControlCode)
1822 {
1823 case IOCTL_VIDEO_SET_CURRENT_MODE:
1824 {
1825 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1826 {
1827 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1828 return TRUE;
1829 }
1830 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1831 (PVIDEO_MODE)RequestPacket->InputBuffer,
1832 RequestPacket->StatusBlock);
1833 break;
1834 }
1835
1836 case IOCTL_VIDEO_RESET_DEVICE:
1837 {
1838 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1839 RequestPacket->StatusBlock);
1840 break;
1841 }
1842
1843 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1844 {
1845 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1846 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1847 {
1848 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1849 return TRUE;
1850 }
1851 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1852 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1853 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1854 RequestPacket->StatusBlock);
1855 break;
1856 }
1857
1858 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1859 {
1860 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1861 {
1862 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1863 return TRUE;
1864 }
1865 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1866 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1867 RequestPacket->StatusBlock);
1868 break;
1869 }
1870
1871 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1872 {
1873 PVIDEO_SHARE_MEMORY pShareMemory;
1874 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1875 PHYSICAL_ADDRESS shareAddress;
1876 PVOID virtualAddress = NULL;
1877 ULONG sharedViewSize;
1878 ULONG inIoSpace = 0;
1879 VP_STATUS status;
1880
1881 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1882
1883 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1884 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1885
1886 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1887 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1888 Result = FALSE;
1889 break;
1890 }
1891
1892 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1893
1894 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1895 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1896
1897 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));
1898 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1899 Result = FALSE;
1900 break;
1901 }
1902
1903 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1904
1905 virtualAddress = pShareMemory->ProcessHandle;
1906 sharedViewSize = pShareMemory->ViewSize;
1907
1908 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1909
1910 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1911 if (status != NO_ERROR)
1912 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1913 Result = (status == NO_ERROR);
1914
1915 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1916 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1917 pShareMemoryInformation->VirtualAddress = virtualAddress;
1918 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1919 break;
1920 }
1921
1922 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1923 {
1924 PVIDEO_SHARE_MEMORY pShareMemory;
1925 VP_STATUS status;
1926
1927 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1928
1929 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1930 {
1931 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1932 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1933 Result = FALSE;
1934 break;
1935 }
1936
1937 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1938
1939 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1940 if (status != NO_ERROR)
1941 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1942 Result = (status == NO_ERROR);
1943 break;
1944 }
1945
1946 /*
1947 * The display driver asks us how many video modes we support
1948 * so that it can supply an appropriate buffer for the next call.
1949 */
1950 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1951 {
1952 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1953 {
1954 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1955 return TRUE;
1956 }
1957 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1958 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1959 RequestPacket->StatusBlock);
1960 break;
1961 }
1962
1963 /*
1964 * The display driver asks us to provide a list of supported video modes
1965 * into a buffer it has allocated.
1966 */
1967 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1968 {
1969 if (RequestPacket->OutputBufferLength <
1970 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1971 {
1972 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1973 return TRUE;
1974 }
1975 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1976 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1977 RequestPacket->StatusBlock);
1978 break;
1979 }
1980
1981 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1982 {
1983 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1984 RequestPacket->InputBufferLength <
1985 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1986 sizeof(VIDEO_CLUT))
1987 {
1988 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1989 return TRUE;
1990 }
1991 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1992 (PVIDEO_CLUT)RequestPacket->InputBuffer,
1993 RequestPacket->StatusBlock);
1994 break;
1995 }
1996
1997 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
1998 {
1999 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
2000 {
2001 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2002 return TRUE;
2003 }
2004 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2005 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2006 RequestPacket->StatusBlock);
2007 break;
2008 }
2009
2010 // show the pointer
2011 case IOCTL_VIDEO_ENABLE_POINTER:
2012 {
2013 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
2014 // find out whether the host wants absolute positioning
2015 /// @todo this is now obsolete - remove it?
2016 if (vboxQueryHostWantsAbsolute())
2017 Result = ShowPointer(HwDeviceExtension);
2018 else
2019 {
2020 // fallback to software pointer
2021 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2022 Result = FALSE;
2023 }
2024 break;
2025 }
2026
2027 // hide the pointer
2028 case IOCTL_VIDEO_DISABLE_POINTER:
2029 {
2030 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
2031 // find out whether the host wants absolute positioning
2032 if (vboxQueryHostWantsAbsolute())
2033 {
2034 // tell the host to hide pointer
2035 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2036
2037 /* Enable == 0 means no shape, not visible.
2038 * It is enough to init only this field.
2039 */
2040 PointerAttributes.Enable = 0;
2041
2042 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
2043
2044 if (Result)
2045 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
2046 else
2047 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
2048 } else
2049 {
2050 // fallback to software pointer
2051 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2052 Result = FALSE;
2053 }
2054 break;
2055 }
2056
2057 /*
2058 * Change the pointer shape
2059 */
2060 case IOCTL_VIDEO_SET_POINTER_ATTR:
2061 {
2062 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
2063 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
2064 {
2065 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
2066 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2067 return TRUE;
2068 }
2069 // find out whether the host wants absolute positioning
2070 if (vboxQueryHostWantsAbsolute())
2071 {
2072 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
2073#if 0
2074 dprintf(("Pointer shape information:\n"
2075 "\tFlags: %d\n"
2076 "\tWidth: %d\n"
2077 "\tHeight: %d\n"
2078 "\tWidthInBytes: %d\n"
2079 "\tEnable: %d\n"
2080 "\tColumn: %d\n"
2081 "\tRow: %d\n",
2082 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
2083 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
2084 pPointerAttributes->Row));
2085 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
2086#endif
2087 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
2088 if (!Result)
2089 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
2090 } else
2091 {
2092 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
2093 // fallback to software pointer
2094 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2095 Result = FALSE;
2096 }
2097 break;
2098 }
2099
2100 // query pointer information
2101 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
2102 {
2103 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
2104 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2105 Result = FALSE;
2106 break;
2107 }
2108
2109 // set the pointer position
2110 case IOCTL_VIDEO_SET_POINTER_POSITION:
2111 {
2112 // find out whether the host wants absolute positioning
2113 /// @todo this is now obsolete - remove it?
2114 if (vboxQueryHostWantsAbsolute())
2115 Result = ShowPointer(HwDeviceExtension);
2116 else
2117 {
2118 // fallback to software pointer
2119 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2120 Result = FALSE;
2121 }
2122 break;
2123 }
2124
2125 // query the pointer position
2126 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
2127 {
2128 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
2129 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
2130 {
2131 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2132 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2133 return TRUE;
2134 }
2135 Result = FALSE;
2136 uint16_t mousePosX;
2137 uint16_t mousePosY;
2138 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
2139 {
2140 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
2141 PVIDEO_MODE_INFORMATION ModeInfo;
2142 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
2143 // map from 0xFFFF to the current resolution
2144 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
2145 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
2146 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
2147 Result = TRUE;
2148 }
2149 if (!Result)
2150 {
2151 // fallback to software pointer
2152 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2153 }
2154 break;
2155 }
2156
2157 // Determine hardware cursor capabilities. We will always report that we are
2158 // very capable even though the host might not want to do pointer integration.
2159 // This is done because we can still return errors on the actual calls later to
2160 // make the display driver go to the fallback routines.
2161 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
2162 {
2163 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
2164 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
2165 {
2166 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2167 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2168 return TRUE;
2169 }
2170 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
2171 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
2172 VIDEO_MODE_COLOR_POINTER |
2173 VIDEO_MODE_MONO_POINTER;
2174 // for now we go with 64x64 cursors
2175 pCaps->MaxWidth = 64;
2176 pCaps->MaxHeight = 64;
2177 // that doesn't seem to be relevant, VBoxDisp doesn't use it
2178 pCaps->HWPtrBitmapStart = -1;
2179 pCaps->HWPtrBitmapEnd = -1;
2180 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
2181 Result = TRUE;
2182 break;
2183 }
2184
2185 /* Attach/detach DualView devices */
2186 case IOCTL_VIDEO_SWITCH_DUALVIEW:
2187 {
2188 ULONG ulAttach;
2189
2190 ulAttach = *((PULONG)RequestPacket->InputBuffer);
2191 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
2192
2193 if (pDevExt->iDevice > 0)
2194 {
2195 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
2196 }
2197 Result = TRUE;
2198 break;
2199 }
2200
2201 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
2202 {
2203 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
2204
2205 if (pDevExt->pPrimary->u.primary.bVBoxVideoSupported)
2206 {
2207 /* The display driver must have prepared the monitor information. */
2208 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VBOX_VIDEO);
2209 VideoPortWritePortUlong((PULONG)VBE_DISPI_IOPORT_DATA, VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE + pDevExt->iDevice);
2210 }
2211 else
2212 {
2213 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2214 }
2215 Result = pDevExt->pPrimary->u.primary.bVBoxVideoSupported;
2216 break;
2217 }
2218
2219
2220 case IOCTL_VIDEO_VBVA_ENABLE:
2221 {
2222 int rc;
2223 ULONG ulEnable;
2224
2225 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2226
2227 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2228 {
2229 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2230 RequestPacket->InputBufferLength, sizeof(ULONG)));
2231 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2232 return FALSE;
2233 }
2234
2235 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2236 {
2237 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2238 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2239 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2240 return FALSE;
2241 }
2242
2243 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2244 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2245
2246 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2247 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2248
2249 if (RT_FAILURE (rc))
2250 {
2251 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2252 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2253 return FALSE;
2254 }
2255
2256 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2257 Result = TRUE;
2258
2259 break;
2260 }
2261
2262 /* Private ioctls */
2263 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2264 {
2265 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2266 int rc;
2267
2268 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2269 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2270 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2271 {
2272 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2273 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2274 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2275 return FALSE;
2276 }
2277 /*
2278 * Inform the host about the visible region
2279 */
2280 VMMDevVideoSetVisibleRegion *req = NULL;
2281
2282 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2283 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2284 VMMDevReq_VideoSetVisibleRegion);
2285
2286 if (RT_SUCCESS(rc))
2287 {
2288 req->cRect = cRect;
2289 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2290
2291 rc = VbglGRPerform (&req->header);
2292
2293 if (RT_SUCCESS(rc))
2294 {
2295 Result = TRUE;
2296 break;
2297 }
2298 }
2299
2300 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
2301 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2302 return FALSE;
2303 }
2304
2305 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2306 {
2307 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2308
2309 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2310 {
2311 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2312 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2313 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2314 return FALSE;
2315 }
2316
2317 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2318 {
2319 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2320 return FALSE;
2321 }
2322
2323 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2324
2325 pInfo->iDevice = pDevExt->iDevice;
2326 pInfo->ulFlags = 0;
2327
2328 /* Describes VRAM chunk for this display device. */
2329 pInfo->areaDisplay = pDevExt->areaDisplay;
2330
2331 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2332 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2333
2334 pInfo->IOPortGuestCommand = commonFromDeviceExt(pDevExt)->IOPortGuest;
2335
2336 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2337 Result = TRUE;
2338
2339 break;
2340 }
2341 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2342 {
2343 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2344
2345 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2346 {
2347 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2348 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2349 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2350 return FALSE;
2351 }
2352
2353 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2354 {
2355 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2356 return FALSE;
2357 }
2358
2359 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2360
2361 pInfo->hContext = pDevExt;
2362 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2363 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2364
2365 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2366 Result = TRUE;
2367 break;
2368 }
2369 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2370 {
2371 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2372
2373 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2374 {
2375 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2376 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2377 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2378 return FALSE;
2379 }
2380
2381 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2382 {
2383 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2384 return FALSE;
2385 }
2386
2387 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2388 pInfo->pContext = pDevExt->pPrimary;
2389 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2390
2391 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2392 Result = TRUE;
2393 break;
2394 }
2395 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2396 {
2397 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2398
2399 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2400 {
2401 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2402 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2403 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2404 return FALSE;
2405 }
2406
2407 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2408 {
2409 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2410 return FALSE;
2411 }
2412
2413 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2414
2415 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2416 pDevExt->iDevice,
2417 pInfo->u8Channel);
2418 if(RT_FAILURE(rc))
2419 {
2420 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2421 }
2422 Result = TRUE;
2423 break;
2424 }
2425 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2426 {
2427 /* TODO: implement */
2428 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2429 {
2430 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2431 return FALSE;
2432 }
2433 break;
2434 }
2435# ifdef VBOX_WITH_VIDEOHWACCEL
2436 case IOCTL_VIDEO_VHWA_QUERY_INFO:
2437 {
2438 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
2439 {
2440 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2441 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
2442 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2443 return FALSE;
2444 }
2445
2446 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2447 {
2448 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2449 return FALSE;
2450 }
2451
2452 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
2453 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
2454 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
2455 Result = TRUE;
2456 break;
2457 }
2458# endif
2459 default:
2460 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2461 RequestPacket->IoControlCode,
2462 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2463 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2464 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2465 return FALSE;
2466 }
2467
2468 if (Result)
2469 RequestPacket->StatusBlock->Status = NO_ERROR;
2470 else
2471 RequestPacket->StatusBlock->Information = 0;
2472
2473// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2474
2475 return TRUE;
2476}
2477
2478/**
2479 * VBoxVideoReset HW
2480 *
2481 * Resets the video hardware.
2482 */
2483BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2484{
2485 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2486
2487 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2488
2489 if (pDevExt->iDevice > 0)
2490 {
2491 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2492 pDevExt->iDevice));
2493 return TRUE;
2494 }
2495
2496 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2497 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2498
2499 if (pDevExt->u.primary.pvReqFlush != NULL)
2500 {
2501 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2502 pDevExt->u.primary.pvReqFlush = NULL;
2503 }
2504
2505 VbglTerminate ();
2506
2507 VBoxUnmapAdapterMemory (pDevExt, &commonFromDeviceExt(pDevExt)->pvMiniportHeap, commonFromDeviceExt(pDevExt)->cbMiniportHeap);
2508 VBoxUnmapAdapterInformation (pDevExt);
2509
2510 return TRUE;
2511}
2512
2513/**
2514 * VBoxVideoGetPowerState
2515 *
2516 * Queries whether the device can support the requested power state.
2517 */
2518VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2519 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2520{
2521 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2522 return NO_ERROR;
2523}
2524
2525/**
2526 * VBoxVideoSetPowerState
2527 *
2528 * Sets the power state of the specified device
2529 */
2530VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2531 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2532{
2533 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2534 return NO_ERROR;
2535}
2536#endif /* #ifndef VBOX_WITH_WDDM */
2537
2538/**
2539 * VBoxVideoSetGraphicsCap
2540 *
2541 * Tells the host whether or not we currently support graphics in the
2542 * additions
2543 */
2544BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2545{
2546 VMMDevReqGuestCapabilities2 *req = NULL;
2547 int rc;
2548
2549 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2550 sizeof (VMMDevReqGuestCapabilities2),
2551 VMMDevReq_SetGuestCapabilities);
2552
2553 if (!RT_SUCCESS(rc))
2554 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2555 else
2556 {
2557 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2558 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2559
2560 rc = VbglGRPerform (&req->header);
2561 if (RT_FAILURE(rc))
2562 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
2563 }
2564 if (req != NULL)
2565 VbglGRFree (&req->header);
2566 return RT_SUCCESS(rc);
2567}
2568
2569
2570BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
2571 USHORT width, USHORT height, USHORT bpp
2572#ifdef VBOX_WITH_WDDM
2573 , ULONG offDisplay
2574#endif
2575 )
2576{
2577 /* set the mode characteristics */
2578 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2579 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, width);
2580 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2581 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, height);
2582 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2583 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, bpp);
2584 /* enable the mode */
2585 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2586 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2587#ifdef VBOX_WITH_WDDM
2588 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
2589 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
2590 ULONG xOffset = offDisplay % cbLine;
2591 if (bpp == 4)
2592 {
2593 xOffset <<= 1;
2594 }
2595 else
2596 {
2597 Assert(!(xOffset%((bpp + 7) >> 3)));
2598 xOffset /= ((bpp + 7) >> 3);
2599 }
2600 ULONG yOffset = offDisplay / cbLine;
2601 Assert(xOffset <= 0xffff);
2602 Assert(yOffset <= 0xffff);
2603 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
2604 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
2605 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
2606 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
2607#endif
2608 /** @todo read from the port to see if the mode switch was successful */
2609
2610 /* Tell the host that we now support graphics in the additions.
2611 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2612 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2613 * (for example Qt GUI debug build asserts when seamless is being enabled).
2614 */
2615 // VBoxVideoSetGraphicsCap(TRUE);
2616
2617 return TRUE;
2618}
2619
2620#ifndef VBOX_WITH_WDDM
2621
2622/**
2623 * VBoxVideoSetCurrentMode
2624 *
2625 * Sets the adapter to the specified operating mode.
2626 */
2627BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2628 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2629{
2630 PVIDEO_MODE_INFORMATION ModeInfo;
2631
2632 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2633
2634 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2635 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2636 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2637 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2638
2639 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2640 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2641 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2642
2643 if (DeviceExtension->iDevice > 0)
2644 {
2645 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
2646 DeviceExtension->iDevice));
2647 return TRUE;
2648 }
2649
2650 return VBoxVideoSetCurrentModePerform(DeviceExtension,
2651 (USHORT)ModeInfo->VisScreenWidth,
2652 (USHORT)ModeInfo->VisScreenHeight,
2653 (USHORT)ModeInfo->BitsPerPlane);
2654}
2655
2656/*
2657 * VBoxVideoResetDevice
2658 *
2659 * Resets the video hardware to the default mode, to which it was initialized
2660 * at system boot.
2661 */
2662
2663BOOLEAN FASTCALL VBoxVideoResetDevice(
2664 PDEVICE_EXTENSION DeviceExtension,
2665 PSTATUS_BLOCK StatusBlock)
2666{
2667 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2668
2669 if (DeviceExtension->iDevice > 0)
2670 {
2671 /* If the device is the secondary display, however, it is recommended that no action be taken. */
2672 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
2673 DeviceExtension->iDevice));
2674 return TRUE;
2675 }
2676
2677#if 0
2678 /* Don't disable the extended video mode. This would only switch the video mode
2679 * to <current width> x <current height> x 0 bpp which is not what we want. And
2680 * even worse, it causes an disturbing additional mode switch */
2681 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2682 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2683#endif
2684
2685 /* Tell the host that we no longer support graphics in the additions
2686 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
2687 */
2688 // VBoxVideoSetGraphicsCap(FALSE);
2689 return TRUE;
2690}
2691
2692/**
2693 * VBoxVideoMapVideoMemory
2694 *
2695 * Maps the video hardware frame buffer and video RAM into the virtual address
2696 * space of the requestor.
2697 */
2698BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2699 PVIDEO_MEMORY RequestedAddress,
2700 PVIDEO_MEMORY_INFORMATION MapInformation,
2701 PSTATUS_BLOCK StatusBlock)
2702{
2703 PHYSICAL_ADDRESS FrameBuffer;
2704 ULONG inIoSpace = 0;
2705 VP_STATUS Status;
2706
2707 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
2708
2709 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2710
2711 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2712 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
2713
2714 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2715 &MapInformation->VideoRamLength, &inIoSpace,
2716 &MapInformation->VideoRamBase);
2717
2718 if (Status == NO_ERROR)
2719 {
2720 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2721 MapInformation->FrameBufferLength =
2722 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2723 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2724 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2725
2726 /* Save the new framebuffer size */
2727 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2728 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
2729 MapInformation->FrameBufferBase,
2730 MapInformation->FrameBufferLength,
2731 DeviceExtension->ulFrameBufferOffset);
2732 return TRUE;
2733 }
2734
2735 return FALSE;
2736}
2737
2738/**
2739 * VBoxVideoUnmapVideoMemory
2740 *
2741 * Releases a mapping between the virtual address space and the adapter's
2742 * frame buffer and video RAM.
2743 */
2744BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2745 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2746{
2747 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2748 HGSMIAreaClear (&DeviceExtension->areaDisplay);
2749 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2750 return TRUE;
2751}
2752
2753/**
2754 * VBoxVideoQueryNumAvailModes
2755 *
2756 * Returns the number of video modes supported by the adapter and the size
2757 * in bytes of the video mode information, which can be used to allocate a
2758 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2759 */
2760BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2761 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2762{
2763 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2764 /* calculate the video modes table */
2765 VBoxBuildModesTable(DeviceExtension);
2766 Modes->NumModes = gNumVideoModes;
2767 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2768 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2769 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2770 return TRUE;
2771}
2772
2773/**
2774 * VBoxVideoQueryAvailModes
2775 *
2776 * Returns information about each video mode supported by the adapter.
2777 */
2778BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2779 PVIDEO_MODE_INFORMATION ReturnedModes,
2780 PSTATUS_BLOCK StatusBlock)
2781{
2782 ULONG Size;
2783
2784 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2785
2786 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2787 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2788 StatusBlock->Information = Size;
2789
2790 return TRUE;
2791}
2792
2793/**
2794 * VBoxVideoQueryCurrentMode
2795 *
2796 * Returns information about current video mode.
2797 */
2798BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2799 PVIDEO_MODE_INFORMATION VideoModeInfo,
2800 PSTATUS_BLOCK StatusBlock)
2801{
2802 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2803
2804 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2805 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2806
2807 return TRUE;
2808}
2809#endif /* ifndef VBOX_WITH_WDDM */
2810/*
2811 * VBoxVideoSetColorRegisters
2812 *
2813 * Sets the adapter's color registers to the specified RGB values. There
2814 * are code paths in this function, one generic and one for VGA compatible
2815 * controllers. The latter is needed for Bochs, where the generic one isn't
2816 * yet implemented.
2817 */
2818
2819BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2820 PDEVICE_EXTENSION DeviceExtension,
2821 PVIDEO_CLUT ColorLookUpTable,
2822 PSTATUS_BLOCK StatusBlock)
2823{
2824 LONG Entry;
2825
2826 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2827
2828 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2829 return FALSE;
2830
2831 for (Entry = ColorLookUpTable->FirstEntry;
2832 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2833 Entry++)
2834 {
2835 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2836 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2837 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2838 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2839 }
2840
2841 return TRUE;
2842}
2843
2844#ifndef VBOX_WITH_WDDM
2845
2846VP_STATUS VBoxVideoGetChildDescriptor(
2847 PVOID HwDeviceExtension,
2848 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2849 PVIDEO_CHILD_TYPE VideoChildType,
2850 PUCHAR pChildDescriptor,
2851 PULONG pUId,
2852 PULONG pUnused)
2853{
2854 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2855 HwDeviceExtension, ChildEnumInfo));
2856
2857 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2858
2859 if (ChildEnumInfo->ChildIndex > 0)
2860 {
2861 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2862 {
2863 *VideoChildType = Monitor;
2864 *pUId = ChildEnumInfo->ChildIndex;
2865
2866 return VIDEO_ENUM_MORE_DEVICES;
2867 }
2868 }
2869
2870 return ERROR_NO_MORE_DEVICES;
2871}
2872
2873
2874static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2875{
2876 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2877 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2878
2879 if (pPrimaryDevExt)
2880 {
2881 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2882
2883 if (req)
2884 {
2885 int rc = VbglGRPerform (&req->header);
2886
2887 if (RT_FAILURE(rc))
2888 {
2889 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
2890 }
2891 }
2892 }
2893
2894 return;
2895}
2896
2897int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2898{
2899 int rc = VINF_SUCCESS;
2900
2901 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2902
2903 /*
2904 * Query the VMMDev memory pointer. There we need VBVAMemory.
2905 */
2906 VMMDevMemory *pVMMDevMemory = NULL;
2907
2908 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2909
2910 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2911
2912 if (pDevExt->iDevice > 0)
2913 {
2914 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2915
2916 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2917 pDevExt->iDevice));
2918
2919 if ( ulEnable
2920 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2921 {
2922 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2923 pVbvaResult->pfnFlush = vboxVbvaFlush;
2924 pVbvaResult->pvFlush = pDevExt;
2925 }
2926 else
2927 {
2928 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2929 }
2930
2931 return rc;
2932 }
2933
2934 if (RT_SUCCESS(rc))
2935 {
2936 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2937 if (pDevExt->u.primary.pvReqFlush == NULL)
2938 {
2939 VMMDevVideoAccelFlush *req = NULL;
2940
2941 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2942 sizeof (VMMDevVideoAccelFlush),
2943 VMMDevReq_VideoAccelFlush);
2944
2945 if (RT_SUCCESS (rc))
2946 {
2947 pDevExt->u.primary.pvReqFlush = req;
2948 }
2949 else
2950 {
2951 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
2952 }
2953 }
2954 }
2955 else
2956 {
2957 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
2958 }
2959
2960 if (RT_SUCCESS(rc))
2961 {
2962 ULONG ulEnabled = 0;
2963
2964 /*
2965 * Tell host that VBVA status is changed.
2966 */
2967 VMMDevVideoAccelEnable *req = NULL;
2968
2969 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2970 sizeof (VMMDevVideoAccelEnable),
2971 VMMDevReq_VideoAccelEnable);
2972
2973 if (RT_SUCCESS(rc))
2974 {
2975 req->u32Enable = ulEnable;
2976 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2977 req->fu32Status = 0;
2978
2979 rc = VbglGRPerform (&req->header);
2980
2981 if (RT_SUCCESS(rc))
2982 {
2983 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2984 {
2985 /*
2986 * Initialize the result information and VBVA memory.
2987 */
2988 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2989 {
2990 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2991 pVbvaResult->pfnFlush = vboxVbvaFlush;
2992 pVbvaResult->pvFlush = pDevExt;
2993 ulEnabled = 1;
2994 }
2995 else
2996 {
2997 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2998 }
2999
3000 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
3001 }
3002 else
3003 {
3004 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
3005
3006 /* Disable VBVA for old hosts. */
3007 req->u32Enable = 0;
3008 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3009 req->fu32Status = 0;
3010
3011 VbglGRPerform (&req->header);
3012
3013 rc = VERR_NOT_SUPPORTED;
3014 }
3015 }
3016 else
3017 {
3018 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
3019 }
3020
3021 VbglGRFree (&req->header);
3022 }
3023 else
3024 {
3025 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
3026 }
3027
3028 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
3029 }
3030
3031 return rc;
3032}
3033#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