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
gfx_framework_init(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 *
gfx_get_fb_address(void)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
gfx_parse_mode_str(char * str,int * x,int * y,int * depth)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
rgb_color_map(uint8_t index,uint32_t rmax,int roffset,uint32_t gmax,int goffset,uint32_t bmax,int boffset)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
gfx_fb_color_map(uint8_t index)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
rgb_to_color_index(uint8_t r,uint8_t g,uint8_t b)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
generate_cons_palette(uint32_t * palette,int format,uint32_t rmax,int roffset,uint32_t gmax,int goffset,uint32_t bmax,int boffset)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
gfx_mem_wr1(uint8_t * base,size_t size,uint32_t o,uint8_t v)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
gfx_mem_wr2(uint8_t * base,size_t size,uint32_t o,uint16_t v)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
gfx_mem_wr4(uint8_t * base,size_t size,uint32_t o,uint32_t v)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
gfxfb_blt_fill(void * BltBuffer,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height)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
gfxfb_blt_video_to_buffer(void * BltBuffer,uint32_t SourceX,uint32_t SourceY,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height,uint32_t Delta)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
gfxfb_blt_buffer_to_video(void * BltBuffer,uint32_t SourceX,uint32_t SourceY,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height,uint32_t Delta)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
gfxfb_blt_video_to_video(uint32_t SourceX,uint32_t SourceY,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height)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
gfxfb_shadow_fill(uint32_t * BltBuffer,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height)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
gfxfb_blt(void * BltBuffer,GFXFB_BLT_OPERATION BltOperation,uint32_t SourceX,uint32_t SourceY,uint32_t DestinationX,uint32_t DestinationY,uint32_t Width,uint32_t Height,uint32_t Delta)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
gfx_bitblt_bitmap(teken_gfx_t * state,const uint8_t * glyph,const teken_attr_t * a,uint32_t alpha,bool cursor)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
gfx_fb_printchar(teken_gfx_t * state,const teken_pos_t * p)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
gfx_fb_putchar(void * arg,const teken_pos_t * p,teken_char_t c,const teken_attr_t * a)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
gfx_fb_fill(void * arg,const teken_rect_t * r,teken_char_t c,const teken_attr_t * a)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
gfx_fb_cursor_draw(teken_gfx_t * state,const teken_pos_t * pos,bool on)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
gfx_fb_cursor(void * arg,const teken_pos_t * p)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
gfx_fb_param(void * arg,int cmd,unsigned int value)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
is_same_pixel(struct text_pixel * px1,struct text_pixel * px2)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
gfx_fb_copy_area(teken_gfx_t * state,const teken_rect_t * s,const teken_pos_t * d)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
gfx_fb_copy_line(teken_gfx_t * state,int ncol,teken_pos_t * s,teken_pos_t * d)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
gfx_fb_copy(void * arg,const teken_rect_t * r,const teken_pos_t * p)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
alpha_blend(uint8_t fg,uint8_t bg,uint8_t alpha)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
bitmap_cpy(void * dst,void * src,uint32_t size)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 *
allocate_glyphbuffer(uint32_t width,uint32_t height)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
gfx_fb_cons_display(uint32_t x,uint32_t y,uint32_t width,uint32_t height,void * data)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
isqrt(int num)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
gfx_fb_getcolor(void)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
gfx_fb_setpixel(uint32_t x,uint32_t y)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
gfx_fb_drawrect(uint32_t x1,uint32_t y1,uint32_t x2,uint32_t y2,uint32_t fill)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
gfx_fb_line(uint32_t x0,uint32_t y0,uint32_t x1,uint32_t y1,uint32_t wd)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
gfx_fb_bezier(uint32_t x0,uint32_t y0,uint32_t x1,uint32_t y1,uint32_t x2,uint32_t y2,uint32_t wd)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
gfx_term_drawrect(uint32_t ux1,uint32_t uy1,uint32_t ux2,uint32_t uy2)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
gfx_fb_putimage(png_t * png,uint32_t ux1,uint32_t uy1,uint32_t ux2,uint32_t uy2,uint32_t flags)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
reset_font_flags(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
edid_diagonal_squared(void)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
gfx_get_ppi(void)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 *
gfx_get_font(void)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 *
set_font(teken_unit_t * rows,teken_unit_t * cols,teken_unit_t h,teken_unit_t w)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
cons_clear(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
setup_font(teken_gfx_t * state,teken_unit_t height,teken_unit_t width)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
font_bisearch(const vfnt_map_t * map,uint32_t len,teken_char_t src)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 *
font_lookup(const struct vt_font * vf,teken_char_t c,const teken_attr_t * a)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
load_mapping(int fd,struct vt_font * fp,int n)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
builtin_mapping(struct vt_font * fp,int n)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 *
load_font(char * path)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 *
read_list(char * fonts)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
insert_font(char * name,FONT_FLAGS flags)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
font_set(struct env_var * ev __unused,int flags __unused,const void * value)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
bios_text_font(bool use_vga_font)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
autoload_font(bool bios)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
command_font(int argc,char * argv[])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
gfx_get_edid_resolution(struct vesa_edid_info * edid,edid_res_list_t * res)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
build_font_module(vm_offset_t addr)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
build_splash_module(vm_offset_t addr)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