VirtualBox

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

Last change on this file since 38869 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

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

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