VirtualBox

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

Last change on this file since 71146 was 71146, checked in by vboxsync, 7 years ago

DevVGA, Additions: added VBE_DISPI_ID_CFG for querying the virtual graphics card features.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.5 KB
Line 
1/* $Id: Modesetting.cpp 71146 2018-02-28 09:54:40Z vboxsync $ */
2/** @file
3 * VirtualBox Video driver, common code - HGSMI initialisation and helper
4 * functions.
5 */
6
7/*
8 * Copyright (C) 2006-2017 Oracle Corporation
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 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
69 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_CFG);
70 const uint16_t DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
71 return (DispiId == VBE_DISPI_ID_CFG);
72}
73
74
75/**
76 * Query a configuration value from the virtual hardware which supports VBE_DISPI_ID_CFG.
77 * I.e. use this function only if VBoxVGACfgAvailable returns true.
78 *
79 * @returns Whether the value is supported.
80 * @param u16Id Identifier of the configuration value (VBE_DISPI_CFG_ID_*).
81 * @param pu32Value Where to store value from the host.
82 */
83DECLHIDDEN(bool) VBoxVGACfgQuery(uint16_t u16Id, uint32_t *pu32Value)
84{
85 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_CFG);
86 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_CFG_MASK_SUPPORT | u16Id);
87 const uint32_t u32 = VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
88 if (u32)
89 {
90 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, u16Id);
91 *pu32Value = VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
92 return true;
93 }
94
95 return false;
96}
97
98
99/**
100 * Returns the size of the video RAM in bytes.
101 *
102 * @returns the size
103 */
104DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void)
105{
106 /** @note A 32bit read on this port returns the VRAM size if interface is older than VBE_DISPI_ID_CFG. */
107 return VBVO_PORT_READ_U32(VBE_DISPI_IOPORT_DATA);
108}
109
110
111/**
112 * Check whether this hardware allows the display width to have non-multiple-
113 * of-eight values.
114 *
115 * @returns true if any width is allowed, false otherwise.
116 */
117DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void)
118{
119 unsigned DispiId;
120 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ID);
121 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, VBE_DISPI_ID_ANYX);
122 DispiId = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
123 return (DispiId == VBE_DISPI_ID_ANYX);
124}
125
126
127/**
128 * Tell the host about how VRAM is divided up between each screen via an HGSMI
129 * command. It is acceptable to specifiy identical data for each screen if
130 * they share a single framebuffer.
131 *
132 * @returns iprt status code, either VERR_NO_MEMORY or the status returned by
133 * @a pfnFill
134 * @todo What was I thinking of with that callback function? It
135 * would be much simpler to just pass in a structure in normal
136 * memory and copy it.
137 * @param pCtx the context containing the heap to use
138 * @param u32Count the number of screens we are activating
139 * @param pfnFill a callback which initialises the VBVAINFOVIEW structures
140 * for all screens
141 * @param pvData context data for @a pfnFill
142 */
143DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
144 uint32_t u32Count,
145 PFNHGSMIFILLVIEWINFO pfnFill,
146 void *pvData)
147{
148 int rc;
149 /* Issue the screen info command. */
150 void *p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAINFOVIEW) * u32Count,
151 HGSMI_CH_VBVA, VBVA_INFO_VIEW);
152 if (p)
153 {
154 VBVAINFOVIEW *pInfo = (VBVAINFOVIEW *)p;
155 rc = pfnFill(pvData, pInfo, u32Count);
156 if (RT_SUCCESS(rc))
157 VBoxHGSMIBufferSubmit (pCtx, p);
158 VBoxHGSMIBufferFree(pCtx, p);
159 }
160 else
161 rc = VERR_NO_MEMORY;
162 return rc;
163}
164
165
166/**
167 * Set a video mode using port registers. This must be done for the first
168 * screen before every HGSMI modeset and also works when HGSM is not enabled.
169 * @param cWidth the mode width
170 * @param cHeight the mode height
171 * @param cVirtWidth the mode pitch
172 * @param cBPP the colour depth of the mode
173 * @param fFlags flags for the mode. These will be or-ed with the
174 * default _ENABLED flag, so unless you are restoring
175 * a saved mode or have special requirements you can pass
176 * zero here.
177 * @param cx the horizontal panning offset
178 * @param cy the vertical panning offset
179 */
180DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight,
181 uint16_t cVirtWidth, uint16_t cBPP,
182 uint16_t fFlags, uint16_t cx,
183 uint16_t cy)
184{
185 /* set the mode characteristics */
186 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
187 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cWidth);
188 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
189 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cHeight);
190 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
191 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cVirtWidth);
192 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
193 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cBPP);
194 /* enable the mode */
195 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
196 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, fFlags | VBE_DISPI_ENABLED);
197 /* Panning registers */
198 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_X_OFFSET);
199 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cx);
200 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_Y_OFFSET);
201 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, cy);
202 /** @todo read from the port to see if the mode switch was successful */
203}
204
205
206/**
207 * Get the video mode for the first screen using the port registers. All
208 * parameters are optional
209 * @returns true if the VBE mode returned is active, false if we are in VGA
210 * mode
211 * @note If anyone else needs additional register values just extend the
212 * function with additional parameters and fix any existing callers.
213 * @param pcWidth where to store the mode width
214 * @param pcHeight where to store the mode height
215 * @param pcVirtWidth where to store the mode pitch
216 * @param pcBPP where to store the colour depth of the mode
217 * @param pfFlags where to store the flags for the mode
218 */
219DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, uint16_t *pcHeight,
220 uint16_t *pcVirtWidth, uint16_t *pcBPP,
221 uint16_t *pfFlags)
222{
223 uint16_t fFlags;
224
225 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
226 fFlags = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
227 if (pcWidth)
228 {
229 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_XRES);
230 *pcWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
231 }
232 if (pcHeight)
233 {
234 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_YRES);
235 *pcHeight = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
236 }
237 if (pcVirtWidth)
238 {
239 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_VIRT_WIDTH);
240 *pcVirtWidth = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
241 }
242 if (pcBPP)
243 {
244 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_BPP);
245 *pcBPP = VBVO_PORT_READ_U16(VBE_DISPI_IOPORT_DATA);
246 }
247 if (pfFlags)
248 *pfFlags = fFlags;
249 return RT_BOOL(fFlags & VBE_DISPI_ENABLED);
250}
251
252
253/**
254 * Disable our extended graphics mode and go back to VGA mode.
255 */
256DECLHIDDEN(void) VBoxVideoDisableVBE(void)
257{
258 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_INDEX, VBE_DISPI_INDEX_ENABLE);
259 VBVO_PORT_WRITE_U16(VBE_DISPI_IOPORT_DATA, 0);
260}
261
262
263/**
264 * Set a video mode via an HGSMI request. The views must have been
265 * initialised first using @a VBoxHGSMISendViewInfo and if the mode is being
266 * set on the first display then it must be set first using registers.
267 * @param pCtx The context containing the heap to use.
268 * @param cDisplay the screen number
269 * @param cOriginX the horizontal displacement relative to the first screen
270 * @param cOriginY the vertical displacement relative to the first screen
271 * @param offStart the offset of the visible area of the framebuffer
272 * relative to the framebuffer start
273 * @param cbPitch the offset in bytes between the starts of two adjecent
274 * scan lines in video RAM
275 * @param cWidth the mode width
276 * @param cHeight the mode height
277 * @param cBPP the colour depth of the mode
278 * @param fFlags flags
279 */
280DECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx,
281 uint32_t cDisplay,
282 int32_t cOriginX,
283 int32_t cOriginY,
284 uint32_t offStart,
285 uint32_t cbPitch,
286 uint32_t cWidth,
287 uint32_t cHeight,
288 uint16_t cBPP,
289 uint16_t fFlags)
290{
291 /* Issue the screen info command. */
292 void *p = VBoxHGSMIBufferAlloc(pCtx,
293 sizeof (VBVAINFOSCREEN),
294 HGSMI_CH_VBVA,
295 VBVA_INFO_SCREEN);
296 if (!p)
297 {
298 // LogFunc(("HGSMIHeapAlloc failed\n"));
299 }
300 else
301 {
302 VBVAINFOSCREEN *pScreen = (VBVAINFOSCREEN *)p;
303
304 pScreen->u32ViewIndex = cDisplay;
305 pScreen->i32OriginX = cOriginX;
306 pScreen->i32OriginY = cOriginY;
307 pScreen->u32StartOffset = offStart;
308 pScreen->u32LineSize = cbPitch;
309 pScreen->u32Width = cWidth;
310 pScreen->u32Height = cHeight;
311 pScreen->u16BitsPerPixel = cBPP;
312 pScreen->u16Flags = fFlags;
313
314 VBoxHGSMIBufferSubmit(pCtx, p);
315
316 VBoxHGSMIBufferFree(pCtx, p);
317 }
318}
319
320
321/** Report the rectangle relative to which absolute pointer events should be
322 * expressed. This information remains valid until the next VBVA resize event
323 * for any screen, at which time it is reset to the bounding rectangle of all
324 * virtual screens.
325 * @param pCtx The context containing the heap to use.
326 * @param cOriginX Upper left X co-ordinate relative to the first screen.
327 * @param cOriginY Upper left Y co-ordinate relative to the first screen.
328 * @param cWidth Rectangle width.
329 * @param cHeight Rectangle height.
330 * @returns iprt status code.
331 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
332 */
333DECLHIDDEN(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY,
334 uint32_t cWidth, uint32_t cHeight)
335{
336 int rc = VINF_SUCCESS;
337 VBVAREPORTINPUTMAPPING *p;
338 // Log(("%s: cOriginX=%d, cOriginY=%d, cWidth=%u, cHeight=%u\n", __PRETTY_FUNCTION__, (int)cOriginX, (int)cOriginX,
339 // (unsigned)cWidth, (unsigned)cHeight));
340
341 /* Allocate the IO buffer. */
342 p = (VBVAREPORTINPUTMAPPING *)VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAREPORTINPUTMAPPING), HGSMI_CH_VBVA,
343 VBVA_REPORT_INPUT_MAPPING);
344 if (p)
345 {
346 /* Prepare data to be sent to the host. */
347 p->x = cOriginX;
348 p->y = cOriginY;
349 p->cx = cWidth;
350 p->cy = cHeight;
351 rc = VBoxHGSMIBufferSubmit(pCtx, p);
352 /* Free the IO buffer. */
353 VBoxHGSMIBufferFree(pCtx, p);
354 }
355 else
356 rc = VERR_NO_MEMORY;
357 // LogFunc(("rc = %d\n", rc));
358 return rc;
359}
360
361
362/**
363 * Get most recent video mode hints.
364 * @param pCtx the context containing the heap to use
365 * @param cScreens the number of screens to query hints for, starting at 0.
366 * @param paHints array of VBVAMODEHINT structures for receiving the hints.
367 * @returns iprt status code
368 * @returns VERR_NO_MEMORY HGSMI heap allocation failed.
369 * @returns VERR_NOT_SUPPORTED Host does not support this command.
370 */
371DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx,
372 unsigned cScreens, VBVAMODEHINT *paHints)
373{
374 int rc;
375 void *p;
376
377 AssertPtr(paHints);
378 if (!VALID_PTR(paHints))
379 return VERR_INVALID_POINTER;
380
381 p = VBoxHGSMIBufferAlloc(pCtx, sizeof(VBVAQUERYMODEHINTS)
382 + cScreens * sizeof(VBVAMODEHINT),
383 HGSMI_CH_VBVA, VBVA_QUERY_MODE_HINTS);
384 if (!p)
385 {
386 // LogFunc(("HGSMIHeapAlloc failed\n"));
387 return VERR_NO_MEMORY;
388 }
389 else
390 {
391 VBVAQUERYMODEHINTS *pQuery = (VBVAQUERYMODEHINTS *)p;
392
393 pQuery->cHintsQueried = cScreens;
394 pQuery->cbHintStructureGuest = sizeof(VBVAMODEHINT);
395 pQuery->rc = VERR_NOT_SUPPORTED;
396
397 VBoxHGSMIBufferSubmit(pCtx, p);
398 rc = pQuery->rc;
399 if (RT_SUCCESS(rc))
400 memcpy(paHints, ((uint8_t *)p) + sizeof(VBVAQUERYMODEHINTS),
401 cScreens * sizeof(VBVAMODEHINT));
402
403 VBoxHGSMIBufferFree(pCtx, p);
404 }
405 return rc;
406}
407
408
409/**
410 * Query the supported flags in VBVAINFOSCREEN::u16Flags.
411 *
412 * @returns The mask of VBVA_SCREEN_F_* flags or 0 if host does not support the request.
413 * @param pCtx the context containing the heap to use
414 */
415DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx)
416{
417 uint32_t u32Flags = 0;
418 int rc = VBoxQueryConfHGSMI(pCtx, VBOX_VBVA_CONF32_SCREEN_FLAGS, &u32Flags);
419 // LogFunc(("u32Flags = 0x%x rc %Rrc\n", u32Flags, rc));
420 if (RT_FAILURE(rc) || u32Flags > UINT16_MAX)
421 u32Flags = 0;
422 return (uint16_t)u32Flags;
423}
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