git: 3630506b9dae - main - loader: implement framebuffer console

Toomas Soome tsoome at FreeBSD.org
Sat Jan 2 20:09:25 UTC 2021


The branch main has been updated by tsoome:

URL: https://cgit.FreeBSD.org/src/commit/?id=3630506b9daec9167a89bc4525638ea45a00769e

commit 3630506b9daec9167a89bc4525638ea45a00769e
Author:     Toomas Soome <tsoome at FreeBSD.org>
AuthorDate: 2020-12-21 05:31:16 +0000
Commit:     Toomas Soome <tsoome at FreeBSD.org>
CommitDate: 2021-01-02 19:41:36 +0000

    loader: implement framebuffer console
    
    Draw console on efi.
    Add vbe framebuffer for BIOS loader (vbe off, vbe on, vbe list,
    vbe set xxx).
    autoload font (/boot/fonts) based on resolution and font size.
    Add command loadfont (set font by file) and
    variable screen.font (set font by size). Pass loaded font to kernel.
    
    Export variables:
    screen.height
    screen.width
    screen.depth
    
    Add gfx primitives to draw the screen and put png image on the screen.
    Rework menu draw to iterate list of consoles to enamble device specific
    output.
    
    Probably something else I forgot...
    
    Relnotes: yes
    Differential Revision: https://reviews.freebsd.org/D27420
---
 stand/Makefile                          |    2 +
 stand/common/bootstrap.h                |    5 +
 stand/common/gfx_fb.c                   | 2641 +++++++++++++++++++++++++++++++
 stand/common/gfx_fb.h                   |  274 ++++
 stand/common/module.c                   |   89 +-
 stand/defaults/loader.conf.5            |    4 +-
 stand/efi/include/efilib.h              |    1 -
 stand/efi/libefi/Makefile               |    2 +-
 stand/efi/libefi/efi_console.c          |  484 ++++--
 stand/efi/loader/Makefile               |   14 +-
 stand/efi/loader/bootinfo.c             |   17 +-
 stand/efi/loader/framebuffer.c          |   15 +-
 stand/efi/loader/main.c                 |    3 +-
 stand/ficl.mk                           |    2 +-
 stand/ficl/Makefile                     |    2 +
 stand/ficl/loader.c                     |  185 +++
 stand/fonts/INDEX.fonts                 |   66 +
 stand/fonts/Makefile                    |   81 +
 stand/forth/beastie.4th                 |    4 +
 stand/forth/brand-fbsd.4th              |   12 +
 stand/forth/brand.4th                   |    4 +
 stand/forth/color.4th                   |   12 +-
 stand/forth/frames.4th                  |   14 +
 stand/forth/logo-orb.4th                |   12 +
 stand/forth/menu.4th                    |   34 +-
 stand/forth/support.4th                 |   91 +-
 stand/i386/libi386/Makefile             |    9 +-
 stand/i386/libi386/bootinfo.c           |   11 +
 stand/i386/libi386/bootinfo32.c         |    3 +
 stand/i386/libi386/bootinfo64.c         |    3 +
 stand/i386/libi386/libi386.h            |    1 +
 stand/i386/libi386/vbe.c                | 1226 ++++++++++++++
 stand/i386/libi386/vbe.h                |  163 ++
 stand/i386/libi386/vidconsole.c         |  659 ++++++--
 stand/i386/loader/Makefile              |   13 +-
 stand/i386/loader/main.c                |   10 +-
 stand/images/Makefile                   |    9 +
 stand/images/freebsd-brand-rev.png      |  Bin 0 -> 7709 bytes
 stand/images/freebsd-brand.png          |  Bin 0 -> 13788 bytes
 stand/images/freebsd-logo-rev.png       |  Bin 0 -> 43898 bytes
 stand/liblua/Makefile                   |    2 +
 stand/liblua/lutils.c                   |  192 +++
 stand/loader.mk                         |    6 +
 stand/lua/color.lua                     |    2 +-
 stand/lua/core.lua                      |   13 +
 stand/lua/drawer.lua                    |   61 +-
 stand/lua/gfx-orb.lua                   |    4 +-
 stand/userboot/userboot/Makefile        |    1 +
 stand/userboot/userboot/userboot_cons.c |    5 +
 sys/sys/font.h                          |    7 +-
 sys/teken/teken.h                       |    1 +
 51 files changed, 6070 insertions(+), 401 deletions(-)

