VirtualBox

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

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

Devices/Main: vmsvga updates

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