VirtualBox

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

Last change on this file since 62296 was 62296, checked in by vboxsync, 9 years ago

fix for r108820

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette