VirtualBox

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

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

DisplayImpl: LogRel nit.

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