VirtualBox

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

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

wddm: bugfix

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