VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispDriver.cpp@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/* $Id: VBoxDispDriver.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox XPDM Display driver interface functions
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "VBoxDisp.h"
29#include "VBoxDispMini.h"
30#include "VBoxDispDDraw.h"
31#include <iprt/initterm.h>
32
33/* Engine version we're running on, set in DrvEnableDriver */
34static ULONG g_EngineVersionDDI = DDI_DRIVER_VERSION_NT4;
35
36/* Callback function supported by our driver, stored in index/address pairs (see winddi.h) */
37/* NT4 version */
38static DRVFN g_aDrvFnTableNT4[] =
39{
40 /* Required functions */
41 {INDEX_DrvGetModes, (PFN) VBoxDispDrvGetModes },
42 {INDEX_DrvEnablePDEV, (PFN) VBoxDispDrvEnablePDEV },
43 {INDEX_DrvCompletePDEV, (PFN) VBoxDispDrvCompletePDEV },
44 {INDEX_DrvDisablePDEV, (PFN) VBoxDispDrvDisablePDEV },
45 {INDEX_DrvEnableSurface, (PFN) VBoxDispDrvEnableSurface },
46 {INDEX_DrvDisableSurface, (PFN) VBoxDispDrvDisableSurface },
47 {INDEX_DrvAssertMode, (PFN) VBoxDispDrvAssertMode },
48 /* Drawing commands */
49 {INDEX_DrvLineTo, (PFN) VBoxDispDrvLineTo },
50 {INDEX_DrvStrokePath, (PFN) VBoxDispDrvStrokePath },
51 {INDEX_DrvFillPath, (PFN) VBoxDispDrvFillPath },
52 {INDEX_DrvPaint, (PFN) VBoxDispDrvPaint },
53 {INDEX_DrvTextOut, (PFN) VBoxDispDrvTextOut },
54 {INDEX_DrvSaveScreenBits, (PFN) VBoxDispDrvSaveScreenBits },
55 /* BitBlt's*/
56 {INDEX_DrvBitBlt, (PFN) VBoxDispDrvBitBlt },
57 {INDEX_DrvStretchBlt, (PFN) VBoxDispDrvStretchBlt, },
58 {INDEX_DrvCopyBits, (PFN) VBoxDispDrvCopyBits },
59 /* Brush related */
60 {INDEX_DrvRealizeBrush, (PFN) VBoxDispDrvRealizeBrush },
61 {INDEX_DrvDitherColor, (PFN) VBoxDispDrvDitherColor },
62 /* Pointer related */
63 {INDEX_DrvSetPointerShape, (PFN) VBoxDispDrvSetPointerShape },
64 {INDEX_DrvMovePointer, (PFN) VBoxDispDrvMovePointer },
65 /* Misc */
66 {INDEX_DrvDisableDriver, (PFN) VBoxDispDrvDisableDriver },
67 {INDEX_DrvSetPalette, (PFN) VBoxDispDrvSetPalette },
68 {INDEX_DrvEscape, (PFN) VBoxDispDrvEscape },
69#ifdef VBOX_WITH_DDRAW
70 {INDEX_DrvGetDirectDrawInfo, (PFN) VBoxDispDrvGetDirectDrawInfo},
71 {INDEX_DrvEnableDirectDraw, (PFN) VBoxDispDrvEnableDirectDraw },
72 {INDEX_DrvDisableDirectDraw, (PFN) VBoxDispDrvDisableDirectDraw},
73#endif
74 /* g_aDrvFnTableNT4, NT4 specific */
75 {INDEX_DrvOffset, (PFN) VBoxDispDrvOffset } /*Obsolete*/
76};
77
78/* WIN2K+ version */
79static DRVFN g_aDrvFnTableNT5[] =
80{
81 /* Required functions */
82 {INDEX_DrvGetModes, (PFN) VBoxDispDrvGetModes },
83 {INDEX_DrvEnablePDEV, (PFN) VBoxDispDrvEnablePDEV },
84 {INDEX_DrvCompletePDEV, (PFN) VBoxDispDrvCompletePDEV },
85 {INDEX_DrvDisablePDEV, (PFN) VBoxDispDrvDisablePDEV },
86 {INDEX_DrvEnableSurface, (PFN) VBoxDispDrvEnableSurface },
87 {INDEX_DrvDisableSurface, (PFN) VBoxDispDrvDisableSurface },
88 {INDEX_DrvAssertMode, (PFN) VBoxDispDrvAssertMode },
89 /* Drawing commands */
90 {INDEX_DrvLineTo, (PFN) VBoxDispDrvLineTo },
91 {INDEX_DrvStrokePath, (PFN) VBoxDispDrvStrokePath },
92 {INDEX_DrvFillPath, (PFN) VBoxDispDrvFillPath },
93 {INDEX_DrvPaint, (PFN) VBoxDispDrvPaint },
94 {INDEX_DrvTextOut, (PFN) VBoxDispDrvTextOut },
95 {INDEX_DrvSaveScreenBits, (PFN) VBoxDispDrvSaveScreenBits },
96 /* BitBlt's*/
97 {INDEX_DrvBitBlt, (PFN) VBoxDispDrvBitBlt },
98 {INDEX_DrvStretchBlt, (PFN) VBoxDispDrvStretchBlt, },
99 {INDEX_DrvCopyBits, (PFN) VBoxDispDrvCopyBits },
100 /* Brush related */
101 {INDEX_DrvRealizeBrush, (PFN) VBoxDispDrvRealizeBrush },
102 {INDEX_DrvDitherColor, (PFN) VBoxDispDrvDitherColor },
103 /* Pointer related */
104 {INDEX_DrvSetPointerShape, (PFN) VBoxDispDrvSetPointerShape },
105 {INDEX_DrvMovePointer, (PFN) VBoxDispDrvMovePointer },
106 /* Misc */
107 {INDEX_DrvDisableDriver, (PFN) VBoxDispDrvDisableDriver },
108 {INDEX_DrvSetPalette, (PFN) VBoxDispDrvSetPalette },
109 {INDEX_DrvEscape, (PFN) VBoxDispDrvEscape },
110#ifdef VBOX_WITH_DDRAW
111 {INDEX_DrvGetDirectDrawInfo, (PFN) VBoxDispDrvGetDirectDrawInfo},
112 {INDEX_DrvEnableDirectDraw, (PFN) VBoxDispDrvEnableDirectDraw },
113 {INDEX_DrvDisableDirectDraw, (PFN) VBoxDispDrvDisableDirectDraw},
114#endif
115 /* g_aDrvFnTableNT5, NT5 specific */
116 {INDEX_DrvNotify, (PFN) VBoxDispDrvNotify },
117#ifdef VBOX_WITH_DDRAW
118 {INDEX_DrvDeriveSurface, (PFN) VBoxDispDrvDeriveSurface }
119#endif
120};
121
122RT_C_DECLS_BEGIN
123ULONG __cdecl DbgPrint(PCH pszFormat, ...)
124{
125 va_list args;
126 va_start(args, pszFormat);
127 RTLogBackdoorPrintfV(pszFormat, args);
128 va_end(args);
129
130 return 0;
131}
132RT_C_DECLS_END
133
134VOID _wcsncpy(WCHAR *pwcd, WCHAR *pwcs, ULONG dstsize)
135{
136 ULONG cnt=0;
137
138 while (*pwcs!=*L"")
139 {
140 if (cnt>=dstsize)
141 {
142 break;
143 }
144
145 *pwcd = *pwcs;
146
147 pwcs++;
148 pwcd++;
149 cnt ++;
150 }
151
152 if (cnt<dstsize)
153 {
154 memset(pwcd, 0, (dstsize-cnt) * sizeof(WCHAR));
155 }
156}
157
158#define VBOXDISPSETCIEC(_ciec, _x, _y, _lum) \
159 do { \
160 _ciec.x = _x; \
161 _ciec.y = _y; \
162 _ciec.Y = _lum; \
163 } while (0)
164
165
166#define VBOXDISPMAKELOGFONTW(_font, _w, _h, _weight, _clip, _quality, _pitch, _name) \
167 do { \
168 _font.lfHeight = _w; \
169 _font.lfWidth = _h; \
170 _font.lfEscapement = 0; \
171 _font.lfOrientation = 0; \
172 _font.lfWeight = _weight; \
173 _font.lfItalic = 0; \
174 _font.lfUnderline = 0; \
175 _font.lfStrikeOut = 0; \
176 _font.lfCharSet = ANSI_CHARSET; \
177 _font.lfOutPrecision = OUT_DEFAULT_PRECIS; \
178 _font.lfClipPrecision = _clip; \
179 _font.lfQuality = _quality; \
180 _font.lfPitchAndFamily = (_pitch) | FF_DONTCARE; \
181 memset(_font.lfFaceName, 0, sizeof(_font.lfFaceName)); \
182 memcpy(_font.lfFaceName, _name, sizeof(_name)); \
183 } while (0)
184
185static int VBoxDispInitDevice(PVBOXDISPDEV pDev, DEVMODEW *pdm, GDIINFO *pGdiInfo, DEVINFO *pDevInfo)
186{
187 VIDEO_MODE_INFORMATION *pModesTable = NULL, selectedMode;
188 ULONG cModes, i=0;
189 int rc;
190
191 LOGF_ENTER();
192
193 memset(&selectedMode, 0, sizeof(VIDEO_MODE_INFORMATION));
194
195 /* Get a list of supported modes by both miniport and display driver */
196 rc = VBoxDispMPGetVideoModes(pDev->hDriver, &pModesTable, &cModes);
197 VBOX_WARNRC_RETRC(rc);
198
199 /* Check if requested mode is available in the list */
200 if ((g_EngineVersionDDI < DDI_DRIVER_VERSION_NT5)
201 && (pdm->dmBitsPerPel==0)
202 && (pdm->dmPelsWidth==0)
203 && (pdm->dmPelsHeight==0)
204 && (pdm->dmDisplayFrequency==0))
205 {
206 /* Special case for NT4, just return default(first) mode */
207 memcpy(&selectedMode, &pModesTable[0], sizeof(VIDEO_MODE_INFORMATION));
208 }
209 else
210 {
211 for (; i<cModes; ++i)
212 {
213 if ((pdm->dmBitsPerPel == (pModesTable[i].BitsPerPlane * pModesTable[i].NumberOfPlanes))
214 && (pdm->dmPelsWidth == pModesTable[i].VisScreenWidth)
215 && (pdm->dmPelsHeight == pModesTable[i].VisScreenHeight)
216 && (pdm->dmDisplayFrequency == pModesTable[i].Frequency))
217 {
218 memcpy(&selectedMode, &pModesTable[i], sizeof(VIDEO_MODE_INFORMATION));
219 break;
220 }
221 }
222 }
223 EngFreeMem(pModesTable);
224
225 if (i>=cModes)
226 {
227 WARN(("can't support requested mode %dx%d@%dbpp(%dHz)!",
228 pdm->dmPelsWidth, pdm->dmPelsHeight, pdm->dmBitsPerPel, pdm->dmDisplayFrequency));
229 return VERR_NOT_SUPPORTED;
230 }
231
232 LOG(("match for requested mode %dx%d@%dbpp(%dHz)",
233 selectedMode.VisScreenWidth, selectedMode.VisScreenHeight, selectedMode.BitsPerPlane, selectedMode.Frequency));
234
235 /* Update private device info with mode information */
236 pDev->mode.ulIndex = selectedMode.ModeIndex;
237 pDev->mode.ulWidth = selectedMode.VisScreenWidth;
238 pDev->mode.ulHeight = selectedMode.VisScreenHeight;
239 pDev->mode.ulBitsPerPel = selectedMode.BitsPerPlane * selectedMode.NumberOfPlanes;
240 pDev->mode.lScanlineStride = RT_ALIGN_32(selectedMode.ScreenStride, 4);
241 pDev->mode.flMaskR = selectedMode.RedMask;
242 pDev->mode.flMaskG = selectedMode.GreenMask;
243 pDev->mode.flMaskB = selectedMode.BlueMask;
244 pDev->mode.ulPaletteShift = (pDev->mode.ulBitsPerPel==8) ? (8-selectedMode.NumberRedBits) : 0;
245
246 /* Fill GDIINFO structure */
247 memset(pGdiInfo, 0, sizeof(GDIINFO));
248
249 pGdiInfo->ulVersion = (g_EngineVersionDDI<DDI_DRIVER_VERSION_NT5) ? GDI_DRIVER_VERSION:0x5000;
250 pGdiInfo->ulVersion |= VBOXDISPDRIVERVERSION;
251
252 pGdiInfo->ulTechnology = DT_RASDISPLAY;
253
254 pGdiInfo->ulHorzSize = selectedMode.XMillimeter;
255 pGdiInfo->ulVertSize = selectedMode.YMillimeter;
256
257 pGdiInfo->ulHorzRes = pDev->mode.ulWidth;
258 pGdiInfo->ulVertRes = pDev->mode.ulHeight;
259
260 pGdiInfo->cBitsPixel = pDev->mode.ulBitsPerPel;
261 pGdiInfo->cPlanes = selectedMode.NumberOfPlanes;
262
263 pGdiInfo->ulNumColors = (pDev->mode.ulBitsPerPel==8) ? 20 : ((ULONG)(-1));
264
265 pGdiInfo->ulLogPixelsX = pdm->dmLogPixels;
266 pGdiInfo->ulLogPixelsY = pdm->dmLogPixels;
267 if (pdm->dmLogPixels!=96)
268 {
269 WARN(("requested logical pixel res %d isn't 96", pdm->dmLogPixels));
270 }
271
272 pGdiInfo->flTextCaps = TC_RA_ABLE;
273
274 pGdiInfo->ulDACRed = selectedMode.NumberRedBits;
275 pGdiInfo->ulDACGreen = selectedMode.NumberGreenBits;
276 pGdiInfo->ulDACBlue = selectedMode.NumberBlueBits;
277
278 pGdiInfo->ulAspectX = 0x24;
279 pGdiInfo->ulAspectY = 0x24;
280 /* note: ulAspectXY should be square root of sum of squares of x and y aspects */
281 pGdiInfo->ulAspectXY = 0x33;
282
283 /* search for "styled cosmetic lines" on msdn for more info */
284 pGdiInfo->xStyleStep = 1;
285 pGdiInfo->yStyleStep = 1;
286 pGdiInfo->denStyleStep = 3;
287
288 pGdiInfo->ulNumPalReg = (pDev->mode.ulBitsPerPel==8) ? (1<<pDev->mode.ulBitsPerPel) : 0;
289
290 /** @todo might want to implement IOCTL_VIDEO_QUERY_COLOR_CAPABILITIES in miniport driver
291 * and query host for this info there
292 */
293 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Red, 6700, 3300, 0);
294 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Green, 2100, 7100, 0);
295 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Blue, 1400, 800, 0);
296 VBOXDISPSETCIEC(pGdiInfo->ciDevice.AlignmentWhite, 3127, 3290, 0);
297 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Cyan, 0, 0, 0);
298 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Magenta, 0, 0, 0);
299 VBOXDISPSETCIEC(pGdiInfo->ciDevice.Yellow, 0, 0, 0);
300 pGdiInfo->ciDevice.RedGamma = 20000;
301 pGdiInfo->ciDevice.GreenGamma = 20000;
302 pGdiInfo->ciDevice.BlueGamma = 20000;
303
304 pGdiInfo->ulPrimaryOrder = PRIMARY_ORDER_CBA;
305
306 pGdiInfo->ulHTPatternSize = HT_PATSIZE_4x4_M;
307 switch (pDev->mode.ulBitsPerPel)
308 {
309 case 8:
310 {
311 pGdiInfo->ulHTOutputFormat = HT_FORMAT_8BPP;
312 break;
313 }
314 case 16:
315 {
316 pGdiInfo->ulHTOutputFormat = HT_FORMAT_16BPP;
317 break;
318 }
319 case 24:
320 {
321 pGdiInfo->ulHTOutputFormat = HT_FORMAT_24BPP;
322 break;
323 }
324 case 32:
325 {
326 pGdiInfo->ulHTOutputFormat = HT_FORMAT_32BPP;
327 break;
328 }
329 }
330 pGdiInfo->flHTFlags = HT_FLAG_ADDITIVE_PRIMS;
331
332 pGdiInfo->ulVRefresh = selectedMode.Frequency;
333
334 /* 0 means BitBlt's are accelerated by driver */
335 pGdiInfo->ulBltAlignment = 0;
336
337 pGdiInfo->ulPhysicalPixelCharacteristics = PPC_UNDEFINED;
338 pGdiInfo->ulPhysicalPixelGamma = PPG_DEFAULT;
339
340 /* Fill DEVINFO structure */
341 memset(pDevInfo, 0, sizeof(DEVINFO));
342
343 pDevInfo->flGraphicsCaps = GCAPS_OPAQUERECT;
344#ifdef VBOX_WITH_DDRAW
345 pDevInfo->flGraphicsCaps |= GCAPS_DIRECTDRAW;
346#endif
347 VBOXDISPMAKELOGFONTW(pDevInfo->lfDefaultFont,
348 16, 7, FW_BOLD, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, L"System");
349
350 VBOXDISPMAKELOGFONTW(pDevInfo->lfAnsiVarFont,
351 12, 9, FW_NORMAL, CLIP_STROKE_PRECIS, PROOF_QUALITY, VARIABLE_PITCH, L"MS Sans Serif");
352
353 VBOXDISPMAKELOGFONTW(pDevInfo->lfAnsiFixFont,
354 12, 9, FW_NORMAL, CLIP_STROKE_PRECIS, PROOF_QUALITY, FIXED_PITCH, L"Courier");
355 pDevInfo->cFonts = 0;
356 pDevInfo->cxDither = 8;
357 pDevInfo->cyDither = 8;
358 pDevInfo->hpalDefault = 0;
359 pDevInfo->flGraphicsCaps2 = 0;
360
361 switch (pDev->mode.ulBitsPerPel)
362 {
363 case 8:
364 {
365 pDevInfo->flGraphicsCaps |= GCAPS_PALMANAGED|GCAPS_COLOR_DITHER;
366 pDevInfo->iDitherFormat = BMF_8BPP;
367 break;
368 }
369 case 16:
370 {
371 pDevInfo->iDitherFormat = BMF_16BPP;
372 break;
373 }
374 case 24:
375 {
376 pDevInfo->iDitherFormat = BMF_24BPP;
377 break;
378 }
379 case 32:
380 {
381 pDevInfo->iDitherFormat = BMF_32BPP;
382 break;
383 }
384 }
385
386 LOGF_LEAVE();
387 return rc;
388}
389
390/* Display Driver entry point,
391 * Returns DDI version number and callbacks supported by driver.
392 */
393BOOL DrvEnableDriver(ULONG iEngineVersion, ULONG cj, PDRVENABLEDATA pded)
394{
395 /** @todo can't link with hal.lib
396 int irc = RTR0Init(0);
397 if (RT_FAILURE(irc))
398 {
399 LOGREL(("failed to init IPRT (rc=%#x)", irc));
400 return FALSE;
401 }
402 */
403
404 LOGF(("iEngineVersion=%#08X, cj=%d", iEngineVersion, cj));
405
406 g_EngineVersionDDI = iEngineVersion;
407
408 /* Driver can't work if we can't fill atleast first 3 fields in passed PDRVENABLEDATA */
409 if (cj < (2*sizeof(ULONG)+sizeof(DRVFN*)))
410 {
411 WARN(("cj<%d, terminating\n", sizeof(DRVENABLEDATA)));
412 return FALSE;
413 }
414
415 /* Report driver DDI version and appropriate callbacks table based on engine DDI */
416 if (iEngineVersion>=DDI_DRIVER_VERSION_NT5)
417 {
418 /* WIN2K and above */
419 pded->iDriverVersion = DDI_DRIVER_VERSION_NT5;
420 pded->pdrvfn = g_aDrvFnTableNT5;
421 pded->c = RT_ELEMENTS(g_aDrvFnTableNT5);
422 }
423 else
424 {
425 /* NT4_SP3 and below*/
426 pded->iDriverVersion = DDI_DRIVER_VERSION_NT4;
427 pded->pdrvfn = g_aDrvFnTableNT4;
428 pded->c = RT_ELEMENTS(g_aDrvFnTableNT4);
429 }
430
431 LOGF_LEAVE();
432 return TRUE;
433}
434
435/* Free all resources allocated in DrvEnableDriver */
436VOID APIENTRY VBoxDispDrvDisableDriver()
437{
438 LOGF_ENTER();
439
440 /* Intentionally left blank */
441
442 LOGF_LEAVE();
443 return;
444}
445
446/* Returns video modes supported by our device/driver
447 * Note: If we fail here we'd be asked to enter 800x600@4bpp mode later in VBoxDispDrvEnablePDEV.
448 */
449ULONG APIENTRY VBoxDispDrvGetModes(HANDLE hDriver, ULONG cjSize, DEVMODEW *pdm)
450{
451 int rc;
452 VIDEO_MODE_INFORMATION *pModesTable;
453 ULONG cModes;
454 LOGF_ENTER();
455
456 rc = VBoxDispMPGetVideoModes(hDriver, &pModesTable, &cModes);
457 VBOX_WARNRC_RETV(rc, 0);
458
459 if (!pdm) /* return size of buffer required to store all supported modes */
460 {
461 EngFreeMem(pModesTable);
462 LOGF_LEAVE();
463 return cModes * sizeof(DEVMODEW);
464 }
465
466 ULONG mode, cMaxNodes=cjSize/sizeof(DEVMODEW);
467
468 for (mode=0; mode<cModes && mode<cMaxNodes; ++mode, ++pdm)
469 {
470 memset(pdm, 0, sizeof(DEVMODEW));
471 memcpy(pdm->dmDeviceName, VBOXDISP_DEVICE_NAME, sizeof(VBOXDISP_DEVICE_NAME));
472
473 pdm->dmSpecVersion = DM_SPECVERSION;
474 pdm->dmDriverVersion = DM_SPECVERSION;
475 pdm->dmSize = sizeof(DEVMODEW);
476 pdm->dmDriverExtra = 0;
477
478 pdm->dmBitsPerPel = pModesTable[mode].NumberOfPlanes*pModesTable[mode].BitsPerPlane;
479 pdm->dmPelsWidth = pModesTable[mode].VisScreenWidth;
480 pdm->dmPelsHeight = pModesTable[mode].VisScreenHeight;
481 pdm->dmDisplayFrequency = pModesTable[mode].Frequency;
482 pdm->dmDisplayFlags = 0;
483 pdm->dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFREQUENCY|DM_DISPLAYFLAGS;
484 }
485 EngFreeMem(pModesTable);
486
487 LOG(("%d mode(s) reported", mode));
488
489 LOGF_LEAVE();
490 return mode * sizeof(DEVMODEW);
491}
492
493/* First function which is called after entry point, provides info about device to GDI.
494 * Returns pointer to our driver private info structure which would be passed by GDI to our other callbacks.
495 */
496DHPDEV APIENTRY
497VBoxDispDrvEnablePDEV(DEVMODEW *pdm, LPWSTR pwszLogAddress, ULONG cPat, HSURF *phsurfPatterns,
498 ULONG cjCaps, ULONG *pdevcaps,
499 ULONG cjDevInfo, DEVINFO *pdi,
500 HDEV hdev, PWSTR pwszDeviceName, HANDLE hDriver)
501{
502 RT_NOREF(hdev);
503 PVBOXDISPDEV pDev = NULL;
504 GDIINFO gdiInfo;
505 DEVINFO devInfo;
506 int rc;
507
508 /* Next 3 are only used for printer drivers */
509 NOREF(pwszLogAddress);
510 NOREF(cPat);
511 NOREF(phsurfPatterns);
512 NOREF(pwszDeviceName);
513
514 LOGF_ENTER();
515
516 pDev = (PVBOXDISPDEV) EngAllocMem(FL_ZERO_MEMORY, sizeof(VBOXDISPDEV), MEM_ALLOC_TAG);
517 if (!pDev)
518 {
519 WARN(("EngAllocMem failed!\n"));
520 return NULL;
521 }
522 pDev->hDriver = hDriver;
523
524 ULONG ulRegistryFlags = 0;
525 rc = VBoxDispMPQueryRegistryFlags(hDriver, &ulRegistryFlags);
526 if (RT_SUCCESS(rc))
527 {
528 pDev->bBitmapCacheDisabled = (ulRegistryFlags & VBOXVIDEO_REGISTRY_FLAGS_DISABLE_BITMAP_CACHE) != 0;
529 LOG(("Bitmap cache %s", pDev->bBitmapCacheDisabled? "disabled": "enabled"));
530 }
531
532 /* Initialize device structure and query miniport to fill device and gdi infos */
533 rc = VBoxDispInitDevice(pDev, pdm, &gdiInfo, &devInfo);
534 if (RT_FAILURE(rc))
535 {
536 VBOX_WARNRC(rc);
537 EngFreeMem(pDev);
538 return NULL;
539 }
540
541 /* Initialize mouse pointer caps */
542 rc = VBoxDispInitPointerCaps(pDev, &devInfo);
543 if (RT_FAILURE(rc))
544 {
545 VBOX_WARNRC(rc);
546 }
547
548 /* Initialize palette */
549 rc = VBoxDispInitPalette(pDev, &devInfo);
550 if (RT_FAILURE(rc))
551 {
552 VBOX_WARNRC(rc);
553 EngFreeMem(pDev);
554 return NULL;
555 }
556
557 if(g_EngineVersionDDI >= DDI_DRIVER_VERSION_NT5)
558 {
559 devInfo.flGraphicsCaps2 |= GCAPS2_RESERVED1;
560 }
561
562 /* Copy gathered info to supplied buffers */
563 memcpy(pdevcaps, &gdiInfo, min(sizeof(GDIINFO), cjCaps));
564 memcpy(pdi, &devInfo, min(sizeof(DEVINFO), cjDevInfo));
565
566 LOGF_LEAVE();
567 return (DHPDEV)pDev;
568}
569
570/* Called to provide us GDI handle for our device, which we should use later for GDI calls */
571VOID APIENTRY VBoxDispDrvCompletePDEV(DHPDEV dhpdev, HDEV hdev)
572{
573 LOGF_ENTER();
574
575 ((PVBOXDISPDEV)dhpdev)->hDevGDI = hdev;
576
577 LOGF_LEAVE();
578}
579
580/* Called to free resources allocated for device in VBoxDispDrvEnablePDEV */
581VOID APIENTRY VBoxDispDrvDisablePDEV(DHPDEV dhpdev)
582{
583 LOGF_ENTER();
584
585 VBoxDispDestroyPalette((PVBOXDISPDEV) dhpdev);
586
587 EngFreeMem(dhpdev);
588
589 LOGF_LEAVE();
590}
591
592/* Called to create and associate surface with device */
593HSURF APIENTRY VBoxDispDrvEnableSurface(DHPDEV dhpdev)
594{
595 int rc;
596 PVBOXDISPDEV pDev = (PVBOXDISPDEV)dhpdev;
597
598 LOGF_ENTER();
599
600 /* Switch device to mode requested in VBoxDispDrvEnablePDEV */
601 rc = VBoxDispMPSetCurrentMode(pDev->hDriver, pDev->mode.ulIndex);
602 VBOX_WARNRC_RETV(rc, NULL);
603
604 /* Map fb and vram */
605 rc = VBoxDispMPMapMemory(pDev, &pDev->memInfo);
606 VBOX_WARNRC_RETV(rc, NULL);
607
608 /* Clear mapped memory, to avoid garbage while video mode is switching */
609 /** @todo VIDEO_MODE_NO_ZERO_MEMORY does nothing in miniport's IOCTL_VIDEO_SET_CURRENT_MODE*/
610 memset(pDev->memInfo.FrameBufferBase, 0, pDev->mode.ulHeight * abs(pDev->mode.lScanlineStride));
611
612 /* Allocate memory for pointer attrs */
613 rc = VBoxDispInitPointerAttrs(pDev);
614 VBOX_WARNRC_RETV(rc, NULL);
615
616 /* Init VBVA */
617 rc = VBoxDispVBVAInit(pDev);
618 VBOX_WARNRC_RETV(rc, NULL);
619
620 /* Enable VBVA */
621 if (pDev->hgsmi.bSupported)
622 {
623 if (pDev->mode.ulBitsPerPel==16 || pDev->mode.ulBitsPerPel==24 || pDev->mode.ulBitsPerPel==32)
624 {
625 VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)pDev->memInfo.VideoRamBase+pDev->layout.offVBVABuffer);
626 pDev->hgsmi.bSupported = VBoxVBVAEnable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pVBVA, -1);
627 LogRel(("VBoxDisp[%d]: VBVA %senabled\n", pDev->iDevice, pDev->hgsmi.bSupported? "":"not "));
628 }
629 }
630
631 /* Inform host */
632 if (pDev->hgsmi.bSupported)
633 {
634 VBoxHGSMIProcessDisplayInfo(&pDev->hgsmi.ctx, pDev->iDevice, pDev->orgDev.x, pDev->orgDev.y,
635 0, abs(pDev->mode.lScanlineStride), pDev->mode.ulWidth, pDev->mode.ulHeight,
636 (uint16_t)pDev->mode.ulBitsPerPel, VBVA_SCREEN_F_ACTIVE);
637 }
638
639#ifdef VBOX_WITH_VIDEOHWACCEL
640 VBoxDispVHWAEnable(pDev);
641#endif
642
643 /* Set device palette if needed */
644 if (pDev->mode.ulBitsPerPel == 8)
645 {
646 rc = VBoxDispSetPalette8BPP(pDev);
647 VBOX_WARNRC_RETV(rc, NULL);
648 }
649
650 pDev->orgDisp.x = 0;
651 pDev->orgDisp.y = 0;
652
653 /* Create GDI managed bitmap, which resides in our framebuffer memory */
654 ULONG iFormat;
655 SIZEL size;
656
657 switch (pDev->mode.ulBitsPerPel)
658 {
659 case 8:
660 {
661 iFormat = BMF_8BPP;
662 break;
663 }
664 case 16:
665 {
666 iFormat = BMF_16BPP;
667 break;
668 }
669 case 24:
670 {
671 iFormat = BMF_24BPP;
672 break;
673 }
674 case 32:
675 {
676 iFormat = BMF_32BPP;
677 break;
678 }
679 default:
680 AssertMsgFailedReturn(("ulBitsPerPel=%#x\n", pDev->mode.ulBitsPerPel), NULL);
681 }
682
683 size.cx = pDev->mode.ulWidth;
684 size.cy = pDev->mode.ulHeight;
685
686 pDev->surface.hBitmap = EngCreateBitmap(size, pDev->mode.lScanlineStride, iFormat,
687 pDev->mode.lScanlineStride > 0 ? BMF_TOPDOWN:0,
688 pDev->memInfo.FrameBufferBase);
689 if (!pDev->surface.hBitmap)
690 {
691 WARN(("EngCreateBitmap failed!"));
692 return NULL;
693 }
694 pDev->surface.psoBitmap = EngLockSurface((HSURF)pDev->surface.hBitmap);
695
696 /* Create device-managed surface */
697 pDev->surface.hSurface = EngCreateDeviceSurface((DHSURF)pDev, size, iFormat);
698 if (!pDev->surface.hSurface)
699 {
700 WARN(("EngCreateDeviceSurface failed!"));
701 VBoxDispDrvDisableSurface(dhpdev);
702 return NULL;
703 }
704
705 FLONG flHooks = HOOK_BITBLT|HOOK_TEXTOUT|HOOK_FILLPATH|HOOK_COPYBITS|HOOK_STROKEPATH|HOOK_LINETO|
706 HOOK_PAINT|HOOK_STRETCHBLT;
707
708 /* Associate created surface with our device */
709 if (!EngAssociateSurface(pDev->surface.hSurface, pDev->hDevGDI, flHooks))
710 {
711 WARN(("EngAssociateSurface failed!"));
712 VBoxDispDrvDisableSurface(dhpdev);
713 return NULL;
714 }
715
716 pDev->surface.ulFormat = iFormat;
717 pDev->flDrawingHooks = flHooks;
718
719 LOG(("Created surface %p for physical device %p", pDev->surface.hSurface, pDev));
720
721 LOGF_LEAVE();
722 return pDev->surface.hSurface;
723}
724
725VOID APIENTRY VBoxDispDrvDisableSurface(DHPDEV dhpdev)
726{
727 PVBOXDISPDEV pDev = (PVBOXDISPDEV)dhpdev;
728 LOGF_ENTER();
729
730 if (pDev->surface.hSurface)
731 {
732 EngDeleteSurface(pDev->surface.hSurface);
733 pDev->surface.hSurface = NULL;
734 }
735
736 if (pDev->surface.psoBitmap)
737 {
738 Assert(pDev->surface.hBitmap);
739 EngUnlockSurface(pDev->surface.psoBitmap);
740 pDev->surface.psoBitmap = NULL;
741 }
742
743 if (pDev->surface.hBitmap)
744 {
745 EngDeleteSurface((HSURF) pDev->surface.hBitmap);
746 pDev->surface.hBitmap = NULL;
747 }
748
749 int rc;
750 rc = VBoxDispMPUnmapMemory(pDev);
751 VBOX_WARNRC(rc);
752
753 LOGF_LEAVE();
754}
755
756BOOL APIENTRY
757VBoxDispDrvRealizeBrush(BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask,
758 XLATEOBJ *pxlo, ULONG iHatch)
759{
760 BOOL bRc = FALSE;
761 LOGF_ENTER();
762
763 if (VBoxDispIsScreenSurface(psoTarget))
764 {
765 PVBOXDISPDEV pDev = (PVBOXDISPDEV)psoTarget->dhpdev;
766
767 if (pDev->vbvaCtx.pVBVA && (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
768 {
769 if (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET)
770 {
771 vrdpReset(pDev);
772 pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents &= ~VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
773 }
774
775 if (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_VRDP)
776 {
777 bRc = vrdpDrvRealizeBrush(pbo, psoTarget, psoPattern, psoMask, pxlo, iHatch);
778 }
779 }
780 }
781
782 LOGF_LEAVE();
783 return bRc;
784}
785
786ULONG APIENTRY VBoxDispDrvDitherColor(DHPDEV dhpdev, ULONG iMode, ULONG rgb, ULONG *pul)
787{
788 RT_NOREF(dhpdev, iMode, rgb, pul);
789 ULONG rc;
790 LOGF_ENTER();
791
792 /* There is no EngDitherColor on NT4, so take the easy path and tell the graphics
793 * engine to create a halftone approximation.
794 */
795 rc = DCR_HALFTONE;
796
797 LOGF_LEAVE();
798 return rc;
799}
800
801/* Called to reset device to default mode or to mode specified with dhpdev */
802BOOL APIENTRY VBoxDispDrvAssertMode(DHPDEV dhpdev, BOOL bEnable)
803{
804 PVBOXDISPDEV pDev = (PVBOXDISPDEV) dhpdev;
805 int rc;
806 LOGF_ENTER();
807
808 if (!bEnable)
809 {
810 LOGF(("!bEnable"));
811#ifdef VBOX_WITH_VIDEOHWACCEL
812 /* tells we can not process host commands any more and ensures that
813 * we've completed processing of the host VHWA commands
814 */
815 VBoxDispVHWADisable(pDev);
816#endif
817
818 /* disable VBVA */
819 if (pDev->hgsmi.bSupported)
820 {
821 VBoxVBVADisable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, -1);
822 }
823
824 /* reset the device to default mode */
825 rc = VBoxDispMPResetDevice(pDev->hDriver);
826 VBOX_WARNRC_RETV(rc, FALSE);
827 }
828 else
829 {
830 LOGF(("bEnable"));
831
832 /* switch device to previous pDev mode */
833 rc = VBoxDispMPSetCurrentMode(pDev->hDriver, pDev->mode.ulIndex);
834 VBOX_WARNRC_RETV(rc, NULL);
835
836 /* enable VBVA */
837 if (pDev->hgsmi.bSupported)
838 {
839 if (pDev->mode.ulBitsPerPel==16 || pDev->mode.ulBitsPerPel==24 || pDev->mode.ulBitsPerPel==32)
840 {
841 VBVABUFFER *pVBVA = (VBVABUFFER *)((uint8_t *)pDev->memInfo.VideoRamBase+pDev->layout.offVBVABuffer);
842 pDev->hgsmi.bSupported = VBoxVBVAEnable(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pVBVA, -1);
843 LogRel(("VBoxDisp[%d]: VBVA %senabled\n", pDev->iDevice, pDev->hgsmi.bSupported? "":"not "));
844 }
845 }
846
847 /* inform host */
848 if (pDev->hgsmi.bSupported)
849 {
850 VBoxHGSMIProcessDisplayInfo(&pDev->hgsmi.ctx, pDev->iDevice, pDev->orgDev.x, pDev->orgDev.y,
851 0, abs(pDev->mode.lScanlineStride), pDev->mode.ulWidth, pDev->mode.ulHeight,
852 (uint16_t)pDev->mode.ulBitsPerPel, VBVA_SCREEN_F_ACTIVE);
853 }
854
855#ifdef VBOX_WITH_VIDEOHWACCEL
856 /* tells we can process host commands */
857 VBoxDispVHWAEnable(pDev);
858#endif
859
860 /* Associate back GDI bitmap residing in our framebuffer memory with GDI's handle to our device */
861 if (!EngAssociateSurface((HSURF)pDev->surface.hBitmap, pDev->hDevGDI, 0))
862 {
863 WARN(("EngAssociateSurface on bitmap failed"));
864 return FALSE;
865 }
866
867 /* Associate device managed surface with GDI's handle to our device */
868 if (!EngAssociateSurface(pDev->surface.hSurface, pDev->hDevGDI, pDev->flDrawingHooks))
869 {
870 WARN(("EngAssociateSurface on surface failed"));
871 return FALSE;
872 }
873 }
874
875 LOGF_LEAVE();
876 return TRUE;
877}
878
879ULONG APIENTRY VBoxDispDrvEscape(SURFOBJ *pso, ULONG iEsc, ULONG cjIn, PVOID pvIn, ULONG cjOut, PVOID pvOut)
880{
881 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
882 LOGF_ENTER();
883
884 switch (iEsc)
885 {
886 case VBOXESC_ISVRDPACTIVE:
887 {
888 if (pDev && pDev->vbvaCtx.pVBVA && pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents&VBVA_F_MODE_VRDP)
889 {
890 LOGF(("VBOXESC_ISVRDPACTIVE: 1"));
891 return 1;
892 }
893 LOGF(("VBOXESC_ISVRDPACTIVE: 0"));
894 return 0;
895 }
896 case VBOXESC_SETVISIBLEREGION:
897 {
898 LOGF(("VBOXESC_SETVISIBLEREGION"));
899 LPRGNDATA lpRgnData = (LPRGNDATA)pvIn;
900 DWORD cRects;
901
902 if ( cjIn >= sizeof(RGNDATAHEADER)
903 && pvIn
904 && lpRgnData->rdh.dwSize == sizeof(RGNDATAHEADER)
905 && lpRgnData->rdh.iType == RDH_RECTANGLES
906 && (cRects = lpRgnData->rdh.nCount) <= _1M
907 && cjIn == cRects * (uint64_t)sizeof(RECT) + sizeof(RGNDATAHEADER))
908 {
909 /** @todo this whole conversion thing could maybe be skipped
910 * since RTRECT matches the RECT layout. */
911#if 0
912 AssertCompile(sizeof(RTRECT) == sizeof(RECT));
913 AssertCompileMembersSameSizeAndOffset(RTRECT, xLeft, RECT, left);
914 AssertCompileMembersSameSizeAndOffset(RTRECT, xBottom, RECT, bottom);
915 AssertCompileMembersSameSizeAndOffset(RTRECT, xRight, RECT, right);
916 AssertCompileMembersSameSizeAndOffset(RTRECT, xTop, RECT, top);
917
918 rc = VBoxDispMPSetVisibleRegion(pDev->hDriver, (PRTRECT)&lpRgnData->Buffer[0], cRects);
919 VBOX_WARNRC(rc);
920#else
921 DWORD i;
922 PRTRECT pRTRect;
923 int rc;
924 RECT *pRect = (RECT *)&lpRgnData->Buffer;
925
926 pRTRect = (PRTRECT) EngAllocMem(0, cRects*sizeof(RTRECT), MEM_ALLOC_TAG);
927 if (!pRTRect)
928 {
929 WARN(("failed to allocate %d bytes", cRects*sizeof(RTRECT)));
930 break;
931 }
932
933 for (i = 0; i < cRects; ++i)
934 {
935 LOG(("New visible rectangle (%d,%d) (%d,%d)",
936 pRect[i].left, pRect[i].bottom, pRect[i].right, pRect[i].top));
937 pRTRect[i].xLeft = pRect[i].left;
938 pRTRect[i].yBottom = pRect[i].bottom;
939 pRTRect[i].xRight = pRect[i].right;
940 pRTRect[i].yTop = pRect[i].top;
941 }
942
943 rc = VBoxDispMPSetVisibleRegion(pDev->hDriver, pRTRect, cRects);
944 VBOX_WARNRC(rc);
945
946 EngFreeMem(pRTRect);
947
948#endif
949 if (RT_SUCCESS(rc))
950 {
951 LOGF_LEAVE();
952 return 1;
953 }
954 }
955 else
956 {
957 if (pvIn)
958 {
959 WARN(("check failed rdh.dwSize=%x iType=%d size=%d expected size=%d",
960 lpRgnData->rdh.dwSize, lpRgnData->rdh.iType, cjIn,
961 lpRgnData->rdh.nCount * sizeof(RECT) + sizeof(RGNDATAHEADER)));
962 }
963 }
964 break;
965 }
966 case VBOXESC_ISANYX:
967 {
968 if (pvOut && cjOut == sizeof(DWORD))
969 {
970 DWORD cbReturned;
971 DWORD dwrc = EngDeviceIoControl(pDev->hDriver, IOCTL_VIDEO_VBOX_ISANYX, NULL, 0,
972 pvOut, sizeof (uint32_t), &cbReturned);
973 if (dwrc == NO_ERROR && cbReturned == sizeof (uint32_t))
974 return 1;
975 WARN(("EngDeviceIoControl failed, dwrc(%d), cbReturned(%d)", dwrc, cbReturned));
976 return 0;
977 }
978 else
979 {
980 WARN(("VBOXESC_ISANYX invalid parms"));
981 return 0;
982 }
983 break;
984 }
985 default:
986 {
987 LOG(("unsupported iEsc %#x", iEsc));
988 }
989 }
990
991 LOGF_LEAVE();
992 return 0;
993}
994
995#define FB_OFFSET(_dev, _x, _y) ((_y)*pDev->mode.lScanlineStride) + ((_x)*((pDev->mode.ulBitsPerPel+1)/8))
996/* Obsolete, NT4 specific. Called to set display offset in virtual desktop */
997BOOL APIENTRY VBoxDispDrvOffset(SURFOBJ* pso, LONG x, LONG y, FLONG flReserved)
998{
999 RT_NOREF(flReserved);
1000 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1001 LOGF(("%x %x %x\n", x, y, flReserved));
1002
1003 pDev->memInfo.FrameBufferBase = ((BYTE*)pDev->memInfo.VideoRamBase) + pDev->layout.offFramebuffer
1004 - FB_OFFSET(pDev, x, y);
1005
1006 pDev->orgDisp.x = x;
1007 pDev->orgDisp.y = y;
1008
1009 LOGF_LEAVE();
1010 return TRUE;
1011}
1012
1013/* Called to notify driver about various events */
1014VOID APIENTRY VBoxDispDrvNotify(SURFOBJ *pso, ULONG iType, PVOID pvData)
1015{
1016 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1017 LOGF_ENTER();
1018
1019 switch (iType)
1020 {
1021 case DN_DEVICE_ORIGIN:
1022 {
1023 /*device origin in dualview*/
1024 POINTL *pOrg = (POINTL *)pvData;
1025 if (pOrg)
1026 {
1027 LOG(("DN_DEVICE_ORIGIN (pso=%p, pDev[%d]=%p) old=%d,%d new=%d,%d",
1028 pso, pDev->iDevice, pDev, pDev->orgDev.x, pDev->orgDev.y, pOrg->x, pOrg->y));
1029 if (pDev->orgDev.x!=pOrg->x || pDev->orgDev.y!=pOrg->y)
1030 {
1031 pDev->orgDev = *pOrg;
1032
1033 /* Inform host about display change */
1034 VBoxHGSMIProcessDisplayInfo(&pDev->hgsmi.ctx, pDev->iDevice, pDev->orgDev.x, pDev->orgDev.y,
1035 0, abs(pDev->mode.lScanlineStride),
1036 pDev->mode.ulWidth, pDev->mode.ulHeight,
1037 (uint16_t)pDev->mode.ulBitsPerPel, VBVA_SCREEN_F_ACTIVE);
1038 }
1039 }
1040 else
1041 {
1042 WARN(("DN_DEVICE_ORIGIN pvData==NULL"));
1043 }
1044
1045 break;
1046 }
1047 case DN_DRAWING_BEGIN:
1048 {
1049 /*first drawing op is about to happen for this device*/
1050 LOG(("DN_DRAWING_BEGIN (pso=%p, pDev[%d]=%p)", pso, pDev->iDevice, pDev));
1051 break;
1052 }
1053 default:
1054 {
1055 LOG(("unknown iType=%#x", iType));
1056 }
1057 }
1058
1059 LOGF_LEAVE();
1060 return;
1061}
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