13630506bSToomas Soome /*- 23630506bSToomas Soome * SPDX-License-Identifier: BSD-2-Clause 33630506bSToomas Soome * 43630506bSToomas Soome * Copyright 2020 Toomas Soome 53630506bSToomas Soome * Copyright 2019 OmniOS Community Edition (OmniOSce) Association. 63630506bSToomas Soome * Copyright 2020 RackTop Systems, Inc. 73630506bSToomas Soome * 83630506bSToomas Soome * Redistribution and use in source and binary forms, with or without 93630506bSToomas Soome * modification, are permitted provided that the following conditions 103630506bSToomas Soome * are met: 113630506bSToomas Soome * 1. Redistributions of source code must retain the above copyright 123630506bSToomas Soome * notice, this list of conditions and the following disclaimer. 133630506bSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 143630506bSToomas Soome * notice, this list of conditions and the following disclaimer in the 153630506bSToomas Soome * documentation and/or other materials provided with the distribution. 163630506bSToomas Soome * 173630506bSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 183630506bSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 193630506bSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 203630506bSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 213630506bSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 223630506bSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 233630506bSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 243630506bSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 253630506bSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 263630506bSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 273630506bSToomas Soome * SUCH DAMAGE. 283630506bSToomas Soome */ 293630506bSToomas Soome 301caed70cSToomas Soome /* 311caed70cSToomas Soome * The workhorse here is gfxfb_blt(). It is implemented to mimic UEFI 321caed70cSToomas Soome * GOP Blt, and allows us to fill the rectangle on screen, copy 331caed70cSToomas Soome * rectangle from video to buffer and buffer to video and video to video. 341caed70cSToomas Soome * Such implementation does allow us to have almost identical implementation 351caed70cSToomas Soome * for both BIOS VBE and UEFI. 361caed70cSToomas Soome * 371caed70cSToomas Soome * ALL pixel data is assumed to be 32-bit BGRA (byte order Blue, Green, Red, 381caed70cSToomas Soome * Alpha) format, this allows us to only handle RGB data and not to worry 391caed70cSToomas Soome * about mixing RGB with indexed colors. 401caed70cSToomas Soome * Data exchange between memory buffer and video will translate BGRA 411caed70cSToomas Soome * and native format as following: 421caed70cSToomas Soome * 431caed70cSToomas Soome * 32-bit to/from 32-bit is trivial case. 441caed70cSToomas Soome * 32-bit to/from 24-bit is also simple - we just drop the alpha channel. 451caed70cSToomas Soome * 32-bit to/from 16-bit is more complicated, because we nee to handle 461caed70cSToomas Soome * data loss from 32-bit to 16-bit. While reading/writing from/to video, we 471caed70cSToomas Soome * need to apply masks of 16-bit color components. This will preserve 481caed70cSToomas Soome * colors for terminal text. For 32-bit truecolor PMG images, we need to 491caed70cSToomas Soome * translate 32-bit colors to 15/16 bit colors and this means data loss. 501caed70cSToomas Soome * There are different algorithms how to perform such color space reduction, 511caed70cSToomas Soome * we are currently using bitwise right shift to reduce color space and so far 521caed70cSToomas Soome * this technique seems to be sufficient (see also gfx_fb_putimage(), the 531caed70cSToomas Soome * end of for loop). 541caed70cSToomas Soome * 32-bit to/from 8-bit is the most troublesome because 8-bit colors are 551caed70cSToomas Soome * indexed. From video, we do get color indexes, and we do translate 561caed70cSToomas Soome * color index values to RGB. To write to video, we again need to translate 571caed70cSToomas Soome * RGB to color index. Additionally, we need to translate between VGA and 581caed70cSToomas Soome * console colors. 591caed70cSToomas Soome * 601caed70cSToomas Soome * Our internal color data is represented using BGRA format. But the hardware 611caed70cSToomas Soome * used indexed colors for 8-bit colors (0-255) and for this mode we do 621caed70cSToomas Soome * need to perform translation to/from BGRA and index values. 631caed70cSToomas Soome * 641caed70cSToomas Soome * - paletteentry RGB <-> index - 651caed70cSToomas Soome * BGRA BUFFER <----/ \ - VIDEO 661caed70cSToomas Soome * \ / 671caed70cSToomas Soome * - RGB (16/24/32) - 681caed70cSToomas Soome * 691caed70cSToomas Soome * To perform index to RGB translation, we use palette table generated 701caed70cSToomas Soome * from when we set up 8-bit mode video. We cannot read palette data from 711caed70cSToomas Soome * the hardware, because not all hardware supports reading it. 721caed70cSToomas Soome * 731caed70cSToomas Soome * BGRA to index is implemented in rgb_to_color_index() by searching 741caed70cSToomas Soome * palette array for closest match of RBG values. 751caed70cSToomas Soome * 761caed70cSToomas Soome * Note: In 8-bit mode, We do store first 16 colors to palette registers 771caed70cSToomas Soome * in VGA color order, this serves two purposes; firstly, 781caed70cSToomas Soome * if palette update is not supported, we still have correct 16 colors. 791caed70cSToomas Soome * Secondly, the kernel does get correct 16 colors when some other boot 801caed70cSToomas Soome * loader is used. However, the palette map for 8-bit colors is using 811caed70cSToomas Soome * console color ordering - this does allow us to skip translation 821caed70cSToomas Soome * from VGA colors to console colors, while we are reading RGB data. 831caed70cSToomas Soome */ 841caed70cSToomas Soome 853630506bSToomas Soome #include <sys/param.h> 863630506bSToomas Soome #include <stand.h> 873630506bSToomas Soome #include <teken.h> 883630506bSToomas Soome #include <gfx_fb.h> 893630506bSToomas Soome #include <sys/font.h> 9000460cc8SEmmanuel Vadot #include <sys/splash.h> 9118968b82SWarner Losh #include <sys/linker.h> 9218968b82SWarner Losh #include <sys/module.h> 933630506bSToomas Soome #include <sys/stdint.h> 943630506bSToomas Soome #include <sys/endian.h> 953630506bSToomas Soome #include <pnglite.h> 963630506bSToomas Soome #include <bootstrap.h> 973630506bSToomas Soome #include <lz4.h> 983630506bSToomas Soome #if defined(EFI) 993630506bSToomas Soome #include <efi.h> 1003630506bSToomas Soome #include <efilib.h> 1013630506bSToomas Soome #else 1023630506bSToomas Soome #include <vbe.h> 1033630506bSToomas Soome #endif 1043630506bSToomas Soome 10586077f4fSAhmad Khalifa #include "modinfo.h" 10686077f4fSAhmad Khalifa 1073630506bSToomas Soome /* VGA text mode does use bold font. */ 1083630506bSToomas Soome #if !defined(VGA_8X16_FONT) 10920fb2ea2SToomas Soome #define VGA_8X16_FONT "/boot/fonts/8x16b.fnt" 1103630506bSToomas Soome #endif 1113630506bSToomas Soome #if !defined(DEFAULT_8X16_FONT) 1123630506bSToomas Soome #define DEFAULT_8X16_FONT "/boot/fonts/8x16.fnt" 1133630506bSToomas Soome #endif 1143630506bSToomas Soome 1153630506bSToomas Soome /* 1163630506bSToomas Soome * Must be sorted by font size in descending order 1173630506bSToomas Soome */ 1183630506bSToomas Soome font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts); 1193630506bSToomas Soome 1203630506bSToomas Soome #define DEFAULT_FONT_DATA font_data_8x16 1213630506bSToomas Soome extern vt_font_bitmap_data_t font_data_8x16; 1223630506bSToomas Soome teken_gfx_t gfx_state = { 0 }; 1233630506bSToomas Soome 1243630506bSToomas Soome static struct { 1253630506bSToomas Soome unsigned char r; /* Red percentage value. */ 1263630506bSToomas Soome unsigned char g; /* Green percentage value. */ 1273630506bSToomas Soome unsigned char b; /* Blue percentage value. */ 1283630506bSToomas Soome } color_def[NCOLORS] = { 1293630506bSToomas Soome {0, 0, 0}, /* black */ 1303630506bSToomas Soome {50, 0, 0}, /* dark red */ 1313630506bSToomas Soome {0, 50, 0}, /* dark green */ 1323630506bSToomas Soome {77, 63, 0}, /* dark yellow */ 1333630506bSToomas Soome {20, 40, 64}, /* dark blue */ 1343630506bSToomas Soome {50, 0, 50}, /* dark magenta */ 1353630506bSToomas Soome {0, 50, 50}, /* dark cyan */ 1363630506bSToomas Soome {75, 75, 75}, /* light gray */ 1373630506bSToomas Soome 1383630506bSToomas Soome {18, 20, 21}, /* dark gray */ 1393630506bSToomas Soome {100, 0, 0}, /* light red */ 1403630506bSToomas Soome {0, 100, 0}, /* light green */ 1413630506bSToomas Soome {100, 100, 0}, /* light yellow */ 1423630506bSToomas Soome {45, 62, 81}, /* light blue */ 1433630506bSToomas Soome {100, 0, 100}, /* light magenta */ 1443630506bSToomas Soome {0, 100, 100}, /* light cyan */ 1453630506bSToomas Soome {100, 100, 100}, /* white */ 1463630506bSToomas Soome }; 1473630506bSToomas Soome uint32_t cmap[NCMAP]; 1483630506bSToomas Soome 1493630506bSToomas Soome /* 1503630506bSToomas Soome * Between console's palette and VGA's one: 1513630506bSToomas Soome * - blue and red are swapped (1 <-> 4) 1523630506bSToomas Soome * - yellow and cyan are swapped (3 <-> 6) 1533630506bSToomas Soome */ 1543630506bSToomas Soome const int cons_to_vga_colors[NCOLORS] = { 1553630506bSToomas Soome 0, 4, 2, 6, 1, 5, 3, 7, 1563630506bSToomas Soome 8, 12, 10, 14, 9, 13, 11, 15 1573630506bSToomas Soome }; 1583630506bSToomas Soome 1593630506bSToomas Soome static const int vga_to_cons_colors[NCOLORS] = { 1603630506bSToomas Soome 0, 1, 2, 3, 4, 5, 6, 7, 1613630506bSToomas Soome 8, 9, 10, 11, 12, 13, 14, 15 1623630506bSToomas Soome }; 1633630506bSToomas Soome 164*21b5b8b3SToomas Soome /* 165*21b5b8b3SToomas Soome * It is reported very slow console draw in some systems. 166*21b5b8b3SToomas Soome * in order to exclude buggy gop->Blt(), we want option 167*21b5b8b3SToomas Soome * to use direct draw to framebuffer and avoid gop->Blt. 168*21b5b8b3SToomas Soome * Can be toggled with "gop" command. 169*21b5b8b3SToomas Soome */ 170*21b5b8b3SToomas Soome bool ignore_gop_blt = false; 171*21b5b8b3SToomas Soome 1723630506bSToomas Soome struct text_pixel *screen_buffer; 1733630506bSToomas Soome #if defined(EFI) 1743630506bSToomas Soome static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GlyphBuffer; 1753630506bSToomas Soome #else 1763630506bSToomas Soome static struct paletteentry *GlyphBuffer; 1773630506bSToomas Soome #endif 1783630506bSToomas Soome static size_t GlyphBufferSize; 1793630506bSToomas Soome 1803630506bSToomas Soome static bool insert_font(char *, FONT_FLAGS); 1813630506bSToomas Soome static int font_set(struct env_var *, int, const void *); 1823630506bSToomas Soome static void * allocate_glyphbuffer(uint32_t, uint32_t); 1833630506bSToomas Soome static void gfx_fb_cursor_draw(teken_gfx_t *, const teken_pos_t *, bool); 1843630506bSToomas Soome 1853630506bSToomas Soome /* 1863630506bSToomas Soome * Initialize gfx framework. 1873630506bSToomas Soome */ 1883630506bSToomas Soome void 1893630506bSToomas Soome gfx_framework_init(void) 1903630506bSToomas Soome { 1913630506bSToomas Soome /* 1923630506bSToomas Soome * Setup font list to have builtin font. 1933630506bSToomas Soome */ 1943630506bSToomas Soome (void) insert_font(NULL, FONT_BUILTIN); 1956faf55c8SWarner Losh gfx_interp_ref(); /* Draw in the gfx interpreter for this thing */ 1963630506bSToomas Soome } 1973630506bSToomas Soome 1983630506bSToomas Soome static uint8_t * 1993630506bSToomas Soome gfx_get_fb_address(void) 2003630506bSToomas Soome { 2013630506bSToomas Soome return (ptov((uint32_t)gfx_state.tg_fb.fb_addr)); 2023630506bSToomas Soome } 2033630506bSToomas Soome 2043630506bSToomas Soome /* 2053630506bSToomas Soome * Utility function to parse gfx mode line strings. 2063630506bSToomas Soome */ 2073630506bSToomas Soome bool 2083630506bSToomas Soome gfx_parse_mode_str(char *str, int *x, int *y, int *depth) 2093630506bSToomas Soome { 2103630506bSToomas Soome char *p, *end; 2113630506bSToomas Soome 2123630506bSToomas Soome errno = 0; 2133630506bSToomas Soome p = str; 2143630506bSToomas Soome *x = strtoul(p, &end, 0); 2153630506bSToomas Soome if (*x == 0 || errno != 0) 2163630506bSToomas Soome return (false); 2173630506bSToomas Soome if (*end != 'x') 2183630506bSToomas Soome return (false); 2193630506bSToomas Soome p = end + 1; 2203630506bSToomas Soome *y = strtoul(p, &end, 0); 2213630506bSToomas Soome if (*y == 0 || errno != 0) 2223630506bSToomas Soome return (false); 2233630506bSToomas Soome if (*end != 'x') { 2243630506bSToomas Soome *depth = -1; /* auto select */ 2253630506bSToomas Soome } else { 2263630506bSToomas Soome p = end + 1; 2273630506bSToomas Soome *depth = strtoul(p, &end, 0); 2283630506bSToomas Soome if (*depth == 0 || errno != 0 || *end != '\0') 2293630506bSToomas Soome return (false); 2303630506bSToomas Soome } 2313630506bSToomas Soome 2323630506bSToomas Soome return (true); 2333630506bSToomas Soome } 2343630506bSToomas Soome 2353630506bSToomas Soome static uint32_t 2363630506bSToomas Soome rgb_color_map(uint8_t index, uint32_t rmax, int roffset, 2373630506bSToomas Soome uint32_t gmax, int goffset, uint32_t bmax, int boffset) 2383630506bSToomas Soome { 2393630506bSToomas Soome uint32_t color, code, gray, level; 2403630506bSToomas Soome 2413630506bSToomas Soome if (index < NCOLORS) { 2423630506bSToomas Soome #define CF(_f, _i) ((_f ## max * color_def[(_i)]._f / 100) << _f ## offset) 2433630506bSToomas Soome return (CF(r, index) | CF(g, index) | CF(b, index)); 2443630506bSToomas Soome #undef CF 2453630506bSToomas Soome } 2463630506bSToomas Soome 2473630506bSToomas Soome #define CF(_f, _c) ((_f ## max & _c) << _f ## offset) 2483630506bSToomas Soome /* 6x6x6 color cube */ 2493630506bSToomas Soome if (index > 15 && index < 232) { 2503630506bSToomas Soome uint32_t red, green, blue; 2513630506bSToomas Soome 2523630506bSToomas Soome for (red = 0; red < 6; red++) { 2533630506bSToomas Soome for (green = 0; green < 6; green++) { 2543630506bSToomas Soome for (blue = 0; blue < 6; blue++) { 2553630506bSToomas Soome code = 16 + (red * 36) + 2563630506bSToomas Soome (green * 6) + blue; 2573630506bSToomas Soome if (code != index) 2583630506bSToomas Soome continue; 2593630506bSToomas Soome red = red ? (red * 40 + 55) : 0; 2603630506bSToomas Soome green = green ? (green * 40 + 55) : 0; 2613630506bSToomas Soome blue = blue ? (blue * 40 + 55) : 0; 2623630506bSToomas Soome color = CF(r, red); 2633630506bSToomas Soome color |= CF(g, green); 2643630506bSToomas Soome color |= CF(b, blue); 2653630506bSToomas Soome return (color); 2663630506bSToomas Soome } 2673630506bSToomas Soome } 2683630506bSToomas Soome } 2693630506bSToomas Soome } 2703630506bSToomas Soome 2713630506bSToomas Soome /* colors 232-255 are a grayscale ramp */ 2723630506bSToomas Soome for (gray = 0; gray < 24; gray++) { 2733630506bSToomas Soome level = (gray * 10) + 8; 2743630506bSToomas Soome code = 232 + gray; 2753630506bSToomas Soome if (code == index) 2763630506bSToomas Soome break; 2773630506bSToomas Soome } 2783630506bSToomas Soome return (CF(r, level) | CF(g, level) | CF(b, level)); 2793630506bSToomas Soome #undef CF 2803630506bSToomas Soome } 2813630506bSToomas Soome 2823630506bSToomas Soome /* 2833630506bSToomas Soome * Support for color mapping. 2843630506bSToomas Soome * For 8, 24 and 32 bit depth, use mask size 8. 2853630506bSToomas Soome * 15/16 bit depth needs to use mask size from mode, 2863630506bSToomas Soome * or we will lose color information from 32-bit to 15/16 bit translation. 2873630506bSToomas Soome */ 2883630506bSToomas Soome uint32_t 2893630506bSToomas Soome gfx_fb_color_map(uint8_t index) 2903630506bSToomas Soome { 2913630506bSToomas Soome int rmask, gmask, bmask; 2923630506bSToomas Soome int roff, goff, boff, bpp; 2933630506bSToomas Soome 2943630506bSToomas Soome roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1; 2953630506bSToomas Soome goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1; 2963630506bSToomas Soome boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; 2973630506bSToomas Soome bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3; 2983630506bSToomas Soome 2993630506bSToomas Soome if (bpp == 2) 3003630506bSToomas Soome rmask = gfx_state.tg_fb.fb_mask_red >> roff; 3013630506bSToomas Soome else 3023630506bSToomas Soome rmask = 0xff; 3033630506bSToomas Soome 3043630506bSToomas Soome if (bpp == 2) 3053630506bSToomas Soome gmask = gfx_state.tg_fb.fb_mask_green >> goff; 3063630506bSToomas Soome else 3073630506bSToomas Soome gmask = 0xff; 3083630506bSToomas Soome 3093630506bSToomas Soome if (bpp == 2) 3103630506bSToomas Soome bmask = gfx_state.tg_fb.fb_mask_blue >> boff; 3113630506bSToomas Soome else 3123630506bSToomas Soome bmask = 0xff; 3133630506bSToomas Soome 3143630506bSToomas Soome return (rgb_color_map(index, rmask, 16, gmask, 8, bmask, 0)); 3153630506bSToomas Soome } 3163630506bSToomas Soome 3174bbfe4bfSToomas Soome /* 3184bbfe4bfSToomas Soome * Get indexed color from RGB. This function is used to write data to video 3194bbfe4bfSToomas Soome * memory when the adapter is set to use indexed colors. 3204bbfe4bfSToomas Soome * Since UEFI does only support 32-bit colors, we do not implement it for 3214bbfe4bfSToomas Soome * UEFI because there is no need for it and we do not have palette array 3224bbfe4bfSToomas Soome * for UEFI. 3234bbfe4bfSToomas Soome */ 3243630506bSToomas Soome static uint8_t 3253630506bSToomas Soome rgb_to_color_index(uint8_t r, uint8_t g, uint8_t b) 3263630506bSToomas Soome { 3273630506bSToomas Soome #if !defined(EFI) 3283630506bSToomas Soome uint32_t color, best, dist, k; 3293630506bSToomas Soome int diff; 3303630506bSToomas Soome 3313630506bSToomas Soome color = 0; 3321caed70cSToomas Soome best = 255 * 255 * 255; 3333630506bSToomas Soome for (k = 0; k < NCMAP; k++) { 3343630506bSToomas Soome diff = r - pe8[k].Red; 3353630506bSToomas Soome dist = diff * diff; 3363630506bSToomas Soome diff = g - pe8[k].Green; 3373630506bSToomas Soome dist += diff * diff; 3383630506bSToomas Soome diff = b - pe8[k].Blue; 3393630506bSToomas Soome dist += diff * diff; 3403630506bSToomas Soome 3414bbfe4bfSToomas Soome /* Exact match, exit the loop */ 3423630506bSToomas Soome if (dist == 0) 3433630506bSToomas Soome break; 3444bbfe4bfSToomas Soome 3453630506bSToomas Soome if (dist < best) { 3463630506bSToomas Soome color = k; 3473630506bSToomas Soome best = dist; 3483630506bSToomas Soome } 3493630506bSToomas Soome } 3503630506bSToomas Soome if (k == NCMAP) 3513630506bSToomas Soome k = color; 3523630506bSToomas Soome return (k); 3533630506bSToomas Soome #else 3543630506bSToomas Soome (void) r; 3553630506bSToomas Soome (void) g; 3563630506bSToomas Soome (void) b; 3573630506bSToomas Soome return (0); 3583630506bSToomas Soome #endif 3593630506bSToomas Soome } 3603630506bSToomas Soome 3613630506bSToomas Soome int 3623630506bSToomas Soome generate_cons_palette(uint32_t *palette, int format, 3633630506bSToomas Soome uint32_t rmax, int roffset, uint32_t gmax, int goffset, 3643630506bSToomas Soome uint32_t bmax, int boffset) 3653630506bSToomas Soome { 3663630506bSToomas Soome int i; 3673630506bSToomas Soome 3683630506bSToomas Soome switch (format) { 3693630506bSToomas Soome case COLOR_FORMAT_VGA: 3703630506bSToomas Soome for (i = 0; i < NCOLORS; i++) 3713630506bSToomas Soome palette[i] = cons_to_vga_colors[i]; 3723630506bSToomas Soome for (; i < NCMAP; i++) 3733630506bSToomas Soome palette[i] = i; 3743630506bSToomas Soome break; 3753630506bSToomas Soome case COLOR_FORMAT_RGB: 3763630506bSToomas Soome for (i = 0; i < NCMAP; i++) 3773630506bSToomas Soome palette[i] = rgb_color_map(i, rmax, roffset, 3783630506bSToomas Soome gmax, goffset, bmax, boffset); 3793630506bSToomas Soome break; 3803630506bSToomas Soome default: 3813630506bSToomas Soome return (ENODEV); 3823630506bSToomas Soome } 3833630506bSToomas Soome 3843630506bSToomas Soome return (0); 3853630506bSToomas Soome } 3863630506bSToomas Soome 3873630506bSToomas Soome static void 3883630506bSToomas Soome gfx_mem_wr1(uint8_t *base, size_t size, uint32_t o, uint8_t v) 3893630506bSToomas Soome { 3903630506bSToomas Soome 3913630506bSToomas Soome if (o >= size) 3923630506bSToomas Soome return; 3933630506bSToomas Soome *(uint8_t *)(base + o) = v; 3943630506bSToomas Soome } 3953630506bSToomas Soome 3963630506bSToomas Soome static void 3973630506bSToomas Soome gfx_mem_wr2(uint8_t *base, size_t size, uint32_t o, uint16_t v) 3983630506bSToomas Soome { 3993630506bSToomas Soome 4003630506bSToomas Soome if (o >= size) 4013630506bSToomas Soome return; 4023630506bSToomas Soome *(uint16_t *)(base + o) = v; 4033630506bSToomas Soome } 4043630506bSToomas Soome 4053630506bSToomas Soome static void 4063630506bSToomas Soome gfx_mem_wr4(uint8_t *base, size_t size, uint32_t o, uint32_t v) 4073630506bSToomas Soome { 4083630506bSToomas Soome 4093630506bSToomas Soome if (o >= size) 4103630506bSToomas Soome return; 4113630506bSToomas Soome *(uint32_t *)(base + o) = v; 4123630506bSToomas Soome } 4133630506bSToomas Soome 4143630506bSToomas Soome static int gfxfb_blt_fill(void *BltBuffer, 4153630506bSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 4163630506bSToomas Soome uint32_t Width, uint32_t Height) 4173630506bSToomas Soome { 4183630506bSToomas Soome #if defined(EFI) 4193630506bSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; 4203630506bSToomas Soome #else 4213630506bSToomas Soome struct paletteentry *p; 4223630506bSToomas Soome #endif 4233630506bSToomas Soome uint32_t data, bpp, pitch, y, x; 4243630506bSToomas Soome int roff, goff, boff; 4253630506bSToomas Soome size_t size; 4263630506bSToomas Soome off_t off; 4273630506bSToomas Soome uint8_t *destination; 4283630506bSToomas Soome 4293630506bSToomas Soome if (BltBuffer == NULL) 4303630506bSToomas Soome return (EINVAL); 4313630506bSToomas Soome 4323630506bSToomas Soome if (DestinationY + Height > gfx_state.tg_fb.fb_height) 4333630506bSToomas Soome return (EINVAL); 4343630506bSToomas Soome 4353630506bSToomas Soome if (DestinationX + Width > gfx_state.tg_fb.fb_width) 4363630506bSToomas Soome return (EINVAL); 4373630506bSToomas Soome 4383630506bSToomas Soome if (Width == 0 || Height == 0) 4393630506bSToomas Soome return (EINVAL); 4403630506bSToomas Soome 4413630506bSToomas Soome p = BltBuffer; 4423630506bSToomas Soome roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1; 4433630506bSToomas Soome goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1; 4443630506bSToomas Soome boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; 4453630506bSToomas Soome 4463630506bSToomas Soome if (gfx_state.tg_fb.fb_bpp == 8) { 4473630506bSToomas Soome data = rgb_to_color_index(p->Red, p->Green, p->Blue); 4483630506bSToomas Soome } else { 4493630506bSToomas Soome data = (p->Red & 4503630506bSToomas Soome (gfx_state.tg_fb.fb_mask_red >> roff)) << roff; 4513630506bSToomas Soome data |= (p->Green & 4523630506bSToomas Soome (gfx_state.tg_fb.fb_mask_green >> goff)) << goff; 4533630506bSToomas Soome data |= (p->Blue & 4543630506bSToomas Soome (gfx_state.tg_fb.fb_mask_blue >> boff)) << boff; 4553630506bSToomas Soome } 4563630506bSToomas Soome 4573630506bSToomas Soome bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3; 4583630506bSToomas Soome pitch = gfx_state.tg_fb.fb_stride * bpp; 4593630506bSToomas Soome destination = gfx_get_fb_address(); 4603630506bSToomas Soome size = gfx_state.tg_fb.fb_size; 4613630506bSToomas Soome 4623630506bSToomas Soome for (y = DestinationY; y < Height + DestinationY; y++) { 4633630506bSToomas Soome off = y * pitch + DestinationX * bpp; 4643630506bSToomas Soome for (x = 0; x < Width; x++) { 4653630506bSToomas Soome switch (bpp) { 4663630506bSToomas Soome case 1: 4673630506bSToomas Soome gfx_mem_wr1(destination, size, off, 4683630506bSToomas Soome (data < NCOLORS) ? 4693630506bSToomas Soome cons_to_vga_colors[data] : data); 4703630506bSToomas Soome break; 4713630506bSToomas Soome case 2: 4723630506bSToomas Soome gfx_mem_wr2(destination, size, off, data); 4733630506bSToomas Soome break; 4743630506bSToomas Soome case 3: 4753630506bSToomas Soome gfx_mem_wr1(destination, size, off, 4763630506bSToomas Soome (data >> 16) & 0xff); 4773630506bSToomas Soome gfx_mem_wr1(destination, size, off + 1, 4783630506bSToomas Soome (data >> 8) & 0xff); 4793630506bSToomas Soome gfx_mem_wr1(destination, size, off + 2, 4803630506bSToomas Soome data & 0xff); 4813630506bSToomas Soome break; 4823630506bSToomas Soome case 4: 4833630506bSToomas Soome gfx_mem_wr4(destination, size, off, data); 4843630506bSToomas Soome break; 4851caed70cSToomas Soome default: 4861caed70cSToomas Soome return (EINVAL); 4873630506bSToomas Soome } 4883630506bSToomas Soome off += bpp; 4893630506bSToomas Soome } 4903630506bSToomas Soome } 4913630506bSToomas Soome 4923630506bSToomas Soome return (0); 4933630506bSToomas Soome } 4943630506bSToomas Soome 4953630506bSToomas Soome static int 4963630506bSToomas Soome gfxfb_blt_video_to_buffer(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, 4973630506bSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 4983630506bSToomas Soome uint32_t Width, uint32_t Height, uint32_t Delta) 4993630506bSToomas Soome { 5003630506bSToomas Soome #if defined(EFI) 5013630506bSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; 5023630506bSToomas Soome #else 5033630506bSToomas Soome struct paletteentry *p; 5043630506bSToomas Soome #endif 5053630506bSToomas Soome uint32_t x, sy, dy; 5063630506bSToomas Soome uint32_t bpp, pitch, copybytes; 5073630506bSToomas Soome off_t off; 5081caed70cSToomas Soome uint8_t *source, *destination, *sb; 5093630506bSToomas Soome uint8_t rm, rp, gm, gp, bm, bp; 5103630506bSToomas Soome bool bgra; 5113630506bSToomas Soome 5123630506bSToomas Soome if (BltBuffer == NULL) 5133630506bSToomas Soome return (EINVAL); 5143630506bSToomas Soome 5153630506bSToomas Soome if (SourceY + Height > 5163630506bSToomas Soome gfx_state.tg_fb.fb_height) 5173630506bSToomas Soome return (EINVAL); 5183630506bSToomas Soome 5193630506bSToomas Soome if (SourceX + Width > gfx_state.tg_fb.fb_width) 5203630506bSToomas Soome return (EINVAL); 5213630506bSToomas Soome 5223630506bSToomas Soome if (Width == 0 || Height == 0) 5233630506bSToomas Soome return (EINVAL); 5243630506bSToomas Soome 5253630506bSToomas Soome if (Delta == 0) 5263630506bSToomas Soome Delta = Width * sizeof (*p); 5273630506bSToomas Soome 5283630506bSToomas Soome bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3; 5293630506bSToomas Soome pitch = gfx_state.tg_fb.fb_stride * bpp; 5303630506bSToomas Soome 5313630506bSToomas Soome copybytes = Width * bpp; 5323630506bSToomas Soome 5333630506bSToomas Soome rp = ffs(gfx_state.tg_fb.fb_mask_red) - 1; 5343630506bSToomas Soome gp = ffs(gfx_state.tg_fb.fb_mask_green) - 1; 5353630506bSToomas Soome bp = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; 5363630506bSToomas Soome rm = gfx_state.tg_fb.fb_mask_red >> rp; 5373630506bSToomas Soome gm = gfx_state.tg_fb.fb_mask_green >> gp; 5383630506bSToomas Soome bm = gfx_state.tg_fb.fb_mask_blue >> bp; 5393630506bSToomas Soome 5403630506bSToomas Soome /* If FB pixel format is BGRA, we can use direct copy. */ 5413630506bSToomas Soome bgra = bpp == 4 && 5423630506bSToomas Soome ffs(rm) - 1 == 8 && rp == 16 && 5433630506bSToomas Soome ffs(gm) - 1 == 8 && gp == 8 && 5443630506bSToomas Soome ffs(bm) - 1 == 8 && bp == 0; 5453630506bSToomas Soome 5463630506bSToomas Soome for (sy = SourceY, dy = DestinationY; dy < Height + DestinationY; 5473630506bSToomas Soome sy++, dy++) { 5483630506bSToomas Soome off = sy * pitch + SourceX * bpp; 5493630506bSToomas Soome source = gfx_get_fb_address() + off; 5503630506bSToomas Soome destination = (uint8_t *)BltBuffer + dy * Delta + 5513630506bSToomas Soome DestinationX * sizeof (*p); 5523630506bSToomas Soome 5531caed70cSToomas Soome if (bgra) { 5543630506bSToomas Soome bcopy(source, destination, copybytes); 5551caed70cSToomas Soome } else { 5563630506bSToomas Soome for (x = 0; x < Width; x++) { 5573630506bSToomas Soome uint32_t c = 0; 5583630506bSToomas Soome 5591caed70cSToomas Soome p = (void *)(destination + x * sizeof (*p)); 5601caed70cSToomas Soome sb = source + x * bpp; 5613630506bSToomas Soome switch (bpp) { 5623630506bSToomas Soome case 1: 5633630506bSToomas Soome c = *sb; 5643630506bSToomas Soome break; 5653630506bSToomas Soome case 2: 5663630506bSToomas Soome c = *(uint16_t *)sb; 5673630506bSToomas Soome break; 5683630506bSToomas Soome case 3: 5693630506bSToomas Soome c = sb[0] << 16 | sb[1] << 8 | sb[2]; 5703630506bSToomas Soome break; 5713630506bSToomas Soome case 4: 5723630506bSToomas Soome c = *(uint32_t *)sb; 5733630506bSToomas Soome break; 5741caed70cSToomas Soome default: 5751caed70cSToomas Soome return (EINVAL); 5763630506bSToomas Soome } 5773630506bSToomas Soome 5783630506bSToomas Soome if (bpp == 1) { 5793630506bSToomas Soome *(uint32_t *)p = gfx_fb_color_map( 5803630506bSToomas Soome (c < 16) ? 5813630506bSToomas Soome vga_to_cons_colors[c] : c); 5823630506bSToomas Soome } else { 5833630506bSToomas Soome p->Red = (c >> rp) & rm; 5843630506bSToomas Soome p->Green = (c >> gp) & gm; 5853630506bSToomas Soome p->Blue = (c >> bp) & bm; 5863630506bSToomas Soome p->Reserved = 0; 5873630506bSToomas Soome } 5883630506bSToomas Soome } 5893630506bSToomas Soome } 5903630506bSToomas Soome } 5913630506bSToomas Soome 5923630506bSToomas Soome return (0); 5933630506bSToomas Soome } 5943630506bSToomas Soome 5953630506bSToomas Soome static int 5963630506bSToomas Soome gfxfb_blt_buffer_to_video(void *BltBuffer, uint32_t SourceX, uint32_t SourceY, 5973630506bSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 5983630506bSToomas Soome uint32_t Width, uint32_t Height, uint32_t Delta) 5993630506bSToomas Soome { 6003630506bSToomas Soome #if defined(EFI) 6013630506bSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; 6023630506bSToomas Soome #else 6033630506bSToomas Soome struct paletteentry *p; 6043630506bSToomas Soome #endif 6053630506bSToomas Soome uint32_t x, sy, dy; 6063630506bSToomas Soome uint32_t bpp, pitch, copybytes; 6073630506bSToomas Soome off_t off; 6081caed70cSToomas Soome uint8_t *source, *destination; 6093630506bSToomas Soome uint8_t rm, rp, gm, gp, bm, bp; 6103630506bSToomas Soome bool bgra; 6113630506bSToomas Soome 6123630506bSToomas Soome if (BltBuffer == NULL) 6133630506bSToomas Soome return (EINVAL); 6143630506bSToomas Soome 6153630506bSToomas Soome if (DestinationY + Height > 6163630506bSToomas Soome gfx_state.tg_fb.fb_height) 6173630506bSToomas Soome return (EINVAL); 6183630506bSToomas Soome 6193630506bSToomas Soome if (DestinationX + Width > gfx_state.tg_fb.fb_width) 6203630506bSToomas Soome return (EINVAL); 6213630506bSToomas Soome 6223630506bSToomas Soome if (Width == 0 || Height == 0) 6233630506bSToomas Soome return (EINVAL); 6243630506bSToomas Soome 6253630506bSToomas Soome if (Delta == 0) 6263630506bSToomas Soome Delta = Width * sizeof (*p); 6273630506bSToomas Soome 6283630506bSToomas Soome bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3; 6293630506bSToomas Soome pitch = gfx_state.tg_fb.fb_stride * bpp; 6303630506bSToomas Soome 6313630506bSToomas Soome copybytes = Width * bpp; 6323630506bSToomas Soome 6333630506bSToomas Soome rp = ffs(gfx_state.tg_fb.fb_mask_red) - 1; 6343630506bSToomas Soome gp = ffs(gfx_state.tg_fb.fb_mask_green) - 1; 6353630506bSToomas Soome bp = ffs(gfx_state.tg_fb.fb_mask_blue) - 1; 6363630506bSToomas Soome rm = gfx_state.tg_fb.fb_mask_red >> rp; 6373630506bSToomas Soome gm = gfx_state.tg_fb.fb_mask_green >> gp; 6383630506bSToomas Soome bm = gfx_state.tg_fb.fb_mask_blue >> bp; 6393630506bSToomas Soome 6403630506bSToomas Soome /* If FB pixel format is BGRA, we can use direct copy. */ 6413630506bSToomas Soome bgra = bpp == 4 && 6423630506bSToomas Soome ffs(rm) - 1 == 8 && rp == 16 && 6433630506bSToomas Soome ffs(gm) - 1 == 8 && gp == 8 && 6443630506bSToomas Soome ffs(bm) - 1 == 8 && bp == 0; 6453630506bSToomas Soome 6463630506bSToomas Soome for (sy = SourceY, dy = DestinationY; sy < Height + SourceY; 6473630506bSToomas Soome sy++, dy++) { 6483630506bSToomas Soome off = dy * pitch + DestinationX * bpp; 6493630506bSToomas Soome destination = gfx_get_fb_address() + off; 6503630506bSToomas Soome 6513630506bSToomas Soome if (bgra) { 6523630506bSToomas Soome source = (uint8_t *)BltBuffer + sy * Delta + 6533630506bSToomas Soome SourceX * sizeof (*p); 6541caed70cSToomas Soome bcopy(source, destination, copybytes); 6553630506bSToomas Soome } else { 6563630506bSToomas Soome for (x = 0; x < Width; x++) { 6573630506bSToomas Soome uint32_t c; 6583630506bSToomas Soome 6593630506bSToomas Soome p = (void *)((uint8_t *)BltBuffer + 6603630506bSToomas Soome sy * Delta + 6613630506bSToomas Soome (SourceX + x) * sizeof (*p)); 6623630506bSToomas Soome if (bpp == 1) { 6633630506bSToomas Soome c = rgb_to_color_index(p->Red, 6643630506bSToomas Soome p->Green, p->Blue); 6653630506bSToomas Soome } else { 6663630506bSToomas Soome c = (p->Red & rm) << rp | 6673630506bSToomas Soome (p->Green & gm) << gp | 6683630506bSToomas Soome (p->Blue & bm) << bp; 6693630506bSToomas Soome } 6703630506bSToomas Soome off = x * bpp; 6713630506bSToomas Soome switch (bpp) { 6723630506bSToomas Soome case 1: 6731caed70cSToomas Soome gfx_mem_wr1(destination, copybytes, 6743630506bSToomas Soome off, (c < 16) ? 6753630506bSToomas Soome cons_to_vga_colors[c] : c); 6763630506bSToomas Soome break; 6773630506bSToomas Soome case 2: 6781caed70cSToomas Soome gfx_mem_wr2(destination, copybytes, 6793630506bSToomas Soome off, c); 6803630506bSToomas Soome break; 6813630506bSToomas Soome case 3: 6821caed70cSToomas Soome gfx_mem_wr1(destination, copybytes, 6833630506bSToomas Soome off, (c >> 16) & 0xff); 6841caed70cSToomas Soome gfx_mem_wr1(destination, copybytes, 6853630506bSToomas Soome off + 1, (c >> 8) & 0xff); 6861caed70cSToomas Soome gfx_mem_wr1(destination, copybytes, 6873630506bSToomas Soome off + 2, c & 0xff); 6883630506bSToomas Soome break; 6893630506bSToomas Soome case 4: 6901caed70cSToomas Soome gfx_mem_wr4(destination, copybytes, 6913630506bSToomas Soome x * bpp, c); 6923630506bSToomas Soome break; 6931caed70cSToomas Soome default: 6941caed70cSToomas Soome return (EINVAL); 6953630506bSToomas Soome } 6963630506bSToomas Soome } 6971caed70cSToomas Soome } 6983630506bSToomas Soome } 6993630506bSToomas Soome 7003630506bSToomas Soome return (0); 7013630506bSToomas Soome } 7023630506bSToomas Soome 7033630506bSToomas Soome static int 7043630506bSToomas Soome gfxfb_blt_video_to_video(uint32_t SourceX, uint32_t SourceY, 7053630506bSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 7063630506bSToomas Soome uint32_t Width, uint32_t Height) 7073630506bSToomas Soome { 7083630506bSToomas Soome uint32_t bpp, copybytes; 7093630506bSToomas Soome int pitch; 7103630506bSToomas Soome uint8_t *source, *destination; 7113630506bSToomas Soome off_t off; 7123630506bSToomas Soome 7133630506bSToomas Soome if (SourceY + Height > 7143630506bSToomas Soome gfx_state.tg_fb.fb_height) 7153630506bSToomas Soome return (EINVAL); 7163630506bSToomas Soome 7173630506bSToomas Soome if (SourceX + Width > gfx_state.tg_fb.fb_width) 7183630506bSToomas Soome return (EINVAL); 7193630506bSToomas Soome 7203630506bSToomas Soome if (DestinationY + Height > 7213630506bSToomas Soome gfx_state.tg_fb.fb_height) 7223630506bSToomas Soome return (EINVAL); 7233630506bSToomas Soome 7243630506bSToomas Soome if (DestinationX + Width > gfx_state.tg_fb.fb_width) 7253630506bSToomas Soome return (EINVAL); 7263630506bSToomas Soome 7273630506bSToomas Soome if (Width == 0 || Height == 0) 7283630506bSToomas Soome return (EINVAL); 7293630506bSToomas Soome 7303630506bSToomas Soome bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3; 7313630506bSToomas Soome pitch = gfx_state.tg_fb.fb_stride * bpp; 7323630506bSToomas Soome 7333630506bSToomas Soome copybytes = Width * bpp; 7343630506bSToomas Soome 7353630506bSToomas Soome off = SourceY * pitch + SourceX * bpp; 7363630506bSToomas Soome source = gfx_get_fb_address() + off; 7373630506bSToomas Soome off = DestinationY * pitch + DestinationX * bpp; 7383630506bSToomas Soome destination = gfx_get_fb_address() + off; 7393630506bSToomas Soome 7403630506bSToomas Soome if ((uintptr_t)destination > (uintptr_t)source) { 7413630506bSToomas Soome source += Height * pitch; 7423630506bSToomas Soome destination += Height * pitch; 7433630506bSToomas Soome pitch = -pitch; 7443630506bSToomas Soome } 7453630506bSToomas Soome 7463630506bSToomas Soome while (Height-- > 0) { 7473630506bSToomas Soome bcopy(source, destination, copybytes); 7483630506bSToomas Soome source += pitch; 7493630506bSToomas Soome destination += pitch; 7503630506bSToomas Soome } 7513630506bSToomas Soome 7523630506bSToomas Soome return (0); 7533630506bSToomas Soome } 7543630506bSToomas Soome 7556102f43cSToomas Soome static void 7566102f43cSToomas Soome gfxfb_shadow_fill(uint32_t *BltBuffer, 7576102f43cSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 7586102f43cSToomas Soome uint32_t Width, uint32_t Height) 7596102f43cSToomas Soome { 7606102f43cSToomas Soome uint32_t fbX, fbY; 7616102f43cSToomas Soome 7626102f43cSToomas Soome if (gfx_state.tg_shadow_fb == NULL) 7636102f43cSToomas Soome return; 7646102f43cSToomas Soome 7656102f43cSToomas Soome fbX = gfx_state.tg_fb.fb_width; 7666102f43cSToomas Soome fbY = gfx_state.tg_fb.fb_height; 7676102f43cSToomas Soome 7686102f43cSToomas Soome if (BltBuffer == NULL) 7696102f43cSToomas Soome return; 7706102f43cSToomas Soome 7716102f43cSToomas Soome if (DestinationX + Width > fbX) 7726102f43cSToomas Soome Width = fbX - DestinationX; 7736102f43cSToomas Soome 7746102f43cSToomas Soome if (DestinationY + Height > fbY) 7756102f43cSToomas Soome Height = fbY - DestinationY; 7766102f43cSToomas Soome 7776102f43cSToomas Soome uint32_t y2 = Height + DestinationY; 7786102f43cSToomas Soome for (uint32_t y1 = DestinationY; y1 < y2; y1++) { 7796102f43cSToomas Soome uint32_t off = y1 * fbX + DestinationX; 7806102f43cSToomas Soome 7816102f43cSToomas Soome for (uint32_t x = 0; x < Width; x++) { 7826102f43cSToomas Soome gfx_state.tg_shadow_fb[off + x] = *BltBuffer; 7836102f43cSToomas Soome } 7846102f43cSToomas Soome } 7856102f43cSToomas Soome } 7866102f43cSToomas Soome 7873630506bSToomas Soome int 7883630506bSToomas Soome gfxfb_blt(void *BltBuffer, GFXFB_BLT_OPERATION BltOperation, 7893630506bSToomas Soome uint32_t SourceX, uint32_t SourceY, 7903630506bSToomas Soome uint32_t DestinationX, uint32_t DestinationY, 7913630506bSToomas Soome uint32_t Width, uint32_t Height, uint32_t Delta) 7923630506bSToomas Soome { 7933630506bSToomas Soome int rv; 7943630506bSToomas Soome #if defined(EFI) 7953630506bSToomas Soome EFI_STATUS status; 7963630506bSToomas Soome EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private; 7974c7a3a70SToomas Soome EFI_TPL tpl; 7983630506bSToomas Soome 7993ddf7eadSToomas Soome /* 800305ef653SWarner Losh * We assume Blt() does work, if not, we will need to build exception 801305ef653SWarner Losh * list case by case. We only have boot services during part of our 802305ef653SWarner Losh * exectution. Once terminate boot services, these operations cannot be 803305ef653SWarner Losh * done as they are provided by protocols that disappear when exit 804305ef653SWarner Losh * boot services. 8053ddf7eadSToomas Soome */ 806*21b5b8b3SToomas Soome if (!ignore_gop_blt && gop != NULL && boot_services_active) { 8074c7a3a70SToomas Soome tpl = BS->RaiseTPL(TPL_NOTIFY); 8083630506bSToomas Soome switch (BltOperation) { 8093630506bSToomas Soome case GfxFbBltVideoFill: 8106102f43cSToomas Soome gfxfb_shadow_fill(BltBuffer, DestinationX, 8116102f43cSToomas Soome DestinationY, Width, Height); 8123630506bSToomas Soome status = gop->Blt(gop, BltBuffer, EfiBltVideoFill, 8133630506bSToomas Soome SourceX, SourceY, DestinationX, DestinationY, 8143630506bSToomas Soome Width, Height, Delta); 8153630506bSToomas Soome break; 8163630506bSToomas Soome 8173630506bSToomas Soome case GfxFbBltVideoToBltBuffer: 8183630506bSToomas Soome status = gop->Blt(gop, BltBuffer, 8193630506bSToomas Soome EfiBltVideoToBltBuffer, 8203630506bSToomas Soome SourceX, SourceY, DestinationX, DestinationY, 8213630506bSToomas Soome Width, Height, Delta); 8223630506bSToomas Soome break; 8233630506bSToomas Soome 8243630506bSToomas Soome case GfxFbBltBufferToVideo: 8253630506bSToomas Soome status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo, 8263630506bSToomas Soome SourceX, SourceY, DestinationX, DestinationY, 8273630506bSToomas Soome Width, Height, Delta); 8283630506bSToomas Soome break; 8293630506bSToomas Soome 8303630506bSToomas Soome case GfxFbBltVideoToVideo: 8313630506bSToomas Soome status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo, 8323630506bSToomas Soome SourceX, SourceY, DestinationX, DestinationY, 8333630506bSToomas Soome Width, Height, Delta); 8343630506bSToomas Soome break; 8353630506bSToomas Soome 8363630506bSToomas Soome default: 8373630506bSToomas Soome status = EFI_INVALID_PARAMETER; 8383630506bSToomas Soome break; 8393630506bSToomas Soome } 8403630506bSToomas Soome 8413630506bSToomas Soome switch (status) { 8423630506bSToomas Soome case EFI_SUCCESS: 8433630506bSToomas Soome rv = 0; 8443630506bSToomas Soome break; 8453630506bSToomas Soome 8463630506bSToomas Soome case EFI_INVALID_PARAMETER: 8473630506bSToomas Soome rv = EINVAL; 8483630506bSToomas Soome break; 8493630506bSToomas Soome 8503630506bSToomas Soome case EFI_DEVICE_ERROR: 8513630506bSToomas Soome default: 8523630506bSToomas Soome rv = EIO; 8533630506bSToomas Soome break; 8543630506bSToomas Soome } 8553630506bSToomas Soome 8564c7a3a70SToomas Soome BS->RestoreTPL(tpl); 8573630506bSToomas Soome return (rv); 8583630506bSToomas Soome } 8593630506bSToomas Soome #endif 8603630506bSToomas Soome 8613630506bSToomas Soome switch (BltOperation) { 8623630506bSToomas Soome case GfxFbBltVideoFill: 8636102f43cSToomas Soome gfxfb_shadow_fill(BltBuffer, DestinationX, DestinationY, 8646102f43cSToomas Soome Width, Height); 8653630506bSToomas Soome rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY, 8663630506bSToomas Soome Width, Height); 8673630506bSToomas Soome break; 8683630506bSToomas Soome 8693630506bSToomas Soome case GfxFbBltVideoToBltBuffer: 8703630506bSToomas Soome rv = gfxfb_blt_video_to_buffer(BltBuffer, SourceX, SourceY, 8713630506bSToomas Soome DestinationX, DestinationY, Width, Height, Delta); 8723630506bSToomas Soome break; 8733630506bSToomas Soome 8743630506bSToomas Soome case GfxFbBltBufferToVideo: 8753630506bSToomas Soome rv = gfxfb_blt_buffer_to_video(BltBuffer, SourceX, SourceY, 8763630506bSToomas Soome DestinationX, DestinationY, Width, Height, Delta); 8773630506bSToomas Soome break; 8783630506bSToomas Soome 8793630506bSToomas Soome case GfxFbBltVideoToVideo: 8803630506bSToomas Soome rv = gfxfb_blt_video_to_video(SourceX, SourceY, 8813630506bSToomas Soome DestinationX, DestinationY, Width, Height); 8823630506bSToomas Soome break; 8833630506bSToomas Soome 8843630506bSToomas Soome default: 8853630506bSToomas Soome rv = EINVAL; 8863630506bSToomas Soome break; 8873630506bSToomas Soome } 8883630506bSToomas Soome return (rv); 8893630506bSToomas Soome } 8903630506bSToomas Soome 8913630506bSToomas Soome void 8923630506bSToomas Soome gfx_bitblt_bitmap(teken_gfx_t *state, const uint8_t *glyph, 8933630506bSToomas Soome const teken_attr_t *a, uint32_t alpha, bool cursor) 8943630506bSToomas Soome { 8953630506bSToomas Soome uint32_t width, height; 8963630506bSToomas Soome uint32_t fgc, bgc, bpl, cc, o; 8973630506bSToomas Soome int bpp, bit, byte; 8983630506bSToomas Soome bool invert = false; 8993630506bSToomas Soome 9003630506bSToomas Soome bpp = 4; /* We only generate BGRA */ 9013630506bSToomas Soome width = state->tg_font.vf_width; 9023630506bSToomas Soome height = state->tg_font.vf_height; 9033630506bSToomas Soome bpl = (width + 7) / 8; /* Bytes per source line. */ 9043630506bSToomas Soome 9053630506bSToomas Soome fgc = a->ta_fgcolor; 9063630506bSToomas Soome bgc = a->ta_bgcolor; 9073630506bSToomas Soome if (a->ta_format & TF_BOLD) 9083630506bSToomas Soome fgc |= TC_LIGHT; 9093630506bSToomas Soome if (a->ta_format & TF_BLINK) 9103630506bSToomas Soome bgc |= TC_LIGHT; 9113630506bSToomas Soome 9123630506bSToomas Soome fgc = gfx_fb_color_map(fgc); 9133630506bSToomas Soome bgc = gfx_fb_color_map(bgc); 9143630506bSToomas Soome 9153630506bSToomas Soome if (a->ta_format & TF_REVERSE) 9163630506bSToomas Soome invert = !invert; 9173630506bSToomas Soome if (cursor) 9183630506bSToomas Soome invert = !invert; 9193630506bSToomas Soome if (invert) { 9203630506bSToomas Soome uint32_t tmp; 9213630506bSToomas Soome 9223630506bSToomas Soome tmp = fgc; 9233630506bSToomas Soome fgc = bgc; 9243630506bSToomas Soome bgc = tmp; 9253630506bSToomas Soome } 9263630506bSToomas Soome 9273630506bSToomas Soome alpha = alpha << 24; 9283630506bSToomas Soome fgc |= alpha; 9293630506bSToomas Soome bgc |= alpha; 9303630506bSToomas Soome 9313630506bSToomas Soome for (uint32_t y = 0; y < height; y++) { 9323630506bSToomas Soome for (uint32_t x = 0; x < width; x++) { 9333630506bSToomas Soome byte = y * bpl + x / 8; 9343630506bSToomas Soome bit = 0x80 >> (x % 8); 9353630506bSToomas Soome o = y * width * bpp + x * bpp; 9363630506bSToomas Soome cc = glyph[byte] & bit ? fgc : bgc; 9373630506bSToomas Soome 9383630506bSToomas Soome gfx_mem_wr4(state->tg_glyph, 9393630506bSToomas Soome state->tg_glyph_size, o, cc); 9403630506bSToomas Soome } 9413630506bSToomas Soome } 9423630506bSToomas Soome } 9433630506bSToomas Soome 9443630506bSToomas Soome /* 9453630506bSToomas Soome * Draw prepared glyph on terminal point p. 9463630506bSToomas Soome */ 9473630506bSToomas Soome static void 9483630506bSToomas Soome gfx_fb_printchar(teken_gfx_t *state, const teken_pos_t *p) 9493630506bSToomas Soome { 9503630506bSToomas Soome unsigned x, y, width, height; 9513630506bSToomas Soome 9523630506bSToomas Soome width = state->tg_font.vf_width; 9533630506bSToomas Soome height = state->tg_font.vf_height; 9543630506bSToomas Soome x = state->tg_origin.tp_col + p->tp_col * width; 9553630506bSToomas Soome y = state->tg_origin.tp_row + p->tp_row * height; 9563630506bSToomas Soome 9573630506bSToomas Soome gfx_fb_cons_display(x, y, width, height, state->tg_glyph); 9583630506bSToomas Soome } 9593630506bSToomas Soome 9603630506bSToomas Soome /* 9613630506bSToomas Soome * Store char with its attribute to buffer and put it on screen. 9623630506bSToomas Soome */ 9633630506bSToomas Soome void 9643630506bSToomas Soome gfx_fb_putchar(void *arg, const teken_pos_t *p, teken_char_t c, 9653630506bSToomas Soome const teken_attr_t *a) 9663630506bSToomas Soome { 9673630506bSToomas Soome teken_gfx_t *state = arg; 9683630506bSToomas Soome const uint8_t *glyph; 9693630506bSToomas Soome int idx; 9703630506bSToomas Soome 9713630506bSToomas Soome idx = p->tp_col + p->tp_row * state->tg_tp.tp_col; 9723630506bSToomas Soome if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) 9733630506bSToomas Soome return; 9743630506bSToomas Soome 9753630506bSToomas Soome /* remove the cursor */ 9763630506bSToomas Soome if (state->tg_cursor_visible) 9773630506bSToomas Soome gfx_fb_cursor_draw(state, &state->tg_cursor, false); 9783630506bSToomas Soome 9793630506bSToomas Soome screen_buffer[idx].c = c; 9803630506bSToomas Soome screen_buffer[idx].a = *a; 9813630506bSToomas Soome 9823630506bSToomas Soome glyph = font_lookup(&state->tg_font, c, a); 9833630506bSToomas Soome gfx_bitblt_bitmap(state, glyph, a, 0xff, false); 9843630506bSToomas Soome gfx_fb_printchar(state, p); 9853630506bSToomas Soome 9863630506bSToomas Soome /* display the cursor */ 9873630506bSToomas Soome if (state->tg_cursor_visible) { 9883630506bSToomas Soome const teken_pos_t *c; 9893630506bSToomas Soome 9903630506bSToomas Soome c = teken_get_cursor(&state->tg_teken); 9913630506bSToomas Soome gfx_fb_cursor_draw(state, c, true); 9923630506bSToomas Soome } 9933630506bSToomas Soome } 9943630506bSToomas Soome 9953630506bSToomas Soome void 9963630506bSToomas Soome gfx_fb_fill(void *arg, const teken_rect_t *r, teken_char_t c, 9973630506bSToomas Soome const teken_attr_t *a) 9983630506bSToomas Soome { 9993630506bSToomas Soome teken_gfx_t *state = arg; 10003630506bSToomas Soome const uint8_t *glyph; 10013630506bSToomas Soome teken_pos_t p; 10023630506bSToomas Soome struct text_pixel *row; 10033630506bSToomas Soome 10043630506bSToomas Soome /* remove the cursor */ 10053630506bSToomas Soome if (state->tg_cursor_visible) 10063630506bSToomas Soome gfx_fb_cursor_draw(state, &state->tg_cursor, false); 10073630506bSToomas Soome 10083630506bSToomas Soome glyph = font_lookup(&state->tg_font, c, a); 10093630506bSToomas Soome gfx_bitblt_bitmap(state, glyph, a, 0xff, false); 10103630506bSToomas Soome 10113630506bSToomas Soome for (p.tp_row = r->tr_begin.tp_row; p.tp_row < r->tr_end.tp_row; 10123630506bSToomas Soome p.tp_row++) { 10133630506bSToomas Soome row = &screen_buffer[p.tp_row * state->tg_tp.tp_col]; 10143630506bSToomas Soome for (p.tp_col = r->tr_begin.tp_col; 10153630506bSToomas Soome p.tp_col < r->tr_end.tp_col; p.tp_col++) { 10163630506bSToomas Soome row[p.tp_col].c = c; 10173630506bSToomas Soome row[p.tp_col].a = *a; 10183630506bSToomas Soome gfx_fb_printchar(state, &p); 10193630506bSToomas Soome } 10203630506bSToomas Soome } 10213630506bSToomas Soome 10223630506bSToomas Soome /* display the cursor */ 10233630506bSToomas Soome if (state->tg_cursor_visible) { 10243630506bSToomas Soome const teken_pos_t *c; 10253630506bSToomas Soome 10263630506bSToomas Soome c = teken_get_cursor(&state->tg_teken); 10273630506bSToomas Soome gfx_fb_cursor_draw(state, c, true); 10283630506bSToomas Soome } 10293630506bSToomas Soome } 10303630506bSToomas Soome 10313630506bSToomas Soome static void 1032e5a50b03SToomas Soome gfx_fb_cursor_draw(teken_gfx_t *state, const teken_pos_t *pos, bool on) 10333630506bSToomas Soome { 10343630506bSToomas Soome const uint8_t *glyph; 1035e5a50b03SToomas Soome teken_pos_t p; 10363630506bSToomas Soome int idx; 10373630506bSToomas Soome 1038e5a50b03SToomas Soome p = *pos; 1039e5a50b03SToomas Soome if (p.tp_col >= state->tg_tp.tp_col) 1040e5a50b03SToomas Soome p.tp_col = state->tg_tp.tp_col - 1; 1041e5a50b03SToomas Soome if (p.tp_row >= state->tg_tp.tp_row) 1042e5a50b03SToomas Soome p.tp_row = state->tg_tp.tp_row - 1; 1043e5a50b03SToomas Soome idx = p.tp_col + p.tp_row * state->tg_tp.tp_col; 10443630506bSToomas Soome if (idx >= state->tg_tp.tp_col * state->tg_tp.tp_row) 10453630506bSToomas Soome return; 10463630506bSToomas Soome 10473630506bSToomas Soome glyph = font_lookup(&state->tg_font, screen_buffer[idx].c, 10483630506bSToomas Soome &screen_buffer[idx].a); 10493630506bSToomas Soome gfx_bitblt_bitmap(state, glyph, &screen_buffer[idx].a, 0xff, on); 1050e5a50b03SToomas Soome gfx_fb_printchar(state, &p); 1051d708f23eSToomas Soome 1052e5a50b03SToomas Soome state->tg_cursor = p; 10533630506bSToomas Soome } 10543630506bSToomas Soome 10553630506bSToomas Soome void 10563630506bSToomas Soome gfx_fb_cursor(void *arg, const teken_pos_t *p) 10573630506bSToomas Soome { 10583630506bSToomas Soome teken_gfx_t *state = arg; 10593630506bSToomas Soome 10603630506bSToomas Soome /* Switch cursor off in old location and back on in new. */ 10613630506bSToomas Soome if (state->tg_cursor_visible) { 10623630506bSToomas Soome gfx_fb_cursor_draw(state, &state->tg_cursor, false); 10633630506bSToomas Soome gfx_fb_cursor_draw(state, p, true); 10643630506bSToomas Soome } 10653630506bSToomas Soome } 10663630506bSToomas Soome 10673630506bSToomas Soome void 10683630506bSToomas Soome gfx_fb_param(void *arg, int cmd, unsigned int value) 10693630506bSToomas Soome { 10703630506bSToomas Soome teken_gfx_t *state = arg; 10713630506bSToomas Soome const teken_pos_t *c; 10723630506bSToomas Soome 10733630506bSToomas Soome switch (cmd) { 10743630506bSToomas Soome case TP_SETLOCALCURSOR: 10753630506bSToomas Soome /* 10763630506bSToomas Soome * 0 means normal (usually block), 1 means hidden, and 10773630506bSToomas Soome * 2 means blinking (always block) for compatibility with 10783630506bSToomas Soome * syscons. We don't support any changes except hiding, 10793630506bSToomas Soome * so must map 2 to 0. 10803630506bSToomas Soome */ 10813630506bSToomas Soome value = (value == 1) ? 0 : 1; 10823630506bSToomas Soome /* FALLTHROUGH */ 10833630506bSToomas Soome case TP_SHOWCURSOR: 10843630506bSToomas Soome c = teken_get_cursor(&state->tg_teken); 10853630506bSToomas Soome gfx_fb_cursor_draw(state, c, true); 10863630506bSToomas Soome if (value != 0) 10873630506bSToomas Soome state->tg_cursor_visible = true; 10883630506bSToomas Soome else 10893630506bSToomas Soome state->tg_cursor_visible = false; 10903630506bSToomas Soome break; 10913630506bSToomas Soome default: 10923630506bSToomas Soome /* Not yet implemented */ 10933630506bSToomas Soome break; 10943630506bSToomas Soome } 10953630506bSToomas Soome } 10963630506bSToomas Soome 10973630506bSToomas Soome bool 10983630506bSToomas Soome is_same_pixel(struct text_pixel *px1, struct text_pixel *px2) 10993630506bSToomas Soome { 11003630506bSToomas Soome if (px1->c != px2->c) 11013630506bSToomas Soome return (false); 11023630506bSToomas Soome 11033630506bSToomas Soome /* Is there image stored? */ 11043630506bSToomas Soome if ((px1->a.ta_format & TF_IMAGE) || 11053630506bSToomas Soome (px2->a.ta_format & TF_IMAGE)) 11063630506bSToomas Soome return (false); 11073630506bSToomas Soome 11083630506bSToomas Soome if (px1->a.ta_format != px2->a.ta_format) 11093630506bSToomas Soome return (false); 11103630506bSToomas Soome if (px1->a.ta_fgcolor != px2->a.ta_fgcolor) 11113630506bSToomas Soome return (false); 11123630506bSToomas Soome if (px1->a.ta_bgcolor != px2->a.ta_bgcolor) 11133630506bSToomas Soome return (false); 11143630506bSToomas Soome 11153630506bSToomas Soome return (true); 11163630506bSToomas Soome } 11173630506bSToomas Soome 11183630506bSToomas Soome static void 11193630506bSToomas Soome gfx_fb_copy_area(teken_gfx_t *state, const teken_rect_t *s, 11203630506bSToomas Soome const teken_pos_t *d) 11213630506bSToomas Soome { 11223630506bSToomas Soome uint32_t sx, sy, dx, dy, width, height; 11236102f43cSToomas Soome uint32_t pitch, bytes; 11246102f43cSToomas Soome int step; 11253630506bSToomas Soome 11263630506bSToomas Soome width = state->tg_font.vf_width; 11273630506bSToomas Soome height = state->tg_font.vf_height; 11283630506bSToomas Soome 11296102f43cSToomas Soome sx = s->tr_begin.tp_col * width; 11306102f43cSToomas Soome sy = s->tr_begin.tp_row * height; 11316102f43cSToomas Soome dx = d->tp_col * width; 11326102f43cSToomas Soome dy = d->tp_row * height; 11333630506bSToomas Soome 11343630506bSToomas Soome width *= (s->tr_end.tp_col - s->tr_begin.tp_col + 1); 11353630506bSToomas Soome 11366102f43cSToomas Soome /* 11376102f43cSToomas Soome * With no shadow fb, use video to video copy. 11386102f43cSToomas Soome */ 11396102f43cSToomas Soome if (state->tg_shadow_fb == NULL) { 11406102f43cSToomas Soome (void) gfxfb_blt(NULL, GfxFbBltVideoToVideo, 11416102f43cSToomas Soome sx + state->tg_origin.tp_col, 11426102f43cSToomas Soome sy + state->tg_origin.tp_row, 11436102f43cSToomas Soome dx + state->tg_origin.tp_col, 11446102f43cSToomas Soome dy + state->tg_origin.tp_row, 11453630506bSToomas Soome width, height, 0); 11466102f43cSToomas Soome return; 11476102f43cSToomas Soome } 11486102f43cSToomas Soome 11496102f43cSToomas Soome /* 11506102f43cSToomas Soome * With shadow fb, we need to copy data on both shadow and video, 11516102f43cSToomas Soome * to preserve the consistency. We only read data from shadow fb. 11526102f43cSToomas Soome */ 11536102f43cSToomas Soome 11546102f43cSToomas Soome step = 1; 11556102f43cSToomas Soome pitch = state->tg_fb.fb_width; 11566102f43cSToomas Soome bytes = width * sizeof (*state->tg_shadow_fb); 11576102f43cSToomas Soome 11586102f43cSToomas Soome /* 11596102f43cSToomas Soome * To handle overlapping areas, set up reverse copy here. 11606102f43cSToomas Soome */ 11616102f43cSToomas Soome if (dy * pitch + dx > sy * pitch + sx) { 11626102f43cSToomas Soome sy += height; 11636102f43cSToomas Soome dy += height; 11646102f43cSToomas Soome step = -step; 11656102f43cSToomas Soome } 11666102f43cSToomas Soome 11676102f43cSToomas Soome while (height-- > 0) { 11686102f43cSToomas Soome uint32_t *source = &state->tg_shadow_fb[sy * pitch + sx]; 11696102f43cSToomas Soome uint32_t *destination = &state->tg_shadow_fb[dy * pitch + dx]; 11706102f43cSToomas Soome 11716102f43cSToomas Soome bcopy(source, destination, bytes); 11726102f43cSToomas Soome (void) gfxfb_blt(destination, GfxFbBltBufferToVideo, 11736102f43cSToomas Soome 0, 0, dx + state->tg_origin.tp_col, 11746102f43cSToomas Soome dy + state->tg_origin.tp_row, width, 1, 0); 11756102f43cSToomas Soome 11766102f43cSToomas Soome sy += step; 11776102f43cSToomas Soome dy += step; 11786102f43cSToomas Soome } 11793630506bSToomas Soome } 11803630506bSToomas Soome 11813630506bSToomas Soome static void 11823630506bSToomas Soome gfx_fb_copy_line(teken_gfx_t *state, int ncol, teken_pos_t *s, teken_pos_t *d) 11833630506bSToomas Soome { 11843630506bSToomas Soome teken_rect_t sr; 11853630506bSToomas Soome teken_pos_t dp; 11863630506bSToomas Soome unsigned soffset, doffset; 11873630506bSToomas Soome bool mark = false; 11883630506bSToomas Soome int x; 11893630506bSToomas Soome 11903630506bSToomas Soome soffset = s->tp_col + s->tp_row * state->tg_tp.tp_col; 11913630506bSToomas Soome doffset = d->tp_col + d->tp_row * state->tg_tp.tp_col; 11923630506bSToomas Soome 11933630506bSToomas Soome for (x = 0; x < ncol; x++) { 11943630506bSToomas Soome if (is_same_pixel(&screen_buffer[soffset + x], 11953630506bSToomas Soome &screen_buffer[doffset + x])) { 11963630506bSToomas Soome if (mark) { 11973630506bSToomas Soome gfx_fb_copy_area(state, &sr, &dp); 11983630506bSToomas Soome mark = false; 11993630506bSToomas Soome } 12003630506bSToomas Soome } else { 12013630506bSToomas Soome screen_buffer[doffset + x] = screen_buffer[soffset + x]; 12023630506bSToomas Soome if (mark) { 12033630506bSToomas Soome /* update end point */ 1204798ea06fSElliott Mitchell sr.tr_end.tp_col = s->tp_col + x; 12053630506bSToomas Soome } else { 12063630506bSToomas Soome /* set up new rectangle */ 12073630506bSToomas Soome mark = true; 12083630506bSToomas Soome sr.tr_begin.tp_col = s->tp_col + x; 12093630506bSToomas Soome sr.tr_begin.tp_row = s->tp_row; 12103630506bSToomas Soome sr.tr_end.tp_col = s->tp_col + x; 12113630506bSToomas Soome sr.tr_end.tp_row = s->tp_row; 12123630506bSToomas Soome dp.tp_col = d->tp_col + x; 12133630506bSToomas Soome dp.tp_row = d->tp_row; 12143630506bSToomas Soome } 12153630506bSToomas Soome } 12163630506bSToomas Soome } 12173630506bSToomas Soome if (mark) { 12183630506bSToomas Soome gfx_fb_copy_area(state, &sr, &dp); 12193630506bSToomas Soome } 12203630506bSToomas Soome } 12213630506bSToomas Soome 12223630506bSToomas Soome void 12233630506bSToomas Soome gfx_fb_copy(void *arg, const teken_rect_t *r, const teken_pos_t *p) 12243630506bSToomas Soome { 12253630506bSToomas Soome teken_gfx_t *state = arg; 12263630506bSToomas Soome unsigned doffset, soffset; 12273630506bSToomas Soome teken_pos_t d, s; 12283630506bSToomas Soome int nrow, ncol, y; /* Has to be signed - >= 0 comparison */ 12293630506bSToomas Soome 12303630506bSToomas Soome /* 12313630506bSToomas Soome * Copying is a little tricky. We must make sure we do it in 12323630506bSToomas Soome * correct order, to make sure we don't overwrite our own data. 12333630506bSToomas Soome */ 12343630506bSToomas Soome 12353630506bSToomas Soome nrow = r->tr_end.tp_row - r->tr_begin.tp_row; 12363630506bSToomas Soome ncol = r->tr_end.tp_col - r->tr_begin.tp_col; 12373630506bSToomas Soome 12383630506bSToomas Soome if (p->tp_row + nrow > state->tg_tp.tp_row || 12393630506bSToomas Soome p->tp_col + ncol > state->tg_tp.tp_col) 12403630506bSToomas Soome return; 12413630506bSToomas Soome 12423630506bSToomas Soome soffset = r->tr_begin.tp_col + r->tr_begin.tp_row * state->tg_tp.tp_col; 12433630506bSToomas Soome doffset = p->tp_col + p->tp_row * state->tg_tp.tp_col; 12443630506bSToomas Soome 12453630506bSToomas Soome /* remove the cursor */ 12463630506bSToomas Soome if (state->tg_cursor_visible) 12473630506bSToomas Soome gfx_fb_cursor_draw(state, &state->tg_cursor, false); 12483630506bSToomas Soome 12493630506bSToomas Soome /* 12503630506bSToomas Soome * Copy line by line. 12513630506bSToomas Soome */ 12523630506bSToomas Soome if (doffset <= soffset) { 12533630506bSToomas Soome s = r->tr_begin; 12543630506bSToomas Soome d = *p; 12553630506bSToomas Soome for (y = 0; y < nrow; y++) { 12563630506bSToomas Soome s.tp_row = r->tr_begin.tp_row + y; 12573630506bSToomas Soome d.tp_row = p->tp_row + y; 12583630506bSToomas Soome 12593630506bSToomas Soome gfx_fb_copy_line(state, ncol, &s, &d); 12603630506bSToomas Soome } 12613630506bSToomas Soome } else { 12623630506bSToomas Soome for (y = nrow - 1; y >= 0; y--) { 12633630506bSToomas Soome s.tp_row = r->tr_begin.tp_row + y; 12643630506bSToomas Soome d.tp_row = p->tp_row + y; 12653630506bSToomas Soome 12663630506bSToomas Soome gfx_fb_copy_line(state, ncol, &s, &d); 12673630506bSToomas Soome } 12683630506bSToomas Soome } 12693630506bSToomas Soome 12703630506bSToomas Soome /* display the cursor */ 12713630506bSToomas Soome if (state->tg_cursor_visible) { 12723630506bSToomas Soome const teken_pos_t *c; 12733630506bSToomas Soome 12743630506bSToomas Soome c = teken_get_cursor(&state->tg_teken); 12753630506bSToomas Soome gfx_fb_cursor_draw(state, c, true); 12763630506bSToomas Soome } 12773630506bSToomas Soome } 12783630506bSToomas Soome 12793630506bSToomas Soome /* 12803630506bSToomas Soome * Implements alpha blending for RGBA data, could use pixels for arguments, 12813630506bSToomas Soome * but byte stream seems more generic. 12823630506bSToomas Soome * The generic alpha blending is: 12833630506bSToomas Soome * blend = alpha * fg + (1.0 - alpha) * bg. 12843630506bSToomas Soome * Since our alpha is not from range [0..1], we scale appropriately. 12853630506bSToomas Soome */ 12863630506bSToomas Soome static uint8_t 12873630506bSToomas Soome alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) 12883630506bSToomas Soome { 12893630506bSToomas Soome uint16_t blend, h, l; 12903630506bSToomas Soome 12913630506bSToomas Soome /* trivial corner cases */ 12923630506bSToomas Soome if (alpha == 0) 12933630506bSToomas Soome return (bg); 12943630506bSToomas Soome if (alpha == 0xFF) 12953630506bSToomas Soome return (fg); 12963630506bSToomas Soome blend = (alpha * fg + (0xFF - alpha) * bg); 12973630506bSToomas Soome /* Division by 0xFF */ 12983630506bSToomas Soome h = blend >> 8; 12993630506bSToomas Soome l = blend & 0xFF; 13003630506bSToomas Soome if (h + l >= 0xFF) 13013630506bSToomas Soome h++; 13023630506bSToomas Soome return (h); 13033630506bSToomas Soome } 13043630506bSToomas Soome 13053630506bSToomas Soome /* 13063630506bSToomas Soome * Implements alpha blending for RGBA data, could use pixels for arguments, 13073630506bSToomas Soome * but byte stream seems more generic. 13083630506bSToomas Soome * The generic alpha blending is: 13093630506bSToomas Soome * blend = alpha * fg + (1.0 - alpha) * bg. 13103630506bSToomas Soome * Since our alpha is not from range [0..1], we scale appropriately. 13113630506bSToomas Soome */ 13123630506bSToomas Soome static void 13133630506bSToomas Soome bitmap_cpy(void *dst, void *src, uint32_t size) 13143630506bSToomas Soome { 13153630506bSToomas Soome #if defined(EFI) 13163630506bSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ps, *pd; 13173630506bSToomas Soome #else 13183630506bSToomas Soome struct paletteentry *ps, *pd; 13193630506bSToomas Soome #endif 13203630506bSToomas Soome uint32_t i; 13213630506bSToomas Soome uint8_t a; 13223630506bSToomas Soome 13233630506bSToomas Soome ps = src; 13243630506bSToomas Soome pd = dst; 13253630506bSToomas Soome 13263630506bSToomas Soome /* 13273630506bSToomas Soome * we only implement alpha blending for depth 32. 13283630506bSToomas Soome */ 13293630506bSToomas Soome for (i = 0; i < size; i ++) { 13303630506bSToomas Soome a = ps[i].Reserved; 13313630506bSToomas Soome pd[i].Red = alpha_blend(ps[i].Red, pd[i].Red, a); 13323630506bSToomas Soome pd[i].Green = alpha_blend(ps[i].Green, pd[i].Green, a); 13333630506bSToomas Soome pd[i].Blue = alpha_blend(ps[i].Blue, pd[i].Blue, a); 13343630506bSToomas Soome pd[i].Reserved = a; 13353630506bSToomas Soome } 13363630506bSToomas Soome } 13373630506bSToomas Soome 13383630506bSToomas Soome static void * 13393630506bSToomas Soome allocate_glyphbuffer(uint32_t width, uint32_t height) 13403630506bSToomas Soome { 13413630506bSToomas Soome size_t size; 13423630506bSToomas Soome 13433630506bSToomas Soome size = sizeof (*GlyphBuffer) * width * height; 13443630506bSToomas Soome if (size != GlyphBufferSize) { 13453630506bSToomas Soome free(GlyphBuffer); 13463630506bSToomas Soome GlyphBuffer = malloc(size); 13473630506bSToomas Soome if (GlyphBuffer == NULL) 13483630506bSToomas Soome return (NULL); 13493630506bSToomas Soome GlyphBufferSize = size; 13503630506bSToomas Soome } 13513630506bSToomas Soome return (GlyphBuffer); 13523630506bSToomas Soome } 13533630506bSToomas Soome 13543630506bSToomas Soome void 13553630506bSToomas Soome gfx_fb_cons_display(uint32_t x, uint32_t y, uint32_t width, uint32_t height, 13563630506bSToomas Soome void *data) 13573630506bSToomas Soome { 13583630506bSToomas Soome #if defined(EFI) 13596102f43cSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, *p; 13603630506bSToomas Soome #else 13616102f43cSToomas Soome struct paletteentry *buf, *p; 13623630506bSToomas Soome #endif 13633630506bSToomas Soome size_t size; 13643630506bSToomas Soome 13656102f43cSToomas Soome /* 13666102f43cSToomas Soome * If we do have shadow fb, we will use shadow to render data, 13676102f43cSToomas Soome * and copy shadow to video. 13686102f43cSToomas Soome */ 13696102f43cSToomas Soome if (gfx_state.tg_shadow_fb != NULL) { 13706102f43cSToomas Soome uint32_t pitch = gfx_state.tg_fb.fb_width; 13716102f43cSToomas Soome 13726102f43cSToomas Soome /* Copy rectangle line by line. */ 13736102f43cSToomas Soome p = data; 13746102f43cSToomas Soome for (uint32_t sy = 0; sy < height; sy++) { 13756102f43cSToomas Soome buf = (void *)(gfx_state.tg_shadow_fb + 13766102f43cSToomas Soome (y - gfx_state.tg_origin.tp_row) * pitch + 13776102f43cSToomas Soome x - gfx_state.tg_origin.tp_col); 13786102f43cSToomas Soome bitmap_cpy(buf, &p[sy * width], width); 13796102f43cSToomas Soome (void) gfxfb_blt(buf, GfxFbBltBufferToVideo, 13806102f43cSToomas Soome 0, 0, x, y, width, 1, 0); 13816102f43cSToomas Soome y++; 13826102f43cSToomas Soome } 13836102f43cSToomas Soome return; 13846102f43cSToomas Soome } 13853630506bSToomas Soome 13863630506bSToomas Soome /* 13873630506bSToomas Soome * Common data to display is glyph, use preallocated 13883630506bSToomas Soome * glyph buffer. 13893630506bSToomas Soome */ 13903630506bSToomas Soome if (gfx_state.tg_glyph_size != GlyphBufferSize) 13913630506bSToomas Soome (void) allocate_glyphbuffer(width, height); 13923630506bSToomas Soome 13936102f43cSToomas Soome size = width * height * sizeof(*buf); 13943630506bSToomas Soome if (size == GlyphBufferSize) 13953630506bSToomas Soome buf = GlyphBuffer; 13963630506bSToomas Soome else 13973630506bSToomas Soome buf = malloc(size); 13983630506bSToomas Soome if (buf == NULL) 13993630506bSToomas Soome return; 14003630506bSToomas Soome 14013630506bSToomas Soome if (gfxfb_blt(buf, GfxFbBltVideoToBltBuffer, x, y, 0, 0, 14023630506bSToomas Soome width, height, 0) == 0) { 14033630506bSToomas Soome bitmap_cpy(buf, data, width * height); 14043630506bSToomas Soome (void) gfxfb_blt(buf, GfxFbBltBufferToVideo, 0, 0, x, y, 14053630506bSToomas Soome width, height, 0); 14063630506bSToomas Soome } 14073630506bSToomas Soome if (buf != GlyphBuffer) 14083630506bSToomas Soome free(buf); 14093630506bSToomas Soome } 14103630506bSToomas Soome 14113630506bSToomas Soome /* 14123630506bSToomas Soome * Public graphics primitives. 14133630506bSToomas Soome */ 14143630506bSToomas Soome 14153630506bSToomas Soome static int 14163630506bSToomas Soome isqrt(int num) 14173630506bSToomas Soome { 14183630506bSToomas Soome int res = 0; 14193630506bSToomas Soome int bit = 1 << 30; 14203630506bSToomas Soome 14213630506bSToomas Soome /* "bit" starts at the highest power of four <= the argument. */ 14223630506bSToomas Soome while (bit > num) 14233630506bSToomas Soome bit >>= 2; 14243630506bSToomas Soome 14253630506bSToomas Soome while (bit != 0) { 14263630506bSToomas Soome if (num >= res + bit) { 14273630506bSToomas Soome num -= res + bit; 14283630506bSToomas Soome res = (res >> 1) + bit; 14293630506bSToomas Soome } else { 14303630506bSToomas Soome res >>= 1; 14313630506bSToomas Soome } 14323630506bSToomas Soome bit >>= 2; 14333630506bSToomas Soome } 14343630506bSToomas Soome return (res); 14353630506bSToomas Soome } 14363630506bSToomas Soome 14375365af66SToomas Soome static uint32_t 14385365af66SToomas Soome gfx_fb_getcolor(void) 14393630506bSToomas Soome { 14403630506bSToomas Soome uint32_t c; 14413630506bSToomas Soome const teken_attr_t *ap; 14423630506bSToomas Soome 14433630506bSToomas Soome ap = teken_get_curattr(&gfx_state.tg_teken); 14443630506bSToomas Soome if (ap->ta_format & TF_REVERSE) { 14453630506bSToomas Soome c = ap->ta_bgcolor; 14463630506bSToomas Soome if (ap->ta_format & TF_BLINK) 14473630506bSToomas Soome c |= TC_LIGHT; 14483630506bSToomas Soome } else { 14493630506bSToomas Soome c = ap->ta_fgcolor; 14503630506bSToomas Soome if (ap->ta_format & TF_BOLD) 14513630506bSToomas Soome c |= TC_LIGHT; 14523630506bSToomas Soome } 14533630506bSToomas Soome 14545365af66SToomas Soome return (gfx_fb_color_map(c)); 14555365af66SToomas Soome } 14565365af66SToomas Soome 14575365af66SToomas Soome /* set pixel in framebuffer using gfx coordinates */ 14585365af66SToomas Soome void 14595365af66SToomas Soome gfx_fb_setpixel(uint32_t x, uint32_t y) 14605365af66SToomas Soome { 14615365af66SToomas Soome uint32_t c; 14625365af66SToomas Soome 14635365af66SToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 14645365af66SToomas Soome return; 14655365af66SToomas Soome 14665365af66SToomas Soome c = gfx_fb_getcolor(); 14673630506bSToomas Soome 14683630506bSToomas Soome if (x >= gfx_state.tg_fb.fb_width || 14693630506bSToomas Soome y >= gfx_state.tg_fb.fb_height) 14703630506bSToomas Soome return; 14713630506bSToomas Soome 14723630506bSToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x, y, 1, 1, 0); 14733630506bSToomas Soome } 14743630506bSToomas Soome 14753630506bSToomas Soome /* 14763630506bSToomas Soome * draw rectangle in framebuffer using gfx coordinates. 14773630506bSToomas Soome */ 14783630506bSToomas Soome void 14793630506bSToomas Soome gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, 14803630506bSToomas Soome uint32_t fill) 14813630506bSToomas Soome { 14825365af66SToomas Soome uint32_t c; 14833630506bSToomas Soome 14843630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 14853630506bSToomas Soome return; 14863630506bSToomas Soome 14875365af66SToomas Soome c = gfx_fb_getcolor(); 14885365af66SToomas Soome 14895365af66SToomas Soome if (fill != 0) { 14905365af66SToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x1, y1, x2 - x1, 14915365af66SToomas Soome y2 - y1, 0); 14923630506bSToomas Soome } else { 14935365af66SToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x1, y1, x2 - x1, 1, 0); 14945365af66SToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x1, y2, x2 - x1, 1, 0); 14955365af66SToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x1, y1, 1, y2 - y1, 0); 14965365af66SToomas Soome gfxfb_blt(&c, GfxFbBltVideoFill, 0, 0, x2, y1, 1, y2 - y1, 0); 14973630506bSToomas Soome } 14983630506bSToomas Soome } 14993630506bSToomas Soome 15003630506bSToomas Soome void 15013630506bSToomas Soome gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t wd) 15023630506bSToomas Soome { 15033630506bSToomas Soome int dx, sx, dy, sy; 15043630506bSToomas Soome int err, e2, x2, y2, ed, width; 15053630506bSToomas Soome 15063630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 15073630506bSToomas Soome return; 15083630506bSToomas Soome 15093630506bSToomas Soome width = wd; 15103630506bSToomas Soome sx = x0 < x1? 1 : -1; 15113630506bSToomas Soome sy = y0 < y1? 1 : -1; 15123630506bSToomas Soome dx = x1 > x0? x1 - x0 : x0 - x1; 15133630506bSToomas Soome dy = y1 > y0? y1 - y0 : y0 - y1; 15143630506bSToomas Soome err = dx + dy; 15153630506bSToomas Soome ed = dx + dy == 0 ? 1: isqrt(dx * dx + dy * dy); 15163630506bSToomas Soome 15173630506bSToomas Soome for (;;) { 15183630506bSToomas Soome gfx_fb_setpixel(x0, y0); 15193630506bSToomas Soome e2 = err; 15203630506bSToomas Soome x2 = x0; 15213630506bSToomas Soome if ((e2 << 1) >= -dx) { /* x step */ 15223630506bSToomas Soome e2 += dy; 15233630506bSToomas Soome y2 = y0; 15243630506bSToomas Soome while (e2 < ed * width && 15253630506bSToomas Soome (y1 != (uint32_t)y2 || dx > dy)) { 15263630506bSToomas Soome y2 += sy; 15273630506bSToomas Soome gfx_fb_setpixel(x0, y2); 15283630506bSToomas Soome e2 += dx; 15293630506bSToomas Soome } 15303630506bSToomas Soome if (x0 == x1) 15313630506bSToomas Soome break; 15323630506bSToomas Soome e2 = err; 15333630506bSToomas Soome err -= dy; 15343630506bSToomas Soome x0 += sx; 15353630506bSToomas Soome } 15363630506bSToomas Soome if ((e2 << 1) <= dy) { /* y step */ 15373630506bSToomas Soome e2 = dx-e2; 15383630506bSToomas Soome while (e2 < ed * width && 15393630506bSToomas Soome (x1 != (uint32_t)x2 || dx < dy)) { 15403630506bSToomas Soome x2 += sx; 15413630506bSToomas Soome gfx_fb_setpixel(x2, y0); 15423630506bSToomas Soome e2 += dy; 15433630506bSToomas Soome } 15443630506bSToomas Soome if (y0 == y1) 15453630506bSToomas Soome break; 15463630506bSToomas Soome err += dx; 15473630506bSToomas Soome y0 += sy; 15483630506bSToomas Soome } 15493630506bSToomas Soome } 15503630506bSToomas Soome } 15513630506bSToomas Soome 15523630506bSToomas Soome /* 15533630506bSToomas Soome * quadratic Bézier curve limited to gradients without sign change. 15543630506bSToomas Soome */ 15553630506bSToomas Soome void 15563630506bSToomas Soome gfx_fb_bezier(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t x2, 15573630506bSToomas Soome uint32_t y2, uint32_t wd) 15583630506bSToomas Soome { 15593630506bSToomas Soome int sx, sy, xx, yy, xy, width; 15603630506bSToomas Soome int dx, dy, err, curvature; 15613630506bSToomas Soome int i; 15623630506bSToomas Soome 15633630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 15643630506bSToomas Soome return; 15653630506bSToomas Soome 15663630506bSToomas Soome width = wd; 15673630506bSToomas Soome sx = x2 - x1; 15683630506bSToomas Soome sy = y2 - y1; 15693630506bSToomas Soome xx = x0 - x1; 15703630506bSToomas Soome yy = y0 - y1; 15713630506bSToomas Soome curvature = xx*sy - yy*sx; 15723630506bSToomas Soome 15733630506bSToomas Soome if (sx*sx + sy*sy > xx*xx+yy*yy) { 15743630506bSToomas Soome x2 = x0; 15753630506bSToomas Soome x0 = sx + x1; 15763630506bSToomas Soome y2 = y0; 15773630506bSToomas Soome y0 = sy + y1; 15783630506bSToomas Soome curvature = -curvature; 15793630506bSToomas Soome } 15803630506bSToomas Soome if (curvature != 0) { 15813630506bSToomas Soome xx += sx; 15823630506bSToomas Soome sx = x0 < x2? 1 : -1; 15833630506bSToomas Soome xx *= sx; 15843630506bSToomas Soome yy += sy; 15853630506bSToomas Soome sy = y0 < y2? 1 : -1; 15863630506bSToomas Soome yy *= sy; 15873630506bSToomas Soome xy = (xx*yy) << 1; 15883630506bSToomas Soome xx *= xx; 15893630506bSToomas Soome yy *= yy; 15903630506bSToomas Soome if (curvature * sx * sy < 0) { 15913630506bSToomas Soome xx = -xx; 15923630506bSToomas Soome yy = -yy; 15933630506bSToomas Soome xy = -xy; 15943630506bSToomas Soome curvature = -curvature; 15953630506bSToomas Soome } 15963630506bSToomas Soome dx = 4 * sy * curvature * (x1 - x0) + xx - xy; 15973630506bSToomas Soome dy = 4 * sx * curvature * (y0 - y1) + yy - xy; 15983630506bSToomas Soome xx += xx; 15993630506bSToomas Soome yy += yy; 16003630506bSToomas Soome err = dx + dy + xy; 16013630506bSToomas Soome do { 16023630506bSToomas Soome for (i = 0; i <= width; i++) 16033630506bSToomas Soome gfx_fb_setpixel(x0 + i, y0); 16043630506bSToomas Soome if (x0 == x2 && y0 == y2) 16053630506bSToomas Soome return; /* last pixel -> curve finished */ 16063630506bSToomas Soome y1 = 2 * err < dx; 16073630506bSToomas Soome if (2 * err > dy) { 16083630506bSToomas Soome x0 += sx; 16093630506bSToomas Soome dx -= xy; 16103630506bSToomas Soome dy += yy; 16113630506bSToomas Soome err += dy; 16123630506bSToomas Soome } 16133630506bSToomas Soome if (y1 != 0) { 16143630506bSToomas Soome y0 += sy; 16153630506bSToomas Soome dy -= xy; 16163630506bSToomas Soome dx += xx; 16173630506bSToomas Soome err += dx; 16183630506bSToomas Soome } 16193630506bSToomas Soome } while (dy < dx); /* gradient negates -> algorithm fails */ 16203630506bSToomas Soome } 16213630506bSToomas Soome gfx_fb_line(x0, y0, x2, y2, width); 16223630506bSToomas Soome } 16233630506bSToomas Soome 16243630506bSToomas Soome /* 16253630506bSToomas Soome * draw rectangle using terminal coordinates and current foreground color. 16263630506bSToomas Soome */ 16273630506bSToomas Soome void 16283630506bSToomas Soome gfx_term_drawrect(uint32_t ux1, uint32_t uy1, uint32_t ux2, uint32_t uy2) 16293630506bSToomas Soome { 16303630506bSToomas Soome int x1, y1, x2, y2; 16313630506bSToomas Soome int xshift, yshift; 16323630506bSToomas Soome int width, i; 16333630506bSToomas Soome uint32_t vf_width, vf_height; 16343630506bSToomas Soome teken_rect_t r; 16353630506bSToomas Soome 16363630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 16373630506bSToomas Soome return; 16383630506bSToomas Soome 16393630506bSToomas Soome vf_width = gfx_state.tg_font.vf_width; 16403630506bSToomas Soome vf_height = gfx_state.tg_font.vf_height; 16413630506bSToomas Soome width = vf_width / 4; /* line width */ 16423630506bSToomas Soome xshift = (vf_width - width) / 2; 16433630506bSToomas Soome yshift = (vf_height - width) / 2; 16443630506bSToomas Soome 16453630506bSToomas Soome /* Shift coordinates */ 16463630506bSToomas Soome if (ux1 != 0) 16473630506bSToomas Soome ux1--; 16483630506bSToomas Soome if (uy1 != 0) 16493630506bSToomas Soome uy1--; 16503630506bSToomas Soome ux2--; 16513630506bSToomas Soome uy2--; 16523630506bSToomas Soome 16533630506bSToomas Soome /* mark area used in terminal */ 16543630506bSToomas Soome r.tr_begin.tp_col = ux1; 16553630506bSToomas Soome r.tr_begin.tp_row = uy1; 16563630506bSToomas Soome r.tr_end.tp_col = ux2 + 1; 16573630506bSToomas Soome r.tr_end.tp_row = uy2 + 1; 16583630506bSToomas Soome 16593630506bSToomas Soome term_image_display(&gfx_state, &r); 16603630506bSToomas Soome 16613630506bSToomas Soome /* 16623630506bSToomas Soome * Draw horizontal lines width points thick, shifted from outer edge. 16633630506bSToomas Soome */ 16643630506bSToomas Soome x1 = (ux1 + 1) * vf_width + gfx_state.tg_origin.tp_col; 16653630506bSToomas Soome y1 = uy1 * vf_height + gfx_state.tg_origin.tp_row + yshift; 16663630506bSToomas Soome x2 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 16673630506bSToomas Soome gfx_fb_drawrect(x1, y1, x2, y1 + width, 1); 16683630506bSToomas Soome y2 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 16693630506bSToomas Soome y2 += vf_height - yshift - width; 16703630506bSToomas Soome gfx_fb_drawrect(x1, y2, x2, y2 + width, 1); 16713630506bSToomas Soome 16723630506bSToomas Soome /* 16733630506bSToomas Soome * Draw vertical lines width points thick, shifted from outer edge. 16743630506bSToomas Soome */ 16753630506bSToomas Soome x1 = ux1 * vf_width + gfx_state.tg_origin.tp_col + xshift; 16763630506bSToomas Soome y1 = uy1 * vf_height + gfx_state.tg_origin.tp_row; 16773630506bSToomas Soome y1 += vf_height; 16783630506bSToomas Soome y2 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 16793630506bSToomas Soome gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); 16803630506bSToomas Soome x1 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 16813630506bSToomas Soome x1 += vf_width - xshift - width; 16823630506bSToomas Soome gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); 16833630506bSToomas Soome 16843630506bSToomas Soome /* Draw upper left corner. */ 16853630506bSToomas Soome x1 = ux1 * vf_width + gfx_state.tg_origin.tp_col + xshift; 16863630506bSToomas Soome y1 = uy1 * vf_height + gfx_state.tg_origin.tp_row; 16873630506bSToomas Soome y1 += vf_height; 16883630506bSToomas Soome 16893630506bSToomas Soome x2 = ux1 * vf_width + gfx_state.tg_origin.tp_col; 16903630506bSToomas Soome x2 += vf_width; 16913630506bSToomas Soome y2 = uy1 * vf_height + gfx_state.tg_origin.tp_row + yshift; 16923630506bSToomas Soome for (i = 0; i <= width; i++) 16933630506bSToomas Soome gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i); 16943630506bSToomas Soome 16953630506bSToomas Soome /* Draw lower left corner. */ 16963630506bSToomas Soome x1 = ux1 * vf_width + gfx_state.tg_origin.tp_col; 16973630506bSToomas Soome x1 += vf_width; 16983630506bSToomas Soome y1 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 16993630506bSToomas Soome y1 += vf_height - yshift; 17003630506bSToomas Soome x2 = ux1 * vf_width + gfx_state.tg_origin.tp_col + xshift; 17013630506bSToomas Soome y2 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 17023630506bSToomas Soome for (i = 0; i <= width; i++) 17033630506bSToomas Soome gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); 17043630506bSToomas Soome 17053630506bSToomas Soome /* Draw upper right corner. */ 17063630506bSToomas Soome x1 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 17073630506bSToomas Soome y1 = uy1 * vf_height + gfx_state.tg_origin.tp_row + yshift; 17083630506bSToomas Soome x2 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 17093630506bSToomas Soome x2 += vf_width - xshift - width; 17103630506bSToomas Soome y2 = uy1 * vf_height + gfx_state.tg_origin.tp_row; 17113630506bSToomas Soome y2 += vf_height; 17123630506bSToomas Soome for (i = 0; i <= width; i++) 17133630506bSToomas Soome gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i); 17143630506bSToomas Soome 17153630506bSToomas Soome /* Draw lower right corner. */ 17163630506bSToomas Soome x1 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 17173630506bSToomas Soome y1 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 17183630506bSToomas Soome y1 += vf_height - yshift; 17193630506bSToomas Soome x2 = ux2 * vf_width + gfx_state.tg_origin.tp_col; 17203630506bSToomas Soome x2 += vf_width - xshift - width; 17213630506bSToomas Soome y2 = uy2 * vf_height + gfx_state.tg_origin.tp_row; 17223630506bSToomas Soome for (i = 0; i <= width; i++) 17233630506bSToomas Soome gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); 17243630506bSToomas Soome } 17253630506bSToomas Soome 17263630506bSToomas Soome int 17273630506bSToomas Soome gfx_fb_putimage(png_t *png, uint32_t ux1, uint32_t uy1, uint32_t ux2, 17283630506bSToomas Soome uint32_t uy2, uint32_t flags) 17293630506bSToomas Soome { 17303630506bSToomas Soome #if defined(EFI) 17313630506bSToomas Soome EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p; 17323630506bSToomas Soome #else 17333630506bSToomas Soome struct paletteentry *p; 17343630506bSToomas Soome #endif 17353630506bSToomas Soome uint8_t *data; 17363630506bSToomas Soome uint32_t i, j, x, y, fheight, fwidth; 17373630506bSToomas Soome int rs, gs, bs; 17383630506bSToomas Soome uint8_t r, g, b, a; 17393630506bSToomas Soome bool scale = false; 17403630506bSToomas Soome bool trace = false; 17413630506bSToomas Soome teken_rect_t rect; 17423630506bSToomas Soome 17433630506bSToomas Soome trace = (flags & FL_PUTIMAGE_DEBUG) != 0; 17443630506bSToomas Soome 17453630506bSToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) { 17463630506bSToomas Soome if (trace) 17473630506bSToomas Soome printf("Framebuffer not active.\n"); 17483630506bSToomas Soome return (1); 17493630506bSToomas Soome } 17503630506bSToomas Soome 17513630506bSToomas Soome if (png->color_type != PNG_TRUECOLOR_ALPHA) { 17523630506bSToomas Soome if (trace) 17533630506bSToomas Soome printf("Not truecolor image.\n"); 17543630506bSToomas Soome return (1); 17553630506bSToomas Soome } 17563630506bSToomas Soome 17573630506bSToomas Soome if (ux1 > gfx_state.tg_fb.fb_width || 17583630506bSToomas Soome uy1 > gfx_state.tg_fb.fb_height) { 17593630506bSToomas Soome if (trace) 17603630506bSToomas Soome printf("Top left coordinate off screen.\n"); 17613630506bSToomas Soome return (1); 17623630506bSToomas Soome } 17633630506bSToomas Soome 17643630506bSToomas Soome if (png->width > UINT16_MAX || png->height > UINT16_MAX) { 17653630506bSToomas Soome if (trace) 17663630506bSToomas Soome printf("Image too large.\n"); 17673630506bSToomas Soome return (1); 17683630506bSToomas Soome } 17693630506bSToomas Soome 17703630506bSToomas Soome if (png->width < 1 || png->height < 1) { 17713630506bSToomas Soome if (trace) 17723630506bSToomas Soome printf("Image too small.\n"); 17733630506bSToomas Soome return (1); 17743630506bSToomas Soome } 17753630506bSToomas Soome 17763630506bSToomas Soome /* 17773630506bSToomas Soome * If 0 was passed for either ux2 or uy2, then calculate the missing 17783630506bSToomas Soome * part of the bottom right coordinate. 17793630506bSToomas Soome */ 17803630506bSToomas Soome scale = true; 17813630506bSToomas Soome if (ux2 == 0 && uy2 == 0) { 17823630506bSToomas Soome /* Both 0, use the native resolution of the image */ 17833630506bSToomas Soome ux2 = ux1 + png->width; 17843630506bSToomas Soome uy2 = uy1 + png->height; 17853630506bSToomas Soome scale = false; 17863630506bSToomas Soome } else if (ux2 == 0) { 17873630506bSToomas Soome /* Set ux2 from uy2/uy1 to maintain aspect ratio */ 17883630506bSToomas Soome ux2 = ux1 + (png->width * (uy2 - uy1)) / png->height; 17893630506bSToomas Soome } else if (uy2 == 0) { 17903630506bSToomas Soome /* Set uy2 from ux2/ux1 to maintain aspect ratio */ 17913630506bSToomas Soome uy2 = uy1 + (png->height * (ux2 - ux1)) / png->width; 17923630506bSToomas Soome } 17933630506bSToomas Soome 17943630506bSToomas Soome if (ux2 > gfx_state.tg_fb.fb_width || 17953630506bSToomas Soome uy2 > gfx_state.tg_fb.fb_height) { 17963630506bSToomas Soome if (trace) 17973630506bSToomas Soome printf("Bottom right coordinate off screen.\n"); 17983630506bSToomas Soome return (1); 17993630506bSToomas Soome } 18003630506bSToomas Soome 18013630506bSToomas Soome fwidth = ux2 - ux1; 18023630506bSToomas Soome fheight = uy2 - uy1; 18033630506bSToomas Soome 18043630506bSToomas Soome /* 18053630506bSToomas Soome * If the original image dimensions have been passed explicitly, 18063630506bSToomas Soome * disable scaling. 18073630506bSToomas Soome */ 18083630506bSToomas Soome if (fwidth == png->width && fheight == png->height) 18093630506bSToomas Soome scale = false; 18103630506bSToomas Soome 18113630506bSToomas Soome if (ux1 == 0) { 18123630506bSToomas Soome /* 18133630506bSToomas Soome * No top left X co-ordinate (real coordinates start at 1), 18143630506bSToomas Soome * place as far right as it will fit. 18153630506bSToomas Soome */ 18163630506bSToomas Soome ux2 = gfx_state.tg_fb.fb_width - gfx_state.tg_origin.tp_col; 18173630506bSToomas Soome ux1 = ux2 - fwidth; 18183630506bSToomas Soome } 18193630506bSToomas Soome 18203630506bSToomas Soome if (uy1 == 0) { 18213630506bSToomas Soome /* 18223630506bSToomas Soome * No top left Y co-ordinate (real coordinates start at 1), 18233630506bSToomas Soome * place as far down as it will fit. 18243630506bSToomas Soome */ 18253630506bSToomas Soome uy2 = gfx_state.tg_fb.fb_height - gfx_state.tg_origin.tp_row; 18263630506bSToomas Soome uy1 = uy2 - fheight; 18273630506bSToomas Soome } 18283630506bSToomas Soome 18293630506bSToomas Soome if (ux1 >= ux2 || uy1 >= uy2) { 18303630506bSToomas Soome if (trace) 18313630506bSToomas Soome printf("Image dimensions reversed.\n"); 18323630506bSToomas Soome return (1); 18333630506bSToomas Soome } 18343630506bSToomas Soome 18353630506bSToomas Soome if (fwidth < 2 || fheight < 2) { 18363630506bSToomas Soome if (trace) 18373630506bSToomas Soome printf("Target area too small\n"); 18383630506bSToomas Soome return (1); 18393630506bSToomas Soome } 18403630506bSToomas Soome 18413630506bSToomas Soome if (trace) 18423630506bSToomas Soome printf("Image %ux%u -> %ux%u @%ux%u\n", 18433630506bSToomas Soome png->width, png->height, fwidth, fheight, ux1, uy1); 18443630506bSToomas Soome 18453630506bSToomas Soome rect.tr_begin.tp_col = ux1 / gfx_state.tg_font.vf_width; 18463630506bSToomas Soome rect.tr_begin.tp_row = uy1 / gfx_state.tg_font.vf_height; 18473630506bSToomas Soome rect.tr_end.tp_col = (ux1 + fwidth) / gfx_state.tg_font.vf_width; 18483630506bSToomas Soome rect.tr_end.tp_row = (uy1 + fheight) / gfx_state.tg_font.vf_height; 18493630506bSToomas Soome 18503630506bSToomas Soome /* 18513630506bSToomas Soome * mark area used in terminal 18523630506bSToomas Soome */ 18533630506bSToomas Soome if (!(flags & FL_PUTIMAGE_NOSCROLL)) 18543630506bSToomas Soome term_image_display(&gfx_state, &rect); 18553630506bSToomas Soome 18563630506bSToomas Soome if ((flags & FL_PUTIMAGE_BORDER)) 18573630506bSToomas Soome gfx_fb_drawrect(ux1, uy1, ux2, uy2, 0); 18583630506bSToomas Soome 18593630506bSToomas Soome data = malloc(fwidth * fheight * sizeof(*p)); 18603630506bSToomas Soome p = (void *)data; 18613630506bSToomas Soome if (data == NULL) { 18623630506bSToomas Soome if (trace) 18633630506bSToomas Soome printf("Out of memory.\n"); 18643630506bSToomas Soome return (1); 18653630506bSToomas Soome } 18663630506bSToomas Soome 18673630506bSToomas Soome /* 18683630506bSToomas Soome * Build image for our framebuffer. 18693630506bSToomas Soome */ 18703630506bSToomas Soome 18713630506bSToomas Soome /* Helper to calculate the pixel index from the source png */ 18723630506bSToomas Soome #define GETPIXEL(xx, yy) (((yy) * png->width + (xx)) * png->bpp) 18733630506bSToomas Soome 18743630506bSToomas Soome /* 18753630506bSToomas Soome * For each of the x and y directions, calculate the number of pixels 18763630506bSToomas Soome * in the source image that correspond to a single pixel in the target. 18773630506bSToomas Soome * Use fixed-point arithmetic with 16-bits for each of the integer and 18783630506bSToomas Soome * fractional parts. 18793630506bSToomas Soome */ 18803630506bSToomas Soome const uint32_t wcstep = ((png->width - 1) << 16) / (fwidth - 1); 18813630506bSToomas Soome const uint32_t hcstep = ((png->height - 1) << 16) / (fheight - 1); 18823630506bSToomas Soome 18833630506bSToomas Soome rs = 8 - (fls(gfx_state.tg_fb.fb_mask_red) - 18843630506bSToomas Soome ffs(gfx_state.tg_fb.fb_mask_red) + 1); 18853630506bSToomas Soome gs = 8 - (fls(gfx_state.tg_fb.fb_mask_green) - 18863630506bSToomas Soome ffs(gfx_state.tg_fb.fb_mask_green) + 1); 18873630506bSToomas Soome bs = 8 - (fls(gfx_state.tg_fb.fb_mask_blue) - 18883630506bSToomas Soome ffs(gfx_state.tg_fb.fb_mask_blue) + 1); 18893630506bSToomas Soome 18903630506bSToomas Soome uint32_t hc = 0; 18913630506bSToomas Soome for (y = 0; y < fheight; y++) { 18923630506bSToomas Soome uint32_t hc2 = (hc >> 9) & 0x7f; 18933630506bSToomas Soome uint32_t hc1 = 0x80 - hc2; 18943630506bSToomas Soome 18953630506bSToomas Soome uint32_t offset_y = hc >> 16; 18963630506bSToomas Soome uint32_t offset_y1 = offset_y + 1; 18973630506bSToomas Soome 18983630506bSToomas Soome uint32_t wc = 0; 18993630506bSToomas Soome for (x = 0; x < fwidth; x++) { 19003630506bSToomas Soome uint32_t wc2 = (wc >> 9) & 0x7f; 19013630506bSToomas Soome uint32_t wc1 = 0x80 - wc2; 19023630506bSToomas Soome 19033630506bSToomas Soome uint32_t offset_x = wc >> 16; 19043630506bSToomas Soome uint32_t offset_x1 = offset_x + 1; 19053630506bSToomas Soome 19063630506bSToomas Soome /* Target pixel index */ 19073630506bSToomas Soome j = y * fwidth + x; 19083630506bSToomas Soome 19093630506bSToomas Soome if (!scale) { 19103630506bSToomas Soome i = GETPIXEL(x, y); 19113630506bSToomas Soome r = png->image[i]; 19123630506bSToomas Soome g = png->image[i + 1]; 19133630506bSToomas Soome b = png->image[i + 2]; 19143630506bSToomas Soome a = png->image[i + 3]; 19153630506bSToomas Soome } else { 19163630506bSToomas Soome uint8_t pixel[4]; 19173630506bSToomas Soome 19183630506bSToomas Soome uint32_t p00 = GETPIXEL(offset_x, offset_y); 19193630506bSToomas Soome uint32_t p01 = GETPIXEL(offset_x, offset_y1); 19203630506bSToomas Soome uint32_t p10 = GETPIXEL(offset_x1, offset_y); 19213630506bSToomas Soome uint32_t p11 = GETPIXEL(offset_x1, offset_y1); 19223630506bSToomas Soome 19233630506bSToomas Soome /* 19243630506bSToomas Soome * Given a 2x2 array of pixels in the source 19253630506bSToomas Soome * image, combine them to produce a single 19263630506bSToomas Soome * value for the pixel in the target image. 19273630506bSToomas Soome * Each column of pixels is combined using 19283630506bSToomas Soome * a weighted average where the top and bottom 19293630506bSToomas Soome * pixels contribute hc1 and hc2 respectively. 19303630506bSToomas Soome * The calculation for bottom pixel pB and 19313630506bSToomas Soome * top pixel pT is: 19323630506bSToomas Soome * (pT * hc1 + pB * hc2) / (hc1 + hc2) 19333630506bSToomas Soome * Once the values are determined for the two 19343630506bSToomas Soome * columns of pixels, then the columns are 19353630506bSToomas Soome * averaged together in the same way but using 19363630506bSToomas Soome * wc1 and wc2 for the weightings. 19373630506bSToomas Soome * 19383630506bSToomas Soome * Since hc1 and hc2 are chosen so that 19393630506bSToomas Soome * hc1 + hc2 == 128 (and same for wc1 + wc2), 19403630506bSToomas Soome * the >> 14 below is a quick way to divide by 19413630506bSToomas Soome * (hc1 + hc2) * (wc1 + wc2) 19423630506bSToomas Soome */ 19433630506bSToomas Soome for (i = 0; i < 4; i++) 19443630506bSToomas Soome pixel[i] = ( 19453630506bSToomas Soome (png->image[p00 + i] * hc1 + 19463630506bSToomas Soome png->image[p01 + i] * hc2) * wc1 + 19473630506bSToomas Soome (png->image[p10 + i] * hc1 + 19483630506bSToomas Soome png->image[p11 + i] * hc2) * wc2) 19493630506bSToomas Soome >> 14; 19503630506bSToomas Soome 19513630506bSToomas Soome r = pixel[0]; 19523630506bSToomas Soome g = pixel[1]; 19533630506bSToomas Soome b = pixel[2]; 19543630506bSToomas Soome a = pixel[3]; 19553630506bSToomas Soome } 19563630506bSToomas Soome 19573630506bSToomas Soome if (trace) 19583630506bSToomas Soome printf("r/g/b: %x/%x/%x\n", r, g, b); 19593630506bSToomas Soome /* 19603630506bSToomas Soome * Rough colorspace reduction for 15/16 bit colors. 19613630506bSToomas Soome */ 19623630506bSToomas Soome p[j].Red = r >> rs; 19633630506bSToomas Soome p[j].Green = g >> gs; 19643630506bSToomas Soome p[j].Blue = b >> bs; 19653630506bSToomas Soome p[j].Reserved = a; 19663630506bSToomas Soome 19673630506bSToomas Soome wc += wcstep; 19683630506bSToomas Soome } 19693630506bSToomas Soome hc += hcstep; 19703630506bSToomas Soome } 19713630506bSToomas Soome 19723630506bSToomas Soome gfx_fb_cons_display(ux1, uy1, fwidth, fheight, data); 19733630506bSToomas Soome free(data); 19743630506bSToomas Soome return (0); 19753630506bSToomas Soome } 19763630506bSToomas Soome 19773630506bSToomas Soome /* 19783630506bSToomas Soome * Reset font flags to FONT_AUTO. 19793630506bSToomas Soome */ 19803630506bSToomas Soome void 19813630506bSToomas Soome reset_font_flags(void) 19823630506bSToomas Soome { 19833630506bSToomas Soome struct fontlist *fl; 19843630506bSToomas Soome 19853630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 19863630506bSToomas Soome fl->font_flags = FONT_AUTO; 19873630506bSToomas Soome } 19883630506bSToomas Soome } 19893630506bSToomas Soome 1990becaac39SToomas Soome /* Return w^2 + h^2 or 0, if the dimensions are unknown */ 1991becaac39SToomas Soome static unsigned 1992becaac39SToomas Soome edid_diagonal_squared(void) 1993becaac39SToomas Soome { 1994becaac39SToomas Soome unsigned w, h; 1995becaac39SToomas Soome 1996becaac39SToomas Soome if (edid_info == NULL) 1997becaac39SToomas Soome return (0); 1998becaac39SToomas Soome 1999becaac39SToomas Soome w = edid_info->display.max_horizontal_image_size; 2000becaac39SToomas Soome h = edid_info->display.max_vertical_image_size; 2001becaac39SToomas Soome 2002becaac39SToomas Soome /* If either one is 0, we have aspect ratio, not size */ 2003becaac39SToomas Soome if (w == 0 || h == 0) 2004becaac39SToomas Soome return (0); 2005becaac39SToomas Soome 2006becaac39SToomas Soome /* 2007becaac39SToomas Soome * some monitors encode the aspect ratio instead of the physical size. 2008becaac39SToomas Soome */ 2009becaac39SToomas Soome if ((w == 16 && h == 9) || (w == 16 && h == 10) || 2010becaac39SToomas Soome (w == 4 && h == 3) || (w == 5 && h == 4)) 2011becaac39SToomas Soome return (0); 2012becaac39SToomas Soome 2013becaac39SToomas Soome /* 2014becaac39SToomas Soome * translate cm to inch, note we scale by 100 here. 2015becaac39SToomas Soome */ 2016becaac39SToomas Soome w = w * 100 / 254; 2017becaac39SToomas Soome h = h * 100 / 254; 2018becaac39SToomas Soome 2019becaac39SToomas Soome /* Return w^2 + h^2 */ 2020becaac39SToomas Soome return (w * w + h * h); 2021becaac39SToomas Soome } 2022becaac39SToomas Soome 2023becaac39SToomas Soome /* 2024becaac39SToomas Soome * calculate pixels per inch. 2025becaac39SToomas Soome */ 2026becaac39SToomas Soome static unsigned 2027becaac39SToomas Soome gfx_get_ppi(void) 2028becaac39SToomas Soome { 2029becaac39SToomas Soome unsigned dp, di; 2030becaac39SToomas Soome 2031becaac39SToomas Soome di = edid_diagonal_squared(); 2032becaac39SToomas Soome if (di == 0) 2033becaac39SToomas Soome return (0); 2034becaac39SToomas Soome 2035becaac39SToomas Soome dp = gfx_state.tg_fb.fb_width * 2036becaac39SToomas Soome gfx_state.tg_fb.fb_width + 2037becaac39SToomas Soome gfx_state.tg_fb.fb_height * 2038becaac39SToomas Soome gfx_state.tg_fb.fb_height; 2039becaac39SToomas Soome 2040becaac39SToomas Soome return (isqrt(dp / di)); 2041becaac39SToomas Soome } 2042becaac39SToomas Soome 2043becaac39SToomas Soome /* 2044becaac39SToomas Soome * Calculate font size from density independent pixels (dp): 2045becaac39SToomas Soome * ((16dp * ppi) / 160) * display_factor. 2046becaac39SToomas Soome * Here we are using fixed constants: 1dp == 160 ppi and 2047becaac39SToomas Soome * display_factor 2. 2048becaac39SToomas Soome * 2049becaac39SToomas Soome * We are rounding font size up and are searching for font which is 2050becaac39SToomas Soome * not smaller than calculated size value. 2051becaac39SToomas Soome */ 2052becaac39SToomas Soome static vt_font_bitmap_data_t * 2053becaac39SToomas Soome gfx_get_font(void) 2054becaac39SToomas Soome { 2055becaac39SToomas Soome unsigned ppi, size; 2056becaac39SToomas Soome vt_font_bitmap_data_t *font = NULL; 2057becaac39SToomas Soome struct fontlist *fl, *next; 2058becaac39SToomas Soome 2059becaac39SToomas Soome /* Text mode is not supported here. */ 2060becaac39SToomas Soome if (gfx_state.tg_fb_type == FB_TEXT) 2061becaac39SToomas Soome return (NULL); 2062becaac39SToomas Soome 2063becaac39SToomas Soome ppi = gfx_get_ppi(); 2064becaac39SToomas Soome if (ppi == 0) 2065becaac39SToomas Soome return (NULL); 2066becaac39SToomas Soome 2067becaac39SToomas Soome /* 2068becaac39SToomas Soome * We will search for 16dp font. 2069becaac39SToomas Soome * We are using scale up by 10 for roundup. 2070becaac39SToomas Soome */ 2071becaac39SToomas Soome size = (16 * ppi * 10) / 160; 2072becaac39SToomas Soome /* Apply display factor 2. */ 2073becaac39SToomas Soome size = roundup(size * 2, 10) / 10; 2074becaac39SToomas Soome 2075becaac39SToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 2076becaac39SToomas Soome next = STAILQ_NEXT(fl, font_next); 2077becaac39SToomas Soome 2078becaac39SToomas Soome /* 2079becaac39SToomas Soome * If this is last font or, if next font is smaller, 2080becaac39SToomas Soome * we have our font. Make sure, it actually is loaded. 2081becaac39SToomas Soome */ 2082becaac39SToomas Soome if (next == NULL || next->font_data->vfbd_height < size) { 2083becaac39SToomas Soome font = fl->font_data; 2084becaac39SToomas Soome if (font->vfbd_font == NULL || 2085becaac39SToomas Soome fl->font_flags == FONT_RELOAD) { 2086becaac39SToomas Soome if (fl->font_load != NULL && 2087becaac39SToomas Soome fl->font_name != NULL) 2088becaac39SToomas Soome font = fl->font_load(fl->font_name); 2089becaac39SToomas Soome } 2090becaac39SToomas Soome break; 2091becaac39SToomas Soome } 2092becaac39SToomas Soome } 2093becaac39SToomas Soome 2094becaac39SToomas Soome return (font); 2095becaac39SToomas Soome } 2096becaac39SToomas Soome 20973630506bSToomas Soome static vt_font_bitmap_data_t * 20983630506bSToomas Soome set_font(teken_unit_t *rows, teken_unit_t *cols, teken_unit_t h, teken_unit_t w) 20993630506bSToomas Soome { 21003630506bSToomas Soome vt_font_bitmap_data_t *font = NULL; 21013630506bSToomas Soome struct fontlist *fl; 21023630506bSToomas Soome unsigned height = h; 21033630506bSToomas Soome unsigned width = w; 21043630506bSToomas Soome 21053630506bSToomas Soome /* 21063630506bSToomas Soome * First check for manually loaded font. 21073630506bSToomas Soome */ 21083630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 21093630506bSToomas Soome if (fl->font_flags == FONT_MANUAL) { 21103630506bSToomas Soome font = fl->font_data; 21113630506bSToomas Soome if (font->vfbd_font == NULL && fl->font_load != NULL && 21123630506bSToomas Soome fl->font_name != NULL) { 21133630506bSToomas Soome font = fl->font_load(fl->font_name); 21143630506bSToomas Soome } 21153630506bSToomas Soome if (font == NULL || font->vfbd_font == NULL) 21163630506bSToomas Soome font = NULL; 21173630506bSToomas Soome break; 21183630506bSToomas Soome } 21193630506bSToomas Soome } 21203630506bSToomas Soome 2121becaac39SToomas Soome if (font == NULL) 2122becaac39SToomas Soome font = gfx_get_font(); 2123becaac39SToomas Soome 21243630506bSToomas Soome if (font != NULL) { 212596bef205SToomas Soome *rows = height / font->vfbd_height; 212696bef205SToomas Soome *cols = width / font->vfbd_width; 21273630506bSToomas Soome return (font); 21283630506bSToomas Soome } 21293630506bSToomas Soome 21303630506bSToomas Soome /* 2131a26f7358SToomas Soome * Find best font for these dimensions, or use default. 2132a26f7358SToomas Soome * If height >= VT_FB_MAX_HEIGHT and width >= VT_FB_MAX_WIDTH, 2133a26f7358SToomas Soome * do not use smaller font than our DEFAULT_FONT_DATA. 21343630506bSToomas Soome */ 21353630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 21363630506bSToomas Soome font = fl->font_data; 2137a26f7358SToomas Soome if ((*rows * font->vfbd_height <= height && 2138a26f7358SToomas Soome *cols * font->vfbd_width <= width) || 2139a26f7358SToomas Soome (height >= VT_FB_MAX_HEIGHT && 2140a26f7358SToomas Soome width >= VT_FB_MAX_WIDTH && 2141a26f7358SToomas Soome font->vfbd_height == DEFAULT_FONT_DATA.vfbd_height && 2142a26f7358SToomas Soome font->vfbd_width == DEFAULT_FONT_DATA.vfbd_width)) { 21433630506bSToomas Soome if (font->vfbd_font == NULL || 21443630506bSToomas Soome fl->font_flags == FONT_RELOAD) { 21453630506bSToomas Soome if (fl->font_load != NULL && 21463630506bSToomas Soome fl->font_name != NULL) { 21473630506bSToomas Soome font = fl->font_load(fl->font_name); 21483630506bSToomas Soome } 21493630506bSToomas Soome if (font == NULL) 21503630506bSToomas Soome continue; 21513630506bSToomas Soome } 215296bef205SToomas Soome *rows = height / font->vfbd_height; 215396bef205SToomas Soome *cols = width / font->vfbd_width; 21543630506bSToomas Soome break; 21553630506bSToomas Soome } 21563630506bSToomas Soome font = NULL; 21573630506bSToomas Soome } 21583630506bSToomas Soome 21593630506bSToomas Soome if (font == NULL) { 21603630506bSToomas Soome /* 21613630506bSToomas Soome * We have fonts sorted smallest last, try it before 21623630506bSToomas Soome * falling back to builtin. 21633630506bSToomas Soome */ 21643630506bSToomas Soome fl = STAILQ_LAST(&fonts, fontlist, font_next); 21653630506bSToomas Soome if (fl != NULL && fl->font_load != NULL && 21663630506bSToomas Soome fl->font_name != NULL) { 21673630506bSToomas Soome font = fl->font_load(fl->font_name); 21683630506bSToomas Soome } 21693630506bSToomas Soome if (font == NULL) 21703630506bSToomas Soome font = &DEFAULT_FONT_DATA; 21713630506bSToomas Soome 217296bef205SToomas Soome *rows = height / font->vfbd_height; 217396bef205SToomas Soome *cols = width / font->vfbd_width; 21743630506bSToomas Soome } 21753630506bSToomas Soome 21763630506bSToomas Soome return (font); 21773630506bSToomas Soome } 21783630506bSToomas Soome 21793630506bSToomas Soome static void 21803630506bSToomas Soome cons_clear(void) 21813630506bSToomas Soome { 21823630506bSToomas Soome char clear[] = { '\033', 'c' }; 21833630506bSToomas Soome 21843630506bSToomas Soome /* Reset terminal */ 21853630506bSToomas Soome teken_input(&gfx_state.tg_teken, clear, sizeof(clear)); 21863630506bSToomas Soome gfx_state.tg_functions->tf_param(&gfx_state, TP_SHOWCURSOR, 0); 21873630506bSToomas Soome } 21883630506bSToomas Soome 21893630506bSToomas Soome void 21903630506bSToomas Soome setup_font(teken_gfx_t *state, teken_unit_t height, teken_unit_t width) 21913630506bSToomas Soome { 21923630506bSToomas Soome vt_font_bitmap_data_t *font_data; 21933630506bSToomas Soome teken_pos_t *tp = &state->tg_tp; 21943630506bSToomas Soome char env[8]; 21953630506bSToomas Soome int i; 21963630506bSToomas Soome 21973630506bSToomas Soome /* 21983630506bSToomas Soome * set_font() will select a appropriate sized font for 21993630506bSToomas Soome * the number of rows and columns selected. If we don't 22003630506bSToomas Soome * have a font that will fit, then it will use the 22013630506bSToomas Soome * default builtin font and adjust the rows and columns 22023630506bSToomas Soome * to fit on the screen. 22033630506bSToomas Soome */ 22043630506bSToomas Soome font_data = set_font(&tp->tp_row, &tp->tp_col, height, width); 22053630506bSToomas Soome 22063630506bSToomas Soome if (font_data == NULL) 22073630506bSToomas Soome panic("out of memory"); 22083630506bSToomas Soome 22093630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) { 22103630506bSToomas Soome state->tg_font.vf_map[i] = 22113630506bSToomas Soome font_data->vfbd_font->vf_map[i]; 22123630506bSToomas Soome state->tg_font.vf_map_count[i] = 22133630506bSToomas Soome font_data->vfbd_font->vf_map_count[i]; 22143630506bSToomas Soome } 22153630506bSToomas Soome 22163630506bSToomas Soome state->tg_font.vf_bytes = font_data->vfbd_font->vf_bytes; 22173630506bSToomas Soome state->tg_font.vf_height = font_data->vfbd_font->vf_height; 22183630506bSToomas Soome state->tg_font.vf_width = font_data->vfbd_font->vf_width; 22193630506bSToomas Soome 22203630506bSToomas Soome snprintf(env, sizeof (env), "%ux%u", 22213630506bSToomas Soome state->tg_font.vf_width, state->tg_font.vf_height); 22223630506bSToomas Soome env_setenv("screen.font", EV_VOLATILE | EV_NOHOOK, 22233630506bSToomas Soome env, font_set, env_nounset); 22243630506bSToomas Soome } 22253630506bSToomas Soome 22263630506bSToomas Soome /* Binary search for the glyph. Return 0 if not found. */ 22273630506bSToomas Soome static uint16_t 22283630506bSToomas Soome font_bisearch(const vfnt_map_t *map, uint32_t len, teken_char_t src) 22293630506bSToomas Soome { 22303630506bSToomas Soome unsigned min, mid, max; 22313630506bSToomas Soome 22323630506bSToomas Soome min = 0; 22333630506bSToomas Soome max = len - 1; 22343630506bSToomas Soome 22353630506bSToomas Soome /* Empty font map. */ 22363630506bSToomas Soome if (len == 0) 22373630506bSToomas Soome return (0); 22383630506bSToomas Soome /* Character below minimal entry. */ 22393630506bSToomas Soome if (src < map[0].vfm_src) 22403630506bSToomas Soome return (0); 22413630506bSToomas Soome /* Optimization: ASCII characters occur very often. */ 22423630506bSToomas Soome if (src <= map[0].vfm_src + map[0].vfm_len) 22433630506bSToomas Soome return (src - map[0].vfm_src + map[0].vfm_dst); 22443630506bSToomas Soome /* Character above maximum entry. */ 22453630506bSToomas Soome if (src > map[max].vfm_src + map[max].vfm_len) 22463630506bSToomas Soome return (0); 22473630506bSToomas Soome 22483630506bSToomas Soome /* Binary search. */ 22493630506bSToomas Soome while (max >= min) { 22503630506bSToomas Soome mid = (min + max) / 2; 22513630506bSToomas Soome if (src < map[mid].vfm_src) 22523630506bSToomas Soome max = mid - 1; 22533630506bSToomas Soome else if (src > map[mid].vfm_src + map[mid].vfm_len) 22543630506bSToomas Soome min = mid + 1; 22553630506bSToomas Soome else 22563630506bSToomas Soome return (src - map[mid].vfm_src + map[mid].vfm_dst); 22573630506bSToomas Soome } 22583630506bSToomas Soome 22593630506bSToomas Soome return (0); 22603630506bSToomas Soome } 22613630506bSToomas Soome 22623630506bSToomas Soome /* 22633630506bSToomas Soome * Return glyph bitmap. If glyph is not found, we will return bitmap 22643630506bSToomas Soome * for the first (offset 0) glyph. 22653630506bSToomas Soome */ 22663630506bSToomas Soome uint8_t * 22673630506bSToomas Soome font_lookup(const struct vt_font *vf, teken_char_t c, const teken_attr_t *a) 22683630506bSToomas Soome { 22693630506bSToomas Soome uint16_t dst; 22703630506bSToomas Soome size_t stride; 22713630506bSToomas Soome 22723630506bSToomas Soome /* Substitute bold with normal if not found. */ 22733630506bSToomas Soome if (a->ta_format & TF_BOLD) { 22743630506bSToomas Soome dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD], 22753630506bSToomas Soome vf->vf_map_count[VFNT_MAP_BOLD], c); 22763630506bSToomas Soome if (dst != 0) 22773630506bSToomas Soome goto found; 22783630506bSToomas Soome } 22793630506bSToomas Soome dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL], 22803630506bSToomas Soome vf->vf_map_count[VFNT_MAP_NORMAL], c); 22813630506bSToomas Soome 22823630506bSToomas Soome found: 22833630506bSToomas Soome stride = howmany(vf->vf_width, 8) * vf->vf_height; 22843630506bSToomas Soome return (&vf->vf_bytes[dst * stride]); 22853630506bSToomas Soome } 22863630506bSToomas Soome 22873630506bSToomas Soome static int 22883630506bSToomas Soome load_mapping(int fd, struct vt_font *fp, int n) 22893630506bSToomas Soome { 22903630506bSToomas Soome size_t i, size; 22913630506bSToomas Soome ssize_t rv; 22923630506bSToomas Soome vfnt_map_t *mp; 22933630506bSToomas Soome 22943630506bSToomas Soome if (fp->vf_map_count[n] == 0) 22953630506bSToomas Soome return (0); 22963630506bSToomas Soome 22973630506bSToomas Soome size = fp->vf_map_count[n] * sizeof(*mp); 22983630506bSToomas Soome mp = malloc(size); 22993630506bSToomas Soome if (mp == NULL) 23003630506bSToomas Soome return (ENOMEM); 23013630506bSToomas Soome fp->vf_map[n] = mp; 23023630506bSToomas Soome 23033630506bSToomas Soome rv = read(fd, mp, size); 23043630506bSToomas Soome if (rv < 0 || (size_t)rv != size) { 23053630506bSToomas Soome free(fp->vf_map[n]); 23063630506bSToomas Soome fp->vf_map[n] = NULL; 23073630506bSToomas Soome return (EIO); 23083630506bSToomas Soome } 23093630506bSToomas Soome 23103630506bSToomas Soome for (i = 0; i < fp->vf_map_count[n]; i++) { 23113630506bSToomas Soome mp[i].vfm_src = be32toh(mp[i].vfm_src); 23123630506bSToomas Soome mp[i].vfm_dst = be16toh(mp[i].vfm_dst); 23133630506bSToomas Soome mp[i].vfm_len = be16toh(mp[i].vfm_len); 23143630506bSToomas Soome } 23153630506bSToomas Soome return (0); 23163630506bSToomas Soome } 23173630506bSToomas Soome 23183630506bSToomas Soome static int 23193630506bSToomas Soome builtin_mapping(struct vt_font *fp, int n) 23203630506bSToomas Soome { 23213630506bSToomas Soome size_t size; 23223630506bSToomas Soome struct vfnt_map *mp; 23233630506bSToomas Soome 23243630506bSToomas Soome if (n >= VFNT_MAPS) 23253630506bSToomas Soome return (EINVAL); 23263630506bSToomas Soome 23273630506bSToomas Soome if (fp->vf_map_count[n] == 0) 23283630506bSToomas Soome return (0); 23293630506bSToomas Soome 23303630506bSToomas Soome size = fp->vf_map_count[n] * sizeof(*mp); 23313630506bSToomas Soome mp = malloc(size); 23323630506bSToomas Soome if (mp == NULL) 23333630506bSToomas Soome return (ENOMEM); 23343630506bSToomas Soome fp->vf_map[n] = mp; 23353630506bSToomas Soome 23363630506bSToomas Soome memcpy(mp, DEFAULT_FONT_DATA.vfbd_font->vf_map[n], size); 23373630506bSToomas Soome return (0); 23383630506bSToomas Soome } 23393630506bSToomas Soome 23403630506bSToomas Soome /* 23413630506bSToomas Soome * Load font from builtin or from file. 23423630506bSToomas Soome * We do need special case for builtin because the builtin font glyphs 23433630506bSToomas Soome * are compressed and we do need to uncompress them. 23443630506bSToomas Soome * Having single load_font() for both cases will help us to simplify 23453630506bSToomas Soome * font switch handling. 23463630506bSToomas Soome */ 23473630506bSToomas Soome static vt_font_bitmap_data_t * 23483630506bSToomas Soome load_font(char *path) 23493630506bSToomas Soome { 23503630506bSToomas Soome int fd, i; 23513630506bSToomas Soome uint32_t glyphs; 23523630506bSToomas Soome struct font_header fh; 23533630506bSToomas Soome struct fontlist *fl; 23543630506bSToomas Soome vt_font_bitmap_data_t *bp; 23553630506bSToomas Soome struct vt_font *fp; 23563630506bSToomas Soome size_t size; 23573630506bSToomas Soome ssize_t rv; 23583630506bSToomas Soome 23593630506bSToomas Soome /* Get our entry from the font list. */ 23603630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 23613630506bSToomas Soome if (strcmp(fl->font_name, path) == 0) 23623630506bSToomas Soome break; 23633630506bSToomas Soome } 23643630506bSToomas Soome if (fl == NULL) 23653630506bSToomas Soome return (NULL); /* Should not happen. */ 23663630506bSToomas Soome 23673630506bSToomas Soome bp = fl->font_data; 23683630506bSToomas Soome if (bp->vfbd_font != NULL && fl->font_flags != FONT_RELOAD) 23693630506bSToomas Soome return (bp); 23703630506bSToomas Soome 23713630506bSToomas Soome fd = -1; 23723630506bSToomas Soome /* 23733630506bSToomas Soome * Special case for builtin font. 23743630506bSToomas Soome * Builtin font is the very first font we load, we do not have 23753630506bSToomas Soome * previous loads to be released. 23763630506bSToomas Soome */ 23773630506bSToomas Soome if (fl->font_flags == FONT_BUILTIN) { 23783630506bSToomas Soome if ((fp = calloc(1, sizeof(struct vt_font))) == NULL) 23793630506bSToomas Soome return (NULL); 23803630506bSToomas Soome 23813630506bSToomas Soome fp->vf_width = DEFAULT_FONT_DATA.vfbd_width; 23823630506bSToomas Soome fp->vf_height = DEFAULT_FONT_DATA.vfbd_height; 23833630506bSToomas Soome 23843630506bSToomas Soome fp->vf_bytes = malloc(DEFAULT_FONT_DATA.vfbd_uncompressed_size); 23853630506bSToomas Soome if (fp->vf_bytes == NULL) { 23863630506bSToomas Soome free(fp); 23873630506bSToomas Soome return (NULL); 23883630506bSToomas Soome } 23893630506bSToomas Soome 23903630506bSToomas Soome bp->vfbd_uncompressed_size = 23913630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_uncompressed_size; 23923630506bSToomas Soome bp->vfbd_compressed_size = 23933630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_compressed_size; 23943630506bSToomas Soome 23953630506bSToomas Soome if (lz4_decompress(DEFAULT_FONT_DATA.vfbd_compressed_data, 23963630506bSToomas Soome fp->vf_bytes, 23973630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_compressed_size, 23983630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_uncompressed_size, 0) != 0) { 23993630506bSToomas Soome free(fp->vf_bytes); 24003630506bSToomas Soome free(fp); 24013630506bSToomas Soome return (NULL); 24023630506bSToomas Soome } 24033630506bSToomas Soome 24043630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) { 24053630506bSToomas Soome fp->vf_map_count[i] = 24063630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_font->vf_map_count[i]; 24073630506bSToomas Soome if (builtin_mapping(fp, i) != 0) 24083630506bSToomas Soome goto free_done; 24093630506bSToomas Soome } 24103630506bSToomas Soome 24113630506bSToomas Soome bp->vfbd_font = fp; 24123630506bSToomas Soome return (bp); 24133630506bSToomas Soome } 24143630506bSToomas Soome 24153630506bSToomas Soome fd = open(path, O_RDONLY); 24163630506bSToomas Soome if (fd < 0) 24173630506bSToomas Soome return (NULL); 24183630506bSToomas Soome 24193630506bSToomas Soome size = sizeof(fh); 24203630506bSToomas Soome rv = read(fd, &fh, size); 24213630506bSToomas Soome if (rv < 0 || (size_t)rv != size) { 24223630506bSToomas Soome bp = NULL; 24233630506bSToomas Soome goto done; 24243630506bSToomas Soome } 24253630506bSToomas Soome if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, sizeof(fh.fh_magic)) != 0) { 24263630506bSToomas Soome bp = NULL; 24273630506bSToomas Soome goto done; 24283630506bSToomas Soome } 24293630506bSToomas Soome if ((fp = calloc(1, sizeof(struct vt_font))) == NULL) { 24303630506bSToomas Soome bp = NULL; 24313630506bSToomas Soome goto done; 24323630506bSToomas Soome } 24333630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) 24343630506bSToomas Soome fp->vf_map_count[i] = be32toh(fh.fh_map_count[i]); 24353630506bSToomas Soome 24363630506bSToomas Soome glyphs = be32toh(fh.fh_glyph_count); 24373630506bSToomas Soome fp->vf_width = fh.fh_width; 24383630506bSToomas Soome fp->vf_height = fh.fh_height; 24393630506bSToomas Soome 24403630506bSToomas Soome size = howmany(fp->vf_width, 8) * fp->vf_height * glyphs; 24413630506bSToomas Soome bp->vfbd_uncompressed_size = size; 24423630506bSToomas Soome if ((fp->vf_bytes = malloc(size)) == NULL) 24433630506bSToomas Soome goto free_done; 24443630506bSToomas Soome 24453630506bSToomas Soome rv = read(fd, fp->vf_bytes, size); 24463630506bSToomas Soome if (rv < 0 || (size_t)rv != size) 24473630506bSToomas Soome goto free_done; 24483630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) { 24493630506bSToomas Soome if (load_mapping(fd, fp, i) != 0) 24503630506bSToomas Soome goto free_done; 24513630506bSToomas Soome } 24523630506bSToomas Soome 24533630506bSToomas Soome /* 24543630506bSToomas Soome * Reset builtin flag now as we have full font loaded. 24553630506bSToomas Soome */ 24563630506bSToomas Soome if (fl->font_flags == FONT_BUILTIN) 24573630506bSToomas Soome fl->font_flags = FONT_AUTO; 24583630506bSToomas Soome 24593630506bSToomas Soome /* 24603630506bSToomas Soome * Release previously loaded entries. We can do this now, as 24613630506bSToomas Soome * the new font is loaded. Note, there can be no console 24623630506bSToomas Soome * output till the new font is in place and teken is notified. 24633630506bSToomas Soome * We do need to keep fl->font_data for glyph dimensions. 24643630506bSToomas Soome */ 24653630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 24663630506bSToomas Soome if (fl->font_data->vfbd_font == NULL) 24673630506bSToomas Soome continue; 24683630506bSToomas Soome 24693630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) 24703630506bSToomas Soome free(fl->font_data->vfbd_font->vf_map[i]); 24713630506bSToomas Soome free(fl->font_data->vfbd_font->vf_bytes); 24723630506bSToomas Soome free(fl->font_data->vfbd_font); 24733630506bSToomas Soome fl->font_data->vfbd_font = NULL; 24743630506bSToomas Soome } 24753630506bSToomas Soome 24763630506bSToomas Soome bp->vfbd_font = fp; 24773630506bSToomas Soome bp->vfbd_compressed_size = 0; 24783630506bSToomas Soome 24793630506bSToomas Soome done: 24803630506bSToomas Soome if (fd != -1) 24813630506bSToomas Soome close(fd); 24823630506bSToomas Soome return (bp); 24833630506bSToomas Soome 24843630506bSToomas Soome free_done: 24853630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) 24863630506bSToomas Soome free(fp->vf_map[i]); 24873630506bSToomas Soome free(fp->vf_bytes); 24883630506bSToomas Soome free(fp); 24893630506bSToomas Soome bp = NULL; 24903630506bSToomas Soome goto done; 24913630506bSToomas Soome } 24923630506bSToomas Soome 24933630506bSToomas Soome struct name_entry { 24943630506bSToomas Soome char *n_name; 24953630506bSToomas Soome SLIST_ENTRY(name_entry) n_entry; 24963630506bSToomas Soome }; 24973630506bSToomas Soome 24983630506bSToomas Soome SLIST_HEAD(name_list, name_entry); 24993630506bSToomas Soome 25003630506bSToomas Soome /* Read font names from index file. */ 25013630506bSToomas Soome static struct name_list * 25023630506bSToomas Soome read_list(char *fonts) 25033630506bSToomas Soome { 25043630506bSToomas Soome struct name_list *nl; 25053630506bSToomas Soome struct name_entry *np; 25063630506bSToomas Soome char *dir, *ptr; 25073630506bSToomas Soome char buf[PATH_MAX]; 25083630506bSToomas Soome int fd, len; 25093630506bSToomas Soome 2510313724baSColin Percival TSENTER(); 2511313724baSColin Percival 25123630506bSToomas Soome dir = strdup(fonts); 25133630506bSToomas Soome if (dir == NULL) 25143630506bSToomas Soome return (NULL); 25153630506bSToomas Soome 25163630506bSToomas Soome ptr = strrchr(dir, '/'); 25173630506bSToomas Soome *ptr = '\0'; 25183630506bSToomas Soome 25193630506bSToomas Soome fd = open(fonts, O_RDONLY); 25203630506bSToomas Soome if (fd < 0) 25213630506bSToomas Soome return (NULL); 25223630506bSToomas Soome 25233630506bSToomas Soome nl = malloc(sizeof(*nl)); 25243630506bSToomas Soome if (nl == NULL) { 25253630506bSToomas Soome close(fd); 25263630506bSToomas Soome return (nl); 25273630506bSToomas Soome } 25283630506bSToomas Soome 25293630506bSToomas Soome SLIST_INIT(nl); 25303630506bSToomas Soome while ((len = fgetstr(buf, sizeof (buf), fd)) >= 0) { 25313630506bSToomas Soome if (*buf == '#' || *buf == '\0') 25323630506bSToomas Soome continue; 25333630506bSToomas Soome 25343630506bSToomas Soome if (bcmp(buf, "MENU", 4) == 0) 25353630506bSToomas Soome continue; 25363630506bSToomas Soome 25373630506bSToomas Soome if (bcmp(buf, "FONT", 4) == 0) 25383630506bSToomas Soome continue; 25393630506bSToomas Soome 25403630506bSToomas Soome ptr = strchr(buf, ':'); 25413630506bSToomas Soome if (ptr == NULL) 25423630506bSToomas Soome continue; 25433630506bSToomas Soome else 25443630506bSToomas Soome *ptr = '\0'; 25453630506bSToomas Soome 25463630506bSToomas Soome np = malloc(sizeof(*np)); 25473630506bSToomas Soome if (np == NULL) { 25483630506bSToomas Soome close(fd); 25493630506bSToomas Soome return (nl); /* return what we have */ 25503630506bSToomas Soome } 25513630506bSToomas Soome if (asprintf(&np->n_name, "%s/%s", dir, buf) < 0) { 25523630506bSToomas Soome free(np); 25533630506bSToomas Soome close(fd); 25543630506bSToomas Soome return (nl); /* return what we have */ 25553630506bSToomas Soome } 25563630506bSToomas Soome SLIST_INSERT_HEAD(nl, np, n_entry); 25573630506bSToomas Soome } 25583630506bSToomas Soome close(fd); 2559313724baSColin Percival TSEXIT(); 25603630506bSToomas Soome return (nl); 25613630506bSToomas Soome } 25623630506bSToomas Soome 25633630506bSToomas Soome /* 25643630506bSToomas Soome * Read the font properties and insert new entry into the list. 25653630506bSToomas Soome * The font list is built in descending order. 25663630506bSToomas Soome */ 25673630506bSToomas Soome static bool 25683630506bSToomas Soome insert_font(char *name, FONT_FLAGS flags) 25693630506bSToomas Soome { 25703630506bSToomas Soome struct font_header fh; 25713630506bSToomas Soome struct fontlist *fp, *previous, *entry, *next; 25723630506bSToomas Soome size_t size; 25733630506bSToomas Soome ssize_t rv; 25743630506bSToomas Soome int fd; 25753630506bSToomas Soome char *font_name; 25763630506bSToomas Soome 2577313724baSColin Percival TSENTER(); 2578313724baSColin Percival 25793630506bSToomas Soome font_name = NULL; 25803630506bSToomas Soome if (flags == FONT_BUILTIN) { 25813630506bSToomas Soome /* 25823630506bSToomas Soome * We only install builtin font once, while setting up 25833630506bSToomas Soome * initial console. Since this will happen very early, 25843630506bSToomas Soome * we assume asprintf will not fail. Once we have access to 25853630506bSToomas Soome * files, the builtin font will be replaced by font loaded 25863630506bSToomas Soome * from file. 25873630506bSToomas Soome */ 25883630506bSToomas Soome if (!STAILQ_EMPTY(&fonts)) 25893630506bSToomas Soome return (false); 25903630506bSToomas Soome 25913630506bSToomas Soome fh.fh_width = DEFAULT_FONT_DATA.vfbd_width; 25923630506bSToomas Soome fh.fh_height = DEFAULT_FONT_DATA.vfbd_height; 25933630506bSToomas Soome 25943630506bSToomas Soome (void) asprintf(&font_name, "%dx%d", 25953630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_width, 25963630506bSToomas Soome DEFAULT_FONT_DATA.vfbd_height); 25973630506bSToomas Soome } else { 25983630506bSToomas Soome fd = open(name, O_RDONLY); 25993630506bSToomas Soome if (fd < 0) 26003630506bSToomas Soome return (false); 26013630506bSToomas Soome rv = read(fd, &fh, sizeof(fh)); 26023630506bSToomas Soome close(fd); 26033630506bSToomas Soome if (rv < 0 || (size_t)rv != sizeof(fh)) 26043630506bSToomas Soome return (false); 26053630506bSToomas Soome 26063630506bSToomas Soome if (memcmp(fh.fh_magic, FONT_HEADER_MAGIC, 26073630506bSToomas Soome sizeof(fh.fh_magic)) != 0) 26083630506bSToomas Soome return (false); 26093630506bSToomas Soome font_name = strdup(name); 26103630506bSToomas Soome } 26113630506bSToomas Soome 26123630506bSToomas Soome if (font_name == NULL) 26133630506bSToomas Soome return (false); 26143630506bSToomas Soome 26153630506bSToomas Soome /* 26163630506bSToomas Soome * If we have an entry with the same glyph dimensions, replace 26173630506bSToomas Soome * the file name and mark us. We only support unique dimensions. 26183630506bSToomas Soome */ 26193630506bSToomas Soome STAILQ_FOREACH(entry, &fonts, font_next) { 26203630506bSToomas Soome if (fh.fh_width == entry->font_data->vfbd_width && 26213630506bSToomas Soome fh.fh_height == entry->font_data->vfbd_height) { 26223630506bSToomas Soome free(entry->font_name); 26233630506bSToomas Soome entry->font_name = font_name; 26243630506bSToomas Soome entry->font_flags = FONT_RELOAD; 2625313724baSColin Percival TSEXIT(); 26263630506bSToomas Soome return (true); 26273630506bSToomas Soome } 26283630506bSToomas Soome } 26293630506bSToomas Soome 26303630506bSToomas Soome fp = calloc(sizeof(*fp), 1); 26313630506bSToomas Soome if (fp == NULL) { 26323630506bSToomas Soome free(font_name); 26333630506bSToomas Soome return (false); 26343630506bSToomas Soome } 26353630506bSToomas Soome fp->font_data = calloc(sizeof(*fp->font_data), 1); 26363630506bSToomas Soome if (fp->font_data == NULL) { 26373630506bSToomas Soome free(font_name); 26383630506bSToomas Soome free(fp); 26393630506bSToomas Soome return (false); 26403630506bSToomas Soome } 26413630506bSToomas Soome fp->font_name = font_name; 26423630506bSToomas Soome fp->font_flags = flags; 26433630506bSToomas Soome fp->font_load = load_font; 26443630506bSToomas Soome fp->font_data->vfbd_width = fh.fh_width; 26453630506bSToomas Soome fp->font_data->vfbd_height = fh.fh_height; 26463630506bSToomas Soome 26473630506bSToomas Soome if (STAILQ_EMPTY(&fonts)) { 26483630506bSToomas Soome STAILQ_INSERT_HEAD(&fonts, fp, font_next); 2649313724baSColin Percival TSEXIT(); 26503630506bSToomas Soome return (true); 26513630506bSToomas Soome } 26523630506bSToomas Soome 26533630506bSToomas Soome previous = NULL; 26543630506bSToomas Soome size = fp->font_data->vfbd_width * fp->font_data->vfbd_height; 26553630506bSToomas Soome 26563630506bSToomas Soome STAILQ_FOREACH(entry, &fonts, font_next) { 26573630506bSToomas Soome vt_font_bitmap_data_t *bd; 26583630506bSToomas Soome 26593630506bSToomas Soome bd = entry->font_data; 26603630506bSToomas Soome /* Should fp be inserted before the entry? */ 26613630506bSToomas Soome if (size > bd->vfbd_width * bd->vfbd_height) { 26623630506bSToomas Soome if (previous == NULL) { 26633630506bSToomas Soome STAILQ_INSERT_HEAD(&fonts, fp, font_next); 26643630506bSToomas Soome } else { 26653630506bSToomas Soome STAILQ_INSERT_AFTER(&fonts, previous, fp, 26663630506bSToomas Soome font_next); 26673630506bSToomas Soome } 2668313724baSColin Percival TSEXIT(); 26693630506bSToomas Soome return (true); 26703630506bSToomas Soome } 26713630506bSToomas Soome next = STAILQ_NEXT(entry, font_next); 26723630506bSToomas Soome if (next == NULL || 26733630506bSToomas Soome size > next->font_data->vfbd_width * 26743630506bSToomas Soome next->font_data->vfbd_height) { 26753630506bSToomas Soome STAILQ_INSERT_AFTER(&fonts, entry, fp, font_next); 2676313724baSColin Percival TSEXIT(); 26773630506bSToomas Soome return (true); 26783630506bSToomas Soome } 26793630506bSToomas Soome previous = entry; 26803630506bSToomas Soome } 2681313724baSColin Percival TSEXIT(); 26823630506bSToomas Soome return (true); 26833630506bSToomas Soome } 26843630506bSToomas Soome 26853630506bSToomas Soome static int 26863630506bSToomas Soome font_set(struct env_var *ev __unused, int flags __unused, const void *value) 26873630506bSToomas Soome { 26883630506bSToomas Soome struct fontlist *fl; 26893630506bSToomas Soome char *eptr; 26903630506bSToomas Soome unsigned long x = 0, y = 0; 26913630506bSToomas Soome 26923630506bSToomas Soome /* 26933630506bSToomas Soome * Attempt to extract values from "XxY" string. In case of error, 26943630506bSToomas Soome * we have unmaching glyph dimensions and will just output the 26953630506bSToomas Soome * available values. 26963630506bSToomas Soome */ 26973630506bSToomas Soome if (value != NULL) { 26983630506bSToomas Soome x = strtoul(value, &eptr, 10); 26993630506bSToomas Soome if (*eptr == 'x') 27003630506bSToomas Soome y = strtoul(eptr + 1, &eptr, 10); 27013630506bSToomas Soome } 27023630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 27033630506bSToomas Soome if (fl->font_data->vfbd_width == x && 27043630506bSToomas Soome fl->font_data->vfbd_height == y) 27053630506bSToomas Soome break; 27063630506bSToomas Soome } 27073630506bSToomas Soome if (fl != NULL) { 27083630506bSToomas Soome /* Reset any FONT_MANUAL flag. */ 27093630506bSToomas Soome reset_font_flags(); 27103630506bSToomas Soome 27113630506bSToomas Soome /* Mark this font manually loaded */ 27123630506bSToomas Soome fl->font_flags = FONT_MANUAL; 27133630506bSToomas Soome cons_update_mode(gfx_state.tg_fb_type != FB_TEXT); 27143630506bSToomas Soome return (CMD_OK); 27153630506bSToomas Soome } 27163630506bSToomas Soome 27173630506bSToomas Soome printf("Available fonts:\n"); 27183630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 27193630506bSToomas Soome printf(" %dx%d\n", fl->font_data->vfbd_width, 27203630506bSToomas Soome fl->font_data->vfbd_height); 27213630506bSToomas Soome } 27223630506bSToomas Soome return (CMD_OK); 27233630506bSToomas Soome } 27243630506bSToomas Soome 27253630506bSToomas Soome void 27263630506bSToomas Soome bios_text_font(bool use_vga_font) 27273630506bSToomas Soome { 27283630506bSToomas Soome if (use_vga_font) 27293630506bSToomas Soome (void) insert_font(VGA_8X16_FONT, FONT_MANUAL); 27303630506bSToomas Soome else 27313630506bSToomas Soome (void) insert_font(DEFAULT_8X16_FONT, FONT_MANUAL); 27323630506bSToomas Soome } 27333630506bSToomas Soome 27343630506bSToomas Soome void 27353630506bSToomas Soome autoload_font(bool bios) 27363630506bSToomas Soome { 27373630506bSToomas Soome struct name_list *nl; 27383630506bSToomas Soome struct name_entry *np; 27393630506bSToomas Soome 2740313724baSColin Percival TSENTER(); 2741313724baSColin Percival 27423630506bSToomas Soome nl = read_list("/boot/fonts/INDEX.fonts"); 27433630506bSToomas Soome if (nl == NULL) 27443630506bSToomas Soome return; 27453630506bSToomas Soome 27463630506bSToomas Soome while (!SLIST_EMPTY(nl)) { 27473630506bSToomas Soome np = SLIST_FIRST(nl); 27483630506bSToomas Soome SLIST_REMOVE_HEAD(nl, n_entry); 27493630506bSToomas Soome if (insert_font(np->n_name, FONT_AUTO) == false) 27503630506bSToomas Soome printf("failed to add font: %s\n", np->n_name); 27513630506bSToomas Soome free(np->n_name); 27523630506bSToomas Soome free(np); 27533630506bSToomas Soome } 27543630506bSToomas Soome 27553630506bSToomas Soome /* 27563630506bSToomas Soome * If vga text mode was requested, load vga.font (8x16 bold) font. 27573630506bSToomas Soome */ 27583630506bSToomas Soome if (bios) { 27593630506bSToomas Soome bios_text_font(true); 27603630506bSToomas Soome } 27613630506bSToomas Soome 27623630506bSToomas Soome (void) cons_update_mode(gfx_state.tg_fb_type != FB_TEXT); 2763313724baSColin Percival 2764313724baSColin Percival TSEXIT(); 27653630506bSToomas Soome } 27663630506bSToomas Soome 27673630506bSToomas Soome COMMAND_SET(load_font, "loadfont", "load console font from file", command_font); 27683630506bSToomas Soome 27693630506bSToomas Soome static int 27703630506bSToomas Soome command_font(int argc, char *argv[]) 27713630506bSToomas Soome { 27723630506bSToomas Soome int i, c, rc; 27733630506bSToomas Soome struct fontlist *fl; 27743630506bSToomas Soome vt_font_bitmap_data_t *bd; 27753630506bSToomas Soome bool list; 27763630506bSToomas Soome 27773630506bSToomas Soome list = false; 27783630506bSToomas Soome optind = 1; 27793630506bSToomas Soome optreset = 1; 27803630506bSToomas Soome rc = CMD_OK; 27813630506bSToomas Soome 27823630506bSToomas Soome while ((c = getopt(argc, argv, "l")) != -1) { 27833630506bSToomas Soome switch (c) { 27843630506bSToomas Soome case 'l': 27853630506bSToomas Soome list = true; 27863630506bSToomas Soome break; 27873630506bSToomas Soome case '?': 27883630506bSToomas Soome default: 27893630506bSToomas Soome return (CMD_ERROR); 27903630506bSToomas Soome } 27913630506bSToomas Soome } 27923630506bSToomas Soome 27933630506bSToomas Soome argc -= optind; 27943630506bSToomas Soome argv += optind; 27953630506bSToomas Soome 27963630506bSToomas Soome if (argc > 1 || (list && argc != 0)) { 27973630506bSToomas Soome printf("Usage: loadfont [-l] | [file.fnt]\n"); 27983630506bSToomas Soome return (CMD_ERROR); 27993630506bSToomas Soome } 28003630506bSToomas Soome 28013630506bSToomas Soome if (list) { 28023630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 28033630506bSToomas Soome printf("font %s: %dx%d%s\n", fl->font_name, 28043630506bSToomas Soome fl->font_data->vfbd_width, 28053630506bSToomas Soome fl->font_data->vfbd_height, 28063630506bSToomas Soome fl->font_data->vfbd_font == NULL? "" : " loaded"); 28073630506bSToomas Soome } 28083630506bSToomas Soome return (CMD_OK); 28093630506bSToomas Soome } 28103630506bSToomas Soome 28113630506bSToomas Soome /* Clear scren */ 28123630506bSToomas Soome cons_clear(); 28133630506bSToomas Soome 28143630506bSToomas Soome if (argc == 1) { 28153630506bSToomas Soome char *name = argv[0]; 28163630506bSToomas Soome 28173630506bSToomas Soome if (insert_font(name, FONT_MANUAL) == false) { 28183630506bSToomas Soome printf("loadfont error: failed to load: %s\n", name); 28193630506bSToomas Soome return (CMD_ERROR); 28203630506bSToomas Soome } 28213630506bSToomas Soome 28223630506bSToomas Soome (void) cons_update_mode(gfx_state.tg_fb_type != FB_TEXT); 28233630506bSToomas Soome return (CMD_OK); 28243630506bSToomas Soome } 28253630506bSToomas Soome 28263630506bSToomas Soome if (argc == 0) { 28273630506bSToomas Soome /* 28283630506bSToomas Soome * Walk entire font list, release any loaded font, and set 28293630506bSToomas Soome * autoload flag. The font list does have at least the builtin 28303630506bSToomas Soome * default font. 28313630506bSToomas Soome */ 28323630506bSToomas Soome STAILQ_FOREACH(fl, &fonts, font_next) { 28333630506bSToomas Soome if (fl->font_data->vfbd_font != NULL) { 28343630506bSToomas Soome 28353630506bSToomas Soome bd = fl->font_data; 28363630506bSToomas Soome /* 28373630506bSToomas Soome * Note the setup_font() is releasing 28383630506bSToomas Soome * font bytes. 28393630506bSToomas Soome */ 28403630506bSToomas Soome for (i = 0; i < VFNT_MAPS; i++) 28413630506bSToomas Soome free(bd->vfbd_font->vf_map[i]); 28423630506bSToomas Soome free(fl->font_data->vfbd_font); 28433630506bSToomas Soome fl->font_data->vfbd_font = NULL; 28443630506bSToomas Soome fl->font_data->vfbd_uncompressed_size = 0; 28453630506bSToomas Soome fl->font_flags = FONT_AUTO; 28463630506bSToomas Soome } 28473630506bSToomas Soome } 28483630506bSToomas Soome (void) cons_update_mode(gfx_state.tg_fb_type != FB_TEXT); 28493630506bSToomas Soome } 28503630506bSToomas Soome return (rc); 28513630506bSToomas Soome } 28523630506bSToomas Soome 28533630506bSToomas Soome bool 28543630506bSToomas Soome gfx_get_edid_resolution(struct vesa_edid_info *edid, edid_res_list_t *res) 28553630506bSToomas Soome { 28563630506bSToomas Soome struct resolution *rp, *p; 28573630506bSToomas Soome 28583630506bSToomas Soome /* 28593630506bSToomas Soome * Walk detailed timings tables (4). 28603630506bSToomas Soome */ 28613630506bSToomas Soome if ((edid->display.supported_features 28623630506bSToomas Soome & EDID_FEATURE_PREFERRED_TIMING_MODE) != 0) { 28633630506bSToomas Soome /* Walk detailed timing descriptors (4) */ 28643630506bSToomas Soome for (int i = 0; i < DET_TIMINGS; i++) { 28653630506bSToomas Soome /* 2866b5e0a701SGordon Bergling * Reserved value 0 is not used for display descriptor. 28673630506bSToomas Soome */ 28683630506bSToomas Soome if (edid->detailed_timings[i].pixel_clock == 0) 28693630506bSToomas Soome continue; 28703630506bSToomas Soome if ((rp = malloc(sizeof(*rp))) == NULL) 28713630506bSToomas Soome continue; 28723630506bSToomas Soome rp->width = GET_EDID_INFO_WIDTH(edid, i); 28733630506bSToomas Soome rp->height = GET_EDID_INFO_HEIGHT(edid, i); 28743630506bSToomas Soome if (rp->width > 0 && rp->width <= EDID_MAX_PIXELS && 28753630506bSToomas Soome rp->height > 0 && rp->height <= EDID_MAX_LINES) 28763630506bSToomas Soome TAILQ_INSERT_TAIL(res, rp, next); 28773630506bSToomas Soome else 28783630506bSToomas Soome free(rp); 28793630506bSToomas Soome } 28803630506bSToomas Soome } 28813630506bSToomas Soome 28823630506bSToomas Soome /* 28833630506bSToomas Soome * Walk standard timings list (8). 28843630506bSToomas Soome */ 28853630506bSToomas Soome for (int i = 0; i < STD_TIMINGS; i++) { 28863630506bSToomas Soome /* Is this field unused? */ 28873630506bSToomas Soome if (edid->standard_timings[i] == 0x0101) 28883630506bSToomas Soome continue; 28893630506bSToomas Soome 28903630506bSToomas Soome if ((rp = malloc(sizeof(*rp))) == NULL) 28913630506bSToomas Soome continue; 28923630506bSToomas Soome 28933630506bSToomas Soome rp->width = HSIZE(edid->standard_timings[i]); 28943630506bSToomas Soome switch (RATIO(edid->standard_timings[i])) { 28953630506bSToomas Soome case RATIO1_1: 28963630506bSToomas Soome rp->height = HSIZE(edid->standard_timings[i]); 28973630506bSToomas Soome if (edid->header.version > 1 || 28983630506bSToomas Soome edid->header.revision > 2) { 28993630506bSToomas Soome rp->height = rp->height * 10 / 16; 29003630506bSToomas Soome } 29013630506bSToomas Soome break; 29023630506bSToomas Soome case RATIO4_3: 29033630506bSToomas Soome rp->height = HSIZE(edid->standard_timings[i]) * 3 / 4; 29043630506bSToomas Soome break; 29053630506bSToomas Soome case RATIO5_4: 29063630506bSToomas Soome rp->height = HSIZE(edid->standard_timings[i]) * 4 / 5; 29073630506bSToomas Soome break; 29083630506bSToomas Soome case RATIO16_9: 29093630506bSToomas Soome rp->height = HSIZE(edid->standard_timings[i]) * 9 / 16; 29103630506bSToomas Soome break; 29113630506bSToomas Soome } 29123630506bSToomas Soome 29133630506bSToomas Soome /* 29143630506bSToomas Soome * Create resolution list in decreasing order, except keep 29153630506bSToomas Soome * first entry (preferred timing mode). 29163630506bSToomas Soome */ 29173630506bSToomas Soome TAILQ_FOREACH(p, res, next) { 29183630506bSToomas Soome if (p->width * p->height < rp->width * rp->height) { 29193630506bSToomas Soome /* Keep preferred mode first */ 29203630506bSToomas Soome if (TAILQ_FIRST(res) == p) 29213630506bSToomas Soome TAILQ_INSERT_AFTER(res, p, rp, next); 29223630506bSToomas Soome else 29233630506bSToomas Soome TAILQ_INSERT_BEFORE(p, rp, next); 29243630506bSToomas Soome break; 29253630506bSToomas Soome } 29263630506bSToomas Soome if (TAILQ_NEXT(p, next) == NULL) { 29273630506bSToomas Soome TAILQ_INSERT_TAIL(res, rp, next); 29283630506bSToomas Soome break; 29293630506bSToomas Soome } 29303630506bSToomas Soome } 29313630506bSToomas Soome } 29323630506bSToomas Soome return (!TAILQ_EMPTY(res)); 29333630506bSToomas Soome } 293418968b82SWarner Losh 293518968b82SWarner Losh vm_offset_t 293618968b82SWarner Losh build_font_module(vm_offset_t addr) 293718968b82SWarner Losh { 293818968b82SWarner Losh vt_font_bitmap_data_t *bd; 293918968b82SWarner Losh struct vt_font *fd; 294018968b82SWarner Losh struct preloaded_file *fp; 294118968b82SWarner Losh size_t size; 294218968b82SWarner Losh uint32_t checksum; 294318968b82SWarner Losh int i; 294418968b82SWarner Losh struct font_info fi; 294518968b82SWarner Losh struct fontlist *fl; 294618968b82SWarner Losh uint64_t fontp; 294718968b82SWarner Losh 294818968b82SWarner Losh if (STAILQ_EMPTY(&fonts)) 294918968b82SWarner Losh return (addr); 295018968b82SWarner Losh 295118968b82SWarner Losh /* We can't load first */ 295218968b82SWarner Losh if ((file_findfile(NULL, NULL)) == NULL) { 295318968b82SWarner Losh printf("Can not load font module: %s\n", 295418968b82SWarner Losh "the kernel is not loaded"); 295518968b82SWarner Losh return (addr); 295618968b82SWarner Losh } 295718968b82SWarner Losh 295818968b82SWarner Losh /* helper pointers */ 295918968b82SWarner Losh bd = NULL; 296018968b82SWarner Losh STAILQ_FOREACH(fl, &fonts, font_next) { 296118968b82SWarner Losh if (gfx_state.tg_font.vf_width == fl->font_data->vfbd_width && 296218968b82SWarner Losh gfx_state.tg_font.vf_height == fl->font_data->vfbd_height) { 296318968b82SWarner Losh /* 296418968b82SWarner Losh * Kernel does have better built in font. 296518968b82SWarner Losh */ 296618968b82SWarner Losh if (fl->font_flags == FONT_BUILTIN) 296718968b82SWarner Losh return (addr); 296818968b82SWarner Losh 296918968b82SWarner Losh bd = fl->font_data; 297018968b82SWarner Losh break; 297118968b82SWarner Losh } 297218968b82SWarner Losh } 297318968b82SWarner Losh if (bd == NULL) 297418968b82SWarner Losh return (addr); 297518968b82SWarner Losh fd = bd->vfbd_font; 297618968b82SWarner Losh 297718968b82SWarner Losh fi.fi_width = fd->vf_width; 297818968b82SWarner Losh checksum = fi.fi_width; 297918968b82SWarner Losh fi.fi_height = fd->vf_height; 298018968b82SWarner Losh checksum += fi.fi_height; 298118968b82SWarner Losh fi.fi_bitmap_size = bd->vfbd_uncompressed_size; 298218968b82SWarner Losh checksum += fi.fi_bitmap_size; 298318968b82SWarner Losh 298418968b82SWarner Losh size = roundup2(sizeof (struct font_info), 8); 298518968b82SWarner Losh for (i = 0; i < VFNT_MAPS; i++) { 298618968b82SWarner Losh fi.fi_map_count[i] = fd->vf_map_count[i]; 298718968b82SWarner Losh checksum += fi.fi_map_count[i]; 298818968b82SWarner Losh size += fd->vf_map_count[i] * sizeof (struct vfnt_map); 298918968b82SWarner Losh size += roundup2(size, 8); 299018968b82SWarner Losh } 299118968b82SWarner Losh size += bd->vfbd_uncompressed_size; 299218968b82SWarner Losh 299318968b82SWarner Losh fi.fi_checksum = -checksum; 299418968b82SWarner Losh 299586077f4fSAhmad Khalifa fp = file_findfile(NULL, md_kerntype); 299618968b82SWarner Losh if (fp == NULL) 299718968b82SWarner Losh panic("can't find kernel file"); 299818968b82SWarner Losh 299918968b82SWarner Losh fontp = addr; 300018968b82SWarner Losh addr += archsw.arch_copyin(&fi, addr, sizeof (struct font_info)); 300118968b82SWarner Losh addr = roundup2(addr, 8); 300218968b82SWarner Losh 300318968b82SWarner Losh /* Copy maps. */ 300418968b82SWarner Losh for (i = 0; i < VFNT_MAPS; i++) { 300518968b82SWarner Losh if (fd->vf_map_count[i] != 0) { 300618968b82SWarner Losh addr += archsw.arch_copyin(fd->vf_map[i], addr, 300718968b82SWarner Losh fd->vf_map_count[i] * sizeof (struct vfnt_map)); 300818968b82SWarner Losh addr = roundup2(addr, 8); 300918968b82SWarner Losh } 301018968b82SWarner Losh } 301118968b82SWarner Losh 301218968b82SWarner Losh /* Copy the bitmap. */ 301318968b82SWarner Losh addr += archsw.arch_copyin(fd->vf_bytes, addr, fi.fi_bitmap_size); 301418968b82SWarner Losh 301518968b82SWarner Losh /* Looks OK so far; populate control structure */ 301618968b82SWarner Losh file_addmetadata(fp, MODINFOMD_FONT, sizeof(fontp), &fontp); 301718968b82SWarner Losh return (addr); 301818968b82SWarner Losh } 301900460cc8SEmmanuel Vadot 302000460cc8SEmmanuel Vadot vm_offset_t 302100460cc8SEmmanuel Vadot build_splash_module(vm_offset_t addr) 302200460cc8SEmmanuel Vadot { 302300460cc8SEmmanuel Vadot struct preloaded_file *fp; 302400460cc8SEmmanuel Vadot struct splash_info si; 302500460cc8SEmmanuel Vadot const char *splash; 302600460cc8SEmmanuel Vadot png_t png; 302700460cc8SEmmanuel Vadot uint64_t splashp; 302800460cc8SEmmanuel Vadot int error; 302900460cc8SEmmanuel Vadot 303000460cc8SEmmanuel Vadot /* We can't load first */ 303100460cc8SEmmanuel Vadot if ((file_findfile(NULL, NULL)) == NULL) { 303200460cc8SEmmanuel Vadot printf("Can not load splash module: %s\n", 303300460cc8SEmmanuel Vadot "the kernel is not loaded"); 303400460cc8SEmmanuel Vadot return (addr); 303500460cc8SEmmanuel Vadot } 303600460cc8SEmmanuel Vadot 303786077f4fSAhmad Khalifa fp = file_findfile(NULL, md_kerntype); 303800460cc8SEmmanuel Vadot if (fp == NULL) 303900460cc8SEmmanuel Vadot panic("can't find kernel file"); 304000460cc8SEmmanuel Vadot 304100460cc8SEmmanuel Vadot splash = getenv("splash"); 304200460cc8SEmmanuel Vadot if (splash == NULL) 304300460cc8SEmmanuel Vadot return (addr); 304400460cc8SEmmanuel Vadot 304500460cc8SEmmanuel Vadot /* Parse png */ 304600460cc8SEmmanuel Vadot if ((error = png_open(&png, splash)) != PNG_NO_ERROR) { 304700460cc8SEmmanuel Vadot return (addr); 304800460cc8SEmmanuel Vadot } 304900460cc8SEmmanuel Vadot 305000460cc8SEmmanuel Vadot si.si_width = png.width; 305100460cc8SEmmanuel Vadot si.si_height = png.height; 305200460cc8SEmmanuel Vadot si.si_depth = png.bpp; 305300460cc8SEmmanuel Vadot splashp = addr; 305400460cc8SEmmanuel Vadot addr += archsw.arch_copyin(&si, addr, sizeof (struct splash_info)); 305500460cc8SEmmanuel Vadot addr = roundup2(addr, 8); 305600460cc8SEmmanuel Vadot 305700460cc8SEmmanuel Vadot /* Copy the bitmap. */ 305800460cc8SEmmanuel Vadot addr += archsw.arch_copyin(png.image, addr, png.png_datalen); 305900460cc8SEmmanuel Vadot 306000460cc8SEmmanuel Vadot printf("Loading splash ok\n"); 306100460cc8SEmmanuel Vadot file_addmetadata(fp, MODINFOMD_SPLASH, sizeof(splashp), &splashp); 306200460cc8SEmmanuel Vadot return (addr); 306300460cc8SEmmanuel Vadot } 3064