VirtualBox

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

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

IDisplay::GetScreenResolution gcc warning

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