VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/Display.cpp

Last change on this file was 99890, checked in by vboxsync, 13 months ago

FE/VBoxBFE: Some crude keyboard implementation for some input support inside the guest for now, bugref:10397

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.6 KB
Line 
1/* $Id: Display.cpp 99890 2023-05-22 10:40:30Z vboxsync $ */
2/** @file
3 * VirtualBox COM class implementation
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_DISPLAY
29#include "Display.h"
30
31#include <iprt/semaphore.h>
32#include <iprt/thread.h>
33#include <iprt/asm.h>
34#include <iprt/time.h>
35#include <iprt/cpp/utils.h>
36#include <iprt/alloca.h>
37#include <iprt/uuid.h>
38
39#include <VBox/vmm/vmmr3vtable.h>
40#include <VBox/vmm/pdmdrv.h>
41
42/**
43 * Display driver instance data.
44 *
45 * @implements PDMIDISPLAYCONNECTOR
46 */
47typedef struct DRVMAINDISPLAY
48{
49 /** Pointer to the display object. */
50 Display *pDisplay;
51 /** Pointer to the driver instance structure. */
52 PPDMDRVINS pDrvIns;
53 /** Pointer to the display port interface of the driver/device above us. */
54 PPDMIDISPLAYPORT pUpPort;
55 /** Our display connector interface. */
56 PDMIDISPLAYCONNECTOR IConnector;
57} DRVMAINDISPLAY, *PDRVMAINDISPLAY;
58
59// constructor / destructor
60/////////////////////////////////////////////////////////////////////////////
61
62Display::Display()
63{
64}
65
66Display::~Display()
67{
68 if (mpDrv)
69 mpDrv->pDisplay = NULL;
70
71 mpDrv = NULL;
72}
73
74
75// public methods only for internal purposes
76/////////////////////////////////////////////////////////////////////////////
77
78int Display::SetFramebuffer(unsigned iScreenID, Framebuffer *pFramebuffer)
79{
80 RT_NOREF(iScreenID);
81 m_pFramebuffer = pFramebuffer;
82 return VINF_SUCCESS;
83}
84
85
86/**
87 * Handles display resize event.
88 *
89 * @param uScreenId Screen ID
90 * @param bpp New bits per pixel.
91 * @param pvVRAM VRAM pointer.
92 * @param cbLine New bytes per line.
93 * @param w New display width.
94 * @param h New display height.
95 * @param flags Flags of the new video mode.
96 * @param xOrigin New display origin X.
97 * @param yOrigin New display origin Y.
98 * @param fVGAResize Whether the resize is originated from the VGA device (DevVGA).
99 */
100int Display::i_handleDisplayResize(unsigned uScreenId, uint32_t bpp, void *pvVRAM,
101 uint32_t cbLine, uint32_t w, uint32_t h, uint16_t flags,
102 int32_t xOrigin, int32_t yOrigin, bool fVGAResize)
103{
104 LogRel2(("Display::i_handleDisplayResize: uScreenId=%d pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X flags=0x%X\n", uScreenId,
105 pvVRAM, w, h, bpp, cbLine, flags));
106
107 if (uScreenId == 0 && mpDrv)
108 {
109 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, false);
110
111 mpDrv->IConnector.pbData = NULL;
112 mpDrv->IConnector.cbScanline = 0;
113 mpDrv->IConnector.cBits = 32;
114 mpDrv->IConnector.cx = 0;
115 mpDrv->IConnector.cy = 0;
116 }
117
118 /* Log changes. */
119 LogRel(("Display::i_handleDisplayResize: uScreenId=%d pvVRAM=%p w=%d h=%d bpp=%d cbLine=0x%X flags=0x%X origin=%d,%d\n",
120 uScreenId, pvVRAM, w, h, bpp, cbLine, flags, xOrigin, yOrigin));
121
122 int vrc = m_pFramebuffer->notifyChange(uScreenId, 0, 0, w, h);
123 LogFunc(("NotifyChange vrc=%Rrc\n", vrc));
124
125 return VINF_SUCCESS;
126}
127
128
129/**
130 * Handle display update
131 *
132 * @returns COM status code
133 * @param w New display width
134 * @param h New display height
135 */
136void Display::i_handleDisplayUpdate (int x, int y, int w, int h)
137{
138 // if there is no Framebuffer, this call is not interesting
139 if (m_pFramebuffer == NULL)
140 return;
141
142 //m_pFramebuffer->Lock();
143 m_pFramebuffer->notifyUpdate(x, y, w, h);
144 //m_pFramebuffer->Unlock();
145}
146
147
148void Display::i_invalidateAndUpdateScreen(uint32_t aScreenId)
149{
150 mpDrv->IConnector.pbData = m_pFramebuffer->getPixelData();
151 mpDrv->IConnector.cbScanline = m_pFramebuffer->getBytesPerLine();
152 mpDrv->IConnector.cBits = m_pFramebuffer->getBitsPerPixel();
153 mpDrv->IConnector.cx = m_pFramebuffer->getWidth();
154 mpDrv->IConnector.cy = m_pFramebuffer->getHeight();
155
156 mpDrv->pUpPort->pfnSetRenderVRAM(mpDrv->pUpPort, true);
157}
158
159
160// private methods
161/////////////////////////////////////////////////////////////////////////////
162
163/**
164 * Handle display resize event issued by the VGA device for the primary screen.
165 *
166 * @see PDMIDISPLAYCONNECTOR::pfnResize
167 */
168DECLCALLBACK(int) Display::i_displayResizeCallback(PPDMIDISPLAYCONNECTOR pInterface,
169 uint32_t bpp, void *pvVRAM, uint32_t cbLine, uint32_t cx, uint32_t cy)
170{
171 PDRVMAINDISPLAY pDrv = RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector);
172 Display *pThis = pDrv->pDisplay;
173
174 LogRelFlowFunc(("bpp %d, pvVRAM %p, cbLine %d, cx %d, cy %d\n",
175 bpp, pvVRAM, cbLine, cx, cy));
176
177 bool f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, true, false);
178 if (!f)
179 {
180 /* This is a result of recursive call when the source bitmap is being updated
181 * during a VGA resize. Tell the VGA device to ignore the call.
182 *
183 * @todo It is a workaround, actually pfnUpdateDisplayAll must
184 * fail on resize.
185 */
186 LogRel(("displayResizeCallback: already processing\n"));
187 return VINF_VGA_RESIZE_IN_PROGRESS;
188 }
189
190 int vrc = pThis->i_handleDisplayResize(0, bpp, pvVRAM, cbLine, cx, cy, 0, 0, 0, true);
191
192 /* Restore the flag. */
193 f = ASMAtomicCmpXchgBool(&pThis->fVGAResizing, false, true);
194 AssertRelease(f);
195
196 return vrc;
197}
198
199/**
200 * Handle display update.
201 *
202 * @see PDMIDISPLAYCONNECTOR::pfnUpdateRect
203 */
204DECLCALLBACK(void) Display::i_displayUpdateCallback(PPDMIDISPLAYCONNECTOR pInterface,
205 uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)
206{
207 PDRVMAINDISPLAY pDrv = RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector);
208
209 pDrv->pDisplay->i_handleDisplayUpdate(x, y, cx, cy);
210}
211
212/**
213 * Periodic display refresh callback.
214 *
215 * @see PDMIDISPLAYCONNECTOR::pfnRefresh
216 * @thread EMT
217 */
218/*static*/ DECLCALLBACK(void) Display::i_displayRefreshCallback(PPDMIDISPLAYCONNECTOR pInterface)
219{
220 PDRVMAINDISPLAY pDrv = RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector);
221 Display *pDisplay = pDrv->pDisplay;
222
223 pDrv->pUpPort->pfnUpdateDisplay(pDrv->pUpPort);
224}
225
226/**
227 * Reset notification
228 *
229 * @see PDMIDISPLAYCONNECTOR::pfnReset
230 */
231DECLCALLBACK(void) Display::i_displayResetCallback(PPDMIDISPLAYCONNECTOR pInterface)
232{
233 RT_NOREF(pInterface);
234 LogRelFlowFunc(("\n"));
235}
236
237/**
238 * LFBModeChange notification
239 *
240 * @see PDMIDISPLAYCONNECTOR::pfnLFBModeChange
241 */
242DECLCALLBACK(void) Display::i_displayLFBModeChangeCallback(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)
243{
244 RT_NOREF(pInterface, fEnabled);
245}
246
247/**
248 * Adapter information change notification.
249 *
250 * @see PDMIDISPLAYCONNECTOR::pfnProcessAdapterData
251 */
252DECLCALLBACK(void) Display::i_displayProcessAdapterDataCallback(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM,
253 uint32_t u32VRAMSize)
254{
255 PDRVMAINDISPLAY pDrv = RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector);
256 //pDrv->pDisplay->processAdapterData(pvVRAM, u32VRAMSize);
257}
258
259/**
260 * Display information change notification.
261 *
262 * @see PDMIDISPLAYCONNECTOR::pfnProcessDisplayData
263 */
264DECLCALLBACK(void) Display::i_displayProcessDisplayDataCallback(PPDMIDISPLAYCONNECTOR pInterface,
265 void *pvVRAM, unsigned uScreenId)
266{
267 PDRVMAINDISPLAY pDrv = RT_FROM_MEMBER(pInterface, DRVMAINDISPLAY, IConnector);
268 //pDrv->pDisplay->processDisplayData(pvVRAM, uScreenId);
269}
270
271
272/**
273 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
274 */
275DECLCALLBACK(void *) Display::i_drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
276{
277 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
278 PDRVMAINDISPLAY pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
279 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
280 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIDISPLAYCONNECTOR, &pDrv->IConnector);
281 return NULL;
282}
283
284
285/**
286 * @interface_method_impl{PDMDRVREG,pfnPowerOff,
287 * Tries to ensure no client calls gets to HGCM or the VGA device from here on.}
288 */
289DECLCALLBACK(void) Display::i_drvPowerOff(PPDMDRVINS pDrvIns)
290{
291 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
292 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
293
294 /*
295 * Do much of the work that i_drvDestruct does.
296 */
297 if (pThis->pUpPort)
298 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
299
300 pThis->IConnector.pbData = NULL;
301 pThis->IConnector.cbScanline = 0;
302 pThis->IConnector.cBits = 32;
303 pThis->IConnector.cx = 0;
304 pThis->IConnector.cy = 0;
305}
306
307
308/**
309 * Destruct a display driver instance.
310 *
311 * @returns VBox status code.
312 * @param pDrvIns The driver instance data.
313 */
314DECLCALLBACK(void) Display::i_drvDestruct(PPDMDRVINS pDrvIns)
315{
316 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
317 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
318 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
319
320 /*
321 * We repeat much of what i_drvPowerOff does in case it wasn't called.
322 * In addition we sever the connection between us and the display.
323 */
324 if (pThis->pUpPort)
325 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
326
327 pThis->IConnector.pbData = NULL;
328 pThis->IConnector.cbScanline = 0;
329 pThis->IConnector.cBits = 32;
330 pThis->IConnector.cx = 0;
331 pThis->IConnector.cy = 0;
332
333 if (pThis->pDisplay)
334 {
335 pThis->pDisplay->mpDrv = NULL;
336 pThis->pDisplay = NULL;
337 }
338}
339
340
341/**
342 * Construct a display driver instance.
343 *
344 * @copydoc FNPDMDRVCONSTRUCT
345 */
346DECLCALLBACK(int) Display::i_drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
347{
348 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
349 RT_NOREF(fFlags, pCfg);
350 PDRVMAINDISPLAY pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINDISPLAY);
351 LogRelFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
352
353 /*
354 * Validate configuration.
355 */
356 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
357 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
358 ("Configuration error: Not possible to attach anything to this driver!\n"),
359 VERR_PDM_DRVINS_NO_ATTACH);
360
361 /*
362 * Init Interfaces.
363 */
364 pDrvIns->IBase.pfnQueryInterface = Display::i_drvQueryInterface;
365
366 pThis->IConnector.pfnResize = Display::i_displayResizeCallback;
367 pThis->IConnector.pfnUpdateRect = Display::i_displayUpdateCallback;
368 pThis->IConnector.pfnRefresh = Display::i_displayRefreshCallback;
369 pThis->IConnector.pfnReset = Display::i_displayResetCallback;
370 pThis->IConnector.pfnLFBModeChange = Display::i_displayLFBModeChangeCallback;
371 pThis->IConnector.pfnProcessAdapterData = Display::i_displayProcessAdapterDataCallback;
372 pThis->IConnector.pfnProcessDisplayData = Display::i_displayProcessDisplayDataCallback;
373
374 /*
375 * Get the IDisplayPort interface of the above driver/device.
376 */
377 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIDISPLAYPORT);
378 if (!pThis->pUpPort)
379 {
380 AssertMsgFailed(("Configuration error: No display port interface above!\n"));
381 return VERR_PDM_MISSING_INTERFACE_ABOVE;
382 }
383
384 /*
385 * Get the Display object pointer and update the mpDrv member.
386 */
387 RTUUID UuidDisp;
388 RTUuidFromStr(&UuidDisp, DISPLAY_OID);
389 Display *pDisplay = (Display *)PDMDrvHlpQueryGenericUserObject(pDrvIns, &UuidDisp);
390 if (!pDisplay)
391 {
392 AssertMsgFailed(("Configuration error: No/bad Display object!\n"));
393 return VERR_NOT_FOUND;
394 }
395 pThis->pDisplay = pDisplay;
396 pThis->pDisplay->mpDrv = pThis;
397
398 /* Disable VRAM to a buffer copy initially. */
399 pThis->pUpPort->pfnSetRenderVRAM(pThis->pUpPort, false);
400 pThis->IConnector.cBits = 32; /* DevVGA does nothing otherwise. */
401
402 /*
403 * Start periodic screen refreshes
404 */
405 pThis->pUpPort->pfnSetRefreshRate(pThis->pUpPort, 20);
406
407 return VINF_SUCCESS;
408}
409
410
411/**
412 * Display driver registration record.
413 */
414const PDMDRVREG Display::DrvReg =
415{
416 /* u32Version */
417 PDM_DRVREG_VERSION,
418 /* szName */
419 "MainDisplay",
420 /* szRCMod */
421 "",
422 /* szR0Mod */
423 "",
424 /* pszDescription */
425 "Main display driver (Main as in the API).",
426 /* fFlags */
427 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
428 /* fClass. */
429 PDM_DRVREG_CLASS_DISPLAY,
430 /* cMaxInstances */
431 ~0U,
432 /* cbInstance */
433 sizeof(DRVMAINDISPLAY),
434 /* pfnConstruct */
435 Display::i_drvConstruct,
436 /* pfnDestruct */
437 Display::i_drvDestruct,
438 /* pfnRelocate */
439 NULL,
440 /* pfnIOCtl */
441 NULL,
442 /* pfnPowerOn */
443 NULL,
444 /* pfnReset */
445 NULL,
446 /* pfnSuspend */
447 NULL,
448 /* pfnResume */
449 NULL,
450 /* pfnAttach */
451 NULL,
452 /* pfnDetach */
453 NULL,
454 /* pfnPowerOff */
455 Display::i_drvPowerOff,
456 /* pfnSoftReset */
457 NULL,
458 /* u32EndVersion */
459 PDM_DRVREG_VERSION
460};
461
462/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use