Implement hardware scrolling in vesafb by utilising the whole frame buffer
memory and scrolling trough it. If the hardware is not capable it will disable hardware scrolling. For 640x480 at 8 bpp the speedup is around 4 times, at 1280x1280 at 32 bpp the speedup is around 9.4 times. Checked and OK'd by Jared McNeill. Thanks go to Jared and Michael Lorenz for their tips and vcons knowledge!
This commit is contained in:
parent
e6e6c988b3
commit
ef34b019ed
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vesabios.c,v 1.23 2007/02/20 00:09:57 xtraeme Exp $ */
|
||||
/* $NetBSD: vesabios.c,v 1.24 2007/03/24 00:07:17 reinoud Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, 2004
|
||||
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vesabios.c,v 1.23 2007/02/20 00:09:57 xtraeme Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vesabios.c,v 1.24 2007/03/24 00:07:17 reinoud Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -186,6 +186,8 @@ vesabios_attach(struct device *parent, struct device *dev,
|
||||
aprint_normal(": version %d.%d",
|
||||
vi->VbeVersion >> 8, vi->VbeVersion & 0xff);
|
||||
|
||||
vbaa.vbaa_vbeversion = vi->VbeVersion;
|
||||
|
||||
res = kvm86_bios_read(FAR2FLATPTR(vi->OemVendorNamePtr),
|
||||
name, sizeof(name));
|
||||
if (res > 0) {
|
||||
@ -259,6 +261,12 @@ vesabios_attach(struct device *parent, struct device *dev,
|
||||
if (mi->ModeAttributes & 0x80) {
|
||||
/* flat buffer */
|
||||
rastermodes[nrastermodes++] = modes[i];
|
||||
#ifdef VESABIOSVERBOSE
|
||||
aprint_verbose("%s: memory window "
|
||||
"granularity %d Kb, window size %d Kb\n",
|
||||
dev->dv_xname,
|
||||
mi->WinGranularity/1024, mi->WinSize/1024);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/* text */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vesabios.h,v 1.6 2006/06/20 20:30:22 drochner Exp $ */
|
||||
/* $NetBSD: vesabios.h,v 1.7 2007/03/24 00:07:17 reinoud Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, 2005
|
||||
@ -32,4 +32,5 @@ struct vesabiosdev_attach_args {
|
||||
const char *vbaa_type;
|
||||
int *vbaa_modes;
|
||||
int vbaa_nmodes;
|
||||
int vbaa_vbeversion;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vesabiosreg.h,v 1.5 2006/06/20 20:30:22 drochner Exp $ */
|
||||
/* $NetBSD: vesabiosreg.h,v 1.6 2007/03/24 00:07:17 reinoud Exp $ */
|
||||
|
||||
/*
|
||||
* Written by M. Drochner
|
||||
@ -29,13 +29,8 @@ struct modeinfoblock {
|
||||
uint8_t DirectColorModeInfo;
|
||||
/* Mandatory information for VBE 2.0 and above */
|
||||
uint32_t PhysBasePtr;
|
||||
#ifdef VBE_2_0
|
||||
uint32_t OffScreenMemOffset;
|
||||
uint16_t OffScreenMemSize;
|
||||
uint8_t Reserved2[206];
|
||||
#else
|
||||
uint32_t Reserved2;
|
||||
uint16_t Reserved3;
|
||||
uint32_t OffScreenMemOffset; /* reserved in VBE 3.0 and above */
|
||||
uint16_t OffScreenMemSize; /* reserved in VBE 3.0 and above */
|
||||
|
||||
/* Mandatory information for VBE 3.0 and above */
|
||||
uint16_t LinBytesPerScanLine;
|
||||
@ -47,7 +42,6 @@ struct modeinfoblock {
|
||||
uint8_t LinRsvdMaskSize, LinRsvdFieldPosition;
|
||||
uint32_t MaxPixelClock;
|
||||
uint8_t Reserved4[189];
|
||||
#endif
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct paletteentry {
|
||||
|
@ -1,9 +1,11 @@
|
||||
/* $NetBSD: vesafb.c,v 1.20 2007/03/04 05:59:56 christos Exp $ */
|
||||
/* $NetBSD: vesafb.c,v 1.21 2007/03/24 00:07:17 reinoud Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Hardware scrolling added in 2007 by Reinoud Zandijk <reinoud@NetBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -35,7 +37,7 @@
|
||||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: vesafb.c,v 1.20 2007/03/04 05:59:56 christos Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: vesafb.c,v 1.21 2007/03/24 00:07:17 reinoud Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
@ -75,7 +77,7 @@ struct wsscreen_descr vesafb_stdscreen = {
|
||||
static int vesafb_ioctl(void *, void *, u_long, void *, int,
|
||||
struct lwp *);
|
||||
static paddr_t vesafb_mmap(void *, void *, off_t, int);
|
||||
|
||||
static void vesafb_show_screen_cb(struct vcons_screen *);
|
||||
static void vesafb_init_screen(void *, struct vcons_screen *,
|
||||
int, long *);
|
||||
|
||||
@ -218,10 +220,32 @@ vesafb_attach(struct device *parent, struct device *dev, void *aux)
|
||||
vcons_init(&sc->sc_vd, sc, &vesafb_stdscreen,
|
||||
&vesafb_accessops);
|
||||
sc->sc_vd.init_screen = vesafb_init_screen;
|
||||
sc->sc_vd.show_screen_cb = vesafb_show_screen_cb;
|
||||
|
||||
aprint_normal("%s: fb %dx%dx%d @0x%x\n", sc->sc_dev.dv_xname,
|
||||
mi->XResolution, mi->YResolution,
|
||||
mi->BitsPerPixel, mi->PhysBasePtr);
|
||||
|
||||
if (vaa->vbaa_vbeversion >= 0x300) {
|
||||
sc->sc_scrollscreens = mi->LinNumberOfImagePages;
|
||||
} else {
|
||||
sc->sc_scrollscreens = mi->NumberOfImagePages;
|
||||
}
|
||||
if (sc->sc_scrollscreens == 0)
|
||||
sc->sc_scrollscreens = 1;
|
||||
|
||||
sc->sc_screensize = mi->YResolution * mi->BytesPerScanLine;
|
||||
sc->sc_fbsize = sc->sc_scrollscreens * sc->sc_screensize;
|
||||
|
||||
aprint_normal("%s: %d Kb memory reported, %d screens possible\n",
|
||||
sc->sc_dev.dv_xname,
|
||||
sc->sc_fbsize / 1024,
|
||||
sc->sc_scrollscreens);
|
||||
|
||||
if (sc->sc_scrollscreens == 1)
|
||||
aprint_normal("%s: one screen, so hardware scrolling not "
|
||||
"possible\n", sc->sc_dev.dv_xname);
|
||||
|
||||
if (sc->sc_pm) {
|
||||
aprint_normal("%s: VBE/PM %d.%d", sc->sc_dev.dv_xname,
|
||||
(sc->sc_pmver >> 4), sc->sc_pmver & 0xf);
|
||||
@ -237,25 +261,35 @@ vesafb_attach(struct device *parent, struct device *dev, void *aux)
|
||||
}
|
||||
|
||||
res = _x86_memio_map(X86_BUS_SPACE_MEM, mi->PhysBasePtr,
|
||||
mi->YResolution * mi->BytesPerScanLine,
|
||||
sc->sc_fbsize, /* was sc_screensize */
|
||||
BUS_SPACE_MAP_LINEAR, &h);
|
||||
if (res) {
|
||||
aprint_error("%s: framebuffer mapping failed\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
goto out;
|
||||
}
|
||||
sc->sc_bits = bus_space_vaddr(X86_BUS_SPACE_MEM, h);
|
||||
sc->sc_fbstart = bus_space_vaddr(X86_BUS_SPACE_MEM, h);
|
||||
sc->sc_bits = sc->sc_fbstart;
|
||||
|
||||
#ifdef VESAFB_SHADOW_FB
|
||||
sc->sc_shadowbits = malloc(mi->YResolution * mi->BytesPerScanLine,
|
||||
sc->sc_shadowbits = malloc(sc->sc_screensize,
|
||||
M_VESAFB, M_NOWAIT);
|
||||
if (sc->sc_shadowbits == NULL) {
|
||||
aprint_error("%s: unable to allocate %d bytes for shadowfb\n",
|
||||
sc->sc_dev.dv_xname, mi->YResolution*mi->BytesPerScanLine);
|
||||
sc->sc_dev.dv_xname, sc->sc_screensize);
|
||||
/* Not fatal; we'll just have to continue without shadowfb */
|
||||
}
|
||||
#endif
|
||||
|
||||
/* initialise our display wide settings */
|
||||
#ifdef VESAFB_SHADOW_FB
|
||||
sc->sc_displ_bits = sc->sc_shadowbits;
|
||||
sc->sc_displ_hwbits = sc->sc_bits;
|
||||
#else
|
||||
sc->sc_displ_bits = sc->sc_bits;
|
||||
sc->sc_displ_hwbits = NULL;
|
||||
#endif /* !VESAFB_SHADOW_FB */
|
||||
|
||||
vesafb_init(sc);
|
||||
|
||||
vesafb_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
|
||||
@ -422,6 +456,119 @@ vesafb_mmap(void *v, void *vs, off_t offset, int prot)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* called back by vcons on screen change; needed for VT display sharing */
|
||||
static void
|
||||
vesafb_show_screen_cb(struct vcons_screen *scr)
|
||||
{
|
||||
struct vesafb_softc *sc;
|
||||
struct rasops_info *ri;
|
||||
|
||||
sc = (struct vesafb_softc *) scr->scr_cookie;
|
||||
ri = &scr->scr_ri;
|
||||
|
||||
/* protect against roque values) */
|
||||
if ((sc == NULL) || (ri == NULL))
|
||||
return;
|
||||
|
||||
/* set our rasops info to match the display's global state (VTs!) */
|
||||
ri->ri_bits = sc->sc_displ_bits;
|
||||
ri->ri_hwbits = sc->sc_displ_hwbits;
|
||||
}
|
||||
|
||||
static void
|
||||
vv_copyrows(void *id, int srcrow, int dstrow, int nrows)
|
||||
{
|
||||
static int working = 1;
|
||||
struct trapframe tf;
|
||||
struct rasops_info *ri = id;
|
||||
struct vcons_screen *scr = (struct vcons_screen *) ri->ri_hw;
|
||||
struct vesafb_softc *sc = (struct vesafb_softc *) scr->scr_cookie;
|
||||
uint32_t displ_offset;
|
||||
uint8_t *src, *dst, *hwbits, *cur_hwbits, *hiwater, *lowater;
|
||||
int fontheight, offset, linesz, size, height;
|
||||
int scrollup, scrolldown, res;
|
||||
|
||||
/* set our rasops info to match the display's global state (VTs!) */
|
||||
ri->ri_bits = sc->sc_displ_bits;
|
||||
ri->ri_hwbits = sc->sc_displ_hwbits;
|
||||
|
||||
/* fontheight = ri->ri_font->fontheight; */
|
||||
fontheight = 16;
|
||||
|
||||
/* All movements are done in multiples of character heights */
|
||||
height = fontheight * nrows;
|
||||
size = height * ri->ri_stride;
|
||||
linesz = fontheight * ri->ri_stride;
|
||||
offset = (srcrow - dstrow) * linesz;
|
||||
|
||||
/* check if we are full screen scrolling */
|
||||
scrollup = (srcrow + nrows >= ri->ri_rows);
|
||||
scrolldown = (dstrow + nrows >= ri->ri_rows);
|
||||
|
||||
if (working && (scrollup || scrolldown)) {
|
||||
lowater = sc->sc_fbstart;
|
||||
hiwater = lowater + sc->sc_fbsize - sc->sc_screensize;
|
||||
#ifdef VESAFB_SHADOW_FB
|
||||
hwbits = ri->ri_hwbits;
|
||||
#else
|
||||
hwbits = ri->ri_bits;
|
||||
#endif
|
||||
cur_hwbits = hwbits;
|
||||
hwbits += offset;
|
||||
if (hwbits > hiwater) {
|
||||
/* offset is positive */
|
||||
memmove(lowater, ri->ri_bits + offset,
|
||||
sc->sc_screensize - offset);
|
||||
hwbits = lowater;
|
||||
}
|
||||
if (hwbits < lowater) {
|
||||
/* offset is negative */
|
||||
memmove(hiwater - offset,
|
||||
ri->ri_bits,
|
||||
sc->sc_screensize + offset);
|
||||
hwbits = hiwater;
|
||||
}
|
||||
/* program VESA frame buffer start */
|
||||
displ_offset = (hwbits - sc->sc_fbstart);
|
||||
memset(&tf, 0, sizeof(struct trapframe));
|
||||
tf.tf_eax = 0x4f07; /* function code */
|
||||
tf.tf_ebx = 0x00; /* set display immediately */
|
||||
tf.tf_ecx = 0; /* hpixels */
|
||||
tf.tf_edx = displ_offset / ri->ri_stride; /* lineno */
|
||||
tf.tf_vm86_es = 0;
|
||||
|
||||
res = kvm86_bioscall(0x10, &tf);
|
||||
if (res || (tf.tf_eax & 0xff) != 0x4f) {
|
||||
working = 0;
|
||||
aprint_error("%s: vbecall: res=%d, ax=%x\n",
|
||||
sc->sc_dev.dv_xname, res, tf.tf_eax);
|
||||
hwbits = cur_hwbits;
|
||||
goto out;
|
||||
}
|
||||
#ifdef VESAFB_SHADOW_FB
|
||||
ri->ri_hwbits = hwbits;
|
||||
src = ri->ri_bits + srcrow * fontheight * ri->ri_stride;
|
||||
dst = ri->ri_bits + dstrow * fontheight * ri->ri_stride;
|
||||
memmove(dst, src, size);
|
||||
#else
|
||||
ri->ri_bits = hwbits;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/* wipe out remains of the screen if nessisary */
|
||||
if (ri->ri_emuheight != ri->ri_height)
|
||||
vv_eraserows(id, ri->ri_rows, 1, 0);
|
||||
#endif
|
||||
/* remember display's global state (VTs!) */
|
||||
sc->sc_displ_bits = ri->ri_bits;
|
||||
sc->sc_displ_hwbits = ri->ri_hwbits;
|
||||
return;
|
||||
}
|
||||
out:
|
||||
/* just deligate to the origional routine */
|
||||
sc->sc_orig_copyrows(id, srcrow, dstrow, nrows);
|
||||
}
|
||||
|
||||
static void
|
||||
vesafb_init_screen(void *c, struct vcons_screen *scr, int existing,
|
||||
long *defattr)
|
||||
@ -437,13 +584,13 @@ vesafb_init_screen(void *c, struct vcons_screen *scr, int existing,
|
||||
ri->ri_depth = mi->BitsPerPixel;
|
||||
ri->ri_width = mi->XResolution;
|
||||
ri->ri_height = mi->YResolution;
|
||||
ri->ri_emuheight = ri->ri_height; /* XXX always ? */
|
||||
ri->ri_stride = mi->BytesPerScanLine;
|
||||
#ifdef VESAFB_SHADOW_FB
|
||||
ri->ri_bits = sc->sc_shadowbits;
|
||||
ri->ri_hwbits = sc->sc_bits;
|
||||
#else
|
||||
ri->ri_bits = sc->sc_bits;
|
||||
#endif /* !VESAFB_SHADOW_FB */
|
||||
|
||||
/* set our rasops info to match the display's global state (VTs!) */
|
||||
ri->ri_bits = sc->sc_displ_bits;
|
||||
ri->ri_hwbits = sc->sc_displ_hwbits;
|
||||
|
||||
ri->ri_caps = WSSCREEN_WSCOLORS;
|
||||
ri->ri_rnum = mi->RedMaskSize;
|
||||
ri->ri_gnum = mi->GreenMaskSize;
|
||||
@ -454,6 +601,12 @@ vesafb_init_screen(void *c, struct vcons_screen *scr, int existing,
|
||||
|
||||
rasops_init(ri, mi->YResolution / 16, mi->XResolution / 8);
|
||||
|
||||
if (sc->sc_scrollscreens > 1) {
|
||||
/* override copyrows but remember old one for delegation */
|
||||
sc->sc_orig_copyrows = ri->ri_ops.copyrows;
|
||||
ri->ri_ops.copyrows = vv_copyrows;
|
||||
}
|
||||
|
||||
#ifdef VESA_DISABLE_TEXT
|
||||
if (scr == &vesafb_console_screen)
|
||||
SCREEN_DISABLE_DRAWING(&vesafb_console_screen);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vesafbvar.h,v 1.3 2006/04/24 14:14:38 jmcneill Exp $ */
|
||||
/* $NetBSD: vesafbvar.h,v 1.4 2007/03/24 00:07:18 reinoud Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2006 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -85,11 +85,21 @@ struct vesafb_softc {
|
||||
char *sc_buf;
|
||||
u_char *sc_bits;
|
||||
u_char *sc_shadowbits;
|
||||
u_char *sc_fbstart;
|
||||
u_char sc_cmap_red[256];
|
||||
u_char sc_cmap_green[256];
|
||||
u_char sc_cmap_blue[256];
|
||||
int sc_wsmode;
|
||||
int sc_nscreens;
|
||||
int sc_scrollscreens;
|
||||
uint32_t sc_screensize;
|
||||
uint32_t sc_fbsize;
|
||||
uint32_t sc_fblines;
|
||||
/* display wide buffer settings for VTs */
|
||||
uint8_t *sc_displ_bits;
|
||||
uint8_t *sc_displ_hwbits;
|
||||
/* delegate rasops function if hardware scrolling */
|
||||
void (*sc_orig_copyrows)(void *, int, int, int);
|
||||
|
||||
int sc_pm;
|
||||
uint8_t sc_pmver;
|
||||
|
Loading…
Reference in New Issue
Block a user