VirtualBox

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

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

crOpenGL/Main: fix assertion

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

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