VirtualBox

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

Last change on this file since 77863 was 77703, checked in by vboxsync, 6 years ago

BVGA,Display,FE/Qt: Don't flood the release log with screen updates message (Debian testing guest), changing the LogRel statements to LogRel2. Display will LogRel actual screen size, position, flag changes (but not VRAM address). Besides being extremely noisy it also slows down guest graphics as each release log message is flushed to the disk. PS. UI folks, we don't break log messages as this reduces the grep-ability.

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