• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2006-2008 H. Peter Anvin - All Rights Reserved
4  *
5  *   Permission is hereby granted, free of charge, to any person
6  *   obtaining a copy of this software and associated documentation
7  *   files (the "Software"), to deal in the Software without
8  *   restriction, including without limitation the rights to use,
9  *   copy, modify, merge, publish, distribute, sublicense, and/or
10  *   sell copies of the Software, and to permit persons to whom
11  *   the Software is furnished to do so, subject to the following
12  *   conditions:
13  *
14  *   The above copyright notice and this permission notice shall
15  *   be included in all copies or substantial portions of the Software.
16  *
17  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  *   OTHER DEALINGS IN THE SOFTWARE.
25  *
26  * ----------------------------------------------------------------------- */
27 
28 #include <inttypes.h>
29 #include <colortbl.h>
30 #include <string.h>
31 #include "vesa.h"
32 #include "video.h"
33 #include "fill.h"
34 
35 /*
36  * Visible cursor information
37  */
38 static uint8_t cursor_pattern[FONT_MAX_HEIGHT];
39 static struct vesa_char *cursor_pointer = NULL;
40 static int cursor_x, cursor_y;
41 
copy_dword(void * dst,void * src,size_t dword_count)42 static inline void *copy_dword(void *dst, void *src, size_t dword_count)
43 {
44     asm volatile ("rep; movsl":"+D" (dst), "+S"(src), "+c"(dword_count));
45     return dst;			/* Updated destination pointer */
46 }
47 
48 static inline __attribute__ ((always_inline))
alpha_val(uint8_t fg,uint8_t bg,uint8_t alpha)49 uint8_t alpha_val(uint8_t fg, uint8_t bg, uint8_t alpha)
50 {
51     unsigned int tmp;
52 
53     tmp = __vesacon_srgb_to_linear[fg] * alpha;
54     tmp += __vesacon_srgb_to_linear[bg] * (255 - alpha);
55 
56     return __vesacon_linear_to_srgb[tmp >> 12];
57 }
58 
alpha_pixel(uint32_t fg,uint32_t bg)59 static uint32_t alpha_pixel(uint32_t fg, uint32_t bg)
60 {
61     uint8_t alpha = fg >> 24;
62     uint8_t fg_r = fg >> 16;
63     uint8_t fg_g = fg >> 8;
64     uint8_t fg_b = fg;
65     uint8_t bg_r = bg >> 16;
66     uint8_t bg_g = bg >> 8;
67     uint8_t bg_b = bg;
68 
69     return
70 	(alpha_val(fg_r, bg_r, alpha) << 16) |
71 	(alpha_val(fg_g, bg_g, alpha) << 8) | (alpha_val(fg_b, bg_b, alpha));
72 }
73 
vesacon_update_characters(int row,int col,int nrows,int ncols)74 static void vesacon_update_characters(int row, int col, int nrows, int ncols)
75 {
76     const int height = __vesacon_font_height;
77     const int width = FONT_WIDTH;
78     uint32_t *bgrowptr, *bgptr, bgval, fgval;
79     uint32_t fgcolor = 0, bgcolor = 0, color;
80     uint8_t chbits = 0, chxbits = 0, chsbits = 0;
81     int i, j, jx, pixrow, pixsrow;
82     struct vesa_char *rowptr, *rowsptr, *cptr, *csptr;
83     unsigned int bytes_per_pixel = __vesacon_bytes_per_pixel;
84     unsigned long pixel_offset;
85     uint32_t row_buffer[__vesa_info.mi.h_res], *rowbufptr;
86     size_t fbrowptr;
87     uint8_t sha;
88 
89     pixel_offset = ((row * height + VIDEO_BORDER) * __vesa_info.mi.h_res) +
90 	(col * width + VIDEO_BORDER);
91 
92     bgrowptr = &__vesacon_background[pixel_offset];
93     fbrowptr = (row * height + VIDEO_BORDER) * __vesa_info.mi.logical_scan +
94 	(col * width + VIDEO_BORDER) * bytes_per_pixel;
95 
96     /* Note that we keep a 1-character guard area around the real text area... */
97     rowptr = &__vesacon_text_display[(row+1)*(__vesacon_text_cols+2)+(col+1)];
98     rowsptr = rowptr - ((__vesacon_text_cols+2)+1);
99     pixrow = 0;
100     pixsrow = height - 1;
101 
102     for (i = height * nrows; i >= 0; i--) {
103 	bgptr = bgrowptr;
104 	rowbufptr = row_buffer;
105 
106 	cptr = rowptr;
107 	csptr = rowsptr;
108 
109 	chsbits = __vesacon_graphics_font[csptr->ch][pixsrow];
110 	if (__unlikely(csptr == cursor_pointer))
111 	    chsbits |= cursor_pattern[pixsrow];
112 	sha = console_color_table[csptr->attr].shadow;
113 	chsbits &= (sha & 0x02) ? 0xff : 0x00;
114 	chsbits ^= (sha & 0x01) ? 0xff : 0x00;
115 	chsbits <<= (width - 2);
116 	csptr++;
117 
118 	/* Draw two pixels beyond the end of the line.  One for the shadow,
119 	   and one to make sure we have a whole dword of data for the copy
120 	   operation at the end.  Note that this code depends on the fact that
121 	   all characters begin on dword boundaries in the frame buffer. */
122 
123 	for (jx = 1, j = width * ncols + 1; j >= 0; j--) {
124 	    chbits <<= 1;
125 	    chsbits <<= 1;
126 	    chxbits <<= 1;
127 
128 	    switch (jx) {
129 	    case 1:
130 		chbits = __vesacon_graphics_font[cptr->ch][pixrow];
131 		if (__unlikely(cptr == cursor_pointer))
132 		    chbits |= cursor_pattern[pixrow];
133 		sha = console_color_table[cptr->attr].shadow;
134 		chxbits = chbits;
135 		chxbits &= (sha & 0x02) ? 0xff : 0x00;
136 		chxbits ^= (sha & 0x01) ? 0xff : 0x00;
137 		fgcolor = console_color_table[cptr->attr].argb_fg;
138 		bgcolor = console_color_table[cptr->attr].argb_bg;
139 		cptr++;
140 		jx--;
141 		break;
142 	    case 0:
143 		chsbits = __vesacon_graphics_font[csptr->ch][pixsrow];
144 		if (__unlikely(csptr == cursor_pointer))
145 		    chsbits |= cursor_pattern[pixsrow];
146 		sha = console_color_table[csptr->attr].shadow;
147 		chsbits &= (sha & 0x02) ? 0xff : 0x00;
148 		chsbits ^= (sha & 0x01) ? 0xff : 0x00;
149 		csptr++;
150 		jx = width - 1;
151 		break;
152 	    default:
153 		jx--;
154 		break;
155 	    }
156 
157 	    /* If this pixel is raised, use the offsetted value */
158 	    bgval = (chxbits & 0x80)
159 		? bgptr[__vesa_info.mi.h_res + 1] : *bgptr;
160 	    bgptr++;
161 
162 	    /* If this pixel is set, use the fg color, else the bg color */
163 	    fgval = (chbits & 0x80) ? fgcolor : bgcolor;
164 
165 	    /* Produce the combined color pixel value */
166 	    color = alpha_pixel(fgval, bgval);
167 
168 	    /* Apply the shadow (75% shadow) */
169 	    if ((chsbits & ~chxbits) & 0x80) {
170 		color >>= 2;
171 		color &= 0x3f3f3f;
172 	    }
173 
174 	    *rowbufptr++ = color;
175 	}
176 
177 	/* Copy to frame buffer */
178 	__vesacon_copy_to_screen(fbrowptr, row_buffer, rowbufptr - row_buffer);
179 
180 	bgrowptr += __vesa_info.mi.h_res;
181 	fbrowptr += __vesa_info.mi.logical_scan;
182 
183 	if (++pixrow == height) {
184 	    rowptr += __vesacon_text_cols + 2;
185 	    pixrow = 0;
186 	}
187 	if (++pixsrow == height) {
188 	    rowsptr += __vesacon_text_cols + 2;
189 	    pixsrow = 0;
190 	}
191     }
192 }
193 
194 /* Bounding box for changed text.  The (x1, y1) coordinates are +1! */
195 static unsigned int upd_x0 = -1U, upd_x1, upd_y0 = -1U, upd_y1;
196 
197 /* Update the range already touched by various variables */
__vesacon_doit(void)198 void __vesacon_doit(void)
199 {
200     if (upd_x1 > upd_x0 && upd_y1 > upd_y0) {
201 	vesacon_update_characters(upd_y0, upd_x0, upd_y1 - upd_y0,
202 				  upd_x1 - upd_x0);
203 	upd_x0 = upd_y0 = -1U;
204 	upd_x1 = upd_y1 = 0;
205     }
206 }
207 
208 /* Mark a range for update; note argument sequence is the same as
209    vesacon_update_characters() */
vesacon_touch(int row,int col,int rows,int cols)210 static inline void vesacon_touch(int row, int col, int rows, int cols)
211 {
212     unsigned int y0 = row;
213     unsigned int x0 = col;
214     unsigned int y1 = y0 + rows;
215     unsigned int x1 = x0 + cols;
216 
217     if (y0 < upd_y0)
218 	upd_y0 = y0;
219     if (y1 > upd_y1)
220 	upd_y1 = y1;
221     if (x0 < upd_x0)
222 	upd_x0 = x0;
223     if (x1 > upd_x1)
224 	upd_x1 = x1;
225 }
226 
227 /* Erase a region of the screen */
__vesacon_erase(int x0,int y0,int x1,int y1,attr_t attr)228 void __vesacon_erase(int x0, int y0, int x1, int y1, attr_t attr)
229 {
230     int y;
231     struct vesa_char *ptr = &__vesacon_text_display
232 	[(y0 + 1) * (__vesacon_text_cols + 2) + (x0 + 1)];
233     struct vesa_char fill = {
234 	.ch = ' ',
235 	.attr = attr,
236     };
237     int ncols = x1 - x0 + 1;
238 
239     for (y = y0; y <= y1; y++) {
240 	vesacon_fill(ptr, fill, ncols);
241 	ptr += __vesacon_text_cols + 2;
242     }
243 
244     vesacon_touch(y0, x0, y1 - y0 + 1, ncols);
245 }
246 
247 /* Scroll the screen up */
__vesacon_scroll_up(int nrows,attr_t attr)248 void __vesacon_scroll_up(int nrows, attr_t attr)
249 {
250     struct vesa_char *fromptr = &__vesacon_text_display
251 	[(nrows + 1) * (__vesacon_text_cols + 2)];
252     struct vesa_char *toptr = &__vesacon_text_display
253 	[(__vesacon_text_cols + 2)];
254     int dword_count =
255 	(__vesacon_text_rows - nrows) * (__vesacon_text_cols + 2);
256     struct vesa_char fill = {
257 	.ch = ' ',
258 	.attr = attr,
259     };
260 
261     toptr = copy_dword(toptr, fromptr, dword_count);
262 
263     dword_count = nrows * (__vesacon_text_cols + 2);
264 
265     vesacon_fill(toptr, fill, dword_count);
266 
267     vesacon_touch(0, 0, __vesacon_text_rows, __vesacon_text_cols);
268 }
269 
270 /* Draw one character text at a specific area of the screen */
__vesacon_write_char(int x,int y,uint8_t ch,attr_t attr)271 void __vesacon_write_char(int x, int y, uint8_t ch, attr_t attr)
272 {
273     struct vesa_char *ptr = &__vesacon_text_display
274 	[(y + 1) * (__vesacon_text_cols + 2) + (x + 1)];
275 
276     ptr->ch = ch;
277     ptr->attr = attr;
278 
279     vesacon_touch(y, x, 1, 1);
280 }
281 
__vesacon_set_cursor(int x,int y,bool visible)282 void __vesacon_set_cursor(int x, int y, bool visible)
283 {
284     struct vesa_char *ptr = &__vesacon_text_display
285 	[(y + 1) * (__vesacon_text_cols + 2) + (x + 1)];
286 
287     if (cursor_pointer)
288 	vesacon_touch(cursor_y, cursor_x, 1, 1);
289 
290     if (!visible) {
291 	/* Invisible cursor */
292 	cursor_pointer = NULL;
293     } else {
294 	cursor_pointer = ptr;
295 	vesacon_touch(y, x, 1, 1);
296     }
297 
298     cursor_x = x;
299     cursor_y = y;
300 }
301 
__vesacon_init_cursor(int font_height)302 void __vesacon_init_cursor(int font_height)
303 {
304     int r0 = font_height - (font_height < 10 ? 2 : 3);
305 
306     if (r0 < 0)
307 	r0 = 0;
308 
309     memset(cursor_pattern, 0, font_height);
310     cursor_pattern[r0] = 0xff;
311     cursor_pattern[r0 + 1] = 0xff;
312 }
313 
__vesacon_redraw_text(void)314 void __vesacon_redraw_text(void)
315 {
316     vesacon_update_characters(0, 0, __vesacon_text_rows, __vesacon_text_cols);
317 }
318