VirtualBox

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

最後變更 在這個檔案從51620是 51612,由 vboxsync 提交於 11 年 前

6813 Use of server side API wrapper code - ConsoleImpl.cpp

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

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