VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 117.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 < DeviceExtension->pPrimary->u.primary.cDisplays; iCustomMode++)
898 {
899 if (fDisplayChangeRequest && iCustomMode == display)
900 {
901 /* Do not keep info for this display, which received a video mode hint, to make sure that
902 * the new mode will be taken from the alternating index entries actually.
903 */
904 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
905 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
906 }
907 else
908 {
909 VideoModes[gNumVideoModes] = CustomVideoModes[iCustomMode];
910 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
911 }
912#ifdef LOG_ENABLED
913 dprintf(("Custom mode for %2d: %4d x %4d @ %2d\n",
914 iCustomMode, CustomVideoModes[iCustomMode].VisScreenWidth,
915 CustomVideoModes[iCustomMode].VisScreenHeight, CustomVideoModes[iCustomMode].BitsPerPlane));
916#endif
917 gNumVideoModes++;
918 }
919
920 if (display != DeviceExtension->iDevice)
921 {
922 /* The display change is for another monitor. Just add 2 standard modes to the table
923 * to make enough entries. This is not necessary if it is a first mode set (CurrentMode == 0),
924 * because these 2 entries will be added by "if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)"
925 * code branch.
926 */
927 if (DeviceExtension->CurrentMode != 0)
928 {
929 dprintf(("Filling custom mode entries.\n"));
930 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
931 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
932 gNumVideoModes++;
933 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
934 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
935 gNumVideoModes++;
936 }
937 }
938#endif /* VBOX_WITH_MULTIMONITOR_FIX */
939
940#ifndef VBOX_WITH_MULTIMONITOR_FIX
941 uint32_t xres = 0, yres = 0, bpp = 0, display = 0;
942 if ( ( vboxQueryDisplayRequest(&xres, &yres, &bpp, &display)
943 && (xres || yres || bpp))
944 || (gCustomXRes || gCustomYRes || gCustomBPP))
945#else
946 if (fDisplayChangeRequest || DeviceExtension->CurrentMode == 0)
947#endif /* VBOX_WITH_MULTIMONITOR_FIX */
948 {
949#ifndef VBOX_WITH_WDDM
950 dprintf(("VBoxVideo: adding custom video mode as #%d, current mode: %d \n", gNumVideoModes + 1, DeviceExtension->CurrentMode));
951 /* handle the startup case */
952 if (DeviceExtension->CurrentMode == 0)
953#else
954 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
955#endif
956 {
957 /* Use the stored custom resolution values only if nothing was read from host.
958 * The custom mode might be not valid anymore and would block any hints from host.
959 */
960#ifndef VBOX_WITH_MULTIMONITOR_FIX
961 if (!xres)
962 xres = gCustomXRes;
963 if (!yres)
964 yres = gCustomYRes;
965 if (!bpp)
966 bpp = gCustomBPP;
967 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d\n", xres, yres, bpp));
968#else
969 if (!xres)
970 xres = CustomVideoModes[DeviceExtension->iDevice].VisScreenWidth;
971 if (!yres)
972 yres = CustomVideoModes[DeviceExtension->iDevice].VisScreenHeight;
973 if (!bpp)
974 bpp = CustomVideoModes[DeviceExtension->iDevice].BitsPerPlane;
975 dprintf(("VBoxVideo: using stored custom resolution %dx%dx%d for %d\n", xres, yres, bpp, DeviceExtension->iDevice));
976#endif /* VBOX_WITH_MULTIMONITOR_FIX */
977 }
978 /* round down to multiple of 8 */
979 if ((xres & 0xfff8) != xres)
980 dprintf(("VBoxVideo: rounding down xres from %d to %d\n", xres, xres & 0xfff8));
981 xres &= 0xfff8;
982 /* take the current values for the fields that are not set */
983#ifndef VBOX_WITH_WDDM
984 if (DeviceExtension->CurrentMode != 0)
985 {
986 if (!xres)
987 xres = DeviceExtension->CurrentModeWidth;
988 if (!yres)
989 yres = DeviceExtension->CurrentModeHeight;
990 if (!bpp)
991 bpp = DeviceExtension->CurrentModeBPP;
992 }
993#else
994 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
995 {
996 if (!xres)
997 xres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.width;
998 if (!yres)
999 yres = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.height;
1000 if (!bpp)
1001 bpp = DeviceExtension->aSources[0].pPrimaryAllocation->SurfDesc.bpp;
1002 }
1003#endif
1004
1005 /* Use a default value. */
1006 if (!bpp)
1007 bpp = 32;
1008
1009 /* does the host like that mode? */
1010#ifndef VBOX_WITH_WDDM
1011 if (vboxLikesVideoMode(DeviceExtension->iDevice, xres, yres, bpp))
1012#else
1013 if (vboxLikesVideoMode(0, xres, yres, bpp))
1014#endif
1015 {
1016 /* we must have a valid video mode by now and it must fit within the VRAM */
1017 if ( ( xres
1018 && yres
1019 && ( (bpp == 16)
1020#ifdef VBOX_WITH_8BPP_MODES
1021 || (bpp == 8)
1022#endif
1023 || (bpp == 24)
1024 || (bpp == 32)))
1025 && (xres * yres * (bpp / 8) < vramSize))
1026
1027 {
1028 /* we need an alternating index */
1029#ifdef VBOX_WITH_MULTIMONITOR_FIX
1030 /* Only alternate index if the new custom mode differs from the last one
1031 * (only resolution and bpp changes are important, a display change does not matter).
1032 * Always add 2 last entries to the mode array, so number of video modes
1033 * do not change.
1034 */
1035 BOOLEAN fNewInvocation = FALSE;
1036 static uint32_t sPrev_xres = 0;
1037 static uint32_t sPrev_yres = 0;
1038 static uint32_t sPrev_bpp = 0;
1039 if ( sPrev_xres != xres
1040 || sPrev_yres != yres
1041 || sPrev_bpp != bpp)
1042 {
1043 sPrev_xres = xres;
1044 sPrev_yres = yres;
1045 sPrev_bpp = bpp;
1046 fNewInvocation = TRUE;
1047 }
1048 BOOLEAN fAlternatedIndex = FALSE;
1049#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1050#ifndef VBOX_WITH_WDDM
1051 if (DeviceExtension->CurrentMode != 0)
1052#else
1053 if (DeviceExtension->u.primary.cDisplays && DeviceExtension->aSources[0].pPrimaryAllocation)
1054#endif
1055#ifndef VBOX_WITH_MULTIMONITOR_FIX
1056 {
1057 if (gInvocationCounter % 2)
1058 gNumVideoModes++;
1059 gInvocationCounter++;
1060 }
1061#else
1062 {
1063 if (fNewInvocation)
1064 gInvocationCounter++;
1065 if (gInvocationCounter % 2)
1066 {
1067 fAlternatedIndex = TRUE;
1068
1069 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1070 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1071 gNumVideoModes++;
1072 }
1073 }
1074 else
1075 {
1076 fNewInvocation = FALSE;
1077 }
1078#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1079
1080 dprintf(("VBoxVideo: setting special mode to xres = %d, yres = %d, bpp = %d, display = %d\n", xres, yres, bpp, display));
1081#ifdef VBOX_WITH_MULTIMONITOR_FIX
1082 dprintf(("VBoxVideo: fNewInvocation = %d, fAlternatedIndex = %d\n", fNewInvocation, fAlternatedIndex));
1083#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1084#ifdef VBOX_WITH_WDDM
1085 /* assign host-supplied as the most preferable */
1086 gPreferredVideoMode = gNumVideoModes;
1087#endif
1088 /*
1089 * Build mode entry.
1090 * Note that we do not apply the y offset for the custom mode. It is
1091 * only used for the predefined modes that the user can configure in
1092 * the display properties dialog.
1093 */
1094 VideoModes[gNumVideoModes].Length = sizeof(VIDEO_MODE_INFORMATION);
1095 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1096 VideoModes[gNumVideoModes].VisScreenWidth = xres;
1097 VideoModes[gNumVideoModes].VisScreenHeight = yres;
1098 VideoModes[gNumVideoModes].ScreenStride = xres * (bpp / 8);
1099 VideoModes[gNumVideoModes].NumberOfPlanes = 1;
1100 VideoModes[gNumVideoModes].BitsPerPlane = bpp;
1101 VideoModes[gNumVideoModes].Frequency = 60;
1102 VideoModes[gNumVideoModes].XMillimeter = 320;
1103 VideoModes[gNumVideoModes].YMillimeter = 240;
1104 switch (bpp)
1105 {
1106#ifdef VBOX_WITH_8BPP_MODES
1107 case 8:
1108 VideoModes[gNumVideoModes].NumberRedBits = 6;
1109 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1110 VideoModes[gNumVideoModes].NumberBlueBits = 6;
1111 VideoModes[gNumVideoModes].RedMask = 0;
1112 VideoModes[gNumVideoModes].GreenMask = 0;
1113 VideoModes[gNumVideoModes].BlueMask = 0;
1114 break;
1115#endif
1116 case 16:
1117 VideoModes[gNumVideoModes].NumberRedBits = 5;
1118 VideoModes[gNumVideoModes].NumberGreenBits = 6;
1119 VideoModes[gNumVideoModes].NumberBlueBits = 5;
1120 VideoModes[gNumVideoModes].RedMask = 0xF800;
1121 VideoModes[gNumVideoModes].GreenMask = 0x7E0;
1122 VideoModes[gNumVideoModes].BlueMask = 0x1F;
1123 break;
1124 case 24:
1125 VideoModes[gNumVideoModes].NumberRedBits = 8;
1126 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1127 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1128 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1129 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1130 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1131 break;
1132 case 32:
1133 VideoModes[gNumVideoModes].NumberRedBits = 8;
1134 VideoModes[gNumVideoModes].NumberGreenBits = 8;
1135 VideoModes[gNumVideoModes].NumberBlueBits = 8;
1136 VideoModes[gNumVideoModes].RedMask = 0xFF0000;
1137 VideoModes[gNumVideoModes].GreenMask = 0xFF00;
1138 VideoModes[gNumVideoModes].BlueMask = 0xFF;
1139 break;
1140 }
1141 VideoModes[gNumVideoModes].AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
1142#ifdef VBOX_WITH_8BPP_MODES
1143 if (bpp == 8)
1144 VideoModes[gNumVideoModes].AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
1145#endif
1146 VideoModes[gNumVideoModes].VideoMemoryBitmapWidth = xres;
1147 VideoModes[gNumVideoModes].VideoMemoryBitmapHeight = yres;
1148 VideoModes[gNumVideoModes].DriverSpecificAttributeFlags = 0;
1149#ifdef VBOX_WITH_MULTIMONITOR_FIX
1150 /* Save the mode in the list of custom modes for this display. */
1151 CustomVideoModes[DeviceExtension->iDevice] = VideoModes[gNumVideoModes];
1152#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1153 ++gNumVideoModes;
1154
1155 /* for the startup case, we need this mode twice due to the alternating mode number */
1156#ifndef VBOX_WITH_WDDM
1157 if (DeviceExtension->CurrentMode == 0)
1158#else
1159 if (!DeviceExtension->u.primary.cDisplays || !DeviceExtension->aSources[0].pPrimaryAllocation)
1160#endif
1161 {
1162 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1163 memcpy(&VideoModes[gNumVideoModes], &VideoModes[gNumVideoModes - 1], sizeof(VIDEO_MODE_INFORMATION));
1164 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1165 gNumVideoModes++;
1166 }
1167#ifdef VBOX_WITH_MULTIMONITOR_FIX
1168 else if (!fAlternatedIndex)
1169 {
1170 dprintf(("VBoxVideo: making a copy of the custom mode as #%d\n", gNumVideoModes + 1));
1171 memcpy(&VideoModes[gNumVideoModes], &VideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
1172 VideoModes[gNumVideoModes].ModeIndex = gNumVideoModes + 1;
1173 gNumVideoModes++;
1174 }
1175#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1176
1177#ifndef VBOX_WITH_MULTIMONITOR_FIX
1178 /* store this video mode as the last custom video mode */
1179 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1180 if (status != NO_ERROR)
1181 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1182 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1183 if (status != NO_ERROR)
1184 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1185 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1186 if (status != NO_ERROR)
1187 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1188#else
1189 /* Save the custom mode for this display. */
1190 if (DeviceExtension->iDevice == 0)
1191 {
1192 /* Name without a suffix */
1193 status = VBoxVideoCmnRegSetDword(Reg, L"CustomXRes", xres);
1194 if (status != NO_ERROR)
1195 dprintf(("VBoxVideo: error %d writing CustomXRes\n", status));
1196 status = VBoxVideoCmnRegSetDword(Reg, L"CustomYRes", yres);
1197 if (status != NO_ERROR)
1198 dprintf(("VBoxVideo: error %d writing CustomYRes\n", status));
1199 status = VBoxVideoCmnRegSetDword(Reg, L"CustomBPP", bpp);
1200 if (status != NO_ERROR)
1201 dprintf(("VBoxVideo: error %d writing CustomBPP\n", status));
1202 }
1203 else
1204 {
1205 wchar_t keyname[32];
1206 swprintf(keyname, L"CustomXRes%d", DeviceExtension->iDevice);
1207 status = VBoxVideoCmnRegSetDword(Reg, keyname, xres);
1208 if (status != NO_ERROR)
1209 dprintf(("VBoxVideo: error %d writing CustomXRes%d\n", status, DeviceExtension->iDevice));
1210 swprintf(keyname, L"CustomYRes%d", DeviceExtension->iDevice);
1211 status = VBoxVideoCmnRegSetDword(Reg, keyname, yres);
1212 if (status != NO_ERROR)
1213 dprintf(("VBoxVideo: error %d writing CustomYRes%d\n", status, DeviceExtension->iDevice));
1214 swprintf(keyname, L"CustomBPP%d", DeviceExtension->iDevice);
1215 status = VBoxVideoCmnRegSetDword(Reg, keyname, bpp);
1216 if (status != NO_ERROR)
1217 dprintf(("VBoxVideo: error %d writing CustomBPP%d\n", status, DeviceExtension->iDevice));
1218 }
1219#endif /* VBOX_WITH_MULTIMONITOR_FIX */
1220 }
1221 else
1222 {
1223 dprintf(("VBoxVideo: invalid parameters for special mode: (xres = %d, yres = %d, bpp = %d, vramSize = %d)\n",
1224 xres, yres, bpp, vramSize));
1225 if (xres * yres * (bpp / 8) >= vramSize
1226 && (xres != g_xresNoVRAM || yres != g_yresNoVRAM || bpp != g_bppNoVRAM))
1227 {
1228 LogRel(("VBoxVideo: not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.\n",
1229 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
1230 g_xresNoVRAM = xres;
1231 g_yresNoVRAM = yres;
1232 g_bppNoVRAM = bpp;
1233 }
1234 }
1235 }
1236 else
1237 dprintf(("VBoxVideo: host does not like special mode: (xres = %d, yres = %d, bpp = %d)\n",
1238 xres, yres, bpp));
1239 }
1240#if defined(LOG_ENABLED)
1241 {
1242 int i;
1243#ifndef VBOX_WITH_WDDM
1244 dprintf(("VBoxVideo: VideoModes (CurrentMode = %d, last #%d)\n", DeviceExtension->CurrentMode, gNumVideoModes));
1245#endif
1246 for (i = 0; i < RT_ELEMENTS(VideoModes); i++)
1247 {
1248 if ( VideoModes[i].VisScreenWidth
1249 || VideoModes[i].VisScreenHeight
1250 || VideoModes[i].BitsPerPlane)
1251 {
1252 dprintf((" %2d: #%d %4d x %4d @ %2d\n",
1253 i, VideoModes[i].ModeIndex, VideoModes[i].VisScreenWidth,
1254 VideoModes[i].VisScreenHeight, VideoModes[i].BitsPerPlane));
1255 }
1256 }
1257 }
1258#endif
1259
1260#ifdef VBOX_WITH_WDDM
1261 vboxWddmBuildResolutionTable();
1262#endif
1263
1264 VBoxVideoCmnRegFini(Reg);
1265}
1266
1267#ifdef VBOX_WITH_WDDM
1268static bool g_bModesTableInitialized = false;
1269/**
1270 * Helper function to dynamically build our table of standard video
1271 * modes. We take the amount of VRAM and create modes with standard
1272 * geometries until we've either reached the maximum number of modes
1273 * or the available VRAM does not allow for additional modes.
1274 */
1275VOID VBoxWddmGetModesTable(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1276 VIDEO_MODE_INFORMATION ** ppModes, uint32_t * pcModes, int32_t * pPreferrableMode,
1277 D3DKMDT_2DREGION **ppResolutions, uint32_t * pcResolutions)
1278{
1279 if(bRebuildTable || !g_bModesTableInitialized)
1280 {
1281 VBoxBuildModesTable(DeviceExtension);
1282 g_bModesTableInitialized = true;
1283 }
1284
1285 *ppModes = VideoModes;
1286 *pcModes = gNumVideoModes;
1287 *pPreferrableMode = (int32_t)gPreferredVideoMode;
1288 *ppResolutions = g_VBoxWddmVideoResolutions;
1289 *pcResolutions = g_VBoxWddmNumResolutions;
1290}
1291
1292VOID VBoxWddmInvalidateModesTable(PDEVICE_EXTENSION DeviceExtension)
1293{
1294 g_bModesTableInitialized = false;
1295}
1296
1297NTSTATUS VBoxWddmGetModesForResolution(PDEVICE_EXTENSION DeviceExtension, bool bRebuildTable,
1298 D3DKMDT_2DREGION *pResolution,
1299 VIDEO_MODE_INFORMATION * pModes, uint32_t cModes, uint32_t *pcModes, int32_t *piPreferrableMode)
1300{
1301 VIDEO_MODE_INFORMATION *pAllModes;
1302 uint32_t cAllModes, cAllResolutions;
1303 int32_t iPreferrableMode;
1304 D3DKMDT_2DREGION *pAllResolutions;
1305 VBoxWddmGetModesTable(DeviceExtension, bRebuildTable,
1306 &pAllModes, &cAllModes, &iPreferrableMode,
1307 &pAllResolutions, &cAllResolutions);
1308 NTSTATUS Status = STATUS_SUCCESS;
1309 uint32_t cFound = 0;
1310 int iFoundPreferrableMode = -1;
1311 for (uint32_t i = 0; i < cAllModes; ++i)
1312 {
1313 VIDEO_MODE_INFORMATION *pCur = &pAllModes[i];
1314 if (pResolution->cx == pAllModes[i].VisScreenWidth
1315 && pResolution->cy == pAllModes[i].VisScreenHeight)
1316 {
1317 if (pModes && cModes > cFound)
1318 memcpy(&pModes[cFound], pCur, sizeof (VIDEO_MODE_INFORMATION));
1319 else
1320 Status = STATUS_BUFFER_TOO_SMALL;
1321
1322 if (i == (uint32_t)iPreferrableMode)
1323 iFoundPreferrableMode = cFound;
1324
1325 ++cFound;
1326 }
1327 }
1328
1329 Assert(iFoundPreferrableMode < 0 || cFound > (uint32_t)iFoundPreferrableMode);
1330
1331 *pcModes = cFound;
1332 if (piPreferrableMode)
1333 *piPreferrableMode = iFoundPreferrableMode;
1334
1335 return Status;
1336}
1337
1338#else
1339
1340/* Computes the size of a framebuffer. DualView has a few framebuffers of the computed size. */
1341void VBoxComputeFrameBufferSizes (PDEVICE_EXTENSION PrimaryExtension)
1342{
1343 ULONG ulAvailable = commonFromDeviceExt(PrimaryExtension)->cbVRAM
1344 - commonFromDeviceExt(PrimaryExtension)->cbMiniportHeap
1345 - VBVA_ADAPTER_INFORMATION_SIZE;
1346
1347 /* Size of a framebuffer. */
1348
1349 ULONG ulSize = ulAvailable / PrimaryExtension->u.primary.cDisplays;
1350
1351 /* Align down to 4096 bytes. */
1352 ulSize &= ~0xFFF;
1353
1354 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: cbVRAM = 0x%08X, cDisplays = %d, ulSize = 0x%08X, ulSize * cDisplays = 0x%08X, slack = 0x%08X\n",
1355 commonFromDeviceExt(PrimaryExtension)->cbVRAM, PrimaryExtension->u.primary.cDisplays,
1356 ulSize, ulSize * PrimaryExtension->u.primary.cDisplays,
1357 ulAvailable - ulSize * PrimaryExtension->u.primary.cDisplays));
1358
1359
1360 /* Update the primary info. */
1361 PrimaryExtension->u.primary.ulMaxFrameBufferSize = ulSize;
1362
1363 /* Update the per extension info. */
1364 PDEVICE_EXTENSION Extension = PrimaryExtension;
1365 ULONG ulFrameBufferOffset = 0;
1366 while (Extension)
1367 {
1368 Extension->ulFrameBufferOffset = ulFrameBufferOffset;
1369 /* That is assigned when a video mode is set. */
1370 Extension->ulFrameBufferSize = 0;
1371
1372 dprintf(("VBoxVideo::VBoxComputeFrameBufferSizes: [%d] ulFrameBufferOffset 0x%08X\n",
1373 Extension->iDevice, ulFrameBufferOffset));
1374
1375 ulFrameBufferOffset += PrimaryExtension->u.primary.ulMaxFrameBufferSize;
1376
1377 Extension = Extension->pNext;
1378 }
1379}
1380
1381#endif
1382
1383int VBoxMapAdapterMemory (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 < pDevExt->u.primary.cDisplays;
1526#else
1527 iCustomMode < pDevExt->pPrimary->u.primary.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 ((PDEVICE_EXTENSION)HwDeviceExtension)->u.primary.cDisplays = 1;
1703 VBoxVideoCmnMemZero(&((PDEVICE_EXTENSION)HwDeviceExtension)->areaDisplay, sizeof(HGSMIAREA));
1704 /* Guest supports only HGSMI, the old VBVA via VMMDev is not supported. Old
1705 * code will be ifdef'ed and later removed.
1706 * The host will however support both old and new interface to keep compatibility
1707 * with old guest additions.
1708 */
1709 VBoxSetupDisplaysHGSMI((PDEVICE_EXTENSION)HwDeviceExtension, ConfigInfo, AdapterMemorySize, 0);
1710
1711 if (commonFromDeviceExt((PDEVICE_EXTENSION)HwDeviceExtension)->bHGSMI)
1712 {
1713 LogRel(("VBoxVideo: using HGSMI\n"));
1714 }
1715
1716 // pretend success to make the driver work.
1717 rc = NO_ERROR;
1718 } else
1719 {
1720 dprintf(("VBoxVideo::VBoxVideoFindAdapter: VBE card not found, returning ERROR_DEV_NOT_EXIST\n"));
1721 rc = ERROR_DEV_NOT_EXIST;
1722 }
1723 dprintf(("VBoxVideo::VBoxVideoFindAdapter: returning with rc = 0x%x\n", rc));
1724 return rc;
1725}
1726
1727/**
1728 * VBoxVideoInitialize
1729 *
1730 * Performs the first initialization of the adapter, after the HAL has given
1731 * up control of the video hardware to the video port driver.
1732 */
1733BOOLEAN VBoxVideoInitialize(PVOID HwDeviceExtension)
1734{
1735 dprintf(("VBoxVideo::VBoxVideoInitialize\n"));
1736
1737 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1738
1739 /* Initialize the request pointer. */
1740 pDevExt->u.primary.pvReqFlush = NULL;
1741
1742 vboxVideoInitCustomVideoModes(pDevExt);
1743
1744 return TRUE;
1745}
1746
1747# ifdef VBOX_WITH_VIDEOHWACCEL
1748
1749BOOLEAN VBoxVideoInterrupt(PVOID HwDeviceExtension)
1750{
1751 PDEVICE_EXTENSION devExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1752 PDEVICE_EXTENSION PrimaryExtension = devExt->pPrimary;
1753 if (PrimaryExtension)
1754 {
1755 if (commonFromDeviceExt(PrimaryExtension)->pHostFlags) /* If HGSMI is enabled at all. */
1756 {
1757 uint32_t flags = commonFromDeviceExt(PrimaryExtension)->pHostFlags->u32HostFlags;
1758 if((flags & HGSMIHOSTFLAGS_IRQ) != 0)
1759 {
1760 if((flags & HGSMIHOSTFLAGS_COMMANDS_PENDING) != 0)
1761 {
1762 /* schedule a DPC*/
1763 BOOLEAN bResult = PrimaryExtension->u.primary.VideoPortProcs.pfnQueueDpc(PrimaryExtension, VBoxVideoHGSMIDpc, (PVOID)1);
1764 Assert(bResult);
1765 }
1766 /* clear the IRQ */
1767 HGSMIClearIrq (commonFromDeviceExt(PrimaryExtension));
1768 return TRUE;
1769 }
1770 }
1771 }
1772 return FALSE;
1773}
1774# endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */
1775#endif /* #ifndef VBOX_WITH_WDDM */
1776/**
1777 * Send a request to the host to make the absolute pointer visible
1778 */
1779static BOOLEAN ShowPointer(PVOID HwDeviceExtension)
1780{
1781 BOOLEAN Result = TRUE;
1782
1783 /* Use primary device extension, because the show pointer request should be processed
1784 * in vboxUpdatePointerShape regardless of the device. */
1785#ifndef VBOX_WITH_WDDM
1786 PDEVICE_EXTENSION PrimaryExtension = ((PDEVICE_EXTENSION)HwDeviceExtension)->pPrimary;
1787#else
1788 PDEVICE_EXTENSION PrimaryExtension = (PDEVICE_EXTENSION)HwDeviceExtension;
1789#endif
1790
1791 if (DEV_MOUSE_HIDDEN(PrimaryExtension))
1792 {
1793 // tell the host to use the guest's pointer
1794 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
1795
1796 /* Visible and No Shape means Show the pointer.
1797 * It is enough to init only this field.
1798 */
1799 PointerAttributes.Enable = VBOX_MOUSE_POINTER_VISIBLE;
1800
1801 Result = vboxUpdatePointerShape(PrimaryExtension, &PointerAttributes, sizeof (PointerAttributes));
1802
1803 if (Result)
1804 DEV_SET_MOUSE_SHOWN(PrimaryExtension);
1805 else
1806 dprintf(("VBoxVideo::ShowPointer: Could not show the hardware pointer -> fallback\n"));
1807 }
1808 return Result;
1809}
1810
1811#ifndef VBOX_WITH_WDDM
1812/**
1813 * VBoxVideoStartIO
1814 *
1815 * Processes the specified Video Request Packet.
1816 */
1817BOOLEAN VBoxVideoStartIO(PVOID HwDeviceExtension,
1818 PVIDEO_REQUEST_PACKET RequestPacket)
1819{
1820 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
1821
1822 BOOLEAN Result;
1823
1824// dprintf(("VBoxVideo::VBoxVideoStartIO: Code %08X\n", RequestPacket->IoControlCode));
1825
1826 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
1827
1828 switch (RequestPacket->IoControlCode)
1829 {
1830 case IOCTL_VIDEO_SET_CURRENT_MODE:
1831 {
1832 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MODE))
1833 {
1834 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1835 return TRUE;
1836 }
1837 Result = VBoxVideoSetCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
1838 (PVIDEO_MODE)RequestPacket->InputBuffer,
1839 RequestPacket->StatusBlock);
1840 break;
1841 }
1842
1843 case IOCTL_VIDEO_RESET_DEVICE:
1844 {
1845 Result = VBoxVideoResetDevice((PDEVICE_EXTENSION)HwDeviceExtension,
1846 RequestPacket->StatusBlock);
1847 break;
1848 }
1849
1850 case IOCTL_VIDEO_MAP_VIDEO_MEMORY:
1851 {
1852 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MEMORY_INFORMATION) ||
1853 RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1854 {
1855 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1856 return TRUE;
1857 }
1858 Result = VBoxVideoMapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1859 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1860 (PVIDEO_MEMORY_INFORMATION)RequestPacket->OutputBuffer,
1861 RequestPacket->StatusBlock);
1862 break;
1863 }
1864
1865 case IOCTL_VIDEO_UNMAP_VIDEO_MEMORY:
1866 {
1867 if (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY))
1868 {
1869 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1870 return TRUE;
1871 }
1872 Result = VBoxVideoUnmapVideoMemory((PDEVICE_EXTENSION)HwDeviceExtension,
1873 (PVIDEO_MEMORY)RequestPacket->InputBuffer,
1874 RequestPacket->StatusBlock);
1875 break;
1876 }
1877
1878 case IOCTL_VIDEO_SHARE_VIDEO_MEMORY:
1879 {
1880 PVIDEO_SHARE_MEMORY pShareMemory;
1881 PVIDEO_SHARE_MEMORY_INFORMATION pShareMemoryInformation;
1882 PHYSICAL_ADDRESS shareAddress;
1883 PVOID virtualAddress = NULL;
1884 ULONG sharedViewSize;
1885 ULONG inIoSpace = 0;
1886 VP_STATUS status;
1887
1888 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY\n"));
1889
1890 if ( (RequestPacket->OutputBufferLength < sizeof(VIDEO_SHARE_MEMORY_INFORMATION))
1891 || (RequestPacket->InputBufferLength < sizeof(VIDEO_MEMORY)) ) {
1892
1893 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1894 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1895 Result = FALSE;
1896 break;
1897 }
1898
1899 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1900
1901 if ( (pShareMemory->ViewOffset > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize)
1902 || ((pShareMemory->ViewOffset + pShareMemory->ViewSize) > pDevExt->pPrimary->u.primary.ulMaxFrameBufferSize) ) {
1903
1904 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));
1905 RequestPacket->StatusBlock->Status = ERROR_INVALID_PARAMETER;
1906 Result = FALSE;
1907 break;
1908 }
1909
1910 RequestPacket->StatusBlock->Information = sizeof(VIDEO_SHARE_MEMORY_INFORMATION);
1911
1912 virtualAddress = pShareMemory->ProcessHandle;
1913 sharedViewSize = pShareMemory->ViewSize;
1914
1915 shareAddress.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + pDevExt->ulFrameBufferOffset;
1916
1917 status = VideoPortMapMemory(HwDeviceExtension, shareAddress, &sharedViewSize, &inIoSpace, &virtualAddress);
1918 if (status != NO_ERROR)
1919 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortMapMemory failed with %x\n", status));
1920 Result = (status == NO_ERROR);
1921
1922 pShareMemoryInformation = (PVIDEO_SHARE_MEMORY_INFORMATION)RequestPacket->OutputBuffer;
1923 pShareMemoryInformation->SharedViewOffset = pShareMemory->ViewOffset;
1924 pShareMemoryInformation->VirtualAddress = virtualAddress;
1925 pShareMemoryInformation->SharedViewSize = sharedViewSize;
1926 break;
1927 }
1928
1929 case IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY:
1930 {
1931 PVIDEO_SHARE_MEMORY pShareMemory;
1932 VP_STATUS status;
1933
1934 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY\n"));
1935
1936 if (RequestPacket->InputBufferLength < sizeof(VIDEO_SHARE_MEMORY))
1937 {
1938 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_UNSHARE_VIDEO_MEMORY: ERROR_INSUFFICIENT_BUFFER\n"));
1939 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1940 Result = FALSE;
1941 break;
1942 }
1943
1944 pShareMemory = (PVIDEO_SHARE_MEMORY)RequestPacket->InputBuffer;
1945
1946 status = VideoPortUnmapMemory(HwDeviceExtension, pShareMemory->RequestedVirtualAddress, pShareMemory->ProcessHandle);
1947 if (status != NO_ERROR)
1948 dprintf(("VBoxVideo::VBoxVideoStartIO: VideoPortUnmapMemory failed with %x\n", status));
1949 Result = (status == NO_ERROR);
1950 break;
1951 }
1952
1953 /*
1954 * The display driver asks us how many video modes we support
1955 * so that it can supply an appropriate buffer for the next call.
1956 */
1957 case IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES:
1958 {
1959 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_NUM_MODES))
1960 {
1961 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1962 return TRUE;
1963 }
1964 Result = VBoxVideoQueryNumAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1965 (PVIDEO_NUM_MODES)RequestPacket->OutputBuffer,
1966 RequestPacket->StatusBlock);
1967 break;
1968 }
1969
1970 /*
1971 * The display driver asks us to provide a list of supported video modes
1972 * into a buffer it has allocated.
1973 */
1974 case IOCTL_VIDEO_QUERY_AVAIL_MODES:
1975 {
1976 if (RequestPacket->OutputBufferLength <
1977 gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION))
1978 {
1979 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1980 return TRUE;
1981 }
1982 Result = VBoxVideoQueryAvailModes((PDEVICE_EXTENSION)HwDeviceExtension,
1983 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
1984 RequestPacket->StatusBlock);
1985 break;
1986 }
1987
1988 case IOCTL_VIDEO_SET_COLOR_REGISTERS:
1989 {
1990 if (RequestPacket->InputBufferLength < sizeof(VIDEO_CLUT) ||
1991 RequestPacket->InputBufferLength <
1992 (((PVIDEO_CLUT)RequestPacket->InputBuffer)->NumEntries * sizeof(ULONG)) +
1993 sizeof(VIDEO_CLUT))
1994 {
1995 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
1996 return TRUE;
1997 }
1998 Result = VBoxVideoSetColorRegisters((PDEVICE_EXTENSION)HwDeviceExtension,
1999 (PVIDEO_CLUT)RequestPacket->InputBuffer,
2000 RequestPacket->StatusBlock);
2001 break;
2002 }
2003
2004 case IOCTL_VIDEO_QUERY_CURRENT_MODE:
2005 {
2006 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_MODE_INFORMATION))
2007 {
2008 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2009 return TRUE;
2010 }
2011 Result = VBoxVideoQueryCurrentMode((PDEVICE_EXTENSION)HwDeviceExtension,
2012 (PVIDEO_MODE_INFORMATION)RequestPacket->OutputBuffer,
2013 RequestPacket->StatusBlock);
2014 break;
2015 }
2016
2017 // show the pointer
2018 case IOCTL_VIDEO_ENABLE_POINTER:
2019 {
2020 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_ENABLE_POINTER\n"));
2021 // find out whether the host wants absolute positioning
2022 /// @todo this is now obsolete - remove it?
2023 if (vboxQueryHostWantsAbsolute())
2024 Result = ShowPointer(HwDeviceExtension);
2025 else
2026 {
2027 // fallback to software pointer
2028 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2029 Result = FALSE;
2030 }
2031 break;
2032 }
2033
2034 // hide the pointer
2035 case IOCTL_VIDEO_DISABLE_POINTER:
2036 {
2037 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_DISABLE_POINTER\n"));
2038 // find out whether the host wants absolute positioning
2039 if (vboxQueryHostWantsAbsolute())
2040 {
2041 // tell the host to hide pointer
2042 VIDEO_POINTER_ATTRIBUTES PointerAttributes;
2043
2044 /* Enable == 0 means no shape, not visible.
2045 * It is enough to init only this field.
2046 */
2047 PointerAttributes.Enable = 0;
2048
2049 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, &PointerAttributes, sizeof (PointerAttributes));
2050
2051 if (Result)
2052 DEV_SET_MOUSE_HIDDEN((PDEVICE_EXTENSION)HwDeviceExtension);
2053 else
2054 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not hide hardware pointer -> fallback\n"));
2055 } else
2056 {
2057 // fallback to software pointer
2058 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2059 Result = FALSE;
2060 }
2061 break;
2062 }
2063
2064 /*
2065 * Change the pointer shape
2066 */
2067 case IOCTL_VIDEO_SET_POINTER_ATTR:
2068 {
2069 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SET_POINTER_ATTR\n"));
2070 if (RequestPacket->InputBufferLength < sizeof(VIDEO_POINTER_ATTRIBUTES))
2071 {
2072 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small (%d bytes)\n", RequestPacket->InputBufferLength));
2073 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2074 return TRUE;
2075 }
2076 // find out whether the host wants absolute positioning
2077 if (vboxQueryHostWantsAbsolute())
2078 {
2079 PVIDEO_POINTER_ATTRIBUTES pPointerAttributes = (PVIDEO_POINTER_ATTRIBUTES)RequestPacket->InputBuffer;
2080#if 0
2081 dprintf(("Pointer shape information:\n"
2082 "\tFlags: %d\n"
2083 "\tWidth: %d\n"
2084 "\tHeight: %d\n"
2085 "\tWidthInBytes: %d\n"
2086 "\tEnable: %d\n"
2087 "\tColumn: %d\n"
2088 "\tRow: %d\n",
2089 pPointerAttributes->Flags, pPointerAttributes->Width, pPointerAttributes->Height,
2090 pPointerAttributes->WidthInBytes, pPointerAttributes->Enable, pPointerAttributes->Column,
2091 pPointerAttributes->Row));
2092 dprintf(("\tBytes attached: %d\n", RequestPacket->InputBufferLength - sizeof(VIDEO_POINTER_ATTRIBUTES)));
2093#endif
2094 Result = vboxUpdatePointerShape((PDEVICE_EXTENSION)HwDeviceExtension, pPointerAttributes, RequestPacket->InputBufferLength);
2095 if (!Result)
2096 dprintf(("VBoxVideo::VBoxVideoStartIO: Could not set hardware pointer -> fallback\n"));
2097 } else
2098 {
2099 dprintf(("VBoxVideo::VBoxVideoStartIO: Fallback to software pointer\n"));
2100 // fallback to software pointer
2101 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2102 Result = FALSE;
2103 }
2104 break;
2105 }
2106
2107 // query pointer information
2108 case IOCTL_VIDEO_QUERY_POINTER_ATTR:
2109 {
2110 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_ATTR\n"));
2111 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2112 Result = FALSE;
2113 break;
2114 }
2115
2116 // set the pointer position
2117 case IOCTL_VIDEO_SET_POINTER_POSITION:
2118 {
2119 // find out whether the host wants absolute positioning
2120 /// @todo this is now obsolete - remove it?
2121 if (vboxQueryHostWantsAbsolute())
2122 Result = ShowPointer(HwDeviceExtension);
2123 else
2124 {
2125 // fallback to software pointer
2126 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2127 Result = FALSE;
2128 }
2129 break;
2130 }
2131
2132 // query the pointer position
2133 case IOCTL_VIDEO_QUERY_POINTER_POSITION:
2134 {
2135 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_POSITION\n"));
2136 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_POSITION))
2137 {
2138 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2139 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2140 return TRUE;
2141 }
2142 Result = FALSE;
2143 uint16_t mousePosX;
2144 uint16_t mousePosY;
2145 if (vboxQueryPointerPos(&mousePosX, &mousePosY))
2146 {
2147 PVIDEO_POINTER_POSITION pointerPos = (PVIDEO_POINTER_POSITION)RequestPacket->OutputBuffer;
2148 PVIDEO_MODE_INFORMATION ModeInfo;
2149 ModeInfo = &VideoModes[((PDEVICE_EXTENSION)HwDeviceExtension)->CurrentMode - 1];
2150 // map from 0xFFFF to the current resolution
2151 pointerPos->Column = (SHORT)(mousePosX / (0xFFFF / ModeInfo->VisScreenWidth));
2152 pointerPos->Row = (SHORT)(mousePosY / (0xFFFF / ModeInfo->VisScreenHeight));
2153 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_POSITION);
2154 Result = TRUE;
2155 }
2156 if (!Result)
2157 {
2158 // fallback to software pointer
2159 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2160 }
2161 break;
2162 }
2163
2164 // Determine hardware cursor capabilities. We will always report that we are
2165 // very capable even though the host might not want to do pointer integration.
2166 // This is done because we can still return errors on the actual calls later to
2167 // make the display driver go to the fallback routines.
2168 case IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES:
2169 {
2170 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_POINTER_CAPABILITIES\n"));
2171 if (RequestPacket->OutputBufferLength < sizeof(VIDEO_POINTER_CAPABILITIES))
2172 {
2173 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small!\n"));
2174 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2175 return TRUE;
2176 }
2177 PVIDEO_POINTER_CAPABILITIES pCaps = (PVIDEO_POINTER_CAPABILITIES)RequestPacket->OutputBuffer;
2178 pCaps->Flags = VIDEO_MODE_ASYNC_POINTER |
2179 VIDEO_MODE_COLOR_POINTER |
2180 VIDEO_MODE_MONO_POINTER;
2181 // for now we go with 64x64 cursors
2182 pCaps->MaxWidth = 64;
2183 pCaps->MaxHeight = 64;
2184 // that doesn't seem to be relevant, VBoxDisp doesn't use it
2185 pCaps->HWPtrBitmapStart = -1;
2186 pCaps->HWPtrBitmapEnd = -1;
2187 RequestPacket->StatusBlock->Information = sizeof(VIDEO_POINTER_CAPABILITIES);
2188 Result = TRUE;
2189 break;
2190 }
2191
2192 /* Attach/detach DualView devices */
2193 case IOCTL_VIDEO_SWITCH_DUALVIEW:
2194 {
2195 ULONG ulAttach;
2196
2197 ulAttach = *((PULONG)RequestPacket->InputBuffer);
2198 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_SWITCH_DUALVIEW[%d] (%ld)\n", pDevExt->iDevice, ulAttach));
2199
2200 if (pDevExt->iDevice > 0)
2201 {
2202 pDevExt->u.secondary.bEnabled = (BOOLEAN)ulAttach;
2203 }
2204 Result = TRUE;
2205 break;
2206 }
2207
2208 case IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY:
2209 {
2210 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_INTERPRET_DISPLAY_MEMORY\n"));
2211 /* Pre-HGSMI IOCTL */
2212 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2213 Result = false;
2214 break;
2215 }
2216
2217
2218 case IOCTL_VIDEO_VBVA_ENABLE:
2219 {
2220 int rc;
2221 ULONG ulEnable;
2222
2223 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE\n"));
2224
2225 if (RequestPacket->InputBufferLength < sizeof(ULONG))
2226 {
2227 dprintf(("VBoxVideo::VBoxVideoStartIO: Input buffer too small: %d needed: %d!!!\n",
2228 RequestPacket->InputBufferLength, sizeof(ULONG)));
2229 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2230 return FALSE;
2231 }
2232
2233 if (RequestPacket->OutputBufferLength < sizeof(VBVAENABLERESULT))
2234 {
2235 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2236 RequestPacket->OutputBufferLength, sizeof(VBVAENABLERESULT)));
2237 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2238 return FALSE;
2239 }
2240
2241 ulEnable = *(ULONG *)RequestPacket->InputBuffer;
2242 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE ulEnable = %08X\n", ulEnable));
2243
2244 rc = vboxVbvaEnable (pDevExt, ulEnable, (VBVAENABLERESULT *)RequestPacket->OutputBuffer);
2245 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE completed rc = %Rrc\n", rc));
2246
2247 if (RT_FAILURE (rc))
2248 {
2249 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_VBVA_ENABLE: failed to enable VBVA\n"));
2250 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2251 return FALSE;
2252 }
2253
2254 RequestPacket->StatusBlock->Information = sizeof(VBVAENABLERESULT);
2255 Result = TRUE;
2256
2257 break;
2258 }
2259
2260 /* Private ioctls */
2261 case IOCTL_VIDEO_VBOX_SETVISIBLEREGION:
2262 {
2263 uint32_t cRect = RequestPacket->InputBufferLength/sizeof(RTRECT);
2264 int rc;
2265
2266 dprintf(("IOCTL_VIDEO_VBOX_SETVISIBLEREGION cRect=%d\n", cRect));
2267 if ( RequestPacket->InputBufferLength < sizeof(RTRECT)
2268 || RequestPacket->InputBufferLength != cRect*sizeof(RTRECT))
2269 {
2270 dprintf(("VBoxVideo::IOCTL_VIDEO_VBOX_SETVISIBLEREGION: Output buffer too small: %d needed: %d!!!\n",
2271 RequestPacket->OutputBufferLength, sizeof(RTRECT)));
2272 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2273 return FALSE;
2274 }
2275 /*
2276 * Inform the host about the visible region
2277 */
2278 VMMDevVideoSetVisibleRegion *req = NULL;
2279
2280 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2281 sizeof (VMMDevVideoSetVisibleRegion) + (cRect-1)*sizeof(RTRECT),
2282 VMMDevReq_VideoSetVisibleRegion);
2283
2284 if (RT_SUCCESS(rc))
2285 {
2286 req->cRect = cRect;
2287 memcpy(&req->Rect, RequestPacket->InputBuffer, cRect*sizeof(RTRECT));
2288
2289 rc = VbglGRPerform (&req->header);
2290
2291 if (RT_SUCCESS(rc))
2292 {
2293 Result = TRUE;
2294 break;
2295 }
2296 }
2297
2298 dprintf(("VBoxVideo::VBoxVideoStartIO: Failed with rc=%x\n", rc));
2299 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2300 return FALSE;
2301 }
2302
2303 case IOCTL_VIDEO_QUERY_HGSMI_INFO:
2304 {
2305 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_QUERY_HGSMI_INFO\n"));
2306
2307 if (RequestPacket->OutputBufferLength < sizeof(QUERYHGSMIRESULT))
2308 {
2309 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2310 RequestPacket->OutputBufferLength, sizeof(QUERYHGSMIRESULT)));
2311 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2312 return FALSE;
2313 }
2314
2315 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2316 {
2317 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2318 return FALSE;
2319 }
2320
2321 QUERYHGSMIRESULT *pInfo = (QUERYHGSMIRESULT *)RequestPacket->OutputBuffer;
2322
2323 pInfo->iDevice = pDevExt->iDevice;
2324 pInfo->ulFlags = 0;
2325
2326 /* Describes VRAM chunk for this display device. */
2327 pInfo->areaDisplay = pDevExt->areaDisplay;
2328
2329 pInfo->u32DisplayInfoSize = VBVA_DISPLAY_INFORMATION_SIZE;
2330 pInfo->u32MinVBVABufferSize = VBVA_MIN_BUFFER_SIZE;
2331
2332 pInfo->IOPortGuestCommand = commonFromDeviceExt(pDevExt)->IOPortGuest;
2333
2334 RequestPacket->StatusBlock->Information = sizeof(QUERYHGSMIRESULT);
2335 Result = TRUE;
2336
2337 break;
2338 }
2339 case IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS:
2340 {
2341 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_CALLBACKS\n"));
2342
2343 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCALLBACKS))
2344 {
2345 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2346 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCALLBACKS)));
2347 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2348 return FALSE;
2349 }
2350
2351 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2352 {
2353 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2354 return FALSE;
2355 }
2356
2357 HGSMIQUERYCALLBACKS *pInfo = (HGSMIQUERYCALLBACKS *)RequestPacket->OutputBuffer;
2358
2359 pInfo->hContext = pDevExt;
2360 pInfo->pfnCompletionHandler = hgsmiHostCmdComplete;
2361 pInfo->pfnRequestCommandsHandler = hgsmiHostCmdRequest;
2362
2363 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCALLBACKS);
2364 Result = TRUE;
2365 break;
2366 }
2367 case IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS:
2368 {
2369 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_QUERY_PORTPROCS\n"));
2370
2371 if (RequestPacket->OutputBufferLength < sizeof(HGSMIQUERYCPORTPROCS))
2372 {
2373 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2374 RequestPacket->OutputBufferLength, sizeof(HGSMIQUERYCPORTPROCS)));
2375 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2376 return FALSE;
2377 }
2378
2379 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2380 {
2381 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2382 return FALSE;
2383 }
2384
2385 HGSMIQUERYCPORTPROCS *pInfo = (HGSMIQUERYCPORTPROCS *)RequestPacket->OutputBuffer;
2386 pInfo->pContext = pDevExt->pPrimary;
2387 pInfo->VideoPortProcs = pDevExt->pPrimary->u.primary.VideoPortProcs;
2388
2389 RequestPacket->StatusBlock->Information = sizeof(HGSMIQUERYCPORTPROCS);
2390 Result = TRUE;
2391 break;
2392 }
2393 case IOCTL_VIDEO_HGSMI_HANDLER_ENABLE:
2394 {
2395 dprintf(("VBoxVideo::VBoxVideoStartIO: IOCTL_VIDEO_HGSMI_HANDLER_ENABLE\n"));
2396
2397 if (RequestPacket->InputBufferLength< sizeof(HGSMIHANDLERENABLE))
2398 {
2399 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2400 RequestPacket->InputBufferLength, sizeof(HGSMIHANDLERENABLE)));
2401 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2402 return FALSE;
2403 }
2404
2405 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2406 {
2407 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2408 return FALSE;
2409 }
2410
2411 HGSMIHANDLERENABLE *pInfo = (HGSMIHANDLERENABLE *)RequestPacket->InputBuffer;
2412
2413 int rc = vboxVBVAChannelDisplayEnable(pDevExt->pPrimary,
2414 pDevExt->iDevice,
2415 pInfo->u8Channel);
2416 if(RT_FAILURE(rc))
2417 {
2418 RequestPacket->StatusBlock->Status = ERROR_INVALID_NAME;
2419 }
2420 Result = TRUE;
2421 break;
2422 }
2423 case IOCTL_VIDEO_HGSMI_HANDLER_DISABLE:
2424 {
2425 /* TODO: implement */
2426 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2427 {
2428 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2429 return FALSE;
2430 }
2431 break;
2432 }
2433# ifdef VBOX_WITH_VIDEOHWACCEL
2434 case IOCTL_VIDEO_VHWA_QUERY_INFO:
2435 {
2436 if (RequestPacket->OutputBufferLength < sizeof (VHWAQUERYINFO))
2437 {
2438 dprintf(("VBoxVideo::VBoxVideoStartIO: Output buffer too small: %d needed: %d!!!\n",
2439 RequestPacket->OutputBufferLength, sizeof(VHWAQUERYINFO)));
2440 RequestPacket->StatusBlock->Status = ERROR_INSUFFICIENT_BUFFER;
2441 return FALSE;
2442 }
2443
2444 if (!commonFromDeviceExt(pDevExt)->bHGSMI)
2445 {
2446 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2447 return FALSE;
2448 }
2449
2450 VHWAQUERYINFO *pInfo = (VHWAQUERYINFO *)RequestPacket->OutputBuffer;
2451 pInfo->offVramBase = (ULONG_PTR)pDevExt->ulFrameBufferOffset;
2452 RequestPacket->StatusBlock->Information = sizeof (VHWAQUERYINFO);
2453 Result = TRUE;
2454 break;
2455 }
2456# endif
2457 default:
2458 dprintf(("VBoxVideo::VBoxVideoStartIO: Unsupported %p, fn %d(0x%x)\n",
2459 RequestPacket->IoControlCode,
2460 (RequestPacket->IoControlCode >> 2) & 0xFFF,
2461 (RequestPacket->IoControlCode >> 2) & 0xFFF));
2462 RequestPacket->StatusBlock->Status = ERROR_INVALID_FUNCTION;
2463 return FALSE;
2464 }
2465
2466 if (Result)
2467 RequestPacket->StatusBlock->Status = NO_ERROR;
2468 else
2469 RequestPacket->StatusBlock->Information = 0;
2470
2471// dprintf(("VBoxVideo::VBoxVideoStartIO: Completed\n"));
2472
2473 return TRUE;
2474}
2475
2476/**
2477 * VBoxVideoReset HW
2478 *
2479 * Resets the video hardware.
2480 */
2481BOOLEAN VBoxVideoResetHW(PVOID HwDeviceExtension, ULONG Columns, ULONG Rows)
2482{
2483 dprintf(("VBoxVideo::VBoxVideoResetHW\n"));
2484
2485 PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)HwDeviceExtension;
2486
2487 if (pDevExt->iDevice > 0)
2488 {
2489 dprintf(("VBoxVideo::VBoxVideoResetHW: Skipping for non-primary display %d\n",
2490 pDevExt->iDevice));
2491 return TRUE;
2492 }
2493
2494 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2495 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2496
2497 if (pDevExt->u.primary.pvReqFlush != NULL)
2498 {
2499 VbglGRFree ((VMMDevRequestHeader *)pDevExt->u.primary.pvReqFlush);
2500 pDevExt->u.primary.pvReqFlush = NULL;
2501 }
2502
2503 VbglTerminate ();
2504
2505 VBoxUnmapAdapterMemory (pDevExt, &commonFromDeviceExt(pDevExt)->pvMiniportHeap, commonFromDeviceExt(pDevExt)->cbMiniportHeap);
2506 VBoxUnmapAdapterInformation (pDevExt);
2507
2508 return TRUE;
2509}
2510
2511/**
2512 * VBoxVideoGetPowerState
2513 *
2514 * Queries whether the device can support the requested power state.
2515 */
2516VP_STATUS VBoxVideoGetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2517 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2518{
2519 dprintf(("VBoxVideo::VBoxVideoGetPowerState\n"));
2520 return NO_ERROR;
2521}
2522
2523/**
2524 * VBoxVideoSetPowerState
2525 *
2526 * Sets the power state of the specified device
2527 */
2528VP_STATUS VBoxVideoSetPowerState(PVOID HwDeviceExtension, ULONG HwId,
2529 PVIDEO_POWER_MANAGEMENT VideoPowerControl)
2530{
2531 dprintf(("VBoxVideo::VBoxVideoSetPowerState\n"));
2532 return NO_ERROR;
2533}
2534#endif /* #ifndef VBOX_WITH_WDDM */
2535
2536/**
2537 * VBoxVideoSetGraphicsCap
2538 *
2539 * Tells the host whether or not we currently support graphics in the
2540 * additions
2541 */
2542BOOLEAN FASTCALL VBoxVideoSetGraphicsCap(BOOLEAN isEnabled)
2543{
2544 VMMDevReqGuestCapabilities2 *req = NULL;
2545 int rc;
2546
2547 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2548 sizeof (VMMDevReqGuestCapabilities2),
2549 VMMDevReq_SetGuestCapabilities);
2550
2551 if (!RT_SUCCESS(rc))
2552 dprintf(("VBoxVideoSetGraphicsCap: failed to allocate a request, rc=%Rrc\n", rc));
2553 else
2554 {
2555 req->u32OrMask = isEnabled ? VMMDEV_GUEST_SUPPORTS_GRAPHICS : 0;
2556 req->u32NotMask = isEnabled ? 0 : VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2557
2558 rc = VbglGRPerform (&req->header);
2559 if (RT_FAILURE(rc))
2560 dprintf(("VBoxVideoSetGraphicsCap: request failed, rc = %Rrc\n", rc));
2561 }
2562 if (req != NULL)
2563 VbglGRFree (&req->header);
2564 return RT_SUCCESS(rc);
2565}
2566
2567
2568BOOLEAN FASTCALL VBoxVideoSetCurrentModePerform(PDEVICE_EXTENSION DeviceExtension,
2569 USHORT width, USHORT height, USHORT bpp
2570#ifdef VBOX_WITH_WDDM
2571 , ULONG offDisplay
2572#endif
2573 )
2574{
2575 /* set the mode characteristics */
2576 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
2577 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, width);
2578 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
2579 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, height);
2580 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
2581 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, bpp);
2582 /* enable the mode */
2583 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2584 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
2585#ifdef VBOX_WITH_WDDM
2586 /* encode linear offDisplay to xOffset & yOffset to ensure offset fits USHORT */
2587 ULONG cbLine = VBOXWDDM_ROUNDBOUND(((width * bpp) + 7) / 8, 4);
2588 ULONG xOffset = offDisplay % cbLine;
2589 if (bpp == 4)
2590 {
2591 xOffset <<= 1;
2592 }
2593 else
2594 {
2595 Assert(!(xOffset%((bpp + 7) >> 3)));
2596 xOffset /= ((bpp + 7) >> 3);
2597 }
2598 ULONG yOffset = offDisplay / cbLine;
2599 Assert(xOffset <= 0xffff);
2600 Assert(yOffset <= 0xffff);
2601 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
2602 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)xOffset);
2603 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
2604 VBoxVideoCmnPortWriteUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, (USHORT)yOffset);
2605#endif
2606 /** @todo read from the port to see if the mode switch was successful */
2607
2608 /* Tell the host that we now support graphics in the additions.
2609 * @todo: Keep old behaviour, because VBoxVideoResetDevice is called on every graphics
2610 * mode switch and causes an OFF/ON sequence which is not handled by frontends
2611 * (for example Qt GUI debug build asserts when seamless is being enabled).
2612 */
2613 // VBoxVideoSetGraphicsCap(TRUE);
2614
2615 return TRUE;
2616}
2617
2618#ifndef VBOX_WITH_WDDM
2619
2620/**
2621 * VBoxVideoSetCurrentMode
2622 *
2623 * Sets the adapter to the specified operating mode.
2624 */
2625BOOLEAN FASTCALL VBoxVideoSetCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2626 PVIDEO_MODE RequestedMode, PSTATUS_BLOCK StatusBlock)
2627{
2628 PVIDEO_MODE_INFORMATION ModeInfo;
2629
2630 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: mode = %d\n", RequestedMode->RequestedMode));
2631
2632 DeviceExtension->CurrentMode = RequestedMode->RequestedMode;
2633 ModeInfo = &VideoModes[DeviceExtension->CurrentMode - 1];
2634 dprintf(("VBoxVideoSetCurrentMode: width: %d, height: %d, bpp: %d\n", ModeInfo->VisScreenWidth,
2635 ModeInfo->VisScreenHeight, ModeInfo->BitsPerPlane));
2636
2637 DeviceExtension->CurrentModeWidth = ModeInfo->VisScreenWidth;
2638 DeviceExtension->CurrentModeHeight = ModeInfo->VisScreenHeight;
2639 DeviceExtension->CurrentModeBPP = ModeInfo->BitsPerPlane;
2640
2641 if (DeviceExtension->iDevice > 0)
2642 {
2643 dprintf(("VBoxVideo::VBoxVideoSetCurrentMode: Skipping for non-primary display %d\n",
2644 DeviceExtension->iDevice));
2645 return TRUE;
2646 }
2647
2648 return VBoxVideoSetCurrentModePerform(DeviceExtension,
2649 (USHORT)ModeInfo->VisScreenWidth,
2650 (USHORT)ModeInfo->VisScreenHeight,
2651 (USHORT)ModeInfo->BitsPerPlane);
2652}
2653
2654/*
2655 * VBoxVideoResetDevice
2656 *
2657 * Resets the video hardware to the default mode, to which it was initialized
2658 * at system boot.
2659 */
2660
2661BOOLEAN FASTCALL VBoxVideoResetDevice(
2662 PDEVICE_EXTENSION DeviceExtension,
2663 PSTATUS_BLOCK StatusBlock)
2664{
2665 dprintf(("VBoxVideo::VBoxVideoResetDevice\n"));
2666
2667 if (DeviceExtension->iDevice > 0)
2668 {
2669 /* If the device is the secondary display, however, it is recommended that no action be taken. */
2670 dprintf(("VBoxVideo::VBoxVideoResetDevice: Skipping for non-primary display %d\n",
2671 DeviceExtension->iDevice));
2672 return TRUE;
2673 }
2674
2675#if 0
2676 /* Don't disable the extended video mode. This would only switch the video mode
2677 * to <current width> x <current height> x 0 bpp which is not what we want. And
2678 * even worse, it causes an disturbing additional mode switch */
2679 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
2680 VideoPortWritePortUshort((PUSHORT)VBE_DISPI_IOPORT_DATA, VBE_DISPI_DISABLED);
2681#endif
2682
2683 /* Tell the host that we no longer support graphics in the additions
2684 * @todo: Keep old behaviour, see similar comment in VBoxVideoSetCurrentMode for details.
2685 */
2686 // VBoxVideoSetGraphicsCap(FALSE);
2687 return TRUE;
2688}
2689
2690/**
2691 * VBoxVideoMapVideoMemory
2692 *
2693 * Maps the video hardware frame buffer and video RAM into the virtual address
2694 * space of the requestor.
2695 */
2696BOOLEAN FASTCALL VBoxVideoMapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2697 PVIDEO_MEMORY RequestedAddress,
2698 PVIDEO_MEMORY_INFORMATION MapInformation,
2699 PSTATUS_BLOCK StatusBlock)
2700{
2701 PHYSICAL_ADDRESS FrameBuffer;
2702 ULONG inIoSpace = 0;
2703 VP_STATUS Status;
2704
2705 dprintf(("VBoxVideo::VBoxVideoMapVideoMemory: fb offset 0x%x\n", DeviceExtension->ulFrameBufferOffset));
2706
2707 FrameBuffer.QuadPart = VBE_DISPI_LFB_PHYSICAL_ADDRESS + DeviceExtension->ulFrameBufferOffset;
2708
2709 MapInformation->VideoRamBase = RequestedAddress->RequestedVirtualAddress;
2710 MapInformation->VideoRamLength = DeviceExtension->pPrimary->u.primary.ulMaxFrameBufferSize;
2711
2712 Status = VideoPortMapMemory(DeviceExtension, FrameBuffer,
2713 &MapInformation->VideoRamLength, &inIoSpace,
2714 &MapInformation->VideoRamBase);
2715
2716 if (Status == NO_ERROR)
2717 {
2718 MapInformation->FrameBufferBase = (PUCHAR)MapInformation->VideoRamBase;
2719 MapInformation->FrameBufferLength =
2720 VideoModes[DeviceExtension->CurrentMode - 1].VisScreenHeight *
2721 VideoModes[DeviceExtension->CurrentMode - 1].ScreenStride;
2722 StatusBlock->Information = sizeof(VIDEO_MEMORY_INFORMATION);
2723
2724 /* Save the new framebuffer size */
2725 DeviceExtension->ulFrameBufferSize = MapInformation->FrameBufferLength;
2726 HGSMIAreaInitialize (&DeviceExtension->areaDisplay,
2727 MapInformation->FrameBufferBase,
2728 MapInformation->FrameBufferLength,
2729 DeviceExtension->ulFrameBufferOffset);
2730 return TRUE;
2731 }
2732
2733 return FALSE;
2734}
2735
2736/**
2737 * VBoxVideoUnmapVideoMemory
2738 *
2739 * Releases a mapping between the virtual address space and the adapter's
2740 * frame buffer and video RAM.
2741 */
2742BOOLEAN FASTCALL VBoxVideoUnmapVideoMemory(PDEVICE_EXTENSION DeviceExtension,
2743 PVIDEO_MEMORY VideoMemory, PSTATUS_BLOCK StatusBlock)
2744{
2745 dprintf(("VBoxVideo::VBoxVideoUnmapVideoMemory\n"));
2746 HGSMIAreaClear (&DeviceExtension->areaDisplay);
2747 VideoPortUnmapMemory(DeviceExtension, VideoMemory->RequestedVirtualAddress, NULL);
2748 return TRUE;
2749}
2750
2751/**
2752 * VBoxVideoQueryNumAvailModes
2753 *
2754 * Returns the number of video modes supported by the adapter and the size
2755 * in bytes of the video mode information, which can be used to allocate a
2756 * buffer for an IOCTL_VIDEO_QUERY_AVAIL_MODES request.
2757 */
2758BOOLEAN FASTCALL VBoxVideoQueryNumAvailModes(PDEVICE_EXTENSION DeviceExtension,
2759 PVIDEO_NUM_MODES Modes, PSTATUS_BLOCK StatusBlock)
2760{
2761 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes\n"));
2762 /* calculate the video modes table */
2763 VBoxBuildModesTable(DeviceExtension);
2764 Modes->NumModes = gNumVideoModes;
2765 Modes->ModeInformationLength = sizeof(VIDEO_MODE_INFORMATION);
2766 StatusBlock->Information = sizeof(VIDEO_NUM_MODES);
2767 dprintf(("VBoxVideo::VBoxVideoQueryNumAvailModes: number of modes: %d\n", Modes->NumModes));
2768 return TRUE;
2769}
2770
2771/**
2772 * VBoxVideoQueryAvailModes
2773 *
2774 * Returns information about each video mode supported by the adapter.
2775 */
2776BOOLEAN FASTCALL VBoxVideoQueryAvailModes(PDEVICE_EXTENSION DeviceExtension,
2777 PVIDEO_MODE_INFORMATION ReturnedModes,
2778 PSTATUS_BLOCK StatusBlock)
2779{
2780 ULONG Size;
2781
2782 dprintf(("VBoxVideo::VBoxVideoQueryAvailModes\n"));
2783
2784 Size = gNumVideoModes * sizeof(VIDEO_MODE_INFORMATION);
2785 VideoPortMoveMemory(ReturnedModes, VideoModes, Size);
2786 StatusBlock->Information = Size;
2787
2788 return TRUE;
2789}
2790
2791/**
2792 * VBoxVideoQueryCurrentMode
2793 *
2794 * Returns information about current video mode.
2795 */
2796BOOLEAN FASTCALL VBoxVideoQueryCurrentMode(PDEVICE_EXTENSION DeviceExtension,
2797 PVIDEO_MODE_INFORMATION VideoModeInfo,
2798 PSTATUS_BLOCK StatusBlock)
2799{
2800 dprintf(("VBoxVideo::VBoxVideoQueryCurrentMode\n"));
2801
2802 StatusBlock->Information = sizeof(VIDEO_MODE_INFORMATION);
2803 VideoPortMoveMemory(VideoModeInfo, VideoModes + DeviceExtension->CurrentMode - 1, 1);
2804
2805 return TRUE;
2806}
2807#endif /* ifndef VBOX_WITH_WDDM */
2808/*
2809 * VBoxVideoSetColorRegisters
2810 *
2811 * Sets the adapter's color registers to the specified RGB values. There
2812 * are code paths in this function, one generic and one for VGA compatible
2813 * controllers. The latter is needed for Bochs, where the generic one isn't
2814 * yet implemented.
2815 */
2816
2817BOOLEAN FASTCALL VBoxVideoSetColorRegisters(
2818 PDEVICE_EXTENSION DeviceExtension,
2819 PVIDEO_CLUT ColorLookUpTable,
2820 PSTATUS_BLOCK StatusBlock)
2821{
2822 LONG Entry;
2823
2824 dprintf(("VBoxVideo::VBoxVideoSetColorRegisters first entry %d num entries %d\n", ColorLookUpTable->FirstEntry, ColorLookUpTable->NumEntries));
2825
2826 if (ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry > 256)
2827 return FALSE;
2828
2829 for (Entry = ColorLookUpTable->FirstEntry;
2830 Entry < ColorLookUpTable->NumEntries + ColorLookUpTable->FirstEntry;
2831 Entry++)
2832 {
2833 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c8, (UCHAR)Entry);
2834 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Red);
2835 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Green);
2836 VBoxVideoCmnPortWriteUchar((PUCHAR)0x03c9, ColorLookUpTable->LookupTable[Entry].RgbArray.Blue);
2837 }
2838
2839 return TRUE;
2840}
2841
2842#ifndef VBOX_WITH_WDDM
2843
2844VP_STATUS VBoxVideoGetChildDescriptor(
2845 PVOID HwDeviceExtension,
2846 PVIDEO_CHILD_ENUM_INFO ChildEnumInfo,
2847 PVIDEO_CHILD_TYPE VideoChildType,
2848 PUCHAR pChildDescriptor,
2849 PULONG pUId,
2850 PULONG pUnused)
2851{
2852 dprintf(("VBoxVideo::VBoxVideoGetChildDescriptor: HwDeviceExtension = %p, ChildEnumInfo = %p\n",
2853 HwDeviceExtension, ChildEnumInfo));
2854
2855 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)HwDeviceExtension;
2856
2857 if (ChildEnumInfo->ChildIndex > 0)
2858 {
2859 if ((int)ChildEnumInfo->ChildIndex <= pDevExt->pPrimary->u.primary.cDisplays)
2860 {
2861 *VideoChildType = Monitor;
2862 *pUId = ChildEnumInfo->ChildIndex;
2863
2864 return VIDEO_ENUM_MORE_DEVICES;
2865 }
2866 }
2867
2868 return ERROR_NO_MORE_DEVICES;
2869}
2870
2871
2872static DECLCALLBACK(void) vboxVbvaFlush (void *pvFlush)
2873{
2874 DEVICE_EXTENSION *pDevExt = (DEVICE_EXTENSION *)pvFlush;
2875 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt? pDevExt->pPrimary: NULL;
2876
2877 if (pPrimaryDevExt)
2878 {
2879 VMMDevVideoAccelFlush *req = (VMMDevVideoAccelFlush *)pPrimaryDevExt->u.primary.pvReqFlush;
2880
2881 if (req)
2882 {
2883 int rc = VbglGRPerform (&req->header);
2884
2885 if (RT_FAILURE(rc))
2886 {
2887 dprintf(("VBoxVideo::vbvaFlush: rc = %Rrc!\n", rc));
2888 }
2889 }
2890 }
2891
2892 return;
2893}
2894
2895int vboxVbvaEnable (PDEVICE_EXTENSION pDevExt, ULONG ulEnable, VBVAENABLERESULT *pVbvaResult)
2896{
2897 int rc = VINF_SUCCESS;
2898
2899 dprintf(("VBoxVideo::vboxVbvaEnable: ulEnable = %08X, pVbvaResult = %p\n", ulEnable, pVbvaResult));
2900
2901 /*
2902 * Query the VMMDev memory pointer. There we need VBVAMemory.
2903 */
2904 VMMDevMemory *pVMMDevMemory = NULL;
2905
2906 rc = VbglQueryVMMDevMemory (&pVMMDevMemory);
2907
2908 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %d, pVMMDevMemory = %p\n", rc, pVMMDevMemory));
2909
2910 if (pDevExt->iDevice > 0)
2911 {
2912 DEVICE_EXTENSION *pPrimaryDevExt = pDevExt->pPrimary;
2913
2914 dprintf(("VBoxVideo::vboxVbvaEnable: Skipping for non-primary display %d\n",
2915 pDevExt->iDevice));
2916
2917 if ( ulEnable
2918 && pPrimaryDevExt->u.primary.ulVbvaEnabled)
2919 {
2920 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2921 pVbvaResult->pfnFlush = vboxVbvaFlush;
2922 pVbvaResult->pvFlush = pDevExt;
2923 }
2924 else
2925 {
2926 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2927 }
2928
2929 return rc;
2930 }
2931
2932 if (RT_SUCCESS(rc))
2933 {
2934 /* Allocate the memory block for VMMDevReq_VideoAccelFlush request. */
2935 if (pDevExt->u.primary.pvReqFlush == NULL)
2936 {
2937 VMMDevVideoAccelFlush *req = NULL;
2938
2939 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2940 sizeof (VMMDevVideoAccelFlush),
2941 VMMDevReq_VideoAccelFlush);
2942
2943 if (RT_SUCCESS (rc))
2944 {
2945 pDevExt->u.primary.pvReqFlush = req;
2946 }
2947 else
2948 {
2949 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc (VMMDevReq_VideoAccelFlush) rc = %Rrc!!!\n", rc));
2950 }
2951 }
2952 }
2953 else
2954 {
2955 dprintf(("VBoxVideo::vboxVbvaEnable: VbglQueryVMMDevMemory rc = %Rrc!!!\n", rc));
2956 }
2957
2958 if (RT_SUCCESS(rc))
2959 {
2960 ULONG ulEnabled = 0;
2961
2962 /*
2963 * Tell host that VBVA status is changed.
2964 */
2965 VMMDevVideoAccelEnable *req = NULL;
2966
2967 rc = VbglGRAlloc ((VMMDevRequestHeader **)&req,
2968 sizeof (VMMDevVideoAccelEnable),
2969 VMMDevReq_VideoAccelEnable);
2970
2971 if (RT_SUCCESS(rc))
2972 {
2973 req->u32Enable = ulEnable;
2974 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
2975 req->fu32Status = 0;
2976
2977 rc = VbglGRPerform (&req->header);
2978
2979 if (RT_SUCCESS(rc))
2980 {
2981 if (req->fu32Status & VBVA_F_STATUS_ACCEPTED)
2982 {
2983 /*
2984 * Initialize the result information and VBVA memory.
2985 */
2986 if (req->fu32Status & VBVA_F_STATUS_ENABLED)
2987 {
2988 pVbvaResult->pVbvaMemory = &pVMMDevMemory->vbvaMemory;
2989 pVbvaResult->pfnFlush = vboxVbvaFlush;
2990 pVbvaResult->pvFlush = pDevExt;
2991 ulEnabled = 1;
2992 }
2993 else
2994 {
2995 VBoxVideoCmnMemZero(&pVbvaResult, sizeof(VBVAENABLERESULT));
2996 }
2997
2998 dprintf(("VBoxVideo::vboxVbvaEnable: success.\n"));
2999 }
3000 else
3001 {
3002 dprintf(("VBoxVideo::vboxVbvaEnable: not accepted.\n"));
3003
3004 /* Disable VBVA for old hosts. */
3005 req->u32Enable = 0;
3006 req->cbRingBuffer = VBVA_RING_BUFFER_SIZE;
3007 req->fu32Status = 0;
3008
3009 VbglGRPerform (&req->header);
3010
3011 rc = VERR_NOT_SUPPORTED;
3012 }
3013 }
3014 else
3015 {
3016 dprintf(("VBoxVideo::vboxVbvaEnable: rc = %Rrc!\n", rc));
3017 }
3018
3019 VbglGRFree (&req->header);
3020 }
3021 else
3022 {
3023 dprintf(("VBoxVideo::vboxVbvaEnable: VbglGRAlloc rc = %Rrc!\n", rc));
3024 }
3025
3026 pDevExt->pPrimary->u.primary.ulVbvaEnabled = ulEnabled;
3027 }
3028
3029 return rc;
3030}
3031#endif
Note: See TracBrowser for help on using the repository browser.

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