VirtualBox

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

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

DisplayImpl: Cache the 'Accelerated3DEnabled && GraphicControlerType == VBoxVGA' query, and use it to avoid a number of useless HGCM call setups when VMSVGA is active.

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