VirtualBox

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

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

wddm: VidPn fixes

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

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