VirtualBox

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

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

wddm: avoid DMA transactions on GDI rendering (for preformance)

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

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