blob: 85a9e9746d960f6a2444fd2b1335b58ba0fcf039 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/* ----------------------------------------------------------------------- *
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 */
38static uint8_t cursor_pattern[FONT_MAX_HEIGHT];
39static struct vesa_char *cursor_pointer = NULL;
40static int cursor_x, cursor_y;
41
42static 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
48static inline __attribute__ ((always_inline))
49uint8_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
59static 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
74static 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! */
195static unsigned int upd_x0 = -1U, upd_x1, upd_y0 = -1U, upd_y1;
196
197/* Update the range already touched by various variables */
198void __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() */
210static 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 */
228void __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 */
248void __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 */
271void __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
282void __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
302void __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
314void __vesacon_redraw_text(void)
315{
316 vesacon_update_characters(0, 0, __vesacon_text_rows, __vesacon_text_cols);
317}