VirtualBox

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

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

wddm: more impl for guest autoresize support

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

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