VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxVideo/Modesetting.cpp@ 106945

Last change on this file since 106945 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1/* $Id: Modesetting.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - HGSMI initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
9 *
10 * Permission is hereby granted, free of charge, to any person
11 * obtaining a copy of this software and associated documentation
12 * files (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use,
14 * copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following
17 * conditions:
18 *
19 * The above copyright notice and this permission notice shall be
20 * included in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29 * OTHER DEALINGS IN THE SOFTWARE.
30 */
31
32#include <VBoxVideoGuest.h>
33#include <VBoxVideoVBE.h>
34#include <HGSMIChannels.h>
35
36#ifndef VBOX_GUESTR3XF86MOD
37# include <VBoxVideoIPRT.h>
38#endif
39
40/**
41 * Gets the count of virtual monitors attached to the guest via an HGSMI
42 * command
43 *
44 * @returns the right count on success or 1 on failure.
45 * @param pCtx the context containing the heap to use
46 */
47DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx)
48{
49 /* Query the configured number of displays. */
50 uint32_t cDisplays = 0;
51 VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_MONITOR_COUNT, &cDisplays);
52 // LogFunc(("cDisplays = %d\n", cDisplays));
53 if (cDisplays == 0 || cDisplays > VBOX_VIDEO_MAX_SCREENS)
54 /* Host reported some bad value. Continue in the 1 screen mode. */
55 cDisplays = 1;
56 return cDisplays;
57}
58
59
60/**
61 * Query whether the virtual hardware supports VBE_DISPI_ID_CFG
62 * and set the interface.
63 *
64 * @returns Whether the interface is supported.
65 */
66DECLHIDDEN(bool) VBoxVGACfgAvailable(void)
67{
68 uint16_t DispiId;
69 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
70 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_CFG);
71 DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
72 return (DispiId == VBE_DISPI_ID_CFG);
73}
74
75
76/**
77 * Query a configuration value from the virtual hardware which supports VBE_DISPI_ID_CFG.
78 * I.e. use this function only if VBoxVGACfgAvailable returns true.
79 *
80 * @returns Whether the value is supported.
81 * @param u16Id Identifier of the configuration value (VBE_DISPI_CFG_ID_*).
82 * @param pu32Value Where to store value from the host.
83 * @param u32DefValue What to assign to *pu32Value if the value is not supported.
84 */
85DECLHIDDEN(bool) VBoxVGACfgQuery(uint16_t u16Id, uint32_t *pu32Value, uint32_t u32DefValue)
86{
87 uint32_t u32;
88 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_CFG);
89 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_CFG_MASK_SUPPORT | u16Id);
90 u32 = VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
91 if (u32)
92 {
93 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, u16Id);
94 *pu32Value = VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
95 return true;
96 }
97
98 *pu32Value = u32DefValue;
99 return false;
100}
101
102
103/**
104 * Returns the size of the video RAM in bytes.
105 *
106 * @returns the size
107 */
108DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void)
109{
110 /** @note A 32bit read on this port returns the VRAM size if interface is older than VBE_DISPI_ID_CFG. */
111 return VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
112}
113
114
115/**
116 * Check whether this hardware allows the display width to have non-multiple-
117 * of-eight values.
118 *
119 * @returns true if any width is allowed, false otherwise.
120 */
121DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void)
122{
123 unsigned DispiId;
124 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
125 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
126 DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
127 return (DispiId == VBE_DISPI_ID_ANYX);
128}
129
130
131/**
132 * Tell the host about how VRAM is divided up between each screen via an HGSMI
133 * command. It is acceptable to specifiy identical data for each screen if
134 * they share a single framebuffer.
135 *
136 * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
137 * @a pfnFill
138 * @todo What was I thinking of with that callback function? It
139 * would be much simpler to just pass in a structure in normal
140 * memory and copy it.
141 * @param pCtx the context containing the heap to use
142 * @param u32Count the number of screens we are activating
143 * @param pfnFill a callback which initialises the VBVAINFOVIEW structures
144 * for all screens
145 * @param pvData context data for @a pfnFill
146 */
147DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
148 uint32_t u32Count,
149 PFNHGSMIFILLVIEWINFO pfnFill,
150 void *pvData)
151{
152 int rc;
153 /* Issue the screen info command. */
154 VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_HOST *pInfo =
155 (VBVAINFOVIEW RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
156 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
157 if (pInfo)
158 {
159 rc = pfnFill(pvData, (VBVAINFOVIEW *)pInfo /* lazy bird */, u32Count);
160 if (RT_SUCCESS(rc))
161 VBoxHGSMIBufferSubmit(pCtx, pInfo);
162 VBoxHGSMIBufferFree(pCtx, pInfo);
163 }
164 else
165 rc = VERR_NO_MEMORY;
166 return rc;
167}
168
169
170/**
171 * Set a video mode using port registers. This must be done for the first
172 * screen before every HGSMI modeset and also works when HGSM is not enabled.
173 * @param cWidth the mode width
174 * @param cHeight the mode height
175 * @param cVirtWidth the mode pitch
176 * @param cBPP the colour depth of the mode
177 * @param fFlags flags for the mode. These will be or-ed with the
178 * default _ENABLED flag, so unless you are restoring
179 * a saved mode or have special requirements you can pass
180 * zero here.
181 * @param cx the horizontal panning offset
182 * @param cy the vertical panning offset
183 */
184DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
185 uint16_t cVirtWidth, uint16_t cBPP,
186 uint16_t fFlags, uint16_t cx,
187 uint16_t cy)
188{
189 /* set the mode characteristics */
190 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
191 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cWidth);
192 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
193 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cHeight);
194 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
195 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cVirtWidth);
196 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
197 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cBPP);
198 /* enable the mode */
199 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
200 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, fFlags | VBE_DISPI_ENABLED);
201 /* Panning registers */
202 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
203 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cx);
204 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
205 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cy);
206 /** @todo read from the port to see if the mode switch was successful */
207}
208
209
210/**
211 * Get the video mode for the first screen using the port registers. All
212 * parameters are optional
213 * @returns true if the VBE mode returned is active, false if we are in VGA
214 * mode
215 * @note If anyone else needs additional register values just extend the
216 * function with additional parameters and fix any existing callers.
217 * @param pcWidth where to store the mode width
218 * @param pcHeight where to store the mode height
219 * @param pcVirtWidth where to store the mode pitch
220 * @param pcBPP where to store the colour depth of the mode
221 * @param pfFlags where to store the flags for the mode
222 */
223DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
224 uint16_t *pcVirtWidth, uint16_t *pcBPP,
225 uint16_t *pfFlags)
226{
227 uint16_t fFlags;
228
229 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
230 fFlags = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
231 if (pcWidth)
232 {
233 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
234 *pcWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
235 }
236 if (pcHeight)
237 {
238 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
239 *pcHeight = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
240 }
241 if (pcVirtWidth)
242 {
243 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
244 *pcVirtWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
245 }
246 if (pcBPP)
247 {
248 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
249 *pcBPP = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
250 }
251 if (pfFlags)
252 *pfFlags = fFlags;
253 return RT_BOOL(fFlags & VBE_DISPI_ENABLED);
254}
255
256
257/**
258 * Disable our extended graphics mode and go back to VGA mode.
259 */
260DECLHIDDEN(void) VBoxVideoDisableVBE(void)
261{
262 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
263 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, 0);
264}
265
266
267/**
268 * Set a video mode via an HGSMI request. The views must have been
269 * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
270 * set on the first display then it must be set first using registers.
271 * @param pCtx The context containing the heap to use.
272 * @param cDisplay the screen number
273 * @param cOriginX the horizontal displacement relative to the first screen
274 * @param cOriginY the vertical displacement relative to the first screen
275 * @param offStart the offset of the visible area of the framebuffer
276 * relative to the framebuffer start
277 * @param cbPitch the offset in bytes between the starts of two adjecent
278 * scan lines in video RAM
279 * @param cWidth the mode width
280 * @param cHeight the mode height
281 * @param cBPP the colour depth of the mode
282 * @param fFlags flags
283 */
284DECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
285 uint32_t cDisplay,
286 int32_t cOriginX,
287 int32_t cOriginY,
288 uint32_t offStart,
289 uint32_t cbPitch,
290 uint32_t cWidth,
291 uint32_t cHeight,
292 uint16_t cBPP,
293 uint16_t fFlags)
294{
295 /* Issue the screen info command. */
296 VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_HOST *pScreen =
297 (VBVAINFOSCREEN RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOSCREEN),
298 HGSMI_CH_VBVA, VBVA_INFO_SCREEN);
299 if (pScreen != NULL)
300 {
301 pScreen->u32ViewIndex = cDisplay;
302 pScreen->i32OriginX = cOriginX;
303 pScreen->i32OriginY = cOriginY;
304 pScreen->u32StartOffset = offStart;
305 pScreen->u32LineSize = cbPitch;
306 pScreen->u32Width = cWidth;
307 pScreen->u32Height = cHeight;
308 pScreen->u16BitsPerPixel = cBPP;
309 pScreen->u16Flags = fFlags;
310
311 VBoxHGSMIBufferSubmit(pCtx, pScreen);
312
313 VBoxHGSMIBufferFree(pCtx, pScreen);
314 }
315 else
316 {
317 // LogFunc(("HGSMIHeapAlloc failed\n"));
318 }
319}
320
321
322/** Report the rectangle relative to which absolute pointer events should be
323 * expressed. This information remains valid until the next VBVA resize event
324 * for any screen, at which time it is reset to the bounding rectangle of all
325 * virtual screens.
326 * @param pCtx The context containing the heap to use.
327 * @param cOriginX Upper left X co-ordinate relative to the first screen.
328 * @param cOriginY Upper left Y co-ordinate relative to the first screen.
329 * @param cWidth Rectangle width.
330 * @param cHeight Rectangle height.
331 * @returns iprt status code.
332 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
333 */
334DECLHIDDEN(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY,
335 uint32_t cWidth, uint32_t cHeight)
336{
337 int rc;
338 VBVAREPORTINPUTMAPPING *p;
339 // Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
340 // (unsigned)cWidth, (unsigned)cHeight));
341
342 /* Allocate the IO buffer. */
343 p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
344 VBVA_REPORT_INPUT_MAPPING);
345 if (p)
346 {
347 /* Prepare data to be sent to the host. */
348 p->x = cOriginX;
349 p->y = cOriginY;
350 p->cx = cWidth;
351 p->cy = cHeight;
352 rc = VBoxHGSMIBufferSubmit(pCtx, p);
353 /* Free the IO buffer. */
354 VBoxHGSMIBufferFree(pCtx, p);
355 }
356 else
357 rc = VERR_NO_MEMORY;
358 // LogFunc(("rc = %d\n", rc));
359 return rc;
360}
361
362
363/**
364 * Get most recent video mode hints.
365 * @param pCtx the context containing the heap to use
366 * @param cScreens the number of screens to query hints for, starting at 0.
367 * @param paHints array of VBVAMODEHINT structures for receiving the hints.
368 * @returns iprt status code
369 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
370 * @returns VERR_NOT_SUPPORTED Host does not support this command.
371 */
372DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
373 unsigned cScreens, VBVAMODEHINT *paHints)
374{
375 int rc;
376 VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_HOST *pQuery;
377
378 AssertPtrReturn(paHints, VERR_INVALID_POINTER);
379 pQuery = (VBVAQUERYMODEHINTS RT_UNTRUSTED_VOLATILE_HOST *)VBoxHGSMIBufferAlloc(pCtx,
380 sizeof(VBVAQUERYMODEHINTS)
381 + cScreens * sizeof(VBVAMODEHINT),
382 HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
383 if (pQuery != NULL)
384 {
385 pQuery->cHintsQueried = cScreens;
386 pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
387 pQuery->rc = VERR_NOT_SUPPORTED;
388
389 VBoxHGSMIBufferSubmit(pCtx, pQuery);
390 rc = pQuery->rc;
391 if (RT_SUCCESS(rc))
392 memcpy(paHints, (void *)(pQuery + 1), cScreens * sizeof(VBVAMODEHINT));
393
394 VBoxHGSMIBufferFree(pCtx, pQuery);
395 }
396 else
397 {
398 // LogFunc(("HGSMIHeapAlloc failed\n"));
399 rc = VERR_NO_MEMORY;
400 }
401 return rc;
402}
403
404
405/**
406 * Query the supported flags in VBVAINFOSCREEN::u16Flags.
407 *
408 * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
409 * @param pCtx the context containing the heap to use
410 */
411DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
412{
413 uint32_t u32Flags = 0;
414 int rc = VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, &u32Flags);
415 // LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
416 if (RT_FAILURE(rc) || u32Flags > UINT16_MAX)
417 u32Flags = 0;
418 return (uint16_t)u32Flags;
419}
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