VirtualBox

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

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

Main: warnings

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

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