diff --git a/stand/Makefile b/stand/Makefile
index 46e0856e45fd..7b871d9164db 100644
--- a/stand/Makefile
+++ b/stand/Makefile
@@ -25,6 +25,8 @@ S.${MK_FORTH}+=		forth
 S.${MK_LOADER_LUA}+=	liblua
 S.${MK_LOADER_LUA}+=	lua
 S.yes+=			defaults
+S.yes+=			fonts
+S.yes+=			images
 S.yes+=			man
 
 .if ${MK_FORTH} != "no"
diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h
index a0640c2bac2c..f671dba96e63 100644
--- a/stand/common/bootstrap.h
+++ b/stand/common/bootstrap.h
@@ -32,6 +32,7 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/linker_set.h>
+#include <stdbool.h>
 
 #include "readin.h"
 
@@ -119,6 +120,8 @@ struct console
 };
 extern struct console *consoles[];
 void cons_probe(void);
+bool		cons_update_mode(bool);
+void		autoload_font(bool);
 
 /*
  * Plug-and-play enumerator/configurator interface.
@@ -258,6 +261,8 @@ int file_addmodule(struct preloaded_file *, char *, int,
     struct kernel_module **);
 void file_removemetadata(struct preloaded_file *fp);
 
+vm_offset_t build_font_module(vm_offset_t);
+
 /* MI module loaders */
 #ifdef __elfN
 /* Relocation types. */
