Rewrite the low-level scroll code so that it is implemented using two basic operations: move text and clear text. This simplifies the low-level code as it no longer needs to handle up scrolling vs down scrolling. Determining the direction of the scroll is now done in the higher level (vgabios.c) code.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- vgasrc/vgabios.c | 63 ++++++++++++--- vgasrc/vgabios.h | 6 +- vgasrc/vgafb.c | 231 +++++++++++++++++++++++++++++-------------------------- 3 files changed, 178 insertions(+), 122 deletions(-)
diff --git a/vgasrc/vgabios.c b/vgasrc/vgabios.c index 040a7ae..d0efc11 100644 --- a/vgasrc/vgabios.c +++ b/vgasrc/vgabios.c @@ -215,9 +215,20 @@ write_teletype(struct cursorpos *pcp, struct carattr ca) u16 nbrows = GET_BDA(video_rows); if (pcp->y > nbrows) { pcp->y--; - struct cursorpos ul = {0, 0, pcp->page}; - struct cursorpos lr = {GET_BDA(video_cols)-1, nbrows, pcp->page}; - vgafb_scroll(1, -1, ul, lr); + + struct vgamode_s *vmode_g = get_current_mode(); + if (!vmode_g) + return; + + struct cursorpos dest = {0, 0, pcp->page}; + struct cursorpos src = {0, 1, pcp->page}; + struct cursorpos size = {GET_BDA(video_cols), nbrows}; + vgafb_move_chars(vmode_g, dest, src, size); + + struct cursorpos clr = {0, nbrows, pcp->page}; + struct carattr attr = {' ', 0, 0}; + struct cursorpos clrsize = {GET_BDA(video_cols), 1}; + vgafb_clear_chars(vmode_g, clr, attr, clrsize); } }
@@ -415,18 +426,48 @@ verify_scroll(struct bregs *regs, int dir) u16 nbcols = GET_BDA(video_cols); if (lrx >= nbcols) lrx = nbcols - 1; - - if (ulx > lrx || uly > lry) + int wincols = lrx - ulx + 1, winrows = lry - uly + 1; + if (wincols <= 0 || winrows <= 0) return;
- int nblines = regs->al; - if (!nblines || nblines > lry - uly + 1) - nblines = lry - uly + 1; + struct vgamode_s *vmode_g = get_current_mode(); + if (!vmode_g) + return;
u8 page = GET_BDA(video_page); - struct cursorpos ul = {ulx, uly, page}; - struct cursorpos lr = {lrx, lry, page}; - vgafb_scroll(dir * nblines, regs->bh, ul, lr); + int clearlines = regs->al, movelines = winrows - clearlines; + if (!clearlines || movelines <= 0) { + // Clear whole area. + struct cursorpos clr = {ulx, uly, page}; + struct carattr attr = {' ', regs->bh, 1}; + struct cursorpos clrsize = {wincols, winrows}; + vgafb_clear_chars(vmode_g, clr, attr, clrsize); + return; + } + + if (dir > 0) { + // Normal scroll + struct cursorpos dest = {ulx, uly, page}; + struct cursorpos src = {ulx, uly + clearlines, page}; + struct cursorpos size = {wincols, movelines}; + vgafb_move_chars(vmode_g, dest, src, size); + + struct cursorpos clr = {ulx, uly + movelines, page}; + struct carattr attr = {' ', regs->bh, 1}; + struct cursorpos clrsize = {wincols, clearlines}; + vgafb_clear_chars(vmode_g, clr, attr, clrsize); + } else { + // Scroll down + struct cursorpos dest = {ulx, uly + clearlines, page}; + struct cursorpos src = {ulx, uly, page}; + struct cursorpos size = {wincols, movelines}; + vgafb_move_chars(vmode_g, dest, src, size); + + struct cursorpos clr = {ulx, uly, page}; + struct carattr attr = {' ', regs->bh, 1}; + struct cursorpos clrsize = {wincols, clearlines}; + vgafb_clear_chars(vmode_g, clr, attr, clrsize); + } }
static void diff --git a/vgasrc/vgabios.h b/vgasrc/vgabios.h index 6949560..de6ae59 100644 --- a/vgasrc/vgabios.h +++ b/vgasrc/vgabios.h @@ -87,8 +87,10 @@ struct vgamode_s *get_current_mode(void); int vga_set_mode(int mode, int flags);
// vgafb.c -void vgafb_scroll(int nblines, int attr - , struct cursorpos ul, struct cursorpos lr); +void vgafb_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize); +void vgafb_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos movesize); void vgafb_write_char(struct cursorpos cp, struct carattr ca); struct carattr vgafb_read_char(struct cursorpos cp); void vgafb_write_pixel(u8 color, u16 x, u16 y); diff --git a/vgasrc/vgafb.c b/vgasrc/vgafb.c index 7c2570f..5a2c4c8 100644 --- a/vgasrc/vgafb.c +++ b/vgasrc/vgafb.c @@ -17,12 +17,16 @@ * Screen scrolling ****************************************************************/
-static inline void * -memcpy_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines) +static inline void +memmove_stride(u16 seg, void *dst, void *src, int copylen, int stride, int lines) { + if (src < dst) { + dst += stride * (lines - 1); + src += stride * (lines - 1); + stride = -stride; + } for (; lines; lines--, dst+=stride, src+=stride) memcpy_far(seg, dst, seg, src, copylen); - return dst; }
static inline void @@ -40,163 +44,172 @@ memset16_stride(u16 seg, void *dst, u16 val, int setlen, int stride, int lines) }
static void -scroll_pl4(struct vgamode_s *vmode_g, int nblines, int attr - , struct cursorpos ul, struct cursorpos lr) +planar_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize) { if (!CONFIG_VGA_STDVGA_PORTS) return; int cheight = GET_BDA(char_height); int cwidth = 1; int stride = GET_BDA(video_cols) * cwidth; - void *src_far, *dest_far; - if (nblines >= 0) { - dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); - src_far = dest_far + nblines * cheight * stride; - } else { - // Scroll down - nblines = -nblines; - dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); - src_far = dest_far - nblines * cheight * stride; - stride = -stride; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth); + int i; + for (i=0; i<4; i++) { + stdvga_planar4_plane(i); + memmove_stride(SEG_GRAPH, dest_far, src_far + , movesize.x * cwidth, stride, movesize.y * cheight); } - if (attr < 0) - attr = 0; - int cols = lr.x - ul.x + 1; - int rows = lr.y - ul.y + 1; + stdvga_planar4_plane(-1); +} + +static void +planar_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos clearsize) +{ + if (!CONFIG_VGA_STDVGA_PORTS) + return; + int cheight = GET_BDA(char_height); + int cwidth = 1; + int stride = GET_BDA(video_cols) * cwidth; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); int i; for (i=0; i<4; i++) { stdvga_planar4_plane(i); - void *dest = dest_far; - if (nblines < rows) - dest = memcpy_stride(SEG_GRAPH, dest, src_far, cols * cwidth - , stride, (rows - nblines) * cheight); - u8 pixels = (attr & (1<<i)) ? 0xff : 0x00; - memset_stride(SEG_GRAPH, dest, pixels, cols * cwidth - , stride, nblines * cheight); + u8 attr = (ca.attr & (1<<i)) ? 0xff : 0x00; + memset_stride(SEG_GRAPH, dest_far, attr + , clearsize.x * cwidth, stride, clearsize.y * cheight); } stdvga_planar4_plane(-1); }
static void -scroll_cga(struct vgamode_s *vmode_g, int nblines, int attr - , struct cursorpos ul, struct cursorpos lr) +cga_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize) { int cheight = GET_BDA(char_height) / 2; int cwidth = GET_GLOBAL(vmode_g->depth); int stride = GET_BDA(video_cols) * cwidth; - void *src_far, *dest_far; - if (nblines >= 0) { - dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); - src_far = dest_far + nblines * cheight * stride; - } else { - // Scroll down - nblines = -nblines; - dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); - src_far = dest_far - nblines * cheight * stride; - stride = -stride; - } - if (attr < 0) - attr = 0; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth); + memmove_stride(SEG_CTEXT, dest_far, src_far + , movesize.x * cwidth, stride, movesize.y * cheight); + memmove_stride(SEG_CTEXT, dest_far + 0x2000, src_far + 0x2000 + , movesize.x * cwidth, stride, movesize.y * cheight); +} + +static void +cga_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos clearsize) +{ + int cheight = GET_BDA(char_height) / 2; + int cwidth = GET_GLOBAL(vmode_g->depth); + int stride = GET_BDA(video_cols) * cwidth; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + u8 attr = ca.attr; if (cwidth == 1) attr = (attr&1) | ((attr&1)<<1); attr &= 3; attr |= (attr<<2) | (attr<<4) | (attr<<6); - int cols = lr.x - ul.x + 1; - int rows = lr.y - ul.y + 1; - if (nblines < rows) { - memcpy_stride(SEG_CTEXT, dest_far+0x2000, src_far+0x2000, cols * cwidth - , stride, (rows - nblines) * cheight); - dest_far = memcpy_stride(SEG_CTEXT, dest_far, src_far, cols * cwidth - , stride, (rows - nblines) * cheight); - } - memset_stride(SEG_CTEXT, dest_far + 0x2000, attr, cols * cwidth - , stride, nblines * cheight); - memset_stride(SEG_CTEXT, dest_far, attr, cols * cwidth - , stride, nblines * cheight); + memset_stride(SEG_CTEXT, dest_far, attr + , clearsize.x * cwidth, stride, clearsize.y * cheight); + memset_stride(SEG_CTEXT, dest_far + 0x2000, attr + , clearsize.x * cwidth, stride, clearsize.y * cheight); }
static void -scroll_lin(struct vgamode_s *vmode_g, int nblines, int attr - , struct cursorpos ul, struct cursorpos lr) +packed_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize) { int cheight = GET_BDA(char_height); int cwidth = 8; int stride = GET_BDA(video_cols) * cwidth; - void *src_far, *dest_far; - if (nblines >= 0) { - dest_far = (void*)(ul.y * cheight * stride + ul.x * cwidth); - src_far = dest_far + nblines * cheight * stride; - } else { - // Scroll down - nblines = -nblines; - dest_far = (void*)(lr.y * cheight * stride + ul.x * cwidth); - src_far = dest_far - nblines * cheight * stride; - stride = -stride; - } - if (attr < 0) - attr = 0; - int cols = lr.x - ul.x + 1; - int rows = lr.y - ul.y + 1; - if (nblines < rows) - dest_far = memcpy_stride(SEG_GRAPH, dest_far, src_far, cols * cwidth - , stride, (rows - nblines) * cheight); - memset_stride(SEG_GRAPH, dest_far, attr, cols * cwidth - , stride, nblines * cheight); + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth); + memmove_stride(SEG_GRAPH, dest_far, src_far + , movesize.x * cwidth, stride, movesize.y * cheight); }
static void -scroll_text(struct vgamode_s *vmode_g, int nblines, int attr - , struct cursorpos ul, struct cursorpos lr) +packed_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos clearsize) +{ + int cheight = GET_BDA(char_height); + int cwidth = 8; + int stride = GET_BDA(video_cols) * cwidth; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + memset_stride(SEG_GRAPH, dest_far, ca.attr + , clearsize.x * cwidth, stride, clearsize.y * cheight); +} + +static void +text_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize) { int cheight = 1; int cwidth = 2; int stride = GET_BDA(video_cols) * cwidth; - void *src_far, *dest_far = (void*)(GET_BDA(video_pagesize) * ul.page); - if (nblines >= 0) { - dest_far += ul.y * cheight * stride + ul.x * cwidth; - src_far = dest_far + nblines * cheight * stride; - } else { - // Scroll down - nblines = -nblines; - dest_far += lr.y * cheight * stride + ul.x * cwidth; - src_far = dest_far - nblines * cheight * stride; - stride = -stride; - } - if (attr < 0) - attr = 0x07; - attr = (attr << 8) | ' '; - int cols = lr.x - ul.x + 1; - int rows = lr.y - ul.y + 1; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + void *src_far = (void*)(src.y * cheight * stride + src.x * cwidth); + u32 pageoffset = GET_BDA(video_pagesize) * dest.page; + u16 seg = GET_GLOBAL(vmode_g->sstart); + memmove_stride(seg, dest_far + pageoffset, src_far + pageoffset + , movesize.x * cwidth, stride, movesize.y * cheight); +} + +static void +text_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos clearsize) +{ + int cheight = 1; + int cwidth = 2; + int stride = GET_BDA(video_cols) * cwidth; + void *dest_far = (void*)(dest.y * cheight * stride + dest.x * cwidth); + u16 attr = ((ca.use_attr ? ca.attr : 0x07) << 8) | ca.car; + u32 pageoffset = GET_BDA(video_pagesize) * dest.page; u16 seg = GET_GLOBAL(vmode_g->sstart); - if (nblines < rows) - dest_far = memcpy_stride(seg, dest_far, src_far, cols * cwidth - , stride, (rows - nblines) * cheight); - memset16_stride(seg, dest_far, attr, cols * cwidth - , stride, nblines * cheight); + memset16_stride(seg, dest_far + pageoffset, attr + , clearsize.x * cwidth, stride, clearsize.y * cheight); }
void -vgafb_scroll(int nblines, int attr, struct cursorpos ul, struct cursorpos lr) +vgafb_move_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct cursorpos src, struct cursorpos movesize) { - // Get the mode - struct vgamode_s *vmode_g = get_current_mode(); - if (!vmode_g) - return; + switch (GET_GLOBAL(vmode_g->memmodel)) { + case MM_TEXT: + text_move_chars(vmode_g, dest, src, movesize); + break; + case MM_PLANAR: + planar_move_chars(vmode_g, dest, src, movesize); + break; + case MM_CGA: + cga_move_chars(vmode_g, dest, src, movesize); + break; + case MM_PACKED: + packed_move_chars(vmode_g, dest, src, movesize); + break; + default: + break; + } +}
- // FIXME gfx mode not complete +void +vgafb_clear_chars(struct vgamode_s *vmode_g, struct cursorpos dest + , struct carattr ca, struct cursorpos movesize) +{ switch (GET_GLOBAL(vmode_g->memmodel)) { case MM_TEXT: - scroll_text(vmode_g, nblines, attr, ul, lr); + text_clear_chars(vmode_g, dest, ca, movesize); break; case MM_PLANAR: - scroll_pl4(vmode_g, nblines, attr, ul, lr); + planar_clear_chars(vmode_g, dest, ca, movesize); break; case MM_CGA: - scroll_cga(vmode_g, nblines, attr, ul, lr); + cga_clear_chars(vmode_g, dest, ca, movesize); break; - case MM_DIRECT: case MM_PACKED: - scroll_lin(vmode_g, nblines, attr, ul, lr); + packed_clear_chars(vmode_g, dest, ca, movesize); break; default: break;