VirtualBox

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

Last change on this file since 15741 was 15732, checked in by vboxsync, 16 years ago

#3285: Improve error handling API to include unique error numbers
Document

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