VirtualBox

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

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

Initialize input mapping variables.

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

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