VirtualBox

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

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

Additions/WINNT/Graphics: more refactoring and disabling of some unused code

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