VirtualBox

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

Last change on this file since 53965 was 53965, checked in by vboxsync, 10 years ago

Devices/Graphics, Main: optionally send cursor integration toggle and guest cursor position information through the graphics device.

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

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