VirtualBox

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

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

Main/VideoRec: Renaming, comment.

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