VirtualBox

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

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

Devices/Graphics, Devices/PC/DevACPI, Main: add support for sending video mode hints through the VGA device.

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