/* * Creation Date: <2002/10/23 20:26:40 samuel> * Time-stamp: <2004/01/07 19:39:15 samuel> * * * * Shared video routines * * Copyright (C) 2002, 2003, 2004 Samuel Rydh (samuel@ibrium.se) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation * */ #include "config.h" #include "libc/vsprintf.h" #include "libopenbios/bindings.h" #include "libopenbios/fontdata.h" #include "libopenbios/ofmem.h" #include "libopenbios/video.h" #include "packages/video.h" #include "drivers/vga.h" #define NO_QEMU_PROTOS #include "arch/common/fw_cfg.h" struct video_info video; unsigned long video_get_color( int col_ind ) { unsigned long col; if( !VIDEO_DICT_VALUE(video.ih) || col_ind < 0 || col_ind > 255 ) return 0; if( VIDEO_DICT_VALUE(video.depth) == 8 ) return col_ind; col = video.pal[col_ind]; if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 ) return col; if( VIDEO_DICT_VALUE(video.depth) == 15 ) return ((col>>9) & 0x7c00) | ((col>>6) & 0x03e0) | ((col>>3) & 0x1f); return 0; } /* ( fbaddr maskaddr width height fgcolor bgcolor -- ) */ void video_mask_blit(void) { ucell bgcolor = POP(); ucell fgcolor = POP(); ucell height = POP(); ucell width = POP(); unsigned char *mask = (unsigned char *)POP(); unsigned char *fbaddr = (unsigned char *)POP(); ucell color; unsigned char *dst, *rowdst; int x, y, m, b, d, depthbytes; fgcolor = video_get_color(fgcolor); bgcolor = video_get_color(bgcolor); d = VIDEO_DICT_VALUE(video.depth); depthbytes = (d + 1) >> 3; dst = fbaddr; for( y = 0; y < height; y++) { rowdst = dst; for( x = 0; x < (width + 1) >> 3; x++ ) { for (b = 0; b < 8; b++) { m = (1 << (7 - b)); if (*mask & m) { color = fgcolor; } else { color = bgcolor; } if( d >= 24 ) *((uint32_t*)dst) = color; else if( d >= 15 ) *((uint16_t*)dst) = color; else *dst = color; dst += depthbytes; } mask++; } dst = rowdst; dst += VIDEO_DICT_VALUE(video.rb); } } /* ( x y w h fgcolor bgcolor -- ) */ void video_invert_rect( void ) { ucell bgcolor = POP(); ucell fgcolor = POP(); int h = POP(); int w = POP(); int y = POP(); int x = POP(); char *pp; bgcolor = video_get_color(bgcolor); fgcolor = video_get_color(fgcolor); if (!VIDEO_DICT_VALUE(video.ih) || x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > VIDEO_DICT_VALUE(video.w) || y + h > VIDEO_DICT_VALUE(video.h)) return; pp = (char*)VIDEO_DICT_VALUE(video.mvirt) + VIDEO_DICT_VALUE(video.rb) * y; for( ; h--; pp += *(video.rb) ) { int ww = w; if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 ) { uint32_t *p = (uint32_t*)pp + x; while( ww-- ) { if (*p == fgcolor) { *p++ = bgcolor; } else if (*p == bgcolor) { *p++ = fgcolor; } } } else if( VIDEO_DICT_VALUE(video.depth) == 16 || VIDEO_DICT_VALUE(video.depth) == 15 ) { uint16_t *p = (uint16_t*)pp + x; while( ww-- ) { if (*p == (uint16_t)fgcolor) { *p++ = bgcolor; } else if (*p == (uint16_t)bgcolor) { *p++ = fgcolor; } } } else { char *p = (char *)(pp + x); while( ww-- ) { if (*p == (char)fgcolor) { *p++ = bgcolor; } else if (*p == (char)bgcolor) { *p++ = fgcolor; } } } } } /* ( color_ind x y width height -- ) (?) */ void video_fill_rect(void) { int h = POP(); int w = POP(); int y = POP(); int x = POP(); int col_ind = POP(); char *pp; unsigned long col = video_get_color(col_ind); if (!VIDEO_DICT_VALUE(video.ih) || x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > VIDEO_DICT_VALUE(video.w) || y + h > VIDEO_DICT_VALUE(video.h)) return; pp = (char*)VIDEO_DICT_VALUE(video.mvirt) + VIDEO_DICT_VALUE(video.rb) * y; for( ; h--; pp += VIDEO_DICT_VALUE(video.rb) ) { int ww = w; if( VIDEO_DICT_VALUE(video.depth) == 24 || VIDEO_DICT_VALUE(video.depth) == 32 ) { uint32_t *p = (uint32_t*)pp + x; while( ww-- ) *p++ = col; } else if( VIDEO_DICT_VALUE(video.depth) == 16 || VIDEO_DICT_VALUE(video.depth) == 15 ) { uint16_t *p = (uint16_t*)pp + x; while( ww-- ) *p++ = col; } else { char *p = (char *)(pp + x); while( ww-- ) *p++ = col; } } } void setup_video() { /* Make everything inside the video_info structure point to the values in the Forth dictionary. Hence everything is always in sync. */ phandle_t options; char buf[10]; feval("['] display-ih cell+"); video.ih = cell2pointer(POP()); feval("['] frame-buffer-adr cell+"); video.mvirt = cell2pointer(POP()); feval("['] openbios-video-width cell+"); video.w = cell2pointer(POP()); feval("['] openbios-video-height cell+"); video.h = cell2pointer(POP()); feval("['] depth-bits cell+"); video.depth = cell2pointer(POP()); feval("['] line-bytes cell+"); video.rb = cell2pointer(POP()); feval("['] color-palette cell+"); video.pal = cell2pointer(POP()); /* Set global variables ready for fb8-install */ PUSH( pointer2cell(video_mask_blit) ); fword("is-noname-cfunc"); feval("to fb8-blitmask"); PUSH( pointer2cell(video_fill_rect) ); fword("is-noname-cfunc"); feval("to fb8-fillrect"); PUSH( pointer2cell(video_invert_rect) ); fword("is-noname-cfunc"); feval("to fb8-invertrect"); /* Static information */ PUSH((ucell)fontdata); feval("to (romfont)"); PUSH(FONT_HEIGHT); feval("to (romfont-height)"); PUSH(FONT_WIDTH); feval("to (romfont-width)"); /* Initialise the structure */ VIDEO_DICT_VALUE(video.w) = VGA_DEFAULT_WIDTH; VIDEO_DICT_VALUE(video.h) = VGA_DEFAULT_HEIGHT; VIDEO_DICT_VALUE(video.depth) = VGA_DEFAULT_DEPTH; VIDEO_DICT_VALUE(video.rb) = VGA_DEFAULT_LINEBYTES; #if defined(CONFIG_QEMU) && (defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64)) /* If running from QEMU, grab the parameters from the firmware interface */ int w, h, d; w = fw_cfg_read_i16(FW_CFG_ARCH_WIDTH); h = fw_cfg_read_i16(FW_CFG_ARCH_HEIGHT); d = fw_cfg_read_i16(FW_CFG_ARCH_DEPTH); if (w && h && d) { VIDEO_DICT_VALUE(video.w) = w; VIDEO_DICT_VALUE(video.h) = h; VIDEO_DICT_VALUE(video.depth) = d; VIDEO_DICT_VALUE(video.rb) = (w * ((d + 7) / 8)); } #endif /* Setup screen-#rows/screen-#columns */ options = find_dev("/options"); snprintf(buf, sizeof(buf), FMT_ucell, VIDEO_DICT_VALUE(video.w) / FONT_WIDTH); set_property(options, "screen-#columns", buf, strlen(buf) + 1); snprintf(buf, sizeof(buf), FMT_ucell, VIDEO_DICT_VALUE(video.h) / FONT_HEIGHT); set_property(options, "screen-#rows", buf, strlen(buf) + 1); }