aboutsummaryrefslogtreecommitdiff
path: root/hw/display/bcm2835_fb.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-08-24 13:17:49 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-08-24 13:17:49 +0100
commit01f18af98b04dc3f47c37a150ae342fafd7337df (patch)
tree84db149056834e17893003550985d3f683179dda /hw/display/bcm2835_fb.c
parent9a1f03f4ee207d58674fc76aecff546551c9da76 (diff)
hw/display/bcm2835_fb: Fix handling of virtual framebuffer
The raspi framebuffir in bcm2835_fb supports the definition of a virtual "viewport", which is smaller than the full physical framebuffer size and at an adjustable offset within it. Only the viewport area is sent to the screen. This allows the guest to do things like double buffering, or scrolling by adjusting the viewport origin. Currently QEMU doesn't implement this at all. Add support for this feature: * the property mailbox code needs to distinguish the virtual width/height from the physical width/height * the framebuffer code needs to do something with the virtual width/height/origin information Note that the wiki documentation on the semantics of the virtual and physical height and width has it the wrong way around -- the virtual size is the size of the allocated buffer, and the physical size is the size of the display, so the virtual size is always the same as or larger than the physical. If the viewport size is set smaller than the physical screen size, we ignore the viewport settings completely and just display the physical screen area. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20180814144436.679-7-peter.maydell@linaro.org
Diffstat (limited to 'hw/display/bcm2835_fb.c')
-rw-r--r--hw/display/bcm2835_fb.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index a6c0a0cc94..76a10072b4 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -126,6 +126,18 @@ static void draw_line_src16(void *opaque, uint8_t *dst, const uint8_t *src,
}
}
+static bool fb_use_offsets(BCM2835FBConfig *config)
+{
+ /*
+ * Return true if we should use the viewport offsets.
+ * Experimentally, the hardware seems to do this only if the
+ * viewport size is larger than the physical screen. (It doesn't
+ * prevent the guest setting this silly viewport setting, though...)
+ */
+ return config->xres_virtual > config->xres &&
+ config->yres_virtual > config->yres;
+}
+
static void fb_update_display(void *opaque)
{
BCM2835FBState *s = opaque;
@@ -134,12 +146,18 @@ static void fb_update_display(void *opaque)
int last = 0;
int src_width = 0;
int dest_width = 0;
+ uint32_t xoff = 0, yoff = 0;
if (s->lock || !s->config.xres) {
return;
}
src_width = bcm2835_fb_get_pitch(&s->config);
+ if (fb_use_offsets(&s->config)) {
+ xoff = s->config.xoffset;
+ yoff = s->config.yoffset;
+ }
+
dest_width = s->config.xres;
switch (surface_bits_per_pixel(surface)) {
@@ -165,8 +183,9 @@ static void fb_update_display(void *opaque)
}
if (s->invalidate) {
+ hwaddr base = s->config.base + xoff + yoff * src_width;
framebuffer_update_memory_section(&s->fbsection, s->dma_mr,
- s->config.base,
+ base,
s->config.yres, src_width);
}
@@ -176,7 +195,8 @@ static void fb_update_display(void *opaque)
draw_line_src16, s, &first, &last);
if (first >= 0) {
- dpy_gfx_update(s->con, 0, first, s->config.xres, last - first + 1);
+ dpy_gfx_update(s->con, 0, first, s->config.xres,
+ last - first + 1);
}
s->invalidate = false;
@@ -202,8 +222,6 @@ static void bcm2835_fb_mbox_push(BCM2835FBState *s, uint32_t value)
s->config.base = s->vcram_base | (value & 0xc0000000);
s->config.base += BCM2835_FB_OFFSET;
- /* TODO - Manage properly virtual resolution */
-
pitch = bcm2835_fb_get_pitch(&s->config);
size = bcm2835_fb_get_size(&s->config);
@@ -224,8 +242,6 @@ void bcm2835_fb_reconfigure(BCM2835FBState *s, BCM2835FBConfig *newconfig)
s->config = *newconfig;
- /* TODO - Manage properly virtual resolution */
-
s->invalidate = true;
qemu_console_resize(s->con, s->config.xres, s->config.yres);
s->lock = false;