VirtualBox

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

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

Add/NT/Graphics: VC++ 14.1 warnings. [build fix] bugref:8489

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