VirtualBox

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

Last change on this file since 33628 was 33628, checked in by vboxsync, 14 years ago

Additions/WINNT/Graphics: more refactoring

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