VirtualBox

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

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

Main: prototyped screenshot usable for scripting languages

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