diff --git a/stand/common/gfx_fb.c b/stand/common/gfx_fb.c
new file mode 100644
index 000000000000..f73899c50525
--- /dev/null
+++ b/stand/common/gfx_fb.c
@@ -0,0 +1,2641 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2020 Toomas Soome
+ * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2020 RackTop Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <stand.h>
+#include <teken.h>
+#include <gfx_fb.h>
+#include <sys/font.h>
+#include <sys/stdint.h>
+#include <sys/endian.h>
+#include <pnglite.h>
+#include <bootstrap.h>
+#include <lz4.h>
+#if defined(EFI)
+#include <efi.h>
+#include <efilib.h>
+#else
+#include <vbe.h>
+#endif
+
+/* VGA text mode does use bold font. */
+#if !defined(VGA_8X16_FONT)
+#define	VGA_8X16_FONT		"/boot/fonts/8x16v.fnt"
+#endif
+#if !defined(DEFAULT_8X16_FONT)
+#define	DEFAULT_8X16_FONT	"/boot/fonts/8x16.fnt"
+#endif
+
+/*
+ * Must be sorted by font size in descending order
+ */
+font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
+
+#define	DEFAULT_FONT_DATA	font_data_8x16
+extern vt_font_bitmap_data_t	font_data_8x16;
+teken_gfx_t gfx_state = { 0 };
+
+static struct {
+	unsigned char r;	/* Red percentage value. */
+	unsigned char g;	/* Green percentage value. */
+	unsigned char b;	/* Blue percentage value. */
+} color_def[NCOLORS] = {
+	{0,	0,	0},	/* black */
+	{50,	0,	0},	/* dark red */
+	{0,	50,	0},	/* dark green */
+	{77,	63,	0},	/* dark yellow */
+	{20,	40,	64},	/* dark blue */
+	{50,	0,	50},	/* dark magenta */
+	{0,	50,	50},	/* dark cyan */
+	{75,	75,	75},	/* light gray */
+
+	{18,	20,	21},	/* dark gray */
+	{100,	0,	0},	/* light red */
+	{0,	100,	0},	/* light green */
+	{100,	100,	0},	/* light yellow */
+	{45,	62,	81},	/* light blue */
+	{100,	0,	100},	/* light magenta */
+	{0,	100,	100},	/* light cyan */
+	{100,	100,	100},	/* white */
+};
+uint32_t cmap[NCMAP];
+
+/*
+ * Between console's palette and VGA's one:
+ *  - blue and red are swapped (1 <-> 4)
+ *  - yellow and cyan are swapped (3 <-> 6)
+ */
+const int cons_to_vga_colors[NCOLORS] = {
+	0,  4,  2,  6,  1,  5,  3,  7,
+	8, 12, 10, 14,  9, 13, 11, 15
+};
+
+static const int vga_to_cons_colors[NCOLORS] = {
+	0,  1,  2,  3,  4,  5,  6,  7,
+	8,  9, 10, 11,  12, 13, 14, 15
+};
+
+struct text_pixel *screen_buffer;
+#if defined(EFI)
+static EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GlyphBuffer;
+#else
+static struct paletteentry *GlyphBuffer;
+#endif
+static size_t GlyphBufferSize;
+
+static bool insert_font(char *, FONT_FLAGS);
+static int font_set(struct env_var *, int, const void *);
+static void * allocate_glyphbuffer(uint32_t, uint32_t);
+static void gfx_fb_cursor_draw(teken_gfx_t *, const teken_pos_t *, bool);
+
+/*
+ * Initialize gfx framework.
+ */
+void
+gfx_framework_init(void)
+{
+	/*
+	 * Setup font list to have builtin font.
+	 */
+	(void) insert_font(NULL, FONT_BUILTIN);
+}
+
+static uint8_t *
+gfx_get_fb_address(void)
+{
+	return (ptov((uint32_t)gfx_state.tg_fb.fb_addr));
+}
+
+/*
+ * Utility function to parse gfx mode line strings.
+ */
+bool
+gfx_parse_mode_str(char *str, int *x, int *y, int *depth)
+{
+	char *p, *end;
+
+	errno = 0;
+	p = str;
+	*x = strtoul(p, &end, 0);
+	if (*x == 0 || errno != 0)
+		return (false);
+	if (*end != 'x')
+		return (false);
+	p = end + 1;
+	*y = strtoul(p, &end, 0);
+	if (*y == 0 || errno != 0)
+		return (false);
+	if (*end != 'x') {
+		*depth = -1;    /* auto select */
+	} else {
+		p = end + 1;
+		*depth = strtoul(p, &end, 0);
+		if (*depth == 0 || errno != 0 || *end != '\0')
+			return (false);
+	}
+
+	return (true);
+}
+
+static uint32_t
+rgb_color_map(uint8_t index, uint32_t rmax, int roffset,
+    uint32_t gmax, int goffset, uint32_t bmax, int boffset)
+{
+	uint32_t color, code, gray, level;
+
+	if (index < NCOLORS) {
+#define	CF(_f, _i) ((_f ## max * color_def[(_i)]._f / 100) << _f ## offset)
+		return (CF(r, index) | CF(g, index) | CF(b, index));
+#undef  CF
+        }
+
+#define	CF(_f, _c) ((_f ## max & _c) << _f ## offset)
+        /* 6x6x6 color cube */
+        if (index > 15 && index < 232) {
+                uint32_t red, green, blue;
+
+                for (red = 0; red < 6; red++) {
+                        for (green = 0; green < 6; green++) {
+                                for (blue = 0; blue < 6; blue++) {
+                                        code = 16 + (red * 36) +
+                                            (green * 6) + blue;
+                                        if (code != index)
+                                                continue;
+                                        red = red ? (red * 40 + 55) : 0;
+                                        green = green ? (green * 40 + 55) : 0;
+                                        blue = blue ? (blue * 40 + 55) : 0;
+                                        color = CF(r, red);
+					color |= CF(g, green);
+					color |= CF(b, blue);
+					return (color);
+                                }
+                        }
+                }
+        }
+
+        /* colors 232-255 are a grayscale ramp */
+        for (gray = 0; gray < 24; gray++) {
+                level = (gray * 10) + 8;
+                code = 232 + gray;
+                if (code == index)
+                        break;
+        }
+        return (CF(r, level) | CF(g, level) | CF(b, level));
+#undef  CF
+}
+
+/*
+ * Support for color mapping.
+ * For 8, 24 and 32 bit depth, use mask size 8.
+ * 15/16 bit depth needs to use mask size from mode,
+ * or we will lose color information from 32-bit to 15/16 bit translation.
+ */
+uint32_t
+gfx_fb_color_map(uint8_t index)
+{
+	int rmask, gmask, bmask;
+	int roff, goff, boff, bpp;
+
+	roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
+        goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
+        boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
+	bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3;
+
+	if (bpp == 2)
+		rmask = gfx_state.tg_fb.fb_mask_red >> roff;
+	else
+		rmask = 0xff;
+
+	if (bpp == 2)
+		gmask = gfx_state.tg_fb.fb_mask_green >> goff;
+	else
+		gmask = 0xff;
+
+	if (bpp == 2)
+		bmask = gfx_state.tg_fb.fb_mask_blue >> boff;
+	else
+		bmask = 0xff;
+
+	return (rgb_color_map(index, rmask, 16, gmask, 8, bmask, 0));
+}
+
+/* Get indexed color */
+static uint8_t
+rgb_to_color_index(uint8_t r, uint8_t g, uint8_t b)
+{
+#if !defined(EFI)
+	uint32_t color, best, dist, k;
+	int diff;
+
+	color = 0;
+	best = NCMAP * NCMAP * NCMAP;
+	for (k = 0; k < NCMAP; k++) {
+		diff = r - pe8[k].Red;
+		dist = diff * diff;
+		diff = g - pe8[k].Green;
+		dist += diff * diff;
+		diff = b - pe8[k].Blue;
+		dist += diff * diff;
+
+		if (dist == 0)
+			break;
+		if (dist < best) {
+			color = k;
+			best = dist;
+		}
+	}
+	if (k == NCMAP)
+		k = color;
+	return (k);
+#else
+	(void) r;
+	(void) g;
+	(void) b;
+	return (0);
+#endif
+}
+
+int
+generate_cons_palette(uint32_t *palette, int format,
+    uint32_t rmax, int roffset, uint32_t gmax, int goffset,
+    uint32_t bmax, int boffset)
+{
+	int i;
+
+	switch (format) {
+	case COLOR_FORMAT_VGA:
+		for (i = 0; i < NCOLORS; i++)
+			palette[i] = cons_to_vga_colors[i];
+		for (; i < NCMAP; i++)
+			palette[i] = i;
+		break;
+	case COLOR_FORMAT_RGB:
+		for (i = 0; i < NCMAP; i++)
+			palette[i] = rgb_color_map(i, rmax, roffset,
+			    gmax, goffset, bmax, boffset);
+		break;
+	default:
+		return (ENODEV);
+	}
+
+	return (0);
+}
+
+static void
+gfx_mem_wr1(uint8_t *base, size_t size, uint32_t o, uint8_t v)
+{
+
+	if (o >= size)
+		return;
+	*(uint8_t *)(base + o) = v;
+}
+
+static void
+gfx_mem_wr2(uint8_t *base, size_t size, uint32_t o, uint16_t v)
+{
+
+	if (o >= size)
+		return;
+	*(uint16_t *)(base + o) = v;
+}
+
+static void
+gfx_mem_wr4(uint8_t *base, size_t size, uint32_t o, uint32_t v)
+{
+
+	if (o >= size)
+		return;
+	*(uint32_t *)(base + o) = v;
+}
+
+/* Our GFX Block transfer toolkit. */
+static int gfxfb_blt_fill(void *BltBuffer,
+    uint32_t DestinationX, uint32_t DestinationY,
+    uint32_t Width, uint32_t Height)
+{
+#if defined(EFI)
+	EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p;
+#else
+	struct paletteentry *p;
+#endif
+	uint32_t data, bpp, pitch, y, x;
+	int roff, goff, boff;
+	size_t size;
+	off_t off;
+	uint8_t *destination;
+
+	if (BltBuffer == NULL)
+		return (EINVAL);
+
+	if (DestinationY + Height > gfx_state.tg_fb.fb_height)
+		return (EINVAL);
+
+	if (DestinationX + Width > gfx_state.tg_fb.fb_width)
+		return (EINVAL);
+
+	if (Width == 0 || Height == 0)
+		return (EINVAL);
+
+	p = BltBuffer;
+	roff = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
+	goff = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
+	boff = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
+
+	if (gfx_state.tg_fb.fb_bpp == 8) {
+		data = rgb_to_color_index(p->Red, p->Green, p->Blue);
+	} else {
+		data = (p->Red &
+		    (gfx_state.tg_fb.fb_mask_red >> roff)) << roff;
+		data |= (p->Green &
+		    (gfx_state.tg_fb.fb_mask_green >> goff)) << goff;
+		data |= (p->Blue &
+		    (gfx_state.tg_fb.fb_mask_blue >> boff)) << boff;
+	}
+
+	bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3;
+	pitch = gfx_state.tg_fb.fb_stride * bpp;
+	destination = gfx_get_fb_address();
+	size = gfx_state.tg_fb.fb_size;
+
+	for (y = DestinationY; y < Height + DestinationY; y++) {
+		off = y * pitch + DestinationX * bpp;
+		for (x = 0; x < Width; x++) {
+			switch (bpp) {
+			case 1:
+				gfx_mem_wr1(destination, size, off,
+				    (data < NCOLORS) ?
+				    cons_to_vga_colors[data] : data);
+				break;
+			case 2:
+				gfx_mem_wr2(destination, size, off, data);
+				break;
+			case 3:
+				gfx_mem_wr1(destination, size, off,
+				    (data >> 16) & 0xff);
+				gfx_mem_wr1(destination, size, off + 1,
+				    (data >> 8) & 0xff);
+				gfx_mem_wr1(destination, size, off + 2,
+				    data & 0xff);
+				break;
+			case 4:
+				gfx_mem_wr4(destination, size, off, data);
+				break;
+			}
+			off += bpp;
+		}
+	}
+
+	return (0);
+}
+
+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)
+{
+#if defined(EFI)
+	EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p;
+#else
+	struct paletteentry *p;
+#endif
+	uint32_t x, sy, dy;
+	uint32_t bpp, pitch, copybytes;
+	off_t off;
+	uint8_t *source, *destination, *buffer, *sb;
+	uint8_t rm, rp, gm, gp, bm, bp;
+	bool bgra;
+
+	if (BltBuffer == NULL)
+		return (EINVAL);
+
+	if (SourceY + Height >
+	    gfx_state.tg_fb.fb_height)
+		return (EINVAL);
+
+	if (SourceX + Width > gfx_state.tg_fb.fb_width)
+		return (EINVAL);
+
+	if (Width == 0 || Height == 0)
+		return (EINVAL);
+
+	if (Delta == 0)
+		Delta = Width * sizeof (*p);
+
+	bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3;
+	pitch = gfx_state.tg_fb.fb_stride * bpp;
+
+	copybytes = Width * bpp;
+
+	rp = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
+	gp = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
+	bp = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
+	rm = gfx_state.tg_fb.fb_mask_red >> rp;
+	gm = gfx_state.tg_fb.fb_mask_green >> gp;
+	bm = gfx_state.tg_fb.fb_mask_blue >> bp;
+
+	/* If FB pixel format is BGRA, we can use direct copy. */
+	bgra = bpp == 4 &&
+	    ffs(rm) - 1 == 8 && rp == 16 &&
+	    ffs(gm) - 1 == 8 && gp == 8 &&
+	    ffs(bm) - 1 == 8 && bp == 0;
+
+	if (bgra) {
+		buffer = NULL;
+	} else {
+		buffer = malloc(copybytes);
+		if (buffer == NULL)
+			return (ENOMEM);
+	}
+
+	for (sy = SourceY, dy = DestinationY; dy < Height + DestinationY;
+	    sy++, dy++) {
+		off = sy * pitch + SourceX * bpp;
+		source = gfx_get_fb_address() + off;
+
+		if (bgra) {
+			destination = (uint8_t *)BltBuffer + dy * Delta +
+			    DestinationX * sizeof (*p);
+		} else {
+			destination = buffer;
+		}
+
+		bcopy(source, destination, copybytes);
+
+		if (!bgra) {
+			for (x = 0; x < Width; x++) {
+				uint32_t c = 0;
+
+				p = (void *)((uint8_t *)BltBuffer +
+				    dy * Delta +
+				    (DestinationX + x) * sizeof (*p));
+				sb = buffer + x * bpp;
+				switch (bpp) {
+				case 1:
+					c = *sb;
+					break;
+				case 2:
+					c = *(uint16_t *)sb;
+					break;
+				case 3:
+					c = sb[0] << 16 | sb[1] << 8 | sb[2];
+					break;
+				case 4:
+					c = *(uint32_t *)sb;
+					break;
+				}
+
+				if (bpp == 1) {
+					*(uint32_t *)p = gfx_fb_color_map(
+					    (c < 16) ?
+					    vga_to_cons_colors[c] : c);
+				} else {
+					p->Red = (c >> rp) & rm;
+					p->Green = (c >> gp) & gm;
+					p->Blue = (c >> bp) & bm;
+					p->Reserved = 0;
+				}
+			}
+		}
+	}
+
+	free(buffer);
+	return (0);
+}
+
+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)
+{
+#if defined(EFI)
+	EFI_GRAPHICS_OUTPUT_BLT_PIXEL *p;
+#else
+	struct paletteentry *p;
+#endif
+	uint32_t x, sy, dy;
+	uint32_t bpp, pitch, copybytes;
+	off_t off;
+	uint8_t *source, *destination, *buffer;
+	uint8_t rm, rp, gm, gp, bm, bp;
+	bool bgra;
+
+	if (BltBuffer == NULL)
+		return (EINVAL);
+
+	if (DestinationY + Height >
+	    gfx_state.tg_fb.fb_height)
+		return (EINVAL);
+
+	if (DestinationX + Width > gfx_state.tg_fb.fb_width)
+		return (EINVAL);
+
+	if (Width == 0 || Height == 0)
+		return (EINVAL);
+
+	if (Delta == 0)
+		Delta = Width * sizeof (*p);
+
+	bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3;
+	pitch = gfx_state.tg_fb.fb_stride * bpp;
+
+	copybytes = Width * bpp;
+
+	rp = ffs(gfx_state.tg_fb.fb_mask_red) - 1;
+	gp = ffs(gfx_state.tg_fb.fb_mask_green) - 1;
+	bp = ffs(gfx_state.tg_fb.fb_mask_blue) - 1;
+	rm = gfx_state.tg_fb.fb_mask_red >> rp;
+	gm = gfx_state.tg_fb.fb_mask_green >> gp;
+	bm = gfx_state.tg_fb.fb_mask_blue >> bp;
+
+	/* If FB pixel format is BGRA, we can use direct copy. */
+	bgra = bpp == 4 &&
+	    ffs(rm) - 1 == 8 && rp == 16 &&
+	    ffs(gm) - 1 == 8 && gp == 8 &&
+	    ffs(bm) - 1 == 8 && bp == 0;
+
+	if (bgra) {
+		buffer = NULL;
+	} else {
+		buffer = malloc(copybytes);
+		if (buffer == NULL)
+			return (ENOMEM);
+	}
+	for (sy = SourceY, dy = DestinationY; sy < Height + SourceY;
+	    sy++, dy++) {
+		off = dy * pitch + DestinationX * bpp;
+		destination = gfx_get_fb_address() + off;
+
+		if (bgra) {
+			source = (uint8_t *)BltBuffer + sy * Delta +
+			    SourceX * sizeof (*p);
+		} else {
+			for (x = 0; x < Width; x++) {
+				uint32_t c;
+
+				p = (void *)((uint8_t *)BltBuffer +
+				    sy * Delta +
+				    (SourceX + x) * sizeof (*p));
+				if (bpp == 1) {
+					c = rgb_to_color_index(p->Red,
+					    p->Green, p->Blue);
+				} else {
+					c = (p->Red & rm) << rp |
+					    (p->Green & gm) << gp |
+					    (p->Blue & bm) << bp;
+				}
+				off = x * bpp;
+				switch (bpp) {
+				case 1:
+					gfx_mem_wr1(buffer, copybytes,
+					    off, (c < 16) ?
+					    cons_to_vga_colors[c] : c);
+					break;
+				case 2:
+					gfx_mem_wr2(buffer, copybytes,
+					    off, c);
+					break;
+				case 3:
+					gfx_mem_wr1(buffer, copybytes,
+					    off, (c >> 16) & 0xff);
+					gfx_mem_wr1(buffer, copybytes,
+					    off + 1, (c >> 8) & 0xff);
+					gfx_mem_wr1(buffer, copybytes,
+					    off + 2, c & 0xff);
+					break;
+				case 4:
+					gfx_mem_wr4(buffer, copybytes,
+					    x * bpp, c);
+					break;
+				}
+			}
+			source = buffer;
+		}
+
+		bcopy(source, destination, copybytes);
+	}
+
+	free(buffer);
+	return (0);
+}
+
+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)
+{
+	uint32_t bpp, copybytes;
+	int pitch;
+	uint8_t *source, *destination;
+	off_t off;
+
+	if (SourceY + Height >
+	    gfx_state.tg_fb.fb_height)
+		return (EINVAL);
+
+	if (SourceX + Width > gfx_state.tg_fb.fb_width)
+		return (EINVAL);
+
+	if (DestinationY + Height >
+	    gfx_state.tg_fb.fb_height)
+		return (EINVAL);
+
+	if (DestinationX + Width > gfx_state.tg_fb.fb_width)
+		return (EINVAL);
+
+	if (Width == 0 || Height == 0)
+		return (EINVAL);
+
+	bpp = roundup2(gfx_state.tg_fb.fb_bpp, 8) >> 3;
+	pitch = gfx_state.tg_fb.fb_stride * bpp;
+
+	copybytes = Width * bpp;
+
+	off = SourceY * pitch + SourceX * bpp;
+	source = gfx_get_fb_address() + off;
+	off = DestinationY * pitch + DestinationX * bpp;
+	destination = gfx_get_fb_address() + off;
+
+	if ((uintptr_t)destination > (uintptr_t)source) {
+		source += Height * pitch;
+		destination += Height * pitch;
+		pitch = -pitch;
+	}
+
+	while (Height-- > 0) {
+		bcopy(source, destination, copybytes);
+		source += pitch;
+		destination += pitch;
+	}
+
+	return (0);
+}
+
+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)
+{
+	int rv;
+#if defined(EFI)
+	EFI_STATUS status;
+	EFI_GRAPHICS_OUTPUT *gop = gfx_state.tg_private;
+
+	if (gop != NULL && (gop->Mode->Info->PixelFormat == PixelBltOnly ||
+	    gfx_state.tg_fb.fb_addr == 0)) {
+		switch (BltOperation) {
+		case GfxFbBltVideoFill:
+			status = gop->Blt(gop, BltBuffer, EfiBltVideoFill,
+			    SourceX, SourceY, DestinationX, DestinationY,
+			    Width, Height, Delta);
+			break;
+
+		case GfxFbBltVideoToBltBuffer:
+			status = gop->Blt(gop, BltBuffer,
+			    EfiBltVideoToBltBuffer,
+			    SourceX, SourceY, DestinationX, DestinationY,
+			    Width, Height, Delta);
+			break;
+
+		case GfxFbBltBufferToVideo:
+			status = gop->Blt(gop, BltBuffer, EfiBltBufferToVideo,
+			    SourceX, SourceY, DestinationX, DestinationY,
+			    Width, Height, Delta);
+			break;
+
+		case GfxFbBltVideoToVideo:
+			status = gop->Blt(gop, BltBuffer, EfiBltVideoToVideo,
+			    SourceX, SourceY, DestinationX, DestinationY,
+			    Width, Height, Delta);
+			break;
+
+		default:
+			status = EFI_INVALID_PARAMETER;
+			break;
+		}
+
+		switch (status) {
+		case EFI_SUCCESS:
+			rv = 0;
+			break;
+
+		case EFI_INVALID_PARAMETER:
+			rv = EINVAL;
+			break;
+
+		case EFI_DEVICE_ERROR:
+		default:
+			rv = EIO;
+			break;
+		}
+
+		return (rv);
+	}
+#endif
+
+	switch (BltOperation) {
+	case GfxFbBltVideoFill:
+		rv = gfxfb_blt_fill(BltBuffer, DestinationX, DestinationY,
+		    Width, Height);
+		break;
+
+	case GfxFbBltVideoToBltBuffer:
+		rv = gfxfb_blt_video_to_buffer(BltBuffer, SourceX, SourceY,
+		    DestinationX, DestinationY, Width, Height, Delta);
+		break;
+
+	case GfxFbBltBufferToVideo:
+		rv = gfxfb_blt_buffer_to_video(BltBuffer, SourceX, SourceY,
+		    DestinationX, DestinationY, Width, Height, Delta);
+		break;
+
+	case GfxFbBltVideoToVideo:
+		rv = gfxfb_blt_video_to_video(SourceX, SourceY,
+		    DestinationX, DestinationY, Width, Height);
+		break;
+
+	default:
+		rv = EINVAL;
+		break;
+	}
+	return (rv);
+}
+
+void
+gfx_bitblt_bitmap(teken_gfx_t *state, const uint8_t *glyph,
+    const teken_attr_t *a, uint32_t alpha, bool cursor)
+{
+	uint32_t width, height;
+	uint32_t fgc, bgc, bpl, cc, o;
+	int bpp, bit, byte;
+	bool invert = false;
+
+	bpp = 4;		/* We only generate BGRA */
+	width = state->tg_font.vf_width;
+	height = state->tg_font.vf_height;
+	bpl = (width + 7) / 8;  /* Bytes per source line. */
+
+	fgc = a->ta_fgcolor;
+	bgc = a->ta_bgcolor;
+	if (a->ta_format & TF_BOLD)
+		fgc |= TC_LIGHT;
+	if (a->ta_format & TF_BLINK)
+		bgc |= TC_LIGHT;
+
+	fgc = gfx_fb_color_map(fgc);
+	bgc = gfx_fb_color_map(bgc);
+
+	if (a->ta_format & TF_REVERSE)
+		invert = !invert;
+	if (cursor)
+		invert = !invert;
+	if (invert) {
+		uint32_t tmp;
+
+		tmp = fgc;
+		fgc = bgc;
+		bgc = tmp;
+	}
+
+	alpha = alpha << 24;
+	fgc |= alpha;
+	bgc |= alpha;
+
+	for (uint32_t y = 0; y < height; y++) {
+		for (uint32_t x = 0; x < width; x++) {
+			byte = y * bpl + x / 8;
+			bit = 0x80 >> (x % 8);
+			o = y * width * bpp + x * bpp;
+			cc = glyph[byte] & bit ? fgc : bgc;
+
+			gfx_mem_wr4(state->tg_glyph,
+			    state->tg_glyph_size, o, cc);
+		}
+	}
+}
+
+/*
+ * Draw prepared glyph on terminal point p.
+ */
+static void
+gfx_fb_printchar(teken_gfx_t *state, const teken_pos_t *p)
+{
+	unsigned x, y, width, height;
*** 6743 LINES SKIPPED ***


More information about the dev-commits-src-all mailing list