VirtualBox

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

Last change on this file since 3110 was 3110, checked in by vboxsync, 17 years ago

Added the display index parameter to the SetVideoModeHint (in the guest all hints are still processed only for the primary monitor).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 59.5 KB
Line 
1/** @file
2 *
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "DisplayImpl.h"
23#include "FramebufferImpl.h"
24#include "ConsoleImpl.h"
25#include "ConsoleVRDPServer.h"
26#include "VMMDev.h"
27
28#include "Logging.h"
29
30#include <iprt/semaphore.h>
31#include <iprt/thread.h>
32#include <iprt/asm.h>
33
34#include <VBox/pdm.h>
35#include <VBox/cfgm.h>
36#include <VBox/err.h>
37#include <VBox/vm.h>
38
39/**
40 * Display driver instance data.
41 */
42typedef struct DRVMAINDISPLAY
43{
44 /** Pointer to the display object. */
45 Display *pDisplay;
46 /** Pointer to the driver instance structure. */
47 PPDMDRVINS pDrvIns;
48 /** Pointer to the keyboard port interface of the driver/device above us. */
49 PPDMIDISPLAYPORT pUpPort;
50 /** Our display connector interface. */
51 PDMIDISPLAYCONNECTOR Connector;
52} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
53
54/** Converts PDMIDISPLAYCONNECTOR pointer to a DRVMAINDISPLAY pointer. */
55#define PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface) ( (PDRVMAINDISPLAY) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINDISPLAY, Connector)) )
56
57#ifdef DEBUG_sunlover
58static STAMPROFILE StatDisplayRefresh;
59static int stam = 0;
60#endif /* DEBUG_sunlover */
61
62// constructor / destructor
63/////////////////////////////////////////////////////////////////////////////
64
65HRESULT Display::FinalConstruct()
66{
67 mpVbvaMemory = NULL;
68 mfVideoAccelEnabled = false;
69 mfVideoAccelVRDP = false;
70 mfu32SupportedOrders = 0;
71 mcVideoAccelVRDPRefs = 0;
72
73 mpPendingVbvaMemory = NULL;
74 mfPendingVideoAccelEnable = false;
75
76 mfMachineRunning = false;
77
78 mpu8VbvaPartial = NULL;
79 mcbVbvaPartial = 0;
80
81 mParent = NULL;
82 mpDrv = NULL;
83 mpVMMDev = NULL;
84 mfVMMDevInited = false;
85 RTSemEventMultiCreate(&mUpdateSem);
86
87 mLastAddress = NULL;
88 mLastLineSize = 0;
89 mLastColorDepth = 0,
90 mLastWidth = 0;
91 mLastHeight = 0;
92
93 mu32ResizeStatus = ResizeStatus_Void;
94
95 return S_OK;
96}
97
98void Display::FinalRelease()
99{
100 if (isReady())
101 uninit();
102}
103
104// public initializer/uninitializer for internal purposes only
105/////////////////////////////////////////////////////////////////////////////
106
107/**
108 * Initializes the display object.
109 *
110 * @returns COM result indicator
111 * @param parent handle of our parent object
112 * @param qemuConsoleData address of common console data structure
113 */
114HRESULT Display::init (Console *parent)
115{
116 LogFlowFunc (("isReady=%d", isReady()));
117
118 ComAssertRet (parent, E_INVALIDARG);
119
120 AutoLock alock (this);
121 ComAssertRet (!isReady(), E_UNEXPECTED);
122
123 mParent = parent;
124
125 /* reset the event sems */
126 RTSemEventMultiReset(mUpdateSem);
127
128 // by default, we have an internal framebuffer which is
129 // NULL, i.e. a black hole for no display output
130 mFramebuffer = 0;
131 mInternalFramebuffer = true;
132 mFramebufferOpened = false;
133 mSupportedAccelOps = 0;
134
135 mParent->RegisterCallback(this);
136
137 setReady (true);
138 return S_OK;
139}
140
141/**
142 * Uninitializes the instance and sets the ready flag to FALSE.
143 * Called either from FinalRelease() or by the parent when it gets destroyed.
144 */
145void Display::uninit()
146{
147 LogFlowFunc (("isReady=%d\n", isReady()));
148
149 AutoLock alock (this);
150 AssertReturn (isReady(), (void) 0);
151
152 mFramebuffer.setNull();
153 RTSemEventMultiDestroy(mUpdateSem);
154
155 if (mParent)
156 {
157 mParent->UnregisterCallback(this);
158 }
159
160 if (mpDrv)
161 mpDrv->pDisplay = NULL;
162 mpDrv = NULL;
163 mpVMMDev = NULL;
164 mfVMMDevInited = true;
165
166 setReady (false);
167}
168
169// IConsoleCallback method
170STDMETHODIMP Display::OnStateChange(MachineState_T machineState)
171{
172 if (machineState == MachineState_Running)
173 {
174 LogFlowFunc (("Machine running\n"));
175
176 mfMachineRunning = true;
177 }
178 else
179 {
180 mfMachineRunning = false;
181 }
182 return S_OK;
183}
184
185// public methods only for internal purposes
186/////////////////////////////////////////////////////////////////////////////
187
188/**
189 * @thread EMT
190 */
191static int callFramebufferResize (IFramebuffer *pFramebuffer, FramebufferPixelFormat_T pixelFormat, void *pvVRAM, uint32_t cbLine, int w, int h)
192{
193 Assert (pFramebuffer);
194
195 /* Call the framebuffer to try and set required pixelFormat. */
196 BOOL finished = TRUE;
197
198 pFramebuffer->RequestResize (pixelFormat, (BYTE *) pvVRAM, cbLine, w, h, &finished);
199
200 if (!finished)
201 {
202 LogFlowFunc (("External framebuffer wants us to wait!\n"));
203 return VINF_VGA_RESIZE_IN_PROGRESS;
204 }
205
206 return VINF_SUCCESS;
207}
208
209/**
210 * Handles display resize event.
211 * Disables access to VGA device;
212 * calls the framebuffer RequestResize method;
213 * if framebuffer resizes synchronously,
214 * updates the display connector data and enables access to the VGA device.
215 *
216 * @param w New display width
217 * @param h New display height
218 *
219 * @thread EMT
220 */
221int Display::handleDisplayResize (uint32_t bpp, void *pvVRAM, uint32_t cbLine, int w, int h)
222{
223 LogRel (("Display::handleDisplayResize(): pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X\n",
224 pvVRAM, w, h, bpp, cbLine));
225
226 /* If there is no framebuffer, this call is not interesting. */
227 if (mFramebuffer.isNull())
228 {
229 return VINF_SUCCESS;
230 }
231
232 mLastAddress = pvVRAM;
233 mLastLineSize = cbLine;
234 mLastColorDepth = bpp,
235 mLastWidth = w;
236 mLastHeight = h;
237
238 FramebufferPixelFormat_T pixelFormat;
239
240 switch (bpp)
241 {
242 case 32: pixelFormat = FramebufferPixelFormat_PixelFormatRGB32; break;
243 case 24: pixelFormat = FramebufferPixelFormat_PixelFormatRGB24; break;
244 case 16: pixelFormat = FramebufferPixelFormat_PixelFormatRGB16; break;
245 default: pixelFormat = FramebufferPixelFormat_PixelFormatDefault; cbLine = 0;
246 }
247
248 /* Atomically set the resize status before calling the framebuffer. The new InProgress status will
249 * disable access to the VGA device by the EMT thread.
250 */
251 bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_InProgress, ResizeStatus_Void);
252 AssertReleaseMsg(f, ("f = %d\n", f));NOREF(f);
253
254 /* The framebuffer is locked in the state.
255 * The lock is kept, because the framebuffer is in undefined state.
256 */
257 mFramebuffer->Lock();
258
259 int rc = callFramebufferResize (mFramebuffer, pixelFormat, pvVRAM, cbLine, w, h);
260 if (rc == VINF_VGA_RESIZE_IN_PROGRESS)
261 {
262 /* Immediately return to the caller. ResizeCompleted will be called back by the
263 * GUI thread. The ResizeCompleted callback will change the resize status from
264 * InProgress to UpdateDisplayData. The latter status will be checked by the
265 * display timer callback on EMT and all required adjustments will be done there.
266 */
267 return rc;
268 }
269
270 /* Set the status so the 'handleResizeCompleted' would work. */
271 f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
272 AssertRelease(f);NOREF(f);
273
274 /* The method also unlocks the framebuffer. */
275 handleResizeCompletedEMT();
276
277 return VINF_SUCCESS;
278}
279
280/**
281 * Framebuffer has been resized.
282 * Read the new display data and unlock the framebuffer.
283 *
284 * @thread EMT
285 */
286void Display::handleResizeCompletedEMT (void)
287{
288 LogFlowFunc(("\n"));
289 if (!mFramebuffer.isNull())
290 {
291 /* Framebuffer has completed the resize. Update the connector data. */
292 updateDisplayData();
293
294 /* Check the framebuffer pixel format to setup the rendering in VGA device. */
295 FramebufferPixelFormat_T newPixelFormat;
296
297 mFramebuffer->COMGETTER(PixelFormat) (&newPixelFormat);
298
299 mpDrv->pUpPort->pfnSetRenderVRAM (mpDrv->pUpPort, newPixelFormat == FramebufferPixelFormat_PixelFormatDefault);
300 }
301
302#ifdef DEBUG_sunlover
303 if (!stam)
304 {
305 /* protect mpVM */
306 Console::SafeVMPtr pVM (mParent);
307 AssertComRC (pVM.rc());
308
309 STAM_REG(pVM, &StatDisplayRefresh, STAMTYPE_PROFILE, "/PROF/Display/Refresh", STAMUNIT_TICKS_PER_CALL, "Time spent in EMT for display updates.");
310 stam = 1;
311 }
312#endif /* DEBUG_sunlover */
313
314 /* Inform VRDP server about the change of display parameters. */
315 LogFlowFunc (("Calling VRDP\n"));
316 mParent->consoleVRDPServer()->SendResize();
317
318 /* Go into non resizing state. */
319 bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_Void, ResizeStatus_UpdateDisplayData);
320 AssertRelease(f);NOREF(f);
321
322 if (!mFramebuffer.isNull())
323 {
324 /* Unlock framebuffer after evrything is done. */
325 mFramebuffer->Unlock();
326 }
327}
328
329static void checkCoordBounds (int *px, int *py, int *pw, int *ph, int cx, int cy)
330{
331 /* Correct negative x and y coordinates. */
332 if (*px < 0)
333 {
334 *px += *pw; /* Compute xRight which is also the new width. */
335
336 *pw = (*px < 0)? 0: *px;
337
338 *px = 0;
339 }
340
341 if (*py < 0)
342 {
343 *py += *ph; /* Compute xBottom, which is also the new height. */
344
345 *ph = (*py < 0)? 0: *py;
346
347 *py = 0;
348 }
349
350 /* Also check if coords are greater than the display resolution. */
351 if (*px + *pw > cx)
352 {
353 *pw = cx > *px? cx - *px: 0;
354 }
355
356 if (*py + *ph > cy)
357 {
358 *ph = cy > *py? cy - *py: 0;
359 }
360}
361
362/**
363 * Handles display update event.
364 *
365 * @param x Update area x coordinate
366 * @param y Update area y coordinate
367 * @param w Update area width
368 * @param h Update area height
369 *
370 * @thread EMT
371 */
372void Display::handleDisplayUpdate (int x, int y, int w, int h)
373{
374 // if there is no framebuffer, this call is not interesting
375 if (mFramebuffer.isNull())
376 return;
377
378 mFramebuffer->Lock();
379
380#ifdef DEBUG_sunlover
381 LogFlowFunc (("%d,%d %dx%d (%d,%d)\n",
382 x, y, w, h, mpDrv->Connector.cx, mpDrv->Connector.cy));
383#endif /* DEBUG_sunlover */
384
385 checkCoordBounds (&x, &y, &w, &h, mpDrv->Connector.cx, mpDrv->Connector.cy);
386
387#ifdef DEBUG_sunlover
388 LogFlowFunc (("%d,%d %dx%d (checked)\n", x, y, w, h));
389#endif /* DEBUG_sunlover */
390
391 /* special processing for the internal framebuffer */
392 if (mInternalFramebuffer)
393 {
394 mFramebuffer->Unlock();
395 } else
396 {
397 /* callback into the framebuffer to notify it */
398 BOOL finished = FALSE;
399
400 RTSemEventMultiReset(mUpdateSem);
401
402 mFramebuffer->NotifyUpdate(x, y, w, h, &finished);
403
404 if (!finished)
405 {
406 /*
407 * the framebuffer needs more time to process
408 * the event so we have to halt the VM until it's done
409 */
410 mFramebuffer->Unlock();
411 RTSemEventMultiWait(mUpdateSem, RT_INDEFINITE_WAIT);
412 } else
413 {
414 mFramebuffer->Unlock();
415 }
416
417 if (!mfVideoAccelEnabled)
418 {
419 /* When VBVA is enabled, the VRDP server is informed in the VideoAccelFlush.
420 * Inform the server here only if VBVA is disabled.
421 */
422 mParent->consoleVRDPServer()->SendUpdateBitmap(x, y, w, h);
423 }
424 }
425 return;
426}
427
428typedef struct _VBVADIRTYREGION
429{
430 /* Copies of object's pointers used by vbvaRgn functions. */
431 IFramebuffer *pFramebuffer;
432 Display *pDisplay;
433 PPDMIDISPLAYPORT pPort;
434
435 /* The Framebuffer has default format and must be updates immediately. */
436 bool fDefaultFormat;
437
438 /* Merged rectangles. */
439 int32_t xLeft;
440 int32_t xRight;
441 int32_t yTop;
442 int32_t yBottom;
443
444} VBVADIRTYREGION;
445
446static void vbvaRgnInit (VBVADIRTYREGION *prgn, IFramebuffer *pfb, Display *pd, PPDMIDISPLAYPORT pp)
447{
448 memset (prgn, 0, sizeof (VBVADIRTYREGION));
449
450 prgn->pFramebuffer = pfb;
451 prgn->pDisplay = pd;
452 prgn->pPort = pp;
453
454 if (pfb)
455 {
456 FramebufferPixelFormat_T pixelFormat;
457 pfb->COMGETTER(PixelFormat) (&pixelFormat);
458 prgn->fDefaultFormat = (pixelFormat == FramebufferPixelFormat_PixelFormatDefault);
459 }
460
461 return;
462}
463
464static void vbvaRgnDirtyRect (VBVADIRTYREGION *prgn, VBVACMDHDR *phdr)
465{
466 LogFlowFunc (("x = %d, y = %d, w = %d, h = %d\n",
467 phdr->x, phdr->y, phdr->w, phdr->h));
468
469 /*
470 * Here update rectangles are accumulated to form an update area.
471 * @todo
472 * Now the simpliest method is used which builds one rectangle that
473 * includes all update areas. A bit more advanced method can be
474 * employed here. The method should be fast however.
475 */
476 if (phdr->w == 0 || phdr->h == 0)
477 {
478 /* Empty rectangle. */
479 return;
480 }
481
482 int32_t xRight = phdr->x + phdr->w;
483 int32_t yBottom = phdr->y + phdr->h;
484
485 if (prgn->xRight == 0)
486 {
487 /* This is the first rectangle to be added. */
488 prgn->xLeft = phdr->x;
489 prgn->yTop = phdr->y;
490 prgn->xRight = xRight;
491 prgn->yBottom = yBottom;
492 }
493 else
494 {
495 /* Adjust region coordinates. */
496 if (prgn->xLeft > phdr->x)
497 {
498 prgn->xLeft = phdr->x;
499 }
500
501 if (prgn->yTop > phdr->y)
502 {
503 prgn->yTop = phdr->y;
504 }
505
506 if (prgn->xRight < xRight)
507 {
508 prgn->xRight = xRight;
509 }
510
511 if (prgn->yBottom < yBottom)
512 {
513 prgn->yBottom = yBottom;
514 }
515 }
516
517 if (prgn->fDefaultFormat)
518 {
519 prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, phdr->x, phdr->y, phdr->w, phdr->h);
520 prgn->pDisplay->handleDisplayUpdate (phdr->x, phdr->y, phdr->w, phdr->h);
521 }
522
523 return;
524}
525
526static void vbvaRgnUpdateFramebuffer (VBVADIRTYREGION *prgn)
527{
528 uint32_t w = prgn->xRight - prgn->xLeft;
529 uint32_t h = prgn->yBottom - prgn->yTop;
530
531 if (!prgn->fDefaultFormat && prgn->pFramebuffer && w != 0 && h != 0)
532 {
533 prgn->pPort->pfnUpdateDisplayRect (prgn->pPort, prgn->xLeft, prgn->yTop, w, h);
534 prgn->pDisplay->handleDisplayUpdate (prgn->xLeft, prgn->yTop, w, h);
535 }
536}
537
538static void vbvaSetMemoryFlags (VBVAMEMORY *pVbvaMemory,
539 bool fVideoAccelEnabled,
540 bool fVideoAccelVRDP,
541 uint32_t fu32SupportedOrders)
542{
543 if (pVbvaMemory)
544 {
545 /* This called only on changes in mode. So reset VRDP always. */
546 uint32_t fu32Flags = VBVA_F_MODE_VRDP_RESET;
547
548 if (fVideoAccelEnabled)
549 {
550 fu32Flags |= VBVA_F_MODE_ENABLED;
551
552 if (fVideoAccelVRDP)
553 {
554 fu32Flags |= VBVA_F_MODE_VRDP | VBVA_F_MODE_VRDP_ORDER_MASK;
555
556 pVbvaMemory->fu32SupportedOrders = fu32SupportedOrders;
557 }
558 }
559
560 pVbvaMemory->fu32ModeFlags = fu32Flags;
561 }
562}
563
564bool Display::VideoAccelAllowed (void)
565{
566 return true;
567}
568
569/**
570 * @thread EMT
571 */
572int Display::VideoAccelEnable (bool fEnable, VBVAMEMORY *pVbvaMemory)
573{
574 int rc = VINF_SUCCESS;
575
576 /* Called each time the guest wants to use acceleration,
577 * or when the VGA device disables acceleration,
578 * or when restoring the saved state with accel enabled.
579 *
580 * VGA device disables acceleration on each video mode change
581 * and on reset.
582 *
583 * Guest enabled acceleration at will. And it has to enable
584 * acceleration after a mode change.
585 */
586 LogFlowFunc (("mfVideoAccelEnabled = %d, fEnable = %d, pVbvaMemory = %p\n",
587 mfVideoAccelEnabled, fEnable, pVbvaMemory));
588
589 /* Strictly check parameters. Callers must not pass anything in the case. */
590 Assert((fEnable && pVbvaMemory) || (!fEnable && pVbvaMemory == NULL));
591
592 if (!VideoAccelAllowed ())
593 {
594 return VERR_NOT_SUPPORTED;
595 }
596
597 /*
598 * Verify that the VM is in running state. If it is not,
599 * then this must be postponed until it goes to running.
600 */
601 if (!mfMachineRunning)
602 {
603 Assert (!mfVideoAccelEnabled);
604
605 LogFlowFunc (("Machine is not yet running.\n"));
606
607 if (fEnable)
608 {
609 mfPendingVideoAccelEnable = fEnable;
610 mpPendingVbvaMemory = pVbvaMemory;
611 }
612
613 return rc;
614 }
615
616 /* Check that current status is not being changed */
617 if (mfVideoAccelEnabled == fEnable)
618 {
619 return rc;
620 }
621
622 if (mfVideoAccelEnabled)
623 {
624 /* Process any pending orders and empty the VBVA ring buffer. */
625 VideoAccelFlush ();
626 }
627
628 if (!fEnable && mpVbvaMemory)
629 {
630 mpVbvaMemory->fu32ModeFlags &= ~VBVA_F_MODE_ENABLED;
631 }
632
633 /* Safety precaution. There is no more VBVA until everything is setup! */
634 mpVbvaMemory = NULL;
635 mfVideoAccelEnabled = false;
636
637 /* Update entire display. */
638 if (mu32ResizeStatus == ResizeStatus_Void)
639 {
640 mpDrv->pUpPort->pfnUpdateDisplayAll(mpDrv->pUpPort);
641 }
642
643 /* Everything OK. VBVA status can be changed. */
644
645 /* Notify the VMMDev, which saves VBVA status in the saved state,
646 * and needs to know current status.
647 */
648 PPDMIVMMDEVPORT pVMMDevPort = mParent->getVMMDev()->getVMMDevPort ();
649
650 if (pVMMDevPort)
651 {
652 pVMMDevPort->pfnVBVAChange (pVMMDevPort, fEnable);
653 }
654
655 if (fEnable)
656 {
657 mpVbvaMemory = pVbvaMemory;
658 mfVideoAccelEnabled = true;
659
660 /* Initialize the hardware memory. */
661 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
662 mpVbvaMemory->off32Data = 0;
663 mpVbvaMemory->off32Free = 0;
664
665 memset (mpVbvaMemory->aRecords, 0, sizeof (mpVbvaMemory->aRecords));
666 mpVbvaMemory->indexRecordFirst = 0;
667 mpVbvaMemory->indexRecordFree = 0;
668
669 LogRel(("VBVA: Enabled.\n"));
670 }
671 else
672 {
673 LogRel(("VBVA: Disabled.\n"));
674 }
675
676 LogFlowFunc (("VideoAccelEnable: rc = %Vrc.\n", rc));
677
678 return rc;
679}
680
681#ifdef VBOX_VRDP
682#ifdef VRDP_MC
683/* Called always by one VRDP server thread. Can be thread-unsafe.
684 */
685void Display::VideoAccelVRDP (bool fEnable)
686{
687#if 0
688 /* Supporting all orders. */
689 uint32_t fu32SupportedOrders = ~0;
690#endif
691
692 int c = fEnable?
693 ASMAtomicIncS32 (&mcVideoAccelVRDPRefs):
694 ASMAtomicDecS32 (&mcVideoAccelVRDPRefs);
695
696 Assert (c >= 0);
697
698 if (c == 0)
699 {
700 /* The last client has disconnected, and the accel can be
701 * disabled.
702 */
703 Assert (fEnable == false);
704
705 mfVideoAccelVRDP = false;
706 mfu32SupportedOrders = 0;
707
708 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
709
710 LogRel(("VBVA: VRDP acceleration has been disabled.\n"));
711 }
712 else if ( c == 1
713 && !mfVideoAccelVRDP)
714 {
715 /* The first client has connected. Enable the accel.
716 */
717 Assert (fEnable == true);
718
719 mfVideoAccelVRDP = true;
720 /* Supporting all orders. */
721 mfu32SupportedOrders = ~0;
722
723 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
724
725 LogRel(("VBVA: VRDP acceleration has been requested.\n"));
726 }
727 else
728 {
729 /* A client is connected or disconnected but there is no change in the
730 * accel state. It remains enabled.
731 */
732 Assert (mfVideoAccelVRDP == true);
733 }
734}
735#else
736void Display::VideoAccelVRDP (bool fEnable, uint32_t fu32SupportedOrders)
737{
738 Assert (mfVideoAccelVRDP != fEnable);
739
740 mfVideoAccelVRDP = fEnable;
741
742 if (fEnable)
743 {
744 mfu32SupportedOrders = fu32SupportedOrders;
745 }
746 else
747 {
748 mfu32SupportedOrders = 0;
749 }
750
751 vbvaSetMemoryFlags (mpVbvaMemory, mfVideoAccelEnabled, mfVideoAccelVRDP, mfu32SupportedOrders);
752
753 LogRel(("VBVA: VRDP acceleration has been %s.\n", fEnable? "requested": "disabled"));
754}
755#endif /* VRDP_MC */
756#endif /* VBOX_VRDP */
757
758static bool vbvaVerifyRingBuffer (VBVAMEMORY *pVbvaMemory)
759{
760 return true;
761}
762
763static void vbvaFetchBytes (VBVAMEMORY *pVbvaMemory, uint8_t *pu8Dst, uint32_t cbDst)
764{
765 if (cbDst >= VBVA_RING_BUFFER_SIZE)
766 {
767 AssertMsgFailed (("cbDst = 0x%08X, ring buffer size 0x%08X", cbDst, VBVA_RING_BUFFER_SIZE));
768 return;
769 }
770
771 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - pVbvaMemory->off32Data;
772 uint8_t *src = &pVbvaMemory->au8RingBuffer[pVbvaMemory->off32Data];
773 int32_t i32Diff = cbDst - u32BytesTillBoundary;
774
775 if (i32Diff <= 0)
776 {
777 /* Chunk will not cross buffer boundary. */
778 memcpy (pu8Dst, src, cbDst);
779 }
780 else
781 {
782 /* Chunk crosses buffer boundary. */
783 memcpy (pu8Dst, src, u32BytesTillBoundary);
784 memcpy (pu8Dst + u32BytesTillBoundary, &pVbvaMemory->au8RingBuffer[0], i32Diff);
785 }
786
787 /* Advance data offset. */
788 pVbvaMemory->off32Data = (pVbvaMemory->off32Data + cbDst) % VBVA_RING_BUFFER_SIZE;
789
790 return;
791}
792
793
794static bool vbvaPartialRead (uint8_t **ppu8, uint32_t *pcb, uint32_t cbRecord, VBVAMEMORY *pVbvaMemory)
795{
796 uint8_t *pu8New;
797
798 LogFlow(("MAIN::DisplayImpl::vbvaPartialRead: p = %p, cb = %d, cbRecord 0x%08X\n",
799 *ppu8, *pcb, cbRecord));
800
801 if (*ppu8)
802 {
803 Assert (*pcb);
804 pu8New = (uint8_t *)RTMemRealloc (*ppu8, cbRecord);
805 }
806 else
807 {
808 Assert (!*pcb);
809 pu8New = (uint8_t *)RTMemAlloc (cbRecord);
810 }
811
812 if (!pu8New)
813 {
814 /* Memory allocation failed, fail the function. */
815 Log(("MAIN::vbvaPartialRead: failed to (re)alocate memory for partial record!!! cbRecord 0x%08X\n",
816 cbRecord));
817
818 if (*ppu8)
819 {
820 RTMemFree (*ppu8);
821 }
822
823 *ppu8 = NULL;
824 *pcb = 0;
825
826 return false;
827 }
828
829 /* Fetch data from the ring buffer. */
830 vbvaFetchBytes (pVbvaMemory, pu8New + *pcb, cbRecord - *pcb);
831
832 *ppu8 = pu8New;
833 *pcb = cbRecord;
834
835 return true;
836}
837
838/* For contiguous chunks just return the address in the buffer.
839 * For crossing boundary - allocate a buffer from heap.
840 */
841bool Display::vbvaFetchCmd (VBVACMDHDR **ppHdr, uint32_t *pcbCmd)
842{
843 uint32_t indexRecordFirst = mpVbvaMemory->indexRecordFirst;
844 uint32_t indexRecordFree = mpVbvaMemory->indexRecordFree;
845
846#ifdef DEBUG_sunlover
847 LogFlowFunc (("first = %d, free = %d\n",
848 indexRecordFirst, indexRecordFree));
849#endif /* DEBUG_sunlover */
850
851 if (!vbvaVerifyRingBuffer (mpVbvaMemory))
852 {
853 return false;
854 }
855
856 if (indexRecordFirst == indexRecordFree)
857 {
858 /* No records to process. Return without assigning output variables. */
859 return true;
860 }
861
862 VBVARECORD *pRecord = &mpVbvaMemory->aRecords[indexRecordFirst];
863
864#ifdef DEBUG_sunlover
865 LogFlowFunc (("cbRecord = 0x%08X\n", pRecord->cbRecord));
866#endif /* DEBUG_sunlover */
867
868 uint32_t cbRecord = pRecord->cbRecord & ~VBVA_F_RECORD_PARTIAL;
869
870 if (mcbVbvaPartial)
871 {
872 /* There is a partial read in process. Continue with it. */
873
874 Assert (mpu8VbvaPartial);
875
876 LogFlowFunc (("continue partial record mcbVbvaPartial = %d cbRecord 0x%08X, first = %d, free = %d\n",
877 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
878
879 if (cbRecord > mcbVbvaPartial)
880 {
881 /* New data has been added to the record. */
882 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
883 {
884 return false;
885 }
886 }
887
888 if (!(pRecord->cbRecord & VBVA_F_RECORD_PARTIAL))
889 {
890 /* The record is completed by guest. Return it to the caller. */
891 *ppHdr = (VBVACMDHDR *)mpu8VbvaPartial;
892 *pcbCmd = mcbVbvaPartial;
893
894 mpu8VbvaPartial = NULL;
895 mcbVbvaPartial = 0;
896
897 /* Advance the record index. */
898 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
899
900#ifdef DEBUG_sunlover
901 LogFlowFunc (("partial done ok, data = %d, free = %d\n",
902 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
903#endif /* DEBUG_sunlover */
904 }
905
906 return true;
907 }
908
909 /* A new record need to be processed. */
910 if (pRecord->cbRecord & VBVA_F_RECORD_PARTIAL)
911 {
912 /* Current record is being written by guest. '=' is important here. */
913 if (cbRecord >= VBVA_RING_BUFFER_SIZE - VBVA_RING_BUFFER_THRESHOLD)
914 {
915 /* Partial read must be started. */
916 if (!vbvaPartialRead (&mpu8VbvaPartial, &mcbVbvaPartial, cbRecord, mpVbvaMemory))
917 {
918 return false;
919 }
920
921 LogFlowFunc (("started partial record mcbVbvaPartial = 0x%08X cbRecord 0x%08X, first = %d, free = %d\n",
922 mcbVbvaPartial, pRecord->cbRecord, indexRecordFirst, indexRecordFree));
923 }
924
925 return true;
926 }
927
928 /* Current record is complete. If it is not empty, process it. */
929 if (cbRecord)
930 {
931 /* The size of largest contiguos chunk in the ring biffer. */
932 uint32_t u32BytesTillBoundary = VBVA_RING_BUFFER_SIZE - mpVbvaMemory->off32Data;
933
934 /* The ring buffer pointer. */
935 uint8_t *au8RingBuffer = &mpVbvaMemory->au8RingBuffer[0];
936
937 /* The pointer to data in the ring buffer. */
938 uint8_t *src = &au8RingBuffer[mpVbvaMemory->off32Data];
939
940 /* Fetch or point the data. */
941 if (u32BytesTillBoundary >= cbRecord)
942 {
943 /* The command does not cross buffer boundary. Return address in the buffer. */
944 *ppHdr = (VBVACMDHDR *)src;
945
946 /* Advance data offset. */
947 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
948 }
949 else
950 {
951 /* The command crosses buffer boundary. Rare case, so not optimized. */
952 uint8_t *dst = (uint8_t *)RTMemAlloc (cbRecord);
953
954 if (!dst)
955 {
956 LogFlowFunc (("could not allocate %d bytes from heap!!!\n", cbRecord));
957 mpVbvaMemory->off32Data = (mpVbvaMemory->off32Data + cbRecord) % VBVA_RING_BUFFER_SIZE;
958 return false;
959 }
960
961 vbvaFetchBytes (mpVbvaMemory, dst, cbRecord);
962
963 *ppHdr = (VBVACMDHDR *)dst;
964
965#ifdef DEBUG_sunlover
966 LogFlowFunc (("Allocated from heap %p\n", dst));
967#endif /* DEBUG_sunlover */
968 }
969 }
970
971 *pcbCmd = cbRecord;
972
973 /* Advance the record index. */
974 mpVbvaMemory->indexRecordFirst = (indexRecordFirst + 1) % VBVA_MAX_RECORDS;
975
976#ifdef DEBUG_sunlover
977 LogFlowFunc (("done ok, data = %d, free = %d\n",
978 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
979#endif /* DEBUG_sunlover */
980
981 return true;
982}
983
984void Display::vbvaReleaseCmd (VBVACMDHDR *pHdr, int32_t cbCmd)
985{
986 uint8_t *au8RingBuffer = mpVbvaMemory->au8RingBuffer;
987
988 if ( (uint8_t *)pHdr >= au8RingBuffer
989 && (uint8_t *)pHdr < &au8RingBuffer[VBVA_RING_BUFFER_SIZE])
990 {
991 /* The pointer is inside ring buffer. Must be continuous chunk. */
992 Assert (VBVA_RING_BUFFER_SIZE - ((uint8_t *)pHdr - au8RingBuffer) >= cbCmd);
993
994 /* Do nothing. */
995
996 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
997 }
998 else
999 {
1000 /* The pointer is outside. It is then an allocated copy. */
1001
1002#ifdef DEBUG_sunlover
1003 LogFlowFunc (("Free heap %p\n", pHdr));
1004#endif /* DEBUG_sunlover */
1005
1006 if ((uint8_t *)pHdr == mpu8VbvaPartial)
1007 {
1008 mpu8VbvaPartial = NULL;
1009 mcbVbvaPartial = 0;
1010 }
1011 else
1012 {
1013 Assert (!mpu8VbvaPartial && mcbVbvaPartial == 0);
1014 }
1015
1016 RTMemFree (pHdr);
1017 }
1018
1019 return;
1020}
1021
1022
1023/**
1024 * Called regularly on the DisplayRefresh timer.
1025 * Also on behalf of guest, when the ring buffer is full.
1026 *
1027 * @thread EMT
1028 */
1029void Display::VideoAccelFlush (void)
1030{
1031#ifdef DEBUG_sunlover
1032 LogFlowFunc (("mfVideoAccelEnabled = %d\n", mfVideoAccelEnabled));
1033#endif /* DEBUG_sunlover */
1034
1035 if (!mfVideoAccelEnabled)
1036 {
1037 Log(("Display::VideoAccelFlush: called with disabled VBVA!!! Ignoring.\n"));
1038 return;
1039 }
1040
1041 /* Here VBVA is enabled and we have the accelerator memory pointer. */
1042 Assert(mpVbvaMemory);
1043
1044#ifdef DEBUG_sunlover
1045 LogFlowFunc (("indexRecordFirst = %d, indexRecordFree = %d, off32Data = %d, off32Free = %d\n",
1046 mpVbvaMemory->indexRecordFirst, mpVbvaMemory->indexRecordFree, mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1047#endif /* DEBUG_sunlover */
1048
1049 /* Quick check for "nothing to update" case. */
1050 if (mpVbvaMemory->indexRecordFirst == mpVbvaMemory->indexRecordFree)
1051 {
1052 return;
1053 }
1054
1055 /* Process the ring buffer */
1056
1057 bool fFramebufferIsNull = mFramebuffer.isNull();
1058
1059 if (!fFramebufferIsNull)
1060 {
1061 mFramebuffer->Lock();
1062 }
1063
1064 /* Initialize dirty rectangles accumulator. */
1065 VBVADIRTYREGION rgn;
1066 vbvaRgnInit (&rgn, mFramebuffer, this, mpDrv->pUpPort);
1067
1068 for (;;)
1069 {
1070 VBVACMDHDR *phdr = NULL;
1071 uint32_t cbCmd = ~0;
1072
1073 /* Fetch the command data. */
1074 if (!vbvaFetchCmd (&phdr, &cbCmd))
1075 {
1076 Log(("Display::VideoAccelFlush: unable to fetch command. off32Data = %d, off32Free = %d. Disabling VBVA!!!\n",
1077 mpVbvaMemory->off32Data, mpVbvaMemory->off32Free));
1078
1079 /* Disable VBVA on those processing errors. */
1080 VideoAccelEnable (false, NULL);
1081
1082 break;
1083 }
1084
1085 if (cbCmd == uint32_t(~0))
1086 {
1087 /* No more commands yet in the queue. */
1088 break;
1089 }
1090
1091 if (cbCmd != 0 && !fFramebufferIsNull)
1092 {
1093#ifdef DEBUG_sunlover
1094 LogFlowFunc (("hdr: cbCmd = %d, x=%d, y=%d, w=%d, h=%d\n",
1095 cbCmd, phdr->x, phdr->y, phdr->w, phdr->h));
1096#endif /* DEBUG_sunlover */
1097
1098 if (mu32ResizeStatus == ResizeStatus_Void)
1099 {
1100 /* Handle the command.
1101 *
1102 * Guest is responsible for updating the guest video memory.
1103 * The Windows guest does all drawing using Eng*.
1104 *
1105 * For local output, only dirty rectangle information is used
1106 * to update changed areas.
1107 *
1108 * Dirty rectangles are accumulated to exclude overlapping updates and
1109 * group small updates to a larger one.
1110 */
1111
1112 /* Accumulate the update. */
1113 vbvaRgnDirtyRect (&rgn, phdr);
1114
1115 /* Forward the command to VRDP server. */
1116 mParent->consoleVRDPServer()->SendUpdate (phdr, cbCmd);
1117 }
1118 }
1119
1120 vbvaReleaseCmd (phdr, cbCmd);
1121 }
1122
1123 if (!fFramebufferIsNull)
1124 {
1125 mFramebuffer->Unlock ();
1126 }
1127
1128 if (mu32ResizeStatus == ResizeStatus_Void)
1129 {
1130 /* Draw the framebuffer. */
1131 vbvaRgnUpdateFramebuffer (&rgn);
1132 }
1133}
1134
1135
1136// IDisplay properties
1137/////////////////////////////////////////////////////////////////////////////
1138
1139/**
1140 * Returns the current display width in pixel
1141 *
1142 * @returns COM status code
1143 * @param width Address of result variable.
1144 */
1145STDMETHODIMP Display::COMGETTER(Width) (ULONG *width)
1146{
1147 if (!width)
1148 return E_POINTER;
1149
1150 AutoLock alock (this);
1151 CHECK_READY();
1152
1153 CHECK_CONSOLE_DRV (mpDrv);
1154
1155 *width = mpDrv->Connector.cx;
1156 return S_OK;
1157}
1158
1159/**
1160 * Returns the current display height in pixel
1161 *
1162 * @returns COM status code
1163 * @param height Address of result variable.
1164 */
1165STDMETHODIMP Display::COMGETTER(Height) (ULONG *height)
1166{
1167 if (!height)
1168 return E_POINTER;
1169
1170 AutoLock alock (this);
1171 CHECK_READY();
1172
1173 CHECK_CONSOLE_DRV (mpDrv);
1174
1175 *height = mpDrv->Connector.cy;
1176 return S_OK;
1177}
1178
1179/**
1180 * Returns the current display color depth in bits
1181 *
1182 * @returns COM status code
1183 * @param colorDepth Address of result variable.
1184 */
1185STDMETHODIMP Display::COMGETTER(ColorDepth) (ULONG *colorDepth)
1186{
1187 if (!colorDepth)
1188 return E_INVALIDARG;
1189
1190 AutoLock alock (this);
1191 CHECK_READY();
1192
1193 CHECK_CONSOLE_DRV (mpDrv);
1194
1195 uint32_t cBits = 0;
1196 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1197 AssertRC(rc);
1198 *colorDepth = cBits;
1199 return S_OK;
1200}
1201
1202
1203// IDisplay methods
1204/////////////////////////////////////////////////////////////////////////////
1205
1206STDMETHODIMP Display::SetupInternalFramebuffer (ULONG depth)
1207{
1208 LogFlowFunc (("\n"));
1209
1210 AutoLock lock (this);
1211 CHECK_READY();
1212
1213 /*
1214 * Create an internal framebuffer only if depth is not zero. Otherwise, we
1215 * reset back to the "black hole" state as it was at Display construction.
1216 */
1217 ComPtr <IFramebuffer> frameBuf;
1218 if (depth)
1219 {
1220 ComObjPtr <InternalFramebuffer> internal;
1221 internal.createObject();
1222 internal->init (640, 480, depth);
1223 frameBuf = internal; // query interface
1224 }
1225
1226 Console::SafeVMPtrQuiet pVM (mParent);
1227 if (pVM.isOk())
1228 {
1229 /* Must leave the lock here because the changeFramebuffer will also obtain it. */
1230 lock.leave ();
1231
1232 /* send request to the EMT thread */
1233 PVMREQ pReq = NULL;
1234 int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
1235 (PFNRT) changeFramebuffer, 3,
1236 this, static_cast <IFramebuffer *> (frameBuf),
1237 true /* aInternal */);
1238 if (VBOX_SUCCESS (vrc))
1239 vrc = pReq->iStatus;
1240 VMR3ReqFree (pReq);
1241
1242 lock.enter ();
1243
1244 ComAssertRCRet (vrc, E_FAIL);
1245 }
1246 else
1247 {
1248 /* No VM is created (VM is powered off), do a direct call */
1249 int vrc = changeFramebuffer (this, frameBuf, true /* aInternal */);
1250 ComAssertRCRet (vrc, E_FAIL);
1251 }
1252
1253 return S_OK;
1254}
1255
1256STDMETHODIMP Display::LockFramebuffer (BYTE **address)
1257{
1258 if (!address)
1259 return E_POINTER;
1260
1261 AutoLock lock(this);
1262 CHECK_READY();
1263
1264 /* only allowed for internal framebuffers */
1265 if (mInternalFramebuffer && !mFramebufferOpened && !mFramebuffer.isNull())
1266 {
1267 CHECK_CONSOLE_DRV (mpDrv);
1268
1269 mFramebuffer->Lock();
1270 mFramebufferOpened = true;
1271 *address = mpDrv->Connector.pu8Data;
1272 return S_OK;
1273 }
1274
1275 return setError (E_FAIL,
1276 tr ("Framebuffer locking is allowed only for the internal framebuffer"));
1277}
1278
1279STDMETHODIMP Display::UnlockFramebuffer()
1280{
1281 AutoLock lock(this);
1282 CHECK_READY();
1283
1284 if (mFramebufferOpened)
1285 {
1286 CHECK_CONSOLE_DRV (mpDrv);
1287
1288 mFramebuffer->Unlock();
1289 mFramebufferOpened = false;
1290 return S_OK;
1291 }
1292
1293 return setError (E_FAIL,
1294 tr ("Framebuffer locking is allowed only for the internal framebuffer"));
1295}
1296
1297STDMETHODIMP Display::RegisterExternalFramebuffer (IFramebuffer *frameBuf)
1298{
1299 LogFlowFunc (("\n"));
1300
1301 if (!frameBuf)
1302 return E_POINTER;
1303
1304 AutoLock lock (this);
1305 CHECK_READY();
1306
1307 Console::SafeVMPtrQuiet pVM (mParent);
1308 if (pVM.isOk())
1309 {
1310 /* Must leave the lock here because the changeFramebuffer will also obtain it. */
1311 lock.leave ();
1312
1313 /* send request to the EMT thread */
1314 PVMREQ pReq = NULL;
1315 int vrc = VMR3ReqCall (pVM, &pReq, RT_INDEFINITE_WAIT,
1316 (PFNRT) changeFramebuffer, 3,
1317 this, frameBuf, false /* aInternal */);
1318 if (VBOX_SUCCESS (vrc))
1319 vrc = pReq->iStatus;
1320 VMR3ReqFree (pReq);
1321
1322 lock.enter ();
1323
1324 ComAssertRCRet (vrc, E_FAIL);
1325 }
1326 else
1327 {
1328 /* No VM is created (VM is powered off), do a direct call */
1329 int vrc = changeFramebuffer (this, frameBuf, false /* aInternal */);
1330 ComAssertRCRet (vrc, E_FAIL);
1331 }
1332
1333 return S_OK;
1334}
1335
1336STDMETHODIMP Display::SetVideoModeHint(ULONG aWidth, ULONG aHeight, ULONG aColorDepth, ULONG aDisplay)
1337{
1338 AutoLock lock(this);
1339 CHECK_READY();
1340
1341 CHECK_CONSOLE_DRV (mpDrv);
1342
1343 /*
1344 * Do some rough checks for valid input
1345 */
1346 ULONG width = aWidth;
1347 if (!width)
1348 width = mpDrv->Connector.cx;
1349 ULONG height = aHeight;
1350 if (!height)
1351 height = mpDrv->Connector.cy;
1352 ULONG bpp = aColorDepth;
1353 if (!bpp)
1354 {
1355 uint32_t cBits = 0;
1356 int rc = mpDrv->pUpPort->pfnQueryColorDepth(mpDrv->pUpPort, &cBits);
1357 AssertRC(rc);
1358 bpp = cBits;
1359 }
1360 ULONG cMonitors;
1361 mParent->machine()->COMGETTER(MonitorCount)(&cMonitors);
1362 if (cMonitors == 0 && aDisplay > 0)
1363 return E_INVALIDARG;
1364 if (aDisplay >= cMonitors)
1365 return E_INVALIDARG;
1366
1367// sunlover 20070614: It is up to the guest to decide whether the hint is valid.
1368// ULONG vramSize;
1369// mParent->machine()->COMGETTER(VRAMSize)(&vramSize);
1370// /* enough VRAM? */
1371// if ((width * height * (bpp / 8)) > (vramSize * 1024 * 1024))
1372// return setError(E_FAIL, tr("Not enough VRAM for the selected video mode"));
1373
1374 if (mParent->getVMMDev())
1375 mParent->getVMMDev()->getVMMDevPort()->pfnRequestDisplayChange(mParent->getVMMDev()->getVMMDevPort(), aWidth, aHeight, aColorDepth, aDisplay);
1376 return S_OK;
1377}
1378
1379STDMETHODIMP Display::TakeScreenShot (BYTE *address, ULONG width, ULONG height)
1380{
1381 /// @todo (r=dmik) this function may take too long to complete if the VM
1382 // is doing something like saving state right now. Which, in case if it
1383 // is called on the GUI thread, will make it unresponsive. We should
1384 // check the machine state here (by enclosing the check and VMRequCall
1385 // within the Console lock to make it atomic).
1386
1387 LogFlowFuncEnter();
1388 LogFlowFunc (("address=%p, width=%d, height=%d\n",
1389 address, width, height));
1390
1391 if (!address)
1392 return E_POINTER;
1393 if (!width || !height)
1394 return E_INVALIDARG;
1395
1396 AutoLock lock(this);
1397 CHECK_READY();
1398
1399 CHECK_CONSOLE_DRV (mpDrv);
1400
1401 Console::SafeVMPtr pVM (mParent);
1402 CheckComRCReturnRC (pVM.rc());
1403
1404 HRESULT rc = S_OK;
1405
1406 LogFlowFunc (("Sending SCREENSHOT request\n"));
1407
1408 /*
1409 * First try use the graphics device features for making a snapshot.
1410 * This does not support streatching, is an optional feature (returns not supported).
1411 *
1412 * Note: It may cause a display resize. Watch out for deadlocks.
1413 */
1414 int rcVBox = VERR_NOT_SUPPORTED;
1415 if ( mpDrv->Connector.cx == width
1416 && mpDrv->Connector.cy == height)
1417 {
1418 PVMREQ pReq;
1419 size_t cbData = RT_ALIGN_Z(width, 4) * 4 * height;
1420 rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
1421 (PFNRT)mpDrv->pUpPort->pfnSnapshot, 6, mpDrv->pUpPort,
1422 address, cbData, NULL, NULL, NULL);
1423 if (VBOX_SUCCESS(rcVBox))
1424 {
1425 rcVBox = pReq->iStatus;
1426 VMR3ReqFree(pReq);
1427 }
1428 }
1429
1430 /*
1431 * If the function returns not supported, or if streaching is requested,
1432 * we'll have to do all the work ourselves using the framebuffer data.
1433 */
1434 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1435 {
1436 /** @todo implement snapshot streching and generic snapshot fallback. */
1437 rc = setError (E_NOTIMPL, tr ("This feature is not implemented"));
1438 }
1439 else if (VBOX_FAILURE(rcVBox))
1440 rc = setError (E_FAIL,
1441 tr ("Could not take a screenshot (%Vrc)"), rcVBox);
1442
1443 LogFlowFunc (("rc=%08X\n", rc));
1444 LogFlowFuncLeave();
1445 return rc;
1446}
1447
1448STDMETHODIMP Display::DrawToScreen (BYTE *address, ULONG x, ULONG y,
1449 ULONG width, ULONG height)
1450{
1451 /// @todo (r=dmik) this function may take too long to complete if the VM
1452 // is doing something like saving state right now. Which, in case if it
1453 // is called on the GUI thread, will make it unresponsive. We should
1454 // check the machine state here (by enclosing the check and VMRequCall
1455 // within the Console lock to make it atomic).
1456
1457 LogFlowFuncEnter();
1458 LogFlowFunc (("address=%p, x=%d, y=%d, width=%d, height=%d\n",
1459 address, x, y, width, height));
1460
1461 if (!address)
1462 return E_POINTER;
1463 if (!width || !height)
1464 return E_INVALIDARG;
1465
1466 AutoLock lock(this);
1467 CHECK_READY();
1468
1469 CHECK_CONSOLE_DRV (mpDrv);
1470
1471 Console::SafeVMPtr pVM (mParent);
1472 CheckComRCReturnRC (pVM.rc());
1473
1474 /*
1475 * Again we're lazy and make the graphics device do all the
1476 * dirty convertion work.
1477 */
1478 PVMREQ pReq;
1479 int rcVBox = VMR3ReqCall(pVM, &pReq, RT_INDEFINITE_WAIT,
1480 (PFNRT)mpDrv->pUpPort->pfnDisplayBlt, 6, mpDrv->pUpPort,
1481 address, x, y, width, height);
1482 if (VBOX_SUCCESS(rcVBox))
1483 {
1484 rcVBox = pReq->iStatus;
1485 VMR3ReqFree(pReq);
1486 }
1487
1488 /*
1489 * If the function returns not supported, we'll have to do all the
1490 * work ourselves using the framebuffer.
1491 */
1492 HRESULT rc = S_OK;
1493 if (rcVBox == VERR_NOT_SUPPORTED || rcVBox == VERR_NOT_IMPLEMENTED)
1494 {
1495 /** @todo implement generic fallback for screen blitting. */
1496 rc = E_NOTIMPL;
1497 }
1498 else if (VBOX_FAILURE(rcVBox))
1499 rc = setError (E_FAIL,
1500 tr ("Could not draw to the screen (%Vrc)"), rcVBox);
1501//@todo
1502// else
1503// {
1504// /* All ok. Redraw the screen. */
1505// handleDisplayUpdate (x, y, width, height);
1506// }
1507
1508 LogFlowFunc (("rc=%08X\n", rc));
1509 LogFlowFuncLeave();
1510 return rc;
1511}
1512
1513/**
1514 * Does a full invalidation of the VM display and instructs the VM
1515 * to update it immediately.
1516 *
1517 * @returns COM status code
1518 */
1519STDMETHODIMP Display::InvalidateAndUpdate()
1520{
1521 LogFlowFuncEnter();
1522
1523 AutoLock lock(this);
1524 CHECK_READY();
1525
1526 CHECK_CONSOLE_DRV (mpDrv);
1527
1528 Console::SafeVMPtr pVM (mParent);
1529 CheckComRCReturnRC (pVM.rc());
1530
1531 HRESULT rc = S_OK;
1532
1533 LogFlowFunc (("Sending DPYUPDATE request\n"));
1534
1535 /* pdm.h says that this has to be called from the EMT thread */
1536 PVMREQ pReq;
1537 int rcVBox = VMR3ReqCallVoid(pVM, &pReq, RT_INDEFINITE_WAIT,
1538 (PFNRT)mpDrv->pUpPort->pfnUpdateDisplayAll, 1, mpDrv->pUpPort);
1539 if (VBOX_SUCCESS(rcVBox))
1540 VMR3ReqFree(pReq);
1541
1542 if (VBOX_FAILURE(rcVBox))
1543 rc = setError (E_FAIL,
1544 tr ("Could not invalidate and update the screen (%Vrc)"), rcVBox);
1545
1546 LogFlowFunc (("rc=%08X\n", rc));
1547 LogFlowFuncLeave();
1548 return rc;
1549}
1550
1551/**
1552 * Notification that the framebuffer has completed the
1553 * asynchronous resize processing
1554 *
1555 * @returns COM status code
1556 */
1557STDMETHODIMP Display::ResizeCompleted()
1558{
1559 LogFlowFunc (("\n"));
1560
1561 /// @todo (dmik) can we AutoLock alock (this); here?
1562 // do it when we switch this class to VirtualBoxBase_NEXT.
1563 // This will require general code review and may add some details.
1564 // In particular, we may want to check whether EMT is really waiting for
1565 // this notification, etc. It might be also good to obey the caller to make
1566 // sure this method is not called from more than one thread at a time
1567 // (and therefore don't use Display lock at all here to save some
1568 // milliseconds).
1569 CHECK_READY();
1570
1571 /* this is only valid for external framebuffers */
1572 if (mInternalFramebuffer)
1573 return setError (E_FAIL,
1574 tr ("Resize completed notification is valid only "
1575 "for external framebuffers"));
1576
1577 /* Set the flag indicating that the resize has completed and display data need to be updated. */
1578 bool f = ASMAtomicCmpXchgU32 (&mu32ResizeStatus, ResizeStatus_UpdateDisplayData, ResizeStatus_InProgress);
1579 AssertRelease(f);NOREF(f);
1580
1581 return S_OK;
1582}
1583
1584/**
1585 * Notification that the framebuffer has completed the
1586 * asynchronous update processing
1587 *
1588 * @returns COM status code
1589 */
1590STDMETHODIMP Display::UpdateCompleted()
1591{
1592 LogFlowFunc (("\n"));
1593
1594 /// @todo (dmik) can we AutoLock alock (this); here?
1595 // do it when we switch this class to VirtualBoxBase_NEXT.
1596 // Tthis will require general code review and may add some details.
1597 // In particular, we may want to check whether EMT is really waiting for
1598 // this notification, etc. It might be also good to obey the caller to make
1599 // sure this method is not called from more than one thread at a time
1600 // (and therefore don't use Display lock at all here to save some
1601 // milliseconds).
1602 CHECK_READY();
1603
1604 /* this is only valid for external framebuffers */
1605 if (mInternalFramebuffer)
1606 return setError (E_FAIL,
1607 tr ("Resize completed notification is valid only "
1608 "for external framebuffers"));
1609
1610 mFramebuffer->Lock();
1611 /* signal our semaphore */
1612 RTSemEventMultiSignal(mUpdateSem);
1613 mFramebuffer->Unlock();
1614
1615 return S_OK;
1616}
1617
1618// private methods
1619/////////////////////////////////////////////////////////////////////////////
1620
1621/**
1622 * Helper to update the display information from the framebuffer.
1623 *
1624 * @param aCheckParams true to compare the parameters of the current framebuffer
1625 * and the new one and issue handleDisplayResize()
1626 * if they differ.
1627 * @thread EMT
1628 */
1629void Display::updateDisplayData (bool aCheckParams /* = false */)
1630{
1631 /* the driver might not have been constructed yet */
1632 if (!mpDrv)
1633 return;
1634
1635#if DEBUG
1636 /*
1637 * Sanity check. Note that this method may be called on EMT after Console
1638 * has started the power down procedure (but before our #drvDestruct() is
1639 * called, in which case pVM will aleady be NULL but mpDrv will not). Since
1640 * we don't really need pVM to proceed, we avoid this check in the release
1641 * build to save some ms (necessary to construct SafeVMPtrQuiet) in this
1642 * time-critical method.
1643 */
1644 Console::SafeVMPtrQuiet pVM (mParent);
1645 if (pVM.isOk())
1646 VM_ASSERT_EMT (pVM.raw());
1647#endif
1648
1649 if (mFramebuffer)
1650 {
1651 HRESULT rc;
1652 BYTE *address = 0;
1653 rc = mFramebuffer->COMGETTER(Address) (&address);
1654 AssertComRC (rc);
1655 ULONG lineSize = 0;
1656 rc = mFramebuffer->COMGETTER(LineSize) (&lineSize);
1657 AssertComRC (rc);
1658 ULONG colorDepth = 0;
1659 rc = mFramebuffer->COMGETTER(ColorDepth) (&colorDepth);
1660 AssertComRC (rc);
1661 ULONG width = 0;
1662 rc = mFramebuffer->COMGETTER(Width) (&width);
1663 AssertComRC (rc);
1664 ULONG height = 0;
1665 rc = mFramebuffer->COMGETTER(Height) (&height);
1666 AssertComRC (rc);
1667
1668 /*
1669 * Check current parameters with new ones and issue handleDisplayResize()
1670 * to let the new frame buffer adjust itself properly. Note that it will
1671 * result into a recursive updateDisplayData() call but with
1672 * aCheckOld = false.
1673 */
1674 if (aCheckParams &&
1675 (mLastAddress != address ||
1676 mLastLineSize != lineSize ||
1677 mLastColorDepth != colorDepth ||
1678 mLastWidth != (int) width ||
1679 mLastHeight != (int) height))
1680 {
1681 handleDisplayResize (mLastColorDepth,
1682 mLastAddress,
1683 mLastLineSize,
1684 mLastWidth,
1685 mLastHeight);
1686 return;
1687 }
1688
1689 mpDrv->Connector.pu8Data = (uint8_t *) address;
1690 mpDrv->Connector.cbScanline = lineSize;
1691 mpDrv->Connector.cBits = colorDepth;
1692 mpDrv->Connector.cx = width;
1693 mpDrv->Connector.cy = height;
1694 }
1695 else
1696 {
1697 /* black hole */
1698 mpDrv->Connector.pu8Data = NULL;
1699 mpDrv->Connector.cbScanline = 0;
1700 mpDrv->Connector.cBits = 0;
1701 mpDrv->Connector.cx = 0;
1702 mpDrv->Connector.cy = 0;
1703 }
1704}
1705
1706/**
1707 * Changes the current frame buffer. Called on EMT to avoid both
1708 * race conditions and excessive locking.
1709 *
1710 * @note locks this object for writing
1711 * @thread EMT
1712 */
1713/* static */
1714DECLCALLBACK(int) Display::changeFramebuffer (Display *that, IFramebuffer *aFB,
1715 bool aInternal)
1716{
1717 LogFlowFunc (("\n"));
1718
1719 AssertReturn (that, VERR_INVALID_PARAMETER);
1720 AssertReturn (aFB || aInternal, VERR_INVALID_PARAMETER);
1721
1722 /// @todo (r=dmik) AutoCaller
1723
1724 AutoLock alock (that);
1725
1726 that->mFramebuffer = aFB;
1727 that->mInternalFramebuffer = aInternal;
1728 that->mSupportedAccelOps = 0;
1729
1730 /* determine which acceleration functions are supported by this framebuffer */
1731 if (aFB && !aInternal)
1732 {
1733 HRESULT rc;
1734 BOOL accelSupported = FALSE;
1735 rc = aFB->OperationSupported (
1736 FramebufferAccelerationOperation_SolidFillAcceleration, &accelSupported);
1737 AssertComRC (rc);
1738 if (accelSupported)
1739 that->mSupportedAccelOps |=
1740 FramebufferAccelerationOperation_SolidFillAcceleration;
1741 accelSupported = FALSE;
1742 rc = aFB->OperationSupported (
1743 FramebufferAccelerationOperation_ScreenCopyAcceleration, &accelSupported);
1744 AssertComRC (rc);
1745 if (accelSupported)
1746 that->mSupportedAccelOps |=
1747 FramebufferAccelerationOperation_ScreenCopyAcceleration;
1748 }
1749
1750 that->mParent->consoleVRDPServer()->
1751 SetFramebuffer (aFB, aFB ? VRDP_EXTERNAL_FRAMEBUFFER :
1752 VRDP_INTERNAL_FRAMEBUFFER);
1753
1754 that->updateDisplayData (true /* aCheckParams */);
1755
1756 return VINF_SUCCESS;
1757}
1758
1759/**
1760 * Handle display resize event.
1761 *
1762 * @see PDMIDISPLAYCONNECTOR::pfnResize
1763 */
1764DECLCALLBACK(int) Display::displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
1765 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
1766{
1767 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1768
1769 LogFlowFunc (("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
1770 bpp, pvVRAM, cbLine, cx, cy));
1771
1772 return pDrv->pDisplay->handleDisplayResize(bpp, pvVRAM, cbLine, cx, cy);
1773}
1774
1775/**
1776 * Handle display update.
1777 *
1778 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
1779 */
1780DECLCALLBACK(void) Display::displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
1781 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
1782{
1783 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1784
1785#ifdef DEBUG_sunlover
1786 LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d, %d,%d %dx%d\n",
1787 pDrv->pDisplay->mfVideoAccelEnabled, x, y, cx, cy));
1788#endif /* DEBUG_sunlover */
1789
1790 /* This call does update regardless of VBVA status.
1791 * But in VBVA mode this is called only as result of
1792 * pfnUpdateDisplayAll in the VGA device.
1793 */
1794
1795 pDrv->pDisplay->handleDisplayUpdate(x, y, cx, cy);
1796}
1797
1798/**
1799 * Periodic display refresh callback.
1800 *
1801 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
1802 */
1803DECLCALLBACK(void) Display::displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
1804{
1805 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1806
1807#ifdef DEBUG_sunlover
1808 STAM_PROFILE_START(&StatDisplayRefresh, a);
1809#endif /* DEBUG_sunlover */
1810
1811#ifdef DEBUG_sunlover
1812 LogFlowFunc (("pDrv->pDisplay->mfVideoAccelEnabled = %d\n",
1813 pDrv->pDisplay->mfVideoAccelEnabled));
1814#endif /* DEBUG_sunlover */
1815
1816 Display *pDisplay = pDrv->pDisplay;
1817
1818 /* Check the resize status. The status can be checked normally because
1819 * the status affects only the EMT.
1820 */
1821 uint32_t u32ResizeStatus = pDisplay->mu32ResizeStatus;
1822
1823 if (u32ResizeStatus == ResizeStatus_UpdateDisplayData)
1824 {
1825 LogFlowFunc (("ResizeStatus_UpdateDisplayData\n"));
1826 /* The framebuffer was resized and display data need to be updated. */
1827 pDisplay->handleResizeCompletedEMT ();
1828 /* Continue with normal processing because the status here is ResizeStatus_Void. */
1829 Assert (pDisplay->mu32ResizeStatus == ResizeStatus_Void);
1830 /* Repaint the display because VM continued to run during the framebuffer resize. */
1831 if (!pDisplay->mFramebuffer.isNull())
1832 pDrv->pUpPort->pfnUpdateDisplayAll(pDrv->pUpPort);
1833 /* Ignore the refresh to replay the logic. */
1834 return;
1835 }
1836 else if (u32ResizeStatus == ResizeStatus_InProgress)
1837 {
1838 /* The framebuffer is being resized. Do not call the VGA device back. Immediately return. */
1839 LogFlowFunc (("ResizeStatus_InProcess\n"));
1840 return;
1841 }
1842
1843 if (pDisplay->mFramebuffer.isNull())
1844 {
1845 /*
1846 * Do nothing in the "black hole" mode to avoid copying guest
1847 * video memory to the frame buffer
1848 */
1849 }
1850 else
1851 {
1852 if (pDisplay->mfPendingVideoAccelEnable)
1853 {
1854 /* Acceleration was enabled while machine was not yet running
1855 * due to restoring from saved state. Update entire display and
1856 * actually enable acceleration.
1857 */
1858 Assert(pDisplay->mpPendingVbvaMemory);
1859
1860 /* Acceleration can not be yet enabled.*/
1861 Assert(pDisplay->mpVbvaMemory == NULL);
1862 Assert(!pDisplay->mfVideoAccelEnabled);
1863
1864 if (pDisplay->mfMachineRunning)
1865 {
1866 pDisplay->VideoAccelEnable (pDisplay->mfPendingVideoAccelEnable,
1867 pDisplay->mpPendingVbvaMemory);
1868
1869 /* Reset the pending state. */
1870 pDisplay->mfPendingVideoAccelEnable = false;
1871 pDisplay->mpPendingVbvaMemory = NULL;
1872 }
1873 }
1874 else
1875 {
1876 Assert(pDisplay->mpPendingVbvaMemory == NULL);
1877
1878 if (pDisplay->mfVideoAccelEnabled)
1879 {
1880 Assert(pDisplay->mpVbvaMemory);
1881 pDisplay->VideoAccelFlush ();
1882 }
1883 else
1884 {
1885 Assert(pDrv->Connector.pu8Data);
1886 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
1887 }
1888 }
1889#ifdef VRDP_MC
1890 /* Inform to VRDP server that the current display update sequence is
1891 * completed. At this moment the framebuffer memory contains a definite
1892 * image, that is synchronized with the orders already sent to VRDP client.
1893 * The server can now process redraw requests from clients or initial
1894 * fullscreen updates for new clients.
1895 */
1896 Assert (pDisplay->mParent && pDisplay->mParent->consoleVRDPServer());
1897 pDisplay->mParent->consoleVRDPServer()->SendUpdate (NULL, 0);
1898#endif /* VRDP_MC */
1899 }
1900
1901#ifdef DEBUG_sunlover
1902 STAM_PROFILE_STOP(&StatDisplayRefresh, a);
1903#endif /* DEBUG_sunlover */
1904}
1905
1906/**
1907 * Reset notification
1908 *
1909 * @see PDMIDISPLAYCONNECTOR::pfnReset
1910 */
1911DECLCALLBACK(void) Display::displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
1912{
1913 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1914
1915 LogFlowFunc (("\n"));
1916
1917 /* Disable VBVA mode. */
1918 pDrv->pDisplay->VideoAccelEnable (false, NULL);
1919}
1920
1921/**
1922 * LFBModeChange notification
1923 *
1924 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
1925 */
1926DECLCALLBACK(void) Display::displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
1927{
1928 PDRVMAINDISPLAY pDrv = PDMIDISPLAYCONNECTOR_2_MAINDISPLAY(pInterface);
1929
1930 LogFlowFunc (("fEnabled=%d\n", fEnabled));
1931
1932 NOREF(fEnabled);
1933
1934 /* Disable VBVA mode in any case. The guest driver reenables VBVA mode if necessary. */
1935 pDrv->pDisplay->VideoAccelEnable (false, NULL);
1936}
1937
1938/**
1939 * Queries an interface to the driver.
1940 *
1941 * @returns Pointer to interface.
1942 * @returns NULL if the interface was not supported by the driver.
1943 * @param pInterface Pointer to this interface structure.
1944 * @param enmInterface The requested interface identification.
1945 */
1946DECLCALLBACK(void *) Display::drvQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1947{
1948 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
1949 PDRVMAINDISPLAY pDrv = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1950 switch (enmInterface)
1951 {
1952 case PDMINTERFACE_BASE:
1953 return &pDrvIns->IBase;
1954 case PDMINTERFACE_DISPLAY_CONNECTOR:
1955 return &pDrv->Connector;
1956 default:
1957 return NULL;
1958 }
1959}
1960
1961
1962/**
1963 * Destruct a display driver instance.
1964 *
1965 * @returns VBox status.
1966 * @param pDrvIns The driver instance data.
1967 */
1968DECLCALLBACK(void) Display::drvDestruct(PPDMDRVINS pDrvIns)
1969{
1970 PDRVMAINDISPLAY pData = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1971 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
1972 if (pData->pDisplay)
1973 {
1974 AutoLock displayLock (pData->pDisplay);
1975 pData->pDisplay->mpDrv = NULL;
1976 pData->pDisplay->mpVMMDev = NULL;
1977 pData->pDisplay->mLastAddress = NULL;
1978 pData->pDisplay->mLastLineSize = 0;
1979 pData->pDisplay->mLastColorDepth = 0,
1980 pData->pDisplay->mLastWidth = 0;
1981 pData->pDisplay->mLastHeight = 0;
1982 }
1983}
1984
1985
1986/**
1987 * Construct a display driver instance.
1988 *
1989 * @returns VBox status.
1990 * @param pDrvIns The driver instance data.
1991 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
1992 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
1993 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
1994 * iInstance it's expected to be used a bit in this function.
1995 */
1996DECLCALLBACK(int) Display::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
1997{
1998 PDRVMAINDISPLAY pData = PDMINS2DATA(pDrvIns, PDRVMAINDISPLAY);
1999 LogFlowFunc (("iInstance=%d\n", pDrvIns->iInstance));
2000
2001 /*
2002 * Validate configuration.
2003 */
2004 if (!CFGMR3AreValuesValid(pCfgHandle, "Object\0"))
2005 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
2006 PPDMIBASE pBaseIgnore;
2007 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseIgnore);
2008 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2009 {
2010 AssertMsgFailed(("Configuration error: Not possible to attach anything to this driver!\n"));
2011 return VERR_PDM_DRVINS_NO_ATTACH;
2012 }
2013
2014 /*
2015 * Init Interfaces.
2016 */
2017 pDrvIns->IBase.pfnQueryInterface = Display::drvQueryInterface;
2018
2019 pData->Connector.pfnResize = Display::displayResizeCallback;
2020 pData->Connector.pfnUpdateRect = Display::displayUpdateCallback;
2021 pData->Connector.pfnRefresh = Display::displayRefreshCallback;
2022 pData->Connector.pfnReset = Display::displayResetCallback;
2023 pData->Connector.pfnLFBModeChange = Display::displayLFBModeChangeCallback;
2024
2025 /*
2026 * Get the IDisplayPort interface of the above driver/device.
2027 */
2028 pData->pUpPort = (PPDMIDISPLAYPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_DISPLAY_PORT);
2029 if (!pData->pUpPort)
2030 {
2031 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
2032 return VERR_PDM_MISSING_INTERFACE_ABOVE;
2033 }
2034
2035 /*
2036 * Get the Display object pointer and update the mpDrv member.
2037 */
2038 void *pv;
2039 rc = CFGMR3QueryPtr(pCfgHandle, "Object", &pv);
2040 if (VBOX_FAILURE(rc))
2041 {
2042 AssertMsgFailed(("Configuration error: No/bad \"Object\" value! rc=%Vrc\n", rc));
2043 return rc;
2044 }
2045 pData->pDisplay = (Display *)pv; /** @todo Check this cast! */
2046 pData->pDisplay->mpDrv = pData;
2047
2048 /*
2049 * Update our display information according to the framebuffer
2050 */
2051 pData->pDisplay->updateDisplayData();
2052
2053 /*
2054 * Start periodic screen refreshes
2055 */
2056 pData->pUpPort->pfnSetRefreshRate(pData->pUpPort, 20);
2057
2058 return VINF_SUCCESS;
2059}
2060
2061
2062/**
2063 * Display driver registration record.
2064 */
2065const PDMDRVREG Display::DrvReg =
2066{
2067 /* u32Version */
2068 PDM_DRVREG_VERSION,
2069 /* szDriverName */
2070 "MainDisplay",
2071 /* pszDescription */
2072 "Main display driver (Main as in the API).",
2073 /* fFlags */
2074 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
2075 /* fClass. */
2076 PDM_DRVREG_CLASS_DISPLAY,
2077 /* cMaxInstances */
2078 ~0,
2079 /* cbInstance */
2080 sizeof(DRVMAINDISPLAY),
2081 /* pfnConstruct */
2082 Display::drvConstruct,
2083 /* pfnDestruct */
2084 Display::drvDestruct,
2085 /* pfnIOCtl */
2086 NULL,
2087 /* pfnPowerOn */
2088 NULL,
2089 /* pfnReset */
2090 NULL,
2091 /* pfnSuspend */
2092 NULL,
2093 /* pfnResume */
2094 NULL,
2095 /* pfnDetach */
2096 NULL
2097};
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