VirtualBox

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

Last change on this file since 52978 was 52978, checked in by vboxsync, 11 years ago

IDisplay::GetScreenResolution returns status of the guest monitor.

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

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