VirtualBox

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

Last change on this file since 27984 was 27984, checked in by vboxsync, 15 years ago

wddm: more impl for autoresize support

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