VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/mp/common/VBoxMPVidModes.cpp@ 76553

Last change on this file since 76553 was 76553, checked in by vboxsync, 5 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.7 KB
Line 
1/* $Id: VBoxMPVidModes.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox Miniport video modes related functions
4 */
5
6/*
7 * Copyright (C) 2011-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "VBoxMPCommon.h"
19
20#if _MSC_VER >= 1400 /* bird: MS fixed swprintf to be standard-conforming... */
21#define _INC_SWPRINTF_INL_
22extern "C" int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
23#endif
24#include <wchar.h>
25#include <VBoxVideoVBE.h>
26
27#ifdef VBOX_WITH_WDDM
28# define VBOX_WITHOUT_24BPP_MODES
29#endif
30
31/* Custom video modes which are being read from registry at driver startup. */
32static VIDEO_MODE_INFORMATION g_CustomVideoModes[VBOX_VIDEO_MAX_SCREENS] = { 0 };
33
34static BOOLEAN
35VBoxMPValidateVideoModeParamsGuest(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t xres, uint32_t yres, uint32_t bpp)
36{
37 RT_NOREF(iDisplay, xres, yres);
38
39 switch (bpp)
40 {
41 case 32:
42 break;
43 case 24:
44#ifdef VBOX_WITHOUT_24BPP_MODES
45 return FALSE;
46#else
47 break;
48#endif
49 case 16:
50 break;
51 case 8:
52#ifndef VBOX_WITH_8BPP_MODES
53 return FALSE;
54#else
55#ifdef VBOX_XPDM_MINIPORT
56 if (pExt->iDevice != 0) /* Secondary monitors do not support 8 bit */
57 return FALSE;
58#endif
59 break;
60#endif
61 default:
62 WARN(("Unexpected bpp (%d)", bpp));
63 return FALSE;
64 }
65 return TRUE;
66}
67
68/* Fills given video mode BPP related fields */
69static void
70VBoxFillVidModeBPP(VIDEO_MODE_INFORMATION *pMode, ULONG bitsR, ULONG bitsG, ULONG bitsB,
71 ULONG maskR, ULONG maskG, ULONG maskB)
72{
73 pMode->NumberRedBits = bitsR;
74 pMode->NumberGreenBits = bitsG;
75 pMode->NumberBlueBits = bitsB;
76 pMode->RedMask = maskR;
77 pMode->GreenMask = maskG;
78 pMode->BlueMask = maskB;
79}
80
81/* Fills given video mode structure */
82static void
83VBoxFillVidModeInfo(VIDEO_MODE_INFORMATION *pMode, ULONG xres, ULONG yres, ULONG bpp, ULONG index, ULONG yoffset)
84{
85 LOGF(("%dx%d:%d (idx=%d, yoffset=%d)", xres, yres, bpp, index, yoffset));
86
87 memset(pMode, 0, sizeof(VIDEO_MODE_INFORMATION));
88
89 /*Common entries*/
90 pMode->Length = sizeof(VIDEO_MODE_INFORMATION);
91 pMode->ModeIndex = index;
92 pMode->VisScreenWidth = xres;
93 pMode->VisScreenHeight = yres - yoffset;
94 pMode->ScreenStride = xres * ((bpp + 7) / 8);
95 pMode->NumberOfPlanes = 1;
96 pMode->BitsPerPlane = bpp;
97 pMode->Frequency = 60;
98 pMode->XMillimeter = 320;
99 pMode->YMillimeter = 240;
100 pMode->VideoMemoryBitmapWidth = xres;
101 pMode->VideoMemoryBitmapHeight = yres - yoffset;
102 pMode->DriverSpecificAttributeFlags = 0;
103 pMode->AttributeFlags = VIDEO_MODE_GRAPHICS | VIDEO_MODE_COLOR | VIDEO_MODE_NO_OFF_SCREEN;
104
105 /*BPP related entries*/
106 switch (bpp)
107 {
108#ifdef VBOX_WITH_8BPP_MODES
109 case 8:
110 VBoxFillVidModeBPP(pMode, 6, 6, 6, 0, 0, 0);
111
112 pMode->AttributeFlags |= VIDEO_MODE_PALETTE_DRIVEN | VIDEO_MODE_MANAGED_PALETTE;
113 break;
114#endif
115 case 16:
116 VBoxFillVidModeBPP(pMode, 5, 6, 5, 0xF800, 0x7E0, 0x1F);
117 break;
118 case 24:
119 case 32:
120 VBoxFillVidModeBPP(pMode, 8, 8, 8, 0xFF0000, 0xFF00, 0xFF);
121 break;
122 default:
123 Assert(0);
124 break;
125 }
126}
127
128void VBoxMPCmnInitCustomVideoModes(PVBOXMP_DEVEXT pExt)
129{
130 VBOXMPCMNREGISTRY Registry;
131 VP_STATUS rc;
132 int iMode;
133
134 LOGF_ENTER();
135
136 rc = VBoxMPCmnRegInit(pExt, &Registry);
137 VBOXMP_WARN_VPS(rc);
138
139 /* Initialize all custom modes to the 800x600x32 */
140 VBoxFillVidModeInfo(&g_CustomVideoModes[0], 800, 600, 32, 0, 0);
141 for (iMode=1; iMode<RT_ELEMENTS(g_CustomVideoModes); ++iMode)
142 {
143 g_CustomVideoModes[iMode] = g_CustomVideoModes[0];
144 }
145
146 /* Read stored custom resolution info from registry */
147 for (iMode=0; iMode<VBoxCommonFromDeviceExt(pExt)->cDisplays; ++iMode)
148 {
149 uint32_t CustomXRes = 0, CustomYRes = 0, CustomBPP = 0;
150
151 if (iMode==0)
152 {
153 /*First name without a suffix*/
154 rc = VBoxMPCmnRegQueryDword(Registry, L"CustomXRes", &CustomXRes);
155 VBOXMP_WARN_VPS_NOBP(rc);
156 rc = VBoxMPCmnRegQueryDword(Registry, L"CustomYRes", &CustomYRes);
157 VBOXMP_WARN_VPS_NOBP(rc);
158 rc = VBoxMPCmnRegQueryDword(Registry, L"CustomBPP", &CustomBPP);
159 VBOXMP_WARN_VPS_NOBP(rc);
160 }
161 else
162 {
163 wchar_t keyname[32];
164 swprintf(keyname, L"CustomXRes%d", iMode);
165 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomXRes);
166 VBOXMP_WARN_VPS_NOBP(rc);
167 swprintf(keyname, L"CustomYRes%d", iMode);
168 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomYRes);
169 VBOXMP_WARN_VPS_NOBP(rc);
170 swprintf(keyname, L"CustomBPP%d", iMode);
171 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &CustomBPP);
172 VBOXMP_WARN_VPS_NOBP(rc);
173 }
174
175 LOG(("got stored custom resolution[%d] %dx%dx%d", iMode, CustomXRes, CustomYRes, CustomBPP));
176
177 if (CustomXRes || CustomYRes || CustomBPP)
178 {
179 if (CustomXRes == 0)
180 {
181 CustomXRes = g_CustomVideoModes[iMode].VisScreenWidth;
182 }
183 if (CustomYRes == 0)
184 {
185 CustomYRes = g_CustomVideoModes[iMode].VisScreenHeight;
186 }
187 if (CustomBPP == 0)
188 {
189 CustomBPP = g_CustomVideoModes[iMode].BitsPerPlane;
190 }
191
192 if (VBoxMPValidateVideoModeParamsGuest(pExt, iMode, CustomXRes, CustomYRes, CustomBPP))
193 {
194 VBoxFillVidModeInfo(&g_CustomVideoModes[iMode], CustomXRes, CustomYRes, CustomBPP, 0, 0);
195 }
196 }
197 }
198
199 rc = VBoxMPCmnRegFini(Registry);
200 VBOXMP_WARN_VPS(rc);
201 LOGF_LEAVE();
202}
203
204VIDEO_MODE_INFORMATION *VBoxMPCmnGetCustomVideoModeInfo(ULONG ulIndex)
205{
206 return (ulIndex<RT_ELEMENTS(g_CustomVideoModes)) ? &g_CustomVideoModes[ulIndex] : NULL;
207}
208
209#ifdef VBOX_XPDM_MINIPORT
210VIDEO_MODE_INFORMATION* VBoxMPCmnGetVideoModeInfo(PVBOXMP_DEVEXT pExt, ULONG ulIndex)
211{
212 return (ulIndex<RT_ELEMENTS(pExt->aVideoModes)) ? &pExt->aVideoModes[ulIndex] : NULL;
213}
214#endif
215
216static bool VBoxMPVideoModesMatch(const PVIDEO_MODE_INFORMATION pMode1, const PVIDEO_MODE_INFORMATION pMode2)
217{
218 return pMode1->VisScreenHeight == pMode2->VisScreenHeight
219 && pMode1->VisScreenWidth == pMode2->VisScreenWidth
220 && pMode1->BitsPerPlane == pMode2->BitsPerPlane;
221}
222
223static int
224VBoxMPFindVideoMode(const PVIDEO_MODE_INFORMATION pModesTable, int cModes, const PVIDEO_MODE_INFORMATION pMode)
225{
226 for (int i = 0; i < cModes; ++i)
227 {
228 if (VBoxMPVideoModesMatch(pMode, &pModesTable[i]))
229 {
230 return i;
231 }
232 }
233 return -1;
234}
235
236/* Helper function to dynamically build our table of standard video
237 * modes. We take the amount of VRAM and create modes with standard
238 * geometries until we've either reached the maximum number of modes
239 * or the available VRAM does not allow for additional modes.
240 * We also check registry for manually added video modes.
241 * Returns number of modes added to the table.
242 */
243static uint32_t
244VBoxMPFillModesTable(PVBOXMP_DEVEXT pExt, int iDisplay, PVIDEO_MODE_INFORMATION pModesTable, size_t tableSize,
245 int32_t *pPrefModeIdx)
246{
247 /* the resolution matrix */
248 struct
249 {
250 uint16_t xRes;
251 uint16_t yRes;
252 } resolutionMatrix[] =
253 {
254 /* standard modes */
255 { 640, 480 },
256 { 800, 600 },
257 { 1024, 768 },
258 { 1152, 864 },
259 { 1280, 960 },
260 { 1280, 1024 },
261 { 1400, 1050 },
262 { 1600, 1200 },
263 { 1920, 1440 },
264#ifndef VBOX_WITH_WDDM
265 /* multi screen modes with 1280x1024 */
266 { 2560, 1024 },
267 { 3840, 1024 },
268 { 5120, 1024 },
269 /* multi screen modes with 1600x1200 */
270 { 3200, 1200 },
271 { 4800, 1200 },
272 { 6400, 1200 },
273#endif
274 };
275
276#ifdef VBOX_XPDM_MINIPORT
277 ULONG vramSize = pExt->pPrimary->u.primary.ulMaxFrameBufferSize;
278#else
279 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt);
280 vramSize /= pExt->u.primary.commonInfo.cDisplays;
281 if (!g_VBoxDisplayOnly)
282 {
283 /* at least two surfaces will be needed: primary & shadow */
284 vramSize /= 2;
285 }
286 vramSize &= ~PAGE_OFFSET_MASK;
287#endif
288
289 uint32_t iMode=0, iPrefIdx=0;
290 /* there are 4 color depths: 8, 16, 24 and 32bpp and we reserve 50% of the modes for other sources */
291 size_t maxModesPerColorDepth = VBOXMP_MAX_VIDEO_MODES / 2 / 4;
292
293 /* Always add 800x600 video modes. Windows XP+ needs at least 800x600 resolution
294 * and fallbacks to 800x600x4bpp VGA mode if the driver did not report suitable modes.
295 * This resolution could be rejected by a low resolution host (netbooks, etc).
296 */
297#ifdef VBOX_WITH_8BPP_MODES
298 int bytesPerPixel=1;
299#else
300 int bytesPerPixel=2;
301#endif
302 for (; bytesPerPixel<=4; bytesPerPixel++)
303 {
304 int bitsPerPixel = 8*bytesPerPixel;
305
306 if (800*600*bytesPerPixel > (LONG)vramSize)
307 {
308 /* we don't have enough VRAM for this mode */
309 continue;
310 }
311
312 if (!VBoxMPValidateVideoModeParamsGuest(pExt, iMode, 800, 600, bitsPerPixel))
313 continue;
314
315 VBoxFillVidModeInfo(&pModesTable[iMode], 800, 600, bitsPerPixel, iMode+1, 0);
316
317 if (32==bitsPerPixel)
318 {
319 iPrefIdx = iMode;
320 }
321 ++iMode;
322 }
323
324 /* Query yoffset from the host */
325 ULONG yOffset = VBoxGetHeightReduction();
326
327 /* Iterate through our static resolution table and add supported video modes for different bpp's */
328#ifdef VBOX_WITH_8BPP_MODES
329 bytesPerPixel=1;
330#else
331 bytesPerPixel=2;
332#endif
333 for (; bytesPerPixel<=4; bytesPerPixel++)
334 {
335 int bitsPerPixel = 8*bytesPerPixel;
336 size_t cAdded, resIndex;
337
338 for (cAdded=0, resIndex=0; resIndex<RT_ELEMENTS(resolutionMatrix) && cAdded<maxModesPerColorDepth; resIndex++)
339 {
340 if (resolutionMatrix[resIndex].xRes * resolutionMatrix[resIndex].yRes * bytesPerPixel > (LONG)vramSize)
341 {
342 /* we don't have enough VRAM for this mode */
343 continue;
344 }
345
346 if (yOffset == 0 && resolutionMatrix[resIndex].xRes == 800 && resolutionMatrix[resIndex].yRes == 600)
347 {
348 /* this mode was already added */
349 continue;
350 }
351
352 if (
353#ifdef VBOX_WDDM_MINIPORT
354 /* 1024x768 resolution is a minimal resolutions for win8 to make most metro apps run.
355 * For small host display resolutions, host will dislike the mode 1024x768 and above
356 * if the framebuffer window requires scrolling to fit the guest resolution.
357 * So add 1024x768 resolution for win8 guest to allow user switch to it */
358 ( (VBoxQueryWinVersion(NULL) != WIN8 && VBoxQueryWinVersion(NULL) != WIN81)
359 || resolutionMatrix[resIndex].xRes != 1024
360 || resolutionMatrix[resIndex].yRes != 768)
361 &&
362#endif
363 !VBoxLikesVideoMode(iDisplay, resolutionMatrix[resIndex].xRes,
364 resolutionMatrix[resIndex].yRes - yOffset, bitsPerPixel))
365 {
366 /* host doesn't like this mode */
367 continue;
368 }
369
370 if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel))
371 {
372 /* guest does not like this mode */
373 continue;
374 }
375
376 /* Sanity check, we shouldn't ever get here */
377 if (iMode >= tableSize)
378 {
379 WARN(("video modes table overflow!"));
380 break;
381 }
382
383 VBoxFillVidModeInfo(&pModesTable[iMode], resolutionMatrix[resIndex].xRes, resolutionMatrix[resIndex].yRes, bitsPerPixel, iMode+1, yOffset);
384 ++iMode;
385 ++cAdded;
386 }
387 }
388
389 /* Check registry for manually added modes, up to 128 entries is supported
390 * Give up on the first error encountered.
391 */
392 VBOXMPCMNREGISTRY Registry;
393 int fPrefSet=0;
394 VP_STATUS rc;
395
396 rc = VBoxMPCmnRegInit(pExt, &Registry);
397 VBOXMP_WARN_VPS(rc);
398
399 for (int curKey=0; curKey<128; curKey++)
400 {
401 if (iMode>=tableSize)
402 {
403 WARN(("ignoring possible custom mode(s), table is full!"));
404 break;
405 }
406
407 wchar_t keyname[24];
408 uint32_t xres, yres, bpp = 0;
409
410 swprintf(keyname, L"CustomMode%dWidth", curKey);
411 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &xres);
412 VBOXMP_CHECK_VPS_BREAK(rc);
413
414 swprintf(keyname, L"CustomMode%dHeight", curKey);
415 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &yres);
416 VBOXMP_CHECK_VPS_BREAK(rc);
417
418 swprintf(keyname, L"CustomMode%dBPP", curKey);
419 rc = VBoxMPCmnRegQueryDword(Registry, keyname, &bpp);
420 VBOXMP_CHECK_VPS_BREAK(rc);
421
422 LOG(("got custom mode[%u]=%ux%u:%u", curKey, xres, yres, bpp));
423
424 /* round down width to be a multiple of 8 if necessary */
425 if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
426 {
427 xres &= 0xFFF8;
428 }
429
430 if ( (xres > (1 << 16))
431 || (yres > (1 << 16))
432 || ( (bpp != 16)
433 && (bpp != 24)
434 && (bpp != 32)))
435 {
436 /* incorrect values */
437 break;
438 }
439
440 /* does it fit within our VRAM? */
441 if (xres * yres * (bpp / 8) > vramSize)
442 {
443 /* we don't have enough VRAM for this mode */
444 break;
445 }
446
447 if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp))
448 {
449 /* host doesn't like this mode */
450 break;
451 }
452
453 if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp))
454 {
455 /* guest does not like this mode */
456 continue;
457 }
458
459 LOG(("adding video mode from registry."));
460
461 VBoxFillVidModeInfo(&pModesTable[iMode], xres, yres, bpp, iMode+1, yOffset);
462
463 if (!fPrefSet)
464 {
465 fPrefSet = 1;
466 iPrefIdx = iMode;
467 }
468#ifdef VBOX_WDDM_MINIPORT
469 /*check if the same mode has been added to the table already*/
470 int foundIdx = VBoxMPFindVideoMode(pModesTable, iMode, &pModesTable[iMode]);
471
472 if (foundIdx>=0)
473 {
474 if (iPrefIdx==iMode)
475 {
476 iPrefIdx=foundIdx;
477 }
478 }
479 else
480#endif
481 {
482 ++iMode;
483 }
484 }
485
486 rc = VBoxMPCmnRegFini(Registry);
487 VBOXMP_WARN_VPS(rc);
488
489 if (pPrefModeIdx)
490 {
491 *pPrefModeIdx = iPrefIdx;
492 }
493
494 return iMode;
495}
496
497/* Returns if we're in the first mode change, ie doesn't have valid video mode set yet */
498static BOOLEAN VBoxMPIsStartingUp(PVBOXMP_DEVEXT pExt, uint32_t iDisplay)
499{
500#ifdef VBOX_XPDM_MINIPORT
501 RT_NOREF(iDisplay);
502 return (pExt->CurrentMode == 0);
503#else
504 VBOXWDDM_SOURCE *pSource = &pExt->aSources[iDisplay];
505 return !pSource->AllocData.SurfDesc.width || !pSource->AllocData.SurfDesc.height;
506#endif
507}
508
509#ifdef VBOX_WDDM_MINIPORT
510static const uint32_t g_aVBoxVidModesSupportedBpps[] = {
511 32
512#ifndef VBOX_WITHOUT_24BPP_MODES
513 , 24
514#endif
515 , 16
516#ifdef VBOX_WITH_8BPP_MODES
517 , 8
518#endif
519};
520DECLINLINE(BOOLEAN) VBoxMPIsSupportedBpp(uint32_t bpp)
521{
522 for (int i = 0; i < RT_ELEMENTS(g_aVBoxVidModesSupportedBpps); ++i)
523 {
524 if (bpp == g_aVBoxVidModesSupportedBpps[i])
525 return TRUE;
526 }
527 return FALSE;
528}
529
530DECLINLINE(uint32_t) VBoxMPAdjustBpp(uint32_t bpp)
531{
532 if (VBoxMPIsSupportedBpp(bpp))
533 return bpp;
534 Assert(g_aVBoxVidModesSupportedBpps[0] == 32);
535 return g_aVBoxVidModesSupportedBpps[0];
536}
537#endif
538/* Updates missing video mode params with current values,
539 * Checks if resulting mode is liked by the host and fits into VRAM.
540 * Returns TRUE if resulting mode could be used.
541 */
542static BOOLEAN
543VBoxMPValidateVideoModeParams(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, uint32_t &xres, uint32_t &yres, uint32_t &bpp)
544{
545 /* Make sure all important video mode values are set */
546 if (VBoxMPIsStartingUp(pExt, iDisplay))
547 {
548 /* Use stored custom values only if nothing was read from host. */
549 xres = xres ? xres:g_CustomVideoModes[iDisplay].VisScreenWidth;
550 yres = yres ? yres:g_CustomVideoModes[iDisplay].VisScreenHeight;
551 bpp = bpp ? bpp :g_CustomVideoModes[iDisplay].BitsPerPlane;
552 }
553 else
554 {
555 /* Use current values for field which weren't read from host. */
556#ifdef VBOX_XPDM_MINIPORT
557 xres = xres ? xres:pExt->CurrentModeWidth;
558 yres = yres ? yres:pExt->CurrentModeHeight;
559 bpp = bpp ? bpp :pExt->CurrentModeBPP;
560#else
561 PVBOXWDDM_ALLOC_DATA pAllocData = pExt->aSources[iDisplay].pPrimaryAllocation ?
562 &pExt->aSources[iDisplay].pPrimaryAllocation->AllocData
563 : &pExt->aSources[iDisplay].AllocData;
564 xres = xres ? xres:pAllocData->SurfDesc.width;
565 yres = yres ? yres:pAllocData->SurfDesc.height;
566 /* VBox WDDM driver does not allow 24 modes since OS could choose the 24bit mode as default in that case,
567 * the pExt->aSources[iDisplay].AllocData.SurfDesc.bpp could be initially 24 though,
568 * i.e. when driver occurs the current mode on driver load via DxgkCbAcquirePostDisplayOwnership
569 * and until driver reports the supported modes
570 * This is true for Win8 Display-Only driver currently since DxgkCbAcquirePostDisplayOwnership is only used by it
571 *
572 * This is why we need to adjust the current mode bpp to the value we actually report as supported */
573 bpp = bpp ? bpp : VBoxMPAdjustBpp(pAllocData->SurfDesc.bpp);
574#endif
575 }
576
577 /* Round down width to be a multiple of 8 if necessary */
578 if (!VBoxCommonFromDeviceExt(pExt)->fAnyX)
579 {
580 xres &= 0xFFF8;
581 }
582
583 /* We always need bpp to be set */
584 if (!bpp)
585 {
586 bpp=32;
587 }
588
589 if (!VBoxMPValidateVideoModeParamsGuest(pExt, iDisplay, xres, yres, bpp))
590 {
591 WARN(("GUEST does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay));
592 return FALSE;
593 }
594
595 /* Check if host likes this mode */
596 if (!VBoxLikesVideoMode(iDisplay, xres, yres, bpp))
597 {
598 WARN_NOBP(("HOST does not like special mode %dx%d:%d for display %d", xres, yres, bpp, iDisplay));
599 return FALSE;
600 }
601
602#ifdef VBOX_XPDM_MINIPORT
603 ULONG vramSize = pExt->pPrimary->u.primary.ulMaxFrameBufferSize;
604#else
605 ULONG vramSize = vboxWddmVramCpuVisibleSegmentSize(pExt);
606 vramSize /= pExt->u.primary.commonInfo.cDisplays;
607 if (!g_VBoxDisplayOnly)
608 {
609 /* at least two surfaces will be needed: primary & shadow */
610 vramSize /= 2;
611 }
612 vramSize &= ~PAGE_OFFSET_MASK;
613#endif
614
615 /* Check that values are valid and mode fits into VRAM */
616 if (!xres || !yres
617 || !((bpp == 16)
618#ifdef VBOX_WITH_8BPP_MODES
619 || (bpp == 8)
620#endif
621 || (bpp == 24)
622 || (bpp == 32)))
623 {
624 LOG(("invalid params for special mode %dx%d:%d", xres, yres, bpp));
625 return FALSE;
626 }
627
628
629
630 if ((xres * yres * (bpp / 8) >= vramSize))
631 {
632 /* Store values of last reported release log message to avoid log flooding. */
633 static uint32_t s_xresNoVRAM=0, s_yresNoVRAM=0, s_bppNoVRAM=0;
634
635 LOG(("not enough VRAM for video mode %dx%dx%dbpp. Available: %d bytes. Required: more than %d bytes.",
636 xres, yres, bpp, vramSize, xres * yres * (bpp / 8)));
637
638 s_xresNoVRAM = xres;
639 s_yresNoVRAM = yres;
640 s_bppNoVRAM = bpp;
641
642 return FALSE;
643 }
644
645 return TRUE;
646}
647
648/* Checks if there's a pending video mode change hint,
649 * and fills pPendingMode with associated info.
650 * returns TRUE if there's a pending change. Otherwise returns FALSE.
651 */
652static BOOLEAN
653VBoxMPCheckPendingVideoMode(PVBOXMP_DEVEXT pExt, PVIDEO_MODE_INFORMATION pPendingMode)
654{
655 uint32_t xres=0, yres=0, bpp=0, display=0;
656
657 /* Check if there's a pending display change request for this display */
658 if (VBoxQueryDisplayRequest(&xres, &yres, &bpp, &display) && (xres || yres || bpp))
659 {
660 if (display >= RT_ELEMENTS(g_CustomVideoModes))
661 {
662 /*display = RT_ELEMENTS(g_CustomVideoModes) - 1;*/
663 WARN(("VBoxQueryDisplayRequest returned invalid display number %d", display));
664 return FALSE;
665 }
666 }
667 else
668 {
669 LOG(("no pending request"));
670 return FALSE;
671 }
672
673 /* Correct video mode params and check if host likes it */
674 if (VBoxMPValidateVideoModeParams(pExt, display, xres, yres, bpp))
675 {
676 VBoxFillVidModeInfo(pPendingMode, xres, yres, bpp, display, 0);
677 return TRUE;
678 }
679
680 return FALSE;
681}
682
683/* Save custom mode info to registry */
684static void VBoxMPRegSaveModeInfo(PVBOXMP_DEVEXT pExt, uint32_t iDisplay, PVIDEO_MODE_INFORMATION pMode)
685{
686 VBOXMPCMNREGISTRY Registry;
687 VP_STATUS rc;
688
689 rc = VBoxMPCmnRegInit(pExt, &Registry);
690 VBOXMP_WARN_VPS(rc);
691
692 if (iDisplay==0)
693 {
694 /*First name without a suffix*/
695 rc = VBoxMPCmnRegSetDword(Registry, L"CustomXRes", pMode->VisScreenWidth);
696 VBOXMP_WARN_VPS(rc);
697 rc = VBoxMPCmnRegSetDword(Registry, L"CustomYRes", pMode->VisScreenHeight);
698 VBOXMP_WARN_VPS(rc);
699 rc = VBoxMPCmnRegSetDword(Registry, L"CustomBPP", pMode->BitsPerPlane);
700 VBOXMP_WARN_VPS(rc);
701 }
702 else
703 {
704 wchar_t keyname[32];
705 swprintf(keyname, L"CustomXRes%d", iDisplay);
706 rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->VisScreenWidth);
707 VBOXMP_WARN_VPS(rc);
708 swprintf(keyname, L"CustomYRes%d", iDisplay);
709 rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->VisScreenHeight);
710 VBOXMP_WARN_VPS(rc);
711 swprintf(keyname, L"CustomBPP%d", iDisplay);
712 rc = VBoxMPCmnRegSetDword(Registry, keyname, pMode->BitsPerPlane);
713 VBOXMP_WARN_VPS(rc);
714 }
715
716 rc = VBoxMPCmnRegFini(Registry);
717 VBOXMP_WARN_VPS(rc);
718}
719
720#ifdef VBOX_XPDM_MINIPORT
721VIDEO_MODE_INFORMATION* VBoxMPXpdmCurrentVideoMode(PVBOXMP_DEVEXT pExt)
722{
723 return VBoxMPCmnGetVideoModeInfo(pExt, pExt->CurrentMode - 1);
724}
725
726ULONG VBoxMPXpdmGetVideoModesCount(PVBOXMP_DEVEXT pExt)
727{
728 return pExt->cVideoModes;
729}
730
731/* Makes a table of video modes consisting of:
732 * Default modes
733 * Custom modes manually added to registry
734 * Custom modes for all displays (either from a display change hint or stored in registry)
735 * 2 special modes, for a pending display change for this adapter. See comments below.
736 */
737void VBoxMPXpdmBuildVideoModesTable(PVBOXMP_DEVEXT pExt)
738{
739 uint32_t cStandartModes;
740 BOOLEAN bPending, bHaveSpecial;
741 VIDEO_MODE_INFORMATION specialMode;
742
743 /* Fill table with standart modes and ones manually added to registry.
744 * Up to VBOXMP_MAX_VIDEO_MODES elements can be used, the rest is reserved
745 * for custom mode alternating indexes.
746 */
747 cStandartModes = VBoxMPFillModesTable(pExt, pExt->iDevice, pExt->aVideoModes, VBOXMP_MAX_VIDEO_MODES, NULL);
748
749 /* Add custom mode for this display to the table */
750 /* Make 2 entries in the video mode table. */
751 uint32_t iModeBase = cStandartModes;
752
753 /* Take the alternating index into account. */
754 BOOLEAN bAlternativeIndex = (pExt->iInvocationCounter % 2)? TRUE: FALSE;
755
756 uint32_t iSpecialMode = iModeBase + (bAlternativeIndex? 1: 0);
757 uint32_t iStandardMode = iModeBase + (bAlternativeIndex? 0: 1);
758
759 /* Fill the special mode. */
760 memcpy(&pExt->aVideoModes[iSpecialMode], &g_CustomVideoModes[pExt->iDevice], sizeof(VIDEO_MODE_INFORMATION));
761 pExt->aVideoModes[iSpecialMode].ModeIndex = iSpecialMode + 1;
762
763 /* Wipe the other entry so it is not selected. */
764 memcpy(&pExt->aVideoModes[iStandardMode], &pExt->aVideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
765 pExt->aVideoModes[iStandardMode].ModeIndex = iStandardMode + 1;
766
767 LOG(("added special mode[%d] %dx%d:%d for display %d\n",
768 iSpecialMode,
769 pExt->aVideoModes[iSpecialMode].VisScreenWidth,
770 pExt->aVideoModes[iSpecialMode].VisScreenHeight,
771 pExt->aVideoModes[iSpecialMode].BitsPerPlane,
772 pExt->iDevice));
773
774 /* Check if host wants us to switch video mode and it's for this adapter */
775 bPending = VBoxMPCheckPendingVideoMode(pExt, &specialMode);
776 bHaveSpecial = bPending && (pExt->iDevice == specialMode.ModeIndex);
777 LOG(("bPending %d, pExt->iDevice %d, specialMode.ModeIndex %d",
778 bPending, pExt->iDevice, specialMode.ModeIndex));
779
780 /* Check the startup case */
781 if (!bHaveSpecial && VBoxMPIsStartingUp(pExt, pExt->iDevice))
782 {
783 uint32_t xres=0, yres=0, bpp=0;
784 LOG(("Startup for screen %d", pExt->iDevice));
785 /* Check if we could make valid mode from values stored to registry */
786 if (VBoxMPValidateVideoModeParams(pExt, pExt->iDevice, xres, yres, bpp))
787 {
788 LOG(("Startup for screen %d validated %dx%d %d", pExt->iDevice, xres, yres, bpp));
789 VBoxFillVidModeInfo(&specialMode, xres, yres, bpp, 0, 0);
790 bHaveSpecial = TRUE;
791 }
792 }
793
794 /* Update number of modes. Each display has 2 entries for alternating custom mode index. */
795 pExt->cVideoModes = cStandartModes + 2;
796
797 if (bHaveSpecial)
798 {
799 /* We need to alternate mode index entry for a pending mode change,
800 * else windows will ignore actual mode change call.
801 * Only alternate index if one of mode parameters changed and
802 * regardless of conditions always add 2 entries to the table.
803 */
804 BOOLEAN bAlternativeIndex = FALSE;
805
806 BOOLEAN bChanged = (pExt->Prev_xres!=specialMode.VisScreenWidth
807 || pExt->Prev_yres!=specialMode.VisScreenHeight
808 || pExt->Prev_bpp!=specialMode.BitsPerPlane);
809
810 LOG(("prev %dx%dx%d, special %dx%dx%d",
811 pExt->Prev_xres, pExt->Prev_yres, pExt->Prev_bpp,
812 specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane));
813
814 if (bChanged)
815 {
816 pExt->Prev_xres = specialMode.VisScreenWidth;
817 pExt->Prev_yres = specialMode.VisScreenHeight;
818 pExt->Prev_bpp = specialMode.BitsPerPlane;
819 }
820
821 /* Check if we need to alternate the index */
822 if (!VBoxMPIsStartingUp(pExt, pExt->iDevice))
823 {
824 if (bChanged)
825 {
826 pExt->iInvocationCounter++;
827 }
828
829 if (pExt->iInvocationCounter % 2)
830 {
831 bAlternativeIndex = TRUE;
832 }
833 }
834
835 uint32_t iSpecialModeElement = cStandartModes + (bAlternativeIndex? 1: 0);
836 uint32_t iSpecialModeElementOld = cStandartModes + (bAlternativeIndex? 0: 1);
837
838 LOG(("add special mode[%d] %dx%d:%d for display %d (bChanged=%d, bAlternativeIndex=%d)",
839 iSpecialModeElement, specialMode.VisScreenWidth, specialMode.VisScreenHeight, specialMode.BitsPerPlane,
840 pExt->iDevice, bChanged, bAlternativeIndex));
841
842 /* Add special mode to the table
843 * Note: Y offset isn't used for a host-supplied modes
844 */
845 specialMode.ModeIndex = iSpecialModeElement + 1;
846 memcpy(&pExt->aVideoModes[iSpecialModeElement], &specialMode, sizeof(VIDEO_MODE_INFORMATION));
847
848 /* Save special mode in the custom modes table */
849 memcpy(&g_CustomVideoModes[pExt->iDevice], &specialMode, sizeof(VIDEO_MODE_INFORMATION));
850
851 /* Wipe the old entry so the special mode will be found in the new positions. */
852 memcpy(&pExt->aVideoModes[iSpecialModeElementOld], &pExt->aVideoModes[3], sizeof(VIDEO_MODE_INFORMATION));
853 pExt->aVideoModes[iSpecialModeElementOld].ModeIndex = iSpecialModeElementOld + 1;
854
855 /* Save special mode info to registry */
856 VBoxMPRegSaveModeInfo(pExt, pExt->iDevice, &specialMode);
857 }
858
859#if defined(LOG_ENABLED)
860 do
861 {
862 LOG(("Filled %d modes for display %d", pExt->cVideoModes, pExt->iDevice));
863
864 for (uint32_t i=0; i < pExt->cVideoModes; ++i)
865 {
866 LOG(("Mode[%2d]: %4dx%4d:%2d (idx=%d)",
867 i, pExt->aVideoModes[i].VisScreenWidth, pExt->aVideoModes[i].VisScreenHeight,
868 pExt->aVideoModes[i].BitsPerPlane, pExt->aVideoModes[i].ModeIndex));
869 }
870 } while (0);
871#endif
872}
873#endif /*VBOX_XPDM_MINIPORT*/
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use