VirtualBox

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

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

DisplayImpl: cleanup - inlined handleResizeCompletedEMT, removed old display disable hack.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 135.3 KB
Line 
1/* $Id: DisplayImpl.cpp 53053 2014-10-14 11:17:08Z 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 return S_OK;
2563}
2564
2565HRESULT Display::querySourceBitmap(ULONG aScreenId,
2566 ComPtr<IDisplaySourceBitmap> &aDisplaySourceBitmap)
2567{
2568 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2569
2570 Console::SafeVMPtr ptrVM(mParent);
2571 if (!ptrVM.isOk())
2572 return ptrVM.rc();
2573
2574 bool fSetRenderVRAM = false;
2575 bool fInvalidate = false;
2576
2577 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2578
2579 if (aScreenId >= mcMonitors)
2580 return setError(E_INVALIDARG, tr("QuerySourceBitmap: Invalid screen %d (total %d)"),
2581 aScreenId, mcMonitors);
2582
2583 if (!mfSourceBitmapEnabled)
2584 {
2585 aDisplaySourceBitmap = NULL;
2586 return E_FAIL;
2587 }
2588
2589 HRESULT hr = S_OK;
2590
2591 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2592 if (pFBInfo->pSourceBitmap.isNull())
2593 {
2594 /* Create a new object. */
2595 ComObjPtr<DisplaySourceBitmap> obj;
2596 hr = obj.createObject();
2597 if (SUCCEEDED(hr))
2598 hr = obj->init(this, aScreenId, pFBInfo);
2599
2600 if (SUCCEEDED(hr))
2601 {
2602 bool fDefaultFormat = !obj->i_usesVRAM();
2603
2604 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2605 {
2606 /* Start buffer updates. */
2607 BYTE *pAddress = NULL;
2608 ULONG ulWidth = 0;
2609 ULONG ulHeight = 0;
2610 ULONG ulBitsPerPixel = 0;
2611 ULONG ulBytesPerLine = 0;
2612 ULONG ulPixelFormat = 0;
2613
2614 obj->QueryBitmapInfo(&pAddress,
2615 &ulWidth,
2616 &ulHeight,
2617 &ulBitsPerPixel,
2618 &ulBytesPerLine,
2619 &ulPixelFormat);
2620
2621 mpDrv->IConnector.pu8Data = pAddress;
2622 mpDrv->IConnector.cbScanline = ulBytesPerLine;
2623 mpDrv->IConnector.cBits = ulBitsPerPixel;
2624 mpDrv->IConnector.cx = ulWidth;
2625 mpDrv->IConnector.cy = ulHeight;
2626
2627 fSetRenderVRAM = fDefaultFormat;
2628 }
2629
2630 /* Make sure that the bitmap contains the latest image. */
2631 fInvalidate = fDefaultFormat;
2632
2633 pFBInfo->pSourceBitmap = obj;
2634 pFBInfo->fDefaultFormat = fDefaultFormat;
2635 }
2636 }
2637
2638 if (SUCCEEDED(hr))
2639 {
2640 pFBInfo->pSourceBitmap.queryInterfaceTo(aDisplaySourceBitmap.asOutParam());
2641 }
2642
2643 /* Leave the IDisplay lock because the VGA device must not be called under it. */
2644 alock.release();
2645
2646 if (SUCCEEDED(hr))
2647 {
2648 if (fSetRenderVRAM)
2649 {
2650 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
2651 }
2652
2653 if (fInvalidate)
2654 VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
2655 3, this, aScreenId, false);
2656 }
2657
2658 LogRelFlowFunc(("%Rhrc\n", hr));
2659 return hr;
2660}
2661
2662// wrapped IEventListener method
2663HRESULT Display::handleEvent(const ComPtr<IEvent> &aEvent)
2664{
2665 VBoxEventType_T aType = VBoxEventType_Invalid;
2666
2667 aEvent->COMGETTER(Type)(&aType);
2668 switch (aType)
2669 {
2670 case VBoxEventType_OnStateChanged:
2671 {
2672 ComPtr<IStateChangedEvent> scev = aEvent;
2673 Assert(scev);
2674 MachineState_T machineState;
2675 scev->COMGETTER(State)(&machineState);
2676 if ( machineState == MachineState_Running
2677 || machineState == MachineState_Teleporting
2678 || machineState == MachineState_LiveSnapshotting
2679 || machineState == MachineState_DeletingSnapshotOnline
2680 )
2681 {
2682 LogRelFlowFunc(("Machine is running.\n"));
2683
2684#ifdef VBOX_WITH_CROGL
2685 i_crOglWindowsShow(true);
2686#endif
2687 }
2688 else
2689 {
2690#ifdef VBOX_WITH_CROGL
2691 if (machineState == MachineState_Paused)
2692 i_crOglWindowsShow(false);
2693#endif
2694 }
2695 break;
2696 }
2697 default:
2698 AssertFailed();
2699 }
2700
2701 return S_OK;
2702}
2703
2704
2705// private methods
2706/////////////////////////////////////////////////////////////////////////////
2707
2708#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2709int Display::i_crViewportNotify(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height)
2710{
2711 VMMDev *pVMMDev = mParent->i_getVMMDev();
2712 if (!pVMMDev)
2713 return VERR_INVALID_STATE;
2714
2715 size_t cbData = RT_UOFFSETOF(VBOXCRCMDCTL_HGCM, aParms[5]);
2716 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)alloca(cbData);
2717
2718 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2719 pData->Hdr.u32Function = SHCRGL_HOST_FN_VIEWPORT_CHANGED;
2720
2721 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
2722 pData->aParms[0].u.uint32 = aScreenId;
2723
2724 pData->aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT;
2725 pData->aParms[1].u.uint32 = x;
2726
2727 pData->aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT;
2728 pData->aParms[2].u.uint32 = y;
2729
2730 pData->aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT;
2731 pData->aParms[3].u.uint32 = width;
2732
2733 pData->aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT;
2734 pData->aParms[4].u.uint32 = height;
2735
2736 return i_crCtlSubmitSyncIfHasDataForScreen(aScreenId, &pData->Hdr, (uint32_t)cbData);
2737}
2738#endif
2739
2740#ifdef VBOX_WITH_CRHGSMI
2741void Display::i_setupCrHgsmiData(void)
2742{
2743 VMMDev *pVMMDev = mParent->i_getVMMDev();
2744 Assert(pVMMDev);
2745 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
2746 AssertRC(rc);
2747
2748 if (pVMMDev)
2749 rc = pVMMDev->hgcmHostSvcHandleCreate("VBoxSharedCrOpenGL", &mhCrOglSvc);
2750 else
2751 rc = VERR_GENERAL_FAILURE;
2752
2753 if (RT_SUCCESS(rc))
2754 {
2755 Assert(mhCrOglSvc);
2756 /* setup command completion callback */
2757 VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion;
2758 Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB;
2759 Completion.Hdr.cbCmd = sizeof(Completion);
2760 Completion.hCompletion = mpDrv->pVBVACallbacks;
2761 Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync;
2762
2763 VBOXHGCMSVCPARM parm;
2764 parm.type = VBOX_HGCM_SVC_PARM_PTR;
2765 parm.u.pointer.addr = &Completion;
2766 parm.u.pointer.size = 0;
2767
2768 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm);
2769 if (RT_SUCCESS(rc))
2770 mCrOglCallbacks = Completion.MainInterface;
2771 else
2772 AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc));
2773 }
2774
2775 if (RT_FAILURE(rc))
2776 mhCrOglSvc = NULL;
2777
2778 RTCritSectRwLeaveExcl(&mCrOglLock);
2779}
2780
2781void Display::i_destructCrHgsmiData(void)
2782{
2783 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
2784 AssertRC(rc);
2785 mhCrOglSvc = NULL;
2786 RTCritSectRwLeaveExcl(&mCrOglLock);
2787}
2788#endif
2789
2790/**
2791 * Handle display resize event issued by the VGA device for the primary screen.
2792 *
2793 * @see PDMIDISPLAYCONNECTOR::pfnResize
2794 */
2795DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
2796 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
2797{
2798 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2799 Display *pThis = pDrv->pDisplay;
2800
2801 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
2802 bpp, pvVRAM, cbLine, cx, cy));
2803
2804 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false);
2805 if (!f)
2806 {
2807 /* This is a result of recursive call when the source bitmap is being updated
2808 * during a VGA resize. Tell the VGA device to ignore the call.
2809 *
2810 * @todo It is a workaround, actually pfnUpdateDisplayAll must
2811 * fail on resize.
2812 */
2813 LogRel(("displayResizeCallback: already processing\n"));
2814 return VINF_VGA_RESIZE_IN_PROGRESS;
2815 }
2816
2817 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE);
2818
2819 /* Restore the flag. */
2820 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true);
2821 AssertRelease(f);
2822
2823 return rc;
2824}
2825
2826/**
2827 * Handle display update.
2828 *
2829 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
2830 */
2831DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
2832 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
2833{
2834 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2835
2836#ifdef DEBUG_sunlover
2837 LogFlowFunc(("fVideoAccelEnabled = %d, %d,%d %dx%d\n",
2838 pDrv->pDisplay->mVideoAccelLegacy.fVideoAccelEnabled, x, y, cx, cy));
2839#endif /* DEBUG_sunlover */
2840
2841 /* This call does update regardless of VBVA status.
2842 * But in VBVA mode this is called only as result of
2843 * pfnUpdateDisplayAll in the VGA device.
2844 */
2845
2846 pDrv->pDisplay->i_handleDisplayUpdate(VBOX_VIDEO_PRIMARY_SCREEN, x, y, cx, cy);
2847}
2848
2849/**
2850 * Periodic display refresh callback.
2851 *
2852 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
2853 * @thread EMT
2854 */
2855DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
2856{
2857 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2858
2859#ifdef DEBUG_sunlover_2
2860 LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
2861 pDrv->pDisplay->mfVideoAccelEnabled));
2862#endif /* DEBUG_sunlover_2 */
2863
2864 Display *pDisplay = pDrv->pDisplay;
2865 unsigned uScreenId;
2866
2867 int rc = pDisplay->i_videoAccelRefreshProcess(pDrv->pUpPort);
2868 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */
2869 {
2870 if (rc == VWRN_INVALID_STATE)
2871 {
2872 /* No VBVA do a display update. */
2873 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN];
2874 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
2875 }
2876
2877 /* Inform the VRDP server that the current display update sequence is
2878 * completed. At this moment the framebuffer memory contains a definite
2879 * image, that is synchronized with the orders already sent to VRDP client.
2880 * The server can now process redraw requests from clients or initial
2881 * fullscreen updates for new clients.
2882 */
2883 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
2884 {
2885 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2886
2887 Assert(pDisplay->mParent && pDisplay->mParent->i_consoleVRDPServer());
2888 pDisplay->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, NULL, 0);
2889 }
2890 }
2891
2892#ifdef VBOX_WITH_VPX
2893 if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx))
2894 {
2895 do {
2896# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2897 BOOL is3denabled;
2898 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
2899 if (is3denabled)
2900 {
2901 if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
2902 {
2903 if (pDisplay->mCrOglCallbacks.pfnHasData())
2904 {
2905 /* submit */
2906 VBOXCRCMDCTL_HGCM *pData = &pDisplay->mCrOglScreenshotCtl;
2907
2908 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2909 pData->Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
2910
2911 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2912 pData->aParms[0].u.pointer.addr = &pDisplay->mCrOglScreenshotData;
2913 pData->aParms[0].u.pointer.size = sizeof(pDisplay->mCrOglScreenshotData);
2914 rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), Display::i_displayVRecCompletion, pDisplay);
2915 if (RT_SUCCESS(rc))
2916 break;
2917 else
2918 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
2919 }
2920
2921 /* no 3D data available, or error has occured,
2922 * go the straight way */
2923 ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE);
2924 }
2925 else
2926 {
2927 /* record request is still in progress, don't do anything */
2928 break;
2929 }
2930 }
2931# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
2932
2933 uint64_t u64Now = RTTimeProgramMilliTS();
2934 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
2935 {
2936 if (!pDisplay->maVideoRecEnabled[uScreenId])
2937 continue;
2938
2939 if (VideoRecIsFull(pDisplay->mpVideoRecCtx, uScreenId, u64Now))
2940 {
2941 pDisplay->i_VideoCaptureStop();
2942 pDisplay->mParent->i_machine()->COMSETTER(VideoCaptureEnabled)(false);
2943 break;
2944 }
2945
2946 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2947
2948 if ( !pFBInfo->pFramebuffer.isNull()
2949 && !pFBInfo->fDisabled)
2950 {
2951 rc = VERR_NOT_SUPPORTED;
2952 if ( pFBInfo->fVBVAEnabled
2953 && pFBInfo->pu8FramebufferVRAM)
2954 {
2955 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
2956 BitmapFormat_BGR,
2957 pFBInfo->u16BitsPerPixel,
2958 pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h,
2959 pFBInfo->pu8FramebufferVRAM, u64Now);
2960 }
2961 else if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && pDrv->IConnector.pu8Data)
2962 {
2963 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
2964 BitmapFormat_BGR,
2965 pDrv->IConnector.cBits,
2966 pDrv->IConnector.cbScanline, pDrv->IConnector.cx,
2967 pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now);
2968 }
2969 if (rc == VINF_TRY_AGAIN)
2970 break;
2971 }
2972 }
2973 } while (0);
2974 }
2975#endif /* VBOX_WITH_VPX */
2976
2977#ifdef DEBUG_sunlover_2
2978 LogFlowFunc(("leave\n"));
2979#endif /* DEBUG_sunlover_2 */
2980}
2981
2982/**
2983 * Reset notification
2984 *
2985 * @see PDMIDISPLAYCONNECTOR::pfnReset
2986 */
2987DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
2988{
2989 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2990
2991 LogRelFlowFunc(("\n"));
2992
2993 /* Disable VBVA mode. */
2994 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
2995}
2996
2997/**
2998 * LFBModeChange notification
2999 *
3000 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
3001 */
3002DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
3003{
3004 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3005
3006 LogRelFlowFunc(("fEnabled=%d\n", fEnabled));
3007
3008 NOREF(fEnabled);
3009
3010 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
3011 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
3012}
3013
3014/**
3015 * Adapter information change notification.
3016 *
3017 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
3018 */
3019DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
3020 uint32_t u32VRAMSize)
3021{
3022 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3023 pDrv->pDisplay->processAdapterData(pvVRAM, u32VRAMSize);
3024}
3025
3026/**
3027 * Display information change notification.
3028 *
3029 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
3030 */
3031DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface,
3032 void *pvVRAM, unsigned uScreenId)
3033{
3034 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3035 pDrv->pDisplay->processDisplayData(pvVRAM, uScreenId);
3036}
3037
3038#ifdef VBOX_WITH_VIDEOHWACCEL
3039
3040#ifndef S_FALSE
3041# define S_FALSE ((HRESULT)1L)
3042#endif
3043
3044int Display::i_handleVHWACommandProcess(PVBOXVHWACMD pCommand)
3045{
3046 unsigned id = (unsigned)pCommand->iDisplay;
3047 int rc = VINF_SUCCESS;
3048 if (id >= mcMonitors)
3049 return VERR_INVALID_PARAMETER;
3050
3051 ComPtr<IFramebuffer> pFramebuffer;
3052 AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS);
3053 pFramebuffer = maFramebuffers[id].pFramebuffer;
3054 bool fVHWASupported = RT_BOOL(maFramebuffers[id].u32Caps & FramebufferCapabilities_VHWA);
3055 arlock.release();
3056
3057 if (pFramebuffer == NULL || !fVHWASupported)
3058 return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */
3059
3060 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);
3061 if (hr == S_FALSE)
3062 return VINF_SUCCESS;
3063 else if (SUCCEEDED(hr))
3064 return VINF_CALLBACK_RETURN;
3065 else if (hr == E_ACCESSDENIED)
3066 return VERR_INVALID_STATE; /* notify we can not handle request atm */
3067 else if (hr == E_NOTIMPL)
3068 return VERR_NOT_IMPLEMENTED;
3069 return VERR_GENERAL_FAILURE;
3070}
3071
3072DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
3073{
3074 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3075
3076 return pDrv->pDisplay->i_handleVHWACommandProcess(pCommand);
3077}
3078#endif
3079
3080#ifdef VBOX_WITH_CRHGSMI
3081void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3082{
3083 mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks,
3084 (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);
3085}
3086
3087void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3088{
3089 PVBOXVDMACMD_CHROMIUM_CTL pCtl = (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr;
3090 mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, pCtl, result);
3091}
3092
3093void Display::i_handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)
3094{
3095 int rc = VERR_NOT_SUPPORTED;
3096 VBOXHGCMSVCPARM parm;
3097 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3098 parm.u.pointer.addr = pCmd;
3099 parm.u.pointer.size = cbCmd;
3100
3101 if (mhCrOglSvc)
3102 {
3103 VMMDev *pVMMDev = mParent->i_getVMMDev();
3104 if (pVMMDev)
3105 {
3106 /* no completion callback is specified with this call,
3107 * the CrOgl code will complete the CrHgsmi command once it processes it */
3108 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, NULL, NULL);
3109 AssertRC(rc);
3110 if (RT_SUCCESS(rc))
3111 return;
3112 }
3113 else
3114 rc = VERR_INVALID_STATE;
3115 }
3116
3117 /* we are here because something went wrong with command processing, complete it */
3118 i_handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm);
3119}
3120
3121void Display::i_handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)
3122{
3123 int rc = VERR_NOT_SUPPORTED;
3124 VBOXHGCMSVCPARM parm;
3125 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3126 parm.u.pointer.addr = pCtl;
3127 parm.u.pointer.size = cbCtl;
3128
3129 if (mhCrOglSvc)
3130 {
3131 VMMDev *pVMMDev = mParent->i_getVMMDev();
3132 if (pVMMDev)
3133 {
3134 bool fCheckPendingViewport = (pCtl->enmType == VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP);
3135 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm,
3136 Display::i_displayCrHgsmiControlCompletion, this);
3137 AssertRC(rc);
3138 if (RT_SUCCESS(rc))
3139 {
3140 if (fCheckPendingViewport)
3141 {
3142 ULONG ul;
3143 for (ul = 0; ul < mcMonitors; ul++)
3144 {
3145 DISPLAYFBINFO *pFb = &maFramebuffers[ul];
3146 if (!pFb->pendingViewportInfo.fPending)
3147 continue;
3148
3149 rc = i_crViewportNotify(ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y,
3150 pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height);
3151 if (RT_SUCCESS(rc))
3152 pFb->pendingViewportInfo.fPending = false;
3153 else
3154 {
3155 AssertMsgFailed(("crViewportNotify failed %d\n", rc));
3156 rc = VINF_SUCCESS;
3157 }
3158 }
3159 }
3160 return;
3161 }
3162 }
3163 else
3164 rc = VERR_INVALID_STATE;
3165 }
3166
3167 /* we are here because something went wrong with command processing, complete it */
3168 i_handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm);
3169}
3170
3171DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,
3172 uint32_t cbCmd)
3173{
3174 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3175
3176 pDrv->pDisplay->i_handleCrHgsmiCommandProcess(pCmd, cbCmd);
3177}
3178
3179DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,
3180 uint32_t cbCmd)
3181{
3182 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3183
3184 pDrv->pDisplay->i_handleCrHgsmiControlProcess(pCmd, cbCmd);
3185}
3186
3187DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3188 void *pvContext)
3189{
3190 AssertMsgFailed(("not expected!"));
3191 Display *pDisplay = (Display *)pvContext;
3192 pDisplay->i_handleCrHgsmiCommandCompletion(result, u32Function, pParam);
3193}
3194
3195DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3196 void *pvContext)
3197{
3198 Display *pDisplay = (Display *)pvContext;
3199 pDisplay->i_handleCrHgsmiControlCompletion(result, u32Function, pParam);
3200
3201}
3202#endif
3203
3204#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3205DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3206 void *pvContext)
3207{
3208 VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;
3209 if (pCmd->u.pfnInternal)
3210 ((PFNCRCTLCOMPLETION)pCmd->u.pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);
3211}
3212
3213int Display::i_handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3214 PFNCRCTLCOMPLETION pfnCompletion,
3215 void *pvCompletion)
3216{
3217 VMMDev *pVMMDev = mParent ? mParent->i_getVMMDev() : NULL;
3218 if (!pVMMDev)
3219 {
3220 AssertMsgFailed(("no vmmdev\n"));
3221 return VERR_INVALID_STATE;
3222 }
3223
3224 Assert(mhCrOglSvc);
3225 VBOXHGCMSVCPARM parm;
3226 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3227 parm.u.pointer.addr = pCmd;
3228 parm.u.pointer.size = cbCmd;
3229
3230 pCmd->u.pfnInternal = (void(*)())pfnCompletion;
3231 int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,
3232 pvCompletion);
3233 if (!RT_SUCCESS(rc))
3234 AssertMsgFailed(("hgcmHostFastCallAsync failed rc %d\n", rc));
3235
3236 return rc;
3237}
3238
3239DECLCALLBACK(int) Display::i_displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
3240 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3241 PFNCRCTLCOMPLETION pfnCompletion,
3242 void *pvCompletion)
3243{
3244 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3245 Display *pThis = pDrv->pDisplay;
3246 return pThis->i_handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);
3247}
3248
3249int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)
3250{
3251 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3252 if (RT_SUCCESS(rc))
3253 {
3254 if (mhCrOglSvc)
3255 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);
3256 else
3257 rc = VERR_NOT_SUPPORTED;
3258
3259 RTCritSectRwLeaveShared(&mCrOglLock);
3260 }
3261 return rc;
3262}
3263
3264int Display::i_crCtlSubmitSync(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3265{
3266 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3267 if (RT_SUCCESS(rc))
3268 {
3269 if (mhCrOglSvc)
3270 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmitSync(mpDrv->pVBVACallbacks, pCmd, cbCmd);
3271 else
3272 rc = VERR_NOT_SUPPORTED;
3273
3274 RTCritSectRwLeaveShared(&mCrOglLock);
3275 }
3276 return rc;
3277}
3278
3279int Display::i_crCtlSubmitAsyncCmdCopy(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3280{
3281 VBOXCRCMDCTL* pCmdCopy = (VBOXCRCMDCTL*)RTMemAlloc(cbCmd);
3282 if (!pCmdCopy)
3283 {
3284 LogRel(("RTMemAlloc failed\n"));
3285 return VERR_NO_MEMORY;
3286 }
3287
3288 memcpy(pCmdCopy, pCmd, cbCmd);
3289
3290 int rc = i_crCtlSubmit(pCmdCopy, cbCmd, i_displayCrCmdFree, pCmdCopy);
3291 if (RT_FAILURE(rc))
3292 {
3293 LogRel(("crCtlSubmit failed %d\n", rc));
3294 RTMemFree(pCmdCopy);
3295 return rc;
3296 }
3297
3298 return VINF_SUCCESS;
3299}
3300
3301int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3302{
3303 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3304 AssertRCReturn(rc, rc);
3305
3306 if (mCrOglCallbacks.pfnHasDataForScreen && mCrOglCallbacks.pfnHasDataForScreen(u32ScreenID))
3307 rc = i_crCtlSubmitSync(pCmd, cbCmd);
3308 else
3309 rc = i_crCtlSubmitAsyncCmdCopy(pCmd, cbCmd);
3310
3311 RTCritSectRwLeaveShared(&mCrOglLock);
3312
3313 return rc;
3314}
3315
3316bool Display::i_handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp)
3317{
3318# if VBOX_WITH_VPX
3319 return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp);
3320# else
3321 return false;
3322# endif
3323}
3324
3325void Display::i_handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp)
3326{
3327}
3328
3329void Display::i_handleCrVRecScreenshotPerform(uint32_t uScreen,
3330 uint32_t x, uint32_t y, uint32_t uPixelFormat,
3331 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
3332 uint32_t uGuestWidth, uint32_t uGuestHeight,
3333 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
3334{
3335 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3336# if VBOX_WITH_VPX
3337 int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y,
3338 uPixelFormat,
3339 uBitsPerPixel, uBytesPerLine,
3340 uGuestWidth, uGuestHeight,
3341 pu8BufferAddress, u64TimeStamp);
3342 Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/);
3343# endif
3344}
3345
3346void Display::i_handleVRecCompletion()
3347{
3348 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3349 ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);
3350}
3351
3352DECLCALLBACK(void) Display::i_displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen,
3353 uint32_t x, uint32_t y,
3354 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
3355 uint32_t uGuestWidth, uint32_t uGuestHeight,
3356 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
3357{
3358 Display *pDisplay = (Display *)pvCtx;
3359 pDisplay->i_handleCrVRecScreenshotPerform(uScreen,
3360 x, y, BitmapFormat_BGR, uBitsPerPixel,
3361 uBytesPerLine, uGuestWidth, uGuestHeight,
3362 pu8BufferAddress, u64TimeStamp);
3363}
3364
3365DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
3366{
3367 Display *pDisplay = (Display *)pvCtx;
3368 return pDisplay->i_handleCrVRecScreenshotBegin(uScreen, u64TimeStamp);
3369}
3370
3371DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
3372{
3373 Display *pDisplay = (Display *)pvCtx;
3374 pDisplay->i_handleCrVRecScreenshotEnd(uScreen, u64TimeStamp);
3375}
3376
3377DECLCALLBACK(void) Display::i_displayVRecCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
3378{
3379 Display *pDisplay = (Display *)pvCompletion;
3380 pDisplay->i_handleVRecCompletion();
3381}
3382
3383#endif
3384
3385
3386#ifdef VBOX_WITH_HGSMI
3387DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,
3388 bool fRenderThreadMode)
3389{
3390 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
3391
3392 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3393 Display *pThis = pDrv->pDisplay;
3394
3395 if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)
3396 {
3397 LogRel(("enabling different vbva mode"));
3398#ifdef DEBUG_misha
3399 AssertMsgFailed(("enabling different vbva mode"));
3400#endif
3401 return VERR_INVALID_STATE;
3402 }
3403
3404 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;
3405 pThis->maFramebuffers[uScreenId].pVBVAHostFlags = pHostFlags;
3406 pThis->maFramebuffers[uScreenId].fRenderThreadMode = fRenderThreadMode;
3407 pThis->maFramebuffers[uScreenId].fVBVAForceResize = true;
3408
3409 vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
3410
3411 return VINF_SUCCESS;
3412}
3413
3414DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
3415{
3416 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
3417
3418 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3419 Display *pThis = pDrv->pDisplay;
3420
3421 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3422
3423 bool fRenderThreadMode = pFBInfo->fRenderThreadMode;
3424
3425 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3426 {
3427 /* Make sure that the primary screen is visible now.
3428 * The guest can't use VBVA anymore, so only only the VGA device output works.
3429 */
3430 if (pFBInfo->fDisabled)
3431 {
3432 pFBInfo->fDisabled = false;
3433 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3434 GuestMonitorChangedEventType_Enabled,
3435 uScreenId,
3436 pFBInfo->xOrigin, pFBInfo->yOrigin,
3437 pFBInfo->w, pFBInfo->h);
3438 }
3439 }
3440
3441 pFBInfo->fVBVAEnabled = false;
3442 pFBInfo->fVBVAForceResize = false;
3443 pFBInfo->fRenderThreadMode = false;
3444
3445 vbvaSetMemoryFlagsHGSMI(uScreenId, 0, false, pFBInfo);
3446
3447 pFBInfo->pVBVAHostFlags = NULL;
3448
3449 if (!fRenderThreadMode && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3450 {
3451 /* Force full screen update, because VGA device must take control, do resize, etc. */
3452 pThis->mpDrv->pUpPort->pfnUpdateDisplayAll(pThis->mpDrv->pUpPort, /* fFailOnResize = */ false);
3453 }
3454}
3455
3456DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
3457{
3458 LogFlowFunc(("uScreenId %d\n", uScreenId));
3459
3460 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3461 Display *pThis = pDrv->pDisplay;
3462 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3463
3464 if (ASMAtomicReadU32(&pThis->mu32UpdateVBVAFlags) > 0)
3465 {
3466 vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,
3467 pThis->mcMonitors);
3468 ASMAtomicDecU32(&pThis->mu32UpdateVBVAFlags);
3469 }
3470}
3471
3472DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,
3473 const PVBVACMDHDR pCmd, size_t cbCmd)
3474{
3475 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
3476
3477 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3478 Display *pThis = pDrv->pDisplay;
3479 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3480
3481 if (pFBInfo->fDefaultFormat)
3482 {
3483 /* Make sure that framebuffer contains the same image as the guest VRAM. */
3484 if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
3485 && !pFBInfo->fDisabled)
3486 {
3487 pDrv->pUpPort->pfnUpdateDisplayRect(pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h);
3488 }
3489 else if ( !pFBInfo->pSourceBitmap.isNull()
3490 && !pFBInfo->fDisabled)
3491 {
3492 /* Render VRAM content to the framebuffer. */
3493 BYTE *pAddress = NULL;
3494 ULONG ulWidth = 0;
3495 ULONG ulHeight = 0;
3496 ULONG ulBitsPerPixel = 0;
3497 ULONG ulBytesPerLine = 0;
3498 ULONG ulPixelFormat = 0;
3499
3500 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
3501 &ulWidth,
3502 &ulHeight,
3503 &ulBitsPerPixel,
3504 &ulBytesPerLine,
3505 &ulPixelFormat);
3506 if (SUCCEEDED(hrc))
3507 {
3508 uint32_t width = pCmd->w;
3509 uint32_t height = pCmd->h;
3510
3511 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
3512 int32_t xSrc = pCmd->x - pFBInfo->xOrigin;
3513 int32_t ySrc = pCmd->y - pFBInfo->yOrigin;
3514 uint32_t u32SrcWidth = pFBInfo->w;
3515 uint32_t u32SrcHeight = pFBInfo->h;
3516 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
3517 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
3518
3519 uint8_t *pu8Dst = pAddress;
3520 int32_t xDst = xSrc;
3521 int32_t yDst = ySrc;
3522 uint32_t u32DstWidth = u32SrcWidth;
3523 uint32_t u32DstHeight = u32SrcHeight;
3524 uint32_t u32DstLineSize = u32DstWidth * 4;
3525 uint32_t u32DstBitsPerPixel = 32;
3526
3527 pDrv->pUpPort->pfnCopyRect(pDrv->pUpPort,
3528 width, height,
3529 pu8Src,
3530 xSrc, ySrc,
3531 u32SrcWidth, u32SrcHeight,
3532 u32SrcLineSize, u32SrcBitsPerPixel,
3533 pu8Dst,
3534 xDst, yDst,
3535 u32DstWidth, u32DstHeight,
3536 u32DstLineSize, u32DstBitsPerPixel);
3537 }
3538 }
3539 }
3540
3541 VBVACMDHDR hdrSaved = *pCmd;
3542
3543 VBVACMDHDR *pHdrUnconst = (VBVACMDHDR *)pCmd;
3544
3545 pHdrUnconst->x -= (int16_t)pFBInfo->xOrigin;
3546 pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin;
3547
3548 /* @todo new SendUpdate entry which can get a separate cmd header or coords. */
3549 pThis->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, pCmd, (uint32_t)cbCmd);
3550
3551 *pHdrUnconst = hdrSaved;
3552}
3553
3554DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,
3555 uint32_t cx, uint32_t cy)
3556{
3557 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));
3558
3559 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3560 Display *pThis = pDrv->pDisplay;
3561 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3562
3563 /* @todo handleFramebufferUpdate (uScreenId,
3564 * x - pThis->maFramebuffers[uScreenId].xOrigin,
3565 * y - pThis->maFramebuffers[uScreenId].yOrigin,
3566 * cx, cy);
3567 */
3568 pThis->i_handleDisplayUpdate(uScreenId, x - pFBInfo->xOrigin, y - pFBInfo->yOrigin, cx, cy);
3569}
3570
3571#ifdef DEBUG_sunlover
3572static void logVBVAResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)
3573{
3574 LogRel(("displayVBVAResize: [%d] %s\n"
3575 " pView->u32ViewIndex %d\n"
3576 " pView->u32ViewOffset 0x%08X\n"
3577 " pView->u32ViewSize 0x%08X\n"
3578 " pView->u32MaxScreenSize 0x%08X\n"
3579 " pScreen->i32OriginX %d\n"
3580 " pScreen->i32OriginY %d\n"
3581 " pScreen->u32StartOffset 0x%08X\n"
3582 " pScreen->u32LineSize 0x%08X\n"
3583 " pScreen->u32Width %d\n"
3584 " pScreen->u32Height %d\n"
3585 " pScreen->u16BitsPerPixel %d\n"
3586 " pScreen->u16Flags 0x%04X\n"
3587 " pFBInfo->u32Offset 0x%08X\n"
3588 " pFBInfo->u32MaxFramebufferSize 0x%08X\n"
3589 " pFBInfo->u32InformationSize 0x%08X\n"
3590 " pFBInfo->fDisabled %d\n"
3591 " xOrigin, yOrigin, w, h: %d,%d %dx%d\n"
3592 " pFBInfo->u16BitsPerPixel %d\n"
3593 " pFBInfo->pu8FramebufferVRAM %p\n"
3594 " pFBInfo->u32LineSize 0x%08X\n"
3595 " pFBInfo->flags 0x%04X\n"
3596 " pFBInfo->pHostEvents %p\n"
3597 " pFBInfo->fDefaultFormat %d\n"
3598 " pFBInfo->fVBVAEnabled %d\n"
3599 " pFBInfo->fVBVAForceResize %d\n"
3600 " pFBInfo->pVBVAHostFlags %p\n"
3601 "",
3602 pScreen->u32ViewIndex,
3603 (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)? "DISABLED": "ENABLED",
3604 pView->u32ViewIndex,
3605 pView->u32ViewOffset,
3606 pView->u32ViewSize,
3607 pView->u32MaxScreenSize,
3608 pScreen->i32OriginX,
3609 pScreen->i32OriginY,
3610 pScreen->u32StartOffset,
3611 pScreen->u32LineSize,
3612 pScreen->u32Width,
3613 pScreen->u32Height,
3614 pScreen->u16BitsPerPixel,
3615 pScreen->u16Flags,
3616 pFBInfo->u32Offset,
3617 pFBInfo->u32MaxFramebufferSize,
3618 pFBInfo->u32InformationSize,
3619 pFBInfo->fDisabled,
3620 pFBInfo->xOrigin,
3621 pFBInfo->yOrigin,
3622 pFBInfo->w,
3623 pFBInfo->h,
3624 pFBInfo->u16BitsPerPixel,
3625 pFBInfo->pu8FramebufferVRAM,
3626 pFBInfo->u32LineSize,
3627 pFBInfo->flags,
3628 pFBInfo->pHostEvents,
3629 pFBInfo->fDefaultFormat,
3630 pFBInfo->fVBVAEnabled,
3631 pFBInfo->fVBVAForceResize,
3632 pFBInfo->pVBVAHostFlags
3633 ));
3634}
3635#endif /* DEBUG_sunlover */
3636
3637DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView,
3638 const PVBVAINFOSCREEN pScreen, void *pvVRAM)
3639{
3640 LogRelFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));
3641
3642 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3643 Display *pThis = pDrv->pDisplay;
3644
3645 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];
3646
3647 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
3648 {
3649 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
3650
3651 pFBInfo->fDisabled = true;
3652 pFBInfo->flags = pScreen->u16Flags;
3653
3654 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.
3655 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,
3656 * the VM window will be black. */
3657 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;
3658 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;
3659 pThis->i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,
3660 u32Width, u32Height, pScreen->u16Flags);
3661
3662 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3663 GuestMonitorChangedEventType_Disabled,
3664 pScreen->u32ViewIndex,
3665 0, 0, 0, 0);
3666 return VINF_SUCCESS;
3667 }
3668
3669 /* If display was disabled or there is no framebuffer, a resize will be required,
3670 * because the framebuffer was/will be changed.
3671 */
3672 bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull();
3673
3674 if (pFBInfo->fVBVAForceResize)
3675 {
3676 /* VBVA was just enabled. Do the resize. */
3677 fResize = true;
3678 pFBInfo->fVBVAForceResize = false;
3679 }
3680
3681 /* Check if this is a real resize or a notification about the screen origin.
3682 * The guest uses this VBVAResize call for both.
3683 */
3684 fResize = fResize
3685 || pFBInfo->u16BitsPerPixel != pScreen->u16BitsPerPixel
3686 || pFBInfo->pu8FramebufferVRAM != (uint8_t *)pvVRAM + pScreen->u32StartOffset
3687 || pFBInfo->u32LineSize != pScreen->u32LineSize
3688 || pFBInfo->w != pScreen->u32Width
3689 || pFBInfo->h != pScreen->u32Height;
3690
3691 bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX
3692 || pFBInfo->yOrigin != pScreen->i32OriginY;
3693
3694 if (fNewOrigin || fResize)
3695 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
3696
3697 if (pFBInfo->fDisabled)
3698 {
3699 pFBInfo->fDisabled = false;
3700 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3701 GuestMonitorChangedEventType_Enabled,
3702 pScreen->u32ViewIndex,
3703 pScreen->i32OriginX, pScreen->i32OriginY,
3704 pScreen->u32Width, pScreen->u32Height);
3705 /* Continue to update pFBInfo. */
3706 }
3707
3708 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */
3709 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */
3710 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */
3711
3712 pFBInfo->xOrigin = pScreen->i32OriginX;
3713 pFBInfo->yOrigin = pScreen->i32OriginY;
3714
3715 pFBInfo->w = pScreen->u32Width;
3716 pFBInfo->h = pScreen->u32Height;
3717
3718 pFBInfo->u16BitsPerPixel = pScreen->u16BitsPerPixel;
3719 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM + pScreen->u32StartOffset;
3720 pFBInfo->u32LineSize = pScreen->u32LineSize;
3721
3722 pFBInfo->flags = pScreen->u16Flags;
3723
3724 if (fNewOrigin)
3725 {
3726 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3727 GuestMonitorChangedEventType_NewOrigin,
3728 pScreen->u32ViewIndex,
3729 pScreen->i32OriginX, pScreen->i32OriginY,
3730 0, 0);
3731 }
3732
3733 if (!fResize)
3734 {
3735 /* No parameters of the framebuffer have actually changed. */
3736 if (fNewOrigin)
3737 {
3738 /* VRDP server still need this notification. */
3739 LogRelFlowFunc(("Calling VRDP\n"));
3740 pThis->mParent->i_consoleVRDPServer()->SendResize();
3741 }
3742 return VINF_SUCCESS;
3743 }
3744
3745 /* Do a regular resize. */
3746 return pThis->i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
3747 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
3748 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags);
3749}
3750
3751DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
3752 uint32_t xHot, uint32_t yHot,
3753 uint32_t cx, uint32_t cy,
3754 const void *pvShape)
3755{
3756 LogFlowFunc(("\n"));
3757
3758 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3759 Display *pThis = pDrv->pDisplay;
3760
3761 uint32_t cbShape = 0;
3762 if (pvShape)
3763 {
3764 cbShape = (cx + 7) / 8 * cy; /* size of the AND mask */
3765 cbShape = ((cbShape + 3) & ~3) + cx * 4 * cy; /* + gap + size of the XOR mask */
3766 }
3767
3768 /* Tell the console about it */
3769 pDrv->pDisplay->mParent->i_onMousePointerShapeChange(fVisible, fAlpha,
3770 xHot, yHot, cx, cy, (uint8_t *)pvShape, cbShape);
3771
3772 return VINF_SUCCESS;
3773}
3774#endif /* VBOX_WITH_HGSMI */
3775
3776/**
3777 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3778 */
3779DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3780{
3781 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
3782 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3783 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
3784 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);
3785 return NULL;
3786}
3787
3788
3789/**
3790 * Destruct a display driver instance.
3791 *
3792 * @returns VBox status.
3793 * @param pDrvIns The driver instance data.
3794 */
3795DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)
3796{
3797 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
3798 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3799 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
3800
3801 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
3802
3803 pThis->IConnector.pu8Data = NULL;
3804 pThis->IConnector.cbScanline = 0;
3805 pThis->IConnector.cBits = 32;
3806 pThis->IConnector.cx = 0;
3807 pThis->IConnector.cy = 0;
3808
3809 if (pThis->pDisplay)
3810 {
3811 AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS);
3812#ifdef VBOX_WITH_VPX
3813 pThis->pDisplay->i_VideoCaptureStop();
3814#endif
3815#ifdef VBOX_WITH_CRHGSMI
3816 pThis->pDisplay->i_destructCrHgsmiData();
3817#endif
3818 pThis->pDisplay->mpDrv = NULL;
3819 pThis->pDisplay->mpVMMDev = NULL;
3820 }
3821}
3822
3823
3824/**
3825 * Construct a display driver instance.
3826 *
3827 * @copydoc FNPDMDRVCONSTRUCT
3828 */
3829DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
3830{
3831 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
3832 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3833 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
3834
3835 /*
3836 * Validate configuration.
3837 */
3838 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
3839 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
3840 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
3841 ("Configuration error: Not possible to attach anything to this driver!\n"),
3842 VERR_PDM_DRVINS_NO_ATTACH);
3843
3844 /*
3845 * Init Interfaces.
3846 */
3847 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;
3848
3849 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;
3850 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;
3851 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;
3852 pThis->IConnector.pfnReset = Display::i_displayResetCallback;
3853 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;
3854 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;
3855 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;
3856#ifdef VBOX_WITH_VIDEOHWACCEL
3857 pThis->IConnector.pfnVHWACommandProcess = Display::i_displayVHWACommandProcess;
3858#endif
3859#ifdef VBOX_WITH_CRHGSMI
3860 pThis->IConnector.pfnCrHgsmiCommandProcess = Display::i_displayCrHgsmiCommandProcess;
3861 pThis->IConnector.pfnCrHgsmiControlProcess = Display::i_displayCrHgsmiControlProcess;
3862#endif
3863#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3864 pThis->IConnector.pfnCrHgcmCtlSubmit = Display::i_displayCrHgcmCtlSubmit;
3865#endif
3866#ifdef VBOX_WITH_HGSMI
3867 pThis->IConnector.pfnVBVAEnable = Display::i_displayVBVAEnable;
3868 pThis->IConnector.pfnVBVADisable = Display::i_displayVBVADisable;
3869 pThis->IConnector.pfnVBVAUpdateBegin = Display::i_displayVBVAUpdateBegin;
3870 pThis->IConnector.pfnVBVAUpdateProcess = Display::i_displayVBVAUpdateProcess;
3871 pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;
3872 pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;
3873 pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;
3874#endif
3875
3876 /*
3877 * Get the IDisplayPort interface of the above driver/device.
3878 */
3879 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);
3880 if (!pThis->pUpPort)
3881 {
3882 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
3883 return VERR_PDM_MISSING_INTERFACE_ABOVE;
3884 }
3885#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
3886 pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS);
3887 if (!pThis->pVBVACallbacks)
3888 {
3889 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
3890 return VERR_PDM_MISSING_INTERFACE_ABOVE;
3891 }
3892#endif
3893 /*
3894 * Get the Display object pointer and update the mpDrv member.
3895 */
3896 void *pv;
3897 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
3898 if (RT_FAILURE(rc))
3899 {
3900 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
3901 return rc;
3902 }
3903 Display *pDisplay = (Display *)pv; /** @todo Check this cast! */
3904 pThis->pDisplay = pDisplay;
3905 pThis->pDisplay->mpDrv = pThis;
3906
3907 /* Disable VRAM to a buffer copy initially. */
3908 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
3909 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */
3910
3911 /*
3912 * Start periodic screen refreshes
3913 */
3914 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);
3915
3916#ifdef VBOX_WITH_CRHGSMI
3917 pDisplay->i_setupCrHgsmiData();
3918#endif
3919
3920#ifdef VBOX_WITH_VPX
3921 ComPtr<IMachine> pMachine = pDisplay->mParent->i_machine();
3922 BOOL fEnabled = false;
3923 HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);
3924 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
3925 if (fEnabled)
3926 {
3927 rc = pDisplay->i_VideoCaptureStart();
3928 fireVideoCaptureChangedEvent(pDisplay->mParent->i_getEventSource());
3929 }
3930#endif
3931
3932 return rc;
3933}
3934
3935
3936/**
3937 * Display driver registration record.
3938 */
3939const PDMDRVREG Display::DrvReg =
3940{
3941 /* u32Version */
3942 PDM_DRVREG_VERSION,
3943 /* szName */
3944 "MainDisplay",
3945 /* szRCMod */
3946 "",
3947 /* szR0Mod */
3948 "",
3949 /* pszDescription */
3950 "Main display driver (Main as in the API).",
3951 /* fFlags */
3952 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
3953 /* fClass. */
3954 PDM_DRVREG_CLASS_DISPLAY,
3955 /* cMaxInstances */
3956 ~0U,
3957 /* cbInstance */
3958 sizeof(DRVMAINDISPLAY),
3959 /* pfnConstruct */
3960 Display::i_drvConstruct,
3961 /* pfnDestruct */
3962 Display::i_drvDestruct,
3963 /* pfnRelocate */
3964 NULL,
3965 /* pfnIOCtl */
3966 NULL,
3967 /* pfnPowerOn */
3968 NULL,
3969 /* pfnReset */
3970 NULL,
3971 /* pfnSuspend */
3972 NULL,
3973 /* pfnResume */
3974 NULL,
3975 /* pfnAttach */
3976 NULL,
3977 /* pfnDetach */
3978 NULL,
3979 /* pfnPowerOff */
3980 NULL,
3981 /* pfnSoftReset */
3982 NULL,
3983 /* u32EndVersion */
3984 PDM_DRVREG_VERSION
3985};
3986
3987/* 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