VirtualBox

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

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

DisplayImpl.cpp: VMSVGA3d does not use the mCrOglCallbacks.

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