VirtualBox

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

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

Main: safearray cleanup, removed unnecessary SafeArray<->vector conversions

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 136.6 KB
Line 
1/* $Id: DisplayImpl.cpp 52934 2014-10-02 13:53:30Z 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 i_handleResizeCompletedEMT(uScreenId, TRUE);
889
890 bool fUpdateImage = RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_UpdateImage);
891 if (fUpdateImage && !pFBInfo->pFramebuffer.isNull())
892 {
893 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
894 HRESULT hr = QuerySourceBitmap(uScreenId, pSourceBitmap.asOutParam());
895 if (SUCCEEDED(hr))
896 {
897 BYTE *pAddress = NULL;
898 ULONG ulWidth = 0;
899 ULONG ulHeight = 0;
900 ULONG ulBitsPerPixel = 0;
901 ULONG ulBytesPerLine = 0;
902 ULONG ulPixelFormat = 0;
903
904 hr = pSourceBitmap->QueryBitmapInfo(&pAddress,
905 &ulWidth,
906 &ulHeight,
907 &ulBitsPerPixel,
908 &ulBytesPerLine,
909 &ulPixelFormat);
910 if (SUCCEEDED(hr))
911 {
912 pFBInfo->updateImage.pSourceBitmap = pSourceBitmap;
913 pFBInfo->updateImage.pu8Address = pAddress;
914 pFBInfo->updateImage.cbLine = ulBytesPerLine;
915 }
916 }
917 }
918
919 return VINF_SUCCESS;
920}
921
922/**
923 * Framebuffer has been resized.
924 * Read the new display data and unlock the framebuffer.
925 *
926 * @thread EMT
927 */
928void Display::i_handleResizeCompletedEMT(unsigned uScreenId, BOOL fResizeContext)
929{
930 LogRelFlowFunc(("\n"));
931
932 do /* to use 'break' */
933 {
934 if (uScreenId >= mcMonitors)
935 {
936 break;
937 }
938
939 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
940
941 /* Inform VRDP server about the change of display parameters.
942 * Must be done before calling NotifyUpdate below.
943 */
944 LogRelFlowFunc(("Calling VRDP\n"));
945 mParent->i_consoleVRDPServer()->SendResize();
946
947 /* @todo Merge these two 'if's within one 'if (!pFBInfo->pFramebuffer.isNull())' */
948 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull())
949 {
950 /* If the screen resize was because of disabling, tell framebuffer to repaint.
951 * The framebuffer if now in default format so it will not use guest VRAM
952 * and will show usually black image which is there after framebuffer resize.
953 */
954 if (pFBInfo->fDisabled)
955 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, mpDrv->IConnector.cx, mpDrv->IConnector.cy);
956 }
957 else if (!pFBInfo->pFramebuffer.isNull())
958 {
959 /* If the screen resize was because of disabling, tell framebuffer to repaint.
960 * The framebuffer if now in default format so it will not use guest VRAM
961 * and will show usually black image which is there after framebuffer resize.
962 */
963 if (pFBInfo->fDisabled)
964 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, pFBInfo->w, pFBInfo->h);
965 }
966 LogRelFlow(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat));
967 } while(0);
968}
969
970static void i_checkCoordBounds(int *px, int *py, int *pw, int *ph, int cx, int cy)
971{
972 /* Correct negative x and y coordinates. */
973 if (*px < 0)
974 {
975 *px += *pw; /* Compute xRight which is also the new width. */
976
977 *pw = (*px < 0)? 0: *px;
978
979 *px = 0;
980 }
981
982 if (*py < 0)
983 {
984 *py += *ph; /* Compute xBottom, which is also the new height. */
985
986 *ph = (*py < 0)? 0: *py;
987
988 *py = 0;
989 }
990
991 /* Also check if coords are greater than the display resolution. */
992 if (*px + *pw > cx)
993 {
994 *pw = cx > *px? cx - *px: 0;
995 }
996
997 if (*py + *ph > cy)
998 {
999 *ph = cy > *py? cy - *py: 0;
1000 }
1001}
1002
1003void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h)
1004{
1005 /*
1006 * Always runs under either VBVA lock or, for HGSMI, DevVGA lock.
1007 * Safe to use VBVA vars and take the framebuffer lock.
1008 */
1009
1010#ifdef DEBUG_sunlover
1011 LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n",
1012 uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy));
1013#endif /* DEBUG_sunlover */
1014
1015 /* No updates for a disabled guest screen. */
1016 if (maFramebuffers[uScreenId].fDisabled)
1017 return;
1018
1019 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1020 i_checkCoordBounds (&x, &y, &w, &h, mpDrv->IConnector.cx, mpDrv->IConnector.cy);
1021 else
1022 i_checkCoordBounds (&x, &y, &w, &h, maFramebuffers[uScreenId].w,
1023 maFramebuffers[uScreenId].h);
1024
1025 IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;
1026 if (pFramebuffer != NULL)
1027 {
1028 if (w != 0 && h != 0)
1029 {
1030 bool fUpdateImage = RT_BOOL(maFramebuffers[uScreenId].u32Caps & FramebufferCapabilities_UpdateImage);
1031 if (RT_LIKELY(!fUpdateImage))
1032 {
1033 pFramebuffer->NotifyUpdate(x, y, w, h);
1034 }
1035 else
1036 {
1037 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1038
1039 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1040
1041 if (!pFBInfo->updateImage.pSourceBitmap.isNull())
1042 {
1043 Assert(pFBInfo->updateImage.pu8Address);
1044
1045 size_t cbData = w * h * 4;
1046 com::SafeArray<BYTE> image(cbData);
1047
1048 uint8_t *pu8Dst = image.raw();
1049 const uint8_t *pu8Src = pFBInfo->updateImage.pu8Address + pFBInfo->updateImage.cbLine * y + x * 4;
1050
1051 int i;
1052 for (i = y; i < y + h; ++i)
1053 {
1054 memcpy(pu8Dst, pu8Src, w * 4);
1055 pu8Dst += w * 4;
1056 pu8Src += pFBInfo->updateImage.cbLine;
1057 }
1058
1059 pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));
1060 }
1061 }
1062 }
1063 }
1064
1065#ifndef VBOX_WITH_HGSMI
1066 if (!mVideoAccelLegacy.fVideoAccelEnabled)
1067 {
1068#else
1069 if (!mVideoAccelLegacy.fVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)
1070 {
1071#endif /* VBOX_WITH_HGSMI */
1072 /* When VBVA is enabled, the VRDP server is informed
1073 * either in VideoAccelFlush or displayVBVAUpdateProcess.
1074 * Inform the server here only if VBVA is disabled.
1075 */
1076 mParent->i_consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);
1077 }
1078}
1079
1080/**
1081 * Returns the upper left and lower right corners of the virtual framebuffer.
1082 * The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),
1083 * and the origin is (0, 0), not (1, 1) like the GUI returns.
1084 */
1085void Display::i_getFramebufferDimensions(int32_t *px1, int32_t *py1,
1086 int32_t *px2, int32_t *py2)
1087{
1088 int32_t x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1089 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1090
1091 AssertPtrReturnVoid(px1);
1092 AssertPtrReturnVoid(py1);
1093 AssertPtrReturnVoid(px2);
1094 AssertPtrReturnVoid(py2);
1095 LogRelFlowFunc(("\n"));
1096
1097 if (!mpDrv)
1098 return;
1099 /* If VBVA is not in use then this flag will not be set and this
1100 * will still work as it should. */
1101 if (!maFramebuffers[0].fDisabled)
1102 {
1103 x1 = (int32_t)maFramebuffers[0].xOrigin;
1104 y1 = (int32_t)maFramebuffers[0].yOrigin;
1105 x2 = mpDrv->IConnector.cx + (int32_t)maFramebuffers[0].xOrigin;
1106 y2 = mpDrv->IConnector.cy + (int32_t)maFramebuffers[0].yOrigin;
1107 }
1108 for (unsigned i = 1; i < mcMonitors; ++i)
1109 {
1110 if (!maFramebuffers[i].fDisabled)
1111 {
1112 x1 = RT_MIN(x1, maFramebuffers[i].xOrigin);
1113 y1 = RT_MIN(y1, maFramebuffers[i].yOrigin);
1114 x2 = RT_MAX(x2, maFramebuffers[i].xOrigin
1115 + (int32_t)maFramebuffers[i].w);
1116 y2 = RT_MAX(y2, maFramebuffers[i].yOrigin
1117 + (int32_t)maFramebuffers[i].h);
1118 }
1119 }
1120 *px1 = x1;
1121 *py1 = y1;
1122 *px2 = x2;
1123 *py2 = y2;
1124}
1125
1126static bool displayIntersectRect(RTRECT *prectResult,
1127 const RTRECT *prect1,
1128 const RTRECT *prect2)
1129{
1130 /* Initialize result to an empty record. */
1131 memset(prectResult, 0, sizeof(RTRECT));
1132
1133 int xLeftResult = RT_MAX(prect1->xLeft, prect2->xLeft);
1134 int xRightResult = RT_MIN(prect1->xRight, prect2->xRight);
1135
1136 if (xLeftResult < xRightResult)
1137 {
1138 /* There is intersection by X. */
1139
1140 int yTopResult = RT_MAX(prect1->yTop, prect2->yTop);
1141 int yBottomResult = RT_MIN(prect1->yBottom, prect2->yBottom);
1142
1143 if (yTopResult < yBottomResult)
1144 {
1145 /* There is intersection by Y. */
1146
1147 prectResult->xLeft = xLeftResult;
1148 prectResult->yTop = yTopResult;
1149 prectResult->xRight = xRightResult;
1150 prectResult->yBottom = yBottomResult;
1151
1152 return true;
1153 }
1154 }
1155
1156 return false;
1157}
1158
1159int Display::i_handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect)
1160{
1161 RTRECT *pVisibleRegion = (RTRECT *)RTMemTmpAlloc( RT_MAX(cRect, 1)
1162 * sizeof(RTRECT));
1163 if (!pVisibleRegion)
1164 {
1165 return VERR_NO_TMP_MEMORY;
1166 }
1167
1168 unsigned uScreenId;
1169 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
1170 {
1171 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1172
1173 if ( !pFBInfo->pFramebuffer.isNull()
1174 & RT_BOOL(pFBInfo->u32Caps & FramebufferCapabilities_VisibleRegion))
1175 {
1176 /* Prepare a new array of rectangles which intersect with the framebuffer.
1177 */
1178 RTRECT rectFramebuffer;
1179 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1180 {
1181 rectFramebuffer.xLeft = 0;
1182 rectFramebuffer.yTop = 0;
1183 if (mpDrv)
1184 {
1185 rectFramebuffer.xRight = mpDrv->IConnector.cx;
1186 rectFramebuffer.yBottom = mpDrv->IConnector.cy;
1187 }
1188 else
1189 {
1190 rectFramebuffer.xRight = 0;
1191 rectFramebuffer.yBottom = 0;
1192 }
1193 }
1194 else
1195 {
1196 rectFramebuffer.xLeft = pFBInfo->xOrigin;
1197 rectFramebuffer.yTop = pFBInfo->yOrigin;
1198 rectFramebuffer.xRight = pFBInfo->xOrigin + pFBInfo->w;
1199 rectFramebuffer.yBottom = pFBInfo->yOrigin + pFBInfo->h;
1200 }
1201
1202 uint32_t cRectVisibleRegion = 0;
1203
1204 uint32_t i;
1205 for (i = 0; i < cRect; i++)
1206 {
1207 if (displayIntersectRect(&pVisibleRegion[cRectVisibleRegion], &pRect[i], &rectFramebuffer))
1208 {
1209 pVisibleRegion[cRectVisibleRegion].xLeft -= pFBInfo->xOrigin;
1210 pVisibleRegion[cRectVisibleRegion].yTop -= pFBInfo->yOrigin;
1211 pVisibleRegion[cRectVisibleRegion].xRight -= pFBInfo->xOrigin;
1212 pVisibleRegion[cRectVisibleRegion].yBottom -= pFBInfo->yOrigin;
1213
1214 cRectVisibleRegion++;
1215 }
1216 }
1217 pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion);
1218 }
1219 }
1220
1221#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1222 BOOL is3denabled = FALSE;
1223
1224 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
1225
1226 VMMDev *vmmDev = mParent->i_getVMMDev();
1227 if (is3denabled && vmmDev)
1228 {
1229 if (mhCrOglSvc)
1230 {
1231 VBOXCRCMDCTL_HGCM *pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(RT_MAX(cRect, 1) * sizeof(RTRECT)
1232 + sizeof(VBOXCRCMDCTL_HGCM));
1233 if (pCtl)
1234 {
1235 RTRECT *pRectsCopy = (RTRECT*)(pCtl+1);
1236 memcpy(pRectsCopy, pRect, cRect * sizeof(RTRECT));
1237
1238 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1239 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
1240
1241 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
1242 pCtl->aParms[0].u.pointer.addr = pRectsCopy;
1243 pCtl->aParms[0].u.pointer.size = cRect * sizeof(RTRECT);
1244
1245 int rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);
1246 if (!RT_SUCCESS(rc))
1247 {
1248 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
1249 RTMemFree(pCtl);
1250 }
1251 }
1252 else
1253 AssertMsgFailed(("failed to allocate rects memory\n"));
1254 }
1255 else
1256 AssertMsgFailed(("mhCrOglSvc is NULL\n"));
1257 }
1258#endif
1259
1260 RTMemTmpFree(pVisibleRegion);
1261
1262 return VINF_SUCCESS;
1263}
1264
1265int Display::i_handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect)
1266{
1267 // @todo Currently not used by the guest and is not implemented in framebuffers. Remove?
1268 return VERR_NOT_SUPPORTED;
1269}
1270
1271#ifdef VBOX_WITH_HGSMI
1272static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId,
1273 uint32_t fu32SupportedOrders,
1274 bool fVideoAccelVRDP,
1275 DISPLAYFBINFO *pFBInfo)
1276{
1277 LogRelFlowFunc(("HGSMI[%d]: %p\n", uScreenId, pFBInfo->pVBVAHostFlags));
1278
1279 if (pFBInfo->pVBVAHostFlags)
1280 {
1281 uint32_t fu32HostEvents = VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
1282
1283 if (pFBInfo->fVBVAEnabled)
1284 {
1285 fu32HostEvents |= VBVA_F_MODE_ENABLED;
1286
1287 if (fVideoAccelVRDP)
1288 {
1289 fu32HostEvents |= VBVA_F_MODE_VRDP;
1290 }
1291 }
1292
1293 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32HostEvents, fu32HostEvents);
1294 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32SupportedOrders, fu32SupportedOrders);
1295
1296 LogRelFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));
1297 }
1298}
1299
1300static void vbvaSetMemoryFlagsAllHGSMI(uint32_t fu32SupportedOrders,
1301 bool fVideoAccelVRDP,
1302 DISPLAYFBINFO *paFBInfos,
1303 unsigned cFBInfos)
1304{
1305 unsigned uScreenId;
1306
1307 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
1308 {
1309 vbvaSetMemoryFlagsHGSMI(uScreenId, fu32SupportedOrders, fVideoAccelVRDP, &paFBInfos[uScreenId]);
1310 }
1311}
1312#endif /* VBOX_WITH_HGSMI */
1313
1314int Display::VideoAccelEnableVMMDev(bool fEnable, VBVAMEMORY *pVbvaMemory)
1315{
1316 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory));
1317 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy);
1318 if (RT_SUCCESS(rc))
1319 {
1320 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort);
1321 videoAccelLeaveVMMDev(&mVideoAccelLegacy);
1322 }
1323 LogFlowFunc(("leave %Rrc\n", rc));
1324 return rc;
1325}
1326
1327int Display::VideoAccelEnableVGA(bool fEnable, VBVAMEMORY *pVbvaMemory)
1328{
1329 LogFlowFunc(("%d %p\n", fEnable, pVbvaMemory));
1330 int rc = videoAccelEnterVGA(&mVideoAccelLegacy);
1331 if (RT_SUCCESS(rc))
1332 {
1333 rc = i_VideoAccelEnable(fEnable, pVbvaMemory, mpDrv->pUpPort);
1334 videoAccelLeaveVGA(&mVideoAccelLegacy);
1335 }
1336 LogFlowFunc(("leave %Rrc\n", rc));
1337 return rc;
1338}
1339
1340void Display::VideoAccelFlushVMMDev(void)
1341{
1342 LogFlowFunc(("enter\n"));
1343 int rc = videoAccelEnterVMMDev(&mVideoAccelLegacy);
1344 if (RT_SUCCESS(rc))
1345 {
1346 i_VideoAccelFlush(mpDrv->pUpPort);
1347 videoAccelLeaveVMMDev(&mVideoAccelLegacy);
1348 }
1349 LogFlowFunc(("leave\n"));
1350}
1351
1352/* Called always by one VRDP server thread. Can be thread-unsafe.
1353 */
1354void Display::i_VideoAccelVRDP(bool fEnable)
1355{
1356 LogRelFlowFunc(("fEnable = %d\n", fEnable));
1357
1358 VIDEOACCEL *pVideoAccel = &mVideoAccelLegacy;
1359
1360 int c = fEnable?
1361 ASMAtomicIncS32(&mcVideoAccelVRDPRefs):
1362 ASMAtomicDecS32(&mcVideoAccelVRDPRefs);
1363
1364 Assert (c >= 0);
1365
1366 /* This can run concurrently with Display videoaccel state change. */
1367 RTCritSectEnter(&mVideoAccelLock);
1368
1369 if (c == 0)
1370 {
1371 /* The last client has disconnected, and the accel can be
1372 * disabled.
1373 */
1374 Assert (fEnable == false);
1375
1376 mfVideoAccelVRDP = false;
1377 mfu32SupportedOrders = 0;
1378
1379 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1380 maFramebuffers, mcMonitors);
1381#ifdef VBOX_WITH_HGSMI
1382 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1383 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1384#endif /* VBOX_WITH_HGSMI */
1385
1386 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
1387 }
1388 else if ( c == 1
1389 && !mfVideoAccelVRDP)
1390 {
1391 /* The first client has connected. Enable the accel.
1392 */
1393 Assert (fEnable == true);
1394
1395 mfVideoAccelVRDP = true;
1396 /* Supporting all orders. */
1397 mfu32SupportedOrders = ~0;
1398
1399 i_vbvaSetMemoryFlags(pVideoAccel->pVbvaMemory, pVideoAccel->fVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1400 maFramebuffers, mcMonitors);
1401#ifdef VBOX_WITH_HGSMI
1402 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1403 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1404#endif /* VBOX_WITH_HGSMI */
1405
1406 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
1407 }
1408 else
1409 {
1410 /* A client is connected or disconnected but there is no change in the
1411 * accel state. It remains enabled.
1412 */
1413 Assert(mfVideoAccelVRDP == true);
1414 }
1415
1416 RTCritSectLeave(&mVideoAccelLock);
1417}
1418
1419void Display::i_notifyPowerDown(void)
1420{
1421 LogRelFlowFunc(("\n"));
1422
1423 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1424
1425 /* Source bitmaps are not available anymore. */
1426 mfSourceBitmapEnabled = false;
1427
1428 /* Resize all displays to tell framebuffers to forget current source bitmap. */
1429 unsigned uScreenId = mcMonitors;
1430 while (uScreenId > 0)
1431 {
1432 --uScreenId;
1433
1434 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1435 if (!pFBInfo->fDisabled)
1436 {
1437 i_handleDisplayResize(uScreenId, 32,
1438 pFBInfo->pu8FramebufferVRAM,
1439 pFBInfo->u32LineSize,
1440 pFBInfo->w,
1441 pFBInfo->h,
1442 pFBInfo->flags);
1443 }
1444 }
1445}
1446
1447// Wrapped IDisplay methods
1448/////////////////////////////////////////////////////////////////////////////
1449HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel,
1450 LONG *aXOrigin, LONG *aYOrigin)
1451{
1452 LogRelFlowFunc(("aScreenId=%RU32\n", aScreenId));
1453
1454 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1455
1456 uint32_t u32Width = 0;
1457 uint32_t u32Height = 0;
1458 uint32_t u32BitsPerPixel = 0;
1459 int32_t xOrigin = 0;
1460 int32_t yOrigin = 0;
1461
1462 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1463 {
1464 if (mpDrv)
1465 {
1466 u32Width = mpDrv->IConnector.cx;
1467 u32Height = mpDrv->IConnector.cy;
1468
1469 alock.release();
1470
1471 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &u32BitsPerPixel);
1472 AssertRC(rc);
1473
1474 alock.acquire();
1475 }
1476 }
1477 else if (aScreenId < mcMonitors)
1478 {
1479 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1480 u32Width = pFBInfo->w;
1481 u32Height = pFBInfo->h;
1482 u32BitsPerPixel = pFBInfo->u16BitsPerPixel;
1483 xOrigin = pFBInfo->xOrigin;
1484 yOrigin = pFBInfo->yOrigin;
1485 }
1486 else
1487 {
1488 return E_INVALIDARG;
1489 }
1490
1491 if (aWidth)
1492 *aWidth = u32Width;
1493 if (aHeight)
1494 *aHeight = u32Height;
1495 if (aBitsPerPixel)
1496 *aBitsPerPixel = u32BitsPerPixel;
1497 if (aXOrigin)
1498 *aXOrigin = xOrigin;
1499 if (aYOrigin)
1500 *aYOrigin = yOrigin;
1501
1502 return S_OK;
1503}
1504
1505
1506HRESULT Display::attachFramebuffer(ULONG aScreenId, const ComPtr<IFramebuffer> &aFramebuffer)
1507{
1508 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
1509
1510 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1511
1512 if (aScreenId >= mcMonitors)
1513 return setError(E_INVALIDARG, tr("AttachFramebuffer: Invalid screen %d (total %d)"),
1514 aScreenId, mcMonitors);
1515
1516 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1517 if (!pFBInfo->pFramebuffer.isNull())
1518 return setError(E_FAIL, tr("AttachFramebuffer: Framebuffer already attached to %d"),
1519 aScreenId);
1520
1521 pFBInfo->pFramebuffer = aFramebuffer;
1522
1523 SafeArray<FramebufferCapabilities_T> caps;
1524 pFBInfo->pFramebuffer->COMGETTER(Capabilities)(ComSafeArrayAsOutParam(caps));
1525 pFBInfo->u32Caps = 0;
1526 size_t i;
1527 for (i = 0; i < caps.size(); ++i)
1528 pFBInfo->u32Caps |= caps[i];
1529
1530 alock.release();
1531
1532 /* The driver might not have been constructed yet */
1533 if (mpDrv)
1534 {
1535 /* Setup the new framebuffer. */
1536 i_handleDisplayResize(aScreenId, pFBInfo->u16BitsPerPixel,
1537 pFBInfo->pu8FramebufferVRAM,
1538 pFBInfo->u32LineSize,
1539 pFBInfo->w,
1540 pFBInfo->h,
1541 pFBInfo->flags);
1542 }
1543
1544 Console::SafeVMPtrQuiet ptrVM(mParent);
1545 if (ptrVM.isOk())
1546 {
1547#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1548 BOOL fIs3DEnabled = FALSE;
1549 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled);
1550
1551 if (fIs3DEnabled)
1552 {
1553 VBOXCRCMDCTL_HGCM data;
1554 RT_ZERO(data);
1555 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1556 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
1557
1558 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
1559 data.aParms[0].u.uint32 = aScreenId;
1560
1561 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
1562 AssertRC(vrc);
1563 }
1564#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
1565
1566 VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
1567 3, this, aScreenId, false);
1568 }
1569
1570 LogRelFlowFunc(("Attached to %d\n", aScreenId));
1571 return S_OK;
1572}
1573
1574HRESULT Display::detachFramebuffer(ULONG aScreenId)
1575{
1576 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
1577
1578 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1579
1580 if (aScreenId >= mcMonitors)
1581 return setError(E_INVALIDARG, tr("DetachFramebuffer: Invalid screen %d (total %d)"),
1582 aScreenId, mcMonitors);
1583
1584 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1585
1586 pFBInfo->pFramebuffer.setNull();
1587
1588 alock.release();
1589
1590#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1591 Console::SafeVMPtrQuiet ptrVM(mParent);
1592 if (ptrVM.isOk())
1593 {
1594 BOOL fIs3DEnabled = FALSE;
1595 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled);
1596
1597 if (fIs3DEnabled)
1598 {
1599 VBOXCRCMDCTL_HGCM data;
1600 RT_ZERO(data);
1601 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1602 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
1603
1604 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
1605 data.aParms[0].u.uint32 = aScreenId;
1606
1607 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
1608 AssertRC(vrc);
1609 }
1610 }
1611#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
1612
1613 return S_OK;
1614}
1615
1616HRESULT Display::queryFramebuffer(ULONG aScreenId, ComPtr<IFramebuffer> &aFramebuffer)
1617{
1618 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
1619
1620 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1621
1622 if (aScreenId >= mcMonitors)
1623 return setError(E_INVALIDARG, tr("QueryFramebuffer: Invalid screen %d (total %d)"),
1624 aScreenId, mcMonitors);
1625
1626 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1627
1628 pFBInfo->pFramebuffer.queryInterfaceTo(aFramebuffer.asOutParam());
1629
1630 return S_OK;
1631}
1632
1633HRESULT Display::setVideoModeHint(ULONG aDisplay, BOOL aEnabled,
1634 BOOL aChangeOrigin, LONG aOriginX, LONG aOriginY,
1635 ULONG aWidth, ULONG aHeight, ULONG aBitsPerPixel)
1636{
1637 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1638
1639 CHECK_CONSOLE_DRV(mpDrv);
1640
1641 /*
1642 * Do some rough checks for valid input.
1643 */
1644 ULONG width = aWidth;
1645 if (!width)
1646 width = mpDrv->IConnector.cx;
1647 ULONG height = aHeight;
1648 if (!height)
1649 height = mpDrv->IConnector.cy;
1650 ULONG bpp = aBitsPerPixel;
1651 if (!bpp)
1652 {
1653 alock.release();
1654
1655 uint32_t cBits = 0;
1656 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1657 AssertRC(rc);
1658 bpp = cBits;
1659
1660 alock.acquire();
1661 }
1662 ULONG cMonitors;
1663 mParent->i_machine()->COMGETTER(MonitorCount)(&cMonitors);
1664 if (cMonitors == 0 && aDisplay > 0)
1665 return E_INVALIDARG;
1666 if (aDisplay >= cMonitors)
1667 return E_INVALIDARG;
1668
1669 /*
1670 * sunlover 20070614: It is up to the guest to decide whether the hint is
1671 * valid. Therefore don't do any VRAM sanity checks here!
1672 */
1673
1674 /* Have to release the lock because the pfnRequestDisplayChange
1675 * will call EMT. */
1676 alock.release();
1677
1678 VMMDev *pVMMDev = mParent->i_getVMMDev();
1679 if (pVMMDev)
1680 {
1681 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
1682 if (pVMMDevPort)
1683 pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel,
1684 aDisplay, aOriginX, aOriginY,
1685 RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin));
1686 }
1687 return S_OK;
1688}
1689
1690HRESULT Display::setSeamlessMode(BOOL enabled)
1691{
1692 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1693
1694 /* Have to release the lock because the pfnRequestSeamlessChange will call EMT. */
1695 alock.release();
1696
1697 VMMDev *pVMMDev = mParent->i_getVMMDev();
1698 if (pVMMDev)
1699 {
1700 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
1701 if (pVMMDevPort)
1702 pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled);
1703 }
1704
1705#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1706 if (!enabled)
1707 {
1708 BOOL is3denabled = FALSE;
1709
1710 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
1711
1712 VMMDev *vmmDev = mParent->i_getVMMDev();
1713 if (is3denabled && vmmDev)
1714 {
1715 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM));
1716 if (!pData)
1717 {
1718 AssertMsgFailed(("RTMemAlloc failed\n"));
1719 return VERR_NO_MEMORY;
1720 }
1721
1722 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1723 pData->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
1724
1725 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
1726 pData->aParms[0].u.pointer.addr = NULL;
1727 pData->aParms[0].u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */
1728
1729 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
1730 if (!RT_SUCCESS(rc))
1731 {
1732 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
1733 RTMemFree(pData);
1734 }
1735 }
1736 }
1737#endif
1738 return S_OK;
1739}
1740
1741#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1742BOOL Display::i_displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data,
1743 uint32_t u32Width, uint32_t u32Height)
1744{
1745 BOOL is3denabled;
1746 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
1747 if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData())
1748 {
1749 VMMDev *pVMMDev = pDisplay->mParent->i_getVMMDev();
1750 if (pVMMDev)
1751 {
1752 CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof(*pScreenshot));
1753 if (pScreenshot)
1754 {
1755 /* screen id or CRSCREEN_ALL to specify all enabled */
1756 pScreenshot->u32Screen = aScreenId;
1757 pScreenshot->u32Width = u32Width;
1758 pScreenshot->u32Height = u32Height;
1759 pScreenshot->u32Pitch = u32Width * 4;
1760 pScreenshot->pvBuffer = pu8Data;
1761 pScreenshot->pvContext = NULL;
1762 pScreenshot->pfnScreenshotBegin = NULL;
1763 pScreenshot->pfnScreenshotPerform = NULL;
1764 pScreenshot->pfnScreenshotEnd = NULL;
1765
1766 VBOXCRCMDCTL_HGCM data;
1767 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1768 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
1769
1770 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
1771 data.aParms[0].u.pointer.addr = pScreenshot;
1772 data.aParms[0].u.pointer.size = sizeof(*pScreenshot);
1773
1774 int rc = pDisplay->i_crCtlSubmitSync(&data.Hdr, sizeof(data));
1775
1776 RTMemFree(pScreenshot);
1777
1778 if (RT_SUCCESS(rc))
1779 return TRUE;
1780 else
1781 {
1782 AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc));
1783 /* fall back to the non-3d mechanism */
1784 }
1785 }
1786 }
1787 }
1788 return FALSE;
1789}
1790#endif
1791
1792int Display::i_displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData,
1793 uint32_t *pu32Width, uint32_t *pu32Height)
1794{
1795 int rc;
1796
1797 if ( aScreenId == VBOX_VIDEO_PRIMARY_SCREEN
1798 && pDisplay->maFramebuffers[aScreenId].fVBVAEnabled == false) /* A non-VBVA mode. */
1799 {
1800 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppu8Data, pcbData, pu32Width, pu32Height);
1801 }
1802 else if (aScreenId < pDisplay->mcMonitors)
1803 {
1804 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
1805
1806 uint32_t width = pFBInfo->w;
1807 uint32_t height = pFBInfo->h;
1808
1809 /* Allocate 32 bit per pixel bitmap. */
1810 size_t cbRequired = width * 4 * height;
1811
1812 if (cbRequired)
1813 {
1814 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired);
1815
1816 if (pu8Data == NULL)
1817 {
1818 rc = VERR_NO_MEMORY;
1819 }
1820 else
1821 {
1822 /* Copy guest VRAM to the allocated 32bpp buffer. */
1823 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
1824 int32_t xSrc = 0;
1825 int32_t ySrc = 0;
1826 uint32_t u32SrcWidth = width;
1827 uint32_t u32SrcHeight = height;
1828 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
1829 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
1830
1831 uint8_t *pu8Dst = pu8Data;
1832 int32_t xDst = 0;
1833 int32_t yDst = 0;
1834 uint32_t u32DstWidth = u32SrcWidth;
1835 uint32_t u32DstHeight = u32SrcHeight;
1836 uint32_t u32DstLineSize = u32DstWidth * 4;
1837 uint32_t u32DstBitsPerPixel = 32;
1838
1839 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
1840 width, height,
1841 pu8Src,
1842 xSrc, ySrc,
1843 u32SrcWidth, u32SrcHeight,
1844 u32SrcLineSize, u32SrcBitsPerPixel,
1845 pu8Dst,
1846 xDst, yDst,
1847 u32DstWidth, u32DstHeight,
1848 u32DstLineSize, u32DstBitsPerPixel);
1849 if (RT_SUCCESS(rc))
1850 {
1851 *ppu8Data = pu8Data;
1852 *pcbData = cbRequired;
1853 *pu32Width = width;
1854 *pu32Height = height;
1855 }
1856 else
1857 {
1858 RTMemFree(pu8Data);
1859
1860 /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */
1861 if ( rc == VERR_INVALID_STATE
1862 && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1863 {
1864 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort,
1865 ppu8Data, pcbData, pu32Width, pu32Height);
1866 }
1867 }
1868 }
1869 }
1870 else
1871 {
1872 /* No image. */
1873 *ppu8Data = NULL;
1874 *pcbData = 0;
1875 *pu32Width = 0;
1876 *pu32Height = 0;
1877 rc = VINF_SUCCESS;
1878 }
1879 }
1880 else
1881 {
1882 rc = VERR_INVALID_PARAMETER;
1883 }
1884
1885 return rc;
1886}
1887
1888static int i_displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId,
1889 BYTE *address, ULONG width, ULONG height)
1890{
1891 uint8_t *pu8Data = NULL;
1892 size_t cbData = 0;
1893 uint32_t cx = 0;
1894 uint32_t cy = 0;
1895 int vrc = VINF_SUCCESS;
1896
1897# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1898 if (Display::i_displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height))
1899 return VINF_SUCCESS;
1900#endif
1901
1902 int cRetries = 5;
1903
1904 while (cRetries-- > 0)
1905 {
1906 /* Note! Not sure if the priority call is such a good idea here, but
1907 it would be nice to have an accurate screenshot for the bug
1908 report if the VM deadlocks. */
1909 vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::i_displayTakeScreenshotEMT, 6,
1910 pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy);
1911 if (vrc != VERR_TRY_AGAIN)
1912 {
1913 break;
1914 }
1915
1916 RTThreadSleep(10);
1917 }
1918
1919 if (RT_SUCCESS(vrc) && pu8Data)
1920 {
1921 if (cx == width && cy == height)
1922 {
1923 /* No scaling required. */
1924 memcpy(address, pu8Data, cbData);
1925 }
1926 else
1927 {
1928 /* Scale. */
1929 LogRelFlowFunc(("SCALE: %dx%d -> %dx%d\n", cx, cy, width, height));
1930
1931 uint8_t *dst = address;
1932 uint8_t *src = pu8Data;
1933 int dstW = width;
1934 int dstH = height;
1935 int srcW = cx;
1936 int srcH = cy;
1937 int iDeltaLine = cx * 4;
1938
1939 BitmapScale32(dst,
1940 dstW, dstH,
1941 src,
1942 iDeltaLine,
1943 srcW, srcH);
1944 }
1945
1946 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1947 {
1948 /* This can be called from any thread. */
1949 pDrv->pUpPort->pfnFreeScreenshot(pDrv->pUpPort, pu8Data);
1950 }
1951 else
1952 {
1953 RTMemFree(pu8Data);
1954 }
1955 }
1956
1957 return vrc;
1958}
1959
1960HRESULT Display::takeScreenShotWorker(ULONG aScreenId,
1961 BYTE *aAddress,
1962 ULONG aWidth,
1963 ULONG aHeight,
1964 BitmapFormat_T aBitmapFormat,
1965 ULONG *pcbOut)
1966{
1967 HRESULT rc = S_OK;
1968
1969 /* Do not allow too small and too large screenshots. This also filters out negative
1970 * values passed as either 'aWidth' or 'aHeight'.
1971 */
1972 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767);
1973 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767);
1974
1975 if ( aBitmapFormat != BitmapFormat_BGR0
1976 && aBitmapFormat != BitmapFormat_BGRA
1977 && aBitmapFormat != BitmapFormat_RGBA
1978 && aBitmapFormat != BitmapFormat_PNG)
1979 {
1980 return setError(E_NOTIMPL,
1981 tr("Unsupported screenshot format 0x%08X"), aBitmapFormat);
1982 }
1983
1984 Console::SafeVMPtr ptrVM(mParent);
1985 if (!ptrVM.isOk())
1986 return ptrVM.rc();
1987
1988 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, aAddress, aWidth, aHeight);
1989
1990 if (RT_SUCCESS(vrc))
1991 {
1992 const size_t cbData = aWidth * 4 * aHeight;
1993
1994 /* Most of uncompressed formats. */
1995 *pcbOut = (ULONG)cbData;
1996
1997 if (aBitmapFormat == BitmapFormat_BGR0)
1998 {
1999 /* Do nothing. */
2000 }
2001 else if (aBitmapFormat == BitmapFormat_BGRA)
2002 {
2003 uint32_t *pu32 = (uint32_t *)aAddress;
2004 size_t cPixels = aWidth * aHeight;
2005 while (cPixels--)
2006 {
2007 *pu32++ |= UINT32_C(0xFF000000);
2008 }
2009 }
2010 else if (aBitmapFormat == BitmapFormat_RGBA)
2011 {
2012 uint8_t *pu8 = aAddress;
2013 size_t cPixels = aWidth * aHeight;
2014 while (cPixels--)
2015 {
2016 uint8_t u8 = pu8[0];
2017 pu8[0] = pu8[2];
2018 pu8[2] = u8;
2019 pu8[3] = 0xFF;
2020
2021 pu8 += 4;
2022 }
2023 }
2024 else if (aBitmapFormat == BitmapFormat_PNG)
2025 {
2026 uint8_t *pu8PNG = NULL;
2027 uint32_t cbPNG = 0;
2028 uint32_t cxPNG = 0;
2029 uint32_t cyPNG = 0;
2030
2031 vrc = DisplayMakePNG(aAddress, aWidth, aHeight, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 0);
2032 if (RT_SUCCESS(vrc))
2033 {
2034 if (cbPNG <= cbData)
2035 {
2036 memcpy(aAddress, pu8PNG, cbPNG);
2037 *pcbOut = cbPNG;
2038 }
2039 else
2040 {
2041 rc = setError(E_FAIL,
2042 tr("PNG is larger than 32bpp bitmap"));
2043 }
2044 }
2045 else
2046 {
2047 rc = setError(VBOX_E_IPRT_ERROR,
2048 tr("Could not convert screenshot to PNG (%Rrc)"), vrc);
2049 }
2050 RTMemFree(pu8PNG);
2051 }
2052 }
2053 else if (vrc == VERR_TRY_AGAIN)
2054 rc = setError(E_UNEXPECTED,
2055 tr("Screenshot is not available at this time"));
2056 else if (RT_FAILURE(vrc))
2057 rc = setError(VBOX_E_IPRT_ERROR,
2058 tr("Could not take a screenshot (%Rrc)"), vrc);
2059
2060 return rc;
2061}
2062
2063HRESULT Display::takeScreenShot(ULONG aScreenId,
2064 BYTE *aAddress,
2065 ULONG aWidth,
2066 ULONG aHeight,
2067 BitmapFormat_T aBitmapFormat)
2068{
2069 HRESULT rc = S_OK;
2070
2071 LogRelFlowFunc(("[%d] address=%p, width=%d, height=%d, format 0x%08X\n",
2072 aScreenId, aAddress, aWidth, aHeight, aBitmapFormat));
2073
2074 ULONG cbOut = 0;
2075 rc = takeScreenShotWorker(aScreenId, aAddress, aWidth, aHeight, aBitmapFormat, &cbOut);
2076 NOREF(cbOut);
2077
2078 LogRelFlowFunc(("%Rhrc\n", rc));
2079 return rc;
2080}
2081
2082HRESULT Display::takeScreenShotToArray(ULONG aScreenId,
2083 ULONG aWidth,
2084 ULONG aHeight,
2085 BitmapFormat_T aBitmapFormat,
2086 std::vector<BYTE> &aScreenData)
2087{
2088 HRESULT rc = S_OK;
2089
2090 LogRelFlowFunc(("[%d] width=%d, height=%d, format 0x%08X\n",
2091 aScreenId, aWidth, aHeight, aBitmapFormat));
2092
2093 /* Do not allow too small and too large screenshots. This also filters out negative
2094 * values passed as either 'aWidth' or 'aHeight'.
2095 */
2096 CheckComArgExpr(aWidth, aWidth != 0 && aWidth <= 32767);
2097 CheckComArgExpr(aHeight, aHeight != 0 && aHeight <= 32767);
2098
2099 const size_t cbData = aWidth * 4 * aHeight;
2100 aScreenData.resize(cbData);
2101
2102 ULONG cbOut = 0;
2103 rc = takeScreenShotWorker(aScreenId, &aScreenData.front(), aWidth, aHeight, aBitmapFormat, &cbOut);
2104 if (FAILED(rc))
2105 cbOut = 0;
2106
2107 aScreenData.resize(cbOut);
2108
2109 LogRelFlowFunc(("%Rhrc\n", rc));
2110 return rc;
2111}
2112
2113
2114int Display::i_VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens))
2115{
2116#ifdef VBOX_WITH_VPX
2117 com::SafeArray<BOOL> Screens(ComSafeArrayInArg(aScreens));
2118 for (unsigned i = 0; i < Screens.size(); i++)
2119 maVideoRecEnabled[i] = RT_BOOL(Screens[i]);
2120 return VINF_SUCCESS;
2121#else
2122 return VERR_NOT_IMPLEMENTED;
2123#endif
2124}
2125
2126/**
2127 * Start video capturing. Does nothing if capturing is already active.
2128 */
2129int Display::i_VideoCaptureStart()
2130{
2131#ifdef VBOX_WITH_VPX
2132 if (VideoRecIsEnabled(mpVideoRecCtx))
2133 return VINF_SUCCESS;
2134
2135 int rc = VideoRecContextCreate(&mpVideoRecCtx, mcMonitors);
2136 if (RT_FAILURE(rc))
2137 {
2138 LogFlow(("Failed to create video recording context (%Rrc)!\n", rc));
2139 return rc;
2140 }
2141 ComPtr<IMachine> pMachine = mParent->i_machine();
2142 com::SafeArray<BOOL> screens;
2143 HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens));
2144 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2145 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
2146 maVideoRecEnabled[i] = i < screens.size() && screens[i];
2147 ULONG ulWidth;
2148 hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth);
2149 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2150 ULONG ulHeight;
2151 hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight);
2152 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2153 ULONG ulRate;
2154 hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate);
2155 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2156 ULONG ulFPS;
2157 hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS);
2158 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2159 BSTR strFile;
2160 hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile);
2161 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2162 ULONG ulMaxTime;
2163 hrc = pMachine->COMGETTER(VideoCaptureMaxTime)(&ulMaxTime);
2164 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2165 ULONG ulMaxSize;
2166 hrc = pMachine->COMGETTER(VideoCaptureMaxFileSize)(&ulMaxSize);
2167 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2168 BSTR strOptions;
2169 hrc = pMachine->COMGETTER(VideoCaptureOptions)(&strOptions);
2170 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2171
2172 RTTIMESPEC ts;
2173 RTTimeNow(&ts);
2174 RTTIME time;
2175 RTTimeExplode(&time, &ts);
2176 for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++)
2177 {
2178 char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str());
2179 char *pszSuff = RTPathSuffix(pszAbsPath);
2180 if (pszSuff)
2181 pszSuff = RTStrDup(pszSuff);
2182 RTPathStripSuffix(pszAbsPath);
2183 if (!pszAbsPath)
2184 rc = VERR_INVALID_PARAMETER;
2185 if (!pszSuff)
2186 pszSuff = RTStrDup(".webm");
2187 char *pszName = NULL;
2188 if (RT_SUCCESS(rc))
2189 {
2190 if (mcMonitors > 1)
2191 rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszSuff);
2192 else
2193 rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszSuff);
2194 }
2195 if (RT_SUCCESS(rc))
2196 {
2197 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen,
2198 pszName, ulWidth, ulHeight,
2199 ulRate, ulFPS, ulMaxTime,
2200 ulMaxSize, com::Utf8Str(strOptions).c_str());
2201 if (rc == VERR_ALREADY_EXISTS)
2202 {
2203 RTStrFree(pszName);
2204 pszName = NULL;
2205
2206 if (mcMonitors > 1)
2207 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s",
2208 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
2209 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
2210 uScreen+1, pszSuff);
2211 else
2212 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s",
2213 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
2214 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
2215 pszSuff);
2216 if (RT_SUCCESS(rc))
2217 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen,
2218 pszName, ulWidth, ulHeight, ulRate,
2219 ulFPS, ulMaxTime,
2220 ulMaxSize, com::Utf8Str(strOptions).c_str());
2221 }
2222 }
2223
2224 if (RT_SUCCESS(rc))
2225 LogRel(("WebM/VP8 video recording screen #%u with %ux%u @ %u kbps, %u fps to '%s' enabled.\n",
2226 uScreen, ulWidth, ulHeight, ulRate, ulFPS, pszName));
2227 else
2228 LogRel(("Failed to initialize video recording context #%u (%Rrc)!\n", uScreen, rc));
2229 RTStrFree(pszName);
2230 RTStrFree(pszSuff);
2231 RTStrFree(pszAbsPath);
2232 }
2233 return rc;
2234#else
2235 return VERR_NOT_IMPLEMENTED;
2236#endif
2237}
2238
2239/**
2240 * Stop video capturing. Does nothing if video capturing is not active.
2241 */
2242void Display::i_VideoCaptureStop()
2243{
2244#ifdef VBOX_WITH_VPX
2245 if (VideoRecIsEnabled(mpVideoRecCtx))
2246 LogRel(("WebM/VP8 video recording stopped.\n"));
2247 VideoRecContextClose(mpVideoRecCtx);
2248 mpVideoRecCtx = NULL;
2249#endif
2250}
2251
2252int Display::i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address,
2253 ULONG x, ULONG y, ULONG width, ULONG height)
2254{
2255 int rc = VINF_SUCCESS;
2256
2257 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
2258
2259 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2260 {
2261 rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height);
2262 }
2263 else if (aScreenId < pDisplay->mcMonitors)
2264 {
2265 /* Copy the bitmap to the guest VRAM. */
2266 const uint8_t *pu8Src = address;
2267 int32_t xSrc = 0;
2268 int32_t ySrc = 0;
2269 uint32_t u32SrcWidth = width;
2270 uint32_t u32SrcHeight = height;
2271 uint32_t u32SrcLineSize = width * 4;
2272 uint32_t u32SrcBitsPerPixel = 32;
2273
2274 uint8_t *pu8Dst = pFBInfo->pu8FramebufferVRAM;
2275 int32_t xDst = x;
2276 int32_t yDst = y;
2277 uint32_t u32DstWidth = pFBInfo->w;
2278 uint32_t u32DstHeight = pFBInfo->h;
2279 uint32_t u32DstLineSize = pFBInfo->u32LineSize;
2280 uint32_t u32DstBitsPerPixel = pFBInfo->u16BitsPerPixel;
2281
2282 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2283 width, height,
2284 pu8Src,
2285 xSrc, ySrc,
2286 u32SrcWidth, u32SrcHeight,
2287 u32SrcLineSize, u32SrcBitsPerPixel,
2288 pu8Dst,
2289 xDst, yDst,
2290 u32DstWidth, u32DstHeight,
2291 u32DstLineSize, u32DstBitsPerPixel);
2292 if (RT_SUCCESS(rc))
2293 {
2294 if (!pFBInfo->pSourceBitmap.isNull())
2295 {
2296 /* Update the changed screen area. When source bitmap uses VRAM directly, just notify
2297 * frontend to update. And for default format, render the guest VRAM to the source bitmap.
2298 */
2299 if ( pFBInfo->fDefaultFormat
2300 && !pFBInfo->fDisabled)
2301 {
2302 BYTE *pAddress = NULL;
2303 ULONG ulWidth = 0;
2304 ULONG ulHeight = 0;
2305 ULONG ulBitsPerPixel = 0;
2306 ULONG ulBytesPerLine = 0;
2307 ULONG ulPixelFormat = 0;
2308
2309 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
2310 &ulWidth,
2311 &ulHeight,
2312 &ulBitsPerPixel,
2313 &ulBytesPerLine,
2314 &ulPixelFormat);
2315 if (SUCCEEDED(hrc))
2316 {
2317 pu8Src = pFBInfo->pu8FramebufferVRAM;
2318 xSrc = x;
2319 ySrc = y;
2320 u32SrcWidth = pFBInfo->w;
2321 u32SrcHeight = pFBInfo->h;
2322 u32SrcLineSize = pFBInfo->u32LineSize;
2323 u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2324
2325 /* Default format is 32 bpp. */
2326 pu8Dst = pAddress;
2327 xDst = xSrc;
2328 yDst = ySrc;
2329 u32DstWidth = u32SrcWidth;
2330 u32DstHeight = u32SrcHeight;
2331 u32DstLineSize = u32DstWidth * 4;
2332 u32DstBitsPerPixel = 32;
2333
2334 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2335 width, height,
2336 pu8Src,
2337 xSrc, ySrc,
2338 u32SrcWidth, u32SrcHeight,
2339 u32SrcLineSize, u32SrcBitsPerPixel,
2340 pu8Dst,
2341 xDst, yDst,
2342 u32DstWidth, u32DstHeight,
2343 u32DstLineSize, u32DstBitsPerPixel);
2344 }
2345 }
2346 }
2347
2348 pDisplay->i_handleDisplayUpdate(aScreenId, x, y, width, height);
2349 }
2350 }
2351 else
2352 {
2353 rc = VERR_INVALID_PARAMETER;
2354 }
2355
2356 if (RT_SUCCESS(rc))
2357 pDisplay->mParent->i_consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height);
2358
2359 return rc;
2360}
2361
2362HRESULT Display::drawToScreen(ULONG aScreenId, BYTE *aAddress, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
2363{
2364 /// @todo (r=dmik) this function may take too long to complete if the VM
2365 // is doing something like saving state right now. Which, in case if it
2366 // is called on the GUI thread, will make it unresponsive. We should
2367 // check the machine state here (by enclosing the check and VMRequCall
2368 // within the Console lock to make it atomic).
2369
2370 LogRelFlowFunc(("aAddress=%p, x=%d, y=%d, width=%d, height=%d\n",
2371 (void *)aAddress, aX, aY, aWidth, aHeight));
2372
2373 CheckComArgExpr(aWidth, aWidth != 0);
2374 CheckComArgExpr(aHeight, aHeight != 0);
2375
2376 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2377
2378 CHECK_CONSOLE_DRV(mpDrv);
2379
2380 Console::SafeVMPtr ptrVM(mParent);
2381 if (!ptrVM.isOk())
2382 return ptrVM.rc();
2383
2384 /* Release lock because the call scheduled on EMT may also try to take it. */
2385 alock.release();
2386
2387 /*
2388 * Again we're lazy and make the graphics device do all the
2389 * dirty conversion work.
2390 */
2391 int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_drawToScreenEMT, 7,
2392 this, aScreenId, aAddress, aX, aY, aWidth, aHeight);
2393
2394 /*
2395 * If the function returns not supported, we'll have to do all the
2396 * work ourselves using the framebuffer.
2397 */
2398 HRESULT rc = S_OK;
2399 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
2400 {
2401 /** @todo implement generic fallback for screen blitting. */
2402 rc = E_NOTIMPL;
2403 }
2404 else if (RT_FAILURE(rcVBox))
2405 rc = setError(VBOX_E_IPRT_ERROR,
2406 tr("Could not draw to the screen (%Rrc)"), rcVBox);
2407//@todo
2408// else
2409// {
2410// /* All ok. Redraw the screen. */
2411// handleDisplayUpdate (x, y, width, height);
2412// }
2413
2414 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2415 return rc;
2416}
2417
2418int Display::i_InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll)
2419{
2420 LogRelFlowFunc(("uId=%d, fUpdateAll %d\n", uId, fUpdateAll));
2421
2422 unsigned uScreenId;
2423 for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++)
2424 {
2425 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2426
2427 if ( !pFBInfo->fVBVAEnabled
2428 && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2429 {
2430 pDisplay->mpDrv->pUpPort->pfnUpdateDisplayAll(pDisplay->mpDrv->pUpPort, /* fFailOnResize = */ true);
2431 }
2432 else
2433 {
2434 if (!pFBInfo->fDisabled)
2435 {
2436 /* Render complete VRAM screen to the framebuffer.
2437 * When framebuffer uses VRAM directly, just notify it to update.
2438 */
2439 if (pFBInfo->fDefaultFormat && !pFBInfo->pSourceBitmap.isNull())
2440 {
2441 BYTE *pAddress = NULL;
2442 ULONG ulWidth = 0;
2443 ULONG ulHeight = 0;
2444 ULONG ulBitsPerPixel = 0;
2445 ULONG ulBytesPerLine = 0;
2446 ULONG ulPixelFormat = 0;
2447
2448 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
2449 &ulWidth,
2450 &ulHeight,
2451 &ulBitsPerPixel,
2452 &ulBytesPerLine,
2453 &ulPixelFormat);
2454 if (SUCCEEDED(hrc))
2455 {
2456 uint32_t width = pFBInfo->w;
2457 uint32_t height = pFBInfo->h;
2458
2459 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
2460 int32_t xSrc = 0;
2461 int32_t ySrc = 0;
2462 uint32_t u32SrcWidth = pFBInfo->w;
2463 uint32_t u32SrcHeight = pFBInfo->h;
2464 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
2465 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2466
2467 /* Default format is 32 bpp. */
2468 uint8_t *pu8Dst = pAddress;
2469 int32_t xDst = xSrc;
2470 int32_t yDst = ySrc;
2471 uint32_t u32DstWidth = u32SrcWidth;
2472 uint32_t u32DstHeight = u32SrcHeight;
2473 uint32_t u32DstLineSize = u32DstWidth * 4;
2474 uint32_t u32DstBitsPerPixel = 32;
2475
2476 /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h
2477 * implies resize of Framebuffer is in progress and
2478 * copyrect should not be called.
2479 */
2480 if (ulWidth == pFBInfo->w && ulHeight == pFBInfo->h)
2481 {
2482 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2483 width, height,
2484 pu8Src,
2485 xSrc, ySrc,
2486 u32SrcWidth, u32SrcHeight,
2487 u32SrcLineSize, u32SrcBitsPerPixel,
2488 pu8Dst,
2489 xDst, yDst,
2490 u32DstWidth, u32DstHeight,
2491 u32DstLineSize, u32DstBitsPerPixel);
2492 }
2493 }
2494 }
2495
2496 pDisplay->i_handleDisplayUpdate(uScreenId, 0, 0, pFBInfo->w, pFBInfo->h);
2497 }
2498 }
2499 if (!fUpdateAll)
2500 break;
2501 }
2502 LogRelFlowFunc(("done\n"));
2503 return VINF_SUCCESS;
2504}
2505
2506/**
2507 * Does a full invalidation of the VM display and instructs the VM
2508 * to update it immediately.
2509 *
2510 * @returns COM status code
2511 */
2512
2513HRESULT Display::invalidateAndUpdate()
2514{
2515 LogRelFlowFunc(("\n"));
2516
2517 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2518
2519 CHECK_CONSOLE_DRV(mpDrv);
2520
2521 Console::SafeVMPtr ptrVM(mParent);
2522 if (!ptrVM.isOk())
2523 return ptrVM.rc();
2524
2525 HRESULT rc = S_OK;
2526
2527 LogRelFlowFunc(("Sending DPYUPDATE request\n"));
2528
2529 /* Have to release the lock when calling EMT. */
2530 alock.release();
2531
2532 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
2533 3, this, 0, true);
2534 alock.acquire();
2535
2536 if (RT_FAILURE(rcVBox))
2537 rc = setError(VBOX_E_IPRT_ERROR,
2538 tr("Could not invalidate and update the screen (%Rrc)"), rcVBox);
2539
2540 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2541 return rc;
2542}
2543
2544HRESULT Display::invalidateAndUpdateScreen(ULONG aScreenId)
2545{
2546 LogRelFlowFunc(("\n"));
2547
2548 HRESULT rc = S_OK;
2549
2550 Console::SafeVMPtr ptrVM(mParent);
2551 if (!ptrVM.isOk())
2552 return ptrVM.rc();
2553
2554 int rcVBox = VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
2555 3, this, aScreenId, false);
2556 if (RT_FAILURE(rcVBox))
2557 rc = setError(VBOX_E_IPRT_ERROR,
2558 tr("Could not invalidate and update the screen %d (%Rrc)"), aScreenId, rcVBox);
2559
2560 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2561 return rc;
2562}
2563
2564HRESULT Display::completeVHWACommand(BYTE *aCommand)
2565{
2566#ifdef VBOX_WITH_VIDEOHWACCEL
2567 mpDrv->pVBVACallbacks->pfnVHWACommandCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVHWACMD)aCommand);
2568 return S_OK;
2569#else
2570 return E_NOTIMPL;
2571#endif
2572}
2573
2574HRESULT Display::viewportChanged(ULONG aScreenId, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
2575{
2576#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2577
2578 if (mcMonitors <= aScreenId)
2579 {
2580 AssertMsgFailed(("invalid screen id\n"));
2581 return E_INVALIDARG;
2582 }
2583
2584 BOOL is3denabled;
2585 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
2586
2587 if (is3denabled)
2588 {
2589 int rc = i_crViewportNotify(aScreenId, aX, aY, aWidth, aHeight);
2590 if (RT_FAILURE(rc))
2591 {
2592 DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId];
2593 pFb->pendingViewportInfo.fPending = true;
2594 pFb->pendingViewportInfo.x = aX;
2595 pFb->pendingViewportInfo.y = aY;
2596 pFb->pendingViewportInfo.width = aWidth;
2597 pFb->pendingViewportInfo.height = aHeight;
2598 }
2599 }
2600#endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */
2601 return S_OK;
2602}
2603
2604HRESULT Display::querySourceBitmap(ULONG aScreenId,
2605 ComPtr<IDisplaySourceBitmap> &aDisplaySourceBitmap)
2606{
2607 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2608
2609 Console::SafeVMPtr ptrVM(mParent);
2610 if (!ptrVM.isOk())
2611 return ptrVM.rc();
2612
2613 bool fSetRenderVRAM = false;
2614 bool fInvalidate = false;
2615
2616 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2617
2618 if (aScreenId >= mcMonitors)
2619 return setError(E_INVALIDARG, tr("QuerySourceBitmap: Invalid screen %d (total %d)"),
2620 aScreenId, mcMonitors);
2621
2622 if (!mfSourceBitmapEnabled)
2623 {
2624 aDisplaySourceBitmap = NULL;
2625 return E_FAIL;
2626 }
2627
2628 HRESULT hr = S_OK;
2629
2630 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2631 if (pFBInfo->pSourceBitmap.isNull())
2632 {
2633 /* Create a new object. */
2634 ComObjPtr<DisplaySourceBitmap> obj;
2635 hr = obj.createObject();
2636 if (SUCCEEDED(hr))
2637 hr = obj->init(this, aScreenId, pFBInfo);
2638
2639 if (SUCCEEDED(hr))
2640 {
2641 bool fDefaultFormat = !obj->i_usesVRAM();
2642
2643 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2644 {
2645 /* Start buffer updates. */
2646 BYTE *pAddress = NULL;
2647 ULONG ulWidth = 0;
2648 ULONG ulHeight = 0;
2649 ULONG ulBitsPerPixel = 0;
2650 ULONG ulBytesPerLine = 0;
2651 ULONG ulPixelFormat = 0;
2652
2653 obj->QueryBitmapInfo(&pAddress,
2654 &ulWidth,
2655 &ulHeight,
2656 &ulBitsPerPixel,
2657 &ulBytesPerLine,
2658 &ulPixelFormat);
2659
2660 mpDrv->IConnector.pu8Data = pAddress;
2661 mpDrv->IConnector.cbScanline = ulBytesPerLine;
2662 mpDrv->IConnector.cBits = ulBitsPerPixel;
2663 mpDrv->IConnector.cx = ulWidth;
2664 mpDrv->IConnector.cy = ulHeight;
2665
2666 fSetRenderVRAM = fDefaultFormat;
2667 }
2668
2669 /* Make sure that the bitmap contains the latest image. */
2670 fInvalidate = fDefaultFormat;
2671
2672 pFBInfo->pSourceBitmap = obj;
2673 pFBInfo->fDefaultFormat = fDefaultFormat;
2674 }
2675 }
2676
2677 if (SUCCEEDED(hr))
2678 {
2679 pFBInfo->pSourceBitmap.queryInterfaceTo(aDisplaySourceBitmap.asOutParam());
2680 }
2681
2682 /* Leave the IDisplay lock because the VGA device must not be called under it. */
2683 alock.release();
2684
2685 if (SUCCEEDED(hr))
2686 {
2687 if (fSetRenderVRAM)
2688 {
2689 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
2690 }
2691
2692 if (fInvalidate)
2693 VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
2694 3, this, aScreenId, false);
2695 }
2696
2697 LogRelFlowFunc(("%Rhrc\n", hr));
2698 return hr;
2699}
2700
2701// wrapped IEventListener method
2702HRESULT Display::handleEvent(const ComPtr<IEvent> &aEvent)
2703{
2704 VBoxEventType_T aType = VBoxEventType_Invalid;
2705
2706 aEvent->COMGETTER(Type)(&aType);
2707 switch (aType)
2708 {
2709 case VBoxEventType_OnStateChanged:
2710 {
2711 ComPtr<IStateChangedEvent> scev = aEvent;
2712 Assert(scev);
2713 MachineState_T machineState;
2714 scev->COMGETTER(State)(&machineState);
2715 if ( machineState == MachineState_Running
2716 || machineState == MachineState_Teleporting
2717 || machineState == MachineState_LiveSnapshotting
2718 || machineState == MachineState_DeletingSnapshotOnline
2719 )
2720 {
2721 LogRelFlowFunc(("Machine is running.\n"));
2722
2723#ifdef VBOX_WITH_CROGL
2724 i_crOglWindowsShow(true);
2725#endif
2726 }
2727 else
2728 {
2729#ifdef VBOX_WITH_CROGL
2730 if (machineState == MachineState_Paused)
2731 i_crOglWindowsShow(false);
2732#endif
2733 }
2734 break;
2735 }
2736 default:
2737 AssertFailed();
2738 }
2739
2740 return S_OK;
2741}
2742
2743
2744// private methods
2745/////////////////////////////////////////////////////////////////////////////
2746
2747#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2748int Display::i_crViewportNotify(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height)
2749{
2750 VMMDev *pVMMDev = mParent->i_getVMMDev();
2751 if (!pVMMDev)
2752 return VERR_INVALID_STATE;
2753
2754 size_t cbData = RT_UOFFSETOF(VBOXCRCMDCTL_HGCM, aParms[5]);
2755 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)alloca(cbData);
2756
2757 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2758 pData->Hdr.u32Function = SHCRGL_HOST_FN_VIEWPORT_CHANGED;
2759
2760 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
2761 pData->aParms[0].u.uint32 = aScreenId;
2762
2763 pData->aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT;
2764 pData->aParms[1].u.uint32 = x;
2765
2766 pData->aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT;
2767 pData->aParms[2].u.uint32 = y;
2768
2769 pData->aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT;
2770 pData->aParms[3].u.uint32 = width;
2771
2772 pData->aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT;
2773 pData->aParms[4].u.uint32 = height;
2774
2775 return i_crCtlSubmitSyncIfHasDataForScreen(aScreenId, &pData->Hdr, (uint32_t)cbData);
2776}
2777#endif
2778
2779#ifdef VBOX_WITH_CRHGSMI
2780void Display::i_setupCrHgsmiData(void)
2781{
2782 VMMDev *pVMMDev = mParent->i_getVMMDev();
2783 Assert(pVMMDev);
2784 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
2785 AssertRC(rc);
2786
2787 if (pVMMDev)
2788 rc = pVMMDev->hgcmHostSvcHandleCreate("VBoxSharedCrOpenGL", &mhCrOglSvc);
2789 else
2790 rc = VERR_GENERAL_FAILURE;
2791
2792 if (RT_SUCCESS(rc))
2793 {
2794 Assert(mhCrOglSvc);
2795 /* setup command completion callback */
2796 VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion;
2797 Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB;
2798 Completion.Hdr.cbCmd = sizeof(Completion);
2799 Completion.hCompletion = mpDrv->pVBVACallbacks;
2800 Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync;
2801
2802 VBOXHGCMSVCPARM parm;
2803 parm.type = VBOX_HGCM_SVC_PARM_PTR;
2804 parm.u.pointer.addr = &Completion;
2805 parm.u.pointer.size = 0;
2806
2807 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm);
2808 if (RT_SUCCESS(rc))
2809 mCrOglCallbacks = Completion.MainInterface;
2810 else
2811 AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc));
2812 }
2813
2814 if (RT_FAILURE(rc))
2815 mhCrOglSvc = NULL;
2816
2817 RTCritSectRwLeaveExcl(&mCrOglLock);
2818}
2819
2820void Display::i_destructCrHgsmiData(void)
2821{
2822 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
2823 AssertRC(rc);
2824 mhCrOglSvc = NULL;
2825 RTCritSectRwLeaveExcl(&mCrOglLock);
2826}
2827#endif
2828
2829/**
2830 * Handle display resize event issued by the VGA device for the primary screen.
2831 *
2832 * @see PDMIDISPLAYCONNECTOR::pfnResize
2833 */
2834DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
2835 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
2836{
2837 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2838 Display *pThis = pDrv->pDisplay;
2839
2840 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
2841 bpp, pvVRAM, cbLine, cx, cy));
2842
2843 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false);
2844 if (!f)
2845 {
2846 /* This is a result of recursive call when the source bitmap is being updated
2847 * during a VGA resize. Tell the VGA device to ignore the call.
2848 *
2849 * @todo It is a workaround, actually pfnUpdateDisplayAll must
2850 * fail on resize.
2851 */
2852 LogRel(("displayResizeCallback: already processing\n"));
2853 return VINF_VGA_RESIZE_IN_PROGRESS;
2854 }
2855
2856 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE);
2857
2858 /* Restore the flag. */
2859 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true);
2860 AssertRelease(f);
2861
2862 return rc;
2863}
2864
2865/**
2866 * Handle display update.
2867 *
2868 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
2869 */
2870DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
2871 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
2872{
2873 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2874
2875#ifdef DEBUG_sunlover
2876 LogFlowFunc(("fVideoAccelEnabled = %d, %d,%d %dx%d\n",
2877 pDrv->pDisplay->mVideoAccelLegacy.fVideoAccelEnabled, x, y, cx, cy));
2878#endif /* DEBUG_sunlover */
2879
2880 /* This call does update regardless of VBVA status.
2881 * But in VBVA mode this is called only as result of
2882 * pfnUpdateDisplayAll in the VGA device.
2883 */
2884
2885 pDrv->pDisplay->i_handleDisplayUpdate(VBOX_VIDEO_PRIMARY_SCREEN, x, y, cx, cy);
2886}
2887
2888/**
2889 * Periodic display refresh callback.
2890 *
2891 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
2892 * @thread EMT
2893 */
2894DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
2895{
2896 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2897
2898#ifdef DEBUG_sunlover_2
2899 LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
2900 pDrv->pDisplay->mfVideoAccelEnabled));
2901#endif /* DEBUG_sunlover_2 */
2902
2903 Display *pDisplay = pDrv->pDisplay;
2904 unsigned uScreenId;
2905
2906 int rc = pDisplay->i_videoAccelRefreshProcess(pDrv->pUpPort);
2907 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */
2908 {
2909 if (rc == VWRN_INVALID_STATE)
2910 {
2911 /* No VBVA do a display update. */
2912 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN];
2913 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
2914 }
2915
2916 /* Inform the VRDP server that the current display update sequence is
2917 * completed. At this moment the framebuffer memory contains a definite
2918 * image, that is synchronized with the orders already sent to VRDP client.
2919 * The server can now process redraw requests from clients or initial
2920 * fullscreen updates for new clients.
2921 */
2922 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
2923 {
2924 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2925
2926 Assert(pDisplay->mParent && pDisplay->mParent->i_consoleVRDPServer());
2927 pDisplay->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, NULL, 0);
2928 }
2929 }
2930
2931#ifdef VBOX_WITH_VPX
2932 if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx))
2933 {
2934 do {
2935# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2936 BOOL is3denabled;
2937 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
2938 if (is3denabled)
2939 {
2940 if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
2941 {
2942 if (pDisplay->mCrOglCallbacks.pfnHasData())
2943 {
2944 /* submit */
2945 VBOXCRCMDCTL_HGCM *pData = &pDisplay->mCrOglScreenshotCtl;
2946
2947 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2948 pData->Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
2949
2950 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2951 pData->aParms[0].u.pointer.addr = &pDisplay->mCrOglScreenshotData;
2952 pData->aParms[0].u.pointer.size = sizeof(pDisplay->mCrOglScreenshotData);
2953 rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), Display::i_displayVRecCompletion, pDisplay);
2954 if (RT_SUCCESS(rc))
2955 break;
2956 else
2957 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
2958 }
2959
2960 /* no 3D data available, or error has occured,
2961 * go the straight way */
2962 ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE);
2963 }
2964 else
2965 {
2966 /* record request is still in progress, don't do anything */
2967 break;
2968 }
2969 }
2970# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
2971
2972 uint64_t u64Now = RTTimeProgramMilliTS();
2973 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
2974 {
2975 if (!pDisplay->maVideoRecEnabled[uScreenId])
2976 continue;
2977
2978 if (VideoRecIsFull(pDisplay->mpVideoRecCtx, uScreenId, u64Now))
2979 {
2980 pDisplay->i_VideoCaptureStop();
2981 pDisplay->mParent->i_machine()->COMSETTER(VideoCaptureEnabled)(false);
2982 break;
2983 }
2984
2985 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2986
2987 if ( !pFBInfo->pFramebuffer.isNull()
2988 && !pFBInfo->fDisabled)
2989 {
2990 rc = VERR_NOT_SUPPORTED;
2991 if ( pFBInfo->fVBVAEnabled
2992 && pFBInfo->pu8FramebufferVRAM)
2993 {
2994 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
2995 BitmapFormat_BGR,
2996 pFBInfo->u16BitsPerPixel,
2997 pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h,
2998 pFBInfo->pu8FramebufferVRAM, u64Now);
2999 }
3000 else if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && pDrv->IConnector.pu8Data)
3001 {
3002 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
3003 BitmapFormat_BGR,
3004 pDrv->IConnector.cBits,
3005 pDrv->IConnector.cbScanline, pDrv->IConnector.cx,
3006 pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now);
3007 }
3008 if (rc == VINF_TRY_AGAIN)
3009 break;
3010 }
3011 }
3012 } while (0);
3013 }
3014#endif /* VBOX_WITH_VPX */
3015
3016#ifdef DEBUG_sunlover_2
3017 LogFlowFunc(("leave\n"));
3018#endif /* DEBUG_sunlover_2 */
3019}
3020
3021/**
3022 * Reset notification
3023 *
3024 * @see PDMIDISPLAYCONNECTOR::pfnReset
3025 */
3026DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
3027{
3028 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3029
3030 LogRelFlowFunc(("\n"));
3031
3032 /* Disable VBVA mode. */
3033 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
3034}
3035
3036/**
3037 * LFBModeChange notification
3038 *
3039 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
3040 */
3041DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
3042{
3043 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3044
3045 LogRelFlowFunc(("fEnabled=%d\n", fEnabled));
3046
3047 NOREF(fEnabled);
3048
3049 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
3050 pDrv->pDisplay->VideoAccelEnableVGA(false, NULL);
3051}
3052
3053/**
3054 * Adapter information change notification.
3055 *
3056 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
3057 */
3058DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
3059 uint32_t u32VRAMSize)
3060{
3061 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3062 pDrv->pDisplay->processAdapterData(pvVRAM, u32VRAMSize);
3063}
3064
3065/**
3066 * Display information change notification.
3067 *
3068 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
3069 */
3070DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface,
3071 void *pvVRAM, unsigned uScreenId)
3072{
3073 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3074 pDrv->pDisplay->processDisplayData(pvVRAM, uScreenId);
3075}
3076
3077#ifdef VBOX_WITH_VIDEOHWACCEL
3078
3079#ifndef S_FALSE
3080# define S_FALSE ((HRESULT)1L)
3081#endif
3082
3083int Display::i_handleVHWACommandProcess(PVBOXVHWACMD pCommand)
3084{
3085 unsigned id = (unsigned)pCommand->iDisplay;
3086 int rc = VINF_SUCCESS;
3087 if (id >= mcMonitors)
3088 return VERR_INVALID_PARAMETER;
3089
3090 ComPtr<IFramebuffer> pFramebuffer;
3091 AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS);
3092 pFramebuffer = maFramebuffers[id].pFramebuffer;
3093 bool fVHWASupported = RT_BOOL(maFramebuffers[id].u32Caps & FramebufferCapabilities_VHWA);
3094 arlock.release();
3095
3096 if (pFramebuffer == NULL || !fVHWASupported)
3097 return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */
3098
3099 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);
3100 if (hr == S_FALSE)
3101 return VINF_SUCCESS;
3102 else if (SUCCEEDED(hr))
3103 return VINF_CALLBACK_RETURN;
3104 else if (hr == E_ACCESSDENIED)
3105 return VERR_INVALID_STATE; /* notify we can not handle request atm */
3106 else if (hr == E_NOTIMPL)
3107 return VERR_NOT_IMPLEMENTED;
3108 return VERR_GENERAL_FAILURE;
3109}
3110
3111DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
3112{
3113 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3114
3115 return pDrv->pDisplay->i_handleVHWACommandProcess(pCommand);
3116}
3117#endif
3118
3119#ifdef VBOX_WITH_CRHGSMI
3120void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3121{
3122 mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks,
3123 (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);
3124}
3125
3126void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
3127{
3128 PVBOXVDMACMD_CHROMIUM_CTL pCtl = (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr;
3129 mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, pCtl, result);
3130}
3131
3132void Display::i_handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)
3133{
3134 int rc = VERR_NOT_SUPPORTED;
3135 VBOXHGCMSVCPARM parm;
3136 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3137 parm.u.pointer.addr = pCmd;
3138 parm.u.pointer.size = cbCmd;
3139
3140 if (mhCrOglSvc)
3141 {
3142 VMMDev *pVMMDev = mParent->i_getVMMDev();
3143 if (pVMMDev)
3144 {
3145 /* no completion callback is specified with this call,
3146 * the CrOgl code will complete the CrHgsmi command once it processes it */
3147 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, NULL, NULL);
3148 AssertRC(rc);
3149 if (RT_SUCCESS(rc))
3150 return;
3151 }
3152 else
3153 rc = VERR_INVALID_STATE;
3154 }
3155
3156 /* we are here because something went wrong with command processing, complete it */
3157 i_handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm);
3158}
3159
3160void Display::i_handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)
3161{
3162 int rc = VERR_NOT_SUPPORTED;
3163 VBOXHGCMSVCPARM parm;
3164 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3165 parm.u.pointer.addr = pCtl;
3166 parm.u.pointer.size = cbCtl;
3167
3168 if (mhCrOglSvc)
3169 {
3170 VMMDev *pVMMDev = mParent->i_getVMMDev();
3171 if (pVMMDev)
3172 {
3173 bool fCheckPendingViewport = (pCtl->enmType == VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP);
3174 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm,
3175 Display::i_displayCrHgsmiControlCompletion, this);
3176 AssertRC(rc);
3177 if (RT_SUCCESS(rc))
3178 {
3179 if (fCheckPendingViewport)
3180 {
3181 ULONG ul;
3182 for (ul = 0; ul < mcMonitors; ul++)
3183 {
3184 DISPLAYFBINFO *pFb = &maFramebuffers[ul];
3185 if (!pFb->pendingViewportInfo.fPending)
3186 continue;
3187
3188 rc = i_crViewportNotify(ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y,
3189 pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height);
3190 if (RT_SUCCESS(rc))
3191 pFb->pendingViewportInfo.fPending = false;
3192 else
3193 {
3194 AssertMsgFailed(("crViewportNotify failed %d\n", rc));
3195 rc = VINF_SUCCESS;
3196 }
3197 }
3198 }
3199 return;
3200 }
3201 }
3202 else
3203 rc = VERR_INVALID_STATE;
3204 }
3205
3206 /* we are here because something went wrong with command processing, complete it */
3207 i_handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm);
3208}
3209
3210DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,
3211 uint32_t cbCmd)
3212{
3213 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3214
3215 pDrv->pDisplay->i_handleCrHgsmiCommandProcess(pCmd, cbCmd);
3216}
3217
3218DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,
3219 uint32_t cbCmd)
3220{
3221 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3222
3223 pDrv->pDisplay->i_handleCrHgsmiControlProcess(pCmd, cbCmd);
3224}
3225
3226DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3227 void *pvContext)
3228{
3229 AssertMsgFailed(("not expected!"));
3230 Display *pDisplay = (Display *)pvContext;
3231 pDisplay->i_handleCrHgsmiCommandCompletion(result, u32Function, pParam);
3232}
3233
3234DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3235 void *pvContext)
3236{
3237 Display *pDisplay = (Display *)pvContext;
3238 pDisplay->i_handleCrHgsmiControlCompletion(result, u32Function, pParam);
3239
3240}
3241#endif
3242
3243#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3244DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
3245 void *pvContext)
3246{
3247 VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;
3248 if (pCmd->u.pfnInternal)
3249 ((PFNCRCTLCOMPLETION)pCmd->u.pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);
3250}
3251
3252int Display::i_handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3253 PFNCRCTLCOMPLETION pfnCompletion,
3254 void *pvCompletion)
3255{
3256 VMMDev *pVMMDev = mParent ? mParent->i_getVMMDev() : NULL;
3257 if (!pVMMDev)
3258 {
3259 AssertMsgFailed(("no vmmdev\n"));
3260 return VERR_INVALID_STATE;
3261 }
3262
3263 Assert(mhCrOglSvc);
3264 VBOXHGCMSVCPARM parm;
3265 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3266 parm.u.pointer.addr = pCmd;
3267 parm.u.pointer.size = cbCmd;
3268
3269 pCmd->u.pfnInternal = (void(*)())pfnCompletion;
3270 int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,
3271 pvCompletion);
3272 if (!RT_SUCCESS(rc))
3273 AssertMsgFailed(("hgcmHostFastCallAsync failed rc %d\n", rc));
3274
3275 return rc;
3276}
3277
3278DECLCALLBACK(int) Display::i_displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
3279 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
3280 PFNCRCTLCOMPLETION pfnCompletion,
3281 void *pvCompletion)
3282{
3283 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3284 Display *pThis = pDrv->pDisplay;
3285 return pThis->i_handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);
3286}
3287
3288int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)
3289{
3290 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3291 if (RT_SUCCESS(rc))
3292 {
3293 if (mhCrOglSvc)
3294 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);
3295 else
3296 rc = VERR_NOT_SUPPORTED;
3297
3298 RTCritSectRwLeaveShared(&mCrOglLock);
3299 }
3300 return rc;
3301}
3302
3303int Display::i_crCtlSubmitSync(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3304{
3305 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3306 if (RT_SUCCESS(rc))
3307 {
3308 if (mhCrOglSvc)
3309 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmitSync(mpDrv->pVBVACallbacks, pCmd, cbCmd);
3310 else
3311 rc = VERR_NOT_SUPPORTED;
3312
3313 RTCritSectRwLeaveShared(&mCrOglLock);
3314 }
3315 return rc;
3316}
3317
3318int Display::i_crCtlSubmitAsyncCmdCopy(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3319{
3320 VBOXCRCMDCTL* pCmdCopy = (VBOXCRCMDCTL*)RTMemAlloc(cbCmd);
3321 if (!pCmdCopy)
3322 {
3323 LogRel(("RTMemAlloc failed\n"));
3324 return VERR_NO_MEMORY;
3325 }
3326
3327 memcpy(pCmdCopy, pCmd, cbCmd);
3328
3329 int rc = i_crCtlSubmit(pCmdCopy, cbCmd, i_displayCrCmdFree, pCmdCopy);
3330 if (RT_FAILURE(rc))
3331 {
3332 LogRel(("crCtlSubmit failed %d\n", rc));
3333 RTMemFree(pCmdCopy);
3334 return rc;
3335 }
3336
3337 return VINF_SUCCESS;
3338}
3339
3340int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
3341{
3342 int rc = RTCritSectRwEnterShared(&mCrOglLock);
3343 AssertRCReturn(rc, rc);
3344
3345 if (mCrOglCallbacks.pfnHasDataForScreen && mCrOglCallbacks.pfnHasDataForScreen(u32ScreenID))
3346 rc = i_crCtlSubmitSync(pCmd, cbCmd);
3347 else
3348 rc = i_crCtlSubmitAsyncCmdCopy(pCmd, cbCmd);
3349
3350 RTCritSectRwLeaveShared(&mCrOglLock);
3351
3352 return rc;
3353}
3354
3355bool Display::i_handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp)
3356{
3357# if VBOX_WITH_VPX
3358 return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp);
3359# else
3360 return false;
3361# endif
3362}
3363
3364void Display::i_handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp)
3365{
3366}
3367
3368void Display::i_handleCrVRecScreenshotPerform(uint32_t uScreen,
3369 uint32_t x, uint32_t y, uint32_t uPixelFormat,
3370 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
3371 uint32_t uGuestWidth, uint32_t uGuestHeight,
3372 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
3373{
3374 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3375# if VBOX_WITH_VPX
3376 int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y,
3377 uPixelFormat,
3378 uBitsPerPixel, uBytesPerLine,
3379 uGuestWidth, uGuestHeight,
3380 pu8BufferAddress, u64TimeStamp);
3381 Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/);
3382# endif
3383}
3384
3385void Display::i_handleVRecCompletion()
3386{
3387 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
3388 ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);
3389}
3390
3391DECLCALLBACK(void) Display::i_displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen,
3392 uint32_t x, uint32_t y,
3393 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
3394 uint32_t uGuestWidth, uint32_t uGuestHeight,
3395 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
3396{
3397 Display *pDisplay = (Display *)pvCtx;
3398 pDisplay->i_handleCrVRecScreenshotPerform(uScreen,
3399 x, y, BitmapFormat_BGR, uBitsPerPixel,
3400 uBytesPerLine, uGuestWidth, uGuestHeight,
3401 pu8BufferAddress, u64TimeStamp);
3402}
3403
3404DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
3405{
3406 Display *pDisplay = (Display *)pvCtx;
3407 return pDisplay->i_handleCrVRecScreenshotBegin(uScreen, u64TimeStamp);
3408}
3409
3410DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
3411{
3412 Display *pDisplay = (Display *)pvCtx;
3413 pDisplay->i_handleCrVRecScreenshotEnd(uScreen, u64TimeStamp);
3414}
3415
3416DECLCALLBACK(void) Display::i_displayVRecCompletion(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
3417{
3418 Display *pDisplay = (Display *)pvCompletion;
3419 pDisplay->i_handleVRecCompletion();
3420}
3421
3422#endif
3423
3424
3425#ifdef VBOX_WITH_HGSMI
3426DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,
3427 bool fRenderThreadMode)
3428{
3429 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
3430
3431 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3432 Display *pThis = pDrv->pDisplay;
3433
3434 if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)
3435 {
3436 LogRel(("enabling different vbva mode"));
3437#ifdef DEBUG_misha
3438 AssertMsgFailed(("enabling different vbva mode"));
3439#endif
3440 return VERR_INVALID_STATE;
3441 }
3442
3443 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;
3444 pThis->maFramebuffers[uScreenId].pVBVAHostFlags = pHostFlags;
3445 pThis->maFramebuffers[uScreenId].fRenderThreadMode = fRenderThreadMode;
3446 pThis->maFramebuffers[uScreenId].fVBVAForceResize = true;
3447
3448 vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
3449
3450 return VINF_SUCCESS;
3451}
3452
3453DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
3454{
3455 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
3456
3457 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3458 Display *pThis = pDrv->pDisplay;
3459
3460 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3461
3462 bool fRenderThreadMode = pFBInfo->fRenderThreadMode;
3463
3464 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3465 {
3466 /* Make sure that the primary screen is visible now.
3467 * The guest can't use VBVA anymore, so only only the VGA device output works.
3468 */
3469 if (pFBInfo->fDisabled)
3470 {
3471 pFBInfo->fDisabled = false;
3472 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3473 GuestMonitorChangedEventType_Enabled,
3474 uScreenId,
3475 pFBInfo->xOrigin, pFBInfo->yOrigin,
3476 pFBInfo->w, pFBInfo->h);
3477 }
3478 }
3479
3480 pFBInfo->fVBVAEnabled = false;
3481 pFBInfo->fVBVAForceResize = false;
3482 pFBInfo->fRenderThreadMode = false;
3483
3484 vbvaSetMemoryFlagsHGSMI(uScreenId, 0, false, pFBInfo);
3485
3486 pFBInfo->pVBVAHostFlags = NULL;
3487
3488 if (!fRenderThreadMode && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3489 {
3490 /* Force full screen update, because VGA device must take control, do resize, etc. */
3491 pThis->mpDrv->pUpPort->pfnUpdateDisplayAll(pThis->mpDrv->pUpPort, /* fFailOnResize = */ false);
3492 }
3493}
3494
3495DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
3496{
3497 LogFlowFunc(("uScreenId %d\n", uScreenId));
3498
3499 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3500 Display *pThis = pDrv->pDisplay;
3501 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3502
3503 if (ASMAtomicReadU32(&pThis->mu32UpdateVBVAFlags) > 0)
3504 {
3505 vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,
3506 pThis->mcMonitors);
3507 ASMAtomicDecU32(&pThis->mu32UpdateVBVAFlags);
3508 }
3509}
3510
3511DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,
3512 const PVBVACMDHDR pCmd, size_t cbCmd)
3513{
3514 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
3515
3516 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3517 Display *pThis = pDrv->pDisplay;
3518 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3519
3520 if (pFBInfo->fDefaultFormat)
3521 {
3522 /* Make sure that framebuffer contains the same image as the guest VRAM. */
3523 if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
3524 && !pFBInfo->fDisabled)
3525 {
3526 pDrv->pUpPort->pfnUpdateDisplayRect(pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h);
3527 }
3528 else if ( !pFBInfo->pSourceBitmap.isNull()
3529 && !pFBInfo->fDisabled)
3530 {
3531 /* Render VRAM content to the framebuffer. */
3532 BYTE *pAddress = NULL;
3533 ULONG ulWidth = 0;
3534 ULONG ulHeight = 0;
3535 ULONG ulBitsPerPixel = 0;
3536 ULONG ulBytesPerLine = 0;
3537 ULONG ulPixelFormat = 0;
3538
3539 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
3540 &ulWidth,
3541 &ulHeight,
3542 &ulBitsPerPixel,
3543 &ulBytesPerLine,
3544 &ulPixelFormat);
3545 if (SUCCEEDED(hrc))
3546 {
3547 uint32_t width = pCmd->w;
3548 uint32_t height = pCmd->h;
3549
3550 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
3551 int32_t xSrc = pCmd->x - pFBInfo->xOrigin;
3552 int32_t ySrc = pCmd->y - pFBInfo->yOrigin;
3553 uint32_t u32SrcWidth = pFBInfo->w;
3554 uint32_t u32SrcHeight = pFBInfo->h;
3555 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
3556 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
3557
3558 uint8_t *pu8Dst = pAddress;
3559 int32_t xDst = xSrc;
3560 int32_t yDst = ySrc;
3561 uint32_t u32DstWidth = u32SrcWidth;
3562 uint32_t u32DstHeight = u32SrcHeight;
3563 uint32_t u32DstLineSize = u32DstWidth * 4;
3564 uint32_t u32DstBitsPerPixel = 32;
3565
3566 pDrv->pUpPort->pfnCopyRect(pDrv->pUpPort,
3567 width, height,
3568 pu8Src,
3569 xSrc, ySrc,
3570 u32SrcWidth, u32SrcHeight,
3571 u32SrcLineSize, u32SrcBitsPerPixel,
3572 pu8Dst,
3573 xDst, yDst,
3574 u32DstWidth, u32DstHeight,
3575 u32DstLineSize, u32DstBitsPerPixel);
3576 }
3577 }
3578 }
3579
3580 VBVACMDHDR hdrSaved = *pCmd;
3581
3582 VBVACMDHDR *pHdrUnconst = (VBVACMDHDR *)pCmd;
3583
3584 pHdrUnconst->x -= (int16_t)pFBInfo->xOrigin;
3585 pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin;
3586
3587 /* @todo new SendUpdate entry which can get a separate cmd header or coords. */
3588 pThis->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, pCmd, (uint32_t)cbCmd);
3589
3590 *pHdrUnconst = hdrSaved;
3591}
3592
3593DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,
3594 uint32_t cx, uint32_t cy)
3595{
3596 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));
3597
3598 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3599 Display *pThis = pDrv->pDisplay;
3600 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
3601
3602 /* @todo handleFramebufferUpdate (uScreenId,
3603 * x - pThis->maFramebuffers[uScreenId].xOrigin,
3604 * y - pThis->maFramebuffers[uScreenId].yOrigin,
3605 * cx, cy);
3606 */
3607 pThis->i_handleDisplayUpdate(uScreenId, x - pFBInfo->xOrigin, y - pFBInfo->yOrigin, cx, cy);
3608}
3609
3610#ifdef DEBUG_sunlover
3611static void logVBVAResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)
3612{
3613 LogRel(("displayVBVAResize: [%d] %s\n"
3614 " pView->u32ViewIndex %d\n"
3615 " pView->u32ViewOffset 0x%08X\n"
3616 " pView->u32ViewSize 0x%08X\n"
3617 " pView->u32MaxScreenSize 0x%08X\n"
3618 " pScreen->i32OriginX %d\n"
3619 " pScreen->i32OriginY %d\n"
3620 " pScreen->u32StartOffset 0x%08X\n"
3621 " pScreen->u32LineSize 0x%08X\n"
3622 " pScreen->u32Width %d\n"
3623 " pScreen->u32Height %d\n"
3624 " pScreen->u16BitsPerPixel %d\n"
3625 " pScreen->u16Flags 0x%04X\n"
3626 " pFBInfo->u32Offset 0x%08X\n"
3627 " pFBInfo->u32MaxFramebufferSize 0x%08X\n"
3628 " pFBInfo->u32InformationSize 0x%08X\n"
3629 " pFBInfo->fDisabled %d\n"
3630 " xOrigin, yOrigin, w, h: %d,%d %dx%d\n"
3631 " pFBInfo->u16BitsPerPixel %d\n"
3632 " pFBInfo->pu8FramebufferVRAM %p\n"
3633 " pFBInfo->u32LineSize 0x%08X\n"
3634 " pFBInfo->flags 0x%04X\n"
3635 " pFBInfo->pHostEvents %p\n"
3636 " pFBInfo->fDefaultFormat %d\n"
3637 " pFBInfo->fVBVAEnabled %d\n"
3638 " pFBInfo->fVBVAForceResize %d\n"
3639 " pFBInfo->pVBVAHostFlags %p\n"
3640 "",
3641 pScreen->u32ViewIndex,
3642 (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)? "DISABLED": "ENABLED",
3643 pView->u32ViewIndex,
3644 pView->u32ViewOffset,
3645 pView->u32ViewSize,
3646 pView->u32MaxScreenSize,
3647 pScreen->i32OriginX,
3648 pScreen->i32OriginY,
3649 pScreen->u32StartOffset,
3650 pScreen->u32LineSize,
3651 pScreen->u32Width,
3652 pScreen->u32Height,
3653 pScreen->u16BitsPerPixel,
3654 pScreen->u16Flags,
3655 pFBInfo->u32Offset,
3656 pFBInfo->u32MaxFramebufferSize,
3657 pFBInfo->u32InformationSize,
3658 pFBInfo->fDisabled,
3659 pFBInfo->xOrigin,
3660 pFBInfo->yOrigin,
3661 pFBInfo->w,
3662 pFBInfo->h,
3663 pFBInfo->u16BitsPerPixel,
3664 pFBInfo->pu8FramebufferVRAM,
3665 pFBInfo->u32LineSize,
3666 pFBInfo->flags,
3667 pFBInfo->pHostEvents,
3668 pFBInfo->fDefaultFormat,
3669 pFBInfo->fVBVAEnabled,
3670 pFBInfo->fVBVAForceResize,
3671 pFBInfo->pVBVAHostFlags
3672 ));
3673}
3674#endif /* DEBUG_sunlover */
3675
3676DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView,
3677 const PVBVAINFOSCREEN pScreen, void *pvVRAM)
3678{
3679 LogRelFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));
3680
3681 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3682 Display *pThis = pDrv->pDisplay;
3683
3684 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];
3685
3686 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
3687 {
3688 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
3689
3690 pFBInfo->fDisabled = true;
3691 pFBInfo->flags = pScreen->u16Flags;
3692
3693 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.
3694 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,
3695 * the VM window will be black. */
3696 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;
3697 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;
3698 pThis->i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,
3699 u32Width, u32Height, pScreen->u16Flags);
3700
3701 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3702 GuestMonitorChangedEventType_Disabled,
3703 pScreen->u32ViewIndex,
3704 0, 0, 0, 0);
3705 return VINF_SUCCESS;
3706 }
3707
3708 /* If display was disabled or there is no framebuffer, a resize will be required,
3709 * because the framebuffer was/will be changed.
3710 */
3711 bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull();
3712
3713 if (pFBInfo->fVBVAForceResize)
3714 {
3715 /* VBVA was just enabled. Do the resize. */
3716 fResize = true;
3717 pFBInfo->fVBVAForceResize = false;
3718 }
3719
3720 /* Check if this is a real resize or a notification about the screen origin.
3721 * The guest uses this VBVAResize call for both.
3722 */
3723 fResize = fResize
3724 || pFBInfo->u16BitsPerPixel != pScreen->u16BitsPerPixel
3725 || pFBInfo->pu8FramebufferVRAM != (uint8_t *)pvVRAM + pScreen->u32StartOffset
3726 || pFBInfo->u32LineSize != pScreen->u32LineSize
3727 || pFBInfo->w != pScreen->u32Width
3728 || pFBInfo->h != pScreen->u32Height;
3729
3730 bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX
3731 || pFBInfo->yOrigin != pScreen->i32OriginY;
3732
3733 if (fNewOrigin || fResize)
3734 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
3735
3736 if (pFBInfo->fDisabled)
3737 {
3738 pFBInfo->fDisabled = false;
3739 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3740 GuestMonitorChangedEventType_Enabled,
3741 pScreen->u32ViewIndex,
3742 pScreen->i32OriginX, pScreen->i32OriginY,
3743 pScreen->u32Width, pScreen->u32Height);
3744 /* Continue to update pFBInfo. */
3745 }
3746
3747 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */
3748 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */
3749 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */
3750
3751 pFBInfo->xOrigin = pScreen->i32OriginX;
3752 pFBInfo->yOrigin = pScreen->i32OriginY;
3753
3754 pFBInfo->w = pScreen->u32Width;
3755 pFBInfo->h = pScreen->u32Height;
3756
3757 pFBInfo->u16BitsPerPixel = pScreen->u16BitsPerPixel;
3758 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM + pScreen->u32StartOffset;
3759 pFBInfo->u32LineSize = pScreen->u32LineSize;
3760
3761 pFBInfo->flags = pScreen->u16Flags;
3762
3763 if (fNewOrigin)
3764 {
3765 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
3766 GuestMonitorChangedEventType_NewOrigin,
3767 pScreen->u32ViewIndex,
3768 pScreen->i32OriginX, pScreen->i32OriginY,
3769 0, 0);
3770 }
3771
3772 if (!fResize)
3773 {
3774 /* No parameters of the framebuffer have actually changed. */
3775 if (fNewOrigin)
3776 {
3777 /* VRDP server still need this notification. */
3778 LogRelFlowFunc(("Calling VRDP\n"));
3779 pThis->mParent->i_consoleVRDPServer()->SendResize();
3780 }
3781 return VINF_SUCCESS;
3782 }
3783
3784 /* Do a regular resize. */
3785 return pThis->i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
3786 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
3787 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags);
3788}
3789
3790DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
3791 uint32_t xHot, uint32_t yHot,
3792 uint32_t cx, uint32_t cy,
3793 const void *pvShape)
3794{
3795 LogFlowFunc(("\n"));
3796
3797 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3798 Display *pThis = pDrv->pDisplay;
3799
3800 uint32_t cbShape = 0;
3801 if (pvShape)
3802 {
3803 cbShape = (cx + 7) / 8 * cy; /* size of the AND mask */
3804 cbShape = ((cbShape + 3) & ~3) + cx * 4 * cy; /* + gap + size of the XOR mask */
3805 }
3806
3807 /* Tell the console about it */
3808 pDrv->pDisplay->mParent->i_onMousePointerShapeChange(fVisible, fAlpha,
3809 xHot, yHot, cx, cy, (uint8_t *)pvShape, cbShape);
3810
3811 return VINF_SUCCESS;
3812}
3813#endif /* VBOX_WITH_HGSMI */
3814
3815/**
3816 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3817 */
3818DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3819{
3820 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
3821 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3822 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
3823 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);
3824 return NULL;
3825}
3826
3827
3828/**
3829 * Destruct a display driver instance.
3830 *
3831 * @returns VBox status.
3832 * @param pDrvIns The driver instance data.
3833 */
3834DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)
3835{
3836 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
3837 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3838 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
3839
3840 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
3841
3842 pThis->IConnector.pu8Data = NULL;
3843 pThis->IConnector.cbScanline = 0;
3844 pThis->IConnector.cBits = 32;
3845 pThis->IConnector.cx = 0;
3846 pThis->IConnector.cy = 0;
3847
3848 if (pThis->pDisplay)
3849 {
3850 AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS);
3851#ifdef VBOX_WITH_VPX
3852 pThis->pDisplay->i_VideoCaptureStop();
3853#endif
3854#ifdef VBOX_WITH_CRHGSMI
3855 pThis->pDisplay->i_destructCrHgsmiData();
3856#endif
3857 pThis->pDisplay->mpDrv = NULL;
3858 pThis->pDisplay->mpVMMDev = NULL;
3859 }
3860}
3861
3862
3863/**
3864 * Construct a display driver instance.
3865 *
3866 * @copydoc FNPDMDRVCONSTRUCT
3867 */
3868DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
3869{
3870 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
3871 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
3872 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
3873
3874 /*
3875 * Validate configuration.
3876 */
3877 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
3878 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
3879 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
3880 ("Configuration error: Not possible to attach anything to this driver!\n"),
3881 VERR_PDM_DRVINS_NO_ATTACH);
3882
3883 /*
3884 * Init Interfaces.
3885 */
3886 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;
3887
3888 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;
3889 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;
3890 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;
3891 pThis->IConnector.pfnReset = Display::i_displayResetCallback;
3892 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;
3893 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;
3894 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;
3895#ifdef VBOX_WITH_VIDEOHWACCEL
3896 pThis->IConnector.pfnVHWACommandProcess = Display::i_displayVHWACommandProcess;
3897#endif
3898#ifdef VBOX_WITH_CRHGSMI
3899 pThis->IConnector.pfnCrHgsmiCommandProcess = Display::i_displayCrHgsmiCommandProcess;
3900 pThis->IConnector.pfnCrHgsmiControlProcess = Display::i_displayCrHgsmiControlProcess;
3901#endif
3902#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3903 pThis->IConnector.pfnCrHgcmCtlSubmit = Display::i_displayCrHgcmCtlSubmit;
3904#endif
3905#ifdef VBOX_WITH_HGSMI
3906 pThis->IConnector.pfnVBVAEnable = Display::i_displayVBVAEnable;
3907 pThis->IConnector.pfnVBVADisable = Display::i_displayVBVADisable;
3908 pThis->IConnector.pfnVBVAUpdateBegin = Display::i_displayVBVAUpdateBegin;
3909 pThis->IConnector.pfnVBVAUpdateProcess = Display::i_displayVBVAUpdateProcess;
3910 pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;
3911 pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;
3912 pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;
3913#endif
3914
3915 /*
3916 * Get the IDisplayPort interface of the above driver/device.
3917 */
3918 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);
3919 if (!pThis->pUpPort)
3920 {
3921 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
3922 return VERR_PDM_MISSING_INTERFACE_ABOVE;
3923 }
3924#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
3925 pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS);
3926 if (!pThis->pVBVACallbacks)
3927 {
3928 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
3929 return VERR_PDM_MISSING_INTERFACE_ABOVE;
3930 }
3931#endif
3932 /*
3933 * Get the Display object pointer and update the mpDrv member.
3934 */
3935 void *pv;
3936 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
3937 if (RT_FAILURE(rc))
3938 {
3939 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
3940 return rc;
3941 }
3942 Display *pDisplay = (Display *)pv; /** @todo Check this cast! */
3943 pThis->pDisplay = pDisplay;
3944 pThis->pDisplay->mpDrv = pThis;
3945
3946 /* Disable VRAM to a buffer copy initially. */
3947 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
3948 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */
3949
3950 /*
3951 * Start periodic screen refreshes
3952 */
3953 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);
3954
3955#ifdef VBOX_WITH_CRHGSMI
3956 pDisplay->i_setupCrHgsmiData();
3957#endif
3958
3959#ifdef VBOX_WITH_VPX
3960 ComPtr<IMachine> pMachine = pDisplay->mParent->i_machine();
3961 BOOL fEnabled = false;
3962 HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);
3963 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
3964 if (fEnabled)
3965 {
3966 rc = pDisplay->i_VideoCaptureStart();
3967 fireVideoCaptureChangedEvent(pDisplay->mParent->i_getEventSource());
3968 }
3969#endif
3970
3971 return rc;
3972}
3973
3974
3975/**
3976 * Display driver registration record.
3977 */
3978const PDMDRVREG Display::DrvReg =
3979{
3980 /* u32Version */
3981 PDM_DRVREG_VERSION,
3982 /* szName */
3983 "MainDisplay",
3984 /* szRCMod */
3985 "",
3986 /* szR0Mod */
3987 "",
3988 /* pszDescription */
3989 "Main display driver (Main as in the API).",
3990 /* fFlags */
3991 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
3992 /* fClass. */
3993 PDM_DRVREG_CLASS_DISPLAY,
3994 /* cMaxInstances */
3995 ~0U,
3996 /* cbInstance */
3997 sizeof(DRVMAINDISPLAY),
3998 /* pfnConstruct */
3999 Display::i_drvConstruct,
4000 /* pfnDestruct */
4001 Display::i_drvDestruct,
4002 /* pfnRelocate */
4003 NULL,
4004 /* pfnIOCtl */
4005 NULL,
4006 /* pfnPowerOn */
4007 NULL,
4008 /* pfnReset */
4009 NULL,
4010 /* pfnSuspend */
4011 NULL,
4012 /* pfnResume */
4013 NULL,
4014 /* pfnAttach */
4015 NULL,
4016 /* pfnDetach */
4017 NULL,
4018 /* pfnPowerOff */
4019 NULL,
4020 /* pfnSoftReset */
4021 NULL,
4022 /* u32EndVersion */
4023 PDM_DRVREG_VERSION
4024};
4025
4026/* 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