VirtualBox

source: vbox/trunk/src/VBox/Main/DisplayImpl.cpp@ 22663

Last change on this file since 22663 was 22480, checked in by vboxsync, 15 years ago

SSM,VMM,Devices,Main,VBoxBFE: Live snapshot/migration SSM API adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.5 KB
Line 
1/* $Id: DisplayImpl.cpp 22480 2009-08-26 17:14:13Z vboxsync $ */
2
3/** @file
4 *
5 * VirtualBox COM class implementation
6 */
7
8/*
9 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "DisplayImpl.h"
25#include "ConsoleImpl.h"
26#include "ConsoleVRDPServer.h"
27#include "VMMDev.h"
28
29#include "Logging.h"
30
31#include <iprt/semaphore.h>
32#include <iprt/thread.h>
33#include <iprt/asm.h>
34
35#include <VBox/pdmdrv.h>
36#ifdef DEBUG /* for VM_ASSERT_EMT(). */
37# include <VBox/vm.h>
38#endif
39
40#ifdef VBOX_WITH_VIDEOHWACCEL
41# include <VBox/VBoxVideo.h>
42#endif
43/**
44 * Display driver instance data.
45 */
46typedef struct DRVMAINDISPLAY
47{
48 /** Pointer to the display object. */
49 Display *pDisplay;
50 /** Pointer to the driver instance structure. */
51 PPDMDRVINS pDrvIns;
52 /** Pointer to the keyboard port interface of the driver/device above us. */
53 PPDMIDISPLAYPORT pUpPort;
54 /** Our display connector interface. */
55 PDMIDISPLAYCONNECTOR Connector;
56#if defined(VBOX_WITH_VIDEOHWACCEL)
57 /** VBVA callbacks */
58 PPDMDDISPLAYVBVACALLBACKS pVBVACallbacks;
59#endif
60} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
61
62/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
63#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) ( (PDRVMAINDISPLAY) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINDISPLAY, Connector)) )
64
65#ifdef DEBUG_sunlover
66static STAMPROFILE StatDisplayRefresh;
67static int stam = 0;
68#endif /* DEBUG_sunlover */
69
70// constructor / destructor
71/////////////////////////////////////////////////////////////////////////////
72
73DEFINE_EMPTY_CTOR_DTOR (Display)
74
75HRESULT Display::FinalConstruct()
76{
77 mpVbvaMemory = NULL;
78 mfVideoAccelEnabled = false;
79 mfVideoAccelVRDP = false;
80 mfu32SupportedOrders = 0;
81 mcVideoAccelVRDPRefs = 0;
82
83 mpPendingVbvaMemory = NULL;
84 mfPendingVideoAccelEnable = false;
85
86 mfMachineRunning = false;
87
88 mpu8VbvaPartial = NULL;
89 mcbVbvaPartial = 0;
90
91 mpDrv = NULL;
92 mpVMMDev = NULL;
93 mfVMMDevInited = false;
94
95 mLastAddress = NULL;
96 mLastBytesPerLine = 0;
97 mLastBitsPerPixel = 0,
98 mLastWidth = 0;
99 mLastHeight = 0;
100
101 return S_OK;
102}
103
104void Display::FinalRelease()
105{
106 uninit();
107}
108
109// public initializer/uninitializer for internal purposes only
110/////////////////////////////////////////////////////////////////////////////
111
112#define sSSMDisplayVer 0x00010001
113
114/**
115 * Save/Load some important guest state
116 */
117DECLCALLBACK(void)
118Display::displaySSMSave(PSSMHANDLE pSSM, void *pvUser)
119{
120 Display *that = static_cast<Display*>(pvUser);
121
122 SSMR3PutU32(pSSM, that->mcMonitors);
123 for (unsigned i = 0; i < that->mcMonitors; i++)
124 {
125 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32Offset);
126 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32MaxFramebufferSize);
127 SSMR3PutU32(pSSM, that->maFramebuffers[i].u32InformationSize);
128 }
129}
130
131DECLCALLBACK(int)
132Display::displaySSMLoad(PSSMHANDLE pSSM, void *pvUser, uint32_t uVersion, uint32_t uPhase)
133{
134 Display *that = static_cast<Display*>(pvUser);
135
136 if (uVersion != sSSMDisplayVer)
137 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
138
139 uint32_t cMonitors;
140 int rc = SSMR3GetU32(pSSM, &cMonitors);
141 if (cMonitors != that->mcMonitors)
142 {
143 LogRel(("Display: Number of monitors changed (%d->%d)!\n",
144 cMonitors, that->mcMonitors));
145 return VERR_SSM_LOAD_CONFIG_MISMATCH;
146 }
147
148 for (uint32_t i = 0; i < cMonitors; i++)
149 {
150 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32Offset);
151 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32MaxFramebufferSize);
152 SSMR3GetU32(pSSM, &that->maFramebuffers[i].u32InformationSize);
153 }
154
155 return VINF_SUCCESS;
156}
157
158/**
159 * Initializes the display object.
160 *
161 * @returns COM result indicator
162 * @param parent handle of our parent object
163 * @param qemuConsoleData address of common console data structure
164 */
165HRESULT Display::init (Console *aParent)
166{
167 LogFlowThisFunc(("aParent=%p\n", aParent));
168
169 ComAssertRet (aParent, E_INVALIDARG);
170
171 /* Enclose the state transition NotReady->InInit->Ready */
172 AutoInitSpan autoInitSpan(this);
173 AssertReturn(autoInitSpan.isOk(), E_FAIL);
174
175 unconst(mParent) = aParent;
176
177 // by default, we have an internal framebuffer which is
178 // NULL, i.e. a black hole for no display output
179 mFramebufferOpened = false;
180
181 ULONG ul;
182 mParent->machine()->COMGETTER(MonitorCount)(&ul);
183 mcMonitors = ul;
184
185 for (ul = 0; ul < mcMonitors; ul++)
186 {
187 maFramebuffers[ul].u32Offset = 0;
188 maFramebuffers[ul].u32MaxFramebufferSize = 0;
189 maFramebuffers[ul].u32InformationSize = 0;
190
191 maFramebuffers[ul].pFramebuffer = NULL;
192
193 maFramebuffers[ul].xOrigin = 0;
194 maFramebuffers[ul].yOrigin = 0;
195
196 maFramebuffers[ul].w = 0;
197 maFramebuffers[ul].h = 0;
198
199 maFramebuffers[ul].pHostEvents = NULL;
200
201 maFramebuffers[ul].u32ResizeStatus = ResizeStatus_Void;
202
203 maFramebuffers[ul].fDefaultFormat = false;
204
205 memset (&maFramebuffers[ul].dirtyRect, 0 , sizeof (maFramebuffers[ul].dirtyRect));
206 memset (&maFramebuffers[ul].pendingResize, 0 , sizeof (maFramebuffers[ul].pendingResize));
207#ifdef VBOX_WITH_HGSMI
208 maFramebuffers[ul].fVBVAEnabled = false;
209#endif /* VBOX_WITH_HGSMI */
210 }
211
212 mParent->RegisterCallback (this);
213
214 /* Confirm a successful initialization */
215 autoInitSpan.setSucceeded();
216
217 return S_OK;
218}
219
220/**
221 * Uninitializes the instance and sets the ready flag to FALSE.
222 * Called either from FinalRelease() or by the parent when it gets destroyed.
223 */
224void Display::uninit()
225{
226 LogFlowThisFunc(("\n"));
227
228 /* Enclose the state transition Ready->InUninit->NotReady */
229 AutoUninitSpan autoUninitSpan(this);
230 if (autoUninitSpan.uninitDone())
231 return;
232
233 ULONG ul;
234 for (ul = 0; ul < mcMonitors; ul++)
235 maFramebuffers[ul].pFramebuffer = NULL;
236
237 if (mParent)
238 mParent->UnregisterCallback (this);
239
240 unconst(mParent).setNull();
241
242 if (mpDrv)
243 mpDrv->pDisplay = NULL;
244
245 mpDrv = NULL;
246 mpVMMDev = NULL;
247 mfVMMDevInited = true;
248}
249
250/**
251 * Register the SSM methods. Called by the power up thread to be able to
252 * pass pVM
253 */
254int Display::registerSSM(PVM pVM)
255{
256 int rc = SSMR3RegisterExternal(pVM, "DisplayData", 0, sSSMDisplayVer,
257 mcMonitors * sizeof(uint32_t) * 3 + sizeof(uint32_t),
258 NULL, NULL, NULL,
259 NULL, displaySSMSave, NULL,
260 NULL, displaySSMLoad, NULL, this);
261
262 AssertRCReturn(rc, rc);
263
264 /*
265 * Register loaders for old saved states where iInstance was 3 * sizeof(uint32_t *).
266 */
267 rc = SSMR3RegisterExternal(pVM, "DisplayData", 12 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
268 NULL, NULL, NULL,
269 NULL, NULL, NULL,
270 NULL, displaySSMLoad, NULL, this);
271 AssertRCReturn(rc, rc);
272
273 rc = SSMR3RegisterExternal(pVM, "DisplayData", 24 /*uInstance*/, sSSMDisplayVer, 0 /*cbGuess*/,
274 NULL, NULL, NULL,
275 NULL, NULL, NULL,
276 NULL, displaySSMLoad, NULL, this);
277 AssertRCReturn(rc, rc);
278 return VINF_SUCCESS;
279}
280
281// IConsoleCallback method
282STDMETHODIMP Display::OnStateChange(MachineState_T machineState)
283{
284 if (machineState == MachineState_Running)
285 {
286 LogFlowFunc (("Machine is running.\n"));
287
288 mfMachineRunning = true;
289 }
290 else
291 mfMachineRunning = false;
292
293 return S_OK;
294}
295
296// public methods only for internal purposes
297/////////////////////////////////////////////////////////////////////////////
298
299/**
300 * @thread EMT
301 */
302static int callFramebufferResize (IFramebuffer *pFramebuffer, unsigned uScreenId,
303 ULONG pixelFormat, void *pvVRAM,
304 uint32_t bpp, uint32_t cbLine,
305 int w, int h)
306{
307 Assert (pFramebuffer);
308
309 /* Call the framebuffer to try and set required pixelFormat. */
310 BOOL finished = TRUE;
311
312 pFramebuffer->RequestResize (uScreenId, pixelFormat, (BYTE *) pvVRAM,
313 bpp, cbLine, w, h, &finished);
314
315 if (!finished)
316 {
317 LogFlowFunc (("External framebuffer wants us to wait!\n"));
318 return VINF_VGA_RESIZE_IN_PROGRESS;
319 }
320
321 return VINF_SUCCESS;
322}
323
324/**
325 * Handles display resize event.
326 * Disables access to VGA device;
327 * calls the framebuffer RequestResize method;
328 * if framebuffer resizes synchronously,
329 * updates the display connector data and enables access to the VGA device.
330 *
331 * @param w New display width
332 * @param h New display height
333 *
334 * @thread EMT
335 */
336int Display::handleDisplayResize (unsigned uScreenId, uint32_t bpp, void *pvVRAM,
337 uint32_t cbLine, int w, int h)
338{
339 LogRel (("Display::handleDisplayResize(): uScreenId = %d, pvVRAM=%p "
340 "w=%d h=%d bpp=%d cbLine=0x%X\n",
341 uScreenId, pvVRAM, w, h, bpp, cbLine));
342
343 /* If there is no framebuffer, this call is not interesting. */
344 if ( uScreenId >= mcMonitors
345 || maFramebuffers[uScreenId].pFramebuffer.isNull())
346 {
347 return VINF_SUCCESS;
348 }
349
350 mLastAddress = pvVRAM;
351 mLastBytesPerLine = cbLine;
352 mLastBitsPerPixel = bpp,
353 mLastWidth = w;
354 mLastHeight = h;
355
356 ULONG pixelFormat;
357
358 switch (bpp)
359 {
360 case 32:
361 case 24:
362 case 16:
363 pixelFormat = FramebufferPixelFormat_FOURCC_RGB;
364 break;
365 default:
366 pixelFormat = FramebufferPixelFormat_Opaque;
367 bpp = cbLine = 0;
368 break;
369 }
370
371 /* Atomically set the resize status before calling the framebuffer. The new InProgress status will
372 * disable access to the VGA device by the EMT thread.
373 */
374 bool f = ASMAtomicCmpXchgU32 (&maFramebuffers[uScreenId].u32ResizeStatus,
375 ResizeStatus_InProgress, ResizeStatus_Void);
376 if (!f)
377 {
378 /* This could be a result of the screenshot taking call Display::TakeScreenShot:
379 * if the framebuffer is processing the resize request and GUI calls the TakeScreenShot
380 * and the guest has reprogrammed the virtual VGA devices again so a new resize is required.
381 *
382 * Save the resize information and return the pending status code.
383 *
384 * Note: the resize information is only accessed on EMT so no serialization is required.
385 */
386 LogRel (("Display::handleDisplayResize(): Warning: resize postponed.\n"));
387
388 maFramebuffers[uScreenId].pendingResize.fPending = true;
389 maFramebuffers[uScreenId].pendingResize.pixelFormat = pixelFormat;
390 maFramebuffers[uScreenId].pendingResize.pvVRAM = pvVRAM;
391 maFramebuffers[uScreenId].pendingResize.bpp = bpp;
392 maFramebuffers[uScreenId].pendingResize.cbLine = cbLine;
393 maFramebuffers[uScreenId].pendingResize.w = w;
394 maFramebuffers[uScreenId].pendingResize.h = h;
395
396 return VINF_VGA_RESIZE_IN_PROGRESS;
397 }
398
399 int rc = callFramebufferResize (maFramebuffers[uScreenId].pFramebuffer, uScreenId,
400 pixelFormat, pvVRAM, bpp, cbLine, w, h);
401 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
402 {
403 /* Immediately return to the caller. ResizeCompleted will be called back by the
404 * GUI thread. The ResizeCompleted callback will change the resize status from
405 * InProgress to UpdateDisplayData. The latter status will be checked by the
406 * display timer callback on EMT and all required adjustments will be done there.
407 */
408 return rc;
409 }
410
411 /* Set the status so the 'handleResizeCompleted' would work. */
412 f = ASMAtomicCmpXchgU32 (&maFramebuffers[uScreenId].u32ResizeStatus,
413 ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
414 AssertRelease(f);NOREF(f);
415
416 AssertRelease(!maFramebuffers[uScreenId].pendingResize.fPending);
417
418 /* The method also unlocks the framebuffer. */
419 handleResizeCompletedEMT();
420
421 return VINF_SUCCESS;
422}
423
424/**
425 * Framebuffer has been resized.
426 * Read the new display data and unlock the framebuffer.
427 *
428 * @thread EMT
429 */
430void Display::handleResizeCompletedEMT (void)
431{
432 LogFlowFunc(("\n"));
433
434 unsigned uScreenId;
435 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
436 {
437 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
438
439 /* Try to into non resizing state. */
440 bool f = ASMAtomicCmpXchgU32 (&pFBInfo->u32ResizeStatus, ResizeStatus_Void, ResizeStatus_UpdateDisplayData);
441
442 if (f == false)
443 {
444 /* This is not the display that has completed resizing. */
445 continue;
446 }
447
448 /* Check whether a resize is pending for this framebuffer. */
449 if (pFBInfo->pendingResize.fPending)
450 {
451 /* Reset the condition, call the display resize with saved data and continue.
452 *
453 * Note: handleDisplayResize can call handleResizeCompletedEMT back,
454 * but infinite recursion is not possible, because when the handleResizeCompletedEMT
455 * is called, the pFBInfo->pendingResize.fPending is equal to false.
456 */
457 pFBInfo->pendingResize.fPending = false;
458 handleDisplayResize (uScreenId, pFBInfo->pendingResize.bpp, pFBInfo->pendingResize.pvVRAM,
459 pFBInfo->pendingResize.cbLine, pFBInfo->pendingResize.w, pFBInfo->pendingResize.h);
460 continue;
461 }
462
463 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN && !pFBInfo->pFramebuffer.isNull())
464 {
465 /* Primary framebuffer has completed the resize. Update the connector data for VGA device. */
466 updateDisplayData();
467
468 /* Check the framebuffer pixel format to setup the rendering in VGA device. */
469 BOOL usesGuestVRAM = FALSE;
470 pFBInfo->pFramebuffer->COMGETTER(UsesGuestVRAM) (&usesGuestVRAM);
471
472 pFBInfo->fDefaultFormat = (usesGuestVRAM == FALSE);
473
474 mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, pFBInfo->fDefaultFormat);
475 }
476
477#ifdef DEBUG_sunlover
478 if (!stam)
479 {
480 /* protect mpVM */
481 Console::SafeVMPtr pVM (mParent);
482 AssertComRC (pVM.rc());
483
484 STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
485 stam = 1;
486 }
487#endif /* DEBUG_sunlover */
488
489 /* Inform VRDP server about the change of display parameters. */
490 LogFlowFunc (("Calling VRDP\n"));
491 mParent->consoleVRDPServer()->SendResize();
492 }
493}
494
495static void checkCoordBounds (int *px, int *py, int *pw, int *ph, int cx, int cy)
496{
497 /* Correct negative x and y coordinates. */
498 if (*px < 0)
499 {
500 *px += *pw; /* Compute xRight which is also the new width. */
501
502 *pw = (*px < 0)? 0: *px;
503
504 *px = 0;
505 }
506
507 if (*py < 0)
508 {
509 *py += *ph; /* Compute xBottom, which is also the new height. */
510
511 *ph = (*py < 0)? 0: *py;
512
513 *py = 0;
514 }
515
516 /* Also check if coords are greater than the display resolution. */
517 if (*px + *pw > cx)
518 {
519 *pw = cx > *px? cx - *px: 0;
520 }
521
522 if (*py + *ph > cy)
523 {
524 *ph = cy > *py? cy - *py: 0;
525 }
526}
527
528unsigned mapCoordsToScreen(DISPLAYFBINFO *pInfos, unsigned cInfos, int *px, int *py, int *pw, int *ph)
529{
530 DISPLAYFBINFO *pInfo = pInfos;
531 unsigned uScreenId;
532 LogSunlover (("mapCoordsToScreen: %d,%d %dx%d\n", *px, *py, *pw, *ph));
533 for (uScreenId = 0; uScreenId < cInfos; uScreenId++, pInfo++)
534 {
535 LogSunlover ((" [%d] %d,%d %dx%d\n", uScreenId, pInfo->xOrigin, pInfo->yOrigin, pInfo->w, pInfo->h));
536 if ( (pInfo->xOrigin <= *px && *px < pInfo->xOrigin + (int)pInfo->w)
537 && (pInfo->yOrigin <= *py && *py < pInfo->yOrigin + (int)pInfo->h))
538 {
539 /* The rectangle belongs to the screen. Correct coordinates. */
540 *px -= pInfo->xOrigin;
541 *py -= pInfo->yOrigin;
542 LogSunlover ((" -> %d,%d", *px, *py));
543 break;
544 }
545 }
546 if (uScreenId == cInfos)
547 {
548 /* Map to primary screen. */
549 uScreenId = 0;
550 }
551 LogSunlover ((" scr %d\n", uScreenId));
552 return uScreenId;
553}
554
555
556/**
557 * Handles display update event.
558 *
559 * @param x Update area x coordinate
560 * @param y Update area y coordinate
561 * @param w Update area width
562 * @param h Update area height
563 *
564 * @thread EMT
565 */
566void Display::handleDisplayUpdate (int x, int y, int w, int h)
567{
568#ifdef DEBUG_sunlover
569 LogFlowFunc (("%d,%d %dx%d (%d,%d)\n",
570 x, y, w, h, mpDrv->Connector.cx, mpDrv->Connector.cy));
571#endif /* DEBUG_sunlover */
572
573 unsigned uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
574
575#ifdef DEBUG_sunlover
576 LogFlowFunc (("%d,%d %dx%d (checked)\n", x, y, w, h));
577#endif /* DEBUG_sunlover */
578
579 IFramebuffer *pFramebuffer = maFramebuffers[uScreenId].pFramebuffer;
580
581 // if there is no framebuffer, this call is not interesting
582 if (pFramebuffer == NULL)
583 return;
584
585 pFramebuffer->Lock();
586
587 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
588 checkCoordBounds (&x, &y, &w, &h, mpDrv->Connector.cx, mpDrv->Connector.cy);
589 else
590 checkCoordBounds (&x, &y, &w, &h, maFramebuffers[uScreenId].w,
591 maFramebuffers[uScreenId].h);
592
593 if (w != 0 && h != 0)
594 pFramebuffer->NotifyUpdate(x, y, w, h);
595
596 pFramebuffer->Unlock();
597
598#ifndef VBOX_WITH_HGSMI
599 if (!mfVideoAccelEnabled)
600 {
601#else
602 if (!mfVideoAccelEnabled && !maFramebuffers[uScreenId].fVBVAEnabled)
603 {
604#endif /* VBOX_WITH_HGSMI */
605 /* When VBVA is enabled, the VRDP server is informed in the VideoAccelFlush.
606 * Inform the server here only if VBVA is disabled.
607 */
608 if (maFramebuffers[uScreenId].u32ResizeStatus == ResizeStatus_Void)
609 mParent->consoleVRDPServer()->SendUpdateBitmap(uScreenId, x, y, w, h);
610 }
611}
612
613typedef struct _VBVADIRTYREGION
614{
615 /* Copies of object's pointers used by vbvaRgn functions. */
616 DISPLAYFBINFO *paFramebuffers;
617 unsigned cMonitors;
618 Display *pDisplay;
619 PPDMIDISPLAYPORT pPort;
620
621} VBVADIRTYREGION;
622
623static void vbvaRgnInit (VBVADIRTYREGION *prgn, DISPLAYFBINFO *paFramebuffers, unsigned cMonitors, Display *pd, PPDMIDISPLAYPORT pp)
624{
625 prgn->paFramebuffers = paFramebuffers;
626 prgn->cMonitors = cMonitors;
627 prgn->pDisplay = pd;
628 prgn->pPort = pp;
629
630 unsigned uScreenId;
631 for (uScreenId = 0; uScreenId < cMonitors; uScreenId++)
632 {
633 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
634
635 memset (&pFBInfo->dirtyRect, 0, sizeof (pFBInfo->dirtyRect));
636 }
637}
638
639static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, unsigned uScreenId, VBVACMDHDR *phdr)
640{
641 LogSunlover (("x = %d, y = %d, w = %d, h = %d\n",
642 phdr->x, phdr->y, phdr->w, phdr->h));
643
644 /*
645 * Here update rectangles are accumulated to form an update area.
646 * @todo
647 * Now the simpliest method is used which builds one rectangle that
648 * includes all update areas. A bit more advanced method can be
649 * employed here. The method should be fast however.
650 */
651 if (phdr->w == 0 || phdr->h == 0)
652 {
653 /* Empty rectangle. */
654 return;
655 }
656
657 int32_t xRight = phdr->x + phdr->w;
658 int32_t yBottom = phdr->y + phdr->h;
659
660 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
661
662 if (pFBInfo->dirtyRect.xRight == 0)
663 {
664 /* This is the first rectangle to be added. */
665 pFBInfo->dirtyRect.xLeft = phdr->x;
666 pFBInfo->dirtyRect.yTop = phdr->y;
667 pFBInfo->dirtyRect.xRight = xRight;
668 pFBInfo->dirtyRect.yBottom = yBottom;
669 }
670 else
671 {
672 /* Adjust region coordinates. */
673 if (pFBInfo->dirtyRect.xLeft > phdr->x)
674 {
675 pFBInfo->dirtyRect.xLeft = phdr->x;
676 }
677
678 if (pFBInfo->dirtyRect.yTop > phdr->y)
679 {
680 pFBInfo->dirtyRect.yTop = phdr->y;
681 }
682
683 if (pFBInfo->dirtyRect.xRight < xRight)
684 {
685 pFBInfo->dirtyRect.xRight = xRight;
686 }
687
688 if (pFBInfo->dirtyRect.yBottom < yBottom)
689 {
690 pFBInfo->dirtyRect.yBottom = yBottom;
691 }
692 }
693
694 if (pFBInfo->fDefaultFormat)
695 {
696 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
697 prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
698 prgn->pDisplay->handleDisplayUpdate (phdr->x + pFBInfo->xOrigin,
699 phdr->y + pFBInfo->yOrigin, phdr->w, phdr->h);
700 }
701
702 return;
703}
704
705static void vbvaRgnUpdateFramebuffer (VBVADIRTYREGION *prgn, unsigned uScreenId)
706{
707 DISPLAYFBINFO *pFBInfo = &prgn->paFramebuffers[uScreenId];
708
709 uint32_t w = pFBInfo->dirtyRect.xRight - pFBInfo->dirtyRect.xLeft;
710 uint32_t h = pFBInfo->dirtyRect.yBottom - pFBInfo->dirtyRect.yTop;
711
712 if (!pFBInfo->fDefaultFormat && pFBInfo->pFramebuffer && w != 0 && h != 0)
713 {
714 //@todo pfnUpdateDisplayRect must take the vram offset parameter for the framebuffer
715 prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, pFBInfo->dirtyRect.xLeft, pFBInfo->dirtyRect.yTop, w, h);
716 prgn->pDisplay->handleDisplayUpdate (pFBInfo->dirtyRect.xLeft + pFBInfo->xOrigin,
717 pFBInfo->dirtyRect.yTop + pFBInfo->yOrigin, w, h);
718 }
719}
720
721static void vbvaSetMemoryFlags (VBVAMEMORY *pVbvaMemory,
722 bool fVideoAccelEnabled,
723 bool fVideoAccelVRDP,
724 uint32_t fu32SupportedOrders,
725 DISPLAYFBINFO *paFBInfos,
726 unsigned cFBInfos)
727{
728 if (pVbvaMemory)
729 {
730 /* This called only on changes in mode. So reset VRDP always. */
731 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
732
733 if (fVideoAccelEnabled)
734 {
735 fu32Flags |= VBVA_F_MODE_ENABLED;
736
737 if (fVideoAccelVRDP)
738 {
739 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
740
741 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
742 }
743 }
744
745 pVbvaMemory->fu32ModeFlags = fu32Flags;
746 }
747
748 unsigned uScreenId;
749 for (uScreenId = 0; uScreenId < cFBInfos; uScreenId++)
750 {
751 if (paFBInfos[uScreenId].pHostEvents)
752 {
753 paFBInfos[uScreenId].pHostEvents->fu32Events |= VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET;
754 }
755 }
756}
757
758bool Display::VideoAccelAllowed (void)
759{
760 return true;
761}
762
763/**
764 * @thread EMT
765 */
766int Display::VideoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory)
767{
768 int rc = VINF_SUCCESS;
769
770 /* Called each time the guest wants to use acceleration,
771 * or when the VGA device disables acceleration,
772 * or when restoring the saved state with accel enabled.
773 *
774 * VGA device disables acceleration on each video mode change
775 * and on reset.
776 *
777 * Guest enabled acceleration at will. And it has to enable
778 * acceleration after a mode change.
779 */
780 LogFlowFunc (("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
781 mfVideoAccelEnabled, fEnable, pVbvaMemory));
782
783 /* Strictly check parameters. Callers must not pass anything in the case. */
784 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
785
786 if (!VideoAccelAllowed ())
787 {
788 return VERR_NOT_SUPPORTED;
789 }
790
791 /*
792 * Verify that the VM is in running state. If it is not,
793 * then this must be postponed until it goes to running.
794 */
795 if (!mfMachineRunning)
796 {
797 Assert (!mfVideoAccelEnabled);
798
799 LogFlowFunc (("Machine is not yet running.\n"));
800
801 if (fEnable)
802 {
803 mfPendingVideoAccelEnable = fEnable;
804 mpPendingVbvaMemory = pVbvaMemory;
805 }
806
807 return rc;
808 }
809
810 /* Check that current status is not being changed */
811 if (mfVideoAccelEnabled == fEnable)
812 {
813 return rc;
814 }
815
816 if (mfVideoAccelEnabled)
817 {
818 /* Process any pending orders and empty the VBVA ring buffer. */
819 VideoAccelFlush ();
820 }
821
822 if (!fEnable && mpVbvaMemory)
823 {
824 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
825 }
826
827 /* Safety precaution. There is no more VBVA until everything is setup! */
828 mpVbvaMemory = NULL;
829 mfVideoAccelEnabled = false;
830
831 /* Update entire display. */
832 if (maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].u32ResizeStatus == ResizeStatus_Void)
833 {
834 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort);
835 }
836
837 /* Everything OK. VBVA status can be changed. */
838
839 /* Notify the VMMDev, which saves VBVA status in the saved state,
840 * and needs to know current status.
841 */
842 PPDMIVMMDEVPORT pVMMDevPort = mParent->getVMMDev()->getVMMDevPort ();
843
844 if (pVMMDevPort)
845 {
846 pVMMDevPort->pfnVBVAChange (pVMMDevPort, fEnable);
847 }
848
849 if (fEnable)
850 {
851 mpVbvaMemory = pVbvaMemory;
852 mfVideoAccelEnabled = true;
853
854 /* Initialize the hardware memory. */
855 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
856 mpVbvaMemory->off32Data = 0;
857 mpVbvaMemory->off32Free = 0;
858
859 memset (mpVbvaMemory->aRecords, 0, sizeof (mpVbvaMemory->aRecords));
860 mpVbvaMemory->indexRecordFirst = 0;
861 mpVbvaMemory->indexRecordFree = 0;
862
863 LogRel(("VBVA: Enabled.\n"));
864 }
865 else
866 {
867 LogRel(("VBVA: Disabled.\n"));
868 }
869
870 LogFlowFunc (("VideoAccelEnable: rc = %Rrc.\n", rc));
871
872 return rc;
873}
874
875#ifdef VBOX_WITH_VRDP
876/* Called always by one VRDP server thread. Can be thread-unsafe.
877 */
878void Display::VideoAccelVRDP (bool fEnable)
879{
880 int c = fEnable?
881 ASMAtomicIncS32 (&mcVideoAccelVRDPRefs):
882 ASMAtomicDecS32 (&mcVideoAccelVRDPRefs);
883
884 Assert (c >= 0);
885
886 if (c == 0)
887 {
888 /* The last client has disconnected, and the accel can be
889 * disabled.
890 */
891 Assert (fEnable == false);
892
893 mfVideoAccelVRDP = false;
894 mfu32SupportedOrders = 0;
895
896 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
897
898 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
899 }
900 else if ( c == 1
901 && !mfVideoAccelVRDP)
902 {
903 /* The first client has connected. Enable the accel.
904 */
905 Assert (fEnable == true);
906
907 mfVideoAccelVRDP = true;
908 /* Supporting all orders. */
909 mfu32SupportedOrders = ~0;
910
911 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders, maFramebuffers, mcMonitors);
912
913 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
914 }
915 else
916 {
917 /* A client is connected or disconnected but there is no change in the
918 * accel state. It remains enabled.
919 */
920 Assert (mfVideoAccelVRDP == true);
921 }
922}
923#endif /* VBOX_WITH_VRDP */
924
925static bool vbvaVerifyRingBuffer (VBVAMEMORY *pVbvaMemory)
926{
927 return true;
928}
929
930static void vbvaFetchBytes (VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
931{
932 if (cbDst >= VBVA_RING_BUFFER_SIZE)
933 {
934 AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X", cbDst, VBVA_RING_BUFFER_SIZE));
935 return;
936 }
937
938 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
939 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
940 int32_t i32Diff = cbDst - u32BytesTillBoundary;
941
942 if (i32Diff <= 0)
943 {
944 /* Chunk will not cross buffer boundary. */
945 memcpy (pu8Dst, src, cbDst);
946 }
947 else
948 {
949 /* Chunk crosses buffer boundary. */
950 memcpy (pu8Dst, src, u32BytesTillBoundary);
951 memcpy (pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
952 }
953
954 /* Advance data offset. */
955 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
956
957 return;
958}
959
960
961static bool vbvaPartialRead (uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
962{
963 uint8_t *pu8New;
964
965 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
966 *ppu8, *pcb, cbRecord));
967
968 if (*ppu8)
969 {
970 Assert (*pcb);
971 pu8New = (uint8_t *)RTMemRealloc (*ppu8, cbRecord);
972 }
973 else
974 {
975 Assert (!*pcb);
976 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
977 }
978
979 if (!pu8New)
980 {
981 /* Memory allocation failed, fail the function. */
982 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
983 cbRecord));
984
985 if (*ppu8)
986 {
987 RTMemFree (*ppu8);
988 }
989
990 *ppu8 = NULL;
991 *pcb = 0;
992
993 return false;
994 }
995
996 /* Fetch data from the ring buffer. */
997 vbvaFetchBytes (pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
998
999 *ppu8 = pu8New;
1000 *pcb = cbRecord;
1001
1002 return true;
1003}
1004
1005/* For contiguous chunks just return the address in the buffer.
1006 * For crossing boundary - allocate a buffer from heap.
1007 */
1008bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
1009{
1010 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst;
1011 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree;
1012
1013#ifdef DEBUG_sunlover
1014 LogFlowFunc (("first = %d, free = %d\n",
1015 indexRecordFirst, indexRecordFree));
1016#endif /* DEBUG_sunlover */
1017
1018 if (!vbvaVerifyRingBuffer (mpVbvaMemory))
1019 {
1020 return false;
1021 }
1022
1023 if (indexRecordFirst == indexRecordFree)
1024 {
1025 /* No records to process. Return without assigning output variables. */
1026 return true;
1027 }
1028
1029 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];
1030
1031#ifdef DEBUG_sunlover
1032 LogFlowFunc (("cbRecord = 0x%08X\n", pRecord->cbRecord));
1033#endif /* DEBUG_sunlover */
1034
1035 uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL;
1036
1037 if (mcbVbvaPartial)
1038 {
1039 /* There is a partial read in process. Continue with it. */
1040
1041 Assert (mpu8VbvaPartial);
1042
1043 LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
1044 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
1045
1046 if (cbRecord > mcbVbvaPartial)
1047 {
1048 /* New data has been added to the record. */
1049 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
1050 {
1051 return false;
1052 }
1053 }
1054
1055 if (!(pRecord->cbRecord & VBVA_F_RECORD_PARTIAL))
1056 {
1057 /* The record is completed by guest. Return it to the caller. */
1058 *ppHdr = (VBVACMDHDR *)mpu8VbvaPartial;
1059 *pcbCmd = mcbVbvaPartial;
1060
1061 mpu8VbvaPartial = NULL;
1062 mcbVbvaPartial = 0;
1063
1064 /* Advance the record index. */
1065 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
1066
1067#ifdef DEBUG_sunlover
1068 LogFlowFunc (("partial done ok, data = %d, free = %d\n",
1069 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1070#endif /* DEBUG_sunlover */
1071 }
1072
1073 return true;
1074 }
1075
1076 /* A new record need to be processed. */
1077 if (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)
1078 {
1079 /* Current record is being written by guest. '=' is important here. */
1080 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
1081 {
1082 /* Partial read must be started. */
1083 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
1084 {
1085 return false;
1086 }
1087
1088 LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
1089 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
1090 }
1091
1092 return true;
1093 }
1094
1095 /* Current record is complete. If it is not empty, process it. */
1096 if (cbRecord)
1097 {
1098 /* The size of largest contiguos chunk in the ring biffer. */
1099 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;
1100
1101 /* The ring buffer pointer. */
1102 uint8_t *au8RingBuffer = &mpVbvaMemory->au8RingBuffer[0];
1103
1104 /* The pointer to data in the ring buffer. */
1105 uint8_t *src = &au8RingBuffer[mpVbvaMemory->off32Data];
1106
1107 /* Fetch or point the data. */
1108 if (u32BytesTillBoundary >= cbRecord)
1109 {
1110 /* The command does not cross buffer boundary. Return address in the buffer. */
1111 *ppHdr = (VBVACMDHDR *)src;
1112
1113 /* Advance data offset. */
1114 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
1115 }
1116 else
1117 {
1118 /* The command crosses buffer boundary. Rare case, so not optimized. */
1119 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
1120
1121 if (!dst)
1122 {
1123 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
1124 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
1125 return false;
1126 }
1127
1128 vbvaFetchBytes (mpVbvaMemory, dst, cbRecord);
1129
1130 *ppHdr = (VBVACMDHDR *)dst;
1131
1132#ifdef DEBUG_sunlover
1133 LogFlowFunc (("Allocated from heap %p\n", dst));
1134#endif /* DEBUG_sunlover */
1135 }
1136 }
1137
1138 *pcbCmd = cbRecord;
1139
1140 /* Advance the record index. */
1141 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
1142
1143#ifdef DEBUG_sunlover
1144 LogFlowFunc (("done ok, data = %d, free = %d\n",
1145 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1146#endif /* DEBUG_sunlover */
1147
1148 return true;
1149}
1150
1151void Display::vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd)
1152{
1153 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;
1154
1155 if ( (uint8_t *)pHdr >= au8RingBuffer
1156 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
1157 {
1158 /* The pointer is inside ring buffer. Must be continuous chunk. */
1159 Assert (VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
1160
1161 /* Do nothing. */
1162
1163 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
1164 }
1165 else
1166 {
1167 /* The pointer is outside. It is then an allocated copy. */
1168
1169#ifdef DEBUG_sunlover
1170 LogFlowFunc (("Free heap %p\n", pHdr));
1171#endif /* DEBUG_sunlover */
1172
1173 if ((uint8_t *)pHdr == mpu8VbvaPartial)
1174 {
1175 mpu8VbvaPartial = NULL;
1176 mcbVbvaPartial = 0;
1177 }
1178 else
1179 {
1180 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
1181 }
1182
1183 RTMemFree (pHdr);
1184 }
1185
1186 return;
1187}
1188
1189
1190/**
1191 * Called regularly on the DisplayRefresh timer.
1192 * Also on behalf of guest, when the ring buffer is full.
1193 *
1194 * @thread EMT
1195 */
1196void Display::VideoAccelFlush (void)
1197{
1198#ifdef DEBUG_sunlover_2
1199 LogFlowFunc (("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));
1200#endif /* DEBUG_sunlover_2 */
1201
1202 if (!mfVideoAccelEnabled)
1203 {
1204 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
1205 return;
1206 }
1207
1208 /* Here VBVA is enabled and we have the accelerator memory pointer. */
1209 Assert(mpVbvaMemory);
1210
1211#ifdef DEBUG_sunlover_2
1212 LogFlowFunc (("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
1213 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1214#endif /* DEBUG_sunlover_2 */
1215
1216 /* Quick check for "nothing to update" case. */
1217 if (mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)
1218 {
1219 return;
1220 }
1221
1222 /* Process the ring buffer */
1223 unsigned uScreenId;
1224 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
1225 {
1226 if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
1227 {
1228 maFramebuffers[uScreenId].pFramebuffer->Lock ();
1229 }
1230 }
1231
1232 /* Initialize dirty rectangles accumulator. */
1233 VBVADIRTYREGION rgn;
1234 vbvaRgnInit (&rgn, maFramebuffers, mcMonitors, this, mpDrv->pUpPort);
1235
1236 for (;;)
1237 {
1238 VBVACMDHDR *phdr = NULL;
1239 uint32_t cbCmd = ~0;
1240
1241 /* Fetch the command data. */
1242 if (!vbvaFetchCmd (&phdr, &cbCmd))
1243 {
1244 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
1245 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1246
1247 /* Disable VBVA on those processing errors. */
1248 VideoAccelEnable (false, NULL);
1249
1250 break;
1251 }
1252
1253 if (cbCmd == uint32_t(~0))
1254 {
1255 /* No more commands yet in the queue. */
1256 break;
1257 }
1258
1259 if (cbCmd != 0)
1260 {
1261#ifdef DEBUG_sunlover
1262 LogFlowFunc (("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
1263 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
1264#endif /* DEBUG_sunlover */
1265
1266 VBVACMDHDR hdrSaved = *phdr;
1267
1268 int x = phdr->x;
1269 int y = phdr->y;
1270 int w = phdr->w;
1271 int h = phdr->h;
1272
1273 uScreenId = mapCoordsToScreen(maFramebuffers, mcMonitors, &x, &y, &w, &h);
1274
1275 phdr->x = (int16_t)x;
1276 phdr->y = (int16_t)y;
1277 phdr->w = (uint16_t)w;
1278 phdr->h = (uint16_t)h;
1279
1280 DISPLAYFBINFO *pFBInfo = &maFramebuffers[uScreenId];
1281
1282 if (pFBInfo->u32ResizeStatus == ResizeStatus_Void)
1283 {
1284 /* Handle the command.
1285 *
1286 * Guest is responsible for updating the guest video memory.
1287 * The Windows guest does all drawing using Eng*.
1288 *
1289 * For local output, only dirty rectangle information is used
1290 * to update changed areas.
1291 *
1292 * Dirty rectangles are accumulated to exclude overlapping updates and
1293 * group small updates to a larger one.
1294 */
1295
1296 /* Accumulate the update. */
1297 vbvaRgnDirtyRect (&rgn, uScreenId, phdr);
1298
1299 /* Forward the command to VRDP server. */
1300 mParent->consoleVRDPServer()->SendUpdate (uScreenId, phdr, cbCmd);
1301
1302 *phdr = hdrSaved;
1303 }
1304 }
1305
1306 vbvaReleaseCmd (phdr, cbCmd);
1307 }
1308
1309 for (uScreenId = 0; uScreenId < mcMonitors; uScreenId++)
1310 {
1311 if (!maFramebuffers[uScreenId].pFramebuffer.isNull())
1312 {
1313 maFramebuffers[uScreenId].pFramebuffer->Unlock ();
1314 }
1315
1316 if (maFramebuffers[uScreenId].u32ResizeStatus == ResizeStatus_Void)
1317 {
1318 /* Draw the framebuffer. */
1319 vbvaRgnUpdateFramebuffer (&rgn, uScreenId);
1320 }
1321 }
1322}
1323
1324
1325// IDisplay properties
1326/////////////////////////////////////////////////////////////////////////////
1327
1328/**
1329 * Returns the current display width in pixel
1330 *
1331 * @returns COM status code
1332 * @param width Address of result variable.
1333 */
1334STDMETHODIMP Display::COMGETTER(Width) (ULONG *width)
1335{
1336 CheckComArgNotNull(width);
1337
1338 AutoCaller autoCaller(this);
1339 CheckComRCReturnRC(autoCaller.rc());
1340
1341 AutoWriteLock alock(this);
1342
1343 CHECK_CONSOLE_DRV (mpDrv);
1344
1345 *width = mpDrv->Connector.cx;
1346
1347 return S_OK;
1348}
1349
1350/**
1351 * Returns the current display height in pixel
1352 *
1353 * @returns COM status code
1354 * @param height Address of result variable.
1355 */
1356STDMETHODIMP Display::COMGETTER(Height) (ULONG *height)
1357{
1358 CheckComArgNotNull(height);
1359
1360 AutoCaller autoCaller(this);
1361 CheckComRCReturnRC(autoCaller.rc());
1362
1363 AutoWriteLock alock(this);
1364
1365 CHECK_CONSOLE_DRV (mpDrv);
1366
1367 *height = mpDrv->Connector.cy;
1368
1369 return S_OK;
1370}
1371
1372/**
1373 * Returns the current display color depth in bits
1374 *
1375 * @returns COM status code
1376 * @param bitsPerPixel Address of result variable.
1377 */
1378STDMETHODIMP Display::COMGETTER(BitsPerPixel) (ULONG *bitsPerPixel)
1379{
1380 if (!bitsPerPixel)
1381 return E_INVALIDARG;
1382
1383 AutoCaller autoCaller(this);
1384 CheckComRCReturnRC(autoCaller.rc());
1385
1386 AutoWriteLock alock(this);
1387
1388 CHECK_CONSOLE_DRV (mpDrv);
1389
1390 uint32_t cBits = 0;
1391 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1392 AssertRC(rc);
1393 *bitsPerPixel = cBits;
1394
1395 return S_OK;
1396}
1397
1398
1399// IDisplay methods
1400/////////////////////////////////////////////////////////////////////////////
1401
1402STDMETHODIMP Display::SetFramebuffer (ULONG aScreenId,
1403 IFramebuffer *aFramebuffer)
1404{
1405 LogFlowFunc (("\n"));
1406
1407 if (aFramebuffer != NULL)
1408 CheckComArgOutPointerValid(aFramebuffer);
1409
1410 AutoCaller autoCaller(this);
1411 CheckComRCReturnRC(autoCaller.rc());
1412
1413 AutoWriteLock alock(this);
1414
1415 Console::SafeVMPtrQuiet pVM (mParent);
1416 if (pVM.isOk())
1417 {
1418 /* Must leave the lock here because the changeFramebuffer will
1419 * also obtain it. */
1420 alock.leave ();
1421
1422 /* send request to the EMT thread */
1423 PVMREQ pReq = NULL;
1424 int vrc = VMR3ReqCall (pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
1425 (PFNRT) changeFramebuffer, 3, this, aFramebuffer, aScreenId);
1426 if (RT_SUCCESS(vrc))
1427 vrc = pReq->iStatus;
1428 VMR3ReqFree (pReq);
1429
1430 alock.enter ();
1431
1432 ComAssertRCRet (vrc, E_FAIL);
1433 }
1434 else
1435 {
1436 /* No VM is created (VM is powered off), do a direct call */
1437 int vrc = changeFramebuffer (this, aFramebuffer, aScreenId);
1438 ComAssertRCRet (vrc, E_FAIL);
1439 }
1440
1441 return S_OK;
1442}
1443
1444STDMETHODIMP Display::GetFramebuffer (ULONG aScreenId,
1445 IFramebuffer **aFramebuffer, LONG *aXOrigin, LONG *aYOrigin)
1446{
1447 LogFlowFunc (("aScreenId = %d\n", aScreenId));
1448
1449 CheckComArgOutPointerValid(aFramebuffer);
1450
1451 AutoCaller autoCaller(this);
1452 CheckComRCReturnRC(autoCaller.rc());
1453
1454 AutoWriteLock alock(this);
1455
1456 /* @todo this should be actually done on EMT. */
1457 DISPLAYFBINFO *pFBInfo = &maFramebuffers[aScreenId];
1458
1459 *aFramebuffer = pFBInfo->pFramebuffer;
1460 if (*aFramebuffer)
1461 (*aFramebuffer)->AddRef ();
1462 if (aXOrigin)
1463 *aXOrigin = pFBInfo->xOrigin;
1464 if (aYOrigin)
1465 *aYOrigin = pFBInfo->yOrigin;
1466
1467 return S_OK;
1468}
1469
1470STDMETHODIMP Display::SetVideoModeHint(ULONG aWidth, ULONG aHeight,
1471 ULONG aBitsPerPixel, ULONG aDisplay)
1472{
1473 AutoCaller autoCaller(this);
1474 CheckComRCReturnRC(autoCaller.rc());
1475
1476 AutoWriteLock alock(this);
1477
1478 CHECK_CONSOLE_DRV (mpDrv);
1479
1480 /*
1481 * Do some rough checks for valid input
1482 */
1483 ULONG width = aWidth;
1484 if (!width)
1485 width = mpDrv->Connector.cx;
1486 ULONG height = aHeight;
1487 if (!height)
1488 height = mpDrv->Connector.cy;
1489 ULONG bpp = aBitsPerPixel;
1490 if (!bpp)
1491 {
1492 uint32_t cBits = 0;
1493 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1494 AssertRC(rc);
1495 bpp = cBits;
1496 }
1497 ULONG cMonitors;
1498 mParent->machine()->COMGETTER(MonitorCount)(&cMonitors);
1499 if (cMonitors == 0 && aDisplay > 0)
1500 return E_INVALIDARG;
1501 if (aDisplay >= cMonitors)
1502 return E_INVALIDARG;
1503
1504// sunlover 20070614: It is up to the guest to decide whether the hint is valid.
1505// ULONG vramSize;
1506// mParent->machine()->COMGETTER(VRAMSize)(&vramSize);
1507// /* enough VRAM? */
1508// if ((width * height * (bpp / 8)) > (vramSize * 1024 * 1024))
1509// return setError(E_FAIL, tr("Not enough VRAM for the selected video mode"));
1510
1511 /* Have to leave the lock because the pfnRequestDisplayChange
1512 * will call EMT. */
1513 alock.leave ();
1514 if (mParent->getVMMDev())
1515 mParent->getVMMDev()->getVMMDevPort()->
1516 pfnRequestDisplayChange (mParent->getVMMDev()->getVMMDevPort(),
1517 aWidth, aHeight, aBitsPerPixel, aDisplay);
1518 return S_OK;
1519}
1520
1521STDMETHODIMP Display::SetSeamlessMode (BOOL enabled)
1522{
1523 AutoCaller autoCaller(this);
1524 CheckComRCReturnRC(autoCaller.rc());
1525
1526 AutoWriteLock alock(this);
1527
1528 /* Have to leave the lock because the pfnRequestSeamlessChange will call EMT. */
1529 alock.leave ();
1530 if (mParent->getVMMDev())
1531 mParent->getVMMDev()->getVMMDevPort()->
1532 pfnRequestSeamlessChange (mParent->getVMMDev()->getVMMDevPort(),
1533 !!enabled);
1534 return S_OK;
1535}
1536
1537STDMETHODIMP Display::TakeScreenShot (BYTE *address, ULONG width, ULONG height)
1538{
1539 /// @todo (r=dmik) this function may take too long to complete if the VM
1540 // is doing something like saving state right now. Which, in case if it
1541 // is called on the GUI thread, will make it unresponsive. We should
1542 // check the machine state here (by enclosing the check and VMRequCall
1543 // within the Console lock to make it atomic).
1544
1545 LogFlowFuncEnter();
1546 LogFlowFunc (("address=%p, width=%d, height=%d\n",
1547 address, width, height));
1548
1549 CheckComArgNotNull(address);
1550 CheckComArgExpr(width, width != 0);
1551 CheckComArgExpr(height, height != 0);
1552
1553 AutoCaller autoCaller(this);
1554 CheckComRCReturnRC(autoCaller.rc());
1555
1556 AutoWriteLock alock(this);
1557
1558 CHECK_CONSOLE_DRV (mpDrv);
1559
1560 Console::SafeVMPtr pVM (mParent);
1561 CheckComRCReturnRC(pVM.rc());
1562
1563 HRESULT rc = S_OK;
1564
1565 LogFlowFunc (("Sending SCREENSHOT request\n"));
1566
1567 /*
1568 * First try use the graphics device features for making a snapshot.
1569 * This does not support stretching, is an optional feature (returns
1570 * not supported).
1571 *
1572 * Note: It may cause a display resize. Watch out for deadlocks.
1573 */
1574 int rcVBox = VERR_NOT_SUPPORTED;
1575 if ( mpDrv->Connector.cx == width
1576 && mpDrv->Connector.cy == height)
1577 {
1578 PVMREQ pReq;
1579 size_t cbData = RT_ALIGN_Z(width, 4) * 4 * height;
1580 rcVBox = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
1581 (PFNRT)mpDrv->pUpPort->pfnSnapshot, 6, mpDrv->pUpPort,
1582 address, cbData, (uintptr_t)NULL, (uintptr_t)NULL, (uintptr_t)NULL);
1583 if (RT_SUCCESS(rcVBox))
1584 {
1585 rcVBox = pReq->iStatus;
1586 VMR3ReqFree(pReq);
1587 }
1588 }
1589
1590 /*
1591 * If the function returns not supported, or if stretching is requested,
1592 * we'll have to do all the work ourselves using the framebuffer data.
1593 */
1594 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1595 {
1596 /** @todo implement snapshot stretching & generic snapshot fallback. */
1597 rc = setError (E_NOTIMPL, tr ("This feature is not implemented"));
1598 }
1599 else if (RT_FAILURE(rcVBox))
1600 rc = setError (VBOX_E_IPRT_ERROR,
1601 tr ("Could not take a screenshot (%Rrc)"), rcVBox);
1602
1603 LogFlowFunc (("rc=%08X\n", rc));
1604 LogFlowFuncLeave();
1605 return rc;
1606}
1607
1608STDMETHODIMP Display::TakeScreenShotSlow (ULONG width, ULONG height,
1609 ComSafeArrayOut(BYTE, aScreenData))
1610{
1611 HRESULT rc = S_OK;
1612
1613 rc = setError (E_NOTIMPL, tr ("This feature is not implemented"));
1614
1615 return rc;
1616}
1617
1618
1619STDMETHODIMP Display::DrawToScreen (BYTE *address, ULONG x, ULONG y,
1620 ULONG width, ULONG height)
1621{
1622 /// @todo (r=dmik) this function may take too long to complete if the VM
1623 // is doing something like saving state right now. Which, in case if it
1624 // is called on the GUI thread, will make it unresponsive. We should
1625 // check the machine state here (by enclosing the check and VMRequCall
1626 // within the Console lock to make it atomic).
1627
1628 LogFlowFuncEnter();
1629 LogFlowFunc (("address=%p, x=%d, y=%d, width=%d, height=%d\n",
1630 (void *)address, x, y, width, height));
1631
1632 CheckComArgNotNull(address);
1633 CheckComArgExpr(width, width != 0);
1634 CheckComArgExpr(height, height != 0);
1635
1636 AutoCaller autoCaller(this);
1637 CheckComRCReturnRC(autoCaller.rc());
1638
1639 AutoWriteLock alock(this);
1640
1641 CHECK_CONSOLE_DRV (mpDrv);
1642
1643 Console::SafeVMPtr pVM (mParent);
1644 CheckComRCReturnRC(pVM.rc());
1645
1646 /*
1647 * Again we're lazy and make the graphics device do all the
1648 * dirty conversion work.
1649 */
1650 PVMREQ pReq;
1651 int rcVBox = VMR3ReqCall(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
1652 (PFNRT)mpDrv->pUpPort->pfnDisplayBlt, 6, mpDrv->pUpPort,
1653 address, x, y, width, height);
1654 if (RT_SUCCESS(rcVBox))
1655 {
1656 rcVBox = pReq->iStatus;
1657 VMR3ReqFree(pReq);
1658 }
1659
1660 /*
1661 * If the function returns not supported, we'll have to do all the
1662 * work ourselves using the framebuffer.
1663 */
1664 HRESULT rc = S_OK;
1665 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1666 {
1667 /** @todo implement generic fallback for screen blitting. */
1668 rc = E_NOTIMPL;
1669 }
1670 else if (RT_FAILURE(rcVBox))
1671 rc = setError (VBOX_E_IPRT_ERROR,
1672 tr ("Could not draw to the screen (%Rrc)"), rcVBox);
1673//@todo
1674// else
1675// {
1676// /* All ok. Redraw the screen. */
1677// handleDisplayUpdate (x, y, width, height);
1678// }
1679
1680 LogFlowFunc (("rc=%08X\n", rc));
1681 LogFlowFuncLeave();
1682 return rc;
1683}
1684
1685/**
1686 * Does a full invalidation of the VM display and instructs the VM
1687 * to update it immediately.
1688 *
1689 * @returns COM status code
1690 */
1691STDMETHODIMP Display::InvalidateAndUpdate()
1692{
1693 LogFlowFuncEnter();
1694
1695 AutoCaller autoCaller(this);
1696 CheckComRCReturnRC(autoCaller.rc());
1697
1698 AutoWriteLock alock(this);
1699
1700 CHECK_CONSOLE_DRV (mpDrv);
1701
1702 Console::SafeVMPtr pVM (mParent);
1703 CheckComRCReturnRC(pVM.rc());
1704
1705 HRESULT rc = S_OK;
1706
1707 LogFlowFunc (("Sending DPYUPDATE request\n"));
1708
1709 /* Have to leave the lock when calling EMT. */
1710 alock.leave ();
1711
1712 /* pdm.h says that this has to be called from the EMT thread */
1713 PVMREQ pReq;
1714 int rcVBox = VMR3ReqCallVoid(pVM, VMCPUID_ANY, &pReq, RT_INDEFINITE_WAIT,
1715 (PFNRT)mpDrv->pUpPort->pfnUpdateDisplayAll, 1, mpDrv->pUpPort);
1716 if (RT_SUCCESS(rcVBox))
1717 VMR3ReqFree(pReq);
1718
1719 alock.enter ();
1720
1721 if (RT_FAILURE(rcVBox))
1722 rc = setError (VBOX_E_IPRT_ERROR,
1723 tr ("Could not invalidate and update the screen (%Rrc)"), rcVBox);
1724
1725 LogFlowFunc (("rc=%08X\n", rc));
1726 LogFlowFuncLeave();
1727 return rc;
1728}
1729
1730/**
1731 * Notification that the framebuffer has completed the
1732 * asynchronous resize processing
1733 *
1734 * @returns COM status code
1735 */
1736STDMETHODIMP Display::ResizeCompleted(ULONG aScreenId)
1737{
1738 LogFlowFunc (("\n"));
1739
1740 /// @todo (dmik) can we AutoWriteLock alock(this); here?
1741 // do it when we switch this class to VirtualBoxBase_NEXT.
1742 // This will require general code review and may add some details.
1743 // In particular, we may want to check whether EMT is really waiting for
1744 // this notification, etc. It might be also good to obey the caller to make
1745 // sure this method is not called from more than one thread at a time
1746 // (and therefore don't use Display lock at all here to save some
1747 // milliseconds).
1748 AutoCaller autoCaller(this);
1749 CheckComRCReturnRC(autoCaller.rc());
1750
1751 /* this is only valid for external framebuffers */
1752 if (maFramebuffers[aScreenId].pFramebuffer == NULL)
1753 return setError (VBOX_E_NOT_SUPPORTED,
1754 tr ("Resize completed notification is valid only "
1755 "for external framebuffers"));
1756
1757 /* Set the flag indicating that the resize has completed and display
1758 * data need to be updated. */
1759 bool f = ASMAtomicCmpXchgU32 (&maFramebuffers[aScreenId].u32ResizeStatus,
1760 ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
1761 AssertRelease(f);NOREF(f);
1762
1763 return S_OK;
1764}
1765
1766/**
1767 * Notification that the framebuffer has completed the
1768 * asynchronous update processing
1769 *
1770 * @returns COM status code
1771 */
1772STDMETHODIMP Display::UpdateCompleted()
1773{
1774 LogFlowFunc (("\n"));
1775
1776 /// @todo (dmik) can we AutoWriteLock alock(this); here?
1777 // do it when we switch this class to VirtualBoxBase_NEXT.
1778 // Tthis will require general code review and may add some details.
1779 // In particular, we may want to check whether EMT is really waiting for
1780 // this notification, etc. It might be also good to obey the caller to make
1781 // sure this method is not called from more than one thread at a time
1782 // (and therefore don't use Display lock at all here to save some
1783 // milliseconds).
1784 AutoCaller autoCaller(this);
1785 CheckComRCReturnRC(autoCaller.rc());
1786
1787 /* this is only valid for external framebuffers */
1788 if (maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer == NULL)
1789 return setError (VBOX_E_NOT_SUPPORTED,
1790 tr ("Resize completed notification is valid only "
1791 "for external framebuffers"));
1792
1793 return S_OK;
1794}
1795
1796STDMETHODIMP Display::CompleteVHWACommand(BYTE *pCommand)
1797{
1798#ifdef VBOX_WITH_VIDEOHWACCEL
1799 mpDrv->pVBVACallbacks->pfnVHWACommandCompleteAsynch(mpDrv->pVBVACallbacks, (PVBOXVHWACMD)pCommand);
1800 return S_OK;
1801#else
1802 return E_NOTIMPL;
1803#endif
1804}
1805
1806// private methods
1807/////////////////////////////////////////////////////////////////////////////
1808
1809/**
1810 * Helper to update the display information from the framebuffer.
1811 *
1812 * @param aCheckParams true to compare the parameters of the current framebuffer
1813 * and the new one and issue handleDisplayResize()
1814 * if they differ.
1815 * @thread EMT
1816 */
1817void Display::updateDisplayData (bool aCheckParams /* = false */)
1818{
1819 /* the driver might not have been constructed yet */
1820 if (!mpDrv)
1821 return;
1822
1823#if DEBUG
1824 /*
1825 * Sanity check. Note that this method may be called on EMT after Console
1826 * has started the power down procedure (but before our #drvDestruct() is
1827 * called, in which case pVM will aleady be NULL but mpDrv will not). Since
1828 * we don't really need pVM to proceed, we avoid this check in the release
1829 * build to save some ms (necessary to construct SafeVMPtrQuiet) in this
1830 * time-critical method.
1831 */
1832 Console::SafeVMPtrQuiet pVM (mParent);
1833 if (pVM.isOk())
1834 VM_ASSERT_EMT (pVM.raw());
1835#endif
1836
1837 /* The method is only relevant to the primary framebuffer. */
1838 IFramebuffer *pFramebuffer = maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN].pFramebuffer;
1839
1840 if (pFramebuffer)
1841 {
1842 HRESULT rc;
1843 BYTE *address = 0;
1844 rc = pFramebuffer->COMGETTER(Address) (&address);
1845 AssertComRC (rc);
1846 ULONG bytesPerLine = 0;
1847 rc = pFramebuffer->COMGETTER(BytesPerLine) (&bytesPerLine);
1848 AssertComRC (rc);
1849 ULONG bitsPerPixel = 0;
1850 rc = pFramebuffer->COMGETTER(BitsPerPixel) (&bitsPerPixel);
1851 AssertComRC (rc);
1852 ULONG width = 0;
1853 rc = pFramebuffer->COMGETTER(Width) (&width);
1854 AssertComRC (rc);
1855 ULONG height = 0;
1856 rc = pFramebuffer->COMGETTER(Height) (&height);
1857 AssertComRC (rc);
1858
1859 /*
1860 * Check current parameters with new ones and issue handleDisplayResize()
1861 * to let the new frame buffer adjust itself properly. Note that it will
1862 * result into a recursive updateDisplayData() call but with
1863 * aCheckOld = false.
1864 */
1865 if (aCheckParams &&
1866 (mLastAddress != address ||
1867 mLastBytesPerLine != bytesPerLine ||
1868 mLastBitsPerPixel != bitsPerPixel ||
1869 mLastWidth != (int) width ||
1870 mLastHeight != (int) height))
1871 {
1872 handleDisplayResize (VBOX_VIDEO_PRIMARY_SCREEN, mLastBitsPerPixel,
1873 mLastAddress,
1874 mLastBytesPerLine,
1875 mLastWidth,
1876 mLastHeight);
1877 return;
1878 }
1879
1880 mpDrv->Connector.pu8Data = (uint8_t *) address;
1881 mpDrv->Connector.cbScanline = bytesPerLine;
1882 mpDrv->Connector.cBits = bitsPerPixel;
1883 mpDrv->Connector.cx = width;
1884 mpDrv->Connector.cy = height;
1885 }
1886 else
1887 {
1888 /* black hole */
1889 mpDrv->Connector.pu8Data = NULL;
1890 mpDrv->Connector.cbScanline = 0;
1891 mpDrv->Connector.cBits = 0;
1892 mpDrv->Connector.cx = 0;
1893 mpDrv->Connector.cy = 0;
1894 }
1895}
1896
1897/**
1898 * Changes the current frame buffer. Called on EMT to avoid both
1899 * race conditions and excessive locking.
1900 *
1901 * @note locks this object for writing
1902 * @thread EMT
1903 */
1904/* static */
1905DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB,
1906 unsigned uScreenId)
1907{
1908 LogFlowFunc (("uScreenId = %d\n", uScreenId));
1909
1910 AssertReturn(that, VERR_INVALID_PARAMETER);
1911 AssertReturn(uScreenId < that->mcMonitors, VERR_INVALID_PARAMETER);
1912
1913 AutoCaller autoCaller(that);
1914 CheckComRCReturnRC(autoCaller.rc());
1915
1916 AutoWriteLock alock(that);
1917
1918 DISPLAYFBINFO *pDisplayFBInfo = &that->maFramebuffers[uScreenId];
1919 pDisplayFBInfo->pFramebuffer = aFB;
1920
1921 that->mParent->consoleVRDPServer()->SendResize ();
1922
1923 that->updateDisplayData (true /* aCheckParams */);
1924
1925 return VINF_SUCCESS;
1926}
1927
1928/**
1929 * Handle display resize event issued by the VGA device for the primary screen.
1930 *
1931 * @see PDMIDISPLAYCONNECTOR::pfnResize
1932 */
1933DECLCALLBACK(int) Display::displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
1934 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
1935{
1936 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1937
1938 LogFlowFunc (("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
1939 bpp, pvVRAM, cbLine, cx, cy));
1940
1941 return pDrv->pDisplay->handleDisplayResize(VBOX_VIDEO_PRIMARY_SCREEN, bpp, pvVRAM, cbLine, cx, cy);
1942}
1943
1944/**
1945 * Handle display update.
1946 *
1947 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
1948 */
1949DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
1950 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
1951{
1952 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1953
1954#ifdef DEBUG_sunlover
1955 LogFlowFunc (("mfVideoAccelEnabled = %d, %d,%d %dx%d\n",
1956 pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy));
1957#endif /* DEBUG_sunlover */
1958
1959 /* This call does update regardless of VBVA status.
1960 * But in VBVA mode this is called only as result of
1961 * pfnUpdateDisplayAll in the VGA device.
1962 */
1963
1964 pDrv->pDisplay->handleDisplayUpdate(x, y, cx, cy);
1965}
1966
1967/**
1968 * Periodic display refresh callback.
1969 *
1970 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
1971 */
1972DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
1973{
1974 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1975
1976#ifdef DEBUG_sunlover
1977 STAM_PROFILE_START(&StatDisplayRefresh, a);
1978#endif /* DEBUG_sunlover */
1979
1980#ifdef DEBUG_sunlover_2
1981 LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
1982 pDrv->pDisplay->mfVideoAccelEnabled));
1983#endif /* DEBUG_sunlover_2 */
1984
1985 Display *pDisplay = pDrv->pDisplay;
1986 bool fNoUpdate = false; /* Do not update the display if any of the framebuffers is being resized. */
1987 unsigned uScreenId;
1988
1989 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
1990 {
1991 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
1992
1993 /* Check the resize status. The status can be checked normally because
1994 * the status affects only the EMT.
1995 */
1996 uint32_t u32ResizeStatus = pFBInfo->u32ResizeStatus;
1997
1998 if (u32ResizeStatus == ResizeStatus_UpdateDisplayData)
1999 {
2000 LogFlowFunc (("ResizeStatus_UpdateDisplayData %d\n", uScreenId));
2001 fNoUpdate = true; /* Always set it here, because pfnUpdateDisplayAll can cause a new resize. */
2002 /* The framebuffer was resized and display data need to be updated. */
2003 pDisplay->handleResizeCompletedEMT ();
2004 if (pFBInfo->u32ResizeStatus != ResizeStatus_Void)
2005 {
2006 /* The resize status could be not Void here because a pending resize is issued. */
2007 continue;
2008 }
2009 /* Continue with normal processing because the status here is ResizeStatus_Void. */
2010 if (uScreenId == VBOX_VIDEO_PRIMARY_SCREEN)
2011 {
2012 /* Repaint the display because VM continued to run during the framebuffer resize. */
2013 if (!pFBInfo->pFramebuffer.isNull())
2014 pDrv->pUpPort->pfnUpdateDisplayAll(pDrv->pUpPort);
2015 }
2016 }
2017 else if (u32ResizeStatus == ResizeStatus_InProgress)
2018 {
2019 /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */
2020 LogFlowFunc (("ResizeStatus_InProcess\n"));
2021 fNoUpdate = true;
2022 continue;
2023 }
2024 }
2025
2026 if (!fNoUpdate)
2027 {
2028 if (pDisplay->mfPendingVideoAccelEnable)
2029 {
2030 /* Acceleration was enabled while machine was not yet running
2031 * due to restoring from saved state. Update entire display and
2032 * actually enable acceleration.
2033 */
2034 Assert(pDisplay->mpPendingVbvaMemory);
2035
2036 /* Acceleration can not be yet enabled.*/
2037 Assert(pDisplay->mpVbvaMemory == NULL);
2038 Assert(!pDisplay->mfVideoAccelEnabled);
2039
2040 if (pDisplay->mfMachineRunning)
2041 {
2042 pDisplay->VideoAccelEnable (pDisplay->mfPendingVideoAccelEnable,
2043 pDisplay->mpPendingVbvaMemory);
2044
2045 /* Reset the pending state. */
2046 pDisplay->mfPendingVideoAccelEnable = false;
2047 pDisplay->mpPendingVbvaMemory = NULL;
2048 }
2049 }
2050 else
2051 {
2052 Assert(pDisplay->mpPendingVbvaMemory == NULL);
2053
2054 if (pDisplay->mfVideoAccelEnabled)
2055 {
2056 Assert(pDisplay->mpVbvaMemory);
2057 pDisplay->VideoAccelFlush ();
2058 }
2059 else
2060 {
2061 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[VBOX_VIDEO_PRIMARY_SCREEN];
2062 if (!pFBInfo->pFramebuffer.isNull())
2063 {
2064 Assert(pDrv->Connector.pu8Data);
2065 Assert(pFBInfo->u32ResizeStatus == ResizeStatus_Void);
2066 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
2067 }
2068 }
2069
2070 /* Inform the VRDP server that the current display update sequence is
2071 * completed. At this moment the framebuffer memory contains a definite
2072 * image, that is synchronized with the orders already sent to VRDP client.
2073 * The server can now process redraw requests from clients or initial
2074 * fullscreen updates for new clients.
2075 */
2076 for (uScreenId = 0; uScreenId < pDisplay->mcMonitors; uScreenId++)
2077 {
2078 DISPLAYFBINFO *pFBInfo = &pDisplay->maFramebuffers[uScreenId];
2079
2080 if (!pFBInfo->pFramebuffer.isNull() && pFBInfo->u32ResizeStatus == ResizeStatus_Void)
2081 {
2082 Assert (pDisplay->mParent && pDisplay->mParent->consoleVRDPServer());
2083 pDisplay->mParent->consoleVRDPServer()->SendUpdate (uScreenId, NULL, 0);
2084 }
2085 }
2086 }
2087 }
2088
2089#ifdef DEBUG_sunlover
2090 STAM_PROFILE_STOP(&StatDisplayRefresh, a);
2091#endif /* DEBUG_sunlover */
2092#ifdef DEBUG_sunlover_2
2093 LogFlowFunc (("leave\n"));
2094#endif /* DEBUG_sunlover_2 */
2095}
2096
2097/**
2098 * Reset notification
2099 *
2100 * @see PDMIDISPLAYCONNECTOR::pfnReset
2101 */
2102DECLCALLBACK(void) Display::displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
2103{
2104 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2105
2106 LogFlowFunc (("\n"));
2107
2108 /* Disable VBVA mode. */
2109 pDrv->pDisplay->VideoAccelEnable (false, NULL);
2110}
2111
2112/**
2113 * LFBModeChange notification
2114 *
2115 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
2116 */
2117DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
2118{
2119 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2120
2121 LogFlowFunc (("fEnabled=%d\n", fEnabled));
2122
2123 NOREF(fEnabled);
2124
2125 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
2126 pDrv->pDisplay->VideoAccelEnable (false, NULL);
2127}
2128
2129/**
2130 * Adapter information change notification.
2131 *
2132 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
2133 */
2134DECLCALLBACK(void) Display::displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)
2135{
2136 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2137
2138 if (pvVRAM == NULL)
2139 {
2140 unsigned i;
2141 for (i = 0; i < pDrv->pDisplay->mcMonitors; i++)
2142 {
2143 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[i];
2144
2145 pFBInfo->u32Offset = 0;
2146 pFBInfo->u32MaxFramebufferSize = 0;
2147 pFBInfo->u32InformationSize = 0;
2148 }
2149 }
2150#ifndef VBOX_WITH_HGSMI
2151 else
2152 {
2153 uint8_t *pu8 = (uint8_t *)pvVRAM;
2154 pu8 += u32VRAMSize - VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
2155
2156 // @todo
2157 uint8_t *pu8End = pu8 + VBOX_VIDEO_ADAPTER_INFORMATION_SIZE;
2158
2159 VBOXVIDEOINFOHDR *pHdr;
2160
2161 for (;;)
2162 {
2163 pHdr = (VBOXVIDEOINFOHDR *)pu8;
2164 pu8 += sizeof (VBOXVIDEOINFOHDR);
2165
2166 if (pu8 >= pu8End)
2167 {
2168 LogRel(("VBoxVideo: Guest adapter information overflow!!!\n"));
2169 break;
2170 }
2171
2172 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_DISPLAY)
2173 {
2174 if (pHdr->u16Length != sizeof (VBOXVIDEOINFODISPLAY))
2175 {
2176 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "DISPLAY", pHdr->u16Length));
2177 break;
2178 }
2179
2180 VBOXVIDEOINFODISPLAY *pDisplay = (VBOXVIDEOINFODISPLAY *)pu8;
2181
2182 if (pDisplay->u32Index >= pDrv->pDisplay->mcMonitors)
2183 {
2184 LogRel(("VBoxVideo: Guest adapter information invalid display index %d!!!\n", pDisplay->u32Index));
2185 break;
2186 }
2187
2188 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[pDisplay->u32Index];
2189
2190 pFBInfo->u32Offset = pDisplay->u32Offset;
2191 pFBInfo->u32MaxFramebufferSize = pDisplay->u32FramebufferSize;
2192 pFBInfo->u32InformationSize = pDisplay->u32InformationSize;
2193
2194 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));
2195 }
2196 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_QUERY_CONF32)
2197 {
2198 if (pHdr->u16Length != sizeof (VBOXVIDEOINFOQUERYCONF32))
2199 {
2200 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "CONF32", pHdr->u16Length));
2201 break;
2202 }
2203
2204 VBOXVIDEOINFOQUERYCONF32 *pConf32 = (VBOXVIDEOINFOQUERYCONF32 *)pu8;
2205
2206 switch (pConf32->u32Index)
2207 {
2208 case VBOX_VIDEO_QCI32_MONITOR_COUNT:
2209 {
2210 pConf32->u32Value = pDrv->pDisplay->mcMonitors;
2211 } break;
2212
2213 case VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE:
2214 {
2215 /* @todo make configurable. */
2216 pConf32->u32Value = _1M;
2217 } break;
2218
2219 default:
2220 LogRel(("VBoxVideo: CONF32 %d not supported!!! Skipping.\n", pConf32->u32Index));
2221 }
2222 }
2223 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
2224 {
2225 if (pHdr->u16Length != 0)
2226 {
2227 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
2228 break;
2229 }
2230
2231 break;
2232 }
2233 else if (pHdr->u8Type != VBOX_VIDEO_INFO_TYPE_NV_HEAP) /** @todo why is Additions/WINNT/Graphics/Miniport/VBoxVideo.cpp pushing this to us? */
2234 {
2235 LogRel(("Guest adapter information contains unsupported type %d. The block has been skipped.\n", pHdr->u8Type));
2236 }
2237
2238 pu8 += pHdr->u16Length;
2239 }
2240 }
2241#endif /* !VBOX_WITH_HGSMI */
2242}
2243
2244/**
2245 * Display information change notification.
2246 *
2247 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
2248 */
2249DECLCALLBACK(void) Display::displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)
2250{
2251 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2252
2253 if (uScreenId >= pDrv->pDisplay->mcMonitors)
2254 {
2255 LogRel(("VBoxVideo: Guest display information invalid display index %d!!!\n", uScreenId));
2256 return;
2257 }
2258
2259 /* Get the display information structure. */
2260 DISPLAYFBINFO *pFBInfo = &pDrv->pDisplay->maFramebuffers[uScreenId];
2261
2262 uint8_t *pu8 = (uint8_t *)pvVRAM;
2263 pu8 += pFBInfo->u32Offset + pFBInfo->u32MaxFramebufferSize;
2264
2265 // @todo
2266 uint8_t *pu8End = pu8 + pFBInfo->u32InformationSize;
2267
2268 VBOXVIDEOINFOHDR *pHdr;
2269
2270 for (;;)
2271 {
2272 pHdr = (VBOXVIDEOINFOHDR *)pu8;
2273 pu8 += sizeof (VBOXVIDEOINFOHDR);
2274
2275 if (pu8 >= pu8End)
2276 {
2277 LogRel(("VBoxVideo: Guest display information overflow!!!\n"));
2278 break;
2279 }
2280
2281 if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_SCREEN)
2282 {
2283 if (pHdr->u16Length != sizeof (VBOXVIDEOINFOSCREEN))
2284 {
2285 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "SCREEN", pHdr->u16Length));
2286 break;
2287 }
2288
2289 VBOXVIDEOINFOSCREEN *pScreen = (VBOXVIDEOINFOSCREEN *)pu8;
2290
2291 pFBInfo->xOrigin = pScreen->xOrigin;
2292 pFBInfo->yOrigin = pScreen->yOrigin;
2293
2294 pFBInfo->w = pScreen->u16Width;
2295 pFBInfo->h = pScreen->u16Height;
2296
2297 LogFlow(("VBOX_VIDEO_INFO_TYPE_SCREEN: (%p) %d: at %d,%d, linesize 0x%X, size %dx%d, bpp %d, flags 0x%02X\n",
2298 pHdr, uScreenId, pScreen->xOrigin, pScreen->yOrigin, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height, pScreen->bitsPerPixel, pScreen->u8Flags));
2299
2300 if (uScreenId != VBOX_VIDEO_PRIMARY_SCREEN)
2301 {
2302 /* Primary screen resize is initiated by the VGA device. */
2303 pDrv->pDisplay->handleDisplayResize(uScreenId, pScreen->bitsPerPixel, (uint8_t *)pvVRAM + pFBInfo->u32Offset, pScreen->u32LineSize, pScreen->u16Width, pScreen->u16Height);
2304 }
2305 }
2306 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_END)
2307 {
2308 if (pHdr->u16Length != 0)
2309 {
2310 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "END", pHdr->u16Length));
2311 break;
2312 }
2313
2314 break;
2315 }
2316 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_HOST_EVENTS)
2317 {
2318 if (pHdr->u16Length != sizeof (VBOXVIDEOINFOHOSTEVENTS))
2319 {
2320 LogRel(("VBoxVideo: Guest display information %s invalid length %d!!!\n", "HOST_EVENTS", pHdr->u16Length));
2321 break;
2322 }
2323
2324 VBOXVIDEOINFOHOSTEVENTS *pHostEvents = (VBOXVIDEOINFOHOSTEVENTS *)pu8;
2325
2326 pFBInfo->pHostEvents = pHostEvents;
2327
2328 LogFlow(("VBOX_VIDEO_INFO_TYPE_HOSTEVENTS: (%p)\n",
2329 pHostEvents));
2330 }
2331 else if (pHdr->u8Type == VBOX_VIDEO_INFO_TYPE_LINK)
2332 {
2333 if (pHdr->u16Length != sizeof (VBOXVIDEOINFOLINK))
2334 {
2335 LogRel(("VBoxVideo: Guest adapter information %s invalid length %d!!!\n", "LINK", pHdr->u16Length));
2336 break;
2337 }
2338
2339 VBOXVIDEOINFOLINK *pLink = (VBOXVIDEOINFOLINK *)pu8;
2340 pu8 += pLink->i32Offset;
2341 }
2342 else
2343 {
2344 LogRel(("Guest display information contains unsupported type %d\n", pHdr->u8Type));
2345 }
2346
2347 pu8 += pHdr->u16Length;
2348 }
2349}
2350
2351#ifdef VBOX_WITH_VIDEOHWACCEL
2352
2353void Display::handleVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
2354{
2355 unsigned id = (unsigned)pCommand->iDisplay;
2356 int rc = VINF_SUCCESS;
2357 if(id < mcMonitors)
2358 {
2359 IFramebuffer *pFramebuffer = maFramebuffers[id].pFramebuffer;
2360
2361 // if there is no framebuffer, this call is not interesting
2362 if (pFramebuffer == NULL)
2363 return;
2364
2365 pFramebuffer->Lock();
2366
2367 HRESULT hr = pFramebuffer->ProcessVHWACommand((BYTE*)pCommand);
2368 if(FAILED(hr))
2369 {
2370 rc = (hr == E_NOTIMPL) ? VERR_NOT_IMPLEMENTED : VERR_GENERAL_FAILURE;
2371 }
2372
2373 pFramebuffer->Unlock();
2374
2375 }
2376 else
2377 {
2378 rc = VERR_INVALID_PARAMETER;
2379 }
2380
2381 if(RT_FAILURE(rc))
2382 {
2383 /* tell the guest the command is complete */
2384 pCommand->Flags &= (~VBOXVHWACMD_FLAG_HG_ASYNCH);
2385 pCommand->rc = rc;
2386 }
2387}
2388
2389DECLCALLBACK(void) Display::displayVHWACommandProcess(PPDMIDISPLAYCONNECTOR pInterface, PVBOXVHWACMD pCommand)
2390{
2391 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2392
2393 pDrv->pDisplay->handleVHWACommandProcess(pInterface, pCommand);
2394}
2395#endif
2396
2397#ifdef VBOX_WITH_HGSMI
2398DECLCALLBACK(int) Display::displayVBVAEnable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
2399{
2400 LogFlowFunc(("uScreenId %d\n", uScreenId));
2401
2402 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2403 Display *pThis = pDrv->pDisplay;
2404
2405 pThis->maFramebuffers[uScreenId].fVBVAEnabled = true;
2406
2407 return VINF_SUCCESS;
2408}
2409
2410DECLCALLBACK(void) Display::displayVBVADisable(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
2411{
2412 LogFlowFunc(("uScreenId %d\n", uScreenId));
2413
2414 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2415 Display *pThis = pDrv->pDisplay;
2416
2417 pThis->maFramebuffers[uScreenId].fVBVAEnabled = false;
2418}
2419
2420DECLCALLBACK(void) Display::displayVBVAUpdateBegin(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)
2421{
2422 LogFlowFunc(("uScreenId %d\n", uScreenId));
2423
2424 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2425 Display *pThis = pDrv->pDisplay;
2426
2427 NOREF(uScreenId);
2428}
2429
2430DECLCALLBACK(void) Display::displayVBVAUpdateProcess(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, const PVBVACMDHDR pCmd, size_t cbCmd)
2431{
2432 LogFlowFunc(("uScreenId %d pCmd %p cbCmd %d\n", uScreenId, pCmd, cbCmd));
2433
2434 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2435 Display *pThis = pDrv->pDisplay;
2436
2437 pThis->mParent->consoleVRDPServer()->SendUpdate (uScreenId, pCmd, cbCmd);
2438}
2439
2440DECLCALLBACK(void) Display::displayVBVAUpdateEnd(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
2441{
2442 LogFlowFunc(("uScreenId %d %d,%d %dx%d\n", uScreenId, x, y, cx, cy));
2443
2444 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2445 Display *pThis = pDrv->pDisplay;
2446
2447 /* @todo handleFramebufferUpdate (uScreenId,
2448 * x - pThis->maFramebuffers[uScreenId].xOrigin,
2449 * y - pThis->maFramebuffers[uScreenId].yOrigin,
2450 * cx, cy);
2451 */
2452 pThis->handleDisplayUpdate(x, y, cx, cy);
2453}
2454
2455DECLCALLBACK(int) Display::displayVBVAResize(PPDMIDISPLAYCONNECTOR pInterface, const PVBVAINFOVIEW pView, const PVBVAINFOSCREEN pScreen, void *pvVRAM)
2456{
2457 LogFlowFunc(("pScreen %p, pvVRAM %p\n", pScreen, pvVRAM));
2458
2459 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2460 Display *pThis = pDrv->pDisplay;
2461
2462 DISPLAYFBINFO *pFBInfo = &pThis->maFramebuffers[pScreen->u32ViewIndex];
2463
2464 pFBInfo->u32Offset = pView->u32ViewOffset; /* Not used in HGSMI. */
2465 pFBInfo->u32MaxFramebufferSize = pView->u32MaxScreenSize; /* Not used in HGSMI. */
2466 pFBInfo->u32InformationSize = 0; /* Not used in HGSMI. */
2467
2468 pFBInfo->xOrigin = pScreen->i32OriginX;
2469 pFBInfo->yOrigin = pScreen->i32OriginY;
2470
2471 pFBInfo->w = pScreen->u32Width;
2472 pFBInfo->h = pScreen->u32Height;
2473
2474 return pThis->handleDisplayResize(pScreen->u32ViewIndex, pScreen->u16BitsPerPixel,
2475 (uint8_t *)pvVRAM + pScreen->u32StartOffset,
2476 pScreen->u32LineSize, pScreen->u32Width, pScreen->u32Height);
2477}
2478
2479DECLCALLBACK(int) Display::displayVBVAMousePointerShape(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha,
2480 uint32_t xHot, uint32_t yHot,
2481 uint32_t cx, uint32_t cy,
2482 const void *pvShape)
2483{
2484 LogFlowFunc(("\n"));
2485
2486 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
2487 Display *pThis = pDrv->pDisplay;
2488
2489 /* Tell the console about it */
2490 pDrv->pDisplay->mParent->onMousePointerShapeChange(fVisible, fAlpha,
2491 xHot, yHot, cx, cy, (void *)pvShape);
2492
2493 return VINF_SUCCESS;
2494}
2495#endif /* VBOX_WITH_HGSMI */
2496
2497/**
2498 * Queries an interface to the driver.
2499 *
2500 * @returns Pointer to interface.
2501 * @returns NULL if the interface was not supported by the driver.
2502 * @param pInterface Pointer to this interface structure.
2503 * @param enmInterface The requested interface identification.
2504 */
2505DECLCALLBACK(void *) Display::drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
2506{
2507 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
2508 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
2509 switch (enmInterface)
2510 {
2511 case PDMINTERFACE_BASE:
2512 return &pDrvIns->IBase;
2513 case PDMINTERFACE_DISPLAY_CONNECTOR:
2514 return &pDrv->Connector;
2515 default:
2516 return NULL;
2517 }
2518}
2519
2520
2521/**
2522 * Destruct a display driver instance.
2523 *
2524 * @returns VBox status.
2525 * @param pDrvIns The driver instance data.
2526 */
2527DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns)
2528{
2529 PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
2530 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
2531 if (pData->pDisplay)
2532 {
2533 AutoWriteLock displayLock (pData->pDisplay);
2534 pData->pDisplay->mpDrv = NULL;
2535 pData->pDisplay->mpVMMDev = NULL;
2536 pData->pDisplay->mLastAddress = NULL;
2537 pData->pDisplay->mLastBytesPerLine = 0;
2538 pData->pDisplay->mLastBitsPerPixel = 0,
2539 pData->pDisplay->mLastWidth = 0;
2540 pData->pDisplay->mLastHeight = 0;
2541 }
2542}
2543
2544
2545/**
2546 * Construct a display driver instance.
2547 *
2548 * @copydoc FNPDMDRVCONSTRUCT
2549 */
2550DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
2551{
2552 PDRVMAINDISPLAY pData = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
2553 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
2554
2555 /*
2556 * Validate configuration.
2557 */
2558 if (!CFGMR3AreValuesValid(pCfgHandle, "Object\0"))
2559 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
2560 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
2561 ("Configuration error: Not possible to attach anything to this driver!\n"),
2562 VERR_PDM_DRVINS_NO_ATTACH);
2563
2564 /*
2565 * Init Interfaces.
2566 */
2567 pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface;
2568
2569 pData->Connector.pfnResize = Display::displayResizeCallback;
2570 pData->Connector.pfnUpdateRect = Display::displayUpdateCallback;
2571 pData->Connector.pfnRefresh = Display::displayRefreshCallback;
2572 pData->Connector.pfnReset = Display::displayResetCallback;
2573 pData->Connector.pfnLFBModeChange = Display::displayLFBModeChangeCallback;
2574 pData->Connector.pfnProcessAdapterData = Display::displayProcessAdapterDataCallback;
2575 pData->Connector.pfnProcessDisplayData = Display::displayProcessDisplayDataCallback;
2576#ifdef VBOX_WITH_VIDEOHWACCEL
2577 pData->Connector.pfnVHWACommandProcess = Display::displayVHWACommandProcess;
2578#endif
2579#ifdef VBOX_WITH_HGSMI
2580 pData->Connector.pfnVBVAEnable = Display::displayVBVAEnable;
2581 pData->Connector.pfnVBVADisable = Display::displayVBVADisable;
2582 pData->Connector.pfnVBVAUpdateBegin = Display::displayVBVAUpdateBegin;
2583 pData->Connector.pfnVBVAUpdateProcess = Display::displayVBVAUpdateProcess;
2584 pData->Connector.pfnVBVAUpdateEnd = Display::displayVBVAUpdateEnd;
2585 pData->Connector.pfnVBVAResize = Display::displayVBVAResize;
2586 pData->Connector.pfnVBVAMousePointerShape = Display::displayVBVAMousePointerShape;
2587#endif
2588
2589
2590 /*
2591 * Get the IDisplayPort interface of the above driver/device.
2592 */
2593 pData->pUpPort = (PPDMIDISPLAYPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_DISPLAY_PORT);
2594 if (!pData->pUpPort)
2595 {
2596 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
2597 return VERR_PDM_MISSING_INTERFACE_ABOVE;
2598 }
2599#if defined(VBOX_WITH_VIDEOHWACCEL)
2600 pData->pVBVACallbacks = (PPDMDDISPLAYVBVACALLBACKS)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_DISPLAY_VBVA_CALLBACKS);
2601 if (!pData->pVBVACallbacks)
2602 {
2603 AssertMsgFailed(("Configuration error: No VBVA callback interface above!\n"));
2604 return VERR_PDM_MISSING_INTERFACE_ABOVE;
2605 }
2606#endif
2607 /*
2608 * Get the Display object pointer and update the mpDrv member.
2609 */
2610 void *pv;
2611 int rc = CFGMR3QueryPtr(pCfgHandle, "Object", &pv);
2612 if (RT_FAILURE(rc))
2613 {
2614 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc));
2615 return rc;
2616 }
2617 pData->pDisplay = (Display *)pv; /** @todo Check this cast! */
2618 pData->pDisplay->mpDrv = pData;
2619
2620 /*
2621 * Update our display information according to the framebuffer
2622 */
2623 pData->pDisplay->updateDisplayData();
2624
2625 /*
2626 * Start periodic screen refreshes
2627 */
2628 pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 20);
2629
2630 return VINF_SUCCESS;
2631}
2632
2633
2634/**
2635 * Display driver registration record.
2636 */
2637const PDMDRVREG Display::DrvReg =
2638{
2639 /* u32Version */
2640 PDM_DRVREG_VERSION,
2641 /* szDriverName */
2642 "MainDisplay",
2643 /* pszDescription */
2644 "Main display driver (Main as in the API).",
2645 /* fFlags */
2646 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2647 /* fClass. */
2648 PDM_DRVREG_CLASS_DISPLAY,
2649 /* cMaxInstances */
2650 ~0,
2651 /* cbInstance */
2652 sizeof(DRVMAINDISPLAY),
2653 /* pfnConstruct */
2654 Display::drvConstruct,
2655 /* pfnDestruct */
2656 Display::drvDestruct,
2657 /* pfnIOCtl */
2658 NULL,
2659 /* pfnPowerOn */
2660 NULL,
2661 /* pfnReset */
2662 NULL,
2663 /* pfnSuspend */
2664 NULL,
2665 /* pfnResume */
2666 NULL,
2667 /* pfnAttach */
2668 NULL,
2669 /* pfnDetach */
2670 NULL,
2671 /* pfnPowerOff */
2672 NULL,
2673 /* pfnSoftReset */
2674 NULL,
2675 /* u32EndVersion */
2676 PDM_DRVREG_VERSION
2677};
2678/* 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