VirtualBox

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

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

DisplayImpl: IDisplay::InvalidateAndUpdateScreen

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 169.4 KB
Line 
1/* $Id: DisplayImpl.cpp 52117 2014-07-21 20:12:17Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "DisplayImpl.h"
19#include "DisplayUtils.h"
20#include "ConsoleImpl.h"
21#include "ConsoleVRDPServer.h"
22#include "VMMDev.h"
23
24#include "AutoCaller.h"
25#include "Logging.h"
26
27/* generated header */
28#include "VBoxEvents.h"
29
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <iprt/asm.h>
33#include <iprt/time.h>
34#include <iprt/cpp/utils.h>
35#include <iprt/alloca.h>
36
37#include <VBox/vmm/pdmdrv.h>
38#if defined(DEBUG) || defined(VBOX_STRICT) /* for VM_ASSERT_EMT(). */
39# include <VBox/vmm/vm.h>
40#endif
41
42#ifdef VBOX_WITH_VIDEOHWACCEL
43# include <VBox/VBoxVideo.h>
44#endif
45
46#if defined(VBOX_WITH_CROGL) || defined(VBOX_WITH_CRHGSMI)
47# include <VBox/HostServices/VBoxCrOpenGLSvc.h>
48#endif
49
50#include <VBox/com/array.h>
51
52#ifdef VBOX_WITH_VPX
53# include <iprt/path.h>
54# include "VideoRec.h"
55#endif
56
57#ifdef VBOX_WITH_CROGL
58typedef enum
59{
60 CRVREC_STATE_IDLE,
61 CRVREC_STATE_SUBMITTED
62} CRVREC_STATE;
63#endif
64
65/**
66 * Display driver instance data.
67 *
68 * @implements PDMIDISPLAYCONNECTOR
69 */
70typedef struct DRVMAINDISPLAY
71{
72 /** Pointer to the display object. */
73 Display *pDisplay;
74 /** Pointer to the driver instance structure. */
75 PPDMDRVINS pDrvIns;
76 /** Pointer to the keyboard port interface of the driver/device above us. */
77 PPDMIDISPLAYPORT pUpPort;
78 /** Our display connector interface. */
79 PDMIDISPLAYCONNECTOR IConnector;
80#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
81 /** VBVA callbacks */
82 PPDMIDISPLAYVBVACALLBACKS pVBVACallbacks;
83#endif
84} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
85
86/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
87#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector)
88
89// constructor / destructor
90/////////////////////////////////////////////////////////////////////////////
91
92Display::Display()
93 : mParent(NULL)
94{
95}
96
97Display::~Display()
98{
99}
100
101
102HRESULT Display::FinalConstruct()
103{
104 mpVbvaMemory = NULL;
105 mfVideoAccelEnabled = false;
106 mfVideoAccelVRDP = false;
107 mfu32SupportedOrders = 0;
108 mcVideoAccelVRDPRefs = 0;
109
110 mpPendingVbvaMemory = NULL;
111 mfPendingVideoAccelEnable = false;
112
113 mfMachineRunning = false;
114#ifdef VBOX_WITH_CROGL
115 mfCrOglDataHidden = false;
116#endif
117
118 mpu8VbvaPartial = NULL;
119 mcbVbvaPartial = 0;
120
121 mpDrv = NULL;
122 mpVMMDev = NULL;
123 mfVMMDevInited = false;
124
125 int rc = RTCritSectInit(&mVBVALock);
126 AssertRC(rc);
127
128 mfu32PendingVideoAccelDisable = false;
129
130#ifdef VBOX_WITH_HGSMI
131 mu32UpdateVBVAFlags = 0;
132#endif
133#ifdef VBOX_WITH_VPX
134 mpVideoRecCtx = NULL;
135 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
136 maVideoRecEnabled[i] = true;
137#endif
138
139#ifdef VBOX_WITH_CRHGSMI
140 mhCrOglSvc = NULL;
141 rc = RTCritSectRwInit(&mCrOglLock);
142 AssertRC(rc);
143#endif
144#ifdef VBOX_WITH_CROGL
145 RT_ZERO(mCrOglCallbacks);
146 RT_ZERO(mCrOglScreenshotData);
147 mfCrOglVideoRecState = CRVREC_STATE_IDLE;
148 mCrOglScreenshotData.u32Screen = CRSCREEN_ALL;
149 mCrOglScreenshotData.pvContext = this;
150 mCrOglScreenshotData.pfnScreenshotBegin = i_displayCrVRecScreenshotBegin;
151 mCrOglScreenshotData.pfnScreenshotPerform = i_displayCrVRecScreenshotPerform;
152 mCrOglScreenshotData.pfnScreenshotEnd = i_displayCrVRecScreenshotEnd;
153#endif
154
155 return BaseFinalConstruct();
156}
157
158void Display::FinalRelease()
159{
160 uninit();
161
162 if (RTCritSectIsInitialized (&mVBVALock))
163 {
164 RTCritSectDelete (&mVBVALock);
165 RT_ZERO(mVBVALock);
166 }
167
168#ifdef VBOX_WITH_CRHGSMI
169 if (RTCritSectRwIsInitialized (&mCrOglLock))
170 {
171 RTCritSectRwDelete (&mCrOglLock);
172 RT_ZERO(mCrOglLock);
173 }
174#endif
175 BaseFinalRelease();
176}
177
178// public initializer/uninitializer for internal purposes only
179/////////////////////////////////////////////////////////////////////////////
180
181#define kMaxSizeThumbnail 64
182
183/**
184 * Save thumbnail and screenshot of the guest screen.
185 */
186static int displayMakeThumbnail(uint8_t *pu8Data, uint32_t cx, uint32_t cy,
187 uint8_t **ppu8Thumbnail, uint32_t *pcbThumbnail, uint32_t *pcxThumbnail, uint32_t *pcyThumbnail)
188{
189 int rc = VINF_SUCCESS;
190
191 uint8_t *pu8Thumbnail = NULL;
192 uint32_t cbThumbnail = 0;
193 uint32_t cxThumbnail = 0;
194 uint32_t cyThumbnail = 0;
195
196 if (cx > cy)
197 {
198 cxThumbnail = kMaxSizeThumbnail;
199 cyThumbnail = (kMaxSizeThumbnail * cy) / cx;
200 }
201 else
202 {
203 cyThumbnail = kMaxSizeThumbnail;
204 cxThumbnail = (kMaxSizeThumbnail * cx) / cy;
205 }
206
207 LogRelFlowFunc(("%dx%d -> %dx%d\n", cx, cy, cxThumbnail, cyThumbnail));
208
209 cbThumbnail = cxThumbnail * 4 * cyThumbnail;
210 pu8Thumbnail = (uint8_t *)RTMemAlloc(cbThumbnail);
211
212 if (pu8Thumbnail)
213 {
214 uint8_t *dst = pu8Thumbnail;
215 uint8_t *src = pu8Data;
216 int dstW = cxThumbnail;
217 int dstH = cyThumbnail;
218 int srcW = cx;
219 int srcH = cy;
220 int iDeltaLine = cx * 4;
221
222 BitmapScale32(dst,
223 dstW, dstH,
224 src,
225 iDeltaLine,
226 srcW, srcH);
227
228 *ppu8Thumbnail = pu8Thumbnail;
229 *pcbThumbnail = cbThumbnail;
230 *pcxThumbnail = cxThumbnail;
231 *pcyThumbnail = cyThumbnail;
232 }
233 else
234 {
235 rc = VERR_NO_MEMORY;
236 }
237
238 return rc;
239}
240
241#ifdef VBOX_WITH_CROGL
242typedef struct
243{
244 CRVBOXHGCMTAKESCREENSHOT Base;
245
246 /* 32bpp small RGB image. */
247 uint8_t *pu8Thumbnail;
248 uint32_t cbThumbnail;
249 uint32_t cxThumbnail;
250 uint32_t cyThumbnail;
251
252 /* PNG screenshot. */
253 uint8_t *pu8PNG;
254 uint32_t cbPNG;
255 uint32_t cxPNG;
256 uint32_t cyPNG;
257} VBOX_DISPLAY_SAVESCREENSHOT_DATA;
258
259static DECLCALLBACK(void) displaySaveScreenshotReport(void *pvCtx, uint32_t uScreen,
260 uint32_t x, uint32_t y, uint32_t uBitsPerPixel,
261 uint32_t uBytesPerLine, uint32_t uGuestWidth, uint32_t uGuestHeight,
262 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
263{
264 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pData = (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)pvCtx;
265 displayMakeThumbnail(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8Thumbnail,
266 &pData->cbThumbnail, &pData->cxThumbnail, &pData->cyThumbnail);
267 int rc = DisplayMakePNG(pu8BufferAddress, uGuestWidth, uGuestHeight, &pData->pu8PNG,
268 &pData->cbPNG, &pData->cxPNG, &pData->cyPNG, 1);
269 if (RT_FAILURE(rc))
270 {
271 AssertMsgFailed(("DisplayMakePNG failed %d\n", rc));
272 if (pData->pu8PNG)
273 {
274 RTMemFree(pData->pu8PNG);
275 pData->pu8PNG = NULL;
276 }
277 pData->cbPNG = 0;
278 pData->cxPNG = 0;
279 pData->cyPNG = 0;
280 }
281}
282#endif
283
284DECLCALLBACK(void) Display::i_displaySSMSaveScreenshot(PSSMHANDLE pSSM, void *pvUser)
285{
286 Display *that = static_cast<Display*>(pvUser);
287
288 /* 32bpp small RGB image. */
289 uint8_t *pu8Thumbnail = NULL;
290 uint32_t cbThumbnail = 0;
291 uint32_t cxThumbnail = 0;
292 uint32_t cyThumbnail = 0;
293
294 /* PNG screenshot. */
295 uint8_t *pu8PNG = NULL;
296 uint32_t cbPNG = 0;
297 uint32_t cxPNG = 0;
298 uint32_t cyPNG = 0;
299
300 Console::SafeVMPtr ptrVM(that->mParent);
301 if (ptrVM.isOk())
302 {
303 /* Query RGB bitmap. */
304 uint8_t *pu8Data = NULL;
305 size_t cbData = 0;
306 uint32_t cx = 0;
307 uint32_t cy = 0;
308
309#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
310 BOOL f3DSnapshot = FALSE;
311 BOOL is3denabled;
312 that->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
313 if (is3denabled && that->mCrOglCallbacks.pfnHasData())
314 {
315 VMMDev *pVMMDev = that->mParent->i_getVMMDev();
316 if (pVMMDev)
317 {
318 VBOX_DISPLAY_SAVESCREENSHOT_DATA *pScreenshot =
319 (VBOX_DISPLAY_SAVESCREENSHOT_DATA*)RTMemAllocZ(sizeof(*pScreenshot));
320 if (pScreenshot)
321 {
322 /* screen id or CRSCREEN_ALL to specify all enabled */
323 pScreenshot->Base.u32Screen = 0;
324 pScreenshot->Base.u32Width = 0;
325 pScreenshot->Base.u32Height = 0;
326 pScreenshot->Base.u32Pitch = 0;
327 pScreenshot->Base.pvBuffer = NULL;
328 pScreenshot->Base.pvContext = pScreenshot;
329 pScreenshot->Base.pfnScreenshotBegin = NULL;
330 pScreenshot->Base.pfnScreenshotPerform = displaySaveScreenshotReport;
331 pScreenshot->Base.pfnScreenshotEnd = NULL;
332
333 VBOXCRCMDCTL_HGCM data;
334 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
335 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
336
337 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
338 data.aParms[0].u.pointer.addr = &pScreenshot->Base;
339 data.aParms[0].u.pointer.size = sizeof(pScreenshot->Base);
340
341 int rc = that->i_crCtlSubmitSync(&data.Hdr, sizeof(data));
342 if (RT_SUCCESS(rc))
343 {
344 if (pScreenshot->pu8PNG)
345 {
346 pu8Thumbnail = pScreenshot->pu8Thumbnail;
347 cbThumbnail = pScreenshot->cbThumbnail;
348 cxThumbnail = pScreenshot->cxThumbnail;
349 cyThumbnail = pScreenshot->cyThumbnail;
350
351 /* PNG screenshot. */
352 pu8PNG = pScreenshot->pu8PNG;
353 cbPNG = pScreenshot->cbPNG;
354 cxPNG = pScreenshot->cxPNG;
355 cyPNG = pScreenshot->cyPNG;
356 f3DSnapshot = TRUE;
357 }
358 else
359 AssertMsgFailed(("no png\n"));
360 }
361 else
362 AssertMsgFailed(("SHCRGL_HOST_FN_TAKE_SCREENSHOT failed %d\n", rc));
363
364
365 RTMemFree(pScreenshot);
366 }
367 }
368 }
369
370 if (!f3DSnapshot)
371#endif
372 {
373 /* SSM code is executed on EMT(0), therefore no need to use VMR3ReqCallWait. */
374 int rc = Display::i_displayTakeScreenshotEMT(that, VBOX_VIDEO_PRIMARY_SCREEN, &pu8Data, &cbData, &cx, &cy);
375
376 /*
377 * It is possible that success is returned but everything is 0 or NULL.
378 * (no display attached if a VM is running with VBoxHeadless on OSE for example)
379 */
380 if (RT_SUCCESS(rc) && pu8Data)
381 {
382 Assert(cx && cy);
383
384 /* Prepare a small thumbnail and a PNG screenshot. */
385 displayMakeThumbnail(pu8Data, cx, cy, &pu8Thumbnail, &cbThumbnail, &cxThumbnail, &cyThumbnail);
386 rc = DisplayMakePNG(pu8Data, cx, cy, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 1);
387 if (RT_FAILURE(rc))
388 {
389 if (pu8PNG)
390 {
391 RTMemFree(pu8PNG);
392 pu8PNG = NULL;
393 }
394 cbPNG = 0;
395 cxPNG = 0;
396 cyPNG = 0;
397 }
398
399 /* This can be called from any thread. */
400 Assert(!that->i_vbvaLockIsOwner());
401 that->mpDrv->pUpPort->pfnFreeScreenshot(that->mpDrv->pUpPort, pu8Data);
402 }
403 }
404 }
405 else
406 {
407 LogFunc(("Failed to get VM pointer 0x%x\n", ptrVM.rc()));
408 }
409
410 /* Regardless of rc, save what is available:
411 * Data format:
412 * uint32_t cBlocks;
413 * [blocks]
414 *
415 * Each block is:
416 * uint32_t cbBlock; if 0 - no 'block data'.
417 * uint32_t typeOfBlock; 0 - 32bpp RGB bitmap, 1 - PNG, ignored if 'cbBlock' is 0.
418 * [block data]
419 *
420 * Block data for bitmap and PNG:
421 * uint32_t cx;
422 * uint32_t cy;
423 * [image data]
424 */
425 SSMR3PutU32(pSSM, 2); /* Write thumbnail and PNG screenshot. */
426
427 /* First block. */
428 SSMR3PutU32(pSSM, cbThumbnail + 2 * sizeof(uint32_t));
429 SSMR3PutU32(pSSM, 0); /* Block type: thumbnail. */
430
431 if (cbThumbnail)
432 {
433 SSMR3PutU32(pSSM, cxThumbnail);
434 SSMR3PutU32(pSSM, cyThumbnail);
435 SSMR3PutMem(pSSM, pu8Thumbnail, cbThumbnail);
436 }
437
438 /* Second block. */
439 SSMR3PutU32(pSSM, cbPNG + 2 * sizeof(uint32_t));
440 SSMR3PutU32(pSSM, 1); /* Block type: png. */
441
442 if (cbPNG)
443 {
444 SSMR3PutU32(pSSM, cxPNG);
445 SSMR3PutU32(pSSM, cyPNG);
446 SSMR3PutMem(pSSM, pu8PNG, cbPNG);
447 }
448
449 RTMemFree(pu8PNG);
450 RTMemFree(pu8Thumbnail);
451}
452
453DECLCALLBACK(int)
454Display::i_displaySSMLoadScreenshot(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass)
455{
456 Display *that = static_cast<Display*>(pvUser);
457
458 if (uVersion != sSSMDisplayScreenshotVer)
459 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
460 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
461
462 /* Skip data. */
463 uint32_t cBlocks;
464 int rc = SSMR3GetU32(pSSM, &cBlocks);
465 AssertRCReturn(rc, rc);
466
467 for (uint32_t i = 0; i < cBlocks; i++)
468 {
469 uint32_t cbBlock;
470 rc = SSMR3GetU32(pSSM, &cbBlock);
471 AssertRCBreak(rc);
472
473 uint32_t typeOfBlock;
474 rc = SSMR3GetU32(pSSM, &typeOfBlock);
475 AssertRCBreak(rc);
476
477 LogRelFlowFunc(("[%d] type %d, size %d bytes\n", i, typeOfBlock, cbBlock));
478
479 /* Note: displaySSMSaveScreenshot writes size of a block = 8 and
480 * do not write any data if the image size was 0.
481 * @todo Fix and increase saved state version.
482 */
483 if (cbBlock > 2 * sizeof(uint32_t))
484 {
485 rc = SSMR3Skip(pSSM, cbBlock);
486 AssertRCBreak(rc);
487 }
488 }
489
490 return rc;
491}
492
493/**
494 * Save/Load some important guest state
495 */
496DECLCALLBACK(void)
497Display::i_displaySSMSave(PSSMHANDLE pSSM, void *pvUser)
498{
499 Display *that = static_cast<Display*>(pvUser);
500
501 SSMR3PutU32(pSSM, that->mcMonitors);
502 for (unsigned i = 0; i < that->mcMonitors; i++)
503 {
504 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32Offset);
505 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32MaxFramebufferSize);
506 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32InformationSize);
507 SSMR3PutU32(pSSM, that->maFramebuffers[i].w);
508 SSMR3PutU32(pSSM, that->maFramebuffers[i].h);
509 SSMR3PutS32(pSSM, that->maFramebuffers[i].xOrigin);
510 SSMR3PutS32(pSSM, that->maFramebuffers[i].yOrigin);
511 SSMR3PutU32(pSSM, that->maFramebuffers[i].flags);
512 }
513}
514
515DECLCALLBACK(int)
516Display::i_displaySSMLoad(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPass)
517{
518 Display *that = static_cast<Display*>(pvUser);
519
520 if (!( uVersion == sSSMDisplayVer
521 || uVersion == sSSMDisplayVer2
522 || uVersion == sSSMDisplayVer3))
523 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
524 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
525
526 uint32_t cMonitors;
527 int rc = SSMR3GetU32(pSSM, &cMonitors);
528 if (cMonitors != that->mcMonitors)
529 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Number of monitors changed (%d->%d)!"), cMonitors, that->mcMonitors);
530
531 for (uint32_t i = 0; i < cMonitors; i++)
532 {
533 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32Offset);
534 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32MaxFramebufferSize);
535 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32InformationSize);
536 if ( uVersion == sSSMDisplayVer2
537 || uVersion == sSSMDisplayVer3)
538 {
539 uint32_t w;
540 uint32_t h;
541 SSMR3GetU32(pSSM, &w);
542 SSMR3GetU32(pSSM, &h);
543 that->maFramebuffers[i].w = w;
544 that->maFramebuffers[i].h = h;
545 }
546 if (uVersion == sSSMDisplayVer3)
547 {
548 int32_t xOrigin;
549 int32_t yOrigin;
550 uint32_t flags;
551 SSMR3GetS32(pSSM, &xOrigin);
552 SSMR3GetS32(pSSM, &yOrigin);
553 SSMR3GetU32(pSSM, &flags);
554 that->maFramebuffers[i].xOrigin = xOrigin;
555 that->maFramebuffers[i].yOrigin = yOrigin;
556 that->maFramebuffers[i].flags = (uint16_t)flags;
557 that->maFramebuffers[i].fDisabled = (that->maFramebuffers[i].flags & VBVA_SCREEN_F_DISABLED) != 0;
558 }
559 }
560
561 return VINF_SUCCESS;
562}
563
564/**
565 * Initializes the display object.
566 *
567 * @returns COM result indicator
568 * @param parent handle of our parent object
569 * @param qemuConsoleData address of common console data structure
570 */
571HRESULT Display::init(Console *aParent)
572{
573 ComAssertRet(aParent, E_INVALIDARG);
574 /* Enclose the state transition NotReady->InInit->Ready */
575 AutoInitSpan autoInitSpan(this);
576 AssertReturn(autoInitSpan.isOk(), E_FAIL);
577
578 unconst(mParent) = aParent;
579
580 mfSourceBitmapEnabled = true;
581 fVGAResizing = false;
582
583 ULONG ul;
584 mParent->i_machine()->COMGETTER(MonitorCount)(&ul);
585 mcMonitors = ul;
586
587 for (ul = 0; ul < mcMonitors; ul++)
588 {
589 maFramebuffers[ul].u32Offset = 0;
590 maFramebuffers[ul].u32MaxFramebufferSize = 0;
591 maFramebuffers[ul].u32InformationSize = 0;
592
593 maFramebuffers[ul].pFramebuffer = NULL;
594 /* All secondary monitors are disabled at startup. */
595 maFramebuffers[ul].fDisabled = ul > 0;
596
597 maFramebuffers[ul].enmFramebufferUpdateMode = FramebufferUpdateMode_NotifyUpdate;
598
599 maFramebuffers[ul].updateImage.pu8Address = NULL;
600 maFramebuffers[ul].updateImage.cbLine = 0;
601
602 maFramebuffers[ul].xOrigin = 0;
603 maFramebuffers[ul].yOrigin = 0;
604
605 maFramebuffers[ul].w = 0;
606 maFramebuffers[ul].h = 0;
607
608 maFramebuffers[ul].flags = maFramebuffers[ul].fDisabled? VBVA_SCREEN_F_DISABLED: 0;
609
610 maFramebuffers[ul].u16BitsPerPixel = 0;
611 maFramebuffers[ul].pu8FramebufferVRAM = NULL;
612 maFramebuffers[ul].u32LineSize = 0;
613
614 maFramebuffers[ul].pHostEvents = NULL;
615
616 maFramebuffers[ul].fDefaultFormat = false;
617
618 RT_ZERO(maFramebuffers[ul].dirtyRect);
619#ifdef VBOX_WITH_HGSMI
620 maFramebuffers[ul].fVBVAEnabled = false;
621 maFramebuffers[ul].fVBVAForceResize = false;
622 maFramebuffers[ul].fRenderThreadMode = false;
623 maFramebuffers[ul].pVBVAHostFlags = NULL;
624#endif /* VBOX_WITH_HGSMI */
625#ifdef VBOX_WITH_CROGL
626 RT_ZERO(maFramebuffers[ul].pendingViewportInfo);
627#endif
628 }
629
630 {
631 // register listener for state change events
632 ComPtr<IEventSource> es;
633 mParent->COMGETTER(EventSource)(es.asOutParam());
634 com::SafeArray<VBoxEventType_T> eventTypes;
635 eventTypes.push_back(VBoxEventType_OnStateChanged);
636 es->RegisterListener(this, ComSafeArrayAsInParam(eventTypes), true);
637 }
638
639 /* Confirm a successful initialization */
640 autoInitSpan.setSucceeded();
641
642 return S_OK;
643}
644
645/**
646 * Uninitializes the instance and sets the ready flag to FALSE.
647 * Called either from FinalRelease() or by the parent when it gets destroyed.
648 */
649void Display::uninit()
650{
651 LogRelFlowFunc(("this=%p\n", this));
652
653 /* Enclose the state transition Ready->InUninit->NotReady */
654 AutoUninitSpan autoUninitSpan(this);
655 if (autoUninitSpan.uninitDone())
656 return;
657
658 unsigned uScreenId;
659 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
660 {
661 maFramebuffers[uScreenId].pSourceBitmap.setNull();
662 maFramebuffers[uScreenId].updateImage.pSourceBitmap.setNull();
663 maFramebuffers[uScreenId].updateImage.pu8Address = NULL;
664 maFramebuffers[uScreenId].updateImage.cbLine = 0;
665 maFramebuffers[uScreenId].pFramebuffer.setNull();
666 }
667
668 if (mParent)
669 {
670 ComPtr<IEventSource> es;
671 mParent->COMGETTER(EventSource)(es.asOutParam());
672 es->UnregisterListener(this);
673 }
674
675 unconst(mParent) = NULL;
676
677 if (mpDrv)
678 mpDrv->pDisplay = NULL;
679
680 mpDrv = NULL;
681 mpVMMDev = NULL;
682 mfVMMDevInited = true;
683}
684
685/**
686 * Register the SSM methods. Called by the power up thread to be able to
687 * pass pVM
688 */
689int Display::i_registerSSM(PUVM pUVM)
690{
691 /* Version 2 adds width and height of the framebuffer; version 3 adds
692 * the framebuffer offset in the virtual desktop and the framebuffer flags.
693 */
694 int rc = SSMR3RegisterExternal(pUVM, "DisplayData", 0, sSSMDisplayVer3,
695 mcMonitors * sizeof(uint32_t) * 8 + sizeof(uint32_t),
696 NULL, NULL, NULL,
697 NULL, i_displaySSMSave, NULL,
698 NULL, i_displaySSMLoad, NULL, this);
699 AssertRCReturn(rc, rc);
700
701 /*
702 * Register loaders for old saved states where iInstance was
703 * 3 * sizeof(uint32_t *) due to a code mistake.
704 */
705 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
706 NULL, NULL, NULL,
707 NULL, NULL, NULL,
708 NULL, i_displaySSMLoad, NULL, this);
709 AssertRCReturn(rc, rc);
710
711 rc = SSMR3RegisterExternal(pUVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
712 NULL, NULL, NULL,
713 NULL, NULL, NULL,
714 NULL, i_displaySSMLoad, NULL, this);
715 AssertRCReturn(rc, rc);
716
717 /* uInstance is an arbitrary value greater than 1024. Such a value will ensure a quick seek in saved state file. */
718 rc = SSMR3RegisterExternal(pUVM, "DisplayScreenshot", 1100 /*uInstance*/, sSSMDisplayScreenshotVer, 0 /*cbGuess*/,
719 NULL, NULL, NULL,
720 NULL, i_displaySSMSaveScreenshot, NULL,
721 NULL, i_displaySSMLoadScreenshot, NULL, this);
722
723 AssertRCReturn(rc, rc);
724
725 return VINF_SUCCESS;
726}
727
728DECLCALLBACK(void) Display::i_displayCrCmdFree(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, int rc, void *pvCompletion)
729{
730 Assert(pvCompletion);
731 RTMemFree(pvCompletion);
732}
733
734#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
735int Display::i_crOglWindowsShow(bool fShow)
736{
737 if (!mfCrOglDataHidden == !!fShow)
738 return VINF_SUCCESS;
739
740 if (!mhCrOglSvc)
741 {
742 /* no 3D */
743#ifdef DEBUG
744 BOOL is3denabled;
745 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
746 Assert(!is3denabled);
747#endif
748 return VERR_INVALID_STATE;
749 }
750
751 VMMDev *pVMMDev = mParent->i_getVMMDev();
752 if (!pVMMDev)
753 {
754 AssertMsgFailed(("no vmmdev\n"));
755 return VERR_INVALID_STATE;
756 }
757
758 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM));
759 if (!pData)
760 {
761 AssertMsgFailed(("RTMemAlloc failed\n"));
762 return VERR_NO_MEMORY;
763 }
764
765 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
766 pData->Hdr.u32Function = SHCRGL_HOST_FN_WINDOWS_SHOW;
767
768 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
769 pData->aParms[0].u.uint32 = (uint32_t)fShow;
770
771 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
772 if (RT_SUCCESS(rc))
773 mfCrOglDataHidden = !fShow;
774 else
775 {
776 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
777 RTMemFree(pData);
778 }
779
780 return rc;
781}
782#endif
783
784
785// public methods only for internal purposes
786/////////////////////////////////////////////////////////////////////////////
787
788int Display::i_notifyCroglResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM)
789{
790#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
791 if (maFramebuffers[pScreen->u32ViewIndex].fRenderThreadMode)
792 return VINF_SUCCESS; /* nop it */
793
794 BOOL is3denabled;
795 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
796
797 if (is3denabled)
798 {
799 int rc = VERR_INVALID_STATE;
800 if (mhCrOglSvc)
801 {
802 VMMDev *pVMMDev = mParent->i_getVMMDev();
803 if (pVMMDev)
804 {
805 VBOXCRCMDCTL_HGCM *pCtl =
806 (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(CRVBOXHGCMDEVRESIZE) + sizeof(VBOXCRCMDCTL_HGCM));
807 if (pCtl)
808 {
809 CRVBOXHGCMDEVRESIZE *pData = (CRVBOXHGCMDEVRESIZE*)(pCtl+1);
810 pData->Screen = *pScreen;
811 pData->pvVRAM = pvVRAM;
812
813 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
814 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_DEV_RESIZE;
815 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
816 pCtl->aParms[0].u.pointer.addr = pData;
817 pCtl->aParms[0].u.pointer.size = sizeof(*pData);
818
819 rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);
820 if (!RT_SUCCESS(rc))
821 {
822 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
823 RTMemFree(pCtl);
824 }
825 }
826 else
827 rc = VERR_NO_MEMORY;
828 }
829 }
830
831 return rc;
832 }
833#endif /* #if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
834 return VINF_SUCCESS;
835}
836
837/**
838 * Handles display resize event.
839 *
840 * @param w New display width
841 * @param h New display height
842 *
843 * @thread EMT
844 */
845int Display::i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM,
846 uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags)
847{
848 LogRel(("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p "
849 "w=%d h=%d bpp=%d cbLine=0x%X, flags=0x%X\n",
850 uScreenId, pvVRAM, w, h, bpp, cbLine, flags));
851
852 if (uScreenId >= mcMonitors)
853 {
854 return VINF_SUCCESS;
855 }
856
857 SetFramebufferUpdateMode(uScreenId, FramebufferUpdateMode_NotifyUpdate);
858
859 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
860 {
861 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
862 pFBInfo->w = w;
863 pFBInfo->h = h;
864
865 pFBInfo->u16BitsPerPixel = (uint16_t)bpp;
866 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM;
867 pFBInfo->u32LineSize = cbLine;
868 pFBInfo->flags = flags;
869 }
870
871 /* Guest screen image will be invalid during resize, make sure that it is not updated. */
872 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
873 {
874 Assert(!i_vbvaLockIsOwner());
875 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, false);
876
877 mpDrv->IConnector.pu8Data = NULL;
878 mpDrv->IConnector.cbScanline = 0;
879 mpDrv->IConnector.cBits = 32; /* DevVGA does not work with cBits == 0. */
880 mpDrv->IConnector.cx = 0;
881 mpDrv->IConnector.cy = 0;
882 }
883
884 maFramebuffers[uScreenId].pSourceBitmap.setNull();
885
886 if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
887 {
888 HRESULT hr = maFramebuffers[uScreenId].pFramebuffer->NotifyChange(uScreenId, 0, 0, w, h); /* @todo origin */
889 LogFunc(("NotifyChange hr %08X\n", hr));
890 NOREF(hr);
891 }
892
893 i_handleResizeCompletedEMT(uScreenId, TRUE);
894
895 return VINF_SUCCESS;
896}
897
898/**
899 * Framebuffer has been resized.
900 * Read the new display data and unlock the framebuffer.
901 *
902 * @thread EMT
903 */
904void Display::i_handleResizeCompletedEMT(unsigned uScreenId, BOOL fResizeContext)
905{
906 LogRelFlowFunc(("\n"));
907
908 do /* to use 'break' */
909 {
910 if (uScreenId >= mcMonitors)
911 {
912 break;
913 }
914
915 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
916
917 /* Inform VRDP server about the change of display parameters.
918 * Must be done before calling NotifyUpdate below.
919 */
920 LogRelFlowFunc(("Calling VRDP\n"));
921 mParent->i_consoleVRDPServer()->SendResize();
922
923 /* @todo Merge these two 'if's within one 'if (!pFBInfo->pFramebuffer.isNull())' */
924 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull())
925 {
926 /* If the screen resize was because of disabling, tell framebuffer to repaint.
927 * The framebuffer if now in default format so it will not use guest VRAM
928 * and will show usually black image which is there after framebuffer resize.
929 */
930 if (pFBInfo->fDisabled)
931 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, mpDrv->IConnector.cx, mpDrv->IConnector.cy);
932 }
933 else if (!pFBInfo->pFramebuffer.isNull())
934 {
935 /* If the screen resize was because of disabling, tell framebuffer to repaint.
936 * The framebuffer if now in default format so it will not use guest VRAM
937 * and will show usually black image which is there after framebuffer resize.
938 */
939 if (pFBInfo->fDisabled)
940 pFBInfo->pFramebuffer->NotifyUpdate(0, 0, pFBInfo->w, pFBInfo->h);
941 }
942 LogRelFlow(("[%d]: default format %d\n", uScreenId, pFBInfo->fDefaultFormat));
943
944#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
945 {
946 BOOL is3denabled;
947 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
948
949 if (is3denabled)
950 {
951 VBOXCRCMDCTL_HGCM data;
952 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
953 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
954
955 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
956 data.aParms[0].u.uint32 = uScreenId;
957
958 if (fResizeContext)
959 i_crCtlSubmitAsyncCmdCopy(&data.Hdr, sizeof(data));
960 else
961 i_crCtlSubmitSync(&data.Hdr, sizeof(data));
962 }
963 }
964#endif /* VBOX_WITH_CROGL */
965 } while(0);
966}
967
968static void i_checkCoordBounds(int *px, int *py, int *pw, int *ph, int cx, int cy)
969{
970 /* Correct negative x and y coordinates. */
971 if (*px < 0)
972 {
973 *px += *pw; /* Compute xRight which is also the new width. */
974
975 *pw = (*px < 0)? 0: *px;
976
977 *px = 0;
978 }
979
980 if (*py < 0)
981 {
982 *py += *ph; /* Compute xBottom, which is also the new height. */
983
984 *ph = (*py < 0)? 0: *py;
985
986 *py = 0;
987 }
988
989 /* Also check if coords are greater than the display resolution. */
990 if (*px + *pw > cx)
991 {
992 *pw = cx > *px? cx - *px: 0;
993 }
994
995 if (*py + *ph > cy)
996 {
997 *ph = cy > *py? cy - *py: 0;
998 }
999}
1000
1001unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
1002{
1003 DISPLAYFBINFO *pInfo = pInfos;
1004 unsigned uScreenId;
1005 LogSunlover(("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));
1006 for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)
1007 {
1008 LogSunlover((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
1009 if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)
1010 && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))
1011 {
1012 /* The rectangle belongs to the screen. Correct coordinates. */
1013 *px -= pInfo->xOrigin;
1014 *py -= pInfo->yOrigin;
1015 LogSunlover((" -> %d,%d", *px, *py));
1016 break;
1017 }
1018 }
1019 if (uScreenId == cInfos)
1020 {
1021 /* Map to primary screen. */
1022 uScreenId = 0;
1023 }
1024 LogSunlover((" scr %d\n", uScreenId));
1025 return uScreenId;
1026}
1027
1028
1029/**
1030 * Handles display update event.
1031 *
1032 * @param x Update area x coordinate
1033 * @param y Update area y coordinate
1034 * @param w Update area width
1035 * @param h Update area height
1036 *
1037 * @thread EMT
1038 */
1039void Display::i_handleDisplayUpdateLegacy(int x, int y, int w, int h)
1040{
1041 unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
1042
1043#ifdef DEBUG_sunlover
1044 LogFlowFunc(("%d,%d %dx%d (checked)\n", x, y, w, h));
1045#endif /* DEBUG_sunlover */
1046
1047 i_handleDisplayUpdate(uScreenId, x, y, w, h);
1048}
1049
1050void Display::i_handleDisplayUpdate(unsigned uScreenId, int x, int y, int w, int h)
1051{
1052 /*
1053 * Always runs under either VBVA lock or, for HGSMI, DevVGA lock.
1054 * Safe to use VBVA vars and take the framebuffer lock.
1055 */
1056
1057#ifdef DEBUG_sunlover
1058 LogFlowFunc(("[%d] %d,%d %dx%d (%d,%d)\n",
1059 uScreenId, x, y, w, h, mpDrv->IConnector.cx, mpDrv->IConnector.cy));
1060#endif /* DEBUG_sunlover */
1061
1062 /* No updates for a disabled guest screen. */
1063 if (maFramebuffers[uScreenId].fDisabled)
1064 return;
1065
1066 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1067 i_checkCoordBounds (&x, &y, &w, &h, mpDrv->IConnector.cx, mpDrv->IConnector.cy);
1068 else
1069 i_checkCoordBounds (&x, &y, &w, &h, maFramebuffers[uScreenId].w,
1070 maFramebuffers[uScreenId].h);
1071
1072 IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;
1073 if (pFramebuffer != NULL)
1074 {
1075 if (w != 0 && h != 0)
1076 {
1077 if (RT_LIKELY(maFramebuffers[uScreenId].enmFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdate))
1078 {
1079 pFramebuffer->NotifyUpdate(x, y, w, h);
1080 }
1081 else if (maFramebuffers[uScreenId].enmFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
1082 {
1083 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1086
1087 if (!pFBInfo->updateImage.pSourceBitmap.isNull())
1088 {
1089 Assert(pFBInfo->updateImage.pu8Address);
1090
1091 size_t cbData = w * h * 4;
1092 com::SafeArray<BYTE> image(cbData);
1093
1094 uint8_t *pu8Dst = image.raw();
1095 const uint8_t *pu8Src = pFBInfo->updateImage.pu8Address + pFBInfo->updateImage.cbLine * y + x * 4;
1096
1097 int i;
1098 for (i = y; i < y + h; ++i)
1099 {
1100 memcpy(pu8Dst, pu8Src, w * 4);
1101 pu8Dst += w * 4;
1102 pu8Src += pFBInfo->updateImage.cbLine;
1103 }
1104
1105 pFramebuffer->NotifyUpdateImage(x, y, w, h, ComSafeArrayAsInParam(image));
1106 }
1107 }
1108 }
1109 }
1110
1111#ifndef VBOX_WITH_HGSMI
1112 if (!mfVideoAccelEnabled)
1113 {
1114#else
1115 if (!mfVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)
1116 {
1117#endif /* VBOX_WITH_HGSMI */
1118 /* When VBVA is enabled, the VRDP server is informed
1119 * either in VideoAccelFlush or displayVBVAUpdateProcess.
1120 * Inform the server here only if VBVA is disabled.
1121 */
1122 mParent->i_consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);
1123 }
1124}
1125
1126/**
1127 * Returns the upper left and lower right corners of the virtual framebuffer.
1128 * The lower right is "exclusive" (i.e. first pixel beyond the framebuffer),
1129 * and the origin is (0, 0), not (1, 1) like the GUI returns.
1130 */
1131void Display::i_getFramebufferDimensions(int32_t *px1, int32_t *py1,
1132 int32_t *px2, int32_t *py2)
1133{
1134 int32_t x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1135 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1136
1137 AssertPtrReturnVoid(px1);
1138 AssertPtrReturnVoid(py1);
1139 AssertPtrReturnVoid(px2);
1140 AssertPtrReturnVoid(py2);
1141 LogRelFlowFunc(("\n"));
1142
1143 if (!mpDrv)
1144 return;
1145 /* If VBVA is not in use then this flag will not be set and this
1146 * will still work as it should. */
1147 if (!maFramebuffers[0].fDisabled)
1148 {
1149 x1 = (int32_t)maFramebuffers[0].xOrigin;
1150 y1 = (int32_t)maFramebuffers[0].yOrigin;
1151 x2 = mpDrv->IConnector.cx + (int32_t)maFramebuffers[0].xOrigin;
1152 y2 = mpDrv->IConnector.cy + (int32_t)maFramebuffers[0].yOrigin;
1153 }
1154 for (unsigned i = 1; i < mcMonitors; ++i)
1155 {
1156 if (!maFramebuffers[i].fDisabled)
1157 {
1158 x1 = RT_MIN(x1, maFramebuffers[i].xOrigin);
1159 y1 = RT_MIN(y1, maFramebuffers[i].yOrigin);
1160 x2 = RT_MAX(x2, maFramebuffers[i].xOrigin
1161 + (int32_t)maFramebuffers[i].w);
1162 y2 = RT_MAX(y2, maFramebuffers[i].yOrigin
1163 + (int32_t)maFramebuffers[i].h);
1164 }
1165 }
1166 *px1 = x1;
1167 *py1 = y1;
1168 *px2 = x2;
1169 *py2 = y2;
1170}
1171
1172static bool displayIntersectRect(RTRECT *prectResult,
1173 const RTRECT *prect1,
1174 const RTRECT *prect2)
1175{
1176 /* Initialize result to an empty record. */
1177 memset(prectResult, 0, sizeof(RTRECT));
1178
1179 int xLeftResult = RT_MAX(prect1->xLeft, prect2->xLeft);
1180 int xRightResult = RT_MIN(prect1->xRight, prect2->xRight);
1181
1182 if (xLeftResult < xRightResult)
1183 {
1184 /* There is intersection by X. */
1185
1186 int yTopResult = RT_MAX(prect1->yTop, prect2->yTop);
1187 int yBottomResult = RT_MIN(prect1->yBottom, prect2->yBottom);
1188
1189 if (yTopResult < yBottomResult)
1190 {
1191 /* There is intersection by Y. */
1192
1193 prectResult->xLeft = xLeftResult;
1194 prectResult->yTop = yTopResult;
1195 prectResult->xRight = xRightResult;
1196 prectResult->yBottom = yBottomResult;
1197
1198 return true;
1199 }
1200 }
1201
1202 return false;
1203}
1204
1205int Display::i_handleSetVisibleRegion(uint32_t cRect, PRTRECT pRect)
1206{
1207 RTRECT *pVisibleRegion = (RTRECT *)RTMemTmpAlloc( RT_MAX(cRect, 1)
1208 * sizeof(RTRECT));
1209 if (!pVisibleRegion)
1210 {
1211 return VERR_NO_TMP_MEMORY;
1212 }
1213
1214 unsigned uScreenId;
1215 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
1216 {
1217 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1218
1219 if (!pFBInfo->pFramebuffer.isNull())
1220 {
1221 /* Prepare a new array of rectangles which intersect with the framebuffer.
1222 */
1223 RTRECT rectFramebuffer;
1224 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
1225 {
1226 rectFramebuffer.xLeft = 0;
1227 rectFramebuffer.yTop = 0;
1228 if (mpDrv)
1229 {
1230 rectFramebuffer.xRight = mpDrv->IConnector.cx;
1231 rectFramebuffer.yBottom = mpDrv->IConnector.cy;
1232 }
1233 else
1234 {
1235 rectFramebuffer.xRight = 0;
1236 rectFramebuffer.yBottom = 0;
1237 }
1238 }
1239 else
1240 {
1241 rectFramebuffer.xLeft = pFBInfo->xOrigin;
1242 rectFramebuffer.yTop = pFBInfo->yOrigin;
1243 rectFramebuffer.xRight = pFBInfo->xOrigin + pFBInfo->w;
1244 rectFramebuffer.yBottom = pFBInfo->yOrigin + pFBInfo->h;
1245 }
1246
1247 uint32_t cRectVisibleRegion = 0;
1248
1249 uint32_t i;
1250 for (i = 0; i < cRect; i++)
1251 {
1252 if (displayIntersectRect(&pVisibleRegion[cRectVisibleRegion], &pRect[i], &rectFramebuffer))
1253 {
1254 pVisibleRegion[cRectVisibleRegion].xLeft -= pFBInfo->xOrigin;
1255 pVisibleRegion[cRectVisibleRegion].yTop -= pFBInfo->yOrigin;
1256 pVisibleRegion[cRectVisibleRegion].xRight -= pFBInfo->xOrigin;
1257 pVisibleRegion[cRectVisibleRegion].yBottom -= pFBInfo->yOrigin;
1258
1259 cRectVisibleRegion++;
1260 }
1261 }
1262 pFBInfo->pFramebuffer->SetVisibleRegion((BYTE *)pVisibleRegion, cRectVisibleRegion);
1263 }
1264 }
1265
1266#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
1267 BOOL is3denabled = FALSE;
1268
1269 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
1270
1271 VMMDev *vmmDev = mParent->i_getVMMDev();
1272 if (is3denabled && vmmDev)
1273 {
1274 if (mhCrOglSvc)
1275 {
1276 VBOXCRCMDCTL_HGCM *pCtl = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(RT_MAX(cRect, 1) * sizeof(RTRECT)
1277 + sizeof(VBOXCRCMDCTL_HGCM));
1278 if (pCtl)
1279 {
1280 RTRECT *pRectsCopy = (RTRECT*)(pCtl+1);
1281 memcpy(pRectsCopy, pRect, cRect * sizeof(RTRECT));
1282
1283 pCtl->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
1284 pCtl->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
1285
1286 pCtl->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
1287 pCtl->aParms[0].u.pointer.addr = pRectsCopy;
1288 pCtl->aParms[0].u.pointer.size = cRect * sizeof(RTRECT);
1289
1290 int rc = i_crCtlSubmit(&pCtl->Hdr, sizeof(*pCtl), i_displayCrCmdFree, pCtl);
1291 if (!RT_SUCCESS(rc))
1292 {
1293 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
1294 RTMemFree(pCtl);
1295 }
1296 }
1297 else
1298 AssertMsgFailed(("failed to allocate rects memory\n"));
1299 }
1300 else
1301 AssertMsgFailed(("mhCrOglSvc is NULL\n"));
1302 }
1303#endif
1304
1305 RTMemTmpFree(pVisibleRegion);
1306
1307 return VINF_SUCCESS;
1308}
1309
1310int Display::i_handleQueryVisibleRegion(uint32_t *pcRect, PRTRECT pRect)
1311{
1312 // @todo Currently not used by the guest and is not implemented in framebuffers. Remove?
1313 return VERR_NOT_SUPPORTED;
1314}
1315
1316typedef struct _VBVADIRTYREGION
1317{
1318 /* Copies of object's pointers used by vbvaRgn functions. */
1319 DISPLAYFBINFO *paFramebuffers;
1320 unsigned cMonitors;
1321 Display *pDisplay;
1322 PPDMIDISPLAYPORT pPort;
1323
1324} VBVADIRTYREGION;
1325
1326static void vbvaRgnInit(VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors,
1327 Display *pd, PPDMIDISPLAYPORT pp)
1328{
1329 prgn->paFramebuffers = paFramebuffers;
1330 prgn->cMonitors = cMonitors;
1331 prgn->pDisplay = pd;
1332 prgn->pPort = pp;
1333
1334 unsigned uScreenId;
1335 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
1336 {
1337 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
1338
1339 RT_ZERO(pFBInfo->dirtyRect);
1340 }
1341}
1342
1343static void vbvaRgnDirtyRect(VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)
1344{
1345 LogSunlover(("x = %d, y = %d, w = %d, h = %d\n",
1346 phdr->x, phdr->y, phdr->w, phdr->h));
1347
1348 /*
1349 * Here update rectangles are accumulated to form an update area.
1350 * @todo
1351 * Now the simplest method is used which builds one rectangle that
1352 * includes all update areas. A bit more advanced method can be
1353 * employed here. The method should be fast however.
1354 */
1355 if (phdr->w == 0 || phdr->h == 0)
1356 {
1357 /* Empty rectangle. */
1358 return;
1359 }
1360
1361 int32_t xRight = phdr->x + phdr->w;
1362 int32_t yBottom = phdr->y + phdr->h;
1363
1364 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
1365
1366 if (pFBInfo->dirtyRect.xRight == 0)
1367 {
1368 /* This is the first rectangle to be added. */
1369 pFBInfo->dirtyRect.xLeft = phdr->x;
1370 pFBInfo->dirtyRect.yTop = phdr->y;
1371 pFBInfo->dirtyRect.xRight = xRight;
1372 pFBInfo->dirtyRect.yBottom = yBottom;
1373 }
1374 else
1375 {
1376 /* Adjust region coordinates. */
1377 if (pFBInfo->dirtyRect.xLeft > phdr->x)
1378 {
1379 pFBInfo->dirtyRect.xLeft = phdr->x;
1380 }
1381
1382 if (pFBInfo->dirtyRect.yTop > phdr->y)
1383 {
1384 pFBInfo->dirtyRect.yTop = phdr->y;
1385 }
1386
1387 if (pFBInfo->dirtyRect.xRight < xRight)
1388 {
1389 pFBInfo->dirtyRect.xRight = xRight;
1390 }
1391
1392 if (pFBInfo->dirtyRect.yBottom < yBottom)
1393 {
1394 pFBInfo->dirtyRect.yBottom = yBottom;
1395 }
1396 }
1397
1398 if (pFBInfo->fDefaultFormat)
1399 {
1400 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
1401 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
1402 prgn->pDisplay->i_handleDisplayUpdateLegacy(phdr->x + pFBInfo->xOrigin,
1403 phdr->y + pFBInfo->yOrigin, phdr->w, phdr->h);
1404 }
1405
1406 return;
1407}
1408
1409static void vbvaRgnUpdateFramebuffer(VBVADIRTYREGION *prgn, unsigned uScreenId)
1410{
1411 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
1412
1413 uint32_t w = pFBInfo->dirtyRect.xRight - pFBInfo->dirtyRect.xLeft;
1414 uint32_t h = pFBInfo->dirtyRect.yBottom - pFBInfo->dirtyRect.yTop;
1415
1416 if (!pFBInfo->fDefaultFormat && w != 0 && h != 0)
1417 {
1418 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
1419 prgn->pPort->pfnUpdateDisplayRect(prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);
1420 prgn->pDisplay->i_handleDisplayUpdateLegacy(pFBInfo->dirtyRect.xLeft + pFBInfo->xOrigin,
1421 pFBInfo->dirtyRect.yTop + pFBInfo->yOrigin, w, h);
1422 }
1423}
1424
1425static void i_vbvaSetMemoryFlags(VBVAMEMORY *pVbvaMemory,
1426 bool fVideoAccelEnabled,
1427 bool fVideoAccelVRDP,
1428 uint32_t fu32SupportedOrders,
1429 DISPLAYFBINFO *paFBInfos,
1430 unsigned cFBInfos)
1431{
1432 if (pVbvaMemory)
1433 {
1434 /* This called only on changes in mode. So reset VRDP always. */
1435 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
1436
1437 if (fVideoAccelEnabled)
1438 {
1439 fu32Flags |= VBVA_F_MODE_ENABLED;
1440
1441 if (fVideoAccelVRDP)
1442 {
1443 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
1444
1445 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
1446 }
1447 }
1448
1449 pVbvaMemory->fu32ModeFlags = fu32Flags;
1450 }
1451
1452 unsigned uScreenId;
1453 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
1454 {
1455 if (paFBInfos[uScreenId].pHostEvents)
1456 {
1457 paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
1458 }
1459 }
1460}
1461
1462#ifdef VBOX_WITH_HGSMI
1463static void vbvaSetMemoryFlagsHGSMI(unsigned uScreenId,
1464 uint32_t fu32SupportedOrders,
1465 bool fVideoAccelVRDP,
1466 DISPLAYFBINFO *pFBInfo)
1467{
1468 LogRelFlowFunc(("HGSMI[%d]: %p\n", uScreenId, pFBInfo->pVBVAHostFlags));
1469
1470 if (pFBInfo->pVBVAHostFlags)
1471 {
1472 uint32_t fu32HostEvents = VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
1473
1474 if (pFBInfo->fVBVAEnabled)
1475 {
1476 fu32HostEvents |= VBVA_F_MODE_ENABLED;
1477
1478 if (fVideoAccelVRDP)
1479 {
1480 fu32HostEvents |= VBVA_F_MODE_VRDP;
1481 }
1482 }
1483
1484 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32HostEvents, fu32HostEvents);
1485 ASMAtomicWriteU32(&pFBInfo->pVBVAHostFlags->u32SupportedOrders, fu32SupportedOrders);
1486
1487 LogRelFlowFunc((" fu32HostEvents = 0x%08X, fu32SupportedOrders = 0x%08X\n", fu32HostEvents, fu32SupportedOrders));
1488 }
1489}
1490
1491static void vbvaSetMemoryFlagsAllHGSMI(uint32_t fu32SupportedOrders,
1492 bool fVideoAccelVRDP,
1493 DISPLAYFBINFO *paFBInfos,
1494 unsigned cFBInfos)
1495{
1496 unsigned uScreenId;
1497
1498 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
1499 {
1500 vbvaSetMemoryFlagsHGSMI(uScreenId, fu32SupportedOrders, fVideoAccelVRDP, &paFBInfos[uScreenId]);
1501 }
1502}
1503#endif /* VBOX_WITH_HGSMI */
1504
1505bool Display::i_VideoAccelAllowed(void)
1506{
1507 return true;
1508}
1509
1510int Display::i_vbvaLock(void)
1511{
1512 return RTCritSectEnter(&mVBVALock);
1513}
1514
1515void Display::i_vbvaUnlock(void)
1516{
1517 RTCritSectLeave(&mVBVALock);
1518}
1519
1520bool Display::i_vbvaLockIsOwner(void)
1521{
1522 return RTCritSectIsOwner(&mVBVALock);
1523}
1524
1525/**
1526 * @thread EMT
1527 */
1528int Display::i_VideoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory)
1529{
1530 int rc;
1531 if (fEnable)
1532 {
1533 /* Process any pending VGA device changes, resize. */
1534 Assert(!i_vbvaLockIsOwner());
1535 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);
1536 }
1537
1538 i_vbvaLock();
1539 rc = i_videoAccelEnable(fEnable, pVbvaMemory);
1540 i_vbvaUnlock();
1541
1542 if (!fEnable)
1543 {
1544 Assert(!i_vbvaLockIsOwner());
1545 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);
1546 }
1547
1548 return rc;
1549}
1550
1551int Display::i_videoAccelEnable(bool fEnable, VBVAMEMORY *pVbvaMemory)
1552{
1553 Assert(i_vbvaLockIsOwner());
1554
1555 int rc = VINF_SUCCESS;
1556 /* Called each time the guest wants to use acceleration,
1557 * or when the VGA device disables acceleration,
1558 * or when restoring the saved state with accel enabled.
1559 *
1560 * VGA device disables acceleration on each video mode change
1561 * and on reset.
1562 *
1563 * Guest enabled acceleration at will. And it has to enable
1564 * acceleration after a mode change.
1565 */
1566 LogRelFlowFunc(("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
1567 mfVideoAccelEnabled, fEnable, pVbvaMemory));
1568
1569 /* Strictly check parameters. Callers must not pass anything in the case. */
1570 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
1571
1572 if (!i_VideoAccelAllowed ())
1573 return VERR_NOT_SUPPORTED;
1574
1575 /*
1576 * Verify that the VM is in running state. If it is not,
1577 * then this must be postponed until it goes to running.
1578 */
1579 if (!mfMachineRunning)
1580 {
1581 Assert (!mfVideoAccelEnabled);
1582
1583 LogRelFlowFunc(("Machine is not yet running.\n"));
1584
1585 if (fEnable)
1586 {
1587 mfPendingVideoAccelEnable = fEnable;
1588 mpPendingVbvaMemory = pVbvaMemory;
1589 }
1590
1591 return rc;
1592 }
1593
1594 /* Check that current status is not being changed */
1595 if (mfVideoAccelEnabled == fEnable)
1596 return rc;
1597
1598 if (mfVideoAccelEnabled)
1599 {
1600 /* Process any pending orders and empty the VBVA ring buffer. */
1601 i_videoAccelFlush ();
1602 }
1603
1604 if (!fEnable && mpVbvaMemory)
1605 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
1606
1607 /* Safety precaution. There is no more VBVA until everything is setup! */
1608 mpVbvaMemory = NULL;
1609 mfVideoAccelEnabled = false;
1610
1611 /* Everything OK. VBVA status can be changed. */
1612
1613 /* Notify the VMMDev, which saves VBVA status in the saved state,
1614 * and needs to know current status.
1615 */
1616 VMMDev *pVMMDev = mParent->i_getVMMDev();
1617 if (pVMMDev)
1618 {
1619 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
1620 if (pVMMDevPort)
1621 pVMMDevPort->pfnVBVAChange(pVMMDevPort, fEnable);
1622 }
1623
1624 if (fEnable)
1625 {
1626 mpVbvaMemory = pVbvaMemory;
1627 mfVideoAccelEnabled = true;
1628
1629 /* Initialize the hardware memory. */
1630 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP,
1631 mfu32SupportedOrders, maFramebuffers, mcMonitors);
1632 mpVbvaMemory->off32Data = 0;
1633 mpVbvaMemory->off32Free = 0;
1634
1635 memset(mpVbvaMemory->aRecords, 0, sizeof(mpVbvaMemory->aRecords));
1636 mpVbvaMemory->indexRecordFirst = 0;
1637 mpVbvaMemory->indexRecordFree = 0;
1638
1639 mfu32PendingVideoAccelDisable = false;
1640
1641 LogRel(("VBVA: Enabled.\n"));
1642 }
1643 else
1644 {
1645 LogRel(("VBVA: Disabled.\n"));
1646 }
1647
1648 LogRelFlowFunc(("VideoAccelEnable: rc = %Rrc.\n", rc));
1649
1650 return rc;
1651}
1652
1653/* Called always by one VRDP server thread. Can be thread-unsafe.
1654 */
1655void Display::i_VideoAccelVRDP(bool fEnable)
1656{
1657 LogRelFlowFunc(("fEnable = %d\n", fEnable));
1658
1659 i_vbvaLock();
1660
1661 int c = fEnable?
1662 ASMAtomicIncS32(&mcVideoAccelVRDPRefs):
1663 ASMAtomicDecS32(&mcVideoAccelVRDPRefs);
1664
1665 Assert (c >= 0);
1666
1667 if (c == 0)
1668 {
1669 /* The last client has disconnected, and the accel can be
1670 * disabled.
1671 */
1672 Assert (fEnable == false);
1673
1674 mfVideoAccelVRDP = false;
1675 mfu32SupportedOrders = 0;
1676
1677 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1678 maFramebuffers, mcMonitors);
1679#ifdef VBOX_WITH_HGSMI
1680 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1681 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1682#endif /* VBOX_WITH_HGSMI */
1683
1684 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
1685 }
1686 else if ( c == 1
1687 && !mfVideoAccelVRDP)
1688 {
1689 /* The first client has connected. Enable the accel.
1690 */
1691 Assert (fEnable == true);
1692
1693 mfVideoAccelVRDP = true;
1694 /* Supporting all orders. */
1695 mfu32SupportedOrders = ~0;
1696
1697 i_vbvaSetMemoryFlags(mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders,
1698 maFramebuffers, mcMonitors);
1699#ifdef VBOX_WITH_HGSMI
1700 /* Here is VRDP-IN thread. Process the request in vbvaUpdateBegin under DevVGA lock on an EMT. */
1701 ASMAtomicIncU32(&mu32UpdateVBVAFlags);
1702#endif /* VBOX_WITH_HGSMI */
1703
1704 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
1705 }
1706 else
1707 {
1708 /* A client is connected or disconnected but there is no change in the
1709 * accel state. It remains enabled.
1710 */
1711 Assert(mfVideoAccelVRDP == true);
1712 }
1713 i_vbvaUnlock();
1714}
1715
1716static bool i_vbvaVerifyRingBuffer(VBVAMEMORY *pVbvaMemory)
1717{
1718 return true;
1719}
1720
1721static void i_vbvaFetchBytes(VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
1722{
1723 if (cbDst >= VBVA_RING_BUFFER_SIZE)
1724 {
1725 AssertMsgFailed(("cbDst = 0x%08X, ring buffer size 0x%08X\n", cbDst, VBVA_RING_BUFFER_SIZE));
1726 return;
1727 }
1728
1729 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
1730 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
1731 int32_t i32Diff = cbDst - u32BytesTillBoundary;
1732
1733 if (i32Diff <= 0)
1734 {
1735 /* Chunk will not cross buffer boundary. */
1736 memcpy (pu8Dst, src, cbDst);
1737 }
1738 else
1739 {
1740 /* Chunk crosses buffer boundary. */
1741 memcpy(pu8Dst, src, u32BytesTillBoundary);
1742 memcpy(pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
1743 }
1744
1745 /* Advance data offset. */
1746 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
1747
1748 return;
1749}
1750
1751
1752static bool i_vbvaPartialRead(uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
1753{
1754 uint8_t *pu8New;
1755
1756 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
1757 *ppu8, *pcb, cbRecord));
1758
1759 if (*ppu8)
1760 {
1761 Assert (*pcb);
1762 pu8New = (uint8_t *)RTMemRealloc(*ppu8, cbRecord);
1763 }
1764 else
1765 {
1766 Assert (!*pcb);
1767 pu8New = (uint8_t *)RTMemAlloc(cbRecord);
1768 }
1769
1770 if (!pu8New)
1771 {
1772 /* Memory allocation failed, fail the function. */
1773 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
1774 cbRecord));
1775
1776 if (*ppu8)
1777 {
1778 RTMemFree(*ppu8);
1779 }
1780
1781 *ppu8 = NULL;
1782 *pcb = 0;
1783
1784 return false;
1785 }
1786
1787 /* Fetch data from the ring buffer. */
1788 i_vbvaFetchBytes(pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
1789
1790 *ppu8 = pu8New;
1791 *pcb = cbRecord;
1792
1793 return true;
1794}
1795
1796/* For contiguous chunks just return the address in the buffer.
1797 * For crossing boundary - allocate a buffer from heap.
1798 */
1799bool Display::i_vbvaFetchCmd(VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
1800{
1801 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst;
1802 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree;
1803
1804#ifdef DEBUG_sunlover
1805 LogFlowFunc(("first = %d, free = %d\n",
1806 indexRecordFirst, indexRecordFree));
1807#endif /* DEBUG_sunlover */
1808
1809 if (!i_vbvaVerifyRingBuffer(mpVbvaMemory))
1810 {
1811 return false;
1812 }
1813
1814 if (indexRecordFirst == indexRecordFree)
1815 {
1816 /* No records to process. Return without assigning output variables. */
1817 return true;
1818 }
1819
1820 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];
1821
1822#ifdef DEBUG_sunlover
1823 LogFlowFunc(("cbRecord = 0x%08X\n", pRecord->cbRecord));
1824#endif /* DEBUG_sunlover */
1825
1826 uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL;
1827
1828 if (mcbVbvaPartial)
1829 {
1830 /* There is a partial read in process. Continue with it. */
1831
1832 Assert(mpu8VbvaPartial);
1833
1834 LogFlowFunc(("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
1835 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
1836
1837 if (cbRecord > mcbVbvaPartial)
1838 {
1839 /* New data has been added to the record. */
1840 if (!i_vbvaPartialRead(&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
1841 {
1842 return false;
1843 }
1844 }
1845
1846 if (!(pRecord->cbRecord & VBVA_F_RECORD_PARTIAL))
1847 {
1848 /* The record is completed by guest. Return it to the caller. */
1849 *ppHdr = (VBVACMDHDR *)mpu8VbvaPartial;
1850 *pcbCmd = mcbVbvaPartial;
1851
1852 mpu8VbvaPartial = NULL;
1853 mcbVbvaPartial = 0;
1854
1855 /* Advance the record index. */
1856 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
1857
1858#ifdef DEBUG_sunlover
1859 LogFlowFunc(("partial done ok, data = %d, free = %d\n",
1860 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1861#endif /* DEBUG_sunlover */
1862 }
1863
1864 return true;
1865 }
1866
1867 /* A new record need to be processed. */
1868 if (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)
1869 {
1870 /* Current record is being written by guest. '=' is important here. */
1871 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
1872 {
1873 /* Partial read must be started. */
1874 if (!i_vbvaPartialRead(&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
1875 {
1876 return false;
1877 }
1878
1879 LogFlowFunc(("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
1880 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
1881 }
1882
1883 return true;
1884 }
1885
1886 /* Current record is complete. If it is not empty, process it. */
1887 if (cbRecord)
1888 {
1889 /* The size of largest contiguous chunk in the ring biffer. */
1890 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;
1891
1892 /* The ring buffer pointer. */
1893 uint8_t *au8RingBuffer = &mpVbvaMemory->au8RingBuffer[0];
1894
1895 /* The pointer to data in the ring buffer. */
1896 uint8_t *src = &au8RingBuffer[mpVbvaMemory->off32Data];
1897
1898 /* Fetch or point the data. */
1899 if (u32BytesTillBoundary >= cbRecord)
1900 {
1901 /* The command does not cross buffer boundary. Return address in the buffer. */
1902 *ppHdr = (VBVACMDHDR *)src;
1903
1904 /* Advance data offset. */
1905 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
1906 }
1907 else
1908 {
1909 /* The command crosses buffer boundary. Rare case, so not optimized. */
1910 uint8_t *dst = (uint8_t *)RTMemAlloc(cbRecord);
1911
1912 if (!dst)
1913 {
1914 LogRelFlowFunc(("could not allocate %d bytes from heap!!!\n", cbRecord));
1915 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
1916 return false;
1917 }
1918
1919 i_vbvaFetchBytes(mpVbvaMemory, dst, cbRecord);
1920
1921 *ppHdr = (VBVACMDHDR *)dst;
1922
1923#ifdef DEBUG_sunlover
1924 LogFlowFunc(("Allocated from heap %p\n", dst));
1925#endif /* DEBUG_sunlover */
1926 }
1927 }
1928
1929 *pcbCmd = cbRecord;
1930
1931 /* Advance the record index. */
1932 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
1933
1934#ifdef DEBUG_sunlover
1935 LogFlowFunc(("done ok, data = %d, free = %d\n",
1936 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1937#endif /* DEBUG_sunlover */
1938
1939 return true;
1940}
1941
1942void Display::i_vbvaReleaseCmd(VBVACMDHDR *pHdr, int32_t cbCmd)
1943{
1944 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;
1945
1946 if ( (uint8_t *)pHdr >= au8RingBuffer
1947 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
1948 {
1949 /* The pointer is inside ring buffer. Must be continuous chunk. */
1950 Assert(VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
1951
1952 /* Do nothing. */
1953
1954 Assert(!mpu8VbvaPartial && mcbVbvaPartial == 0);
1955 }
1956 else
1957 {
1958 /* The pointer is outside. It is then an allocated copy. */
1959
1960#ifdef DEBUG_sunlover
1961 LogFlowFunc(("Free heap %p\n", pHdr));
1962#endif /* DEBUG_sunlover */
1963
1964 if ((uint8_t *)pHdr == mpu8VbvaPartial)
1965 {
1966 mpu8VbvaPartial = NULL;
1967 mcbVbvaPartial = 0;
1968 }
1969 else
1970 {
1971 Assert(!mpu8VbvaPartial && mcbVbvaPartial == 0);
1972 }
1973
1974 RTMemFree(pHdr);
1975 }
1976
1977 return;
1978}
1979
1980
1981/**
1982 * Called regularly on the DisplayRefresh timer.
1983 * Also on behalf of guest, when the ring buffer is full.
1984 *
1985 * @thread EMT
1986 */
1987void Display::i_VideoAccelFlush(void)
1988{
1989 i_vbvaLock();
1990 int rc = i_videoAccelFlush();
1991 if (RT_FAILURE(rc))
1992 {
1993 /* Disable on errors. */
1994 i_videoAccelEnable(false, NULL);
1995 }
1996 i_vbvaUnlock();
1997
1998 if (RT_FAILURE(rc))
1999 {
2000 /* VideoAccel was disabled because of a failure, switching back to VGA updates. Redraw the screen. */
2001 Assert(!i_vbvaLockIsOwner());
2002 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort, /* fFailOnResize = */ false);
2003 }
2004}
2005
2006int Display::i_videoAccelFlush(void)
2007{
2008 Assert(i_vbvaLockIsOwner());
2009
2010#ifdef DEBUG_sunlover_2
2011 LogFlowFunc(("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));
2012#endif /* DEBUG_sunlover_2 */
2013
2014 if (!mfVideoAccelEnabled)
2015 {
2016 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
2017 return VINF_SUCCESS;
2018 }
2019
2020 /* Here VBVA is enabled and we have the accelerator memory pointer. */
2021 Assert(mpVbvaMemory);
2022
2023#ifdef DEBUG_sunlover_2
2024 LogFlowFunc(("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
2025 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree,
2026 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
2027#endif /* DEBUG_sunlover_2 */
2028
2029 /* Quick check for "nothing to update" case. */
2030 if (mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)
2031 {
2032 return VINF_SUCCESS;
2033 }
2034
2035 /* Process the ring buffer */
2036 unsigned uScreenId;
2037
2038 /* Initialize dirty rectangles accumulator. */
2039 VBVADIRTYREGION rgn;
2040 vbvaRgnInit(&rgn, maFramebuffers, mcMonitors, this, mpDrv->pUpPort);
2041
2042 for (;;)
2043 {
2044 VBVACMDHDR *phdr = NULL;
2045 uint32_t cbCmd = ~0;
2046
2047 /* Fetch the command data. */
2048 if (!i_vbvaFetchCmd(&phdr, &cbCmd))
2049 {
2050 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
2051 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
2052 return VERR_INVALID_STATE;
2053 }
2054
2055 if (cbCmd == uint32_t(~0))
2056 {
2057 /* No more commands yet in the queue. */
2058 break;
2059 }
2060
2061 if (cbCmd != 0)
2062 {
2063#ifdef DEBUG_sunlover
2064 LogFlowFunc(("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
2065 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
2066#endif /* DEBUG_sunlover */
2067
2068 VBVACMDHDR hdrSaved = *phdr;
2069
2070 int x = phdr->x;
2071 int y = phdr->y;
2072 int w = phdr->w;
2073 int h = phdr->h;
2074
2075 uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
2076
2077 phdr->x = (int16_t)x;
2078 phdr->y = (int16_t)y;
2079 phdr->w = (uint16_t)w;
2080 phdr->h = (uint16_t)h;
2081
2082 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
2083
2084 /* Handle the command.
2085 *
2086 * Guest is responsible for updating the guest video memory.
2087 * The Windows guest does all drawing using Eng*.
2088 *
2089 * For local output, only dirty rectangle information is used
2090 * to update changed areas.
2091 *
2092 * Dirty rectangles are accumulated to exclude overlapping updates and
2093 * group small updates to a larger one.
2094 */
2095
2096 /* Accumulate the update. */
2097 vbvaRgnDirtyRect(&rgn, uScreenId, phdr);
2098
2099 /* Forward the command to VRDP server. */
2100 mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, phdr, cbCmd);
2101
2102 *phdr = hdrSaved;
2103 }
2104
2105 i_vbvaReleaseCmd(phdr, cbCmd);
2106 }
2107
2108 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
2109 {
2110 /* Draw the framebuffer. */
2111 vbvaRgnUpdateFramebuffer(&rgn, uScreenId);
2112 }
2113 return VINF_SUCCESS;
2114}
2115
2116int Display::i_videoAccelRefreshProcess(void)
2117{
2118 int rc = VWRN_INVALID_STATE; /* Default is to do a display update in VGA device. */
2119
2120 i_vbvaLock();
2121
2122 if (ASMAtomicCmpXchgU32(&mfu32PendingVideoAccelDisable, false, true))
2123 {
2124 i_videoAccelEnable(false, NULL);
2125 }
2126 else if (mfPendingVideoAccelEnable)
2127 {
2128 /* Acceleration was enabled while machine was not yet running
2129 * due to restoring from saved state. Actually enable acceleration.
2130 */
2131 Assert(mpPendingVbvaMemory);
2132
2133 /* Acceleration can not be yet enabled.*/
2134 Assert(mpVbvaMemory == NULL);
2135 Assert(!mfVideoAccelEnabled);
2136
2137 if (mfMachineRunning)
2138 {
2139 i_videoAccelEnable(mfPendingVideoAccelEnable,
2140 mpPendingVbvaMemory);
2141
2142 /* Reset the pending state. */
2143 mfPendingVideoAccelEnable = false;
2144 mpPendingVbvaMemory = NULL;
2145 }
2146
2147 rc = VINF_TRY_AGAIN;
2148 }
2149 else
2150 {
2151 Assert(mpPendingVbvaMemory == NULL);
2152
2153 if (mfVideoAccelEnabled)
2154 {
2155 Assert(mpVbvaMemory);
2156 rc = i_videoAccelFlush();
2157 if (RT_FAILURE(rc))
2158 {
2159 /* Disable on errors. */
2160 i_videoAccelEnable(false, NULL);
2161 rc = VWRN_INVALID_STATE; /* Do a display update in VGA device. */
2162 }
2163 else
2164 {
2165 rc = VINF_SUCCESS;
2166 }
2167 }
2168 }
2169
2170 i_vbvaUnlock();
2171
2172 return rc;
2173}
2174
2175void Display::i_notifyPowerDown(void)
2176{
2177 LogRelFlowFunc(("\n"));
2178
2179 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2180
2181 /* Source bitmaps are not available anymore. */
2182 mfSourceBitmapEnabled = false;
2183
2184 /* Resize all displays to tell framebuffers to forget current source bitmap. */
2185 unsigned uScreenId = mcMonitors;
2186 while (uScreenId > 0)
2187 {
2188 --uScreenId;
2189
2190 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
2191 if (!pFBInfo->fDisabled)
2192 {
2193 i_handleDisplayResize(uScreenId, 32,
2194 pFBInfo->pu8FramebufferVRAM,
2195 pFBInfo->u32LineSize,
2196 pFBInfo->w,
2197 pFBInfo->h,
2198 pFBInfo->flags);
2199 }
2200 }
2201}
2202
2203// Wrapped IDisplay methods
2204/////////////////////////////////////////////////////////////////////////////
2205HRESULT Display::getScreenResolution(ULONG aScreenId, ULONG *aWidth, ULONG *aHeight, ULONG *aBitsPerPixel,
2206 LONG *aXOrigin, LONG *aYOrigin)
2207{
2208 LogRelFlowFunc(("aScreenId=%RU32\n", aScreenId));
2209
2210 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2211
2212 uint32_t u32Width = 0;
2213 uint32_t u32Height = 0;
2214 uint32_t u32BitsPerPixel = 0;
2215 int32_t xOrigin = 0;
2216 int32_t yOrigin = 0;
2217
2218 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2219 {
2220 if (mpDrv)
2221 {
2222 u32Width = mpDrv->IConnector.cx;
2223 u32Height = mpDrv->IConnector.cy;
2224
2225 alock.release();
2226
2227 Assert(!i_vbvaLockIsOwner());
2228 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &u32BitsPerPixel);
2229 AssertRC(rc);
2230
2231 alock.acquire();
2232 }
2233 }
2234 else if (aScreenId < mcMonitors)
2235 {
2236 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2237 u32Width = pFBInfo->w;
2238 u32Height = pFBInfo->h;
2239 u32BitsPerPixel = pFBInfo->u16BitsPerPixel;
2240 xOrigin = pFBInfo->xOrigin;
2241 yOrigin = pFBInfo->yOrigin;
2242 }
2243 else
2244 {
2245 return E_INVALIDARG;
2246 }
2247
2248 if (aWidth)
2249 *aWidth = u32Width;
2250 if (aHeight)
2251 *aHeight = u32Height;
2252 if (aBitsPerPixel)
2253 *aBitsPerPixel = u32BitsPerPixel;
2254 if (aXOrigin)
2255 *aXOrigin = xOrigin;
2256 if (aYOrigin)
2257 *aYOrigin = yOrigin;
2258
2259 return S_OK;
2260}
2261
2262
2263HRESULT Display::attachFramebuffer(ULONG aScreenId, const ComPtr<IFramebuffer> &aFramebuffer)
2264{
2265 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2266
2267 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2268
2269 if (aScreenId >= mcMonitors)
2270 return setError(E_INVALIDARG, tr("AttachFramebuffer: Invalid screen %d (total %d)"),
2271 aScreenId, mcMonitors);
2272
2273 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2274 if (!pFBInfo->pFramebuffer.isNull())
2275 return setError(E_FAIL, tr("AttachFramebuffer: Framebuffer already attached to %d"),
2276 aScreenId);
2277
2278 pFBInfo->pFramebuffer = aFramebuffer;
2279
2280 alock.release();
2281
2282 /* The driver might not have been constructed yet */
2283 if (mpDrv)
2284 {
2285 /* Setup the new framebuffer. */
2286 i_handleDisplayResize(aScreenId, pFBInfo->u16BitsPerPixel,
2287 pFBInfo->pu8FramebufferVRAM,
2288 pFBInfo->u32LineSize,
2289 pFBInfo->w,
2290 pFBInfo->h,
2291 pFBInfo->flags);
2292 }
2293
2294 Console::SafeVMPtrQuiet ptrVM(mParent);
2295 if (ptrVM.isOk())
2296 {
2297#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2298 BOOL fIs3DEnabled = FALSE;
2299 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled);
2300
2301 if (fIs3DEnabled)
2302 {
2303 VBOXCRCMDCTL_HGCM data;
2304 RT_ZERO(data);
2305 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2306 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
2307
2308 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
2309 data.aParms[0].u.uint32 = aScreenId;
2310
2311 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
2312 AssertRC(vrc);
2313 }
2314#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
2315
2316 VMR3ReqCallNoWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
2317 3, this, aScreenId, false);
2318 }
2319
2320 LogRelFlowFunc(("Attached to %d\n", aScreenId));
2321 return S_OK;
2322}
2323
2324HRESULT Display::detachFramebuffer(ULONG aScreenId)
2325{
2326 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2327
2328 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2329
2330 if (aScreenId >= mcMonitors)
2331 return setError(E_INVALIDARG, tr("DetachFramebuffer: Invalid screen %d (total %d)"),
2332 aScreenId, mcMonitors);
2333
2334 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2335
2336 pFBInfo->pFramebuffer.setNull();
2337
2338 alock.release();
2339
2340#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2341 Console::SafeVMPtrQuiet ptrVM(mParent);
2342 if (ptrVM.isOk())
2343 {
2344 BOOL fIs3DEnabled = FALSE;
2345 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&fIs3DEnabled);
2346
2347 if (fIs3DEnabled)
2348 {
2349 VBOXCRCMDCTL_HGCM data;
2350 RT_ZERO(data);
2351 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2352 data.Hdr.u32Function = SHCRGL_HOST_FN_SCREEN_CHANGED;
2353
2354 data.aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
2355 data.aParms[0].u.uint32 = aScreenId;
2356
2357 int vrc = i_crCtlSubmitSync(&data.Hdr, sizeof(data));
2358 AssertRC(vrc);
2359 }
2360 }
2361#endif /* defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL) */
2362
2363 return S_OK;
2364}
2365
2366HRESULT Display::queryFramebuffer(ULONG aScreenId, ComPtr<IFramebuffer> &aFramebuffer)
2367{
2368 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
2369
2370 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2371
2372 if (aScreenId >= mcMonitors)
2373 return setError(E_INVALIDARG, tr("QueryFramebuffer: Invalid screen %d (total %d)"),
2374 aScreenId, mcMonitors);
2375
2376 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
2377
2378 pFBInfo->pFramebuffer.queryInterfaceTo(aFramebuffer.asOutParam());
2379
2380 return S_OK;
2381}
2382
2383HRESULT Display::setVideoModeHint(ULONG aDisplay, BOOL aEnabled,
2384 BOOL aChangeOrigin, LONG aOriginX, LONG aOriginY,
2385 ULONG aWidth, ULONG aHeight, ULONG aBitsPerPixel)
2386{
2387 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2388
2389 CHECK_CONSOLE_DRV(mpDrv);
2390
2391 /*
2392 * Do some rough checks for valid input.
2393 */
2394 ULONG width = aWidth;
2395 if (!width)
2396 width = mpDrv->IConnector.cx;
2397 ULONG height = aHeight;
2398 if (!height)
2399 height = mpDrv->IConnector.cy;
2400 ULONG bpp = aBitsPerPixel;
2401 if (!bpp)
2402 {
2403 alock.release();
2404
2405 uint32_t cBits = 0;
2406 Assert(!i_vbvaLockIsOwner());
2407 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
2408 AssertRC(rc);
2409 bpp = cBits;
2410
2411 alock.acquire();
2412 }
2413 ULONG cMonitors;
2414 mParent->i_machine()->COMGETTER(MonitorCount)(&cMonitors);
2415 if (cMonitors == 0 && aDisplay > 0)
2416 return E_INVALIDARG;
2417 if (aDisplay >= cMonitors)
2418 return E_INVALIDARG;
2419
2420 /*
2421 * sunlover 20070614: It is up to the guest to decide whether the hint is
2422 * valid. Therefore don't do any VRAM sanity checks here!
2423 */
2424
2425 /* Have to release the lock because the pfnRequestDisplayChange
2426 * will call EMT. */
2427 alock.release();
2428
2429 VMMDev *pVMMDev = mParent->i_getVMMDev();
2430 if (pVMMDev)
2431 {
2432 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
2433 if (pVMMDevPort)
2434 pVMMDevPort->pfnRequestDisplayChange(pVMMDevPort, aWidth, aHeight, aBitsPerPixel,
2435 aDisplay, aOriginX, aOriginY,
2436 RT_BOOL(aEnabled), RT_BOOL(aChangeOrigin));
2437 }
2438 return S_OK;
2439}
2440
2441HRESULT Display::setSeamlessMode(BOOL enabled)
2442{
2443 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2444
2445 /* Have to release the lock because the pfnRequestSeamlessChange will call EMT. */
2446 alock.release();
2447
2448 VMMDev *pVMMDev = mParent->i_getVMMDev();
2449 if (pVMMDev)
2450 {
2451 PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
2452 if (pVMMDevPort)
2453 pVMMDevPort->pfnRequestSeamlessChange(pVMMDevPort, !!enabled);
2454 }
2455
2456#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2457 if (!enabled)
2458 {
2459 BOOL is3denabled = FALSE;
2460
2461 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
2462
2463 VMMDev *vmmDev = mParent->i_getVMMDev();
2464 if (is3denabled && vmmDev)
2465 {
2466 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)RTMemAlloc(sizeof(VBOXCRCMDCTL_HGCM));
2467 if (!pData)
2468 {
2469 AssertMsgFailed(("RTMemAlloc failed\n"));
2470 return VERR_NO_MEMORY;
2471 }
2472
2473 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2474 pData->Hdr.u32Function = SHCRGL_HOST_FN_SET_VISIBLE_REGION;
2475
2476 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2477 pData->aParms[0].u.pointer.addr = NULL;
2478 pData->aParms[0].u.pointer.size = 0; /* <- means null rects, NULL pRects address and 0 rects means "disable" */
2479
2480 int rc = i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
2481 if (!RT_SUCCESS(rc))
2482 {
2483 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
2484 RTMemFree(pData);
2485 }
2486 }
2487 }
2488#endif
2489 return S_OK;
2490}
2491
2492#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2493BOOL Display::i_displayCheckTakeScreenshotCrOgl(Display *pDisplay, ULONG aScreenId, uint8_t *pu8Data,
2494 uint32_t u32Width, uint32_t u32Height)
2495{
2496 BOOL is3denabled;
2497 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
2498 if (is3denabled && pDisplay->mCrOglCallbacks.pfnHasData())
2499 {
2500 VMMDev *pVMMDev = pDisplay->mParent->i_getVMMDev();
2501 if (pVMMDev)
2502 {
2503 CRVBOXHGCMTAKESCREENSHOT *pScreenshot = (CRVBOXHGCMTAKESCREENSHOT*)RTMemAlloc(sizeof(*pScreenshot));
2504 if (pScreenshot)
2505 {
2506 /* screen id or CRSCREEN_ALL to specify all enabled */
2507 pScreenshot->u32Screen = aScreenId;
2508 pScreenshot->u32Width = u32Width;
2509 pScreenshot->u32Height = u32Height;
2510 pScreenshot->u32Pitch = u32Width * 4;
2511 pScreenshot->pvBuffer = pu8Data;
2512 pScreenshot->pvContext = NULL;
2513 pScreenshot->pfnScreenshotBegin = NULL;
2514 pScreenshot->pfnScreenshotPerform = NULL;
2515 pScreenshot->pfnScreenshotEnd = NULL;
2516
2517 VBOXCRCMDCTL_HGCM data;
2518 data.Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
2519 data.Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
2520
2521 data.aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2522 data.aParms[0].u.pointer.addr = pScreenshot;
2523 data.aParms[0].u.pointer.size = sizeof(*pScreenshot);
2524
2525 int rc = pDisplay->i_crCtlSubmitSync(&data.Hdr, sizeof(data));
2526
2527 RTMemFree(pScreenshot);
2528
2529 if (RT_SUCCESS(rc))
2530 return TRUE;
2531 else
2532 {
2533 AssertMsgFailed(("failed to get screenshot data from crOgl %d\n", rc));
2534 /* fall back to the non-3d mechanism */
2535 }
2536 }
2537 }
2538 }
2539 return FALSE;
2540}
2541#endif
2542
2543int Display::i_displayTakeScreenshotEMT(Display *pDisplay, ULONG aScreenId, uint8_t **ppu8Data, size_t *pcbData,
2544 uint32_t *pu32Width, uint32_t *pu32Height)
2545{
2546 int rc;
2547
2548 if ( aScreenId == VBOX_VIDEO_PRIMARY_SCREEN
2549 && pDisplay->maFramebuffers[aScreenId].fVBVAEnabled == false) /* A non-VBVA mode. */
2550 {
2551 Assert(!pDisplay->i_vbvaLockIsOwner());
2552 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort, ppu8Data, pcbData, pu32Width, pu32Height);
2553 }
2554 else if (aScreenId < pDisplay->mcMonitors)
2555 {
2556 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
2557
2558 uint32_t width = pFBInfo->w;
2559 uint32_t height = pFBInfo->h;
2560
2561 /* Allocate 32 bit per pixel bitmap. */
2562 size_t cbRequired = width * 4 * height;
2563
2564 if (cbRequired)
2565 {
2566 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbRequired);
2567
2568 if (pu8Data == NULL)
2569 {
2570 rc = VERR_NO_MEMORY;
2571 }
2572 else
2573 {
2574 /* Copy guest VRAM to the allocated 32bpp buffer. */
2575 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
2576 int32_t xSrc = 0;
2577 int32_t ySrc = 0;
2578 uint32_t u32SrcWidth = width;
2579 uint32_t u32SrcHeight = height;
2580 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
2581 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
2582
2583 uint8_t *pu8Dst = pu8Data;
2584 int32_t xDst = 0;
2585 int32_t yDst = 0;
2586 uint32_t u32DstWidth = u32SrcWidth;
2587 uint32_t u32DstHeight = u32SrcHeight;
2588 uint32_t u32DstLineSize = u32DstWidth * 4;
2589 uint32_t u32DstBitsPerPixel = 32;
2590
2591 Assert(!pDisplay->i_vbvaLockIsOwner());
2592 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
2593 width, height,
2594 pu8Src,
2595 xSrc, ySrc,
2596 u32SrcWidth, u32SrcHeight,
2597 u32SrcLineSize, u32SrcBitsPerPixel,
2598 pu8Dst,
2599 xDst, yDst,
2600 u32DstWidth, u32DstHeight,
2601 u32DstLineSize, u32DstBitsPerPixel);
2602 if (RT_SUCCESS(rc))
2603 {
2604 *ppu8Data = pu8Data;
2605 *pcbData = cbRequired;
2606 *pu32Width = width;
2607 *pu32Height = height;
2608 }
2609 else
2610 {
2611 RTMemFree(pu8Data);
2612
2613 /* CopyRect can fail if VBVA was paused in VGA device, retry using the generic method. */
2614 if ( rc == VERR_INVALID_STATE
2615 && aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2616 {
2617 Assert(!pDisplay->i_vbvaLockIsOwner());
2618 rc = pDisplay->mpDrv->pUpPort->pfnTakeScreenshot(pDisplay->mpDrv->pUpPort,
2619 ppu8Data, pcbData, pu32Width, pu32Height);
2620 }
2621 }
2622 }
2623 }
2624 else
2625 {
2626 /* No image. */
2627 *ppu8Data = NULL;
2628 *pcbData = 0;
2629 *pu32Width = 0;
2630 *pu32Height = 0;
2631 rc = VINF_SUCCESS;
2632 }
2633 }
2634 else
2635 {
2636 rc = VERR_INVALID_PARAMETER;
2637 }
2638
2639 return rc;
2640}
2641
2642static int i_displayTakeScreenshot(PUVM pUVM, Display *pDisplay, struct DRVMAINDISPLAY *pDrv, ULONG aScreenId,
2643 BYTE *address, ULONG width, ULONG height)
2644{
2645 uint8_t *pu8Data = NULL;
2646 size_t cbData = 0;
2647 uint32_t cx = 0;
2648 uint32_t cy = 0;
2649 int vrc = VINF_SUCCESS;
2650
2651# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
2652 if (Display::i_displayCheckTakeScreenshotCrOgl(pDisplay, aScreenId, (uint8_t*)address, width, height))
2653 return VINF_SUCCESS;
2654#endif
2655
2656 int cRetries = 5;
2657
2658 while (cRetries-- > 0)
2659 {
2660 /* Note! Not sure if the priority call is such a good idea here, but
2661 it would be nice to have an accurate screenshot for the bug
2662 report if the VM deadlocks. */
2663 vrc = VMR3ReqPriorityCallWaitU(pUVM, VMCPUID_ANY, (PFNRT)Display::i_displayTakeScreenshotEMT, 6,
2664 pDisplay, aScreenId, &pu8Data, &cbData, &cx, &cy);
2665 if (vrc != VERR_TRY_AGAIN)
2666 {
2667 break;
2668 }
2669
2670 RTThreadSleep(10);
2671 }
2672
2673 if (RT_SUCCESS(vrc) && pu8Data)
2674 {
2675 if (cx == width && cy == height)
2676 {
2677 /* No scaling required. */
2678 memcpy(address, pu8Data, cbData);
2679 }
2680 else
2681 {
2682 /* Scale. */
2683 LogRelFlowFunc(("SCALE: %dx%d -> %dx%d\n", cx, cy, width, height));
2684
2685 uint8_t *dst = address;
2686 uint8_t *src = pu8Data;
2687 int dstW = width;
2688 int dstH = height;
2689 int srcW = cx;
2690 int srcH = cy;
2691 int iDeltaLine = cx * 4;
2692
2693 BitmapScale32(dst,
2694 dstW, dstH,
2695 src,
2696 iDeltaLine,
2697 srcW, srcH);
2698 }
2699
2700 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2701 {
2702 /* This can be called from any thread. */
2703 Assert(!pDisplay->i_vbvaLockIsOwner());
2704 pDrv->pUpPort->pfnFreeScreenshot(pDrv->pUpPort, pu8Data);
2705 }
2706 else
2707 {
2708 RTMemFree(pu8Data);
2709 }
2710 }
2711
2712 return vrc;
2713}
2714
2715HRESULT Display::takeScreenShot(ULONG aScreenId, BYTE *aAddress, ULONG aWidth, ULONG aHeight)
2716{
2717 /// @todo (r=dmik) this function may take too long to complete if the VM
2718 // is doing something like saving state right now. Which, in case if it
2719 // is called on the GUI thread, will make it unresponsive. We should
2720 // check the machine state here (by enclosing the check and VMRequCall
2721 // within the Console lock to make it atomic).
2722
2723 LogRelFlowFunc(("address=%p, width=%d, height=%d\n",
2724 aAddress, aWidth, aHeight));
2725
2726 CheckComArgExpr(aWidth, aWidth != 0);
2727 CheckComArgExpr(aHeight, aHeight != 0);
2728
2729 /* Do not allow too large screenshots. This also filters out negative
2730 * values passed as either 'width' or 'height'.
2731 */
2732 CheckComArgExpr(aWidth, aWidth <= 32767);
2733 CheckComArgExpr(aHeight, aHeight <= 32767);
2734
2735 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2736
2737 if (!mpDrv)
2738 return E_FAIL;
2739
2740 Console::SafeVMPtr ptrVM(mParent);
2741 if (!ptrVM.isOk())
2742 return ptrVM.rc();
2743
2744 HRESULT rc = S_OK;
2745
2746 LogRelFlowFunc(("Sending SCREENSHOT request\n"));
2747
2748 /* Release lock because other thread (EMT) is called and it may initiate a resize
2749 * which also needs lock.
2750 *
2751 * This method does not need the lock anymore.
2752 */
2753 alock.release();
2754
2755 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, aAddress, aWidth, aHeight);
2756
2757 if (vrc == VERR_NOT_IMPLEMENTED)
2758 rc = setError(E_NOTIMPL,
2759 tr("This feature is not implemented"));
2760 else if (vrc == VERR_TRY_AGAIN)
2761 rc = setError(E_UNEXPECTED,
2762 tr("This feature is not available at this time"));
2763 else if (RT_FAILURE(vrc))
2764 rc = setError(VBOX_E_IPRT_ERROR,
2765 tr("Could not take a screenshot (%Rrc)"), vrc);
2766
2767 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2768 return rc;
2769}
2770
2771HRESULT Display::takeScreenShotToArray(ULONG aScreenId, ULONG aWidth, ULONG aHeight, std::vector<BYTE> &aScreenData)
2772
2773{
2774 LogRelFlowFunc(("width=%d, height=%d\n", aWidth, aHeight));
2775
2776 CheckComArgExpr(aWidth, aWidth != 0);
2777 CheckComArgExpr(raHeight, aHeight != 0);
2778
2779 /* Do not allow too large screenshots. This also filters out negative
2780 * values passed as either 'width' or 'height'.
2781 */
2782 CheckComArgExpr(aWidth, aWidth <= 32767);
2783 CheckComArgExpr(aHeight, aHeight <= 32767);
2784
2785 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2786
2787 if (!mpDrv)
2788 return E_FAIL;
2789
2790 Console::SafeVMPtr ptrVM(mParent);
2791 if (!ptrVM.isOk())
2792 return ptrVM.rc();
2793
2794 HRESULT rc = S_OK;
2795
2796 LogRelFlowFunc(("Sending SCREENSHOT request\n"));
2797
2798 /* Release lock because other thread (EMT) is called and it may initiate a resize
2799 * which also needs lock.
2800 *
2801 * This method does not need the lock anymore.
2802 */
2803 alock.release();
2804
2805 size_t cbData = aWidth * 4 * aHeight;
2806 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbData);
2807
2808 if (!pu8Data)
2809 return E_OUTOFMEMORY;
2810
2811 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, aWidth, aHeight);
2812
2813 if (RT_SUCCESS(vrc))
2814 {
2815 aScreenData.resize(cbData);
2816
2817 /* Convert pixels to format expected by the API caller: [0] R, [1] G, [2] B, [3] A
2818 * and copy to the output buffer.
2819 */
2820 size_t i = 0;
2821 uint8_t *pu8 = pu8Data;
2822 unsigned cPixels = aWidth * aHeight;
2823 while (cPixels)
2824 {
2825 aScreenData[i++] = pu8[2];
2826 aScreenData[i++] = pu8[1];
2827 aScreenData[i++] = pu8[0];
2828 aScreenData[i++] = 0xff;
2829
2830 cPixels--;
2831 pu8 += 4;
2832 }
2833 }
2834 else if (vrc == VERR_NOT_IMPLEMENTED)
2835 rc = setError(E_NOTIMPL,
2836 tr("This feature is not implemented"));
2837 else
2838 rc = setError(VBOX_E_IPRT_ERROR,
2839 tr("Could not take a screenshot (%Rrc)"), vrc);
2840
2841 RTMemFree(pu8Data);
2842
2843 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2844 return rc;
2845}
2846
2847HRESULT Display::takeScreenShotPNGToArray(ULONG aScreenId, ULONG aWidth, ULONG aHeight, std::vector<BYTE> &aScreenData)
2848{
2849 LogRelFlowFunc(("width=%d, height=%d\n", aWidth, aHeight));
2850
2851 CheckComArgExpr(aWidth, aWidth != 0);
2852 CheckComArgExpr(aHeight, aHeight != 0);
2853
2854 /* Do not allow too large screenshots. This also filters out negative
2855 * values passed as either 'width' or 'height'.
2856 */
2857 CheckComArgExpr(aWidth, aWidth <= 32767);
2858 CheckComArgExpr(aHeight, aHeight <= 32767);
2859
2860 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2861
2862 CHECK_CONSOLE_DRV(mpDrv);
2863
2864 Console::SafeVMPtr ptrVM(mParent);
2865 if (!ptrVM.isOk())
2866 return ptrVM.rc();
2867
2868 HRESULT rc = S_OK;
2869
2870 LogRelFlowFunc(("Sending SCREENSHOT request\n"));
2871
2872 /* Release lock because other thread (EMT) is called and it may initiate a resize
2873 * which also needs lock.
2874 *
2875 * This method does not need the lock anymore.
2876 */
2877 alock.release();
2878
2879 size_t cbData = aWidth * 4 * aHeight;
2880 uint8_t *pu8Data = (uint8_t *)RTMemAlloc(cbData);
2881
2882 if (!pu8Data)
2883 return E_OUTOFMEMORY;
2884
2885 int vrc = i_displayTakeScreenshot(ptrVM.rawUVM(), this, mpDrv, aScreenId, pu8Data, aWidth, aHeight);
2886
2887 if (RT_SUCCESS(vrc))
2888 {
2889 uint8_t *pu8PNG = NULL;
2890 uint32_t cbPNG = 0;
2891 uint32_t cxPNG = 0;
2892 uint32_t cyPNG = 0;
2893
2894 vrc = DisplayMakePNG(pu8Data, aWidth, aHeight, &pu8PNG, &cbPNG, &cxPNG, &cyPNG, 0);
2895 if (RT_SUCCESS(vrc))
2896 {
2897 aScreenData.resize(cbPNG);
2898 memcpy(&aScreenData.front(), pu8PNG, cbPNG);
2899 if (pu8PNG)
2900 RTMemFree(pu8PNG);
2901 }
2902 else
2903 {
2904 if (pu8PNG)
2905 RTMemFree(pu8PNG);
2906 rc = setError(VBOX_E_IPRT_ERROR,
2907 tr("Could not convert screenshot to PNG (%Rrc)"), vrc);
2908 }
2909 }
2910 else if (vrc == VERR_NOT_IMPLEMENTED)
2911 rc = setError(E_NOTIMPL,
2912 tr("This feature is not implemented"));
2913 else
2914 rc = setError(VBOX_E_IPRT_ERROR,
2915 tr("Could not take a screenshot (%Rrc)"), vrc);
2916
2917 RTMemFree(pu8Data);
2918
2919 LogRelFlowFunc(("rc=%Rhrc\n", rc));
2920 return rc;
2921}
2922
2923
2924int Display::i_VideoCaptureEnableScreens(ComSafeArrayIn(BOOL, aScreens))
2925{
2926#ifdef VBOX_WITH_VPX
2927 com::SafeArray<BOOL> Screens(ComSafeArrayInArg(aScreens));
2928 for (unsigned i = 0; i < Screens.size(); i++)
2929 maVideoRecEnabled[i] = RT_BOOL(Screens[i]);
2930 return VINF_SUCCESS;
2931#else
2932 return VERR_NOT_IMPLEMENTED;
2933#endif
2934}
2935
2936/**
2937 * Start video capturing. Does nothing if capturing is already active.
2938 */
2939int Display::i_VideoCaptureStart()
2940{
2941#ifdef VBOX_WITH_VPX
2942 if (VideoRecIsEnabled(mpVideoRecCtx))
2943 return VINF_SUCCESS;
2944
2945 int rc = VideoRecContextCreate(&mpVideoRecCtx, mcMonitors);
2946 if (RT_FAILURE(rc))
2947 {
2948 LogFlow(("Failed to create video recording context (%Rrc)!\n", rc));
2949 return rc;
2950 }
2951 ComPtr<IMachine> pMachine = mParent->i_machine();
2952 com::SafeArray<BOOL> screens;
2953 HRESULT hrc = pMachine->COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens));
2954 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2955 for (unsigned i = 0; i < RT_ELEMENTS(maVideoRecEnabled); i++)
2956 maVideoRecEnabled[i] = i < screens.size() && screens[i];
2957 ULONG ulWidth;
2958 hrc = pMachine->COMGETTER(VideoCaptureWidth)(&ulWidth);
2959 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2960 ULONG ulHeight;
2961 hrc = pMachine->COMGETTER(VideoCaptureHeight)(&ulHeight);
2962 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2963 ULONG ulRate;
2964 hrc = pMachine->COMGETTER(VideoCaptureRate)(&ulRate);
2965 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2966 ULONG ulFPS;
2967 hrc = pMachine->COMGETTER(VideoCaptureFPS)(&ulFPS);
2968 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2969 BSTR strFile;
2970 hrc = pMachine->COMGETTER(VideoCaptureFile)(&strFile);
2971 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
2972 RTTIMESPEC ts;
2973 RTTimeNow(&ts);
2974 RTTIME time;
2975 RTTimeExplode(&time, &ts);
2976 for (unsigned uScreen = 0; uScreen < mcMonitors; uScreen++)
2977 {
2978 char *pszAbsPath = RTPathAbsDup(com::Utf8Str(strFile).c_str());
2979 char *pszSuff = RTPathSuffix(pszAbsPath);
2980 if (pszSuff)
2981 pszSuff = RTStrDup(pszSuff);
2982 RTPathStripSuffix(pszAbsPath);
2983 if (!pszAbsPath)
2984 rc = VERR_INVALID_PARAMETER;
2985 if (!pszSuff)
2986 pszSuff = RTStrDup(".webm");
2987 char *pszName = NULL;
2988 if (RT_SUCCESS(rc))
2989 {
2990 if (mcMonitors > 1)
2991 rc = RTStrAPrintf(&pszName, "%s-%u%s", pszAbsPath, uScreen+1, pszSuff);
2992 else
2993 rc = RTStrAPrintf(&pszName, "%s%s", pszAbsPath, pszSuff);
2994 }
2995 if (RT_SUCCESS(rc))
2996 {
2997 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen,
2998 pszName, ulWidth, ulHeight, ulRate, ulFPS);
2999 if (rc == VERR_ALREADY_EXISTS)
3000 {
3001 RTStrFree(pszName);
3002 pszName = NULL;
3003
3004 if (mcMonitors > 1)
3005 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ-%u%s",
3006 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
3007 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
3008 uScreen+1, pszSuff);
3009 else
3010 rc = RTStrAPrintf(&pszName, "%s-%04d-%02u-%02uT%02u-%02u-%02u-%09uZ%s",
3011 pszAbsPath, time.i32Year, time.u8Month, time.u8MonthDay,
3012 time.u8Hour, time.u8Minute, time.u8Second, time.u32Nanosecond,
3013 pszSuff);
3014 if (RT_SUCCESS(rc))
3015 rc = VideoRecStrmInit(mpVideoRecCtx, uScreen,
3016 pszName, ulWidth, ulHeight, ulRate, ulFPS);
3017 }
3018 }
3019
3020 if (RT_SUCCESS(rc))
3021 LogRel(("WebM/VP8 video recording screen #%u with %ux%u @ %u kbps, %u fps to '%s' enabled.\n",
3022 uScreen, ulWidth, ulHeight, ulRate, ulFPS, pszName));
3023 else
3024 LogRel(("Failed to initialize video recording context #%u (%Rrc)!\n", uScreen, rc));
3025 RTStrFree(pszName);
3026 RTStrFree(pszSuff);
3027 RTStrFree(pszAbsPath);
3028 }
3029 return rc;
3030#else
3031 return VERR_NOT_IMPLEMENTED;
3032#endif
3033}
3034
3035/**
3036 * Stop video capturing. Does nothing if video capturing is not active.
3037 */
3038void Display::i_VideoCaptureStop()
3039{
3040#ifdef VBOX_WITH_VPX
3041 if (VideoRecIsEnabled(mpVideoRecCtx))
3042 LogRel(("WebM/VP8 video recording stopped.\n"));
3043 VideoRecContextClose(mpVideoRecCtx);
3044 mpVideoRecCtx = NULL;
3045#endif
3046}
3047
3048int Display::i_drawToScreenEMT(Display *pDisplay, ULONG aScreenId, BYTE *address,
3049 ULONG x, ULONG y, ULONG width, ULONG height)
3050{
3051 int rc = VINF_SUCCESS;
3052
3053 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[aScreenId];
3054
3055 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3056 {
3057 Assert(!pDisplay->i_vbvaLockIsOwner());
3058 rc = pDisplay->mpDrv->pUpPort->pfnDisplayBlt(pDisplay->mpDrv->pUpPort, address, x, y, width, height);
3059 }
3060 else if (aScreenId < pDisplay->mcMonitors)
3061 {
3062 /* Copy the bitmap to the guest VRAM. */
3063 const uint8_t *pu8Src = address;
3064 int32_t xSrc = 0;
3065 int32_t ySrc = 0;
3066 uint32_t u32SrcWidth = width;
3067 uint32_t u32SrcHeight = height;
3068 uint32_t u32SrcLineSize = width * 4;
3069 uint32_t u32SrcBitsPerPixel = 32;
3070
3071 uint8_t *pu8Dst = pFBInfo->pu8FramebufferVRAM;
3072 int32_t xDst = x;
3073 int32_t yDst = y;
3074 uint32_t u32DstWidth = pFBInfo->w;
3075 uint32_t u32DstHeight = pFBInfo->h;
3076 uint32_t u32DstLineSize = pFBInfo->u32LineSize;
3077 uint32_t u32DstBitsPerPixel = pFBInfo->u16BitsPerPixel;
3078
3079 Assert(!pDisplay->i_vbvaLockIsOwner());
3080 rc = pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
3081 width, height,
3082 pu8Src,
3083 xSrc, ySrc,
3084 u32SrcWidth, u32SrcHeight,
3085 u32SrcLineSize, u32SrcBitsPerPixel,
3086 pu8Dst,
3087 xDst, yDst,
3088 u32DstWidth, u32DstHeight,
3089 u32DstLineSize, u32DstBitsPerPixel);
3090 if (RT_SUCCESS(rc))
3091 {
3092 if (!pFBInfo->pSourceBitmap.isNull())
3093 {
3094 /* Update the changed screen area. When source bitmap uses VRAM directly, just notify
3095 * frontend to update. And for default format, render the guest VRAM to the source bitmap.
3096 */
3097 if ( pFBInfo->fDefaultFormat
3098 && !pFBInfo->fDisabled)
3099 {
3100 BYTE *pAddress = NULL;
3101 ULONG ulWidth = 0;
3102 ULONG ulHeight = 0;
3103 ULONG ulBitsPerPixel = 0;
3104 ULONG ulBytesPerLine = 0;
3105 ULONG ulPixelFormat = 0;
3106
3107 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
3108 &ulWidth,
3109 &ulHeight,
3110 &ulBitsPerPixel,
3111 &ulBytesPerLine,
3112 &ulPixelFormat);
3113 if (SUCCEEDED(hrc))
3114 {
3115 pu8Src = pFBInfo->pu8FramebufferVRAM;
3116 xSrc = x;
3117 ySrc = y;
3118 u32SrcWidth = pFBInfo->w;
3119 u32SrcHeight = pFBInfo->h;
3120 u32SrcLineSize = pFBInfo->u32LineSize;
3121 u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
3122
3123 /* Default format is 32 bpp. */
3124 pu8Dst = pAddress;
3125 xDst = xSrc;
3126 yDst = ySrc;
3127 u32DstWidth = u32SrcWidth;
3128 u32DstHeight = u32SrcHeight;
3129 u32DstLineSize = u32DstWidth * 4;
3130 u32DstBitsPerPixel = 32;
3131
3132 Assert(!pDisplay->i_vbvaLockIsOwner());
3133 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
3134 width, height,
3135 pu8Src,
3136 xSrc, ySrc,
3137 u32SrcWidth, u32SrcHeight,
3138 u32SrcLineSize, u32SrcBitsPerPixel,
3139 pu8Dst,
3140 xDst, yDst,
3141 u32DstWidth, u32DstHeight,
3142 u32DstLineSize, u32DstBitsPerPixel);
3143 }
3144 }
3145 }
3146
3147 pDisplay->i_handleDisplayUpdate(aScreenId, x, y, width, height);
3148 }
3149 }
3150 else
3151 {
3152 rc = VERR_INVALID_PARAMETER;
3153 }
3154
3155 if (RT_SUCCESS(rc))
3156 pDisplay->mParent->i_consoleVRDPServer()->SendUpdateBitmap(aScreenId, x, y, width, height);
3157
3158 return rc;
3159}
3160
3161HRESULT Display::drawToScreen(ULONG aScreenId, BYTE *aAddress, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
3162{
3163 /// @todo (r=dmik) this function may take too long to complete if the VM
3164 // is doing something like saving state right now. Which, in case if it
3165 // is called on the GUI thread, will make it unresponsive. We should
3166 // check the machine state here (by enclosing the check and VMRequCall
3167 // within the Console lock to make it atomic).
3168
3169 LogRelFlowFunc(("aAddress=%p, x=%d, y=%d, width=%d, height=%d\n",
3170 (void *)aAddress, aX, aY, aWidth, aHeight));
3171
3172 CheckComArgExpr(aWidth, aWidth != 0);
3173 CheckComArgExpr(aHeight, aHeight != 0);
3174
3175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3176
3177 CHECK_CONSOLE_DRV(mpDrv);
3178
3179 Console::SafeVMPtr ptrVM(mParent);
3180 if (!ptrVM.isOk())
3181 return ptrVM.rc();
3182
3183 /* Release lock because the call scheduled on EMT may also try to take it. */
3184 alock.release();
3185
3186 /*
3187 * Again we're lazy and make the graphics device do all the
3188 * dirty conversion work.
3189 */
3190 int rcVBox = VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_drawToScreenEMT, 7,
3191 this, aScreenId, aAddress, aX, aY, aWidth, aHeight);
3192
3193 /*
3194 * If the function returns not supported, we'll have to do all the
3195 * work ourselves using the framebuffer.
3196 */
3197 HRESULT rc = S_OK;
3198 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
3199 {
3200 /** @todo implement generic fallback for screen blitting. */
3201 rc = E_NOTIMPL;
3202 }
3203 else if (RT_FAILURE(rcVBox))
3204 rc = setError(VBOX_E_IPRT_ERROR,
3205 tr("Could not draw to the screen (%Rrc)"), rcVBox);
3206//@todo
3207// else
3208// {
3209// /* All ok. Redraw the screen. */
3210// handleDisplayUpdate (x, y, width, height);
3211// }
3212
3213 LogRelFlowFunc(("rc=%Rhrc\n", rc));
3214 return rc;
3215}
3216
3217void Display::i_InvalidateAndUpdateEMT(Display *pDisplay, unsigned uId, bool fUpdateAll)
3218{
3219 unsigned uScreenId;
3220 for (uScreenId = (fUpdateAll ? 0 : uId); uScreenId < pDisplay->mcMonitors; uScreenId++)
3221 {
3222 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
3223
3224 if ( !pFBInfo->fVBVAEnabled
3225 && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3226 {
3227 Assert(!pDisplay->i_vbvaLockIsOwner());
3228 pDisplay->mpDrv->pUpPort->pfnUpdateDisplayAll(pDisplay->mpDrv->pUpPort, /* fFailOnResize = */ true);
3229 }
3230 else
3231 {
3232 if (!pFBInfo->fDisabled)
3233 {
3234 /* Render complete VRAM screen to the framebuffer.
3235 * When framebuffer uses VRAM directly, just notify it to update.
3236 */
3237 if (pFBInfo->fDefaultFormat && !pFBInfo->pSourceBitmap.isNull())
3238 {
3239 BYTE *pAddress = NULL;
3240 ULONG ulWidth = 0;
3241 ULONG ulHeight = 0;
3242 ULONG ulBitsPerPixel = 0;
3243 ULONG ulBytesPerLine = 0;
3244 ULONG ulPixelFormat = 0;
3245
3246 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
3247 &ulWidth,
3248 &ulHeight,
3249 &ulBitsPerPixel,
3250 &ulBytesPerLine,
3251 &ulPixelFormat);
3252 if (SUCCEEDED(hrc))
3253 {
3254 uint32_t width = pFBInfo->w;
3255 uint32_t height = pFBInfo->h;
3256
3257 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
3258 int32_t xSrc = 0;
3259 int32_t ySrc = 0;
3260 uint32_t u32SrcWidth = pFBInfo->w;
3261 uint32_t u32SrcHeight = pFBInfo->h;
3262 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
3263 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
3264
3265 /* Default format is 32 bpp. */
3266 uint8_t *pu8Dst = pAddress;
3267 int32_t xDst = xSrc;
3268 int32_t yDst = ySrc;
3269 uint32_t u32DstWidth = u32SrcWidth;
3270 uint32_t u32DstHeight = u32SrcHeight;
3271 uint32_t u32DstLineSize = u32DstWidth * 4;
3272 uint32_t u32DstBitsPerPixel = 32;
3273
3274 /* if uWidth != pFBInfo->w and uHeight != pFBInfo->h
3275 * implies resize of Framebuffer is in progress and
3276 * copyrect should not be called.
3277 */
3278 if (ulWidth == pFBInfo->w && ulHeight == pFBInfo->h)
3279 {
3280 Assert(!pDisplay->i_vbvaLockIsOwner());
3281 pDisplay->mpDrv->pUpPort->pfnCopyRect(pDisplay->mpDrv->pUpPort,
3282 width, height,
3283 pu8Src,
3284 xSrc, ySrc,
3285 u32SrcWidth, u32SrcHeight,
3286 u32SrcLineSize, u32SrcBitsPerPixel,
3287 pu8Dst,
3288 xDst, yDst,
3289 u32DstWidth, u32DstHeight,
3290 u32DstLineSize, u32DstBitsPerPixel);
3291 }
3292 }
3293 }
3294
3295 pDisplay->i_handleDisplayUpdate(uScreenId, 0, 0, pFBInfo->w, pFBInfo->h);
3296 }
3297 }
3298 if (!fUpdateAll)
3299 break;
3300 }
3301}
3302
3303/**
3304 * Does a full invalidation of the VM display and instructs the VM
3305 * to update it immediately.
3306 *
3307 * @returns COM status code
3308 */
3309
3310HRESULT Display::invalidateAndUpdate()
3311{
3312 LogRelFlowFunc(("\n"));
3313
3314 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3315
3316 CHECK_CONSOLE_DRV(mpDrv);
3317
3318 Console::SafeVMPtr ptrVM(mParent);
3319 if (!ptrVM.isOk())
3320 return ptrVM.rc();
3321
3322 HRESULT rc = S_OK;
3323
3324 LogRelFlowFunc(("Sending DPYUPDATE request\n"));
3325
3326 /* Have to release the lock when calling EMT. */
3327 alock.release();
3328
3329 /* pdm.h says that this has to be called from the EMT thread */
3330 int rcVBox = VMR3ReqCallVoidWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3331 3, this, 0, true);
3332 alock.acquire();
3333
3334 if (RT_FAILURE(rcVBox))
3335 rc = setError(VBOX_E_IPRT_ERROR,
3336 tr("Could not invalidate and update the screen (%Rrc)"), rcVBox);
3337
3338 LogRelFlowFunc(("rc=%Rhrc\n", rc));
3339 return rc;
3340}
3341
3342HRESULT Display::invalidateAndUpdateScreen(ULONG aScreenId)
3343{
3344 LogRelFlowFunc(("\n"));
3345
3346 HRESULT rc = S_OK;
3347
3348 Console::SafeVMPtr ptrVM(mParent);
3349 if (!ptrVM.isOk())
3350 return ptrVM.rc();
3351
3352 /* pdm.h says that this has to be called from the EMT thread */
3353 int rcVBox = VMR3ReqCallVoidWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3354 3, this, aScreenId, false);
3355 if (RT_FAILURE(rcVBox))
3356 rc = setError(VBOX_E_IPRT_ERROR,
3357 tr("Could not invalidate and update the screen %d (%Rrc)"), aScreenId, rcVBox);
3358
3359 LogRelFlowFunc(("rc=%Rhrc\n", rc));
3360 return rc;
3361}
3362
3363HRESULT Display::completeVHWACommand(BYTE *aCommand)
3364{
3365#ifdef VBOX_WITH_VIDEOHWACCEL
3366 mpDrv->pVBVACallbacks->pfnVHWACommandCompleteAsync(mpDrv->pVBVACallbacks, (PVBOXVHWACMD)aCommand);
3367 return S_OK;
3368#else
3369 return E_NOTIMPL;
3370#endif
3371}
3372
3373HRESULT Display::viewportChanged(ULONG aScreenId, ULONG aX, ULONG aY, ULONG aWidth, ULONG aHeight)
3374{
3375#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3376
3377 if (mcMonitors <= aScreenId)
3378 {
3379 AssertMsgFailed(("invalid screen id\n"));
3380 return E_INVALIDARG;
3381 }
3382
3383 BOOL is3denabled;
3384 mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
3385
3386 if (is3denabled)
3387 {
3388 int rc = i_crViewportNotify(aScreenId, aX, aY, aWidth, aHeight);
3389 if (RT_FAILURE(rc))
3390 {
3391 DISPLAYFBINFO *pFb = &maFramebuffers[aScreenId];
3392 pFb->pendingViewportInfo.fPending = true;
3393 pFb->pendingViewportInfo.x = aX;
3394 pFb->pendingViewportInfo.y = aY;
3395 pFb->pendingViewportInfo.width = aWidth;
3396 pFb->pendingViewportInfo.height = aHeight;
3397 }
3398 }
3399#endif /* VBOX_WITH_CROGL && VBOX_WITH_HGCM */
3400 return S_OK;
3401}
3402
3403HRESULT Display::querySourceBitmap(ULONG aScreenId,
3404 ComPtr<IDisplaySourceBitmap> &aDisplaySourceBitmap)
3405{
3406 LogRelFlowFunc(("aScreenId = %d\n", aScreenId));
3407
3408 Console::SafeVMPtr ptrVM(mParent);
3409 if (!ptrVM.isOk())
3410 return ptrVM.rc();
3411
3412 bool fSetRenderVRAM = false;
3413 bool fInvalidate = false;
3414
3415 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3416
3417 if (aScreenId >= mcMonitors)
3418 return setError(E_INVALIDARG, tr("QuerySourceBitmap: Invalid screen %d (total %d)"),
3419 aScreenId, mcMonitors);
3420
3421 if (!mfSourceBitmapEnabled)
3422 {
3423 aDisplaySourceBitmap = NULL;
3424 return E_FAIL;
3425 }
3426
3427 HRESULT hr = S_OK;
3428
3429 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
3430 if (pFBInfo->pSourceBitmap.isNull())
3431 {
3432 /* Create a new object. */
3433 ComObjPtr<DisplaySourceBitmap> obj;
3434 hr = obj.createObject();
3435 if (SUCCEEDED(hr))
3436 hr = obj->init(this, aScreenId, pFBInfo);
3437
3438 if (SUCCEEDED(hr))
3439 {
3440 bool fDefaultFormat = !obj->i_usesVRAM();
3441
3442 if (aScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
3443 {
3444 /* Start buffer updates. */
3445 BYTE *pAddress = NULL;
3446 ULONG ulWidth = 0;
3447 ULONG ulHeight = 0;
3448 ULONG ulBitsPerPixel = 0;
3449 ULONG ulBytesPerLine = 0;
3450 ULONG ulPixelFormat = 0;
3451
3452 obj->QueryBitmapInfo(&pAddress,
3453 &ulWidth,
3454 &ulHeight,
3455 &ulBitsPerPixel,
3456 &ulBytesPerLine,
3457 &ulPixelFormat);
3458
3459 mpDrv->IConnector.pu8Data = pAddress;
3460 mpDrv->IConnector.cbScanline = ulBytesPerLine;
3461 mpDrv->IConnector.cBits = ulBitsPerPixel;
3462 mpDrv->IConnector.cx = ulWidth;
3463 mpDrv->IConnector.cy = ulHeight;
3464
3465 fSetRenderVRAM = fDefaultFormat;
3466 }
3467
3468 /* Make sure that the bitmap contains the latest image. */
3469 fInvalidate = fDefaultFormat;
3470
3471 pFBInfo->pSourceBitmap = obj;
3472 pFBInfo->fDefaultFormat = fDefaultFormat;
3473 }
3474 }
3475
3476 if (SUCCEEDED(hr))
3477 {
3478 pFBInfo->pSourceBitmap.queryInterfaceTo(aDisplaySourceBitmap.asOutParam());
3479 }
3480
3481 /* Leave the IDisplay lock because the VGA device must not be called under it. */
3482 alock.release();
3483
3484 if (SUCCEEDED(hr))
3485 {
3486 if (fSetRenderVRAM)
3487 {
3488 Assert(!i_vbvaLockIsOwner());
3489 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
3490 }
3491
3492 if (fInvalidate)
3493 VMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)Display::i_InvalidateAndUpdateEMT,
3494 3, this, aScreenId, false);
3495 }
3496
3497 LogRelFlowFunc(("%Rhrc\n", hr));
3498 return hr;
3499}
3500
3501HRESULT Display::setFramebufferUpdateMode(ULONG aScreenId, FramebufferUpdateMode_T aFramebufferUpdateMode)
3502{
3503 LogRelFlowFunc(("aScreenId %d, aFramebufferUpdateMode %d\n", aScreenId, aFramebufferUpdateMode));
3504
3505 HRESULT hr = S_OK;
3506
3507 /* Prepare without taking a lock. API has it's own locking. */
3508 ComPtr<IDisplaySourceBitmap> pSourceBitmap;
3509 if (aFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
3510 {
3511 /* A source bitmap will be needed. */
3512 hr = QuerySourceBitmap(aScreenId, pSourceBitmap.asOutParam());
3513 }
3514
3515 if (FAILED(hr))
3516 return hr;
3517
3518 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3519
3520 if (aScreenId >= mcMonitors)
3521 return setError(E_INVALIDARG, tr("SetFramebufferUpdateMode: Invalid screen %d (total %d)"),
3522 aScreenId, mcMonitors);
3523
3524 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
3525
3526 /* Reset the update mode. */
3527 pFBInfo->updateImage.pSourceBitmap.setNull();
3528 pFBInfo->updateImage.pu8Address = NULL;
3529 pFBInfo->updateImage.cbLine = 0;
3530
3531 if (aFramebufferUpdateMode == FramebufferUpdateMode_NotifyUpdateImage)
3532 {
3533 BYTE *pAddress = NULL;
3534 ULONG ulWidth = 0;
3535 ULONG ulHeight = 0;
3536 ULONG ulBitsPerPixel = 0;
3537 ULONG ulBytesPerLine = 0;
3538 ULONG ulPixelFormat = 0;
3539
3540 hr = pSourceBitmap->QueryBitmapInfo(&pAddress,
3541 &ulWidth,
3542 &ulHeight,
3543 &ulBitsPerPixel,
3544 &ulBytesPerLine,
3545 &ulPixelFormat);
3546 if (SUCCEEDED(hr))
3547 {
3548 pFBInfo->updateImage.pSourceBitmap = pSourceBitmap;
3549 pFBInfo->updateImage.pu8Address = pAddress;
3550 pFBInfo->updateImage.cbLine = ulBytesPerLine;
3551 }
3552 }
3553
3554 pFBInfo->enmFramebufferUpdateMode = aFramebufferUpdateMode;
3555
3556 return S_OK;
3557}
3558
3559// wrapped IEventListener method
3560HRESULT Display::handleEvent(const ComPtr<IEvent> &aEvent)
3561{
3562 VBoxEventType_T aType = VBoxEventType_Invalid;
3563
3564 aEvent->COMGETTER(Type)(&aType);
3565 switch (aType)
3566 {
3567 case VBoxEventType_OnStateChanged:
3568 {
3569 ComPtr<IStateChangedEvent> scev = aEvent;
3570 Assert(scev);
3571 MachineState_T machineState;
3572 scev->COMGETTER(State)(&machineState);
3573 if ( machineState == MachineState_Running
3574 || machineState == MachineState_Teleporting
3575 || machineState == MachineState_LiveSnapshotting
3576 || machineState == MachineState_DeletingSnapshotOnline
3577 )
3578 {
3579 LogRelFlowFunc(("Machine is running.\n"));
3580
3581 mfMachineRunning = true;
3582
3583#ifdef VBOX_WITH_CROGL
3584 i_crOglWindowsShow(true);
3585#endif
3586 }
3587 else
3588 {
3589 mfMachineRunning = false;
3590
3591#ifdef VBOX_WITH_CROGL
3592 if (machineState == MachineState_Paused)
3593 i_crOglWindowsShow(false);
3594#endif
3595 }
3596 break;
3597 }
3598 default:
3599 AssertFailed();
3600 }
3601
3602 return S_OK;
3603}
3604
3605
3606// private methods
3607/////////////////////////////////////////////////////////////////////////////
3608
3609#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3610int Display::i_crViewportNotify(ULONG aScreenId, ULONG x, ULONG y, ULONG width, ULONG height)
3611{
3612 VMMDev *pVMMDev = mParent->i_getVMMDev();
3613 if (!pVMMDev)
3614 return VERR_INVALID_STATE;
3615
3616 size_t cbData = RT_UOFFSETOF(VBOXCRCMDCTL_HGCM, aParms[5]);
3617 VBOXCRCMDCTL_HGCM *pData = (VBOXCRCMDCTL_HGCM*)alloca(cbData);
3618
3619 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
3620 pData->Hdr.u32Function = SHCRGL_HOST_FN_VIEWPORT_CHANGED;
3621
3622 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_32BIT;
3623 pData->aParms[0].u.uint32 = aScreenId;
3624
3625 pData->aParms[1].type = VBOX_HGCM_SVC_PARM_32BIT;
3626 pData->aParms[1].u.uint32 = x;
3627
3628 pData->aParms[2].type = VBOX_HGCM_SVC_PARM_32BIT;
3629 pData->aParms[2].u.uint32 = y;
3630
3631 pData->aParms[3].type = VBOX_HGCM_SVC_PARM_32BIT;
3632 pData->aParms[3].u.uint32 = width;
3633
3634 pData->aParms[4].type = VBOX_HGCM_SVC_PARM_32BIT;
3635 pData->aParms[4].u.uint32 = height;
3636
3637 return i_crCtlSubmitSyncIfHasDataForScreen(aScreenId, &pData->Hdr, (uint32_t)cbData);
3638}
3639#endif
3640
3641#ifdef VBOX_WITH_CRHGSMI
3642void Display::i_setupCrHgsmiData(void)
3643{
3644 VMMDev *pVMMDev = mParent->i_getVMMDev();
3645 Assert(pVMMDev);
3646 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
3647 AssertRC(rc);
3648
3649 if (pVMMDev)
3650 rc = pVMMDev->hgcmHostSvcHandleCreate("VBoxSharedCrOpenGL", &mhCrOglSvc);
3651 else
3652 rc = VERR_GENERAL_FAILURE;
3653
3654 if (RT_SUCCESS(rc))
3655 {
3656 Assert(mhCrOglSvc);
3657 /* setup command completion callback */
3658 VBOXVDMACMD_CHROMIUM_CTL_CRHGSMI_SETUP_MAINCB Completion;
3659 Completion.Hdr.enmType = VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_MAINCB;
3660 Completion.Hdr.cbCmd = sizeof(Completion);
3661 Completion.hCompletion = mpDrv->pVBVACallbacks;
3662 Completion.pfnCompletion = mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync;
3663
3664 VBOXHGCMSVCPARM parm;
3665 parm.type = VBOX_HGCM_SVC_PARM_PTR;
3666 parm.u.pointer.addr = &Completion;
3667 parm.u.pointer.size = 0;
3668
3669 rc = pVMMDev->hgcmHostCall("VBoxSharedCrOpenGL", SHCRGL_HOST_FN_CRHGSMI_CTL, 1, &parm);
3670 if (RT_SUCCESS(rc))
3671 mCrOglCallbacks = Completion.MainInterface;
3672 else
3673 AssertMsgFailed(("VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP_COMPLETION failed rc %d", rc));
3674 }
3675
3676 if (RT_FAILURE(rc))
3677 mhCrOglSvc = NULL;
3678
3679 RTCritSectRwLeaveExcl(&mCrOglLock);
3680}
3681
3682void Display::i_destructCrHgsmiData(void)
3683{
3684 int rc = RTCritSectRwEnterExcl(&mCrOglLock);
3685 AssertRC(rc);
3686 mhCrOglSvc = NULL;
3687 RTCritSectRwLeaveExcl(&mCrOglLock);
3688}
3689#endif
3690
3691/**
3692 * Handle display resize event issued by the VGA device for the primary screen.
3693 *
3694 * @see PDMIDISPLAYCONNECTOR::pfnResize
3695 */
3696DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
3697 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
3698{
3699 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3700 Display *pThis = pDrv->pDisplay;
3701
3702 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
3703 bpp, pvVRAM, cbLine, cx, cy));
3704
3705 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false);
3706 if (!f)
3707 {
3708 /* This is a result of recursive call when the source bitmap is being updated
3709 * during a VGA resize. Tell the VGA device to ignore the call.
3710 *
3711 * @todo It is a workaround, actually pfnUpdateDisplayAll must
3712 * fail on resize.
3713 */
3714 LogRel(("displayResizeCallback: already processing\n"));
3715 return VINF_VGA_RESIZE_IN_PROGRESS;
3716 }
3717
3718 int rc = pThis->i_handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy, VBVA_SCREEN_F_ACTIVE);
3719
3720 /* Restore the flag. */
3721 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true);
3722 AssertRelease(f);
3723
3724 return rc;
3725}
3726
3727/**
3728 * Handle display update.
3729 *
3730 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
3731 */
3732DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
3733 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
3734{
3735 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3736
3737#ifdef DEBUG_sunlover
3738 LogFlowFunc(("mfVideoAccelEnabled = %d, %d,%d %dx%d\n",
3739 pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy));
3740#endif /* DEBUG_sunlover */
3741
3742 /* This call does update regardless of VBVA status.
3743 * But in VBVA mode this is called only as result of
3744 * pfnUpdateDisplayAll in the VGA device.
3745 */
3746
3747 pDrv->pDisplay->i_handleDisplayUpdate(VBOX_VIDEO_PRIMARY_SCREEN, x, y, cx, cy);
3748}
3749
3750/**
3751 * Periodic display refresh callback.
3752 *
3753 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
3754 * @thread EMT
3755 */
3756DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
3757{
3758 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3759
3760#ifdef DEBUG_sunlover_2
3761 LogFlowFunc(("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
3762 pDrv->pDisplay->mfVideoAccelEnabled));
3763#endif /* DEBUG_sunlover_2 */
3764
3765 Display *pDisplay = pDrv->pDisplay;
3766 unsigned uScreenId;
3767
3768 int rc = pDisplay->i_videoAccelRefreshProcess();
3769 if (rc != VINF_TRY_AGAIN) /* Means 'do nothing' here. */
3770 {
3771 if (rc == VWRN_INVALID_STATE)
3772 {
3773 /* No VBVA do a display update. */
3774 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN];
3775 Assert(!pDisplay->i_vbvaLockIsOwner());
3776 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
3777 }
3778
3779 /* Inform the VRDP server that the current display update sequence is
3780 * completed. At this moment the framebuffer memory contains a definite
3781 * image, that is synchronized with the orders already sent to VRDP client.
3782 * The server can now process redraw requests from clients or initial
3783 * fullscreen updates for new clients.
3784 */
3785 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
3786 {
3787 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
3788
3789 Assert(pDisplay->mParent && pDisplay->mParent->i_consoleVRDPServer());
3790 pDisplay->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, NULL, 0);
3791 }
3792 }
3793
3794#ifdef VBOX_WITH_VPX
3795 if (VideoRecIsEnabled(pDisplay->mpVideoRecCtx))
3796 {
3797 do {
3798# if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
3799 BOOL is3denabled;
3800 pDisplay->mParent->i_machine()->COMGETTER(Accelerate3DEnabled)(&is3denabled);
3801 if (is3denabled)
3802 {
3803 if (ASMAtomicCmpXchgU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_SUBMITTED, CRVREC_STATE_IDLE))
3804 {
3805 if (pDisplay->mCrOglCallbacks.pfnHasData())
3806 {
3807 /* submit */
3808 VBOXCRCMDCTL_HGCM *pData = &pDisplay->mCrOglScreenshotCtl;
3809
3810 pData->Hdr.enmType = VBOXCRCMDCTL_TYPE_HGCM;
3811 pData->Hdr.u32Function = SHCRGL_HOST_FN_TAKE_SCREENSHOT;
3812
3813 pData->aParms[0].type = VBOX_HGCM_SVC_PARM_PTR;
3814 pData->aParms[0].u.pointer.addr = &pDisplay->mCrOglScreenshotData;
3815 pData->aParms[0].u.pointer.size = sizeof(pDisplay->mCrOglScreenshotData);
3816 rc = pDisplay->i_crCtlSubmit(&pData->Hdr, sizeof(*pData), i_displayCrCmdFree, pData);
3817 if (!RT_SUCCESS(rc))
3818 AssertMsgFailed(("crCtlSubmit failed rc %d\n", rc));
3819 }
3820
3821 /* no 3D data available, or error has occured,
3822 * go the straight way */
3823 ASMAtomicWriteU32(&pDisplay->mfCrOglVideoRecState, CRVREC_STATE_IDLE);
3824 }
3825 else
3826 {
3827 /* record request is still in progress, don't do anything */
3828 break;
3829 }
3830 }
3831# endif /* VBOX_WITH_HGCM && VBOX_WITH_CROGL */
3832
3833 uint64_t u64Now = RTTimeProgramMilliTS();
3834 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
3835 {
3836 if (!pDisplay->maVideoRecEnabled[uScreenId])
3837 continue;
3838
3839 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
3840
3841 if ( !pFBInfo->pFramebuffer.isNull()
3842 && !pFBInfo->fDisabled)
3843 {
3844 rc = VERR_NOT_SUPPORTED;
3845 if ( pFBInfo->fVBVAEnabled
3846 && pFBInfo->pu8FramebufferVRAM)
3847 {
3848 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
3849 FramebufferPixelFormat_FOURCC_RGB,
3850 pFBInfo->u16BitsPerPixel,
3851 pFBInfo->u32LineSize, pFBInfo->w, pFBInfo->h,
3852 pFBInfo->pu8FramebufferVRAM, u64Now);
3853 }
3854 else if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && pDrv->IConnector.pu8Data)
3855 {
3856 rc = VideoRecCopyToIntBuf(pDisplay->mpVideoRecCtx, uScreenId, 0, 0,
3857 FramebufferPixelFormat_FOURCC_RGB,
3858 pDrv->IConnector.cBits,
3859 pDrv->IConnector.cbScanline, pDrv->IConnector.cx,
3860 pDrv->IConnector.cy, pDrv->IConnector.pu8Data, u64Now);
3861 }
3862 if (rc == VINF_TRY_AGAIN)
3863 break;
3864 }
3865 }
3866 } while (0);
3867 }
3868#endif /* VBOX_WITH_VPX */
3869
3870#ifdef DEBUG_sunlover_2
3871 LogFlowFunc(("leave\n"));
3872#endif /* DEBUG_sunlover_2 */
3873}
3874
3875/**
3876 * Reset notification
3877 *
3878 * @see PDMIDISPLAYCONNECTOR::pfnReset
3879 */
3880DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
3881{
3882 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3883
3884 LogRelFlowFunc(("\n"));
3885
3886 /* Disable VBVA mode. */
3887 pDrv->pDisplay->i_VideoAccelEnable(false, NULL);
3888}
3889
3890/**
3891 * LFBModeChange notification
3892 *
3893 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
3894 */
3895DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
3896{
3897 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3898
3899 LogRelFlowFunc(("fEnabled=%d\n", fEnabled));
3900
3901 NOREF(fEnabled);
3902
3903 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
3904 /* The LFBModeChange function is called under DevVGA lock. Postpone disabling VBVA, do it in the refresh timer. */
3905 ASMAtomicWriteU32(&pDrv->pDisplay->mfu32PendingVideoAccelDisable, true);
3906}
3907
3908/**
3909 * Adapter information change notification.
3910 *
3911 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
3912 */
3913DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
3914 uint32_t u32VRAMSize)
3915{
3916 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
3917
3918 if (pvVRAM == NULL)
3919 {
3920 unsigned i;
3921 for (i = 0; i < pDrv->pDisplay->mcMonitors; i++)
3922 {
3923 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[i];
3924
3925 pFBInfo->u32Offset = 0;
3926 pFBInfo->u32MaxFramebufferSize = 0;
3927 pFBInfo->u32InformationSize = 0;
3928 }
3929 }
3930#ifndef VBOX_WITH_HGSMI
3931 else
3932 {
3933 uint8_t *pu8 = (uint8_t *)pvVRAM;
3934 pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
3935
3936 // @todo
3937 uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
3938
3939 VBOXVIDEOINFOHDR *pHdr;
3940
3941 for (;;)
3942 {
3943 pHdr = (VBOXVIDEOINFOHDR *)pu8;
3944 pu8 += sizeof(VBOXVIDEOINFOHDR);
3945
3946 if (pu8 >= pu8End)
3947 {
3948 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n"));
3949 break;
3950 }
3951
3952 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY)
3953 {
3954 if (pHdr->u16Length != sizeof(VBOXVIDEOINFODISPLAY))
3955 {
3956 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
3957 break;
3958 }
3959
3960 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
3961
3962 if (pDisplay->u32Index >= pDrv->pDisplay->mcMonitors)
3963 {
3964 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index));
3965 break;
3966 }
3967
3968 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[pDisplay->u32Index];
3969
3970 pFBInfo->u32Offset = pDisplay->u32Offset;
3971 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize;
3972 pFBInfo->u32InformationSize = pDisplay->u32InformationSize;
3973
3974 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_DISPLAY: %d: at 0x%08X, size 0x%08X, info 0x%08X\n", pDisplay->u32Index,
3975 pDisplay->u32Offset, pDisplay->u32FramebufferSize, pDisplay->u32InformationSize));
3976 }
3977 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_QUERY_CONF32)
3978 {
3979 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOQUERYCONF32))
3980 {
3981 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length));
3982 break;
3983 }
3984
3985 VBOXVIDEOINFOQUERYCONF32 *pConf32 = (VBOXVIDEOINFOQUERYCONF32 *)pu8;
3986
3987 switch (pConf32->u32Index)
3988 {
3989 case VBOX_VIDEO_QCI32_MONITOR_COUNT:
3990 {
3991 pConf32->u32Value = pDrv->pDisplay->mcMonitors;
3992 } break;
3993
3994 case VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE:
3995 {
3996 /* @todo make configurable. */
3997 pConf32->u32Value = _1M;
3998 } break;
3999
4000 default:
4001 LogRel(("VBoxVideo: CONF32 %d not supported!!! Skipping.\n", pConf32->u32Index));
4002 }
4003 }
4004 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
4005 {
4006 if (pHdr->u16Length != 0)
4007 {
4008 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
4009 break;
4010 }
4011
4012 break;
4013 }
4014 else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP)
4015 {
4016 /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo. cpp pushing this to us? */
4017 LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type));
4018 }
4019
4020 pu8 += pHdr->u16Length;
4021 }
4022 }
4023#endif /* !VBOX_WITH_HGSMI */
4024}
4025
4026/**
4027 * Display information change notification.
4028 *
4029 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
4030 */
4031DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface,
4032 void *pvVRAM, unsigned uScreenId)
4033{
4034 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4035
4036 if (uScreenId >= pDrv->pDisplay->mcMonitors)
4037 {
4038 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId));
4039 return;
4040 }
4041
4042 /* Get the display information structure. */
4043 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[uScreenId];
4044
4045 uint8_t *pu8 = (uint8_t *)pvVRAM;
4046 pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize;
4047
4048 // @todo
4049 uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize;
4050
4051 VBOXVIDEOINFOHDR *pHdr;
4052
4053 for (;;)
4054 {
4055 pHdr = (VBOXVIDEOINFOHDR *)pu8;
4056 pu8 += sizeof(VBOXVIDEOINFOHDR);
4057
4058 if (pu8 >= pu8End)
4059 {
4060 LogRel(("VBoxVideo: Guest display information overflow!!!\n"));
4061 break;
4062 }
4063
4064 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN)
4065 {
4066 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOSCREEN))
4067 {
4068 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
4069 break;
4070 }
4071
4072 VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8;
4073
4074 pFBInfo->xOrigin = pScreen->xOrigin;
4075 pFBInfo->yOrigin = pScreen->yOrigin;
4076
4077 pFBInfo->w = pScreen->u16Width;
4078 pFBInfo->h = pScreen->u16Height;
4079
4080 LogRelFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
4081 pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width,
4082 pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
4083
4084 if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN)
4085 {
4086 /* Primary screen resize is eeeeeeeee by the VGA device. */
4087 if (pFBInfo->fDisabled)
4088 {
4089 pFBInfo->fDisabled = false;
4090 fireGuestMonitorChangedEvent(pDrv->pDisplay->mParent->i_getEventSource(),
4091 GuestMonitorChangedEventType_Enabled,
4092 uScreenId,
4093 pFBInfo->xOrigin, pFBInfo->yOrigin,
4094 pFBInfo->w, pFBInfo->h);
4095 }
4096
4097 pDrv->pDisplay->i_handleDisplayResize(uScreenId, pScreen->bitsPerPixel,
4098 (uint8_t *)pvVRAM + pFBInfo->u32Offset,
4099 pScreen->u32LineSize,
4100 pScreen->u16Width, pScreen->u16Height,
4101 VBVA_SCREEN_F_ACTIVE);
4102 }
4103 }
4104 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
4105 {
4106 if (pHdr->u16Length != 0)
4107 {
4108 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
4109 break;
4110 }
4111
4112 break;
4113 }
4114 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS)
4115 {
4116 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOHOSTEVENTS))
4117 {
4118 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
4119 break;
4120 }
4121
4122 VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8;
4123
4124 pFBInfo->pHostEvents = pHostEvents;
4125
4126 LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n",
4127 pHostEvents));
4128 }
4129 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK)
4130 {
4131 if (pHdr->u16Length != sizeof(VBOXVIDEOINFOLINK))
4132 {
4133 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
4134 break;
4135 }
4136
4137 VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8;
4138 pu8 += pLink->i32Offset;
4139 }
4140 else
4141 {
4142 LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type));
4143 }
4144
4145 pu8 += pHdr->u16Length;
4146 }
4147}
4148
4149#ifdef VBOX_WITH_VIDEOHWACCEL
4150
4151#ifndef S_FALSE
4152# define S_FALSE ((HRESULT)1L)
4153#endif
4154
4155int Display::i_handleVHWACommandProcess(PVBOXVHWACMD pCommand)
4156{
4157 unsigned id = (unsigned)pCommand->iDisplay;
4158 int rc = VINF_SUCCESS;
4159 if (id >= mcMonitors)
4160 return VERR_INVALID_PARAMETER;
4161
4162 ComPtr<IFramebuffer> pFramebuffer;
4163 AutoReadLock arlock(this COMMA_LOCKVAL_SRC_POS);
4164 pFramebuffer = maFramebuffers[id].pFramebuffer;
4165 arlock.release();
4166
4167 if (pFramebuffer == NULL)
4168 return VERR_NOT_IMPLEMENTED; /* Implementation is not available. */
4169
4170 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);
4171 if (hr == S_FALSE)
4172 return VINF_SUCCESS;
4173 else if (SUCCEEDED(hr))
4174 return VINF_CALLBACK_RETURN;
4175 else if (hr == E_ACCESSDENIED)
4176 return VERR_INVALID_STATE; /* notify we can not handle request atm */
4177 else if (hr == E_NOTIMPL)
4178 return VERR_NOT_IMPLEMENTED;
4179 return VERR_GENERAL_FAILURE;
4180}
4181
4182DECLCALLBACK(int) Display::i_displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
4183{
4184 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4185
4186 return pDrv->pDisplay->i_handleVHWACommandProcess(pCommand);
4187}
4188#endif
4189
4190#ifdef VBOX_WITH_CRHGSMI
4191void Display::i_handleCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
4192{
4193 mpDrv->pVBVACallbacks->pfnCrHgsmiCommandCompleteAsync(mpDrv->pVBVACallbacks,
4194 (PVBOXVDMACMD_CHROMIUM_CMD)pParam->u.pointer.addr, result);
4195}
4196
4197void Display::i_handleCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam)
4198{
4199 PVBOXVDMACMD_CHROMIUM_CTL pCtl = (PVBOXVDMACMD_CHROMIUM_CTL)pParam->u.pointer.addr;
4200 mpDrv->pVBVACallbacks->pfnCrHgsmiControlCompleteAsync(mpDrv->pVBVACallbacks, pCtl, result);
4201}
4202
4203void Display::i_handleCrHgsmiCommandProcess(PVBOXVDMACMD_CHROMIUM_CMD pCmd, uint32_t cbCmd)
4204{
4205 int rc = VERR_NOT_SUPPORTED;
4206 VBOXHGCMSVCPARM parm;
4207 parm.type = VBOX_HGCM_SVC_PARM_PTR;
4208 parm.u.pointer.addr = pCmd;
4209 parm.u.pointer.size = cbCmd;
4210
4211 if (mhCrOglSvc)
4212 {
4213 VMMDev *pVMMDev = mParent->i_getVMMDev();
4214 if (pVMMDev)
4215 {
4216 /* no completion callback is specified with this call,
4217 * the CrOgl code will complete the CrHgsmi command once it processes it */
4218 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm, NULL, NULL);
4219 AssertRC(rc);
4220 if (RT_SUCCESS(rc))
4221 return;
4222 }
4223 else
4224 rc = VERR_INVALID_STATE;
4225 }
4226
4227 /* we are here because something went wrong with command processing, complete it */
4228 i_handleCrHgsmiCommandCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CMD, &parm);
4229}
4230
4231void Display::i_handleCrHgsmiControlProcess(PVBOXVDMACMD_CHROMIUM_CTL pCtl, uint32_t cbCtl)
4232{
4233 int rc = VERR_NOT_SUPPORTED;
4234 VBOXHGCMSVCPARM parm;
4235 parm.type = VBOX_HGCM_SVC_PARM_PTR;
4236 parm.u.pointer.addr = pCtl;
4237 parm.u.pointer.size = cbCtl;
4238
4239 if (mhCrOglSvc)
4240 {
4241 VMMDev *pVMMDev = mParent->i_getVMMDev();
4242 if (pVMMDev)
4243 {
4244 bool fCheckPendingViewport = (pCtl->enmType == VBOXVDMACMD_CHROMIUM_CTL_TYPE_CRHGSMI_SETUP);
4245 rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm,
4246 Display::i_displayCrHgsmiControlCompletion, this);
4247 AssertRC(rc);
4248 if (RT_SUCCESS(rc))
4249 {
4250 if (fCheckPendingViewport)
4251 {
4252 ULONG ul;
4253 for (ul = 0; ul < mcMonitors; ul++)
4254 {
4255 DISPLAYFBINFO *pFb = &maFramebuffers[ul];
4256 if (!pFb->pendingViewportInfo.fPending)
4257 continue;
4258
4259 rc = i_crViewportNotify(ul, pFb->pendingViewportInfo.x, pFb->pendingViewportInfo.y,
4260 pFb->pendingViewportInfo.width, pFb->pendingViewportInfo.height);
4261 if (RT_SUCCESS(rc))
4262 pFb->pendingViewportInfo.fPending = false;
4263 else
4264 {
4265 AssertMsgFailed(("crViewportNotify failed %d\n", rc));
4266 rc = VINF_SUCCESS;
4267 }
4268 }
4269 }
4270 return;
4271 }
4272 }
4273 else
4274 rc = VERR_INVALID_STATE;
4275 }
4276
4277 /* we are here because something went wrong with command processing, complete it */
4278 i_handleCrHgsmiControlCompletion(rc, SHCRGL_HOST_FN_CRHGSMI_CTL, &parm);
4279}
4280
4281DECLCALLBACK(void) Display::i_displayCrHgsmiCommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CMD pCmd,
4282 uint32_t cbCmd)
4283{
4284 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4285
4286 pDrv->pDisplay->i_handleCrHgsmiCommandProcess(pCmd, cbCmd);
4287}
4288
4289DECLCALLBACK(void) Display::i_displayCrHgsmiControlProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVDMACMD_CHROMIUM_CTL pCmd,
4290 uint32_t cbCmd)
4291{
4292 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4293
4294 pDrv->pDisplay->i_handleCrHgsmiControlProcess(pCmd, cbCmd);
4295}
4296
4297DECLCALLBACK(void) Display::i_displayCrHgsmiCommandCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
4298 void *pvContext)
4299{
4300 AssertMsgFailed(("not expected!"));
4301 Display *pDisplay = (Display *)pvContext;
4302 pDisplay->i_handleCrHgsmiCommandCompletion(result, u32Function, pParam);
4303}
4304
4305DECLCALLBACK(void) Display::i_displayCrHgsmiControlCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
4306 void *pvContext)
4307{
4308 Display *pDisplay = (Display *)pvContext;
4309 pDisplay->i_handleCrHgsmiControlCompletion(result, u32Function, pParam);
4310
4311}
4312#endif
4313
4314#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
4315DECLCALLBACK(void) Display::i_displayCrHgcmCtlSubmitCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam,
4316 void *pvContext)
4317{
4318 VBOXCRCMDCTL *pCmd = (VBOXCRCMDCTL*)pParam->u.pointer.addr;
4319 if (pCmd->u.pfnInternal)
4320 ((PFNCRCTLCOMPLETION)pCmd->u.pfnInternal)(pCmd, pParam->u.pointer.size, result, pvContext);
4321}
4322
4323int Display::i_handleCrHgcmCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
4324 PFNCRCTLCOMPLETION pfnCompletion,
4325 void *pvCompletion)
4326{
4327 VMMDev *pVMMDev = mParent ? mParent->i_getVMMDev() : NULL;
4328 if (!pVMMDev)
4329 {
4330 AssertMsgFailed(("no vmmdev\n"));
4331 return VERR_INVALID_STATE;
4332 }
4333
4334 Assert(mhCrOglSvc);
4335 VBOXHGCMSVCPARM parm;
4336 parm.type = VBOX_HGCM_SVC_PARM_PTR;
4337 parm.u.pointer.addr = pCmd;
4338 parm.u.pointer.size = cbCmd;
4339
4340 pCmd->u.pfnInternal = (void(*)())pfnCompletion;
4341 int rc = pVMMDev->hgcmHostFastCallAsync(mhCrOglSvc, SHCRGL_HOST_FN_CTL, &parm, i_displayCrHgcmCtlSubmitCompletion,
4342 pvCompletion);
4343 if (!RT_SUCCESS(rc))
4344 AssertMsgFailed(("hgcmHostFastCallAsync failed rc %d\n", rc));
4345
4346 return rc;
4347}
4348
4349DECLCALLBACK(int) Display::i_displayCrHgcmCtlSubmit(PPDMIDISPLAYCONNECTOR pInterface,
4350 struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd,
4351 PFNCRCTLCOMPLETION pfnCompletion,
4352 void *pvCompletion)
4353{
4354 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4355 Display *pThis = pDrv->pDisplay;
4356 return pThis->i_handleCrHgcmCtlSubmit(pCmd, cbCmd, pfnCompletion, pvCompletion);
4357}
4358
4359int Display::i_crCtlSubmit(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd, PFNCRCTLCOMPLETION pfnCompletion, void *pvCompletion)
4360{
4361 int rc = RTCritSectRwEnterShared(&mCrOglLock);
4362 if (RT_SUCCESS(rc))
4363 {
4364 if (mhCrOglSvc)
4365 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmit(mpDrv->pVBVACallbacks, pCmd, cbCmd, pfnCompletion, pvCompletion);
4366 else
4367 rc = VERR_NOT_SUPPORTED;
4368
4369 RTCritSectRwLeaveShared(&mCrOglLock);
4370 }
4371 return rc;
4372}
4373
4374int Display::i_crCtlSubmitSync(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
4375{
4376 int rc = RTCritSectRwEnterShared(&mCrOglLock);
4377 if (RT_SUCCESS(rc))
4378 {
4379 if (mhCrOglSvc)
4380 rc = mpDrv->pVBVACallbacks->pfnCrCtlSubmitSync(mpDrv->pVBVACallbacks, pCmd, cbCmd);
4381 else
4382 rc = VERR_NOT_SUPPORTED;
4383
4384 RTCritSectRwLeaveShared(&mCrOglLock);
4385 }
4386 return rc;
4387}
4388
4389int Display::i_crCtlSubmitAsyncCmdCopy(struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
4390{
4391 VBOXCRCMDCTL* pCmdCopy = (VBOXCRCMDCTL*)RTMemAlloc(cbCmd);
4392 if (!pCmdCopy)
4393 {
4394 LogRel(("RTMemAlloc failed\n"));
4395 return VERR_NO_MEMORY;
4396 }
4397
4398 memcpy(pCmdCopy, pCmd, cbCmd);
4399
4400 int rc = i_crCtlSubmit(pCmdCopy, cbCmd, i_displayCrCmdFree, pCmdCopy);
4401 if (RT_FAILURE(rc))
4402 {
4403 LogRel(("crCtlSubmit failed %d\n", rc));
4404 RTMemFree(pCmdCopy);
4405 return rc;
4406 }
4407
4408 return VINF_SUCCESS;
4409}
4410
4411int Display::i_crCtlSubmitSyncIfHasDataForScreen(uint32_t u32ScreenID, struct VBOXCRCMDCTL* pCmd, uint32_t cbCmd)
4412{
4413 int rc = RTCritSectRwEnterShared(&mCrOglLock);
4414 AssertRCReturn(rc, rc);
4415
4416 if (mCrOglCallbacks.pfnHasDataForScreen && mCrOglCallbacks.pfnHasDataForScreen(u32ScreenID))
4417 rc = i_crCtlSubmitSync(pCmd, cbCmd);
4418 else
4419 rc = i_crCtlSubmitAsyncCmdCopy(pCmd, cbCmd);
4420
4421 RTCritSectRwLeaveShared(&mCrOglLock);
4422
4423 return rc;
4424}
4425
4426bool Display::i_handleCrVRecScreenshotBegin(uint32_t uScreen, uint64_t u64TimeStamp)
4427{
4428# if VBOX_WITH_VPX
4429 return VideoRecIsReady(mpVideoRecCtx, uScreen, u64TimeStamp);
4430# else
4431 return false;
4432# endif
4433}
4434
4435void Display::i_handleCrVRecScreenshotEnd(uint32_t uScreen, uint64_t u64TimeStamp)
4436{
4437}
4438
4439void Display::i_handleCrVRecScreenshotPerform(uint32_t uScreen,
4440 uint32_t x, uint32_t y, uint32_t uPixelFormat,
4441 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
4442 uint32_t uGuestWidth, uint32_t uGuestHeight,
4443 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
4444{
4445 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
4446# if VBOX_WITH_VPX
4447 int rc = VideoRecCopyToIntBuf(mpVideoRecCtx, uScreen, x, y,
4448 uPixelFormat,
4449 uBitsPerPixel, uBytesPerLine,
4450 uGuestWidth, uGuestHeight,
4451 pu8BufferAddress, u64TimeStamp);
4452 Assert(rc == VINF_SUCCESS /* || rc == VERR_TRY_AGAIN || rc == VINF_TRY_AGAIN*/);
4453# endif
4454}
4455
4456void Display::i_handleVRecCompletion(int32_t result, uint32_t u32Function, PVBOXHGCMSVCPARM pParam, void *pvContext)
4457{
4458 Assert(mfCrOglVideoRecState == CRVREC_STATE_SUBMITTED);
4459 ASMAtomicWriteU32(&mfCrOglVideoRecState, CRVREC_STATE_IDLE);
4460}
4461
4462DECLCALLBACK(void) Display::i_displayCrVRecScreenshotPerform(void *pvCtx, uint32_t uScreen,
4463 uint32_t x, uint32_t y,
4464 uint32_t uBitsPerPixel, uint32_t uBytesPerLine,
4465 uint32_t uGuestWidth, uint32_t uGuestHeight,
4466 uint8_t *pu8BufferAddress, uint64_t u64TimeStamp)
4467{
4468 Display *pDisplay = (Display *)pvCtx;
4469 pDisplay->i_handleCrVRecScreenshotPerform(uScreen,
4470 x, y, FramebufferPixelFormat_FOURCC_RGB, uBitsPerPixel,
4471 uBytesPerLine, uGuestWidth, uGuestHeight,
4472 pu8BufferAddress, u64TimeStamp);
4473}
4474
4475DECLCALLBACK(bool) Display::i_displayCrVRecScreenshotBegin(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
4476{
4477 Display *pDisplay = (Display *)pvCtx;
4478 return pDisplay->i_handleCrVRecScreenshotBegin(uScreen, u64TimeStamp);
4479}
4480
4481DECLCALLBACK(void) Display::i_displayCrVRecScreenshotEnd(void *pvCtx, uint32_t uScreen, uint64_t u64TimeStamp)
4482{
4483 Display *pDisplay = (Display *)pvCtx;
4484 pDisplay->i_handleCrVRecScreenshotEnd(uScreen, u64TimeStamp);
4485}
4486
4487DECLCALLBACK(void) Display::i_displayVRecCompletion(int32_t result, uint32_t u32Function,
4488 PVBOXHGCMSVCPARM pParam, void *pvContext)
4489{
4490 Display *pDisplay = (Display *)pvContext;
4491 pDisplay->i_handleVRecCompletion(result, u32Function, pParam, pvContext);
4492}
4493
4494#endif
4495
4496
4497#ifdef VBOX_WITH_HGSMI
4498DECLCALLBACK(int) Display::i_displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, PVBVAHOSTFLAGS pHostFlags,
4499 bool fRenderThreadMode)
4500{
4501 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
4502
4503 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4504 Display *pThis = pDrv->pDisplay;
4505
4506 if (pThis->maFramebuffers[uScreenId].fVBVAEnabled && pThis->maFramebuffers[uScreenId].fRenderThreadMode != fRenderThreadMode)
4507 {
4508 LogRel(("enabling different vbva mode"));
4509#ifdef DEBUG_misha
4510 AssertMsgFailed(("enabling different vbva mode"));
4511#endif
4512 return VERR_INVALID_STATE;
4513 }
4514
4515 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;
4516 pThis->maFramebuffers[uScreenId].pVBVAHostFlags = pHostFlags;
4517 pThis->maFramebuffers[uScreenId].fRenderThreadMode = fRenderThreadMode;
4518 pThis->maFramebuffers[uScreenId].fVBVAForceResize = true;
4519
4520 vbvaSetMemoryFlagsHGSMI(uScreenId, pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, &pThis->maFramebuffers[uScreenId]);
4521
4522 return VINF_SUCCESS;
4523}
4524
4525DECLCALLBACK(void) Display::i_displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
4526{
4527 LogRelFlowFunc(("uScreenId %d\n", uScreenId));
4528
4529 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4530 Display *pThis = pDrv->pDisplay;
4531
4532 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4533
4534 bool fRenderThreadMode = pFBInfo->fRenderThreadMode;
4535
4536 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
4537 {
4538 /* Make sure that the primary screen is visible now.
4539 * The guest can't use VBVA anymore, so only only the VGA device output works.
4540 */
4541 if (pFBInfo->fDisabled)
4542 {
4543 pFBInfo->fDisabled = false;
4544 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4545 GuestMonitorChangedEventType_Enabled,
4546 uScreenId,
4547 pFBInfo->xOrigin, pFBInfo->yOrigin,
4548 pFBInfo->w, pFBInfo->h);
4549 }
4550 }
4551
4552 pFBInfo->fVBVAEnabled = false;
4553 pFBInfo->fVBVAForceResize = false;
4554 pFBInfo->fRenderThreadMode = false;
4555
4556 vbvaSetMemoryFlagsHGSMI(uScreenId, 0, false, pFBInfo);
4557
4558 pFBInfo->pVBVAHostFlags = NULL;
4559
4560 if (!fRenderThreadMode && uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
4561 {
4562 /* Force full screen update, because VGA device must take control, do resize, etc. */
4563 Assert(!pThis->i_vbvaLockIsOwner());
4564 pThis->mpDrv->pUpPort->pfnUpdateDisplayAll(pThis->mpDrv->pUpPort, /* fFailOnResize = */ false);
4565 }
4566}
4567
4568DECLCALLBACK(void) Display::i_displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
4569{
4570 LogFlowFunc(("uScreenId %d\n", uScreenId));
4571
4572 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4573 Display *pThis = pDrv->pDisplay;
4574 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4575
4576 if (ASMAtomicReadU32(&pThis->mu32UpdateVBVAFlags) > 0)
4577 {
4578 vbvaSetMemoryFlagsAllHGSMI(pThis->mfu32SupportedOrders, pThis->mfVideoAccelVRDP, pThis->maFramebuffers,
4579 pThis->mcMonitors);
4580 ASMAtomicDecU32(&pThis->mu32UpdateVBVAFlags);
4581 }
4582}
4583
4584DECLCALLBACK(void) Display::i_displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId,
4585 const PVBVACMDHDR pCmd, size_t cbCmd)
4586{
4587 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d, @%d,%d %dx%d\n", uScreenId, pCmd, cbCmd, pCmd->x, pCmd->y, pCmd->w, pCmd->h));
4588
4589 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4590 Display *pThis = pDrv->pDisplay;
4591 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4592
4593 if (pFBInfo->fDefaultFormat)
4594 {
4595 /* Make sure that framebuffer contains the same image as the guest VRAM. */
4596 if ( uScreenId == VBOX_VIDEO_PRIMARY_SCREEN
4597 && !pFBInfo->fDisabled)
4598 {
4599 Assert(!pThis->i_vbvaLockIsOwner());
4600 pDrv->pUpPort->pfnUpdateDisplayRect(pDrv->pUpPort, pCmd->x, pCmd->y, pCmd->w, pCmd->h);
4601 }
4602 else if ( !pFBInfo->pSourceBitmap.isNull()
4603 && !pFBInfo->fDisabled)
4604 {
4605 /* Render VRAM content to the framebuffer. */
4606 BYTE *pAddress = NULL;
4607 ULONG ulWidth = 0;
4608 ULONG ulHeight = 0;
4609 ULONG ulBitsPerPixel = 0;
4610 ULONG ulBytesPerLine = 0;
4611 ULONG ulPixelFormat = 0;
4612
4613 HRESULT hrc = pFBInfo->pSourceBitmap->QueryBitmapInfo(&pAddress,
4614 &ulWidth,
4615 &ulHeight,
4616 &ulBitsPerPixel,
4617 &ulBytesPerLine,
4618 &ulPixelFormat);
4619 if (SUCCEEDED(hrc))
4620 {
4621 uint32_t width = pCmd->w;
4622 uint32_t height = pCmd->h;
4623
4624 const uint8_t *pu8Src = pFBInfo->pu8FramebufferVRAM;
4625 int32_t xSrc = pCmd->x - pFBInfo->xOrigin;
4626 int32_t ySrc = pCmd->y - pFBInfo->yOrigin;
4627 uint32_t u32SrcWidth = pFBInfo->w;
4628 uint32_t u32SrcHeight = pFBInfo->h;
4629 uint32_t u32SrcLineSize = pFBInfo->u32LineSize;
4630 uint32_t u32SrcBitsPerPixel = pFBInfo->u16BitsPerPixel;
4631
4632 uint8_t *pu8Dst = pAddress;
4633 int32_t xDst = xSrc;
4634 int32_t yDst = ySrc;
4635 uint32_t u32DstWidth = u32SrcWidth;
4636 uint32_t u32DstHeight = u32SrcHeight;
4637 uint32_t u32DstLineSize = u32DstWidth * 4;
4638 uint32_t u32DstBitsPerPixel = 32;
4639
4640 Assert(!pThis->i_vbvaLockIsOwner());
4641 pDrv->pUpPort->pfnCopyRect(pDrv->pUpPort,
4642 width, height,
4643 pu8Src,
4644 xSrc, ySrc,
4645 u32SrcWidth, u32SrcHeight,
4646 u32SrcLineSize, u32SrcBitsPerPixel,
4647 pu8Dst,
4648 xDst, yDst,
4649 u32DstWidth, u32DstHeight,
4650 u32DstLineSize, u32DstBitsPerPixel);
4651 }
4652 }
4653 }
4654
4655 VBVACMDHDR hdrSaved = *pCmd;
4656
4657 VBVACMDHDR *pHdrUnconst = (VBVACMDHDR *)pCmd;
4658
4659 pHdrUnconst->x -= (int16_t)pFBInfo->xOrigin;
4660 pHdrUnconst->y -= (int16_t)pFBInfo->yOrigin;
4661
4662 /* @todo new SendUpdate entry which can get a separate cmd header or coords. */
4663 pThis->mParent->i_consoleVRDPServer()->SendUpdate(uScreenId, pCmd, (uint32_t)cbCmd);
4664
4665 *pHdrUnconst = hdrSaved;
4666}
4667
4668DECLCALLBACK(void) Display::i_displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y,
4669 uint32_t cx, uint32_t cy)
4670{
4671 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));
4672
4673 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4674 Display *pThis = pDrv->pDisplay;
4675 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[uScreenId];
4676
4677 /* @todo handleFramebufferUpdate (uScreenId,
4678 * x - pThis->maFramebuffers[uScreenId].xOrigin,
4679 * y - pThis->maFramebuffers[uScreenId].yOrigin,
4680 * cx, cy);
4681 */
4682 pThis->i_handleDisplayUpdate(uScreenId, x - pFBInfo->xOrigin, y - pFBInfo->yOrigin, cx, cy);
4683}
4684
4685#ifdef DEBUG_sunlover
4686static void logVBVAResize(const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, const DISPLAYFBINFO *pFBInfo)
4687{
4688 LogRel(("displayVBVAResize: [%d] %s\n"
4689 " pView->u32ViewIndex %d\n"
4690 " pView->u32ViewOffset 0x%08X\n"
4691 " pView->u32ViewSize 0x%08X\n"
4692 " pView->u32MaxScreenSize 0x%08X\n"
4693 " pScreen->i32OriginX %d\n"
4694 " pScreen->i32OriginY %d\n"
4695 " pScreen->u32StartOffset 0x%08X\n"
4696 " pScreen->u32LineSize 0x%08X\n"
4697 " pScreen->u32Width %d\n"
4698 " pScreen->u32Height %d\n"
4699 " pScreen->u16BitsPerPixel %d\n"
4700 " pScreen->u16Flags 0x%04X\n"
4701 " pFBInfo->u32Offset 0x%08X\n"
4702 " pFBInfo->u32MaxFramebufferSize 0x%08X\n"
4703 " pFBInfo->u32InformationSize 0x%08X\n"
4704 " pFBInfo->fDisabled %d\n"
4705 " xOrigin, yOrigin, w, h: %d,%d %dx%d\n"
4706 " pFBInfo->u16BitsPerPixel %d\n"
4707 " pFBInfo->pu8FramebufferVRAM %p\n"
4708 " pFBInfo->u32LineSize 0x%08X\n"
4709 " pFBInfo->flags 0x%04X\n"
4710 " pFBInfo->pHostEvents %p\n"
4711 " pFBInfo->fDefaultFormat %d\n"
4712 " dirtyRect %d-%d %d-%d\n"
4713 " pFBInfo->fVBVAEnabled %d\n"
4714 " pFBInfo->fVBVAForceResize %d\n"
4715 " pFBInfo->pVBVAHostFlags %p\n"
4716 "",
4717 pScreen->u32ViewIndex,
4718 (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)? "DISABLED": "ENABLED",
4719 pView->u32ViewIndex,
4720 pView->u32ViewOffset,
4721 pView->u32ViewSize,
4722 pView->u32MaxScreenSize,
4723 pScreen->i32OriginX,
4724 pScreen->i32OriginY,
4725 pScreen->u32StartOffset,
4726 pScreen->u32LineSize,
4727 pScreen->u32Width,
4728 pScreen->u32Height,
4729 pScreen->u16BitsPerPixel,
4730 pScreen->u16Flags,
4731 pFBInfo->u32Offset,
4732 pFBInfo->u32MaxFramebufferSize,
4733 pFBInfo->u32InformationSize,
4734 pFBInfo->fDisabled,
4735 pFBInfo->xOrigin,
4736 pFBInfo->yOrigin,
4737 pFBInfo->w,
4738 pFBInfo->h,
4739 pFBInfo->u16BitsPerPixel,
4740 pFBInfo->pu8FramebufferVRAM,
4741 pFBInfo->u32LineSize,
4742 pFBInfo->flags,
4743 pFBInfo->pHostEvents,
4744 pFBInfo->fDefaultFormat,
4745 pFBInfo->dirtyRect.xLeft,
4746 pFBInfo->dirtyRect.xRight,
4747 pFBInfo->dirtyRect.yTop,
4748 pFBInfo->dirtyRect.yBottom,
4749 pFBInfo->fVBVAEnabled,
4750 pFBInfo->fVBVAForceResize,
4751 pFBInfo->pVBVAHostFlags
4752 ));
4753}
4754#endif /* DEBUG_sunlover */
4755
4756DECLCALLBACK(int) Display::i_displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView,
4757 const PVBVAINFOSCREEN pScreen, void *pvVRAM)
4758{
4759 LogRelFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));
4760
4761 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4762 Display *pThis = pDrv->pDisplay;
4763
4764 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];
4765
4766 if (pScreen->u16Flags & VBVA_SCREEN_F_DISABLED)
4767 {
4768 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
4769
4770 pFBInfo->fDisabled = true;
4771 pFBInfo->flags = pScreen->u16Flags;
4772
4773 /* Ask the framebuffer to resize using a default format. The framebuffer will be black.
4774 * So if the frontend does not support GuestMonitorChangedEventType_Disabled event,
4775 * the VM window will be black. */
4776 uint32_t u32Width = pFBInfo->w ? pFBInfo->w : 640;
4777 uint32_t u32Height = pFBInfo->h ? pFBInfo->h : 480;
4778 pThis->i_handleDisplayResize(pScreen->u32ViewIndex, 0, (uint8_t *)NULL, 0,
4779 u32Width, u32Height, pScreen->u16Flags);
4780
4781 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4782 GuestMonitorChangedEventType_Disabled,
4783 pScreen->u32ViewIndex,
4784 0, 0, 0, 0);
4785 return VINF_SUCCESS;
4786 }
4787
4788 /* If display was disabled or there is no framebuffer, a resize will be required,
4789 * because the framebuffer was/will be changed.
4790 */
4791 bool fResize = pFBInfo->fDisabled || pFBInfo->pFramebuffer.isNull();
4792
4793 if (pFBInfo->fVBVAForceResize)
4794 {
4795 /* VBVA was just enabled. Do the resize. */
4796 fResize = true;
4797 pFBInfo->fVBVAForceResize = false;
4798 }
4799
4800 /* Check if this is a real resize or a notification about the screen origin.
4801 * The guest uses this VBVAResize call for both.
4802 */
4803 fResize = fResize
4804 || pFBInfo->u16BitsPerPixel != pScreen->u16BitsPerPixel
4805 || pFBInfo->pu8FramebufferVRAM != (uint8_t *)pvVRAM + pScreen->u32StartOffset
4806 || pFBInfo->u32LineSize != pScreen->u32LineSize
4807 || pFBInfo->w != pScreen->u32Width
4808 || pFBInfo->h != pScreen->u32Height;
4809
4810 bool fNewOrigin = pFBInfo->xOrigin != pScreen->i32OriginX
4811 || pFBInfo->yOrigin != pScreen->i32OriginY;
4812
4813 if (fNewOrigin || fResize)
4814 pThis->i_notifyCroglResize(pView, pScreen, pvVRAM);
4815
4816 if (pFBInfo->fDisabled)
4817 {
4818 pFBInfo->fDisabled = false;
4819 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4820 GuestMonitorChangedEventType_Enabled,
4821 pScreen->u32ViewIndex,
4822 pScreen->i32OriginX, pScreen->i32OriginY,
4823 pScreen->u32Width, pScreen->u32Height);
4824 /* Continue to update pFBInfo. */
4825 }
4826
4827 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */
4828 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */
4829 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */
4830
4831 pFBInfo->xOrigin = pScreen->i32OriginX;
4832 pFBInfo->yOrigin = pScreen->i32OriginY;
4833
4834 pFBInfo->w = pScreen->u32Width;
4835 pFBInfo->h = pScreen->u32Height;
4836
4837 pFBInfo->u16BitsPerPixel = pScreen->u16BitsPerPixel;
4838 pFBInfo->pu8FramebufferVRAM = (uint8_t *)pvVRAM + pScreen->u32StartOffset;
4839 pFBInfo->u32LineSize = pScreen->u32LineSize;
4840
4841 pFBInfo->flags = pScreen->u16Flags;
4842
4843 if (fNewOrigin)
4844 {
4845 fireGuestMonitorChangedEvent(pThis->mParent->i_getEventSource(),
4846 GuestMonitorChangedEventType_NewOrigin,
4847 pScreen->u32ViewIndex,
4848 pScreen->i32OriginX, pScreen->i32OriginY,
4849 0, 0);
4850 }
4851
4852 if (!fResize)
4853 {
4854 /* No parameters of the framebuffer have actually changed. */
4855 if (fNewOrigin)
4856 {
4857 /* VRDP server still need this notification. */
4858 LogRelFlowFunc(("Calling VRDP\n"));
4859 pThis->mParent->i_consoleVRDPServer()->SendResize();
4860 }
4861 return VINF_SUCCESS;
4862 }
4863
4864 /* Do a regular resize. */
4865 return pThis->i_handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
4866 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
4867 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height, pScreen->u16Flags);
4868}
4869
4870DECLCALLBACK(int) Display::i_displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
4871 uint32_t xHot, uint32_t yHot,
4872 uint32_t cx, uint32_t cy,
4873 const void *pvShape)
4874{
4875 LogFlowFunc(("\n"));
4876
4877 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
4878 Display *pThis = pDrv->pDisplay;
4879
4880 size_t cbShapeSize = 0;
4881
4882 if (pvShape)
4883 {
4884 cbShapeSize = (cx + 7) / 8 * cy; /* size of the AND mask */
4885 cbShapeSize = ((cbShapeSize + 3) & ~3) + cx * 4 * cy; /* + gap + size of the XOR mask */
4886 }
4887 com::SafeArray<BYTE> shapeData(cbShapeSize);
4888
4889 if (pvShape)
4890 ::memcpy(shapeData.raw(), pvShape, cbShapeSize);
4891
4892 /* Tell the console about it */
4893 pDrv->pDisplay->mParent->i_onMousePointerShapeChange(fVisible, fAlpha,
4894 xHot, yHot, cx, cy, ComSafeArrayAsInParam(shapeData));
4895
4896 return VINF_SUCCESS;
4897}
4898#endif /* VBOX_WITH_HGSMI */
4899
4900/**
4901 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
4902 */
4903DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
4904{
4905 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
4906 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4907 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
4908 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);
4909 return NULL;
4910}
4911
4912
4913/**
4914 * Destruct a display driver instance.
4915 *
4916 * @returns VBox status.
4917 * @param pDrvIns The driver instance data.
4918 */
4919DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)
4920{
4921 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
4922 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4923 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
4924
4925 if (pThis->pDisplay)
4926 Assert(!pThis->pDisplay->i_vbvaLockIsOwner());
4927
4928 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
4929
4930 pThis->IConnector.pu8Data = NULL;
4931 pThis->IConnector.cbScanline = 0;
4932 pThis->IConnector.cBits = 32;
4933 pThis->IConnector.cx = 0;
4934 pThis->IConnector.cy = 0;
4935
4936 if (pThis->pDisplay)
4937 {
4938 AutoWriteLock displayLock(pThis->pDisplay COMMA_LOCKVAL_SRC_POS);
4939#ifdef VBOX_WITH_VPX
4940 pThis->pDisplay->i_VideoCaptureStop();
4941#endif
4942#ifdef VBOX_WITH_CRHGSMI
4943 pThis->pDisplay->i_destructCrHgsmiData();
4944#endif
4945 pThis->pDisplay->mpDrv = NULL;
4946 pThis->pDisplay->mpVMMDev = NULL;
4947 }
4948}
4949
4950
4951/**
4952 * Construct a display driver instance.
4953 *
4954 * @copydoc FNPDMDRVCONSTRUCT
4955 */
4956DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
4957{
4958 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
4959 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
4960 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
4961
4962 /*
4963 * Validate configuration.
4964 */
4965 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
4966 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
4967 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
4968 ("Configuration error: Not possible to attach anything to this driver!\n"),
4969 VERR_PDM_DRVINS_NO_ATTACH);
4970
4971 /*
4972 * Init Interfaces.
4973 */
4974 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;
4975
4976 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;
4977 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;
4978 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;
4979 pThis->IConnector.pfnReset = Display::i_displayResetCallback;
4980 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;
4981 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;
4982 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;
4983#ifdef VBOX_WITH_VIDEOHWACCEL
4984 pThis->IConnector.pfnVHWACommandProcess = Display::i_displayVHWACommandProcess;
4985#endif
4986#ifdef VBOX_WITH_CRHGSMI
4987 pThis->IConnector.pfnCrHgsmiCommandProcess = Display::i_displayCrHgsmiCommandProcess;
4988 pThis->IConnector.pfnCrHgsmiControlProcess = Display::i_displayCrHgsmiControlProcess;
4989#endif
4990#if defined(VBOX_WITH_HGCM) && defined(VBOX_WITH_CROGL)
4991 pThis->IConnector.pfnCrHgcmCtlSubmit = Display::i_displayCrHgcmCtlSubmit;
4992#endif
4993#ifdef VBOX_WITH_HGSMI
4994 pThis->IConnector.pfnVBVAEnable = Display::i_displayVBVAEnable;
4995 pThis->IConnector.pfnVBVADisable = Display::i_displayVBVADisable;
4996 pThis->IConnector.pfnVBVAUpdateBegin = Display::i_displayVBVAUpdateBegin;
4997 pThis->IConnector.pfnVBVAUpdateProcess = Display::i_displayVBVAUpdateProcess;
4998 pThis->IConnector.pfnVBVAUpdateEnd = Display::i_displayVBVAUpdateEnd;
4999 pThis->IConnector.pfnVBVAResize = Display::i_displayVBVAResize;
5000 pThis->IConnector.pfnVBVAMousePointerShape = Display::i_displayVBVAMousePointerShape;
5001#endif
5002
5003 /*
5004 * Get the IDisplayPort interface of the above driver/device.
5005 */
5006 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);
5007 if (!pThis->pUpPort)
5008 {
5009 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
5010 return VERR_PDM_MISSING_INTERFACE_ABOVE;
5011 }
5012#if defined(VBOX_WITH_VIDEOHWACCEL) || defined(VBOX_WITH_CRHGSMI)
5013 pThis->pVBVACallbacks = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYVBVACALLBACKS);
5014 if (!pThis->pVBVACallbacks)
5015 {
5016 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
5017 return VERR_PDM_MISSING_INTERFACE_ABOVE;
5018 }
5019#endif
5020 /*
5021 * Get the Display object pointer and update the mpDrv member.
5022 */
5023 void *pv;
5024 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
5025 if (RT_FAILURE(rc))
5026 {
5027 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
5028 return rc;
5029 }
5030 Display *pDisplay = (Display *)pv; /** @todo Check this cast! */
5031 pThis->pDisplay = pDisplay;
5032 pThis->pDisplay->mpDrv = pThis;
5033
5034 /* Disable VRAM to a buffer copy initially. */
5035 Assert(!pDisplay->i_vbvaLockIsOwner());
5036 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
5037 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */
5038
5039 /*
5040 * Start periodic screen refreshes
5041 */
5042 Assert(!pDisplay->i_vbvaLockIsOwner());
5043 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);
5044
5045#ifdef VBOX_WITH_CRHGSMI
5046 pDisplay->i_setupCrHgsmiData();
5047#endif
5048
5049#ifdef VBOX_WITH_VPX
5050 ComPtr<IMachine> pMachine = pDisplay->mParent->i_machine();
5051 BOOL fEnabled = false;
5052 HRESULT hrc = pMachine->COMGETTER(VideoCaptureEnabled)(&fEnabled);
5053 AssertComRCReturn(hrc, VERR_COM_UNEXPECTED);
5054 if (fEnabled)
5055 {
5056 rc = pDisplay->i_VideoCaptureStart();
5057 fireVideoCaptureChangedEvent(pDisplay->mParent->i_getEventSource());
5058 }
5059#endif
5060
5061 return rc;
5062}
5063
5064
5065/**
5066 * Display driver registration record.
5067 */
5068const PDMDRVREG Display::DrvReg =
5069{
5070 /* u32Version */
5071 PDM_DRVREG_VERSION,
5072 /* szName */
5073 "MainDisplay",
5074 /* szRCMod */
5075 "",
5076 /* szR0Mod */
5077 "",
5078 /* pszDescription */
5079 "Main display driver (Main as in the API).",
5080 /* fFlags */
5081 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
5082 /* fClass. */
5083 PDM_DRVREG_CLASS_DISPLAY,
5084 /* cMaxInstances */
5085 ~0U,
5086 /* cbInstance */
5087 sizeof(DRVMAINDISPLAY),
5088 /* pfnConstruct */
5089 Display::i_drvConstruct,
5090 /* pfnDestruct */
5091 Display::i_drvDestruct,
5092 /* pfnRelocate */
5093 NULL,
5094 /* pfnIOCtl */
5095 NULL,
5096 /* pfnPowerOn */
5097 NULL,
5098 /* pfnReset */
5099 NULL,
5100 /* pfnSuspend */
5101 NULL,
5102 /* pfnResume */
5103 NULL,
5104 /* pfnAttach */
5105 NULL,
5106 /* pfnDetach */
5107 NULL,
5108 /* pfnPowerOff */
5109 NULL,
5110 /* pfnSoftReset */
5111 NULL,
5112 /* u32EndVersion */
5113 PDM_DRVREG_VERSION
5114};
5115
5116/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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