VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DisplayImpl.cpp@ 67510

Last change on this file since 67510 was 67474, checked in by vboxsync, 8 years ago

Devices/DevVGA: Unify the drawing logic (full update is handled by the other case, too). Introduce proper VGA blanking.
Main/Display: Handle VGA blanking

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 170.9 KB
Line 
1/* $Id: DisplayImpl.cpp 67474 2017-06-19 13:12:33Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2017 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 "DisplayImpl.h"
19#include "DisplayUtils.h"
20#include "ConsoleImpl.h"
21#include "ConsoleVRDPServer.h"
22#include "GuestImpl.h"
23#include "VMMDev.h"
24
25#include "AutoCaller.h"
26#include "Logging.h"
27
28/* generated header */
29#include "VBoxEvents.h"
30
31#include <iprt/semaphore.h>
32#include <iprt/thread.h>
33#include <iprt/asm.h>
34#include <iprt/time.h>
35#include <iprt/cpp/utils.h>
36#include <iprt/alloca.h>
37
38#include <VBox/vmm/pdmdrv.h>
39#if defined(DEBUG) || defined(VBOX_STRICT) /* for VM_ASSERT_EMT(). */
40# include <VBox/vmm/vm.h>
41#endif
42
43#ifdef VBOX_WITH_VIDEOHWACCEL
44# include <VBoxVideo.h>
45#endif
46
47#if defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_CRHGSMI)
48# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
49#endif
50
51#include <VBox/com/array.h>
52
53#ifdef VBOX_WITH_VIDEOREC
54# include <iprt/path.h>
55# include "VideoRec.h"
56#endif
57
58#ifdef VBOX_WITH_CROGL
59typedef enum
60{
61 CRVREC_STATE_IDLE,
62 CRVREC_STATE_SUBMITTED
63} CRVREC_STATE;
64#endif
65
66/**
67 * Display driver instance data.
68 *
69 * @implements PDMIDISPLAYCONNECTOR
70 */
71typedef struct DRVMAINDISPLAY
72{
73 /** Pointer to the display object. */
74 Display *pDisplay;
75 /** Pointer to the driver instance structure. */
76 PPDMDRVINS pDrvIns;
77 /** Pointer to the keyboard port interface of the driver/device above us. */
78 PPDMIDISPLAYPORT pUpPort;
79 /** Our display connector interface. */
80 PDMIDISPLAYCONNECTOR IConnector;
81#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
82 /** VBVA callbacks */
83 PPDMIDISPLAYVBVACALLBACKS pVBVACallbacks;
84#endif
85} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
86
87/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
88#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
89
90// constructor / destructor
91/////////////////////////////////////////////////////////////////////////////
92
93Display::Display()
94 : mParent(NULL), mfIsCr3DEnabled(false)
95{
96}
97
98Display::~Display()
99{
100}
101
102
103HRESULT Display::FinalConstruct()
104{
105 int rc = videoAccelConstruct(&mVideoAccelLegacy);
106 AssertRC(rc);
107
108 mfVideoAccelVRDP = false;
109 mfu32SupportedOrders = 0;
110 mcVideoAccelVRDPRefs = 0;
111
112 mfSeamlessEnabled = false;
113 mpRectVisibleRegion = NULL;
114 mcRectVisibleRegion = 0;
115
116#ifdef VBOX_WITH_CROGL
117 mfCrOglDataHidden = false;
118#endif
119
120 mpDrv = NULL;
121 mpVMMDev = NULL;
122 mfVMMDevInited = false;
123
124 rc = RTCritSectInit(&mVideoAccelLock);
125 AssertRC(rc);
126
127#ifdef VBOX_WITH_HGSMI
128 mu32UpdateVBVAFlags = 0;
129 mfVMMDevSupportsGraphics = false;
130 mfGuestVBVACapabilities = 0;
131 mfHostCursorCapabilities = 0;
132#endif
133
134#ifdef VBOX_WITH_VIDEOREC
135 rc = RTCritSectInit(&mVideoCaptureLock);
136 AssertRC(rc);
137
138 mpVideoRecCtx = NULL;
139 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
140 maVideoRecEnabled[i] = true;
141#endif
142
143#ifdef VBOX_WITH_CRHGSMI
144 mhCrOglSvc = NULL;
145 rc = RTCritSectRwInit(&mCrOglLock);
146 AssertRC(rc);
147#endif
148
149#ifdef VBOX_WITH_CROGL
150 RT_ZERO(mCrOglCallbacks);
151 RT_ZERO(mCrOglScreenshotData);
152 mfCrOglVideoRecState = CRVREC_STATE_IDLE;
153 mCrOglScreenshotData.u32Screen = CRSCREEN_ALL;
154 mCrOglScreenshotData.pvContext = this;
155 mCrOglScreenshotData.pfnScreenshotBegin = i_displayCrVRecScreenshotBegin;
156 mCrOglScreenshotData.pfnScreenshotPerform = i_displayCrVRecScreenshotPerform;
157 mCrOglScreenshotData.pfnScreenshotEnd = i_displayCrVRecScreenshotEnd;
158#endif
159
160 return BaseFinalConstruct();
161}
162
163void Display::FinalRelease()
164{
165 uninit();
166
167#ifdef VBOX_WITH_VIDEOREC
168 if (RTCritSectIsInitialized(&mVideoCaptureLock))
169 {
170 RTCritSectDelete(&mVideoCaptureLock);
171 RT_ZERO(mVideoCaptureLock);
172 }
173#endif
174
175 videoAccelDestroy(&mVideoAccelLegacy);
176 i_saveVisibleRegion(0, NULL);
177
178 if (RTCritSectIsInitialized(&mVideoAccelLock))
179 {
180 RTCritSectDelete(&mVideoAccelLock);
181 RT_ZERO(mVideoAccelLock);
182 }
183
184#ifdef VBOX_WITH_CRHGSMI
185 if (RTCritSectRwIsInitialized(&mCrOglLock))
186 {
187 RTCritSectRwDelete(&mCrOglLock);
188 RT_ZERO(mCrOglLock);
189 }
190#endif
191 BaseFinalRelease();
192}
193
194// public initializer/uninitializer for internal purposes only
195/////////////////////////////////////////////////////////////////////////////
196
197#define kMaxSizeThumbnail 64
198
199/**
200 * Save thumbnail and screenshot of the guest screen.
201 */
202static int displayMakeThumbnail(uint8_t *pbData, uint32_t cx, uint32_t cy,
203 uint8_t **ppu8Thumbnail, uint32_t *pcbThumbnail, uint32_t *pcxThumbnail, uint32_t *pcyThumbnail)
204{
205 int rc = VINF_SUCCESS;
206
207 uint8_t *pu8Thumbnail = NULL;
208 uint32_t cbThumbnail = 0;
209 uint32_t cxThumbnail = 0;
210 uint32_t cyThumbnail = 0;
211
212 if (cx > cy)
213 {
214 cxThumbnail = kMaxSizeThumbnail;
215 cyThumbnail = (kMaxSizeThumbnail * cy) / cx;
216 }
217 else
218 {
219 cyThumbnail = kMaxSizeThumbnail;
220 cxThumbnail = (kMaxSizeThumbnail * cx) / cy;
221 }
222
223 LogRelFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxThumbnail, cyThumbnail));
224
225 cbThumbnail = cxThumbnail * 4 * cyThumbnail;
226 pu8Thumbnail = (uint8_t *)RTMemAlloc(cbThumbnail);
227
228 if (pu8Thumbnail)
229 {
230 uint8_t *dst = pu8Thumbnail;
231 uint8_t *src = pbData;
232 int dstW = cxThumbnail;
233 int dstH = cyThumbnail;
234 int srcW = cx;
235 int srcH = cy;
236 int iDeltaLine = cx * 4;
237
238 BitmapScale32(dst,
239 dstW, dstH,
240 src,
241 iDeltaLine,
242 srcW, srcH);
243
244 *ppu8Thumbnail = pu8Thumbnail;
245 *pcbThumbnail = cbThumbnail;
246 *pcxThumbnail = cxThumbnail;
247 *pcyThumbnail = cyThumbnail;
248 }
249 else
250 {
251 rc = VERR_NO_MEMORY;
252 }
253
254 return rc;
255}
256
257#ifdef VBOX_WITH_CROGL
258typedef struct
259{
260 CRVBOXHGCMTAKESCREENSHOT Base;
261
262 /* 32bpp small RGB image. */
263 uint8_t *pu8Thumbnail;
264 uint32_t cbThumbnail;
265 uint32_t cxThumbnail;
266 uint32_t cyThumbnail;
267
268 /* PNG screenshot. */
269 uint8_t *pu8PNG;
270 uint32_t cbPNG;
271 uint32_t cxPNG;
272 uint32_t cyPNG;
273} VBOX_DISPLAY_SAVESCREENSHOT_DATA;
274
275static DECLCALLBACK(void) displaySaveScreenshotReport(void *pvCtx, uint32_t uScreen,
276 uint32_t x, uint32_t y, uint32_t uBitsPerPixel,
277 uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
278 uint8_t *pu8BufferAddress, uint64_t u64Timestamp)
279{
280 RT_NOREF(uScreen, x, y, uBitsPerPixel,uBytesPerLine, u64Timestamp);
281 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pData = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)pvCtx;
282 displayMakeThumbnail(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8Thumbnail,
283 &pData->cbThumbnail, &pData->cxThumbnail, &pData->cyThumbnail);
284 int rc = DisplayMakePNG(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8PNG,
285 &pData->cbPNG, &pData->cxPNG, &pData->cyPNG, 1);
286 if (RT_FAILURE(rc))
287 {
288 AssertMsgFailed(("DisplayMakePNG failed (rc=%Rrc)\n", rc));
289 if (pData->pu8PNG)
290 {
291 RTMemFree(pData->pu8PNG);
292 pData->pu8PNG = NULL;
293 }
294 pData->cbPNG = 0;
295 pData->cxPNG = 0;
296 pData->cyPNG = 0;
297 }
298}
299#endif
300
301DECLCALLBACK(void) Display::i_displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser)
302{
303 Display *that = static_cast<Display*>(pvUser);
304
305 /* 32bpp small RGB image. */
306 uint8_t *pu8Thumbnail = NULL;
307 uint32_t cbThumbnail = 0;
308 uint32_t cxThumbnail = 0;
309 uint32_t cyThumbnail = 0;
310
311 /* PNG screenshot. */
312 uint8_t *pu8PNG = NULL;
313 uint32_t cbPNG = 0;
314 uint32_t cxPNG = 0;
315 uint32_t cyPNG = 0;
316
317 Console::SafeVMPtr ptrVM(that->mParent);
318 if (ptrVM.isOk())
319 {
320#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
321 BOOL f3DSnapshot = FALSE;
322 if ( that->mfIsCr3DEnabled
323 && that->mCrOglCallbacks.pfnHasData
324 && that->mCrOglCallbacks.pfnHasData())
325 {
326 VMMDev *pVMMDev = that->mParent->i_getVMMDev();
327 if (pVMMDev)
328 {
329 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pScreenshot;
330 pScreenshot = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)RTMemAllocZ(sizeof(*pScreenshot));
331 if (pScreenshot)
332 {
333 /* screen id or CRSCREEN_ALL to specify all enabled */
334 pScreenshot->Base.u32Screen = 0;
335 pScreenshot->Base.u32Width = 0;
336 pScreenshot->Base.u32Height = 0;
337 pScreenshot->Base.u32Pitch = 0;
338 pScreenshot->Base.pvBuffer = NULL;
339 pScreenshot->Base.pvContext = pScreenshot;
340 pScreenshot->Base.pfnScreenshotBegin = NULL;
341 pScreenshot->Base.pfnScreenshotPerform = displaySaveScreenshotReport;
342 pScreenshot->Base.pfnScreenshotEnd = NULL;
343
344 VBOXCRCMDCTL_HGCM data;
345 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
346 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
347
348 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
349 data.aParms[0].u.pointer.addr = &pScreenshot->Base;
350 data.aParms[0].u.pointer.size = sizeof(pScreenshot->Base);
351
352 int rc = that->i_crCtlSubmitSync(&data.Hdr, sizeof(data));
353 if (RT_SUCCESS(rc))
354 {
355 if (pScreenshot->pu8PNG)
356 {
357 pu8Thumbnail = pScreenshot->pu8Thumbnail;
358 cbThumbnail = pScreenshot->cbThumbnail;
359 cxThumbnail = pScreenshot->cxThumbnail;
360 cyThumbnail = pScreenshot->cyThumbnail;
361
362 /* PNG screenshot. */
363 pu8PNG = pScreenshot->pu8PNG;
364 cbPNG = pScreenshot->cbPNG;
365 cxPNG = pScreenshot->cxPNG;
366 cyPNG = pScreenshot->cyPNG;
367 f3DSnapshot = TRUE;
368 }
369 else
370 AssertMsgFailed(("no png\n"));
371 }
372 else
373 AssertMsgFailed(("SHCRGL_HOST_FN_TAKE_SCREENSHOT failed (rc=%Rrc)\n", rc));
374
375
376 RTMemFree(pScreenshot);
377 }
378 }
379 }
380
381 if (!f3DSnapshot)
382#endif
383 {
384 /* Query RGB bitmap. */
385 /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */
386 uint8_t *pbData = NULL;
387 size_t cbData = 0;
388 uint32_t cx = 0;
389 uint32_t cy = 0;
390 bool fFreeMem = false;
391 int rc = Display::i_displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pbData, &cbData, &cx, &cy, &fFreeMem);
392
393 /*
394 * It is possible that success is returned but everything is 0 or NULL.
395 * (no display attached if a VM is running with VBoxHeadless on OSE for example)
396 */
397 if (RT_SUCCESS(rc) && pbData)
398 {
399 Assert(cx && cy);
400
401 /* Prepare a small thumbnail and a PNG screenshot. */
402 displayMakeThumbnail(pbData, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail);
403 rc = DisplayMakePNG(pbData, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1);
404 if (RT_FAILURE(rc))
405 {
406 if (pu8PNG)
407 {
408 RTMemFree(pu8PNG);
409 pu8PNG = NULL;
410 }
411 cbPNG = 0;
412 cxPNG = 0;
413 cyPNG = 0;
414 }
415
416 if (fFreeMem)
417 RTMemFree(pbData);
418 else
419 that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pbData);
420 }
421 }
422 }
423 else
424 {
425 LogFunc(("Failed to get VM pointer 0x%x\n", ptrVM.rc()));
426 }
427
428 /* Regardless of rc, save what is available:
429 * Data format:
430 * uint32_t cBlocks;
431 * [blocks]
432 *
433 * Each block is:
434 * uint32_t cbBlock; if 0 - no 'block data'.
435 * uint32_t typeOfBlock; 0 - 32bpp RGB bitmap, 1 - PNG, ignored if 'cbBlock' is 0.
436 * [block data]
437 *
438 * Block data for bitmap and PNG:
439 * uint32_t cx;
440 * uint32_t cy;
441 * [image data]
442 */
443 SSMR3PutU32(pSSM, 2); /* Write thumbnail and PNG screenshot. */
444
445 /* First block. */
446 SSMR3PutU32(pSSM, (uint32_t)(cbThumbnail + 2 * sizeof(uint32_t)));
447 SSMR3PutU32(pSSM, 0); /* Block type: thumbnail. */
448
449 if (cbThumbnail)
450 {
451 SSMR3PutU32(pSSM, cxThumbnail);
452 SSMR3PutU32(pSSM, cyThumbnail);
453 SSMR3PutMem(pSSM, pu8Thumbnail, cbThumbnail);
454 }
455
456 /* Second block. */
457 SSMR3PutU32(pSSM, (uint32_t)(cbPNG + 2 * sizeof(uint32_t)));
458 SSMR3PutU32(pSSM, 1); /* Block type: png. */
459
460 if (cbPNG)
461 {
462 SSMR3PutU32(pSSM, cxPNG);
463 SSMR3PutU32(pSSM, cyPNG);
464 SSMR3PutMem(pSSM, pu8PNG, cbPNG);
465 }
466
467 RTMemFree(pu8PNG);
468 RTMemFree(pu8Thumbnail);
469}
470
471DECLCALLBACK(int)
472Display::i_displaySSMLoadScreenshot(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass)
473{
474 RT_NOREF(pvUser);
475 if (uVersion != sSSMDisplayScreenshotVer)
476 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
477 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
478
479 /* Skip data. */
480 uint32_t cBlocks;
481 int rc = SSMR3GetU32(pSSM, &cBlocks);
482 AssertRCReturn(rc, rc);
483
484 for (uint32_t i = 0; i < cBlocks; i++)
485 {
486 uint32_t cbBlock;
487 rc = SSMR3GetU32(pSSM, &cbBlock);
488 AssertRCBreak(rc);
489
490 uint32_t typeOfBlock;
491 rc = SSMR3GetU32(pSSM, &typeOfBlock);
492 AssertRCBreak(rc);
493
494 LogRelFlowFunc(("[%d] type %d, size %d bytes\n", i, typeOfBlock, cbBlock));
495
496 /* Note: displaySSMSaveScreenshot writes size of a block = 8 and
497 * do not write any data if the image size was 0.
498 * @todo Fix and increase saved state version.
499 */
500 if (cbBlock > 2 * sizeof(uint32_t))
501 {
502 rc = SSMR3Skip(pSSM, cbBlock);
503 AssertRCBreak(rc);
504 }
505 }
506
507 return rc;
508}
509
510/**
511 * Save/Load some important guest state
512 */
513DECLCALLBACK(void)
514Display::i_displaySSMSave(PSSMHANDLE pSSM, void *pvUser)
515{
516 Display *that = static_cast<Display*>(pvUser);
517
518 SSMR3PutU32(pSSM, that->mcMonitors);
519 for (unsigned i = 0; i < that->mcMonitors; i++)
520 {
521 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32Offset);
522 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32MaxFramebufferSize);
523 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32InformationSize);
524 SSMR3PutU32(pSSM, that->maFramebuffers[i].w);
525 SSMR3PutU32(pSSM, that->maFramebuffers[i].h);
526 SSMR3PutS32(pSSM, that->maFramebuffers[i].xOrigin);
527 SSMR3PutS32(pSSM, that->maFramebuffers[i].yOrigin);
528 SSMR3PutU32(pSSM, that->maFramebuffers[i].flags);
529 }
530 SSMR3PutS32(pSSM, that->xInputMappingOrigin);
531 SSMR3PutS32(pSSM, that->yInputMappingOrigin);
532 SSMR3PutU32(pSSM, that->cxInputMapping);
533 SSMR3PutU32(pSSM, that->cyInputMapping);
534 SSMR3PutU32(pSSM, that->mfGuestVBVACapabilities);
535 SSMR3PutU32(pSSM, that->mfHostCursorCapabilities);
536}
537
538DECLCALLBACK(int)
539Display::i_displaySSMLoad(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass)
540{
541 Display *that = static_cast<Display*>(pvUser);
542
543 if ( uVersion != sSSMDisplayVer
544 && uVersion != sSSMDisplayVer2
545 && uVersion != sSSMDisplayVer3
546 && uVersion != sSSMDisplayVer4
547 && uVersion != sSSMDisplayVer5)
548 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
549 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
550
551 uint32_t cMonitors;
552 int rc = SSMR3GetU32(pSSM, &cMonitors);
553 AssertRCReturn(rc, rc);
554 if (cMonitors != that->mcMonitors)
555 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Number of monitors changed (%d->%d)!"), cMonitors, that->mcMonitors);
556
557 for (uint32_t i = 0; i < cMonitors; i++)
558 {
559 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32Offset);
560 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32MaxFramebufferSize);
561 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32InformationSize);
562 if ( uVersion == sSSMDisplayVer2
563 || uVersion == sSSMDisplayVer3
564 || uVersion == sSSMDisplayVer4
565 || uVersion == sSSMDisplayVer5)
566 {
567 uint32_t w;
568 uint32_t h;
569 SSMR3GetU32(pSSM, &w);
570 SSMR3GetU32(pSSM, &h);
571 that->maFramebuffers[i].w = w;
572 that->maFramebuffers[i].h = h;
573 }
574 if ( uVersion == sSSMDisplayVer3
575 || uVersion == sSSMDisplayVer4
576 || uVersion == sSSMDisplayVer5)
577 {
578 int32_t xOrigin;
579 int32_t yOrigin;
580 uint32_t flags;
581 SSMR3GetS32(pSSM, &xOrigin);
582 SSMR3GetS32(pSSM, &yOrigin);
583 SSMR3GetU32(pSSM, &flags);
584 that->maFramebuffers[i].xOrigin = xOrigin;
585 that->maFramebuffers[i].yOrigin = yOrigin;
586 that->maFramebuffers[i].flags = (uint16_t)flags;
587 that->maFramebuffers[i].fDisabled = (that->maFramebuffers[i].flags & VBVA_SCREEN_F_DISABLED) != 0;
588 }
589 }
590 if ( uVersion == sSSMDisplayVer4
591 || uVersion == sSSMDisplayVer5)
592 {
593 SSMR3GetS32(pSSM, &that->xInputMappingOrigin);
594 SSMR3GetS32(pSSM, &that->yInputMappingOrigin);
595 SSMR3GetU32(pSSM, &that->cxInputMapping);
596 SSMR3GetU32(pSSM, &that->cyInputMapping);
597 }
598 if (uVersion == sSSMDisplayVer5)
599 {
600 SSMR3GetU32(pSSM, &that->mfGuestVBVACapabilities);
601 SSMR3GetU32(pSSM, &that->mfHostCursorCapabilities);
602 }
603
604 return VINF_SUCCESS;
605}
606
607/**
608 * Initializes the display object.
609 *
610 * @returns COM result indicator
611 * @param aParent handle of our parent object
612 */
613HRESULT Display::init(Console *aParent)
614{
615 ComAssertRet(aParent, E_INVALIDARG);
616 /* Enclose the state transition NotReady->InInit->Ready */
617 AutoInitSpan autoInitSpan(this);
618 AssertReturn(autoInitSpan.isOk(), E_FAIL);
619
620 unconst(mParent) = aParent;
621
622 mfSourceBitmapEnabled = true;
623 fVGAResizing = false;
624
625 ULONG ul;
626 mParent->i_machine()->COMGETTER(MonitorCount)(&ul);
627 mcMonitors = ul;
628 xInputMappingOrigin = 0;
629 yInputMappingOrigin = 0;
630 cxInputMapping = 0;
631 cyInputMapping = 0;
632
633 for (ul = 0; ul < mcMonitors; ul++)
634 {
635 maFramebuffers[ul].u32Offset = 0;
636 maFramebuffers[ul].u32MaxFramebufferSize = 0;
637 maFramebuffers[ul].u32InformationSize = 0;
638
639 maFramebuffers[ul].pFramebuffer = NULL;
640 /* All secondary monitors are disabled at startup. */
641 maFramebuffers[ul].fDisabled = ul > 0;
642
643 maFramebuffers[ul].u32Caps = 0;
644
645 maFramebuffers[ul].updateImage.pu8Address = NULL;
646 maFramebuffers[ul].updateImage.cbLine = 0;
647
648 maFramebuffers[ul].xOrigin = 0;
649 maFramebuffers[ul].yOrigin = 0;
650
651 maFramebuffers[ul].w = 0;
652 maFramebuffers[ul].h = 0;
653
654 maFramebuffers[ul].flags = maFramebuffers[ul].fDisabled? VBVA_SCREEN_F_DISABLED: 0;
655
656 maFramebuffers[ul].u16BitsPerPixel = 0;
657 maFramebuffers[ul].pu8FramebufferVRAM = NULL;
658 maFramebuffers[ul].u32LineSize = 0;
659
660 maFramebuffers[ul].pHostEvents = NULL;
661
662 maFramebuffers[ul].fDefaultFormat = false;
663
664#ifdef VBOX_WITH_HGSMI
665 maFramebuffers[ul].fVBVAEnabled = false;
666 maFramebuffers[ul].fVBVAForceResize = false;
667 maFramebuffers[ul].fRenderThreadMode = false;
668 maFramebuffers[ul].pVBVAHostFlags = NULL;
669#endif /* VBOX_WITH_HGSMI */
670#ifdef VBOX_WITH_CROGL
671 RT_ZERO(maFramebuffers[ul].pendingViewportInfo);
672#endif
673 }
674
675 {
676 // register listener for state change events
677 ComPtr<IEventSource> es;
678 mParent->COMGETTER(EventSource)(es.asOutParam());
679 com::SafeArray<VBoxEventType_T> eventTypes;
680 eventTypes.push_back(VBoxEventType_OnStateChanged);
681 es->RegisterListener(this, ComSafeArrayAsInParam(eventTypes), true);
682 }
683
684 /* Cache the 3D settings. */
685 BOOL fIs3DEnabled = FALSE;
686 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled);
687 GraphicsControllerType_T enmGpuType = (GraphicsControllerType_T)GraphicsControllerType_VBoxVGA;
688 mParent->i_machine()->COMGETTER(GraphicsControllerType)(&enmGpuType);
689 mfIsCr3DEnabled = fIs3DEnabled && enmGpuType == GraphicsControllerType_VBoxVGA;
690
691 /* Confirm a successful initialization */
692 autoInitSpan.setSucceeded();
693
694 return S_OK;
695}
696
697/**
698 * Uninitializes the instance and sets the ready flag to FALSE.
699 * Called either from FinalRelease() or by the parent when it gets destroyed.
700 */
701void Display::uninit()
702{
703 LogRelFlowFunc(("this=%p\n", this));
704
705 /* Enclose the state transition Ready->InUninit->NotReady */
706 AutoUninitSpan autoUninitSpan(this);
707 if (autoUninitSpan.uninitDone())
708 return;
709
710 unsigned uScreenId;
711 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
712 {
713 maFramebuffers[uScreenId].pSourceBitmap.setNull();
714 maFramebuffers[uScreenId].updateImage.pSourceBitmap.setNull();
715 maFramebuffers[uScreenId].updateImage.pu8Address = NULL;
716 maFramebuffers[uScreenId].updateImage.cbLine = 0;
717 maFramebuffers[uScreenId].pFramebuffer.setNull();
718#ifdef VBOX_WITH_VIDEOREC
719 maFramebuffers[uScreenId].videoCapture.pSourceBitmap.setNull();
720#endif
721 }
722
723 if (mParent)
724 {
725 ComPtr<IEventSource> es;
726 mParent->COMGETTER(EventSource)(es.asOutParam());
727 es->UnregisterListener(this);
728 }
729
730 unconst(mParent) = NULL;
731
732 if (mpDrv)
733 mpDrv->pDisplay = NULL;
734
735 mpDrv = NULL;
736 mpVMMDev = NULL;
737 mfVMMDevInited = true;
738}
739
740/**
741 * Register the SSM methods. Called by the power up thread to be able to
742 * pass pVM
743 */
744int Display::i_registerSSM(PUVM pUVM)
745{
746 /* Version 2 adds width and height of the framebuffer; version 3 adds
747 * the framebuffer offset in the virtual desktop and the framebuffer flags;
748 * version 4 adds guest to host input event mapping and version 5 adds
749 * guest VBVA and host cursor capabilities.
750 */
751 int rc = SSMR3RegisterExternal(pUVM, "DisplayData", 0, sSSMDisplayVer5,
752 mcMonitors * sizeof(uint32_t) * 8 + sizeof(uint32_t),
753 NULL, NULL, NULL,
754 NULL, i_displaySSMSave, NULL,
755 NULL, i_displaySSMLoad, NULL, this);
756 AssertRCReturn(rc, rc);
757
758 /*
759 * Register loaders for old saved states where iInstance was
760 * 3 * sizeof(uint32_t *) due to a code mistake.
761 */
762 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
763 NULL, NULL, NULL,
764 NULL, NULL, NULL,
765 NULL, i_displaySSMLoad, NULL, this);
766 AssertRCReturn(rc, rc);
767
768 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
769 NULL, NULL, NULL,
770 NULL, NULL, NULL,
771 NULL, i_displaySSMLoad, NULL, this);
772 AssertRCReturn(rc, rc);
773
774 /* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */
775 rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/,
776 NULL, NULL, NULL,
777 NULL, i_displaySSMSaveScreenshot, NULL,
778 NULL, i_displaySSMLoadScreenshot, NULL, this);
779
780 AssertRCReturn(rc, rc);
781
782 return VINF_SUCCESS;
783}
784
785DECLCALLBACK(void) Display::i_displayCrCmdFree(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
786{
787 RT_NOREF(pCmd, cbCmd, rc);
788 Assert(pvCompletion);
789 RTMemFree(pvCompletion);
790}
791
792#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
793int Display::i_crOglWindowsShow(bool fShow)
794{
795 if (!mfCrOglDataHidden == !!fShow)
796 return VINF_SUCCESS;
797
798 if (!mhCrOglSvc)
799 {
800 /* No 3D or the VMSVGA3d kind. */
801 Assert(!mfIsCr3DEnabled);
802 return VERR_INVALID_STATE;
803 }
804
805 VMMDev *pVMMDev = mParent->i_getVMMDev();
806 if (!pVMMDev)
807 {
808 AssertMsgFailed(("no vmmdev\n"));
809 return VERR_INVALID_STATE;
810 }
811
812 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM));
813 if (!pData)
814 {
815 AssertMsgFailed(("RTMemAlloc failed\n"));
816 return VERR_NO_MEMORY;
817 }
818
819 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
820 pData->Hdr.u32Function = SHCRGL_HOST_FN_WINDOWS_SHOW;
821
822 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
823 pData->aParms[0].u.uint32 = (uint32_t)fShow;
824
825 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
826 if (RT_SUCCESS(rc))
827 mfCrOglDataHidden = !fShow;
828 else
829 {
830 AssertMsgFailed(("crCtlSubmit failed (rc=%Rrc)\n", rc));
831 RTMemFree(pData);
832 }
833
834 return rc;
835}
836#endif
837
838
839// public methods only for internal purposes
840/////////////////////////////////////////////////////////////////////////////
841
842int Display::i_notifyCroglResize(PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, void *pvVRAM)
843{
844 RT_NOREF(pView);
845#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
846 if (maFramebuffers[pScreen->u32ViewIndex].fRenderThreadMode)
847 return VINF_SUCCESS; /* nop it */
848
849 if (mfIsCr3DEnabled)
850 {
851 int rc = VERR_INVALID_STATE;
852 if (mhCrOglSvc)
853 {
854 VMMDev *pVMMDev = mParent->i_getVMMDev();
855 if (pVMMDev)
856 {
857 VBOXCRCMDCTL_HGCM *pCtl;
858 pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(CRVBOXHGCMDEVRESIZE) + sizeof(VBOXCRCMDCTL_HGCM));
859 if (pCtl)
860 {
861 CRVBOXHGCMDEVRESIZE *pData = (CRVBOXHGCMDEVRESIZE*)(pCtl+1);
862 pData->Screen = *pScreen;
863 pData->pvVRAM = pvVRAM;
864
865 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
866 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_DEV_RESIZE;
867 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
868 pCtl->aParms[0].u.pointer.addr = pData;
869 pCtl->aParms[0].u.pointer.size = sizeof(*pData);
870
871 rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);
872 if (RT_FAILURE(rc))
873 {
874 AssertMsgFailed(("crCtlSubmit failed (rc=%Rrc)\n", rc));
875 RTMemFree(pCtl);
876 }
877 }
878 else
879 rc = VERR_NO_MEMORY;
880 }
881 }
882
883 return rc;
884 }
885#else /* !VBOX_WITH_HGCM || !VBOX_WITH_CROGL */
886 RT_NOREF(pScreen, pvVRAM);
887#endif
888 return VINF_SUCCESS;
889}
890
891#ifndef NEW_RESIZE
892/**
893 * Handles display resize event.
894 *
895 * @param uScreenId Screen ID
896 * @param bpp New bits per pixel.
897 * @param pvVRAM VRAM pointer.
898 * @param cbLine New bytes per line.
899 * @param w New display width.
900 * @param h New display height.
901 * @param flags Flags of the new video mode.
902 *
903 * @thread EMT
904 */
905int Display::i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM,
906 uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags)
907#else
908/**
909 * Handles display resize event.
910 *
911 * @param uScreenId Screen ID
912 * @param bpp New bits per pixel.
913 * @param pvVRAM VRAM pointer.
914 * @param cbLine New bytes per line.
915 * @param w New display width.
916 * @param h New display height.
917 * @param flags Flags of the new video mode.
918 * @param xOrigin New display origin X.
919 * @param yOrigin New display origin Y.
920 * @param fVGAResize Whether the resize is originated from the VGA device (DevVGA).
921 */
922int Display::i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM,
923 uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags,
924 int32_t xOrigin, int32_t yOrigin, bool fVGAResize)
925#endif
926{
927 LogRel(("Display::handleDisplayResize: uScreenId=%d pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X flags=0x%X\n", uScreenId,
928 pvVRAM, w, h, bpp, cbLine, flags));
929
930#ifndef NEW_RESIZE
931 if (uScreenId >= mcMonitors)
932 return VINF_SUCCESS;
933
934 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
935
936 /* Reset the update mode. */
937 pFBInfo->updateImage.pSourceBitmap.setNull();
938 pFBInfo->updateImage.pu8Address = NULL;
939 pFBInfo->updateImage.cbLine = 0;
940
941 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
942 {
943 pFBInfo->w = w;
944 pFBInfo->h = h;
945
946 pFBInfo->u16BitsPerPixel = (uint16_t)bpp;
947 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM;
948 pFBInfo->u32LineSize = cbLine;
949 pFBInfo->flags = flags;
950 }
951
952 /* Guest screen image will be invalid during resize, make sure that it is not updated. */
953 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
954 {
955 if (mpDrv)
956 {
957 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, false);
958
959 mpDrv->IConnector.pbData = NULL;
960 mpDrv->IConnector.cbScanline = 0;
961 mpDrv->IConnector.cBits = 32; /* DevVGA does not work with cBits == 0. */
962 mpDrv->IConnector.cx = 0;
963 mpDrv->IConnector.cy = 0;
964 }
965 }
966
967 maFramebuffers[uScreenId].pSourceBitmap.setNull();
968
969 if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
970 {
971 HRESULT hr = maFramebuffers[uScreenId].pFramebuffer->NotifyChange(uScreenId, 0, 0, w, h); /** @todo origin */
972 LogFunc(("NotifyChange hr %08X\n", hr));
973 NOREF(hr);
974 }
975
976 bool fUpdateImage = RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_UpdateImage);
977 if (fUpdateImage && !pFBInfo->pFramebuffer.isNull())
978 {
979 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
980 HRESULT hr = QuerySourceBitmap(uScreenId, pSourceBitmap.asOutParam());
981 if (SUCCEEDED(hr))
982 {
983 BYTE *pAddress = NULL;
984 ULONG ulWidth = 0;
985 ULONG ulHeight = 0;
986 ULONG ulBitsPerPixel = 0;
987 ULONG ulBytesPerLine = 0;
988 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
989
990 hr = pSourceBitmap->QueryBitmapInfo(&pAddress,
991 &ulWidth,
992 &ulHeight,
993 &ulBitsPerPixel,
994 &ulBytesPerLine,
995 &bitmapFormat);
996 if (SUCCEEDED(hr))
997 {
998 pFBInfo->updateImage.pSourceBitmap = pSourceBitmap;
999 pFBInfo->updateImage.pu8Address = pAddress;
1000 pFBInfo->updateImage.cbLine = ulBytesPerLine;
1001 }
1002 }
1003 }
1004
1005 /* Inform the VRDP server about the change of display parameters. */
1006 LogRelFlowFunc(("Calling VRDP\n"));
1007 mParent->i_consoleVRDPServer()->SendResize();
1008
1009 /* And re-send the seamless rectangles if necessary. */
1010 if (mfSeamlessEnabled)
1011 i_handleSetVisibleRegion(mcRectVisibleRegion, mpRectVisibleRegion);
1012
1013#ifdef VBOX_WITH_VIDEOREC
1014 videoCaptureScreenChanged(uScreenId);
1015#endif
1016
1017#else /* NEW_RESIZE */
1018
1019 /* Caller must not hold the object lock. */
1020 AssertReturn(!isWriteLockOnCurrentThread(), VERR_INVALID_STATE);
1021
1022 /* Note: the old code checked if the video mode was actially chnaged and
1023 * did not invalidate the source bitmap if the mode did not change.
1024 * The new code always invalidates the source bitmap, i.e. it will
1025 * notify the frontend even if nothing actually changed.
1026 *
1027 * Implementing the filtering is possible but might lead to pfnSetRenderVRAM races
1028 * between this method and QuerySourceBitmap. Such races can be avoided by implementing
1029 * the @todo below.
1030 */
1031
1032 /* Make sure that the VGA device does not access the source bitmap. */
1033 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && mpDrv)
1034 {
1035 /// @todo It is probably more convenient to implement
1036 // mpDrv->pUpPort->pfnSetOutputBitmap(pvVRAM, cbScanline, cBits, cx, cy, bool fSet);
1037 // and remove IConnector.pbData, cbScanline, cBits, cx, cy.
1038 // fSet = false disables rendering and VGA can check
1039 // if it is already rendering to a different bitmap, avoiding
1040 // enable/disable rendering races.
1041 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, false);
1042
1043 mpDrv->IConnector.pbData = NULL;
1044 mpDrv->IConnector.cbScanline = 0;
1045 mpDrv->IConnector.cBits = 32; /* DevVGA does not work with cBits == 0. */
1046 mpDrv->IConnector.cx = 0;
1047 mpDrv->IConnector.cy = 0;
1048 }
1049
1050 /* Update maFramebuffers[uScreenId] under lock. */
1051 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1052
1053 if (uScreenId >= mcMonitors)
1054 return VINF_SUCCESS;
1055
1056 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1057
1058 /* Whether the monitor position has changed.
1059 * A resize initiated by the VGA device does not change the monitor position.
1060 */
1061 const bool fNewOrigin = !fVGAResize
1062 && ( pFBInfo->xOrigin != xOrigin
1063 || pFBInfo->yOrigin != yOrigin);
1064
1065 /* The event for disabled->enabled transition.
1066 * VGA resizes also come when the guest uses VBVA mode. They do not affect pFBInfo->fDisabled.
1067 * The primary screen is re-enabled when the guest leaves the VBVA mode in i_displayVBVADisable.
1068 */
1069 const bool fGuestMonitorChangedEvent = !fVGAResize
1070 && (pFBInfo->fDisabled != RT_BOOL(flags & VBVA_SCREEN_F_DISABLED));
1071
1072 /* Reset the update mode. */
1073 pFBInfo->updateImage.pSourceBitmap.setNull();
1074 pFBInfo->updateImage.pu8Address = NULL;
1075 pFBInfo->updateImage.cbLine = 0;
1076
1077 /* Release the current source bitmap. */
1078 pFBInfo->pSourceBitmap.setNull();
1079
1080 /* VGA blanking is signaled as w=0, h=0, bpp=0 and cbLine=0, and it's
1081 * best to keep the old resolution, as otherwise the window size would
1082 * change before the new resolution is known. */
1083 const bool fVGABlank = fVGAResize && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
1084 && w == 0 && h == 0 && bpp == 0 && cbLine == 0;
1085 if (fVGABlank)
1086 {
1087 w = pFBInfo->w;
1088 h = pFBInfo->h;
1089 }
1090
1091 /* Update the video mode information. */
1092 pFBInfo->w = w;
1093 pFBInfo->h = h;
1094 pFBInfo->u16BitsPerPixel = (uint16_t)bpp;
1095 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM;
1096 pFBInfo->u32LineSize = cbLine;
1097 if (!fVGAResize)
1098 {
1099 /* Fields which are not used in not VBVA modes and not affected by a VGA resize. */
1100 pFBInfo->flags = flags;
1101 pFBInfo->xOrigin = xOrigin;
1102 pFBInfo->yOrigin = yOrigin;
1103 pFBInfo->fDisabled = RT_BOOL(flags & VBVA_SCREEN_F_DISABLED);
1104 pFBInfo->fVBVAForceResize = false;
1105 }
1106 else
1107 {
1108 pFBInfo->flags = 0;
1109 if (fVGABlank)
1110 pFBInfo->flags |= VBVA_SCREEN_F_BLANK;
1111 pFBInfo->fDisabled = false;
1112 }
1113
1114 /* Prepare local vars for the notification code below. */
1115 ComPtr<IFramebuffer> pFramebuffer = pFBInfo->pFramebuffer;
1116 const bool fDisabled = pFBInfo->fDisabled;
1117
1118 alock.release();
1119
1120 if (!pFramebuffer.isNull())
1121 {
1122 HRESULT hr = pFramebuffer->NotifyChange(uScreenId, 0, 0, w, h); /** @todo origin */
1123 LogFunc(("NotifyChange hr %08X\n", hr));
1124 NOREF(hr);
1125 }
1126
1127 if (fGuestMonitorChangedEvent)
1128 {
1129 if (fDisabled)
1130 fireGuestMonitorChangedEvent(mParent->i_getEventSource(),
1131 GuestMonitorChangedEventType_Disabled,
1132 uScreenId,
1133 0, 0, 0, 0);
1134 else
1135 fireGuestMonitorChangedEvent(mParent->i_getEventSource(),
1136 GuestMonitorChangedEventType_Enabled,
1137 uScreenId,
1138 xOrigin, yOrigin, w, h);
1139 }
1140
1141 if (fNewOrigin)
1142 fireGuestMonitorChangedEvent(mParent->i_getEventSource(),
1143 GuestMonitorChangedEventType_NewOrigin,
1144 uScreenId,
1145 xOrigin, yOrigin, 0, 0);
1146
1147 /* Inform the VRDP server about the change of display parameters. */
1148 LogRelFlowFunc(("Calling VRDP\n"));
1149 mParent->i_consoleVRDPServer()->SendResize();
1150
1151 /* And re-send the seamless rectangles if necessary. */
1152 if (mfSeamlessEnabled)
1153 i_handleSetVisibleRegion(mcRectVisibleRegion, mpRectVisibleRegion);
1154
1155#ifdef VBOX_WITH_VIDEOREC
1156 videoCaptureScreenChanged(uScreenId);
1157#endif
1158
1159#endif /* NEW_RESIZE */
1160
1161 LogRelFlowFunc(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat));
1162
1163 return VINF_SUCCESS;
1164}
1165
1166static void i_checkCoordBounds(int *px, int *py, int *pw, int *ph, int cx, int cy)
1167{
1168 /* Correct negative x and y coordinates. */
1169 if (*px < 0)
1170 {
1171 *px += *pw; /* Compute xRight which is also the new width. */
1172
1173 *pw = (*px < 0)? 0: *px;
1174
1175 *px = 0;
1176 }
1177
1178 if (*py < 0)
1179 {
1180 *py += *ph; /* Compute xBottom, which is also the new height. */
1181
1182 *ph = (*py < 0)? 0: *py;
1183
1184 *py = 0;
1185 }
1186
1187 /* Also check if coords are greater than the display resolution. */
1188 if (*px + *pw > cx)
1189 {
1190 *pw = cx > *px? cx - *px: 0;
1191 }
1192
1193 if (*py + *ph > cy)
1194 {
1195 *ph = cy > *py? cy - *py: 0;
1196 }
1197}
1198
1199void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h)
1200{
1201 /*
1202 * Always runs under either VBVA lock or, for HGSMI, DevVGA lock.
1203 * Safe to use VBVA vars and take the framebuffer lock.
1204 */
1205
1206#ifdef DEBUG_sunlover
1207 LogFlowFunc(("[%d] %d,%d %dx%d\n",
1208 uScreenId, x, y, w, h));
1209#endif /* DEBUG_sunlover */
1210
1211 /* No updates for a disabled guest screen. */
1212 if (maFramebuffers[uScreenId].fDisabled)
1213 return;
1214
1215 /* No updates for a blank guest screen. */
1216 /** @note Disabled for now, as the GUI does not update the picture when we
1217 * first blank. */
1218 /* if (maFramebuffers[uScreenId].flags & VBVA_SCREEN_F_BLANK)
1219 return; */
1220
1221#ifndef NEW_RESIZE
1222 i_checkCoordBounds(&x, &y, &w, &h, maFramebuffers[uScreenId].w,
1223 maFramebuffers[uScreenId].h);
1224
1225 IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;
1226 if (pFramebuffer != NULL)
1227 {
1228 if (w != 0 && h != 0)
1229 {
1230 bool fUpdateImage = RT_BOOL(maFramebuffers[uScreenId].u32Caps & FramebufferCapabilities_UpdateImage);
1231 if (RT_LIKELY(!fUpdateImage))
1232 {
1233 pFramebuffer->NotifyUpdate(x, y, w, h);
1234 }
1235 else
1236 {
1237 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1238
1239 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1240
1241 if (!pFBInfo->updateImage.pSourceBitmap.isNull())
1242 {
1243 Assert(pFBInfo->updateImage.pu8Address);
1244
1245 size_t cbData = w * h * 4;
1246 com::SafeArray<BYTE> image(cbData);
1247
1248 uint8_t *pu8Dst = image.raw();
1249 const uint8_t *pu8Src = pFBInfo->updateImage.pu8Address + pFBInfo->updateImage.cbLine * y + x * 4;
1250
1251 int i;
1252 for (i = y; i < y + h; ++i)
1253 {
1254 memcpy(pu8Dst, pu8Src, w * 4);
1255 pu8Dst += w * 4;
1256 pu8Src += pFBInfo->updateImage.cbLine;
1257 }
1258
1259 pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));
1260 }
1261 }
1262 }
1263 }
1264#else /* NEW_RESIZE */
1265 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1266 AutoReadLock alockr(this COMMA_LOCKVAL_SRC_POS);
1267
1268 ComPtr<IFramebuffer> pFramebuffer = pFBInfo->pFramebuffer;
1269 ComPtr<IDisplaySourceBitmap> pSourceBitmap = pFBInfo->updateImage.pSourceBitmap;
1270
1271 alockr.release();
1272
1273 if (RT_LIKELY(!pFramebuffer.isNull()))
1274 {
1275 if (RT_LIKELY(!RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_UpdateImage)))
1276 {
1277 i_checkCoordBounds(&x, &y, &w, &h, pFBInfo->w, pFBInfo->h);
1278
1279 if (w != 0 && h != 0)
1280 {
1281 pFramebuffer->NotifyUpdate(x, y, w, h);
1282 }
1283 }
1284 else
1285 {
1286 if (RT_LIKELY(!pSourceBitmap.isNull()))
1287 { /* likely */ }
1288 else
1289 {
1290 /* Create a source bitmap if UpdateImage mode is used. */
1291 HRESULT hr = QuerySourceBitmap(uScreenId, pSourceBitmap.asOutParam());
1292 if (SUCCEEDED(hr))
1293 {
1294 BYTE *pAddress = NULL;
1295 ULONG ulWidth = 0;
1296 ULONG ulHeight = 0;
1297 ULONG ulBitsPerPixel = 0;
1298 ULONG ulBytesPerLine = 0;
1299 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
1300
1301 hr = pSourceBitmap->QueryBitmapInfo(&pAddress,
1302 &ulWidth,
1303 &ulHeight,
1304 &ulBitsPerPixel,
1305 &ulBytesPerLine,
1306 &bitmapFormat);
1307 if (SUCCEEDED(hr))
1308 {
1309 AutoWriteLock alockw(this COMMA_LOCKVAL_SRC_POS);
1310
1311 if (pFBInfo->updateImage.pSourceBitmap.isNull())
1312 {
1313 pFBInfo->updateImage.pSourceBitmap = pSourceBitmap;
1314 pFBInfo->updateImage.pu8Address = pAddress;
1315 pFBInfo->updateImage.cbLine = ulBytesPerLine;
1316 }
1317
1318 pSourceBitmap = pFBInfo->updateImage.pSourceBitmap;
1319
1320 alockw.release();
1321 }
1322 }
1323 }
1324
1325 if (RT_LIKELY(!pSourceBitmap.isNull()))
1326 {
1327 BYTE *pbAddress = NULL;
1328 ULONG ulWidth = 0;
1329 ULONG ulHeight = 0;
1330 ULONG ulBitsPerPixel = 0;
1331 ULONG ulBytesPerLine = 0;
1332 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
1333
1334 HRESULT hr = pSourceBitmap->QueryBitmapInfo(&pbAddress,
1335 &ulWidth,
1336 &ulHeight,
1337 &ulBitsPerPixel,
1338 &ulBytesPerLine,
1339 &bitmapFormat);
1340 if (SUCCEEDED(hr))
1341 {
1342 /* Make sure that the requested update is within the source bitmap dimensions. */
1343 i_checkCoordBounds(&x, &y, &w, &h, ulWidth, ulHeight);
1344
1345 if (w != 0 && h != 0)
1346 {
1347 const size_t cbData = w * h * 4;
1348 com::SafeArray<BYTE> image(cbData);
1349
1350 uint8_t *pu8Dst = image.raw();
1351 const uint8_t *pu8Src = pbAddress + ulBytesPerLine * y + x * 4;
1352
1353 int i;
1354 for (i = y; i < y + h; ++i)
1355 {
1356 memcpy(pu8Dst, pu8Src, w * 4);
1357 pu8Dst += w * 4;
1358 pu8Src += ulBytesPerLine;
1359 }
1360
1361 pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));
1362 }
1363 }
1364 }
1365 }
1366 }
1367#endif /* NEW_RESIZE */
1368
1369#ifndef VBOX_WITH_HGSMI
1370 if (!mVideoAccelLegacy.fVideoAccelEnabled)
1371 {
1372#else
1373 if (!mVideoAccelLegacy.fVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)
1374 {
1375#endif /* VBOX_WITH_HGSMI */
1376 /* When VBVA is enabled, the VRDP server is informed
1377 * either in VideoAccelFlush or displayVBVAUpdateProcess.
1378 * Inform the server here only if VBVA is disabled.
1379 */
1380 mParent->i_consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);
1381 }
1382}
1383
1384void Display::i_updateGuestGraphicsFacility(void)
1385{
1386 Guest* pGuest = mParent->i_getGuest();
1387 AssertPtrReturnVoid(pGuest);
1388 /* The following is from GuestImpl.cpp. */
1389 /** @todo A nit: The timestamp is wrong on saved state restore. Would be better
1390 * to move the graphics and seamless capability -> facility translation to
1391 * VMMDev so this could be saved. */
1392 RTTIMESPEC TimeSpecTS;
1393 RTTimeNow(&TimeSpecTS);
1394
1395 if ( mfVMMDevSupportsGraphics
1396 || (mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS) != 0)
1397 pGuest->i_setAdditionsStatus(VBoxGuestFacilityType_Graphics,
1398 VBoxGuestFacilityStatus_Active,
1399 0 /*fFlags*/, &TimeSpecTS);
1400 else
1401 pGuest->i_setAdditionsStatus(VBoxGuestFacilityType_Graphics,
1402 VBoxGuestFacilityStatus_Inactive,
1403 0 /*fFlags*/, &TimeSpecTS);
1404}
1405
1406void Display::i_handleUpdateVMMDevSupportsGraphics(bool fSupportsGraphics)
1407{
1408 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1409 if (mfVMMDevSupportsGraphics == fSupportsGraphics)
1410 return;
1411 mfVMMDevSupportsGraphics = fSupportsGraphics;
1412 i_updateGuestGraphicsFacility();
1413 /* The VMMDev interface notifies the console. */
1414}
1415
1416void Display::i_handleUpdateGuestVBVACapabilities(uint32_t fNewCapabilities)
1417{
1418 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1419 bool fNotify = (fNewCapabilities & VBVACAPS_VIDEO_MODE_HINTS) != (mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS);
1420
1421 mfGuestVBVACapabilities = fNewCapabilities;
1422 if (!fNotify)
1423 return;
1424 i_updateGuestGraphicsFacility();
1425 /* Tell the console about it */
1426 mParent->i_onAdditionsStateChange();
1427}
1428
1429void Display::i_handleUpdateVBVAInputMapping(int32_t xOrigin, int32_t yOrigin, uint32_t cx, uint32_t cy)
1430{
1431 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1432
1433 xInputMappingOrigin = xOrigin;
1434 yInputMappingOrigin = yOrigin;
1435 cxInputMapping = cx;
1436 cyInputMapping = cy;
1437
1438 /* Re-send the seamless rectangles if necessary. */
1439 if (mfSeamlessEnabled)
1440 i_handleSetVisibleRegion(mcRectVisibleRegion, mpRectVisibleRegion);
1441}
1442
1443/**
1444 * Returns the upper left and lower right corners of the virtual framebuffer.
1445 * The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),
1446 * and the origin is (0, 0), not (1, 1) like the GUI returns.
1447 */
1448void Display::i_getFramebufferDimensions(int32_t *px1, int32_t *py1,
1449 int32_t *px2, int32_t *py2)
1450{
1451 int32_t x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1452 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1453
1454 AssertPtrReturnVoid(px1);
1455 AssertPtrReturnVoid(py1);
1456 AssertPtrReturnVoid(px2);
1457 AssertPtrReturnVoid(py2);
1458 LogRelFlowFunc(("\n"));
1459
1460 if (!mpDrv)
1461 return;
1462 /* If VBVA is not in use then this flag will not be set and this
1463 * will still work as it should. */
1464 if (!maFramebuffers[0].fDisabled)
1465 {
1466 x1 = (int32_t)maFramebuffers[0].xOrigin;
1467 y1 = (int32_t)maFramebuffers[0].yOrigin;
1468 x2 = (int32_t)maFramebuffers[0].w + (int32_t)maFramebuffers[0].xOrigin;
1469 y2 = (int32_t)maFramebuffers[0].h + (int32_t)maFramebuffers[0].yOrigin;
1470 }
1471 if (cxInputMapping && cyInputMapping)
1472 {
1473 x1 = xInputMappingOrigin;
1474 y1 = yInputMappingOrigin;
1475 x2 = xInputMappingOrigin + cxInputMapping;
1476 y2 = yInputMappingOrigin + cyInputMapping;
1477 }
1478 else
1479 for (unsigned i = 1; i < mcMonitors; ++i)
1480 {
1481 if (!maFramebuffers[i].fDisabled)
1482 {
1483 x1 = RT_MIN(x1, maFramebuffers[i].xOrigin);
1484 y1 = RT_MIN(y1, maFramebuffers[i].yOrigin);
1485 x2 = RT_MAX(x2, maFramebuffers[i].xOrigin + (int32_t)maFramebuffers[i].w);
1486 y2 = RT_MAX(y2, maFramebuffers[i].yOrigin + (int32_t)maFramebuffers[i].h);
1487 }
1488 }
1489 *px1 = x1;
1490 *py1 = y1;
1491 *px2 = x2;
1492 *py2 = y2;
1493}
1494
1495HRESULT Display::i_reportHostCursorCapabilities(uint32_t fCapabilitiesAdded, uint32_t fCapabilitiesRemoved)
1496{
1497 /* Do we need this to access mParent? I presume that the safe VM pointer
1498 * ensures that mpDrv will remain valid. */
1499 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1500 uint32_t fHostCursorCapabilities = (mfHostCursorCapabilities | fCapabilitiesAdded)
1501 & ~fCapabilitiesRemoved;
1502
1503 Console::SafeVMPtr ptrVM(mParent);
1504 if (!ptrVM.isOk())
1505 return ptrVM.rc();
1506 if (mfHostCursorCapabilities == fHostCursorCapabilities)
1507 return S_OK;
1508 CHECK_CONSOLE_DRV(mpDrv);
1509 alock.release(); /* Release before calling up for lock order reasons. */
1510 mpDrv->pUpPort->pfnReportHostCursorCapabilities(mpDrv->pUpPort, fCapabilitiesAdded, fCapabilitiesRemoved);
1511 mfHostCursorCapabilities = fHostCursorCapabilities;
1512 return S_OK;
1513}
1514
1515HRESULT Display::i_reportHostCursorPosition(int32_t x, int32_t y)
1516{
1517 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1518 uint32_t xAdj = (uint32_t)RT_MAX(x - xInputMappingOrigin, 0);
1519 uint32_t yAdj = (uint32_t)RT_MAX(y - yInputMappingOrigin, 0);
1520 xAdj = RT_MIN(xAdj, cxInputMapping);
1521 yAdj = RT_MIN(yAdj, cyInputMapping);
1522
1523 Console::SafeVMPtr ptrVM(mParent);
1524 if (!ptrVM.isOk())
1525 return ptrVM.rc();
1526 CHECK_CONSOLE_DRV(mpDrv);
1527 alock.release(); /* Release before calling up for lock order reasons. */
1528 mpDrv->pUpPort->pfnReportHostCursorPosition(mpDrv->pUpPort, xAdj, yAdj);
1529 return S_OK;
1530}
1531
1532static bool displayIntersectRect(RTRECT *prectResult,
1533 const RTRECT *prect1,
1534 const RTRECT *prect2)
1535{
1536 /* Initialize result to an empty record. */
1537 memset(prectResult, 0, sizeof(RTRECT));
1538
1539 int xLeftResult = RT_MAX(prect1->xLeft, prect2->xLeft);
1540 int xRightResult = RT_MIN(prect1->xRight, prect2->xRight);
1541
1542 if (xLeftResult < xRightResult)
1543 {
1544 /* There is intersection by X. */
1545
1546 int yTopResult = RT_MAX(prect1->yTop, prect2->yTop);
1547 int yBottomResult = RT_MIN(prect1->yBottom, prect2->yBottom);
1548
1549 if (yTopResult < yBottomResult)
1550 {
1551 /* There is intersection by Y. */
1552
1553 prectResult->xLeft = xLeftResult;
1554 prectResult->yTop = yTopResult;
1555 prectResult->xRight = xRightResult;
1556 prectResult->yBottom = yBottomResult;
1557
1558 return true;
1559 }
1560 }
1561
1562 return false;
1563}
1564
1565int Display::i_saveVisibleRegion(uint32_t cRect, PRTRECT pRect)
1566{
1567 RTRECT *pRectVisibleRegion = NULL;
1568
1569 if (pRect == mpRectVisibleRegion)
1570 return VINF_SUCCESS;
1571 if (cRect != 0)
1572 {
1573 pRectVisibleRegion = (RTRECT *)RTMemAlloc(cRect * sizeof(RTRECT));
1574 if (!pRectVisibleRegion)
1575 {
1576 return VERR_NO_MEMORY;
1577 }
1578 memcpy(pRectVisibleRegion, pRect, cRect * sizeof(RTRECT));
1579 }
1580 if (mpRectVisibleRegion)
1581 RTMemFree(mpRectVisibleRegion);
1582 mcRectVisibleRegion = cRect;
1583 mpRectVisibleRegion = pRectVisibleRegion;
1584 return VINF_SUCCESS;
1585}
1586
1587int Display::i_handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect)
1588{
1589 RTRECT *pVisibleRegion = (RTRECT *)RTMemTmpAlloc( RT_MAX(cRect, 1)
1590 * sizeof(RTRECT));
1591 LogRel2(("%s: cRect=%u\n", __PRETTY_FUNCTION__, cRect));
1592 if (!pVisibleRegion)
1593 {
1594 return VERR_NO_TMP_MEMORY;
1595 }
1596 int rc = i_saveVisibleRegion(cRect, pRect);
1597 if (RT_FAILURE(rc))
1598 {
1599 RTMemTmpFree(pVisibleRegion);
1600 return rc;
1601 }
1602
1603 unsigned uScreenId;
1604 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
1605 {
1606 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1607
1608 if ( !pFBInfo->pFramebuffer.isNull()
1609 && RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_VisibleRegion))
1610 {
1611 /* Prepare a new array of rectangles which intersect with the framebuffer.
1612 */
1613 RTRECT rectFramebuffer;
1614 rectFramebuffer.xLeft = pFBInfo->xOrigin - xInputMappingOrigin;
1615 rectFramebuffer.yTop = pFBInfo->yOrigin - yInputMappingOrigin;
1616 rectFramebuffer.xRight = rectFramebuffer.xLeft + pFBInfo->w;
1617 rectFramebuffer.yBottom = rectFramebuffer.yTop + pFBInfo->h;
1618
1619 uint32_t cRectVisibleRegion = 0;
1620
1621 uint32_t i;
1622 for (i = 0; i < cRect; i++)
1623 {
1624 if (displayIntersectRect(&pVisibleRegion[cRectVisibleRegion], &pRect[i], &rectFramebuffer))
1625 {
1626 pVisibleRegion[cRectVisibleRegion].xLeft -= rectFramebuffer.xLeft;
1627 pVisibleRegion[cRectVisibleRegion].yTop -= rectFramebuffer.yTop;
1628 pVisibleRegion[cRectVisibleRegion].xRight -= rectFramebuffer.xLeft;
1629 pVisibleRegion[cRectVisibleRegion].yBottom -= rectFramebuffer.yTop;
1630
1631 cRectVisibleRegion++;
1632 }
1633 }
1634 pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion);
1635 }
1636 }
1637
1638#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1639 VMMDev *vmmDev = mParent->i_getVMMDev();
1640 if (mfIsCr3DEnabled && vmmDev)
1641 {
1642 if (mhCrOglSvc)
1643 {
1644 VBOXCRCMDCTL_HGCM *pCtl;
1645 pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(RT_MAX(cRect, 1) * sizeof(RTRECT) + sizeof(VBOXCRCMDCTL_HGCM));
1646 if (pCtl)
1647 {
1648 RTRECT *pRectsCopy = (RTRECT*)(pCtl+1);
1649 memcpy(pRectsCopy, pRect, cRect * sizeof(RTRECT));
1650
1651 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1652 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
1653
1654 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
1655 pCtl->aParms[0].u.pointer.addr = pRectsCopy;
1656 pCtl->aParms[0].u.pointer.size = (uint32_t)(cRect * sizeof(RTRECT));
1657
1658 rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);
1659 if (!RT_SUCCESS(rc))
1660 {
1661 AssertMsgFailed(("crCtlSubmit failed (rc=%Rrc)\n", rc));
1662 RTMemFree(pCtl);
1663 }
1664 }
1665 else
1666 AssertMsgFailed(("failed to allocate rects memory\n"));
1667 }
1668 else
1669 AssertMsgFailed(("mhCrOglSvc is NULL\n"));
1670 }
1671#endif
1672
1673 RTMemTmpFree(pVisibleRegion);
1674
1675 return VINF_SUCCESS;
1676}
1677
1678int Display::i_handleQueryVisibleRegion(uint32_t *pcRects, PRTRECT paRects)
1679{
1680 /// @todo Currently not used by the guest and is not implemented in
1681 /// framebuffers. Remove?
1682 RT_NOREF(pcRects, paRects);
1683 return VERR_NOT_SUPPORTED;
1684}
1685
1686#ifdef VBOX_WITH_HGSMI
1687static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId,
1688 uint32_t fu32SupportedOrders,
1689 bool fVideoAccelVRDP,
1690 DISPLAYFBINFO *pFBInfo)
1691{
1692 LogRelFlowFunc(("HGSMI[%d]: %p\n", uScreenId, pFBInfo->pVBVAHostFlags));
1693
1694 if (pFBInfo->pVBVAHostFlags)
1695 {
1696 uint32_t fu32HostEvents = VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
1697
1698 if (pFBInfo->fVBVAEnabled)
1699 {
1700 fu32HostEvents |= VBVA_F_MODE_ENABLED;
1701
1702 if (fVideoAccelVRDP)
1703 {
1704 fu32HostEvents |= VBVA_F_MODE_VRDP;
1705 }
1706 }
1707
1708 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32HostEvents, fu32HostEvents);
1709 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32SupportedOrders, fu32SupportedOrders);
1710
1711 LogRelFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));
1712 }
1713}
1714
1715static void vbvaSetMemoryFlagsAllHGSMI(uint32_t fu32SupportedOrders,
1716 bool fVideoAccelVRDP,
1717 DISPLAYFBINFO *paFBInfos,
1718 unsigned cFBInfos)
1719{
1720 unsigned uScreenId;
1721
1722 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
1723 {
1724 vbvaSetMemoryFlagsHGSMI(uScreenId, fu32SupportedOrders, fVideoAccelVRDP, &paFBInfos[uScreenId]);
1725 }
1726}
1727#endif /* VBOX_WITH_HGSMI */
1728
1729int Display::VideoAccelEnableVMMDev(bool fEnable, VBVAMEMORY *pVbvaMemory)
1730{
1731 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory));
1732 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy);
1733 if (RT_SUCCESS(rc))
1734 {
1735 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort);
1736 videoAccelLeaveVMMDev(&mVideoAccelLegacy);
1737 }
1738 LogFlowFunc(("leave %Rrc\n", rc));
1739 return rc;
1740}
1741
1742int Display::VideoAccelEnableVGA(bool fEnable, VBVAMEMORY *pVbvaMemory)
1743{
1744 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory));
1745 int rc = videoAccelEnterVGA(&mVideoAccelLegacy);
1746 if (RT_SUCCESS(rc))
1747 {
1748 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort);
1749 videoAccelLeaveVGA(&mVideoAccelLegacy);
1750 }
1751 LogFlowFunc(("leave %Rrc\n", rc));
1752 return rc;
1753}
1754
1755void Display::VideoAccelFlushVMMDev(void)
1756{
1757 LogFlowFunc(("enter\n"));
1758 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy);
1759 if (RT_SUCCESS(rc))
1760 {
1761 i_VideoAccelFlush(mpDrv->pUpPort);
1762 videoAccelLeaveVMMDev(&mVideoAccelLegacy);
1763 }
1764 LogFlowFunc(("leave\n"));
1765}
1766
1767/* Called always by one VRDP server thread. Can be thread-unsafe.
1768 */
1769void Display::i_VideoAccelVRDP(bool fEnable)
1770{
1771 LogRelFlowFunc(("fEnable = %d\n", fEnable));
1772
1773 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
1774
1775 int c = fEnable?
1776 ASMAtomicIncS32(&mcVideoAccelVRDPRefs):
1777 ASMAtomicDecS32(&mcVideoAccelVRDPRefs);
1778
1779 Assert (c >= 0);
1780
1781 /* This can run concurrently with Display videoaccel state change. */
1782 RTCritSectEnter(&mVideoAccelLock);
1783
1784 if (c == 0)
1785 {
1786 /* The last client has disconnected, and the accel can be
1787 * disabled.
1788 */
1789 Assert(fEnable == false);
1790
1791 mfVideoAccelVRDP = false;
1792 mfu32SupportedOrders = 0;
1793
1794 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1795 maFramebuffers, mcMonitors);
1796#ifdef VBOX_WITH_HGSMI
1797 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1798 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1799#endif /* VBOX_WITH_HGSMI */
1800
1801 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
1802 }
1803 else if ( c == 1
1804 && !mfVideoAccelVRDP)
1805 {
1806 /* The first client has connected. Enable the accel.
1807 */
1808 Assert(fEnable == true);
1809
1810 mfVideoAccelVRDP = true;
1811 /* Supporting all orders. */
1812 mfu32SupportedOrders = UINT32_MAX;
1813
1814 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1815 maFramebuffers, mcMonitors);
1816#ifdef VBOX_WITH_HGSMI
1817 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1818 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1819#endif /* VBOX_WITH_HGSMI */
1820
1821 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
1822 }
1823 else
1824 {
1825 /* A client is connected or disconnected but there is no change in the
1826 * accel state. It remains enabled.
1827 */
1828 Assert(mfVideoAccelVRDP == true);
1829 }
1830
1831 RTCritSectLeave(&mVideoAccelLock);
1832}
1833
1834void Display::i_notifyPowerDown(void)
1835{
1836 LogRelFlowFunc(("\n"));
1837
1838 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1839
1840 /* Source bitmaps are not available anymore. */
1841 mfSourceBitmapEnabled = false;
1842
1843 alock.release();
1844
1845 /* Resize all displays to tell framebuffers to forget current source bitmap. */
1846 unsigned uScreenId = mcMonitors;
1847 while (uScreenId > 0)
1848 {
1849 --uScreenId;
1850
1851 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1852 if (!pFBInfo->fDisabled)
1853 {
1854#ifndef NEW_RESIZE
1855 i_handleDisplayResize(uScreenId, 32,
1856 pFBInfo->pu8FramebufferVRAM,
1857 pFBInfo->u32LineSize,
1858 pFBInfo->w,
1859 pFBInfo->h,
1860 pFBInfo->flags);
1861#else
1862 i_handleDisplayResize(uScreenId, 32,
1863 pFBInfo->pu8FramebufferVRAM,
1864 pFBInfo->u32LineSize,
1865 pFBInfo->w,
1866 pFBInfo->h,
1867 pFBInfo->flags,
1868 pFBInfo->xOrigin,
1869 pFBInfo->yOrigin,
1870 false);
1871#endif
1872 }
1873 }
1874}
1875
1876// Wrapped IDisplay methods
1877/////////////////////////////////////////////////////////////////////////////
1878HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel,
1879 LONG *aXOrigin, LONG *aYOrigin, GuestMonitorStatus_T *aGuestMonitorStatus)
1880{
1881 LogRelFlowFunc(("aScreenId=%RU32\n", aScreenId));
1882
1883 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1884
1885 if (aScreenId >= mcMonitors)
1886 return E_INVALIDARG;
1887
1888 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1889
1890 GuestMonitorStatus_T guestMonitorStatus = GuestMonitorStatus_Enabled;
1891
1892 if (pFBInfo->flags & VBVA_SCREEN_F_DISABLED)
1893 guestMonitorStatus = GuestMonitorStatus_Disabled;
1894 else if (pFBInfo->flags & (VBVA_SCREEN_F_BLANK | VBVA_SCREEN_F_BLANK2))
1895 guestMonitorStatus = GuestMonitorStatus_Blank;
1896
1897 if (aWidth)
1898 *aWidth = pFBInfo->w;
1899 if (aHeight)
1900 *aHeight = pFBInfo->h;
1901 if (aBitsPerPixel)
1902 *aBitsPerPixel = pFBInfo->u16BitsPerPixel;
1903 if (aXOrigin)
1904 *aXOrigin = pFBInfo->xOrigin;
1905 if (aYOrigin)
1906 *aYOrigin = pFBInfo->yOrigin;
1907 if (aGuestMonitorStatus)
1908 *aGuestMonitorStatus = guestMonitorStatus;
1909
1910 return S_OK;
1911}
1912
1913
1914HRESULT Display::attachFramebuffer(ULONG aScreenId, const ComPtr<IFramebuffer> &aFramebuffer, com::Guid &aId)
1915{
1916 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
1917
1918 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1919
1920 if (aScreenId >= mcMonitors)
1921 return setError(E_INVALIDARG, tr("AttachFramebuffer: Invalid screen %d (total %d)"),
1922 aScreenId, mcMonitors);
1923
1924 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1925 if (!pFBInfo->pFramebuffer.isNull())
1926 return setError(E_FAIL, tr("AttachFramebuffer: Framebuffer already attached to %d"),
1927 aScreenId);
1928
1929 pFBInfo->pFramebuffer = aFramebuffer;
1930 pFBInfo->framebufferId.create();
1931 aId = pFBInfo->framebufferId;
1932
1933 SafeArray<FramebufferCapabilities_T> caps;
1934 pFBInfo->pFramebuffer->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(caps));
1935 pFBInfo->u32Caps = 0;
1936 size_t i;
1937 for (i = 0; i < caps.size(); ++i)
1938 pFBInfo->u32Caps |= caps[i];
1939
1940 alock.release();
1941
1942 /* The driver might not have been constructed yet */
1943 if (mpDrv)
1944 {
1945#ifndef NEW_RESIZE
1946 /* Setup the new framebuffer. */
1947 i_handleDisplayResize(aScreenId, pFBInfo->u16BitsPerPixel,
1948 pFBInfo->pu8FramebufferVRAM,
1949 pFBInfo->u32LineSize,
1950 pFBInfo->w,
1951 pFBInfo->h,
1952 pFBInfo->flags);
1953#else
1954 /* Inform the framebuffer about the actual screen size. */
1955 HRESULT hr = aFramebuffer->NotifyChange(aScreenId, 0, 0, pFBInfo->w, pFBInfo->h); /** @todo origin */
1956 LogFunc(("NotifyChange hr %08X\n", hr)); NOREF(hr);
1957
1958 /* Re-send the seamless rectangles if necessary. */
1959 if (mfSeamlessEnabled)
1960 i_handleSetVisibleRegion(mcRectVisibleRegion, mpRectVisibleRegion);
1961#endif
1962 }
1963
1964 Console::SafeVMPtrQuiet ptrVM(mParent);
1965 if (ptrVM.isOk())
1966 {
1967#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1968 if (mfIsCr3DEnabled)
1969 {
1970 VBOXCRCMDCTL_HGCM data;
1971 RT_ZERO(data);
1972 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1973 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
1974
1975 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
1976 data.aParms[0].u.uint32 = aScreenId;
1977
1978 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
1979 AssertRC(vrc);
1980 }
1981#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
1982
1983 VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
1984 3, this, aScreenId, false);
1985 }
1986
1987 LogRelFlowFunc(("Attached to %d %RTuuid\n", aScreenId, aId.raw()));
1988 return S_OK;
1989}
1990
1991HRESULT Display::detachFramebuffer(ULONG aScreenId, const com::Guid &aId)
1992{
1993 LogRelFlowFunc(("aScreenId = %d %RTuuid\n", aScreenId, aId.raw()));
1994
1995 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1996
1997 if (aScreenId >= mcMonitors)
1998 return setError(E_INVALIDARG, tr("DetachFramebuffer: Invalid screen %d (total %d)"),
1999 aScreenId, mcMonitors);
2000
2001 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2002
2003 if (pFBInfo->framebufferId != aId)
2004 {
2005 LogRelFlowFunc(("Invalid framebuffer aScreenId = %d, attached %p\n", aScreenId, pFBInfo->framebufferId.raw()));
2006 return setError(E_FAIL, tr("DetachFramebuffer: Invalid framebuffer object"));
2007 }
2008
2009 pFBInfo->pFramebuffer.setNull();
2010 pFBInfo->framebufferId.clear();
2011
2012 alock.release();
2013
2014#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2015 Console::SafeVMPtrQuiet ptrVM(mParent);
2016 if (ptrVM.isOk())
2017 {
2018 if (mfIsCr3DEnabled)
2019 {
2020 VBOXCRCMDCTL_HGCM data;
2021 RT_ZERO(data);
2022 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2023 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
2024
2025 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
2026 data.aParms[0].u.uint32 = aScreenId;
2027
2028 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
2029 AssertRC(vrc);
2030 }
2031 }
2032#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
2033
2034 return S_OK;
2035}
2036
2037HRESULT Display::queryFramebuffer(ULONG aScreenId, ComPtr<IFramebuffer> &aFramebuffer)
2038{
2039 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2040
2041 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2042
2043 if (aScreenId >= mcMonitors)
2044 return setError(E_INVALIDARG, tr("QueryFramebuffer: Invalid screen %d (total %d)"),
2045 aScreenId, mcMonitors);
2046
2047 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2048
2049 pFBInfo->pFramebuffer.queryInterfaceTo(aFramebuffer.asOutParam());
2050
2051 return S_OK;
2052}
2053
2054HRESULT Display::setVideoModeHint(ULONG aDisplay, BOOL aEnabled,
2055 BOOL aChangeOrigin, LONG aOriginX, LONG aOriginY,
2056 ULONG aWidth, ULONG aHeight, ULONG aBitsPerPixel)
2057{
2058 if (aWidth == 0 || aHeight == 0 || aBitsPerPixel == 0)
2059 {
2060 /* Some of parameters must not change. Query current mode. */
2061 ULONG ulWidth = 0;
2062 ULONG ulHeight = 0;
2063 ULONG ulBitsPerPixel = 0;
2064 HRESULT hr = getScreenResolution(aDisplay, &ulWidth, &ulHeight, &ulBitsPerPixel, NULL, NULL, NULL);
2065 if (FAILED(hr))
2066 return hr;
2067
2068 /* Assign current values to not changing parameters. */
2069 if (aWidth == 0)
2070 aWidth = ulWidth;
2071 if (aHeight == 0)
2072 aHeight = ulHeight;
2073 if (aBitsPerPixel == 0)
2074 aBitsPerPixel = ulBitsPerPixel;
2075 }
2076
2077 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2078
2079 if (aDisplay >= mcMonitors)
2080 return E_INVALIDARG;
2081
2082 CHECK_CONSOLE_DRV(mpDrv);
2083
2084 /*
2085 * It is up to the guest to decide whether the hint is
2086 * valid. Therefore don't do any VRAM sanity checks here.
2087 */
2088
2089 /* Have to release the lock because the pfnRequestDisplayChange
2090 * will call EMT. */
2091 alock.release();
2092
2093 /* We always send the hint to the graphics card in case the guest enables
2094 * support later. For now we notify exactly when support is enabled. */
2095 mpDrv->pUpPort->pfnSendModeHint(mpDrv->pUpPort, aWidth, aHeight,
2096 aBitsPerPixel, aDisplay,
2097 aChangeOrigin ? aOriginX : ~0,
2098 aChangeOrigin ? aOriginY : ~0,
2099 RT_BOOL(aEnabled),
2100 mfGuestVBVACapabilities
2101 & VBVACAPS_VIDEO_MODE_HINTS);
2102 if ( mfGuestVBVACapabilities & VBVACAPS_VIDEO_MODE_HINTS
2103 && !(mfGuestVBVACapabilities & VBVACAPS_IRQ))
2104 {
2105 mParent->i_sendACPIMonitorHotPlugEvent();
2106 }
2107
2108 /* We currently never suppress the VMMDev hint if the guest has requested
2109 * it. Specifically the video graphics driver may not be responsible for
2110 * screen positioning in the guest virtual desktop, and the component
2111 * responsible may want to get the hint from VMMDev. */
2112 VMMDev *pVMMDev = mParent->i_getVMMDev();
2113 if (pVMMDev)
2114 {
2115 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
2116 if (pVMMDevPort)
2117 pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel,
2118 aDisplay, aOriginX, aOriginY,
2119 RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin));
2120 }
2121 return S_OK;
2122}
2123
2124HRESULT Display::setSeamlessMode(BOOL enabled)
2125{
2126 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2127
2128 /* Have to release the lock because the pfnRequestSeamlessChange will call EMT. */
2129 alock.release();
2130
2131 VMMDev *pVMMDev = mParent->i_getVMMDev();
2132 if (pVMMDev)
2133 {
2134 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
2135 if (pVMMDevPort)
2136 pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled);
2137 }
2138 mfSeamlessEnabled = RT_BOOL(enabled);
2139
2140#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2141 if (!enabled)
2142 {
2143 VMMDev *vmmDev = mParent->i_getVMMDev();
2144 if (mfIsCr3DEnabled && vmmDev)
2145 {
2146 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM));
2147 if (!pData)
2148 {
2149 AssertMsgFailed(("RTMemAlloc failed\n"));
2150 return VERR_NO_MEMORY;
2151 }
2152
2153 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2154 pData->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
2155
2156 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2157 pData->aParms[0].u.pointer.addr = NULL;
2158 pData->aParms[0].u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */
2159
2160 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
2161 if (!RT_SUCCESS(rc))
2162 {
2163 AssertMsgFailed(("crCtlSubmit failed (rc=%Rrc)\n", rc));
2164 RTMemFree(pData);
2165 }
2166 }
2167 }
2168#endif
2169 return S_OK;
2170}
2171
2172#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2173BOOL Display::i_displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pbData,
2174 uint32_t u32Width, uint32_t u32Height)
2175{
2176 if ( pDisplay->mfIsCr3DEnabled
2177 && pDisplay->mCrOglCallbacks.pfnHasData
2178 && pDisplay->mCrOglCallbacks.pfnHasData())
2179 {
2180 VMMDev *pVMMDev = pDisplay->mParent->i_getVMMDev();
2181 if (pVMMDev)
2182 {
2183 CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT *)RTMemAlloc(sizeof(*pScreenshot));
2184 if (pScreenshot)
2185 {
2186 /* screen id or CRSCREEN_ALL to specify all enabled */
2187 pScreenshot->u32Screen = aScreenId;
2188 pScreenshot->u32Width = u32Width;
2189 pScreenshot->u32Height = u32Height;
2190 pScreenshot->u32Pitch = u32Width * 4;
2191 pScreenshot->pvBuffer = pbData;
2192 pScreenshot->pvContext = NULL;
2193 pScreenshot->pfnScreenshotBegin = NULL;
2194 pScreenshot->pfnScreenshotPerform = NULL;
2195 pScreenshot->pfnScreenshotEnd = NULL;
2196
2197 VBOXCRCMDCTL_HGCM data;
2198 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2199 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
2200
2201 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2202 data.aParms[0].u.pointer.addr = pScreenshot;
2203 data.aParms[0].u.pointer.size = sizeof(*pScreenshot);
2204
2205 int rc = pDisplay->i_crCtlSubmitSync(&data.Hdr, sizeof(data));
2206
2207 RTMemFree(pScreenshot);
2208
2209 if (RT_SUCCESS(rc))
2210 return TRUE;
2211 AssertMsgFailed(("failed to get screenshot data from crOgl (rc=%Rrc)\n", rc));
2212 /* fall back to the non-3d mechanism */
2213 }
2214 }
2215 }
2216 return FALSE;
2217}
2218#endif
2219
2220/* static */
2221int Display::i_displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppbData, size_t *pcbData,
2222 uint32_t *pcx, uint32_t *pcy, bool *pfMemFree)
2223{
2224 int rc;
2225 if ( aScreenId == VBOX_VIDEO_PRIMARY_SCREEN
2226 && pDisplay->maFramebuffers[aScreenId].fVBVAEnabled == false) /* A non-VBVA mode. */
2227 {
2228 if (pDisplay->mpDrv)
2229 {
2230 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppbData, pcbData, pcx, pcy);
2231 *pfMemFree = false;
2232 }
2233 else
2234 {
2235 /* No image. */
2236 *ppbData = NULL;
2237 *pcbData = 0;
2238 *pcx = 0;
2239 *pcy = 0;
2240 *pfMemFree = true;
2241 rc = VINF_SUCCESS;
2242 }
2243 }
2244 else if (aScreenId < pDisplay->mcMonitors)
2245 {
2246 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
2247
2248 uint32_t width = pFBInfo->w;
2249 uint32_t height = pFBInfo->h;
2250
2251 /* Allocate 32 bit per pixel bitmap. */
2252 size_t cbRequired = width * 4 * height;
2253
2254 if (cbRequired)
2255 {
2256 uint8_t *pbDst = (uint8_t *)RTMemAlloc(cbRequired);
2257 if (pbDst != NULL)
2258 {
2259 if (pFBInfo->flags & VBVA_SCREEN_F_ACTIVE)
2260 {
2261 /* Copy guest VRAM to the allocated 32bpp buffer. */
2262 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
2263 int32_t xSrc = 0;
2264 int32_t ySrc = 0;
2265 uint32_t u32SrcWidth = width;
2266 uint32_t u32SrcHeight = height;
2267 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
2268 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2269
2270 int32_t xDst = 0;
2271 int32_t yDst = 0;
2272 uint32_t u32DstWidth = u32SrcWidth;
2273 uint32_t u32DstHeight = u32SrcHeight;
2274 uint32_t u32DstLineSize = u32DstWidth * 4;
2275 uint32_t u32DstBitsPerPixel = 32;
2276
2277 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2278 width, height,
2279 pu8Src,
2280 xSrc, ySrc,
2281 u32SrcWidth, u32SrcHeight,
2282 u32SrcLineSize, u32SrcBitsPerPixel,
2283 pbDst,
2284 xDst, yDst,
2285 u32DstWidth, u32DstHeight,
2286 u32DstLineSize, u32DstBitsPerPixel);
2287 }
2288 else
2289 {
2290 memset(pbDst, 0, cbRequired);
2291 rc = VINF_SUCCESS;
2292 }
2293 if (RT_SUCCESS(rc))
2294 {
2295 *ppbData = pbDst;
2296 *pcbData = cbRequired;
2297 *pcx = width;
2298 *pcy = height;
2299 *pfMemFree = true;
2300 }
2301 else
2302 {
2303 RTMemFree(pbDst);
2304
2305 /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */
2306 if ( rc == VERR_INVALID_STATE
2307 && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2308 {
2309 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppbData, pcbData, pcx, pcy);
2310 *pfMemFree = false;
2311 }
2312 }
2313 }
2314 else
2315 rc = VERR_NO_MEMORY;
2316 }
2317 else
2318 {
2319 /* No image. */
2320 *ppbData = NULL;
2321 *pcbData = 0;
2322 *pcx = 0;
2323 *pcy = 0;
2324 *pfMemFree = true;
2325 rc = VINF_SUCCESS;
2326 }
2327 }
2328 else
2329 rc = VERR_INVALID_PARAMETER;
2330 return rc;
2331}
2332
2333static int i_displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId,
2334 BYTE *address, ULONG width, ULONG height)
2335{
2336#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2337 /*
2338 * CrOgl screenshot hook/hack.
2339 */
2340 if (Display::i_displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t *)address, width, height))
2341 return VINF_SUCCESS;
2342#endif
2343
2344 uint8_t *pbData = NULL;
2345 size_t cbData = 0;
2346 uint32_t cx = 0;
2347 uint32_t cy = 0;
2348 bool fFreeMem = false;
2349 int vrc = VINF_SUCCESS;
2350
2351 int cRetries = 5;
2352 while (cRetries-- > 0)
2353 {
2354 /* Note! Not sure if the priority call is such a good idea here, but
2355 it would be nice to have an accurate screenshot for the bug
2356 report if the VM deadlocks. */
2357 vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::i_displayTakeScreenshotEMT, 7,
2358 pDisplay, aScreenId, &pbData, &cbData, &cx, &cy, &fFreeMem);
2359 if (vrc != VERR_TRY_AGAIN)
2360 {
2361 break;
2362 }
2363
2364 RTThreadSleep(10);
2365 }
2366
2367 if (RT_SUCCESS(vrc) && pbData)
2368 {
2369 if (cx == width && cy == height)
2370 {
2371 /* No scaling required. */
2372 memcpy(address, pbData, cbData);
2373 }
2374 else
2375 {
2376 /* Scale. */
2377 LogRelFlowFunc(("SCALE: %dx%d -> %dx%d\n", cx, cy, width, height));
2378
2379 uint8_t *dst = address;
2380 uint8_t *src = pbData;
2381 int dstW = width;
2382 int dstH = height;
2383 int srcW = cx;
2384 int srcH = cy;
2385 int iDeltaLine = cx * 4;
2386
2387 BitmapScale32(dst,
2388 dstW, dstH,
2389 src,
2390 iDeltaLine,
2391 srcW, srcH);
2392 }
2393
2394 if (fFreeMem)
2395 RTMemFree(pbData);
2396 else
2397 {
2398 /* This can be called from any thread. */
2399 pDrv->pUpPort->pfnFreeScreenshot(pDrv->pUpPort, pbData);
2400 }
2401 }
2402
2403 return vrc;
2404}
2405
2406HRESULT Display::takeScreenShotWorker(ULONG aScreenId,
2407 BYTE *aAddress,
2408 ULONG aWidth,
2409 ULONG aHeight,
2410 BitmapFormat_T aBitmapFormat,
2411 ULONG *pcbOut)
2412{
2413 HRESULT rc = S_OK;
2414
2415 /* Do not allow too small and too large screenshots. This also filters out negative
2416 * values passed as either 'aWidth' or 'aHeight'.
2417 */
2418 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767);
2419 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767);
2420
2421 if ( aBitmapFormat != BitmapFormat_BGR0
2422 && aBitmapFormat != BitmapFormat_BGRA
2423 && aBitmapFormat != BitmapFormat_RGBA
2424 && aBitmapFormat != BitmapFormat_PNG)
2425 {
2426 return setError(E_NOTIMPL,
2427 tr("Unsupported screenshot format 0x%08X"), aBitmapFormat);
2428 }
2429
2430 Console::SafeVMPtr ptrVM(mParent);
2431 if (!ptrVM.isOk())
2432 return ptrVM.rc();
2433
2434 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, aAddress, aWidth, aHeight);
2435
2436 if (RT_SUCCESS(vrc))
2437 {
2438 const size_t cbData = aWidth * 4 * aHeight;
2439
2440 /* Most of uncompressed formats. */
2441 *pcbOut = (ULONG)cbData;
2442
2443 if (aBitmapFormat == BitmapFormat_BGR0)
2444 {
2445 /* Do nothing. */
2446 }
2447 else if (aBitmapFormat == BitmapFormat_BGRA)
2448 {
2449 uint32_t *pu32 = (uint32_t *)aAddress;
2450 size_t cPixels = aWidth * aHeight;
2451 while (cPixels--)
2452 {
2453 *pu32++ |= UINT32_C(0xFF000000);
2454 }
2455 }
2456 else if (aBitmapFormat == BitmapFormat_RGBA)
2457 {
2458 uint8_t *pu8 = aAddress;
2459 size_t cPixels = aWidth * aHeight;
2460 while (cPixels--)
2461 {
2462 uint8_t u8 = pu8[0];
2463 pu8[0] = pu8[2];
2464 pu8[2] = u8;
2465 pu8[3] = 0xFF;
2466
2467 pu8 += 4;
2468 }
2469 }
2470 else if (aBitmapFormat == BitmapFormat_PNG)
2471 {
2472 uint8_t *pu8PNG = NULL;
2473 uint32_t cbPNG = 0;
2474 uint32_t cxPNG = 0;
2475 uint32_t cyPNG = 0;
2476
2477 vrc = DisplayMakePNG(aAddress, aWidth, aHeight, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 0);
2478 if (RT_SUCCESS(vrc))
2479 {
2480 if (cbPNG <= cbData)
2481 {
2482 memcpy(aAddress, pu8PNG, cbPNG);
2483 *pcbOut = cbPNG;
2484 }
2485 else
2486 {
2487 rc = setError(E_FAIL,
2488 tr("PNG is larger than 32bpp bitmap"));
2489 }
2490 }
2491 else
2492 {
2493 rc = setError(VBOX_E_IPRT_ERROR,
2494 tr("Could not convert screenshot to PNG (%Rrc)"), vrc);
2495 }
2496 RTMemFree(pu8PNG);
2497 }
2498 }
2499 else if (vrc == VERR_TRY_AGAIN)
2500 rc = setError(E_UNEXPECTED,
2501 tr("Screenshot is not available at this time"));
2502 else if (RT_FAILURE(vrc))
2503 rc = setError(VBOX_E_IPRT_ERROR,
2504 tr("Could not take a screenshot (%Rrc)"), vrc);
2505
2506 return rc;
2507}
2508
2509HRESULT Display::takeScreenShot(ULONG aScreenId,
2510 BYTE *aAddress,
2511 ULONG aWidth,
2512 ULONG aHeight,
2513 BitmapFormat_T aBitmapFormat)
2514{
2515 HRESULT rc = S_OK;
2516
2517 LogRelFlowFunc(("[%d] address=%p, width=%d, height=%d, format 0x%08X\n",
2518 aScreenId, aAddress, aWidth, aHeight, aBitmapFormat));
2519
2520 ULONG cbOut = 0;
2521 rc = takeScreenShotWorker(aScreenId, aAddress, aWidth, aHeight, aBitmapFormat, &cbOut);
2522 NOREF(cbOut);
2523
2524 LogRelFlowFunc(("%Rhrc\n", rc));
2525 return rc;
2526}
2527
2528HRESULT Display::takeScreenShotToArray(ULONG aScreenId,
2529 ULONG aWidth,
2530 ULONG aHeight,
2531 BitmapFormat_T aBitmapFormat,
2532 std::vector<BYTE> &aScreenData)
2533{
2534 HRESULT rc = S_OK;
2535
2536 LogRelFlowFunc(("[%d] width=%d, height=%d, format 0x%08X\n",
2537 aScreenId, aWidth, aHeight, aBitmapFormat));
2538
2539 /* Do not allow too small and too large screenshots. This also filters out negative
2540 * values passed as either 'aWidth' or 'aHeight'.
2541 */
2542 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767);
2543 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767);
2544
2545 const size_t cbData = aWidth * 4 * aHeight;
2546 aScreenData.resize(cbData);
2547
2548 ULONG cbOut = 0;
2549 rc = takeScreenShotWorker(aScreenId, &aScreenData.front(), aWidth, aHeight, aBitmapFormat, &cbOut);
2550 if (FAILED(rc))
2551 cbOut = 0;
2552
2553 aScreenData.resize(cbOut);
2554
2555 LogRelFlowFunc(("%Rhrc\n", rc));
2556 return rc;
2557}
2558
2559int Display::i_videoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens))
2560{
2561#ifdef VBOX_WITH_VIDEOREC
2562 com::SafeArray<BOOL> Screens(ComSafeArrayInArg(aScreens));
2563 for (unsigned i = 0; i < Screens.size(); i++)
2564 {
2565 bool fChanged = maVideoRecEnabled[i] != RT_BOOL(Screens[i]);
2566
2567 maVideoRecEnabled[i] = RT_BOOL(Screens[i]);
2568
2569 if (fChanged && i < mcMonitors)
2570 videoCaptureScreenChanged(i);
2571
2572 }
2573 return VINF_SUCCESS;
2574#else
2575 ComSafeArrayNoRef(aScreens);
2576 return VERR_NOT_SUPPORTED;
2577#endif
2578}
2579
2580/**
2581 * Sends belonging audio samples to the video capturing code.
2582 * Does nothing if capturing is disabled or if audio support for video capturing is disabled.
2583 *
2584 * @returns IPRT status code.
2585 * @param pvData Audio data.
2586 * @param cbData Size (in bytes) of audio data.
2587 * @param uTimestampMs Timestamp (in ms) of the audio data.
2588 */
2589int Display::i_videoCaptureSendAudio(const void *pvData, size_t cbData, uint64_t uTimestampMs)
2590{
2591#ifdef VBOX_WITH_AUDIO_VIDEOREC
2592 if (!VideoRecIsEnabled(mpVideoRecCtx))
2593 return VINF_SUCCESS;
2594
2595 return VideoRecSendAudioFrame(mpVideoRecCtx, pvData, cbData, uTimestampMs);
2596#else
2597 RT_NOREF(pvData, cbData, uTimestampMs);
2598 return VERR_NOT_SUPPORTED;
2599#endif
2600}
2601
2602/**
2603 * Start video capturing. Does nothing if capturing is already active.
2604 *
2605 * @returns IPRT status code.
2606 */
2607int Display::i_videoCaptureStart(void)
2608{
2609#ifdef VBOX_WITH_VIDEOREC
2610 if (VideoRecIsEnabled(mpVideoRecCtx))
2611 return VINF_SUCCESS;
2612
2613 int rc = VideoRecContextCreate(mcMonitors, &mpVideoRecCtx);
2614 if (RT_FAILURE(rc))
2615 {
2616 LogFlow(("Failed to create video recording context (%Rrc)!\n", rc));
2617 return rc;
2618 }
2619 ComPtr<IMachine> pMachine = mParent->i_machine();
2620 com::SafeArray<BOOL> screens;
2621 HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens));
2622 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2623 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
2624 maVideoRecEnabled[i] = i < screens.size() && screens[i];
2625 ULONG ulWidth;
2626 hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth);
2627 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2628 ULONG ulHeight;
2629 hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight);
2630 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2631 ULONG ulRate;
2632 hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate);
2633 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2634 ULONG ulFPS;
2635 hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS);
2636 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2637 BSTR strFile;
2638 hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile);
2639 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2640 ULONG ulMaxTime;
2641 hrc = pMachine->COMGETTER(VideoCaptureMaxTime)(&ulMaxTime);
2642 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2643 ULONG ulMaxSize;
2644 hrc = pMachine->COMGETTER(VideoCaptureMaxFileSize)(&ulMaxSize);
2645 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2646 BSTR strOptions;
2647 hrc = pMachine->COMGETTER(VideoCaptureOptions)(&strOptions);
2648 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2649
2650 RTTIMESPEC ts;
2651 RTTimeNow(&ts);
2652 RTTIME time;
2653 RTTimeExplode(&time, &ts);
2654 for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++)
2655 {
2656 char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str());
2657 char *pszSuff = RTPathSuffix(pszAbsPath);
2658 if (pszSuff)
2659 pszSuff = RTStrDup(pszSuff);
2660 RTPathStripSuffix(pszAbsPath);
2661 if (!pszAbsPath)
2662 rc = VERR_INVALID_PARAMETER;
2663 if (!pszSuff)
2664 pszSuff = RTStrDup(".webm");
2665 char *pszName = NULL;
2666 if (RT_SUCCESS(rc))
2667 {
2668 if (mcMonitors > 1)
2669 rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszSuff);
2670 else
2671 rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszSuff);
2672 }
2673 if (RT_SUCCESS(rc))
2674 {
2675 rc = VideoRecStreamInit(mpVideoRecCtx, uScreen,
2676 pszName, ulWidth, ulHeight,
2677 ulRate, ulFPS, ulMaxTime,
2678 ulMaxSize, com::Utf8Str(strOptions).c_str());
2679 if (rc == VERR_ALREADY_EXISTS)
2680 {
2681 RTStrFree(pszName);
2682 pszName = NULL;
2683
2684 if (mcMonitors > 1)
2685 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s",
2686 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
2687 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
2688 uScreen+1, pszSuff);
2689 else
2690 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s",
2691 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
2692 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
2693 pszSuff);
2694 if (RT_SUCCESS(rc))
2695 rc = VideoRecStreamInit(mpVideoRecCtx, uScreen,
2696 pszName, ulWidth, ulHeight, ulRate,
2697 ulFPS, ulMaxTime,
2698 ulMaxSize, com::Utf8Str(strOptions).c_str());
2699 }
2700 }
2701
2702 if (RT_SUCCESS(rc))
2703 {
2704 videoCaptureScreenChanged(uScreen);
2705 }
2706 else
2707 LogRel(("Display::VideoCaptureStart: Failed to initialize video recording context #%u, (%Rrc)\n", uScreen, rc));
2708
2709 RTStrFree(pszName);
2710 RTStrFree(pszSuff);
2711 RTStrFree(pszAbsPath);
2712 }
2713 return rc;
2714#else /* VBOX_WITH_VIDEOREC */
2715 return VERR_NOT_SUPPORTED;
2716#endif
2717}
2718
2719/**
2720 * Stop video capturing. Does nothing if video capturing is not active.
2721 */
2722void Display::i_videoCaptureStop()
2723{
2724#ifdef VBOX_WITH_VIDEOREC
2725 if (!VideoRecIsEnabled(mpVideoRecCtx))
2726 return;
2727
2728 VideoRecContextDestroy(mpVideoRecCtx);
2729 mpVideoRecCtx = NULL;
2730
2731 unsigned uScreenId;
2732 for (uScreenId = 0; uScreenId < mcMonitors; ++uScreenId)
2733 videoCaptureScreenChanged(uScreenId);
2734#endif
2735}
2736
2737#ifdef VBOX_WITH_VIDEOREC
2738void Display::videoCaptureScreenChanged(unsigned uScreenId)
2739{
2740 if ( !VideoRecIsEnabled(mpVideoRecCtx)
2741 || !maVideoRecEnabled[uScreenId])
2742 {
2743 /* Skip recording this screen. */
2744 return;
2745 }
2746
2747 /* Get a new source bitmap which will be used by video capture code. */
2748 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
2749 QuerySourceBitmap(uScreenId, pSourceBitmap.asOutParam());
2750
2751 int rc2 = RTCritSectEnter(&mVideoCaptureLock);
2752 if (RT_SUCCESS(rc2))
2753 {
2754 maFramebuffers[uScreenId].videoCapture.pSourceBitmap = pSourceBitmap;
2755
2756 rc2 = RTCritSectLeave(&mVideoCaptureLock);
2757 AssertRC(rc2);
2758 }
2759}
2760#endif /* VBOX_WITH_VIDEOREC */
2761
2762int Display::i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address,
2763 ULONG x, ULONG y, ULONG width, ULONG height)
2764{
2765 int rc = VINF_SUCCESS;
2766
2767 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
2768
2769 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2770 {
2771 rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height);
2772 }
2773 else if (aScreenId < pDisplay->mcMonitors)
2774 {
2775 /* Copy the bitmap to the guest VRAM. */
2776 const uint8_t *pu8Src = address;
2777 int32_t xSrc = 0;
2778 int32_t ySrc = 0;
2779 uint32_t u32SrcWidth = width;
2780 uint32_t u32SrcHeight = height;
2781 uint32_t u32SrcLineSize = width * 4;
2782 uint32_t u32SrcBitsPerPixel = 32;
2783
2784 uint8_t *pu8Dst = pFBInfo->pu8FramebufferVRAM;
2785 int32_t xDst = x;
2786 int32_t yDst = y;
2787 uint32_t u32DstWidth = pFBInfo->w;
2788 uint32_t u32DstHeight = pFBInfo->h;
2789 uint32_t u32DstLineSize = pFBInfo->u32LineSize;
2790 uint32_t u32DstBitsPerPixel = pFBInfo->u16BitsPerPixel;
2791
2792 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2793 width, height,
2794 pu8Src,
2795 xSrc, ySrc,
2796 u32SrcWidth, u32SrcHeight,
2797 u32SrcLineSize, u32SrcBitsPerPixel,
2798 pu8Dst,
2799 xDst, yDst,
2800 u32DstWidth, u32DstHeight,
2801 u32DstLineSize, u32DstBitsPerPixel);
2802 if (RT_SUCCESS(rc))
2803 {
2804 if (!pFBInfo->pSourceBitmap.isNull())
2805 {
2806 /* Update the changed screen area. When source bitmap uses VRAM directly, just notify
2807 * frontend to update. And for default format, render the guest VRAM to the source bitmap.
2808 */
2809 if ( pFBInfo->fDefaultFormat
2810 && !pFBInfo->fDisabled)
2811 {
2812 BYTE *pAddress = NULL;
2813 ULONG ulWidth = 0;
2814 ULONG ulHeight = 0;
2815 ULONG ulBitsPerPixel = 0;
2816 ULONG ulBytesPerLine = 0;
2817 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
2818
2819 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
2820 &ulWidth,
2821 &ulHeight,
2822 &ulBitsPerPixel,
2823 &ulBytesPerLine,
2824 &bitmapFormat);
2825 if (SUCCEEDED(hrc))
2826 {
2827 pu8Src = pFBInfo->pu8FramebufferVRAM;
2828 xSrc = x;
2829 ySrc = y;
2830 u32SrcWidth = pFBInfo->w;
2831 u32SrcHeight = pFBInfo->h;
2832 u32SrcLineSize = pFBInfo->u32LineSize;
2833 u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2834
2835 /* Default format is 32 bpp. */
2836 pu8Dst = pAddress;
2837 xDst = xSrc;
2838 yDst = ySrc;
2839 u32DstWidth = u32SrcWidth;
2840 u32DstHeight = u32SrcHeight;
2841 u32DstLineSize = u32DstWidth * 4;
2842 u32DstBitsPerPixel = 32;
2843
2844 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2845 width, height,
2846 pu8Src,
2847 xSrc, ySrc,
2848 u32SrcWidth, u32SrcHeight,
2849 u32SrcLineSize, u32SrcBitsPerPixel,
2850 pu8Dst,
2851 xDst, yDst,
2852 u32DstWidth, u32DstHeight,
2853 u32DstLineSize, u32DstBitsPerPixel);
2854 }
2855 }
2856 }
2857
2858 pDisplay->i_handleDisplayUpdate(aScreenId, x, y, width, height);
2859 }
2860 }
2861 else
2862 {
2863 rc = VERR_INVALID_PARAMETER;
2864 }
2865
2866 if (RT_SUCCESS(rc))
2867 pDisplay->mParent->i_consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height);
2868
2869 return rc;
2870}
2871
2872HRESULT Display::drawToScreen(ULONG aScreenId, BYTE *aAddress, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
2873{
2874 /// @todo (r=dmik) this function may take too long to complete if the VM
2875 // is doing something like saving state right now. Which, in case if it
2876 // is called on the GUI thread, will make it unresponsive. We should
2877 // check the machine state here (by enclosing the check and VMRequCall
2878 // within the Console lock to make it atomic).
2879
2880 LogRelFlowFunc(("aAddress=%p, x=%d, y=%d, width=%d, height=%d\n",
2881 (void *)aAddress, aX, aY, aWidth, aHeight));
2882
2883 CheckComArgExpr(aWidth, aWidth != 0);
2884 CheckComArgExpr(aHeight, aHeight != 0);
2885
2886 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2887
2888 CHECK_CONSOLE_DRV(mpDrv);
2889
2890 Console::SafeVMPtr ptrVM(mParent);
2891 if (!ptrVM.isOk())
2892 return ptrVM.rc();
2893
2894 /* Release lock because the call scheduled on EMT may also try to take it. */
2895 alock.release();
2896
2897 /*
2898 * Again we're lazy and make the graphics device do all the
2899 * dirty conversion work.
2900 */
2901 int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_drawToScreenEMT, 7,
2902 this, aScreenId, aAddress, aX, aY, aWidth, aHeight);
2903
2904 /*
2905 * If the function returns not supported, we'll have to do all the
2906 * work ourselves using the framebuffer.
2907 */
2908 HRESULT rc = S_OK;
2909 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
2910 {
2911 /** @todo implement generic fallback for screen blitting. */
2912 rc = E_NOTIMPL;
2913 }
2914 else if (RT_FAILURE(rcVBox))
2915 rc = setError(VBOX_E_IPRT_ERROR,
2916 tr("Could not draw to the screen (%Rrc)"), rcVBox);
2917/// @todo
2918// else
2919// {
2920// /* All ok. Redraw the screen. */
2921// handleDisplayUpdate(x, y, width, height);
2922// }
2923
2924 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2925 return rc;
2926}
2927
2928int Display::i_InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll)
2929{
2930 LogRelFlowFunc(("uId=%d, fUpdateAll %d\n", uId, fUpdateAll));
2931
2932 unsigned uScreenId;
2933 for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++)
2934 {
2935 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2936
2937 if ( !pFBInfo->fVBVAEnabled
2938 && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2939 {
2940 pDisplay->mpDrv->pUpPort->pfnUpdateDisplayAll(pDisplay->mpDrv->pUpPort, /* fFailOnResize = */ true);
2941 }
2942 else
2943 {
2944 if (!pFBInfo->fDisabled)
2945 {
2946 /* Render complete VRAM screen to the framebuffer.
2947 * When framebuffer uses VRAM directly, just notify it to update.
2948 */
2949 if (pFBInfo->fDefaultFormat && !pFBInfo->pSourceBitmap.isNull())
2950 {
2951 BYTE *pAddress = NULL;
2952 ULONG ulWidth = 0;
2953 ULONG ulHeight = 0;
2954 ULONG ulBitsPerPixel = 0;
2955 ULONG ulBytesPerLine = 0;
2956 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
2957
2958 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
2959 &ulWidth,
2960 &ulHeight,
2961 &ulBitsPerPixel,
2962 &ulBytesPerLine,
2963 &bitmapFormat);
2964 if (SUCCEEDED(hrc))
2965 {
2966 uint32_t width = pFBInfo->w;
2967 uint32_t height = pFBInfo->h;
2968
2969 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
2970 int32_t xSrc = 0;
2971 int32_t ySrc = 0;
2972 uint32_t u32SrcWidth = pFBInfo->w;
2973 uint32_t u32SrcHeight = pFBInfo->h;
2974 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
2975 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2976
2977 /* Default format is 32 bpp. */
2978 uint8_t *pu8Dst = pAddress;
2979 int32_t xDst = xSrc;
2980 int32_t yDst = ySrc;
2981 uint32_t u32DstWidth = u32SrcWidth;
2982 uint32_t u32DstHeight = u32SrcHeight;
2983 uint32_t u32DstLineSize = u32DstWidth * 4;
2984 uint32_t u32DstBitsPerPixel = 32;
2985
2986 /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h
2987 * implies resize of Framebuffer is in progress and
2988 * copyrect should not be called.
2989 */
2990 if (ulWidth == pFBInfo->w && ulHeight == pFBInfo->h)
2991 {
2992 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2993 width, height,
2994 pu8Src,
2995 xSrc, ySrc,
2996 u32SrcWidth, u32SrcHeight,
2997 u32SrcLineSize, u32SrcBitsPerPixel,
2998 pu8Dst,
2999 xDst, yDst,
3000 u32DstWidth, u32DstHeight,
3001 u32DstLineSize, u32DstBitsPerPixel);
3002 }
3003 }
3004 }
3005
3006 pDisplay->i_handleDisplayUpdate(uScreenId, 0, 0, pFBInfo->w, pFBInfo->h);
3007 }
3008 }
3009 if (!fUpdateAll)
3010 break;
3011 }
3012 LogRelFlowFunc(("done\n"));
3013 return VINF_SUCCESS;
3014}
3015
3016/**
3017 * Does a full invalidation of the VM display and instructs the VM
3018 * to update it immediately.
3019 *
3020 * @returns COM status code
3021 */
3022
3023HRESULT Display::invalidateAndUpdate()
3024{
3025 LogRelFlowFunc(("\n"));
3026
3027 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3028
3029 CHECK_CONSOLE_DRV(mpDrv);
3030
3031 Console::SafeVMPtr ptrVM(mParent);
3032 if (!ptrVM.isOk())
3033 return ptrVM.rc();
3034
3035 HRESULT rc = S_OK;
3036
3037 LogRelFlowFunc(("Sending DPYUPDATE request\n"));
3038
3039 /* Have to release the lock when calling EMT. */
3040 alock.release();
3041
3042 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3043 3, this, 0, true);
3044 alock.acquire();
3045
3046 if (RT_FAILURE(rcVBox))
3047 rc = setError(VBOX_E_IPRT_ERROR,
3048 tr("Could not invalidate and update the screen (%Rrc)"), rcVBox);
3049
3050 LogRelFlowFunc(("rc=%Rhrc\n", rc));
3051 return rc;
3052}
3053
3054HRESULT Display::invalidateAndUpdateScreen(ULONG aScreenId)
3055{
3056 LogRelFlowFunc(("\n"));
3057
3058 HRESULT rc = S_OK;
3059
3060 Console::SafeVMPtr ptrVM(mParent);
3061 if (!ptrVM.isOk())
3062 return ptrVM.rc();
3063
3064 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3065 3, this, aScreenId, false);
3066 if (RT_FAILURE(rcVBox))
3067 rc = setError(VBOX_E_IPRT_ERROR,
3068 tr("Could not invalidate and update the screen %d (%Rrc)"), aScreenId, rcVBox);
3069
3070 LogRelFlowFunc(("rc=%Rhrc\n", rc));
3071 return rc;
3072}
3073
3074HRESULT Display::completeVHWACommand(BYTE *aCommand)
3075{
3076#ifdef VBOX_WITH_VIDEOHWACCEL
3077 mpDrv->pVBVACallbacks->pfnVHWACommandCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVHWACMD)aCommand);
3078 return S_OK;
3079#else
3080 return E_NOTIMPL;
3081#endif
3082}
3083
3084HRESULT Display::viewportChanged(ULONG aScreenId, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
3085{
3086 AssertMsgReturn(aScreenId < mcMonitors, ("aScreendId=%d mcMonitors=%d\n", aScreenId, mcMonitors), E_INVALIDARG);
3087
3088#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3089 if (mfIsCr3DEnabled)
3090 {
3091 int rc = i_crViewportNotify(aScreenId, aX, aY, aWidth, aHeight);
3092 if (RT_FAILURE(rc))
3093 {
3094 DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId];
3095 pFb->pendingViewportInfo.fPending = true;
3096 pFb->pendingViewportInfo.x = aX;
3097 pFb->pendingViewportInfo.y = aY;
3098 pFb->pendingViewportInfo.width = aWidth;
3099 pFb->pendingViewportInfo.height = aHeight;
3100 }
3101 }
3102#endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */
3103
3104 /* The driver might not have been constructed yet */
3105 if (mpDrv && mpDrv->pUpPort->pfnSetViewport)
3106 mpDrv->pUpPort->pfnSetViewport(mpDrv->pUpPort, aScreenId, aX, aY, aWidth, aHeight);
3107
3108 return S_OK;
3109}
3110
3111HRESULT Display::querySourceBitmap(ULONG aScreenId,
3112 ComPtr<IDisplaySourceBitmap> &aDisplaySourceBitmap)
3113{
3114 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
3115
3116 Console::SafeVMPtr ptrVM(mParent);
3117 if (!ptrVM.isOk())
3118 return ptrVM.rc();
3119
3120 bool fSetRenderVRAM = false;
3121 bool fInvalidate = false;
3122
3123 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3124
3125 if (aScreenId >= mcMonitors)
3126 return setError(E_INVALIDARG, tr("QuerySourceBitmap: Invalid screen %d (total %d)"),
3127 aScreenId, mcMonitors);
3128
3129 if (!mfSourceBitmapEnabled)
3130 {
3131 aDisplaySourceBitmap = NULL;
3132 return E_FAIL;
3133 }
3134
3135 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
3136
3137 /* No source bitmap for a blank guest screen. */
3138 if (pFBInfo->flags & VBVA_SCREEN_F_BLANK)
3139 {
3140 aDisplaySourceBitmap = NULL;
3141 return E_FAIL;
3142 }
3143
3144 HRESULT hr = S_OK;
3145
3146 if (pFBInfo->pSourceBitmap.isNull())
3147 {
3148#ifndef NEW_RESIZE
3149 /* Create a new object. */
3150 ComObjPtr<DisplaySourceBitmap> obj;
3151 hr = obj.createObject();
3152 if (SUCCEEDED(hr))
3153 hr = obj->init(this, aScreenId, pFBInfo);
3154
3155 if (SUCCEEDED(hr))
3156 {
3157 bool fDefaultFormat = !obj->i_usesVRAM();
3158
3159 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3160 {
3161 /* Start buffer updates. */
3162 BYTE *pAddress = NULL;
3163 ULONG ulWidth = 0;
3164 ULONG ulHeight = 0;
3165 ULONG ulBitsPerPixel = 0;
3166 ULONG ulBytesPerLine = 0;
3167 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
3168
3169 obj->QueryBitmapInfo(&pAddress,
3170 &ulWidth,
3171 &ulHeight,
3172 &ulBitsPerPixel,
3173 &ulBytesPerLine,
3174 &bitmapFormat);
3175
3176 mpDrv->IConnector.pbData = pAddress;
3177 mpDrv->IConnector.cbScanline = ulBytesPerLine;
3178 mpDrv->IConnector.cBits = ulBitsPerPixel;
3179 mpDrv->IConnector.cx = ulWidth;
3180 mpDrv->IConnector.cy = ulHeight;
3181
3182 fSetRenderVRAM = fDefaultFormat;
3183 }
3184
3185 /* Make sure that the bitmap contains the latest image. */
3186 fInvalidate = fDefaultFormat;
3187
3188 pFBInfo->pSourceBitmap = obj;
3189 pFBInfo->fDefaultFormat = fDefaultFormat;
3190 }
3191#else /* NEW_RESIZE */
3192 /* Create a new object. */
3193 ComObjPtr<DisplaySourceBitmap> obj;
3194 hr = obj.createObject();
3195 if (SUCCEEDED(hr))
3196 hr = obj->init(this, aScreenId, pFBInfo);
3197
3198 if (SUCCEEDED(hr))
3199 {
3200 pFBInfo->pSourceBitmap = obj;
3201 pFBInfo->fDefaultFormat = !obj->i_usesVRAM();
3202
3203 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3204 {
3205 /* Start buffer updates. */
3206 BYTE *pAddress = NULL;
3207 ULONG ulWidth = 0;
3208 ULONG ulHeight = 0;
3209 ULONG ulBitsPerPixel = 0;
3210 ULONG ulBytesPerLine = 0;
3211 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
3212
3213 pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
3214 &ulWidth,
3215 &ulHeight,
3216 &ulBitsPerPixel,
3217 &ulBytesPerLine,
3218 &bitmapFormat);
3219
3220 mpDrv->IConnector.pbData = pAddress;
3221 mpDrv->IConnector.cbScanline = ulBytesPerLine;
3222 mpDrv->IConnector.cBits = ulBitsPerPixel;
3223 mpDrv->IConnector.cx = ulWidth;
3224 mpDrv->IConnector.cy = ulHeight;
3225
3226 fSetRenderVRAM = pFBInfo->fDefaultFormat;
3227 }
3228
3229 /* Make sure that the bitmap contains the latest image. */
3230 fInvalidate = pFBInfo->fDefaultFormat;
3231 }
3232#endif /* NEW_RESIZE */
3233 }
3234
3235 if (SUCCEEDED(hr))
3236 {
3237 pFBInfo->pSourceBitmap.queryInterfaceTo(aDisplaySourceBitmap.asOutParam());
3238 }
3239
3240 /* Leave the IDisplay lock because the VGA device must not be called under it. */
3241 alock.release();
3242
3243 if (SUCCEEDED(hr))
3244 {
3245 if (fSetRenderVRAM)
3246 {
3247 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
3248 }
3249
3250 if (fInvalidate)
3251 VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3252 3, this, aScreenId, false);
3253 }
3254
3255 LogRelFlowFunc(("%Rhrc\n", hr));
3256 return hr;
3257}
3258
3259HRESULT Display::getGuestScreenLayout(std::vector<ComPtr<IGuestScreenInfo> > &aGuestScreenLayout)
3260{
3261 NOREF(aGuestScreenLayout);
3262 return E_NOTIMPL;
3263}
3264
3265HRESULT Display::setScreenLayout(ScreenLayoutMode_T aScreenLayoutMode,
3266 const std::vector<ComPtr<IGuestScreenInfo> > &aGuestScreenInfo)
3267{
3268 NOREF(aScreenLayoutMode);
3269 NOREF(aGuestScreenInfo);
3270 return E_NOTIMPL;
3271}
3272
3273// wrapped IEventListener method
3274HRESULT Display::handleEvent(const ComPtr<IEvent> &aEvent)
3275{
3276 VBoxEventType_T aType = VBoxEventType_Invalid;
3277
3278 aEvent->COMGETTER(Type)(&aType);
3279 switch (aType)
3280 {
3281 case VBoxEventType_OnStateChanged:
3282 {
3283 ComPtr<IStateChangedEvent> scev = aEvent;
3284 Assert(scev);
3285 MachineState_T machineState;
3286 scev->COMGETTER(State)(&machineState);
3287 if ( machineState == MachineState_Running
3288 || machineState == MachineState_Teleporting
3289 || machineState == MachineState_LiveSnapshotting
3290 || machineState == MachineState_DeletingSnapshotOnline
3291 )
3292 {
3293 LogRelFlowFunc(("Machine is running.\n"));
3294
3295#ifdef VBOX_WITH_CROGL
3296 i_crOglWindowsShow(true);
3297#endif
3298 }
3299 else
3300 {
3301#ifdef VBOX_WITH_CROGL
3302 if (machineState == MachineState_Paused)
3303 i_crOglWindowsShow(false);
3304#endif
3305 }
3306 break;
3307 }
3308 default:
3309 AssertFailed();
3310 }
3311
3312 return S_OK;
3313}
3314
3315
3316// private methods
3317/////////////////////////////////////////////////////////////////////////////
3318
3319#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3320int Display::i_crViewportNotify(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height)
3321{
3322 VMMDev *pVMMDev = mParent->i_getVMMDev();
3323 if (!pVMMDev)
3324 return VERR_INVALID_STATE;
3325
3326 size_t cbData = RT_UOFFSETOF(VBOXCRCMDCTL_HGCM, aParms[5]);
3327 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM *)alloca(cbData);
3328
3329 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
3330 pData->Hdr.u32Function = SHCRGL_HOST_FN_VIEWPORT_CHANGED;
3331
3332 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
3333 pData->aParms[0].u.uint32 = aScreenId;
3334
3335 pData->aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT;
3336 pData->aParms[1].u.uint32 = x;
3337
3338 pData->aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT;
3339 pData->aParms[2].u.uint32 = y;
3340
3341 pData->aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT;
3342 pData->aParms[3].u.uint32 = width;
3343
3344 pData->aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT;
3345 pData->aParms[4].u.uint32 = height;
3346
3347 return i_crCtlSubmitSyncIfHasDataForScreen(aScreenId, &pData->Hdr, (uint32_t)cbData);
3348}
3349#endif
3350
3351#ifdef VBOX_WITH_CRHGSMI
3352void Display::i_setupCrHgsmiData(void)
3353{
3354 VMMDev *pVMMDev = mParent->i_getVMMDev();
3355 Assert(pVMMDev);
3356 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
3357 AssertRC(rc);
3358
3359 if (pVMMDev)
3360 rc = pVMMDev->hgcmHostSvcHandleCreate("VBoxSharedCrOpenGL", &mhCrOglSvc);
3361 else
3362 rc = VERR_GENERAL_FAILURE;
3363
3364 if (RT_SUCCESS(rc))
3365 {
3366 Assert(mhCrOglSvc);
3367 /* setup command completion callback */
3368 VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion;
3369 Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB;
3370 Completion.Hdr.cbCmd = sizeof(Completion);
3371 Completion.hCompletion = mpDrv->pVBVACallbacks;
3372 Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync;
3373
3374 VBOXHGCMSVCPARM parm;
3375 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3376 parm.u.pointer.addr = &Completion;
3377 parm.u.pointer.size = 0;
3378
3379 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm);
3380 if (RT_SUCCESS(rc))
3381 mCrOglCallbacks = Completion.MainInterface;
3382 else
3383 AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed (rc=%Rrc)\n", rc));
3384 }
3385
3386 if (RT_FAILURE(rc))
3387 mhCrOglSvc = NULL;
3388
3389 RTCritSectRwLeaveExcl(&mCrOglLock);
3390}
3391
3392void Display::i_destructCrHgsmiData(void)
3393{
3394 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
3395 AssertRC(rc);
3396 mhCrOglSvc = NULL;
3397 RTCritSectRwLeaveExcl(&mCrOglLock);
3398}
3399#endif /* VBOX_WITH_CRHGSMI */
3400
3401/**
3402 * Handle display resize event issued by the VGA device for the primary screen.
3403 *
3404 * @see PDMIDISPLAYCONNECTOR::pfnResize
3405 */
3406DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
3407 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
3408{
3409 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3410 Display *pThis = pDrv->pDisplay;
3411
3412 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
3413 bpp, pvVRAM, cbLine, cx, cy));
3414
3415 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false);
3416 if (!f)
3417 {
3418 /* This is a result of recursive call when the source bitmap is being updated
3419 * during a VGA resize. Tell the VGA device to ignore the call.
3420 *
3421 * @todo It is a workaround, actually pfnUpdateDisplayAll must
3422 * fail on resize.
3423 */
3424 LogRel(("displayResizeCallback: already processing\n"));
3425 return VINF_VGA_RESIZE_IN_PROGRESS;
3426 }
3427
3428#ifndef NEW_RESIZE
3429 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE);
3430#else
3431 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, 0, 0, 0, true);
3432#endif
3433
3434 /* Restore the flag. */
3435 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true);
3436 AssertRelease(f);
3437
3438 return rc;
3439}
3440
3441/**
3442 * Handle display update.
3443 *
3444 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
3445 */
3446DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
3447 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
3448{
3449 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3450
3451#ifdef DEBUG_sunlover
3452 LogFlowFunc(("fVideoAccelEnabled = %d, %d,%d %dx%d\n",
3453 pDrv->pDisplay->mVideoAccelLegacy.fVideoAccelEnabled, x, y, cx, cy));
3454#endif /* DEBUG_sunlover */
3455
3456 /* This call does update regardless of VBVA status.
3457 * But in VBVA mode this is called only as result of
3458 * pfnUpdateDisplayAll in the VGA device.
3459 */
3460
3461 pDrv->pDisplay->i_handleDisplayUpdate(VBOX_VIDEO_PRIMARY_SCREEN, x, y, cx, cy);
3462}
3463
3464/**
3465 * Periodic display refresh callback.
3466 *
3467 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
3468 * @thread EMT
3469 */
3470/*static*/ DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
3471{
3472 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3473
3474#ifdef DEBUG_sunlover_2
3475 LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
3476 pDrv->pDisplay->mfVideoAccelEnabled));
3477#endif /* DEBUG_sunlover_2 */
3478
3479 Display *pDisplay = pDrv->pDisplay;
3480 unsigned uScreenId;
3481
3482 int rc = pDisplay->i_videoAccelRefreshProcess(pDrv->pUpPort);
3483 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */
3484 {
3485 if (rc == VWRN_INVALID_STATE)
3486 {
3487 /* No VBVA do a display update. */
3488 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
3489 }
3490
3491 /* Inform the VRDP server that the current display update sequence is
3492 * completed. At this moment the framebuffer memory contains a definite
3493 * image, that is synchronized with the orders already sent to VRDP client.
3494 * The server can now process redraw requests from clients or initial
3495 * fullscreen updates for new clients.
3496 */
3497 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
3498 {
3499 Assert(pDisplay->mParent && pDisplay->mParent->i_consoleVRDPServer());
3500 pDisplay->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, NULL, 0);
3501 }
3502 }
3503
3504#ifdef VBOX_WITH_VIDEOREC
3505 if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx))
3506 {
3507 do {
3508# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3509 if (pDisplay->mfIsCr3DEnabled)
3510 {
3511 if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
3512 {
3513 if ( pDisplay->mCrOglCallbacks.pfnHasData
3514 && pDisplay->mCrOglCallbacks.pfnHasData())
3515 {
3516 /* submit */
3517 VBOXCRCMDCTL_HGCM *pData = &pDisplay->mCrOglScreenshotCtl;
3518
3519 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
3520 pData->Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
3521
3522 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
3523 pData->aParms[0].u.pointer.addr = &pDisplay->mCrOglScreenshotData;
3524 pData->aParms[0].u.pointer.size = sizeof(pDisplay->mCrOglScreenshotData);
3525 rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), Display::i_displayVRecCompletion, pDisplay);
3526 if (RT_SUCCESS(rc))
3527 break;
3528 AssertMsgFailed(("crCtlSubmit failed (rc=%Rrc)\n", rc));
3529 }
3530
3531 /* no 3D data available, or error has occured,
3532 * go the straight way */
3533 ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE);
3534 }
3535 else
3536 {
3537 /* record request is still in progress, don't do anything */
3538 break;
3539 }
3540 }
3541# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
3542
3543 uint64_t u64Now = RTTimeProgramMilliTS();
3544 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
3545 {
3546 if (!pDisplay->maVideoRecEnabled[uScreenId])
3547 continue;
3548
3549 if (VideoRecIsLimitReached(pDisplay->mpVideoRecCtx, uScreenId, u64Now))
3550 {
3551 pDisplay->i_videoCaptureStop();
3552 pDisplay->mParent->i_machine()->COMSETTER(VideoCaptureEnabled)(false);
3553 break;
3554 }
3555
3556 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
3557 if (!pFBInfo->fDisabled)
3558 {
3559 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
3560 int rc2 = RTCritSectEnter(&pDisplay->mVideoCaptureLock);
3561 if (RT_SUCCESS(rc2))
3562 {
3563 pSourceBitmap = pFBInfo->videoCapture.pSourceBitmap;
3564 RTCritSectLeave(&pDisplay->mVideoCaptureLock);
3565 }
3566
3567 if (!pSourceBitmap.isNull())
3568 {
3569 BYTE *pbAddress = NULL;
3570 ULONG ulWidth = 0;
3571 ULONG ulHeight = 0;
3572 ULONG ulBitsPerPixel = 0;
3573 ULONG ulBytesPerLine = 0;
3574 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
3575 HRESULT hr = pSourceBitmap->QueryBitmapInfo(&pbAddress,
3576 &ulWidth,
3577 &ulHeight,
3578 &ulBitsPerPixel,
3579 &ulBytesPerLine,
3580 &bitmapFormat);
3581 if (SUCCEEDED(hr) && pbAddress)
3582 rc = VideoRecSendVideoFrame(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
3583 BitmapFormat_BGR,
3584 ulBitsPerPixel, ulBytesPerLine, ulWidth, ulHeight,
3585 pbAddress, u64Now);
3586 else
3587 rc = VERR_NOT_SUPPORTED;
3588
3589 pSourceBitmap.setNull();
3590 }
3591 else
3592 rc = VERR_NOT_SUPPORTED;
3593
3594 if (rc == VINF_TRY_AGAIN)
3595 break;
3596 }
3597 }
3598 } while (0);
3599 }
3600#endif /* VBOX_WITH_VIDEOREC */
3601
3602#ifdef DEBUG_sunlover_2
3603 LogFlowFunc(("leave\n"));
3604#endif /* DEBUG_sunlover_2 */
3605}
3606
3607/**
3608 * Reset notification
3609 *
3610 * @see PDMIDISPLAYCONNECTOR::pfnReset
3611 */
3612DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
3613{
3614 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3615
3616 LogRelFlowFunc(("\n"));
3617
3618 /* Disable VBVA mode. */
3619 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
3620}
3621
3622/**
3623 * LFBModeChange notification
3624 *
3625 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
3626 */
3627DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
3628{
3629 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3630
3631 LogRelFlowFunc(("fEnabled=%d\n", fEnabled));
3632
3633 NOREF(fEnabled);
3634
3635 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
3636 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
3637}
3638
3639/**
3640 * Adapter information change notification.
3641 *
3642 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
3643 */
3644DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
3645 uint32_t u32VRAMSize)
3646{
3647 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3648 pDrv->pDisplay->processAdapterData(pvVRAM, u32VRAMSize);
3649}
3650
3651/**
3652 * Display information change notification.
3653 *
3654 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
3655 */
3656DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface,
3657 void *pvVRAM, unsigned uScreenId)
3658{
3659 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3660 pDrv->pDisplay->processDisplayData(pvVRAM, uScreenId);
3661}
3662
3663#ifdef VBOX_WITH_VIDEOHWACCEL
3664
3665#ifndef S_FALSE
3666# define S_FALSE ((HRESULT)1L)
3667#endif
3668
3669int Display::i_handleVHWACommandProcess(PVBOXVHWACMD pCommand)
3670{
3671 unsigned id = (unsigned)pCommand->iDisplay;
3672 if (id >= mcMonitors)
3673 return VERR_INVALID_PARAMETER;
3674
3675 ComPtr<IFramebuffer> pFramebuffer;
3676 AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS);
3677 pFramebuffer = maFramebuffers[id].pFramebuffer;
3678 bool fVHWASupported = RT_BOOL(maFramebuffers[id].u32Caps & FramebufferCapabilities_VHWA);
3679 arlock.release();
3680
3681 if (pFramebuffer == NULL || !fVHWASupported)
3682 return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */
3683
3684 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);
3685 if (hr == S_FALSE)
3686 return VINF_SUCCESS;
3687 if (SUCCEEDED(hr))
3688 return VINF_CALLBACK_RETURN;
3689 if (hr == E_ACCESSDENIED)
3690 return VERR_INVALID_STATE; /* notify we can not handle request atm */
3691 if (hr == E_NOTIMPL)
3692 return VERR_NOT_IMPLEMENTED;
3693 return VERR_GENERAL_FAILURE;
3694}
3695
3696DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
3697{
3698 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3699
3700 return pDrv->pDisplay->i_handleVHWACommandProcess(pCommand);
3701}
3702#endif
3703
3704#ifdef VBOX_WITH_CRHGSMI
3705void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3706{
3707 RT_NOREF(u32Function);
3708 mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks,
3709 (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);
3710}
3711
3712void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3713{
3714 RT_NOREF(u32Function);
3715 PVBOXVDMACMD_CHROMIUM_CTL pCtl = (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr;
3716 mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, pCtl, result);
3717}
3718
3719void Display::i_handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)
3720{
3721 int rc = VERR_NOT_SUPPORTED;
3722 VBOXHGCMSVCPARM parm;
3723 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3724 parm.u.pointer.addr = pCmd;
3725 parm.u.pointer.size = cbCmd;
3726
3727 if (mhCrOglSvc)
3728 {
3729 VMMDev *pVMMDev = mParent->i_getVMMDev();
3730 if (pVMMDev)
3731 {
3732 /* no completion callback is specified with this call,
3733 * the CrOgl code will complete the CrHgsmi command once it processes it */
3734 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, NULL, NULL);
3735 AssertRC(rc);
3736 if (RT_SUCCESS(rc))
3737 return;
3738 }
3739 else
3740 rc = VERR_INVALID_STATE;
3741 }
3742
3743 /* we are here because something went wrong with command processing, complete it */
3744 i_handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm);
3745}
3746
3747void Display::i_handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)
3748{
3749 int rc = VERR_NOT_SUPPORTED;
3750 VBOXHGCMSVCPARM parm;
3751 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3752 parm.u.pointer.addr = pCtl;
3753 parm.u.pointer.size = cbCtl;
3754
3755 if (mhCrOglSvc)
3756 {
3757 VMMDev *pVMMDev = mParent->i_getVMMDev();
3758 if (pVMMDev)
3759 {
3760 bool fCheckPendingViewport = (pCtl->enmType == VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP);
3761 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm,
3762 Display::i_displayCrHgsmiControlCompletion, this);
3763 AssertRC(rc);
3764 if (RT_SUCCESS(rc))
3765 {
3766 if (fCheckPendingViewport)
3767 {
3768 ULONG ul;
3769 for (ul = 0; ul < mcMonitors; ul++)
3770 {
3771 DISPLAYFBINFO *pFb = &maFramebuffers[ul];
3772 if (!pFb->pendingViewportInfo.fPending)
3773 continue;
3774
3775 rc = i_crViewportNotify(ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y,
3776 pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height);
3777 if (RT_SUCCESS(rc))
3778 pFb->pendingViewportInfo.fPending = false;
3779 else
3780 {
3781 AssertMsgFailed(("crViewportNotify failed (rc=%Rrc)\n", rc));
3782 rc = VINF_SUCCESS;
3783 }
3784 }
3785 }
3786 return;
3787 }
3788 }
3789 else
3790 rc = VERR_INVALID_STATE;
3791 }
3792
3793 /* we are here because something went wrong with command processing, complete it */
3794 i_handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm);
3795}
3796
3797DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,
3798 uint32_t cbCmd)
3799{
3800 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3801
3802 pDrv->pDisplay->i_handleCrHgsmiCommandProcess(pCmd, cbCmd);
3803}
3804
3805DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,
3806 uint32_t cbCmd)
3807{
3808 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3809
3810 pDrv->pDisplay->i_handleCrHgsmiControlProcess(pCmd, cbCmd);
3811}
3812
3813DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3814 void *pvContext)
3815{
3816 AssertMsgFailed(("not expected!\n"));
3817 Display *pDisplay = (Display *)pvContext;
3818 pDisplay->i_handleCrHgsmiCommandCompletion(result, u32Function, pParam);
3819}
3820
3821DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3822 void *pvContext)
3823{
3824 Display *pDisplay = (Display *)pvContext;
3825 pDisplay->i_handleCrHgsmiControlCompletion(result, u32Function, pParam);
3826
3827}
3828#endif
3829
3830#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3831DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3832 void *pvContext)
3833{
3834 RT_NOREF(u32Function);
3835 VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;
3836 if (pCmd->u.pfnInternal)
3837 ((PFNCRCTLCOMPLETION)pCmd->u.pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);
3838}
3839
3840int Display::i_handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3841 PFNCRCTLCOMPLETION pfnCompletion,
3842 void *pvCompletion)
3843{
3844 VMMDev *pVMMDev = mParent ? mParent->i_getVMMDev() : NULL;
3845 if (!pVMMDev)
3846 {
3847 AssertMsgFailed(("no vmmdev\n"));
3848 return VERR_INVALID_STATE;
3849 }
3850
3851 Assert(mhCrOglSvc);
3852 VBOXHGCMSVCPARM parm;
3853 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3854 parm.u.pointer.addr = pCmd;
3855 parm.u.pointer.size = cbCmd;
3856
3857 pCmd->u.pfnInternal = (void(*)())pfnCompletion;
3858 int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,
3859 pvCompletion);
3860 if (!RT_SUCCESS(rc))
3861 AssertMsgFailed(("hgcmHostFastCallAsync failed (rc=%Rrc)\n", rc));
3862
3863 return rc;
3864}
3865
3866DECLCALLBACK(int) Display::i_displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
3867 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3868 PFNCRCTLCOMPLETION pfnCompletion,
3869 void *pvCompletion)
3870{
3871 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3872 Display *pThis = pDrv->pDisplay;
3873 return pThis->i_handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);
3874}
3875
3876int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)
3877{
3878 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3879 if (RT_SUCCESS(rc))
3880 {
3881 if (mhCrOglSvc)
3882 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);
3883 else
3884 rc = VERR_NOT_SUPPORTED;
3885
3886 RTCritSectRwLeaveShared(&mCrOglLock);
3887 }
3888 return rc;
3889}
3890
3891int Display::i_crCtlSubmitSync(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3892{
3893 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3894 if (RT_SUCCESS(rc))
3895 {
3896 if (mhCrOglSvc)
3897 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmitSync(mpDrv->pVBVACallbacks, pCmd, cbCmd);
3898 else
3899 rc = VERR_NOT_SUPPORTED;
3900
3901 RTCritSectRwLeaveShared(&mCrOglLock);
3902 }
3903 return rc;
3904}
3905
3906int Display::i_crCtlSubmitAsyncCmdCopy(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3907{
3908 VBOXCRCMDCTL* pCmdCopy = (VBOXCRCMDCTL*)RTMemAlloc(cbCmd);
3909 if (!pCmdCopy)
3910 {
3911 LogRel(("RTMemAlloc failed\n"));
3912 return VERR_NO_MEMORY;
3913 }
3914
3915 memcpy(pCmdCopy, pCmd, cbCmd);
3916
3917 int rc = i_crCtlSubmit(pCmdCopy, cbCmd, i_displayCrCmdFree, pCmdCopy);
3918 if (RT_FAILURE(rc))
3919 {
3920 LogRel(("crCtlSubmit failed (rc=%Rrc)\n", rc));
3921 RTMemFree(pCmdCopy);
3922 return rc;
3923 }
3924
3925 return VINF_SUCCESS;
3926}
3927
3928int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3929{
3930 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3931 AssertRCReturn(rc, rc);
3932
3933 if ( mCrOglCallbacks.pfnHasDataForScreen
3934 && mCrOglCallbacks.pfnHasDataForScreen(u32ScreenID))
3935 rc = i_crCtlSubmitSync(pCmd, cbCmd);
3936 else
3937 rc = i_crCtlSubmitAsyncCmdCopy(pCmd, cbCmd);
3938
3939 RTCritSectRwLeaveShared(&mCrOglLock);
3940
3941 return rc;
3942}
3943
3944bool Display::i_handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64Timestamp)
3945{
3946 /** @todo r=bird: u64Timestamp - using the 'u64' prefix add nothing.
3947 * However, using one of the prefixes indicating the timestamp unit
3948 * would be very valuable! */
3949# ifdef VBOX_WITH_VIDEOREC
3950 return VideoRecIsReady(mpVideoRecCtx, uScreen, u64Timestamp);
3951# else
3952 RT_NOREF(uScreen, u64Timestamp);
3953 return false;
3954# endif
3955}
3956
3957void Display::i_handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64Timestamp)
3958{
3959 RT_NOREF(uScreen, u64Timestamp);
3960}
3961
3962void Display::i_handleCrVRecScreenshotPerform(uint32_t uScreen,
3963 uint32_t x, uint32_t y, uint32_t uPixelFormat,
3964 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
3965 uint32_t uGuestWidth, uint32_t uGuestHeight,
3966 uint8_t *pu8BufferAddress, uint64_t u64Timestamp)
3967{
3968 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3969# ifdef VBOX_WITH_VIDEOREC
3970 int rc = VideoRecSendVideoFrame(mpVideoRecCtx, uScreen, x, y,
3971 uPixelFormat,
3972 uBitsPerPixel, uBytesPerLine,
3973 uGuestWidth, uGuestHeight,
3974 pu8BufferAddress, u64Timestamp);
3975 NOREF(rc);
3976 Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/);
3977# else
3978 RT_NOREF(uScreen, x, y, uPixelFormat, \
3979 uBitsPerPixel, uBytesPerLine, uGuestWidth, uGuestHeight, pu8BufferAddress, u64Timestamp);
3980# endif /* VBOX_WITH_VIDEOREC */
3981}
3982
3983void Display::i_handleVRecCompletion()
3984{
3985 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3986 ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);
3987}
3988
3989#endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
3990
3991HRESULT Display::notifyScaleFactorChange(ULONG aScreenId, ULONG aScaleFactorWMultiplied, ULONG aScaleFactorHMultiplied)
3992{
3993#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3994 HRESULT hr = E_UNEXPECTED;
3995
3996 if (aScreenId >= mcMonitors)
3997 return E_INVALIDARG;
3998
3999 /* 3D acceleration enabled in VM config. */
4000 if (mfIsCr3DEnabled)
4001 {
4002 /* VBoxSharedCrOpenGL HGCM host service is running. */
4003 if (mhCrOglSvc)
4004 {
4005 VMMDev *pVMMDev = mParent->i_getVMMDev();
4006 if (pVMMDev)
4007 {
4008 VBOXCRCMDCTL_HGCM *pCtl;
4009 pCtl = (VBOXCRCMDCTL_HGCM *)RTMemAlloc(sizeof(CRVBOXHGCMSETSCALEFACTOR) + sizeof(VBOXCRCMDCTL_HGCM));
4010 if (pCtl)
4011 {
4012 CRVBOXHGCMSETSCALEFACTOR *pData = (CRVBOXHGCMSETSCALEFACTOR *)(pCtl + 1);
4013 int rc;
4014
4015 pData->u32Screen = aScreenId;
4016 pData->u32ScaleFactorWMultiplied = aScaleFactorWMultiplied;
4017 pData->u32ScaleFactorHMultiplied = aScaleFactorHMultiplied;
4018
4019 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
4020 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_SCALE_FACTOR;
4021 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
4022 pCtl->aParms[0].u.pointer.addr = pData;
4023 pCtl->aParms[0].u.pointer.size = sizeof(*pData);
4024
4025 rc = i_crCtlSubmitSync(&pCtl->Hdr, sizeof(*pCtl));
4026 if (RT_FAILURE(rc))
4027 AssertMsgFailed(("crCtlSubmitSync failed (rc=%Rrc)\n", rc));
4028 else
4029 hr = S_OK;
4030
4031 RTMemFree(pCtl);
4032 }
4033 else
4034 {
4035 LogRel(("Running out of memory on attempt to set OpenGL content scale factor. Ignored.\n"));
4036 hr = E_OUTOFMEMORY;
4037 }
4038 }
4039 else
4040 LogRel(("Internal error occurred on attempt to set OpenGL content scale factor. Ignored.\n"));
4041 }
4042 else
4043 LogRel(("Attempt to specify OpenGL content scale factor while corresponding HGCM host service not yet runing. Ignored.\n"));
4044 }
4045 else
4046# if 0 /** @todo Thank you so very much from anyone using VMSVGA3d! */
4047 AssertMsgFailed(("Attempt to specify OpenGL content scale factor while 3D acceleration is disabled in VM config. Ignored.\n"));
4048# else
4049 {
4050 hr = S_OK;
4051 /* Need an interface like this here (and the #ifdefs needs adjusting):
4052 PPDMIDISPLAYPORT pUpPort = mpDrv ? mpDrv->pUpPort : NULL;
4053 if (pUpPort && pUpPort->pfnSetScaleFactor)
4054 pUpPort->pfnSetScaleFactor(pUpPort, aScreeId, aScaleFactorWMultiplied, aScaleFactorHMultiplied); */
4055 }
4056# endif
4057
4058 return hr;
4059
4060#else /* !VBOX_WITH_HGCM || !VBOX_WITH_CROGL */
4061 RT_NOREF(aScreenId, aScaleFactorWMultiplied, aScaleFactorHMultiplied);
4062 AssertMsgFailed(("Attempt to specify OpenGL content scale factor while corresponding functionality is disabled."));
4063 return E_UNEXPECTED;
4064#endif /* !VBOX_WITH_HGCM || !VBOX_WITH_CROGL */
4065}
4066
4067HRESULT Display::notifyHiDPIOutputPolicyChange(BOOL fUnscaledHiDPI)
4068{
4069#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
4070 HRESULT hr = E_UNEXPECTED;
4071
4072 /* 3D acceleration enabled in VM config. */
4073 if (mfIsCr3DEnabled)
4074 {
4075 /* VBoxSharedCrOpenGL HGCM host service is running. */
4076 if (mhCrOglSvc)
4077 {
4078 VMMDev *pVMMDev = mParent->i_getVMMDev();
4079 if (pVMMDev)
4080 {
4081 VBOXCRCMDCTL_HGCM *pCtl;
4082 pCtl = (VBOXCRCMDCTL_HGCM *)RTMemAlloc(sizeof(CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT) + sizeof(VBOXCRCMDCTL_HGCM));
4083 if (pCtl)
4084 {
4085 CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *pData = (CRVBOXHGCMSETUNSCALEDHIDPIOUTPUT *)(pCtl + 1);
4086 int rc;
4087
4088 pData->fUnscaledHiDPI = RT_BOOL(fUnscaledHiDPI);
4089
4090 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
4091 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_UNSCALED_HIDPI;
4092 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
4093 pCtl->aParms[0].u.pointer.addr = pData;
4094 pCtl->aParms[0].u.pointer.size = sizeof(*pData);
4095
4096 rc = i_crCtlSubmitSync(&pCtl->Hdr, sizeof(*pCtl));
4097 if (RT_FAILURE(rc))
4098 AssertMsgFailed(("crCtlSubmitSync failed (rc=%Rrc)\n", rc));
4099 else
4100 hr = S_OK;
4101
4102 RTMemFree(pCtl);
4103 }
4104 else
4105 {
4106 LogRel(("Running out of memory on attempt to notify OpenGL about HiDPI output scaling policy change. Ignored.\n"));
4107 hr = E_OUTOFMEMORY;
4108 }
4109 }
4110 else
4111 LogRel(("Internal error occurred on attempt to notify OpenGL about HiDPI output scaling policy change. Ignored.\n"));
4112 }
4113 else
4114 LogRel(("Attempt to notify OpenGL about HiDPI output scaling policy change while corresponding HGCM host service not yet runing. Ignored.\n"));
4115 }
4116 else
4117 {
4118 hr = S_OK;
4119 /* Need an interface like this here (and the #ifdefs needs adjusting):
4120 PPDMIDISPLAYPORT pUpPort = mpDrv ? mpDrv->pUpPort : NULL;
4121 if (pUpPort && pUpPort->pfnSetScaleFactor)
4122 pUpPort->pfnSetScaleFactor(pUpPort, aScreeId, aScaleFactorWMultiplied, aScaleFactorHMultiplied); */
4123 }
4124
4125 return hr;
4126
4127#else /* !VBOX_WITH_HGCM || !VBOX_WITH_CROGL */
4128 RT_NOREF(fUnscaledHiDPI);
4129 AssertMsgFailed(("Attempt to notify OpenGL about HiDPI output scaling policy change while corresponding functionality is disabled."));
4130 return E_UNEXPECTED;
4131#endif /* !VBOX_WITH_HGCM || !VBOX_WITH_CROGL */
4132}
4133
4134#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
4135DECLCALLBACK(void) Display::i_displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen,
4136 uint32_t x, uint32_t y,
4137 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
4138 uint32_t uGuestWidth, uint32_t uGuestHeight,
4139 uint8_t *pu8BufferAddress, uint64_t u64Timestamp)
4140{
4141 Display *pDisplay = (Display *)pvCtx;
4142 pDisplay->i_handleCrVRecScreenshotPerform(uScreen,
4143 x, y, BitmapFormat_BGR, uBitsPerPixel,
4144 uBytesPerLine, uGuestWidth, uGuestHeight,
4145 pu8BufferAddress, u64Timestamp);
4146}
4147
4148DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64Timestamp)
4149{
4150 Display *pDisplay = (Display *)pvCtx;
4151 return pDisplay->i_handleCrVRecScreenshotBegin(uScreen, u64Timestamp);
4152}
4153
4154DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64Timestamp)
4155{
4156 Display *pDisplay = (Display *)pvCtx;
4157 pDisplay->i_handleCrVRecScreenshotEnd(uScreen, u64Timestamp);
4158}
4159
4160DECLCALLBACK(void) Display::i_displayVRecCompletion(struct VBOXCRCMDCTL *pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
4161{
4162 RT_NOREF(pCmd, cbCmd, rc);
4163 Display *pDisplay = (Display *)pvCompletion;
4164 pDisplay->i_handleVRecCompletion();
4165}
4166
4167#endif
4168
4169
4170#ifdef VBOX_WITH_HGSMI
4171DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,
4172 bool fRenderThreadMode)
4173{
4174 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
4175
4176 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4177 Display *pThis = pDrv->pDisplay;
4178
4179 if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)
4180 {
4181 LogRel(("Enabling different vbva mode\n"));
4182#ifdef DEBUG_misha
4183 AssertMsgFailed(("enabling different vbva mode\n"));
4184#endif
4185 return VERR_INVALID_STATE;
4186 }
4187
4188 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;
4189 pThis->maFramebuffers[uScreenId].pVBVAHostFlags = pHostFlags;
4190 pThis->maFramebuffers[uScreenId].fRenderThreadMode = fRenderThreadMode;
4191 pThis->maFramebuffers[uScreenId].fVBVAForceResize = true;
4192
4193 vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
4194
4195 return VINF_SUCCESS;
4196}
4197
4198DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
4199{
4200 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
4201
4202 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4203 Display *pThis = pDrv->pDisplay;
4204
4205 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4206
4207 bool fRenderThreadMode = pFBInfo->fRenderThreadMode;
4208
4209 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
4210 {
4211 /* Make sure that the primary screen is visible now.
4212 * The guest can't use VBVA anymore, so only only the VGA device output works.
4213 */
4214#ifdef NEW_RESIZE
4215 pFBInfo->flags = 0;
4216#endif
4217 if (pFBInfo->fDisabled)
4218 {
4219 pFBInfo->fDisabled = false;
4220 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4221 GuestMonitorChangedEventType_Enabled,
4222 uScreenId,
4223 pFBInfo->xOrigin, pFBInfo->yOrigin,
4224 pFBInfo->w, pFBInfo->h);
4225 }
4226 }
4227
4228 pFBInfo->fVBVAEnabled = false;
4229 pFBInfo->fVBVAForceResize = false;
4230 pFBInfo->fRenderThreadMode = false;
4231
4232 vbvaSetMemoryFlagsHGSMI(uScreenId, 0, false, pFBInfo);
4233
4234 pFBInfo->pVBVAHostFlags = NULL;
4235
4236 if (!fRenderThreadMode && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
4237 {
4238 /* Force full screen update, because VGA device must take control, do resize, etc. */
4239 pThis->mpDrv->pUpPort->pfnUpdateDisplayAll(pThis->mpDrv->pUpPort, /* fFailOnResize = */ false);
4240 }
4241}
4242
4243DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
4244{
4245 RT_NOREF(uScreenId);
4246 LogFlowFunc(("uScreenId %d\n", uScreenId));
4247
4248 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4249 Display *pThis = pDrv->pDisplay;
4250
4251 if (ASMAtomicReadU32(&pThis->mu32UpdateVBVAFlags) > 0)
4252 {
4253 vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,
4254 pThis->mcMonitors);
4255 ASMAtomicDecU32(&pThis->mu32UpdateVBVAFlags);
4256 }
4257}
4258
4259DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,
4260 PCVBVACMDHDR pCmd, size_t cbCmd)
4261{
4262 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
4263
4264 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4265 Display *pThis = pDrv->pDisplay;
4266 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4267
4268 if (pFBInfo->fDefaultFormat)
4269 {
4270 /* Make sure that framebuffer contains the same image as the guest VRAM. */
4271 if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
4272 && !pFBInfo->fDisabled)
4273 {
4274 pDrv->pUpPort->pfnUpdateDisplayRect(pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h);
4275 }
4276 else if ( !pFBInfo->pSourceBitmap.isNull()
4277 && !pFBInfo->fDisabled)
4278 {
4279 /* Render VRAM content to the framebuffer. */
4280 BYTE *pAddress = NULL;
4281 ULONG ulWidth = 0;
4282 ULONG ulHeight = 0;
4283 ULONG ulBitsPerPixel = 0;
4284 ULONG ulBytesPerLine = 0;
4285 BitmapFormat_T bitmapFormat = BitmapFormat_Opaque;
4286
4287 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
4288 &ulWidth,
4289 &ulHeight,
4290 &ulBitsPerPixel,
4291 &ulBytesPerLine,
4292 &bitmapFormat);
4293 if (SUCCEEDED(hrc))
4294 {
4295 uint32_t width = pCmd->w;
4296 uint32_t height = pCmd->h;
4297
4298 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
4299 int32_t xSrc = pCmd->x - pFBInfo->xOrigin;
4300 int32_t ySrc = pCmd->y - pFBInfo->yOrigin;
4301 uint32_t u32SrcWidth = pFBInfo->w;
4302 uint32_t u32SrcHeight = pFBInfo->h;
4303 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
4304 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
4305
4306 uint8_t *pu8Dst = pAddress;
4307 int32_t xDst = xSrc;
4308 int32_t yDst = ySrc;
4309 uint32_t u32DstWidth = u32SrcWidth;
4310 uint32_t u32DstHeight = u32SrcHeight;
4311 uint32_t u32DstLineSize = u32DstWidth * 4;
4312 uint32_t u32DstBitsPerPixel = 32;
4313
4314 pDrv->pUpPort->pfnCopyRect(pDrv->pUpPort,
4315 width, height,
4316 pu8Src,
4317 xSrc, ySrc,
4318 u32SrcWidth, u32SrcHeight,
4319 u32SrcLineSize, u32SrcBitsPerPixel,
4320 pu8Dst,
4321 xDst, yDst,
4322 u32DstWidth, u32DstHeight,
4323 u32DstLineSize, u32DstBitsPerPixel);
4324 }
4325 }
4326 }
4327
4328 VBVACMDHDR hdrSaved = *pCmd;
4329
4330 VBVACMDHDR *pHdrUnconst = (VBVACMDHDR *)pCmd;
4331
4332 pHdrUnconst->x -= (int16_t)pFBInfo->xOrigin;
4333 pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin;
4334
4335 /** @todo new SendUpdate entry which can get a separate cmd header or coords. */
4336 pThis->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, pHdrUnconst, (uint32_t)cbCmd);
4337
4338 *pHdrUnconst = hdrSaved;
4339}
4340
4341DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,
4342 uint32_t cx, uint32_t cy)
4343{
4344 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));
4345
4346 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4347 Display *pThis = pDrv->pDisplay;
4348 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4349
4350 /** @todo handleFramebufferUpdate (uScreenId,
4351 * x - pThis->maFramebuffers[uScreenId].xOrigin,
4352 * y - pThis->maFramebuffers[uScreenId].yOrigin,
4353 * cx, cy);
4354 */
4355 pThis->i_handleDisplayUpdate(uScreenId, x - pFBInfo->xOrigin, y - pFBInfo->yOrigin, cx, cy);
4356}
4357
4358#ifdef DEBUG_sunlover
4359static void logVBVAResize(PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)
4360{
4361 LogRel(("displayVBVAResize: [%d] %s\n"
4362 " pView->u32ViewIndex %d\n"
4363 " pView->u32ViewOffset 0x%08X\n"
4364 " pView->u32ViewSize 0x%08X\n"
4365 " pView->u32MaxScreenSize 0x%08X\n"
4366 " pScreen->i32OriginX %d\n"
4367 " pScreen->i32OriginY %d\n"
4368 " pScreen->u32StartOffset 0x%08X\n"
4369 " pScreen->u32LineSize 0x%08X\n"
4370 " pScreen->u32Width %d\n"
4371 " pScreen->u32Height %d\n"
4372 " pScreen->u16BitsPerPixel %d\n"
4373 " pScreen->u16Flags 0x%04X\n"
4374 " pFBInfo->u32Offset 0x%08X\n"
4375 " pFBInfo->u32MaxFramebufferSize 0x%08X\n"
4376 " pFBInfo->u32InformationSize 0x%08X\n"
4377 " pFBInfo->fDisabled %d\n"
4378 " xOrigin, yOrigin, w, h: %d,%d %dx%d\n"
4379 " pFBInfo->u16BitsPerPixel %d\n"
4380 " pFBInfo->pu8FramebufferVRAM %p\n"
4381 " pFBInfo->u32LineSize 0x%08X\n"
4382 " pFBInfo->flags 0x%04X\n"
4383 " pFBInfo->pHostEvents %p\n"
4384 " pFBInfo->fDefaultFormat %d\n"
4385 " pFBInfo->fVBVAEnabled %d\n"
4386 " pFBInfo->fVBVAForceResize %d\n"
4387 " pFBInfo->pVBVAHostFlags %p\n"
4388 "",
4389 pScreen->u32ViewIndex,
4390 (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)? "DISABLED": "ENABLED",
4391 pView->u32ViewIndex,
4392 pView->u32ViewOffset,
4393 pView->u32ViewSize,
4394 pView->u32MaxScreenSize,
4395 pScreen->i32OriginX,
4396 pScreen->i32OriginY,
4397 pScreen->u32StartOffset,
4398 pScreen->u32LineSize,
4399 pScreen->u32Width,
4400 pScreen->u32Height,
4401 pScreen->u16BitsPerPixel,
4402 pScreen->u16Flags,
4403 pFBInfo->u32Offset,
4404 pFBInfo->u32MaxFramebufferSize,
4405 pFBInfo->u32InformationSize,
4406 pFBInfo->fDisabled,
4407 pFBInfo->xOrigin,
4408 pFBInfo->yOrigin,
4409 pFBInfo->w,
4410 pFBInfo->h,
4411 pFBInfo->u16BitsPerPixel,
4412 pFBInfo->pu8FramebufferVRAM,
4413 pFBInfo->u32LineSize,
4414 pFBInfo->flags,
4415 pFBInfo->pHostEvents,
4416 pFBInfo->fDefaultFormat,
4417 pFBInfo->fVBVAEnabled,
4418 pFBInfo->fVBVAForceResize,
4419 pFBInfo->pVBVAHostFlags
4420 ));
4421}
4422#endif /* DEBUG_sunlover */
4423
4424DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, PCVBVAINFOVIEW pView,
4425 PCVBVAINFOSCREEN pScreen, void *pvVRAM, bool fResetInputMapping)
4426{
4427 LogRelFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));
4428
4429 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4430 Display *pThis = pDrv->pDisplay;
4431
4432#ifndef NEW_RESIZE
4433 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];
4434
4435 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
4436 {
4437 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
4438
4439 pFBInfo->fDisabled = true;
4440 pFBInfo->flags = pScreen->u16Flags;
4441
4442 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.
4443 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,
4444 * the VM window will be black. */
4445 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;
4446 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;
4447 pThis->i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,
4448 u32Width, u32Height, pScreen->u16Flags);
4449
4450 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4451 GuestMonitorChangedEventType_Disabled,
4452 pScreen->u32ViewIndex,
4453 0, 0, 0, 0);
4454 return VINF_SUCCESS;
4455 }
4456
4457 VBVAINFOSCREEN screenInfo;
4458 RT_ZERO(screenInfo);
4459
4460 if (pScreen->u16Flags & VBVA_SCREEN_F_BLANK2)
4461 {
4462 /* Init a local VBVAINFOSCREEN structure, which will be used instead of
4463 * the original pScreen. Set VBVA_SCREEN_F_BLANK, which will force
4464 * the code below to choose the "blanking" branches.
4465 */
4466 screenInfo.u32ViewIndex = pScreen->u32ViewIndex;
4467 screenInfo.i32OriginX = pFBInfo->xOrigin;
4468 screenInfo.i32OriginY = pFBInfo->yOrigin;
4469 screenInfo.u32StartOffset = 0; /* Irrelevant */
4470 screenInfo.u32LineSize = pFBInfo->u32LineSize;
4471 screenInfo.u32Width = pFBInfo->w;
4472 screenInfo.u32Height = pFBInfo->h;
4473 screenInfo.u16BitsPerPixel = pFBInfo->u16BitsPerPixel;
4474 screenInfo.u16Flags = pScreen->u16Flags | VBVA_SCREEN_F_BLANK;
4475
4476 pScreen = &screenInfo;
4477 }
4478
4479 /* If display was disabled or there is no framebuffer, a resize will be required,
4480 * because the framebuffer was/will be changed.
4481 */
4482 bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull();
4483
4484 if (pFBInfo->fVBVAForceResize)
4485 {
4486 /* VBVA was just enabled. Do the resize. */
4487 fResize = true;
4488 pFBInfo->fVBVAForceResize = false;
4489 }
4490
4491 /* If the screen if blanked, then do a resize request to make sure that the framebuffer
4492 * switches to the default format.
4493 */
4494 fResize = fResize || RT_BOOL((pScreen->u16Flags ^ pFBInfo->flags) & VBVA_SCREEN_F_BLANK);
4495
4496 /* Check if this is a real resize or a notification about the screen origin.
4497 * The guest uses this VBVAResize call for both.
4498 */
4499 fResize = fResize
4500 || pFBInfo->u16BitsPerPixel != pScreen->u16BitsPerPixel
4501 || pFBInfo->pu8FramebufferVRAM != (uint8_t *)pvVRAM + pScreen->u32StartOffset
4502 || pFBInfo->u32LineSize != pScreen->u32LineSize
4503 || pFBInfo->w != pScreen->u32Width
4504 || pFBInfo->h != pScreen->u32Height;
4505
4506 bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX
4507 || pFBInfo->yOrigin != pScreen->i32OriginY;
4508
4509 if (fNewOrigin || fResize)
4510 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
4511
4512 if (pFBInfo->fDisabled)
4513 {
4514 pFBInfo->fDisabled = false;
4515 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4516 GuestMonitorChangedEventType_Enabled,
4517 pScreen->u32ViewIndex,
4518 pScreen->i32OriginX, pScreen->i32OriginY,
4519 pScreen->u32Width, pScreen->u32Height);
4520 /* Continue to update pFBInfo. */
4521 }
4522
4523 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */
4524 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */
4525 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */
4526
4527 pFBInfo->xOrigin = pScreen->i32OriginX;
4528 pFBInfo->yOrigin = pScreen->i32OriginY;
4529
4530 pFBInfo->w = pScreen->u32Width;
4531 pFBInfo->h = pScreen->u32Height;
4532
4533 pFBInfo->u16BitsPerPixel = pScreen->u16BitsPerPixel;
4534 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM + pScreen->u32StartOffset;
4535 pFBInfo->u32LineSize = pScreen->u32LineSize;
4536
4537 pFBInfo->flags = pScreen->u16Flags;
4538
4539 if (fResetInputMapping)
4540 {
4541 pThis->xInputMappingOrigin = 0;
4542 pThis->yInputMappingOrigin = 0;
4543 pThis->cxInputMapping = 0;
4544 pThis->cyInputMapping = 0;
4545 }
4546
4547 if (fNewOrigin)
4548 {
4549 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4550 GuestMonitorChangedEventType_NewOrigin,
4551 pScreen->u32ViewIndex,
4552 pScreen->i32OriginX, pScreen->i32OriginY,
4553 0, 0);
4554 }
4555
4556 if (!fResize)
4557 {
4558 /* No parameters of the framebuffer have actually changed. */
4559 if (fNewOrigin)
4560 {
4561 /* VRDP server still need this notification. */
4562 LogRelFlowFunc(("Calling VRDP\n"));
4563 pThis->mParent->i_consoleVRDPServer()->SendResize();
4564 }
4565 return VINF_SUCCESS;
4566 }
4567
4568 /* Do a regular resize. */
4569 return pThis->i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
4570 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
4571 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags);
4572#else /* NEW_RESIZE */
4573 return pThis->processVBVAResize(pView, pScreen, pvVRAM, fResetInputMapping);
4574#endif /* NEW_RESIZE */
4575}
4576
4577#ifdef NEW_RESIZE
4578int Display::processVBVAResize(PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, void *pvVRAM, bool fResetInputMapping)
4579{
4580 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
4581
4582 DISPLAYFBINFO *pFBInfo = &maFramebuffers[pScreen->u32ViewIndex];
4583
4584 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
4585 {
4586 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.
4587 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,
4588 * the VM window will be black. */
4589 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;
4590 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;
4591 int32_t xOrigin = pFBInfo->xOrigin;
4592 int32_t yOrigin = pFBInfo->yOrigin;
4593
4594 alock.release();
4595
4596 i_notifyCroglResize(pView, pScreen, pvVRAM);
4597
4598 i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,
4599 u32Width, u32Height, pScreen->u16Flags, xOrigin, yOrigin, false);
4600
4601 return VINF_SUCCESS;
4602 }
4603
4604 VBVAINFOSCREEN screenInfo;
4605 RT_ZERO(screenInfo);
4606
4607 if (pScreen->u16Flags & VBVA_SCREEN_F_BLANK2)
4608 {
4609 /* Init a local VBVAINFOSCREEN structure, which will be used instead of
4610 * the original pScreen. Set VBVA_SCREEN_F_BLANK, which will force
4611 * the code below to choose the "blanking" branches.
4612 */
4613 screenInfo.u32ViewIndex = pScreen->u32ViewIndex;
4614 screenInfo.i32OriginX = pFBInfo->xOrigin;
4615 screenInfo.i32OriginY = pFBInfo->yOrigin;
4616 screenInfo.u32StartOffset = 0; /* Irrelevant */
4617 screenInfo.u32LineSize = pFBInfo->u32LineSize;
4618 screenInfo.u32Width = pFBInfo->w;
4619 screenInfo.u32Height = pFBInfo->h;
4620 screenInfo.u16BitsPerPixel = pFBInfo->u16BitsPerPixel;
4621 screenInfo.u16Flags = pScreen->u16Flags | VBVA_SCREEN_F_BLANK;
4622
4623 pScreen = &screenInfo;
4624 }
4625
4626 if (fResetInputMapping)
4627 {
4628 /// @todo Rename to m* and verify whether some kind of lock is required.
4629 xInputMappingOrigin = 0;
4630 yInputMappingOrigin = 0;
4631 cxInputMapping = 0;
4632 cyInputMapping = 0;
4633 }
4634
4635 alock.release();
4636
4637 i_notifyCroglResize(pView, pScreen, pvVRAM);
4638
4639 return i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
4640 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
4641 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags,
4642 pScreen->i32OriginX, pScreen->i32OriginY, false);
4643}
4644#endif /* NEW_RESIZE */
4645
4646DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
4647 uint32_t xHot, uint32_t yHot,
4648 uint32_t cx, uint32_t cy,
4649 const void *pvShape)
4650{
4651 LogFlowFunc(("\n"));
4652
4653 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4654
4655 uint32_t cbShape = 0;
4656 if (pvShape)
4657 {
4658 cbShape = (cx + 7) / 8 * cy; /* size of the AND mask */
4659 cbShape = ((cbShape + 3) & ~3) + cx * 4 * cy; /* + gap + size of the XOR mask */
4660 }
4661
4662 /* Tell the console about it */
4663 pDrv->pDisplay->mParent->i_onMousePointerShapeChange(fVisible, fAlpha,
4664 xHot, yHot, cx, cy, (uint8_t *)pvShape, cbShape);
4665
4666 return VINF_SUCCESS;
4667}
4668
4669DECLCALLBACK(void) Display::i_displayVBVAGuestCapabilityUpdate(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)
4670{
4671 LogFlowFunc(("\n"));
4672
4673 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4674 Display *pThis = pDrv->pDisplay;
4675
4676 pThis->i_handleUpdateGuestVBVACapabilities(fCapabilities);
4677}
4678
4679DECLCALLBACK(void) Display::i_displayVBVAInputMappingUpdate(PPDMIDISPLAYCONNECTOR pInterface, int32_t xOrigin, int32_t yOrigin,
4680 uint32_t cx, uint32_t cy)
4681{
4682 LogFlowFunc(("\n"));
4683
4684 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4685 Display *pThis = pDrv->pDisplay;
4686
4687 pThis->i_handleUpdateVBVAInputMapping(xOrigin, yOrigin, cx, cy);
4688}
4689
4690#endif /* VBOX_WITH_HGSMI */
4691
4692/**
4693 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4694 */
4695DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4696{
4697 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
4698 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4699 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
4700 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);
4701 return NULL;
4702}
4703
4704
4705/**
4706 * Destruct a display driver instance.
4707 *
4708 * @returns VBox status code.
4709 * @param pDrvIns The driver instance data.
4710 */
4711DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)
4712{
4713 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
4714 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4715 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
4716
4717 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
4718
4719 pThis->IConnector.pbData = NULL;
4720 pThis->IConnector.cbScanline = 0;
4721 pThis->IConnector.cBits = 32;
4722 pThis->IConnector.cx = 0;
4723 pThis->IConnector.cy = 0;
4724
4725 if (pThis->pDisplay)
4726 {
4727 AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS);
4728#ifdef VBOX_WITH_VIDEOREC
4729 pThis->pDisplay->i_videoCaptureStop();
4730#endif
4731#ifdef VBOX_WITH_CRHGSMI
4732 pThis->pDisplay->i_destructCrHgsmiData();
4733#endif
4734 pThis->pDisplay->mpDrv = NULL;
4735 pThis->pDisplay->mpVMMDev = NULL;
4736 }
4737}
4738
4739
4740/**
4741 * Construct a display driver instance.
4742 *
4743 * @copydoc FNPDMDRVCONSTRUCT
4744 */
4745DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
4746{
4747 RT_NOREF(fFlags);
4748 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
4749 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4750 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
4751
4752 /*
4753 * Validate configuration.
4754 */
4755 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
4756 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
4757 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
4758 ("Configuration error: Not possible to attach anything to this driver!\n"),
4759 VERR_PDM_DRVINS_NO_ATTACH);
4760
4761 /*
4762 * Init Interfaces.
4763 */
4764 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;
4765
4766 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;
4767 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;
4768 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;
4769 pThis->IConnector.pfnReset = Display::i_displayResetCallback;
4770 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;
4771 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;
4772 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;
4773#ifdef VBOX_WITH_VIDEOHWACCEL
4774 pThis->IConnector.pfnVHWACommandProcess = Display::i_displayVHWACommandProcess;
4775#endif
4776#ifdef VBOX_WITH_CRHGSMI
4777 pThis->IConnector.pfnCrHgsmiCommandProcess = Display::i_displayCrHgsmiCommandProcess;
4778 pThis->IConnector.pfnCrHgsmiControlProcess = Display::i_displayCrHgsmiControlProcess;
4779#endif
4780#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
4781 pThis->IConnector.pfnCrHgcmCtlSubmit = Display::i_displayCrHgcmCtlSubmit;
4782#endif
4783#ifdef VBOX_WITH_HGSMI
4784 pThis->IConnector.pfnVBVAEnable = Display::i_displayVBVAEnable;
4785 pThis->IConnector.pfnVBVADisable = Display::i_displayVBVADisable;
4786 pThis->IConnector.pfnVBVAUpdateBegin = Display::i_displayVBVAUpdateBegin;
4787 pThis->IConnector.pfnVBVAUpdateProcess = Display::i_displayVBVAUpdateProcess;
4788 pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;
4789 pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;
4790 pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;
4791 pThis->IConnector.pfnVBVAGuestCapabilityUpdate = Display::i_displayVBVAGuestCapabilityUpdate;
4792 pThis->IConnector.pfnVBVAInputMappingUpdate = Display::i_displayVBVAInputMappingUpdate;
4793#endif
4794
4795 /*
4796 * Get the IDisplayPort interface of the above driver/device.
4797 */
4798 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);
4799 if (!pThis->pUpPort)
4800 {
4801 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
4802 return VERR_PDM_MISSING_INTERFACE_ABOVE;
4803 }
4804#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
4805 pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS);
4806 if (!pThis->pVBVACallbacks)
4807 {
4808 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
4809 return VERR_PDM_MISSING_INTERFACE_ABOVE;
4810 }
4811#endif
4812 /*
4813 * Get the Display object pointer and update the mpDrv member.
4814 */
4815 void *pv;
4816 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
4817 if (RT_FAILURE(rc))
4818 {
4819 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
4820 return rc;
4821 }
4822 Display *pDisplay = (Display *)pv; /** @todo Check this cast! */
4823 pThis->pDisplay = pDisplay;
4824 pThis->pDisplay->mpDrv = pThis;
4825
4826 /* Disable VRAM to a buffer copy initially. */
4827 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
4828 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */
4829
4830 /*
4831 * Start periodic screen refreshes
4832 */
4833 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);
4834
4835#ifdef VBOX_WITH_CRHGSMI
4836 pDisplay->i_setupCrHgsmiData();
4837#endif
4838
4839#ifdef VBOX_WITH_VIDEOREC
4840 ComPtr<IMachine> pMachine = pDisplay->mParent->i_machine();
4841 BOOL fEnabled = false;
4842 HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);
4843 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
4844
4845 if (fEnabled)
4846 {
4847 rc = pDisplay->i_videoCaptureStart();
4848 fireVideoCaptureChangedEvent(pDisplay->mParent->i_getEventSource());
4849 }
4850#endif
4851
4852 return rc;
4853}
4854
4855
4856/**
4857 * Display driver registration record.
4858 */
4859const PDMDRVREG Display::DrvReg =
4860{
4861 /* u32Version */
4862 PDM_DRVREG_VERSION,
4863 /* szName */
4864 "MainDisplay",
4865 /* szRCMod */
4866 "",
4867 /* szR0Mod */
4868 "",
4869 /* pszDescription */
4870 "Main display driver (Main as in the API).",
4871 /* fFlags */
4872 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
4873 /* fClass. */
4874 PDM_DRVREG_CLASS_DISPLAY,
4875 /* cMaxInstances */
4876 ~0U,
4877 /* cbInstance */
4878 sizeof(DRVMAINDISPLAY),
4879 /* pfnConstruct */
4880 Display::i_drvConstruct,
4881 /* pfnDestruct */
4882 Display::i_drvDestruct,
4883 /* pfnRelocate */
4884 NULL,
4885 /* pfnIOCtl */
4886 NULL,
4887 /* pfnPowerOn */
4888 NULL,
4889 /* pfnReset */
4890 NULL,
4891 /* pfnSuspend */
4892 NULL,
4893 /* pfnResume */
4894 NULL,
4895 /* pfnAttach */
4896 NULL,
4897 /* pfnDetach */
4898 NULL,
4899 /* pfnPowerOff */
4900 NULL,
4901 /* pfnSoftReset */
4902 NULL,
4903 /* u32EndVersion */
4904 PDM_DRVREG_VERSION
4905};
4906
4907/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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