10bead3caSToomas Soome /* 20bead3caSToomas Soome * This file and its contents are supplied under the terms of the 30bead3caSToomas Soome * Common Development and Distribution License ("CDDL"), version 1.0. 40bead3caSToomas Soome * You may only use this file in accordance with the terms of version 50bead3caSToomas Soome * 1.0 of the CDDL. 60bead3caSToomas Soome * 70bead3caSToomas Soome * A full copy of the text of the CDDL should have accompanied this 80bead3caSToomas Soome * source. A copy of the CDDL is also available via the Internet at 90bead3caSToomas Soome * http://www.illumos.org/license/CDDL. 100bead3caSToomas Soome */ 110bead3caSToomas Soome 120bead3caSToomas Soome /* 130bead3caSToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com> 140bead3caSToomas Soome */ 150bead3caSToomas Soome 160bead3caSToomas Soome /* 170bead3caSToomas Soome * Graphics support for loader emulation. 180bead3caSToomas Soome * The interface in loader and here needs some more development. 190bead3caSToomas Soome * We can get colormap from gfx_private, but loader is currently 200bead3caSToomas Soome * relying on tem fg/bg colors for drawing, once the menu code 210bead3caSToomas Soome * will get some facelift, we would need to provide colors as menu component 220bead3caSToomas Soome * attributes and stop depending on tem. 230bead3caSToomas Soome */ 240bead3caSToomas Soome 250bead3caSToomas Soome #include <stdio.h> 260bead3caSToomas Soome #include <stdlib.h> 270bead3caSToomas Soome #include <stdbool.h> 280bead3caSToomas Soome #include <sys/types.h> 290bead3caSToomas Soome #include <sys/stat.h> 300bead3caSToomas Soome #include <fcntl.h> 310bead3caSToomas Soome #include <unistd.h> 320bead3caSToomas Soome #include <sys/mman.h> 330bead3caSToomas Soome #include <sys/fbio.h> 340bead3caSToomas Soome #include <string.h> 350bead3caSToomas Soome #include "gfx_fb.h" 360bead3caSToomas Soome 370bead3caSToomas Soome struct framebuffer fb; 380bead3caSToomas Soome 390bead3caSToomas Soome #define max(x, y) ((x) >= (y) ? (x) : (y)) 400bead3caSToomas Soome 410bead3caSToomas Soome static void gfx_fb_cons_display(uint32_t, uint32_t, 420bead3caSToomas Soome uint32_t, uint32_t, uint8_t *); 430bead3caSToomas Soome 440bead3caSToomas Soome /* This colormap should be replaced by colormap query from kernel */ 450bead3caSToomas Soome typedef struct { 460bead3caSToomas Soome uint8_t red[16]; 470bead3caSToomas Soome uint8_t green[16]; 480bead3caSToomas Soome uint8_t blue[16]; 490bead3caSToomas Soome } text_cmap_t; 500bead3caSToomas Soome 510bead3caSToomas Soome text_cmap_t cmap4_to_24 = { 520bead3caSToomas Soome /* BEGIN CSTYLED */ 530bead3caSToomas Soome /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 540bead3caSToomas Soome Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ 550bead3caSToomas Soome .red = {0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff}, 560bead3caSToomas Soome .green = {0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff}, 570bead3caSToomas Soome .blue = {0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00} 580bead3caSToomas Soome /* END CSTYLED */ 590bead3caSToomas Soome }; 600bead3caSToomas Soome 610bead3caSToomas Soome const uint8_t solaris_color_to_pc_color[16] = { 620bead3caSToomas Soome 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 630bead3caSToomas Soome }; 640bead3caSToomas Soome 650bead3caSToomas Soome void 660bead3caSToomas Soome gfx_framework_init(void) 670bead3caSToomas Soome { 680bead3caSToomas Soome struct fbgattr attr; 690bead3caSToomas Soome struct gfxfb_info *gfxfb_info; 700bead3caSToomas Soome char buf[10]; 710bead3caSToomas Soome 720bead3caSToomas Soome fb.fd = open("/dev/fb", O_RDWR); 730bead3caSToomas Soome if (fb.fd < 0) 740bead3caSToomas Soome return; 750bead3caSToomas Soome 760bead3caSToomas Soome /* make sure we have GFX framebuffer */ 770bead3caSToomas Soome if (ioctl(fb.fd, VIS_GETIDENTIFIER, &fb.ident) < 0 || 780bead3caSToomas Soome strcmp(fb.ident.name, "illumos_fb") != 0) { 79*c0bb4f73SToomas Soome (void) close(fb.fd); 800bead3caSToomas Soome fb.fd = -1; 810bead3caSToomas Soome return; 820bead3caSToomas Soome } 830bead3caSToomas Soome 840bead3caSToomas Soome if (ioctl(fb.fd, FBIOGATTR, &attr) < 0) { 85*c0bb4f73SToomas Soome (void) close(fb.fd); 860bead3caSToomas Soome fb.fd = -1; 870bead3caSToomas Soome return; 880bead3caSToomas Soome } 890bead3caSToomas Soome gfxfb_info = (struct gfxfb_info *)attr.sattr.dev_specific; 900bead3caSToomas Soome 910bead3caSToomas Soome fb.fb_height = attr.fbtype.fb_height; 920bead3caSToomas Soome fb.fb_width = attr.fbtype.fb_width; 930bead3caSToomas Soome fb.fb_depth = attr.fbtype.fb_depth; 940bead3caSToomas Soome fb.fb_size = attr.fbtype.fb_size; 950bead3caSToomas Soome fb.fb_bpp = attr.fbtype.fb_depth >> 3; 960bead3caSToomas Soome if (attr.fbtype.fb_depth == 15) 970bead3caSToomas Soome fb.fb_bpp = 2; 980bead3caSToomas Soome fb.fb_pitch = gfxfb_info->pitch; 990bead3caSToomas Soome fb.terminal_origin_x = gfxfb_info->terminal_origin_x; 1000bead3caSToomas Soome fb.terminal_origin_y = gfxfb_info->terminal_origin_y; 1010bead3caSToomas Soome fb.font_width = gfxfb_info->font_width; 1020bead3caSToomas Soome fb.font_height = gfxfb_info->font_height; 1030bead3caSToomas Soome 1040bead3caSToomas Soome fb.red_mask_size = gfxfb_info->red_mask_size; 1050bead3caSToomas Soome fb.red_field_position = gfxfb_info->red_field_position; 1060bead3caSToomas Soome fb.green_mask_size = gfxfb_info->green_mask_size; 1070bead3caSToomas Soome fb.green_field_position = gfxfb_info->green_field_position; 1080bead3caSToomas Soome fb.blue_mask_size = gfxfb_info->blue_mask_size; 1090bead3caSToomas Soome fb.blue_field_position = gfxfb_info->blue_field_position; 1100bead3caSToomas Soome 1110bead3caSToomas Soome fb.fb_addr = (uint8_t *)mmap(0, fb.fb_size, (PROT_READ | PROT_WRITE), 1120bead3caSToomas Soome MAP_SHARED, fb.fd, 0); 1130bead3caSToomas Soome 1140bead3caSToomas Soome if (fb.fb_addr == NULL) { 115*c0bb4f73SToomas Soome (void) close(fb.fd); 1160bead3caSToomas Soome fb.fd = -1; 1170bead3caSToomas Soome return; 1180bead3caSToomas Soome } 119*c0bb4f73SToomas Soome (void) snprintf(buf, sizeof (buf), "%d", fb.fb_height); 120*c0bb4f73SToomas Soome (void) setenv("screen-height", buf, 1); 121*c0bb4f73SToomas Soome (void) snprintf(buf, sizeof (buf), "%d", fb.fb_width); 122*c0bb4f73SToomas Soome (void) setenv("screen-width", buf, 1); 1230bead3caSToomas Soome } 1240bead3caSToomas Soome 1250bead3caSToomas Soome void 1260bead3caSToomas Soome gfx_framework_fini(void) 1270bead3caSToomas Soome { 1280bead3caSToomas Soome if (fb.fd < 0) 1290bead3caSToomas Soome return; 1300bead3caSToomas Soome 1310bead3caSToomas Soome (void) munmap((caddr_t)fb.fb_addr, fb.fb_size); 132*c0bb4f73SToomas Soome (void) close(fb.fd); 1330bead3caSToomas Soome fb.fd = -1; 1340bead3caSToomas Soome } 1350bead3caSToomas Soome 1360bead3caSToomas Soome static int 1370bead3caSToomas Soome isqrt(int num) 1380bead3caSToomas Soome { 1390bead3caSToomas Soome int res = 0; 1400bead3caSToomas Soome int bit = 1 << 30; 1410bead3caSToomas Soome 1420bead3caSToomas Soome /* "bit" starts at the highest power of four <= the argument. */ 1430bead3caSToomas Soome while (bit > num) 1440bead3caSToomas Soome bit >>= 2; 1450bead3caSToomas Soome 1460bead3caSToomas Soome while (bit != 0) { 1470bead3caSToomas Soome if (num >= res + bit) { 1480bead3caSToomas Soome num -= res + bit; 1490bead3caSToomas Soome res = (res >> 1) + bit; 1500bead3caSToomas Soome } else { 1510bead3caSToomas Soome res >>= 1; 1520bead3caSToomas Soome } 1530bead3caSToomas Soome bit >>= 2; 1540bead3caSToomas Soome } 1550bead3caSToomas Soome return (res); 1560bead3caSToomas Soome } 1570bead3caSToomas Soome 1580bead3caSToomas Soome void 1590bead3caSToomas Soome gfx_fb_setpixel(uint32_t x, uint32_t y) 1600bead3caSToomas Soome { 1610bead3caSToomas Soome uint32_t c, offset; 1620bead3caSToomas Soome 1630bead3caSToomas Soome if (fb.fd < 0) 1640bead3caSToomas Soome return; 1650bead3caSToomas Soome c = 0; /* black */ 1660bead3caSToomas Soome 1670bead3caSToomas Soome if (x >= fb.fb_width || y >= fb.fb_height) 1680bead3caSToomas Soome return; 1690bead3caSToomas Soome 1700bead3caSToomas Soome offset = y * fb.fb_pitch + x * fb.fb_bpp; 1710bead3caSToomas Soome switch (fb.fb_depth) { 1720bead3caSToomas Soome case 8: 1730bead3caSToomas Soome fb.fb_addr[offset] = c & 0xff; 1740bead3caSToomas Soome break; 1750bead3caSToomas Soome case 15: 1760bead3caSToomas Soome case 16: 1770bead3caSToomas Soome *(uint16_t *)(fb.fb_addr + offset) = c & 0xffff; 1780bead3caSToomas Soome break; 1790bead3caSToomas Soome case 24: 1800bead3caSToomas Soome fb.fb_addr[offset] = (c >> 16) & 0xff; 1810bead3caSToomas Soome fb.fb_addr[offset + 1] = (c >> 8) & 0xff; 1820bead3caSToomas Soome fb.fb_addr[offset + 2] = c & 0xff; 1830bead3caSToomas Soome break; 1840bead3caSToomas Soome case 32: 1850bead3caSToomas Soome *(uint32_t *)(fb.fb_addr + offset) = c; 1860bead3caSToomas Soome break; 1870bead3caSToomas Soome } 1880bead3caSToomas Soome } 1890bead3caSToomas Soome 1900bead3caSToomas Soome void 1910bead3caSToomas Soome gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, 1920bead3caSToomas Soome uint32_t fill) 1930bead3caSToomas Soome { 1940bead3caSToomas Soome int x, y; 1950bead3caSToomas Soome 1960bead3caSToomas Soome if (fb.fd < 0) 1970bead3caSToomas Soome return; 1980bead3caSToomas Soome 1990bead3caSToomas Soome for (y = y1; y <= y2; y++) { 2000bead3caSToomas Soome if (fill || (y == y1) || (y == y2)) { 2010bead3caSToomas Soome for (x = x1; x <= x2; x++) 2020bead3caSToomas Soome gfx_fb_setpixel(x, y); 2030bead3caSToomas Soome } else { 2040bead3caSToomas Soome gfx_fb_setpixel(x1, y); 2050bead3caSToomas Soome gfx_fb_setpixel(x2, y); 2060bead3caSToomas Soome } 2070bead3caSToomas Soome } 2080bead3caSToomas Soome } 2090bead3caSToomas Soome 2100bead3caSToomas Soome void 2110bead3caSToomas Soome gfx_term_drawrect(uint32_t row1, uint32_t col1, uint32_t row2, uint32_t col2) 2120bead3caSToomas Soome { 2130bead3caSToomas Soome int x1, y1, x2, y2; 2140bead3caSToomas Soome int xshift, yshift; 2150bead3caSToomas Soome int width, i; 2160bead3caSToomas Soome 2170bead3caSToomas Soome if (fb.fd < 0) 2180bead3caSToomas Soome return; 2190bead3caSToomas Soome 2200bead3caSToomas Soome width = fb.font_width / 4; /* line width */ 2210bead3caSToomas Soome xshift = (fb.font_width - width) / 2; 2220bead3caSToomas Soome yshift = (fb.font_height - width) / 2; 2230bead3caSToomas Soome /* Terminal coordinates start from (1,1) */ 2240bead3caSToomas Soome row1--; 2250bead3caSToomas Soome col1--; 2260bead3caSToomas Soome row2--; 2270bead3caSToomas Soome col2--; 2280bead3caSToomas Soome 2290bead3caSToomas Soome /* 2300bead3caSToomas Soome * Draw horizontal lines width points thick, shifted from outer edge. 2310bead3caSToomas Soome */ 2320bead3caSToomas Soome x1 = (row1 + 1) * fb.font_width + fb.terminal_origin_x; 2330bead3caSToomas Soome y1 = col1 * fb.font_height + fb.terminal_origin_y + yshift; 2340bead3caSToomas Soome x2 = row2 * fb.font_width + fb.terminal_origin_x; 2350bead3caSToomas Soome gfx_fb_drawrect(x1, y1, x2, y1 + width, 1); 2360bead3caSToomas Soome y2 = col2 * fb.font_height + fb.terminal_origin_y; 2370bead3caSToomas Soome y2 += fb.font_height - yshift - width; 2380bead3caSToomas Soome gfx_fb_drawrect(x1, y2, x2, y2 + width, 1); 2390bead3caSToomas Soome 2400bead3caSToomas Soome /* 2410bead3caSToomas Soome * Draw vertical lines width points thick, shifted from outer edge. 2420bead3caSToomas Soome */ 2430bead3caSToomas Soome x1 = row1 * fb.font_width + fb.terminal_origin_x + xshift; 2440bead3caSToomas Soome y1 = col1 * fb.font_height + fb.terminal_origin_y; 2450bead3caSToomas Soome y1 += fb.font_height; 2460bead3caSToomas Soome y2 = col2 * fb.font_height + fb.terminal_origin_y; 2470bead3caSToomas Soome gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); 2480bead3caSToomas Soome x1 = row2 * fb.font_width + fb.terminal_origin_x; 2490bead3caSToomas Soome x1 += fb.font_width - xshift - width; 2500bead3caSToomas Soome gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); 2510bead3caSToomas Soome 2520bead3caSToomas Soome /* Draw upper left corner. */ 2530bead3caSToomas Soome x1 = row1 * fb.font_width + fb.terminal_origin_x + xshift; 2540bead3caSToomas Soome y1 = col1 * fb.font_height + fb.terminal_origin_y; 2550bead3caSToomas Soome y1 += fb.font_height; 2560bead3caSToomas Soome 2570bead3caSToomas Soome x2 = row1 * fb.font_width + fb.terminal_origin_x; 2580bead3caSToomas Soome x2 += fb.font_width; 2590bead3caSToomas Soome y2 = col1 * fb.font_height + fb.terminal_origin_y + yshift; 2600bead3caSToomas Soome for (i = 0; i <= width; i++) 2610bead3caSToomas Soome gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i); 2620bead3caSToomas Soome 2630bead3caSToomas Soome /* Draw lower left corner. */ 2640bead3caSToomas Soome x1 = row1 * fb.font_width + fb.terminal_origin_x; 2650bead3caSToomas Soome x1 += fb.font_width; 2660bead3caSToomas Soome y1 = col2 * fb.font_height + fb.terminal_origin_y; 2670bead3caSToomas Soome y1 += fb.font_height - yshift; 2680bead3caSToomas Soome x2 = row1 * fb.font_width + fb.terminal_origin_x + xshift; 2690bead3caSToomas Soome y2 = col2 * fb.font_height + fb.terminal_origin_y; 2700bead3caSToomas Soome for (i = 0; i <= width; i++) 2710bead3caSToomas Soome gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); 2720bead3caSToomas Soome 2730bead3caSToomas Soome /* Draw upper right corner. */ 2740bead3caSToomas Soome x1 = row2 * fb.font_width + fb.terminal_origin_x; 2750bead3caSToomas Soome y1 = col1 * fb.font_height + fb.terminal_origin_y + yshift; 2760bead3caSToomas Soome x2 = row2 * fb.font_width + fb.terminal_origin_x; 2770bead3caSToomas Soome x2 += fb.font_width - xshift - width; 2780bead3caSToomas Soome y2 = col1 * fb.font_height + fb.terminal_origin_y; 2790bead3caSToomas Soome y2 += fb.font_height; 2800bead3caSToomas Soome for (i = 0; i <= width; i++) 2810bead3caSToomas Soome gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i); 2820bead3caSToomas Soome 2830bead3caSToomas Soome /* Draw lower right corner. */ 2840bead3caSToomas Soome x1 = row2 * fb.font_width + fb.terminal_origin_x; 2850bead3caSToomas Soome y1 = col2 * fb.font_height + fb.terminal_origin_y; 2860bead3caSToomas Soome y1 += fb.font_height - yshift; 2870bead3caSToomas Soome x2 = row2 * fb.font_width + fb.terminal_origin_x; 2880bead3caSToomas Soome x2 += fb.font_width - xshift - width; 2890bead3caSToomas Soome y2 = col2 * fb.font_height + fb.terminal_origin_y; 2900bead3caSToomas Soome for (i = 0; i <= width; i++) 2910bead3caSToomas Soome gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); 2920bead3caSToomas Soome } 2930bead3caSToomas Soome 2940bead3caSToomas Soome void 2950bead3caSToomas Soome gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t width) 2960bead3caSToomas Soome { 2970bead3caSToomas Soome int dx, sx, dy, sy; 2980bead3caSToomas Soome int err, e2, x2, y2, ed; 2990bead3caSToomas Soome 3000bead3caSToomas Soome if (fb.fd < 0) 3010bead3caSToomas Soome return; 3020bead3caSToomas Soome 3030bead3caSToomas Soome sx = x0 < x1? 1 : -1; 3040bead3caSToomas Soome sy = y0 < y1? 1 : -1; 3050bead3caSToomas Soome dx = abs(x1 - x0); 3060bead3caSToomas Soome dy = abs(y1 - y0); 3070bead3caSToomas Soome err = dx - dy; 3080bead3caSToomas Soome ed = dx + dy == 0 ? 1 : isqrt(dx * dx + dy * dy); 3090bead3caSToomas Soome 3100bead3caSToomas Soome if (dx != 0 && dy != 0) 3110bead3caSToomas Soome width = (width + 1) >> 1; 3120bead3caSToomas Soome 3130bead3caSToomas Soome for (;;) { 3140bead3caSToomas Soome gfx_fb_setpixel(x0, y0); 3150bead3caSToomas Soome e2 = err; 3160bead3caSToomas Soome x2 = x0; 3170bead3caSToomas Soome if ((e2 << 1) >= -dx) { /* x step */ 3180bead3caSToomas Soome e2 += dy; 3190bead3caSToomas Soome y2 = y0; 3200bead3caSToomas Soome while (e2 < ed * width && (y1 != y2 || dx > dy)) { 3210bead3caSToomas Soome y2 += sy; 3220bead3caSToomas Soome gfx_fb_setpixel(x0, y2); 3230bead3caSToomas Soome e2 += dx; 3240bead3caSToomas Soome } 3250bead3caSToomas Soome if (x0 == x1) 3260bead3caSToomas Soome break; 3270bead3caSToomas Soome e2 = err; 3280bead3caSToomas Soome err -= dy; 3290bead3caSToomas Soome x0 += sx; 3300bead3caSToomas Soome } 3310bead3caSToomas Soome if ((e2 << 1) <= dy) { /* y step */ 3320bead3caSToomas Soome e2 = dx-e2; 3330bead3caSToomas Soome while (e2 < ed * width && (x1 != x2 || dx < dy)) { 3340bead3caSToomas Soome x2 += sx; 3350bead3caSToomas Soome gfx_fb_setpixel(x2, y0); 3360bead3caSToomas Soome e2 += dy; 3370bead3caSToomas Soome } 3380bead3caSToomas Soome if (y0 == y1) 3390bead3caSToomas Soome break; 3400bead3caSToomas Soome err += dx; 3410bead3caSToomas Soome y0 += sy; 3420bead3caSToomas Soome } 3430bead3caSToomas Soome } 3440bead3caSToomas Soome } 3450bead3caSToomas Soome 3460bead3caSToomas Soome void 3470bead3caSToomas Soome gfx_fb_bezier(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t x2, 3480bead3caSToomas Soome uint32_t y2, uint32_t wd) 3490bead3caSToomas Soome { 3500bead3caSToomas Soome int sx, sy, xx, yy, xy, width; 3510bead3caSToomas Soome int dx, dy, err, curvature; 3520bead3caSToomas Soome int i; 3530bead3caSToomas Soome 3540bead3caSToomas Soome if (fb.fd < 0) 3550bead3caSToomas Soome return; 3560bead3caSToomas Soome 3570bead3caSToomas Soome width = wd; 3580bead3caSToomas Soome sx = x2 - x1; 3590bead3caSToomas Soome sy = y2 - y1; 3600bead3caSToomas Soome xx = x0 - x1; 3610bead3caSToomas Soome yy = y0 - y1; 3620bead3caSToomas Soome curvature = xx*sy - yy*sx; 3630bead3caSToomas Soome 3640bead3caSToomas Soome if (sx * sx + sy * sy > xx * xx + yy * yy) { 3650bead3caSToomas Soome x2 = x0; 3660bead3caSToomas Soome x0 = sx + x1; 3670bead3caSToomas Soome y2 = y0; 3680bead3caSToomas Soome y0 = sy + y1; 3690bead3caSToomas Soome curvature = -curvature; 3700bead3caSToomas Soome } 3710bead3caSToomas Soome if (curvature != 0) { 3720bead3caSToomas Soome xx += sx; 3730bead3caSToomas Soome sx = x0 < x2? 1 : -1; 3740bead3caSToomas Soome xx *= sx; 3750bead3caSToomas Soome yy += sy; 3760bead3caSToomas Soome sy = y0 < y2? 1 : -1; 3770bead3caSToomas Soome yy *= sy; 3780bead3caSToomas Soome xy = 2 * xx * yy; 3790bead3caSToomas Soome xx *= xx; 3800bead3caSToomas Soome yy *= yy; 3810bead3caSToomas Soome if (curvature * sx * sy < 0) { 3820bead3caSToomas Soome xx = -xx; 3830bead3caSToomas Soome yy = -yy; 3840bead3caSToomas Soome xy = -xy; 3850bead3caSToomas Soome curvature = -curvature; 3860bead3caSToomas Soome } 3870bead3caSToomas Soome dx = 4 * sy * curvature * (x1 - x0) + xx - xy; 3880bead3caSToomas Soome dy = 4 * sx * curvature * (y0 - y1) + yy - xy; 3890bead3caSToomas Soome xx += xx; 3900bead3caSToomas Soome yy += yy; 3910bead3caSToomas Soome err = dx + dy + xy; 3920bead3caSToomas Soome do { 3930bead3caSToomas Soome for (i = 0; i <= width; i++) 3940bead3caSToomas Soome gfx_fb_setpixel(x0 + i, y0); 3950bead3caSToomas Soome if (x0 == x2 && y0 == y2) 3960bead3caSToomas Soome return; /* last pixel -> curve finished */ 3970bead3caSToomas Soome y1 = 2 * err < dx; 3980bead3caSToomas Soome if (2 * err > dy) { 3990bead3caSToomas Soome x0 += sx; 4000bead3caSToomas Soome dx -= xy; 4010bead3caSToomas Soome dy += yy; 4020bead3caSToomas Soome err += dy; 4030bead3caSToomas Soome } 4040bead3caSToomas Soome if (y1 != 0) { 4050bead3caSToomas Soome y0 += sy; 4060bead3caSToomas Soome dy -= xy; 4070bead3caSToomas Soome dx += xx; 4080bead3caSToomas Soome err += dx; 4090bead3caSToomas Soome } 4100bead3caSToomas Soome } while (dy < dx); /* gradient negates -> algorithm fails */ 4110bead3caSToomas Soome } 4120bead3caSToomas Soome gfx_fb_line(x0, y0, x2, y2, width); 4130bead3caSToomas Soome } 4140bead3caSToomas Soome 4150bead3caSToomas Soome #define FL_PUTIMAGE_BORDER 0x1 4160bead3caSToomas Soome #define FL_PUTIMAGE_NOSCROLL 0x2 4170bead3caSToomas Soome #define FL_PUTIMAGE_DEBUG 0x80 4180bead3caSToomas Soome 4190bead3caSToomas Soome int 4200bead3caSToomas Soome gfx_fb_putimage(png_t *png, uint32_t ux1, uint32_t uy1, uint32_t ux2, 4210bead3caSToomas Soome uint32_t uy2, uint32_t flags) 4220bead3caSToomas Soome { 4230bead3caSToomas Soome uint32_t i, j, x, y, fheight, fwidth, color; 4240bead3caSToomas Soome uint8_t r, g, b, a, *p, *data; 4250bead3caSToomas Soome bool scale = false; 4260bead3caSToomas Soome bool trace = false; 4270bead3caSToomas Soome 4280bead3caSToomas Soome trace = (flags & FL_PUTIMAGE_DEBUG) != 0; 4290bead3caSToomas Soome 4300bead3caSToomas Soome if (fb.fd < 0) { 4310bead3caSToomas Soome if (trace) 4320bead3caSToomas Soome printf("Framebuffer not active.\n"); 4330bead3caSToomas Soome return (1); 4340bead3caSToomas Soome } 4350bead3caSToomas Soome 4360bead3caSToomas Soome if (png->color_type != PNG_TRUECOLOR_ALPHA) { 4370bead3caSToomas Soome if (trace) 4380bead3caSToomas Soome printf("Not truecolor image.\n"); 4390bead3caSToomas Soome return (1); 4400bead3caSToomas Soome } 4410bead3caSToomas Soome 4420bead3caSToomas Soome if (ux1 > fb.fb_width || uy1 > fb.fb_height) { 4430bead3caSToomas Soome if (trace) 4440bead3caSToomas Soome printf("Top left coordinate off screen.\n"); 4450bead3caSToomas Soome return (1); 4460bead3caSToomas Soome } 4470bead3caSToomas Soome 4480bead3caSToomas Soome if (png->width > UINT16_MAX || png->height > UINT16_MAX) { 4490bead3caSToomas Soome if (trace) 4500bead3caSToomas Soome printf("Image too large.\n"); 4510bead3caSToomas Soome return (1); 4520bead3caSToomas Soome } 4530bead3caSToomas Soome 4540bead3caSToomas Soome if (png->width < 1 || png->height < 1) { 4550bead3caSToomas Soome if (trace) 4560bead3caSToomas Soome printf("Image too small.\n"); 4570bead3caSToomas Soome return (1); 4580bead3caSToomas Soome } 4590bead3caSToomas Soome 4600bead3caSToomas Soome /* 4610bead3caSToomas Soome * If 0 was passed for either ux2 or uy2, then calculate the missing 4620bead3caSToomas Soome * part of the bottom right coordinate. 4630bead3caSToomas Soome */ 4640bead3caSToomas Soome scale = true; 4650bead3caSToomas Soome if (ux2 == 0 && uy2 == 0) { 4660bead3caSToomas Soome /* Both 0, use the native resolution of the image */ 4670bead3caSToomas Soome ux2 = ux1 + png->width; 4680bead3caSToomas Soome uy2 = uy1 + png->height; 4690bead3caSToomas Soome scale = false; 4700bead3caSToomas Soome } else if (ux2 == 0) { 4710bead3caSToomas Soome /* Set ux2 from uy2/uy1 to maintain aspect ratio */ 4720bead3caSToomas Soome ux2 = ux1 + (png->width * (uy2 - uy1)) / png->height; 4730bead3caSToomas Soome } else if (uy2 == 0) { 4740bead3caSToomas Soome /* Set uy2 from ux2/ux1 to maintain aspect ratio */ 4750bead3caSToomas Soome uy2 = uy1 + (png->height * (ux2 - ux1)) / png->width; 4760bead3caSToomas Soome } 4770bead3caSToomas Soome 4780bead3caSToomas Soome if (ux2 > fb.fb_width || uy2 > fb.fb_height) { 4790bead3caSToomas Soome if (trace) 4800bead3caSToomas Soome printf("Bottom right coordinate off screen.\n"); 4810bead3caSToomas Soome return (1); 4820bead3caSToomas Soome } 4830bead3caSToomas Soome 4840bead3caSToomas Soome fwidth = ux2 - ux1; 4850bead3caSToomas Soome fheight = uy2 - uy1; 4860bead3caSToomas Soome 4870bead3caSToomas Soome /* 4880bead3caSToomas Soome * If the original image dimensions have been passed explicitly, 4890bead3caSToomas Soome * disable scaling. 4900bead3caSToomas Soome */ 4910bead3caSToomas Soome if (fwidth == png->width && fheight == png->height) 4920bead3caSToomas Soome scale = false; 4930bead3caSToomas Soome 4940bead3caSToomas Soome if (ux1 == 0) { 4950bead3caSToomas Soome /* 4960bead3caSToomas Soome * No top left X co-ordinate (real coordinates start at 1), 4970bead3caSToomas Soome * place as far right as it will fit. 4980bead3caSToomas Soome */ 4990bead3caSToomas Soome ux2 = fb.fb_width - fb.terminal_origin_x; 5000bead3caSToomas Soome ux1 = ux2 - fwidth; 5010bead3caSToomas Soome } 5020bead3caSToomas Soome 5030bead3caSToomas Soome if (uy1 == 0) { 5040bead3caSToomas Soome /* 5050bead3caSToomas Soome * No top left Y co-ordinate (real coordinates start at 1), 5060bead3caSToomas Soome * place as far down as it will fit. 5070bead3caSToomas Soome */ 5080bead3caSToomas Soome uy2 = fb.fb_height - fb.terminal_origin_y; 5090bead3caSToomas Soome uy1 = uy2 - fheight; 5100bead3caSToomas Soome } 5110bead3caSToomas Soome 5120bead3caSToomas Soome if (ux1 >= ux2 || uy1 >= uy2) { 5130bead3caSToomas Soome if (trace) 5140bead3caSToomas Soome printf("Image dimensions reversed.\n"); 5150bead3caSToomas Soome return (1); 5160bead3caSToomas Soome } 5170bead3caSToomas Soome 5180bead3caSToomas Soome if (fwidth < 2 || fheight < 2) { 5190bead3caSToomas Soome if (trace) 5200bead3caSToomas Soome printf("Target area too small\n"); 5210bead3caSToomas Soome return (1); 5220bead3caSToomas Soome } 5230bead3caSToomas Soome 5240bead3caSToomas Soome if (trace) 5250bead3caSToomas Soome printf("Image %ux%u -> %ux%u @%ux%u\n", 5260bead3caSToomas Soome png->width, png->height, fwidth, fheight, ux1, uy1); 5270bead3caSToomas Soome 5280bead3caSToomas Soome if ((flags & FL_PUTIMAGE_BORDER)) 5290bead3caSToomas Soome gfx_fb_drawrect(ux1, uy1, ux2, uy2, 0); 5300bead3caSToomas Soome 5310bead3caSToomas Soome data = malloc(fwidth * fheight * fb.fb_bpp); 5320bead3caSToomas Soome if (data == NULL) { 5330bead3caSToomas Soome if (trace) 5340bead3caSToomas Soome printf("Out of memory.\n"); 5350bead3caSToomas Soome return (1); 5360bead3caSToomas Soome } 5370bead3caSToomas Soome 5380bead3caSToomas Soome /* 5390bead3caSToomas Soome * Build image for our framebuffer. 5400bead3caSToomas Soome */ 5410bead3caSToomas Soome 5420bead3caSToomas Soome /* Helper to calculate the pixel index from the source png */ 5430bead3caSToomas Soome #define GETPIXEL(xx, yy) (((yy) * png->width + (xx)) * png->bpp) 5440bead3caSToomas Soome 5450bead3caSToomas Soome /* 5460bead3caSToomas Soome * For each of the x and y directions, calculate the number of pixels 5470bead3caSToomas Soome * in the source image that correspond to a single pixel in the target. 5480bead3caSToomas Soome * Use fixed-point arithmetic with 16-bits for each of the integer and 5490bead3caSToomas Soome * fractional parts. 5500bead3caSToomas Soome */ 5510bead3caSToomas Soome const uint32_t wcstep = ((png->width - 1) << 16) / (fwidth - 1); 5520bead3caSToomas Soome const uint32_t hcstep = ((png->height - 1) << 16) / (fheight - 1); 5530bead3caSToomas Soome 5540bead3caSToomas Soome uint32_t hc = 0; 5550bead3caSToomas Soome for (y = 0; y < fheight; y++) { 5560bead3caSToomas Soome uint32_t hc2 = (hc >> 9) & 0x7f; 5570bead3caSToomas Soome uint32_t hc1 = 0x80 - hc2; 5580bead3caSToomas Soome 5590bead3caSToomas Soome uint32_t offset_y = hc >> 16; 5600bead3caSToomas Soome uint32_t offset_y1 = offset_y + 1; 5610bead3caSToomas Soome 5620bead3caSToomas Soome uint32_t wc = 0; 5630bead3caSToomas Soome for (x = 0; x < fwidth; x++) { 5640bead3caSToomas Soome uint32_t wc2 = (wc >> 9) & 0x7f; 5650bead3caSToomas Soome uint32_t wc1 = 0x80 - wc2; 5660bead3caSToomas Soome 5670bead3caSToomas Soome uint32_t offset_x = wc >> 16; 5680bead3caSToomas Soome uint32_t offset_x1 = offset_x + 1; 5690bead3caSToomas Soome 5700bead3caSToomas Soome /* Target pixel index */ 5710bead3caSToomas Soome j = (y * fwidth + x) * fb.fb_bpp; 5720bead3caSToomas Soome 5730bead3caSToomas Soome if (!scale) { 5740bead3caSToomas Soome i = GETPIXEL(x, y); 5750bead3caSToomas Soome r = png->image[i]; 5760bead3caSToomas Soome g = png->image[i + 1]; 5770bead3caSToomas Soome b = png->image[i + 2]; 5780bead3caSToomas Soome a = png->image[i + 3]; 5790bead3caSToomas Soome } else { 5800bead3caSToomas Soome uint8_t pixel[4]; 5810bead3caSToomas Soome 5820bead3caSToomas Soome uint32_t p00 = GETPIXEL(offset_x, offset_y); 5830bead3caSToomas Soome uint32_t p01 = GETPIXEL(offset_x, offset_y1); 5840bead3caSToomas Soome uint32_t p10 = GETPIXEL(offset_x1, offset_y); 5850bead3caSToomas Soome uint32_t p11 = GETPIXEL(offset_x1, offset_y1); 5860bead3caSToomas Soome 5870bead3caSToomas Soome /* 5880bead3caSToomas Soome * Given a 2x2 array of pixels in the source 5890bead3caSToomas Soome * image, combine them to produce a single 5900bead3caSToomas Soome * value for the pixel in the target image. 5910bead3caSToomas Soome * Each column of pixels is combined using 5920bead3caSToomas Soome * a weighted average where the top and bottom 5930bead3caSToomas Soome * pixels contribute hc1 and hc2 respectively. 5940bead3caSToomas Soome * The calculation for bottom pixel pB and 5950bead3caSToomas Soome * top pixel pT is: 5960bead3caSToomas Soome * (pT * hc1 + pB * hc2) / (hc1 + hc2) 5970bead3caSToomas Soome * Once the values are determined for the two 5980bead3caSToomas Soome * columns of pixels, then the columns are 5990bead3caSToomas Soome * averaged together in the same way but using 6000bead3caSToomas Soome * wc1 and wc2 for the weightings. 6010bead3caSToomas Soome * 6020bead3caSToomas Soome * Since hc1 and hc2 are chosen so that 6030bead3caSToomas Soome * hc1 + hc2 == 128 (and same for wc1 + wc2), 6040bead3caSToomas Soome * the >> 14 below is a quick way to divide by 6050bead3caSToomas Soome * (hc1 + hc2) * (wc1 + wc2) 6060bead3caSToomas Soome */ 6070bead3caSToomas Soome for (i = 0; i < 4; i++) 6080bead3caSToomas Soome pixel[i] = ( 6090bead3caSToomas Soome (png->image[p00 + i] * hc1 + 6100bead3caSToomas Soome png->image[p01 + i] * hc2) * wc1 + 6110bead3caSToomas Soome (png->image[p10 + i] * hc1 + 6120bead3caSToomas Soome png->image[p11 + i] * hc2) * wc2) 6130bead3caSToomas Soome >> 14; 6140bead3caSToomas Soome 6150bead3caSToomas Soome r = pixel[0]; 6160bead3caSToomas Soome g = pixel[1]; 6170bead3caSToomas Soome b = pixel[2]; 6180bead3caSToomas Soome a = pixel[3]; 6190bead3caSToomas Soome } 6200bead3caSToomas Soome 6210bead3caSToomas Soome color = 6220bead3caSToomas Soome r >> (8 - fb.red_mask_size) 6230bead3caSToomas Soome << fb.red_field_position | 6240bead3caSToomas Soome g >> (8 - fb.green_mask_size) 6250bead3caSToomas Soome << fb.green_field_position | 6260bead3caSToomas Soome b >> (8 - fb.blue_mask_size) 6270bead3caSToomas Soome << fb.blue_field_position; 6280bead3caSToomas Soome 6290bead3caSToomas Soome switch (fb.fb_depth) { 6300bead3caSToomas Soome case 8: { 6310bead3caSToomas Soome uint32_t best, dist, k; 6320bead3caSToomas Soome int diff; 6330bead3caSToomas Soome 6340bead3caSToomas Soome color = 0; 6350bead3caSToomas Soome best = 256 * 256 * 256; 6360bead3caSToomas Soome for (k = 0; k < 16; k++) { 6370bead3caSToomas Soome diff = r - cmap4_to_24.red[k]; 6380bead3caSToomas Soome dist = diff * diff; 6390bead3caSToomas Soome diff = g - cmap4_to_24.green[k]; 6400bead3caSToomas Soome dist += diff * diff; 6410bead3caSToomas Soome diff = b - cmap4_to_24.blue[k]; 6420bead3caSToomas Soome dist += diff * diff; 6430bead3caSToomas Soome 6440bead3caSToomas Soome if (dist < best) { 6450bead3caSToomas Soome color = k; 6460bead3caSToomas Soome best = dist; 6470bead3caSToomas Soome if (dist == 0) 6480bead3caSToomas Soome break; 6490bead3caSToomas Soome } 6500bead3caSToomas Soome } 6510bead3caSToomas Soome data[j] = solaris_color_to_pc_color[color]; 6520bead3caSToomas Soome break; 6530bead3caSToomas Soome } 6540bead3caSToomas Soome case 15: 6550bead3caSToomas Soome case 16: 6560bead3caSToomas Soome *(uint16_t *)(data+j) = color; 6570bead3caSToomas Soome break; 6580bead3caSToomas Soome case 24: 6590bead3caSToomas Soome p = (uint8_t *)&color; 6600bead3caSToomas Soome data[j] = p[0]; 6610bead3caSToomas Soome data[j+1] = p[1]; 6620bead3caSToomas Soome data[j+2] = p[2]; 6630bead3caSToomas Soome break; 6640bead3caSToomas Soome case 32: 6650bead3caSToomas Soome color |= a << 24; 6660bead3caSToomas Soome *(uint32_t *)(data+j) = color; 6670bead3caSToomas Soome break; 6680bead3caSToomas Soome } 6690bead3caSToomas Soome wc += wcstep; 6700bead3caSToomas Soome } 6710bead3caSToomas Soome hc += hcstep; 6720bead3caSToomas Soome } 6730bead3caSToomas Soome 6740bead3caSToomas Soome gfx_fb_cons_display(uy1, ux1, fwidth, fheight, data); 6750bead3caSToomas Soome free(data); 6760bead3caSToomas Soome return (0); 6770bead3caSToomas Soome } 6780bead3caSToomas Soome 6790bead3caSToomas Soome /* 6800bead3caSToomas Soome * Implements alpha blending for RGBA data, could use pixels for arguments, 6810bead3caSToomas Soome * but byte stream seems more generic. 6820bead3caSToomas Soome * The generic alpha blending is: 6830bead3caSToomas Soome * blend = alpha * fg + (1.0 - alpha) * bg. 6840bead3caSToomas Soome * Since our alpha is not from range [0..1], we scale appropriately. 6850bead3caSToomas Soome */ 6860bead3caSToomas Soome static uint8_t 6870bead3caSToomas Soome alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) 6880bead3caSToomas Soome { 6890bead3caSToomas Soome uint16_t blend, h, l; 6900bead3caSToomas Soome 6910bead3caSToomas Soome /* trivial corner cases */ 6920bead3caSToomas Soome if (alpha == 0) 6930bead3caSToomas Soome return (bg); 6940bead3caSToomas Soome if (alpha == 0xFF) 6950bead3caSToomas Soome return (fg); 6960bead3caSToomas Soome blend = (alpha * fg + (0xFF - alpha) * bg); 6970bead3caSToomas Soome /* Division by 0xFF */ 6980bead3caSToomas Soome h = blend >> 8; 6990bead3caSToomas Soome l = blend & 0xFF; 7000bead3caSToomas Soome if (h + l >= 0xFF) 7010bead3caSToomas Soome h++; 7020bead3caSToomas Soome return (h); 7030bead3caSToomas Soome } 7040bead3caSToomas Soome 7050bead3caSToomas Soome /* Copy memory to framebuffer or to memory. */ 7060bead3caSToomas Soome static void 7070bead3caSToomas Soome bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp) 7080bead3caSToomas Soome { 7090bead3caSToomas Soome uint32_t i; 7100bead3caSToomas Soome uint8_t a; 7110bead3caSToomas Soome 7120bead3caSToomas Soome switch (bpp) { 7130bead3caSToomas Soome case 4: 7140bead3caSToomas Soome for (i = 0; i < len; i += bpp) { 7150bead3caSToomas Soome a = src[i+3]; 7160bead3caSToomas Soome dst[i] = alpha_blend(src[i], dst[i], a); 7170bead3caSToomas Soome dst[i+1] = alpha_blend(src[i+1], dst[i+1], a); 7180bead3caSToomas Soome dst[i+2] = alpha_blend(src[i+2], dst[i+2], a); 7190bead3caSToomas Soome dst[i+3] = a; 7200bead3caSToomas Soome } 7210bead3caSToomas Soome break; 7220bead3caSToomas Soome default: 7230bead3caSToomas Soome (void) memcpy(dst, src, len); 7240bead3caSToomas Soome break; 7250bead3caSToomas Soome } 7260bead3caSToomas Soome } 7270bead3caSToomas Soome 7280bead3caSToomas Soome /* 7290bead3caSToomas Soome * gfx_fb_cons_display implements direct draw on frame buffer memory. 7300bead3caSToomas Soome * It is needed till we have way to send bitmaps to tem, tem already has 7310bead3caSToomas Soome * function to send data down to framebuffer. 7320bead3caSToomas Soome */ 7330bead3caSToomas Soome static void 7340bead3caSToomas Soome gfx_fb_cons_display(uint32_t row, uint32_t col, 7350bead3caSToomas Soome uint32_t width, uint32_t height, uint8_t *data) 7360bead3caSToomas Soome { 7370bead3caSToomas Soome uint32_t size; /* write size per scanline */ 7380bead3caSToomas Soome uint8_t *fbp; /* fb + calculated offset */ 7390bead3caSToomas Soome int i; 7400bead3caSToomas Soome 7410bead3caSToomas Soome /* make sure we will not write past FB */ 7420bead3caSToomas Soome if (col >= fb.fb_width || row >= fb.fb_height || 7430bead3caSToomas Soome col + width > fb.fb_width || row + height > fb.fb_height) 7440bead3caSToomas Soome return; 7450bead3caSToomas Soome 7460bead3caSToomas Soome size = width * fb.fb_bpp; 7470bead3caSToomas Soome fbp = fb.fb_addr + col * fb.fb_bpp + row * fb.fb_pitch; 7480bead3caSToomas Soome 7490bead3caSToomas Soome /* write all scanlines in rectangle */ 7500bead3caSToomas Soome for (i = 0; i < height; i++) { 7510bead3caSToomas Soome uint8_t *dest = fbp + i * fb.fb_pitch; 7520bead3caSToomas Soome uint8_t *src = data + i * size; 7530bead3caSToomas Soome bitmap_cpy(dest, src, size, fb.fb_bpp); 7540bead3caSToomas Soome } 7550bead3caSToomas Soome } 756