VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring and some re-ordering

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