diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/common/ficl/emu/gfx_fb.c | 755 | ||||
-rw-r--r-- | usr/src/common/ficl/emu/gfx_fb.h | 68 | ||||
-rw-r--r-- | usr/src/common/ficl/emu/loader_emu.c | 37 | ||||
-rw-r--r-- | usr/src/common/ficl/loader.c | 5 | ||||
-rw-r--r-- | usr/src/lib/libficl/Makefile.com | 4 |
5 files changed, 864 insertions, 5 deletions
diff --git a/usr/src/common/ficl/emu/gfx_fb.c b/usr/src/common/ficl/emu/gfx_fb.c new file mode 100644 index 0000000000..caed97f85f --- /dev/null +++ b/usr/src/common/ficl/emu/gfx_fb.c @@ -0,0 +1,755 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Soome <tsoome@me.com> + */ + +/* + * Graphics support for loader emulation. + * The interface in loader and here needs some more development. + * We can get colormap from gfx_private, but loader is currently + * relying on tem fg/bg colors for drawing, once the menu code + * will get some facelift, we would need to provide colors as menu component + * attributes and stop depending on tem. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/fbio.h> +#include <string.h> +#include "gfx_fb.h" + +struct framebuffer fb; + +#define max(x, y) ((x) >= (y) ? (x) : (y)) + +static void gfx_fb_cons_display(uint32_t, uint32_t, + uint32_t, uint32_t, uint8_t *); + +/* This colormap should be replaced by colormap query from kernel */ +typedef struct { + uint8_t red[16]; + uint8_t green[16]; + uint8_t blue[16]; +} text_cmap_t; + +text_cmap_t cmap4_to_24 = { +/* BEGIN CSTYLED */ +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ + .red = {0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff}, + .green = {0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff}, + .blue = {0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00} +/* END CSTYLED */ +}; + +const uint8_t solaris_color_to_pc_color[16] = { + 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 +}; + +void +gfx_framework_init(void) +{ + struct fbgattr attr; + struct gfxfb_info *gfxfb_info; + char buf[10]; + + fb.fd = open("/dev/fb", O_RDWR); + if (fb.fd < 0) + return; + + /* make sure we have GFX framebuffer */ + if (ioctl(fb.fd, VIS_GETIDENTIFIER, &fb.ident) < 0 || + strcmp(fb.ident.name, "illumos_fb") != 0) { + close(fb.fd); + fb.fd = -1; + return; + } + + if (ioctl(fb.fd, FBIOGATTR, &attr) < 0) { + close(fb.fd); + fb.fd = -1; + return; + } + gfxfb_info = (struct gfxfb_info *)attr.sattr.dev_specific; + + fb.fb_height = attr.fbtype.fb_height; + fb.fb_width = attr.fbtype.fb_width; + fb.fb_depth = attr.fbtype.fb_depth; + fb.fb_size = attr.fbtype.fb_size; + fb.fb_bpp = attr.fbtype.fb_depth >> 3; + if (attr.fbtype.fb_depth == 15) + fb.fb_bpp = 2; + fb.fb_pitch = gfxfb_info->pitch; + fb.terminal_origin_x = gfxfb_info->terminal_origin_x; + fb.terminal_origin_y = gfxfb_info->terminal_origin_y; + fb.font_width = gfxfb_info->font_width; + fb.font_height = gfxfb_info->font_height; + + fb.red_mask_size = gfxfb_info->red_mask_size; + fb.red_field_position = gfxfb_info->red_field_position; + fb.green_mask_size = gfxfb_info->green_mask_size; + fb.green_field_position = gfxfb_info->green_field_position; + fb.blue_mask_size = gfxfb_info->blue_mask_size; + fb.blue_field_position = gfxfb_info->blue_field_position; + + fb.fb_addr = (uint8_t *)mmap(0, fb.fb_size, (PROT_READ | PROT_WRITE), + MAP_SHARED, fb.fd, 0); + + if (fb.fb_addr == NULL) { + close(fb.fd); + fb.fd = -1; + return; + } + snprintf(buf, sizeof (buf), "%d", fb.fb_height); + setenv("screen-height", buf, 1); + snprintf(buf, sizeof (buf), "%d", fb.fb_width); + setenv("screen-width", buf, 1); +} + +void +gfx_framework_fini(void) +{ + if (fb.fd < 0) + return; + + (void) munmap((caddr_t)fb.fb_addr, fb.fb_size); + close(fb.fd); + fb.fd = -1; +} + +static int +isqrt(int num) +{ + int res = 0; + int bit = 1 << 30; + + /* "bit" starts at the highest power of four <= the argument. */ + while (bit > num) + bit >>= 2; + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else { + res >>= 1; + } + bit >>= 2; + } + return (res); +} + +void +gfx_fb_setpixel(uint32_t x, uint32_t y) +{ + uint32_t c, offset; + + if (fb.fd < 0) + return; + c = 0; /* black */ + + if (x >= fb.fb_width || y >= fb.fb_height) + return; + + offset = y * fb.fb_pitch + x * fb.fb_bpp; + switch (fb.fb_depth) { + case 8: + fb.fb_addr[offset] = c & 0xff; + break; + case 15: + case 16: + *(uint16_t *)(fb.fb_addr + offset) = c & 0xffff; + break; + case 24: + fb.fb_addr[offset] = (c >> 16) & 0xff; + fb.fb_addr[offset + 1] = (c >> 8) & 0xff; + fb.fb_addr[offset + 2] = c & 0xff; + break; + case 32: + *(uint32_t *)(fb.fb_addr + offset) = c; + break; + } +} + +void +gfx_fb_drawrect(uint32_t x1, uint32_t y1, uint32_t x2, uint32_t y2, + uint32_t fill) +{ + int x, y; + + if (fb.fd < 0) + return; + + for (y = y1; y <= y2; y++) { + if (fill || (y == y1) || (y == y2)) { + for (x = x1; x <= x2; x++) + gfx_fb_setpixel(x, y); + } else { + gfx_fb_setpixel(x1, y); + gfx_fb_setpixel(x2, y); + } + } +} + +void +gfx_term_drawrect(uint32_t row1, uint32_t col1, uint32_t row2, uint32_t col2) +{ + int x1, y1, x2, y2; + int xshift, yshift; + int width, i; + + if (fb.fd < 0) + return; + + width = fb.font_width / 4; /* line width */ + xshift = (fb.font_width - width) / 2; + yshift = (fb.font_height - width) / 2; + /* Terminal coordinates start from (1,1) */ + row1--; + col1--; + row2--; + col2--; + + /* + * Draw horizontal lines width points thick, shifted from outer edge. + */ + x1 = (row1 + 1) * fb.font_width + fb.terminal_origin_x; + y1 = col1 * fb.font_height + fb.terminal_origin_y + yshift; + x2 = row2 * fb.font_width + fb.terminal_origin_x; + gfx_fb_drawrect(x1, y1, x2, y1 + width, 1); + y2 = col2 * fb.font_height + fb.terminal_origin_y; + y2 += fb.font_height - yshift - width; + gfx_fb_drawrect(x1, y2, x2, y2 + width, 1); + + /* + * Draw vertical lines width points thick, shifted from outer edge. + */ + x1 = row1 * fb.font_width + fb.terminal_origin_x + xshift; + y1 = col1 * fb.font_height + fb.terminal_origin_y; + y1 += fb.font_height; + y2 = col2 * fb.font_height + fb.terminal_origin_y; + gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); + x1 = row2 * fb.font_width + fb.terminal_origin_x; + x1 += fb.font_width - xshift - width; + gfx_fb_drawrect(x1, y1, x1 + width, y2, 1); + + /* Draw upper left corner. */ + x1 = row1 * fb.font_width + fb.terminal_origin_x + xshift; + y1 = col1 * fb.font_height + fb.terminal_origin_y; + y1 += fb.font_height; + + x2 = row1 * fb.font_width + fb.terminal_origin_x; + x2 += fb.font_width; + y2 = col1 * fb.font_height + fb.terminal_origin_y + yshift; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1 + i, y1, x1 + i, y2 + i, x2, y2 + i, width-i); + + /* Draw lower left corner. */ + x1 = row1 * fb.font_width + fb.terminal_origin_x; + x1 += fb.font_width; + y1 = col2 * fb.font_height + fb.terminal_origin_y; + y1 += fb.font_height - yshift; + x2 = row1 * fb.font_width + fb.terminal_origin_x + xshift; + y2 = col2 * fb.font_height + fb.terminal_origin_y; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); + + /* Draw upper right corner. */ + x1 = row2 * fb.font_width + fb.terminal_origin_x; + y1 = col1 * fb.font_height + fb.terminal_origin_y + yshift; + x2 = row2 * fb.font_width + fb.terminal_origin_x; + x2 += fb.font_width - xshift - width; + y2 = col1 * fb.font_height + fb.terminal_origin_y; + y2 += fb.font_height; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 + i, x2 + i, y1 + i, x2 + i, y2, width-i); + + /* Draw lower right corner. */ + x1 = row2 * fb.font_width + fb.terminal_origin_x; + y1 = col2 * fb.font_height + fb.terminal_origin_y; + y1 += fb.font_height - yshift; + x2 = row2 * fb.font_width + fb.terminal_origin_x; + x2 += fb.font_width - xshift - width; + y2 = col2 * fb.font_height + fb.terminal_origin_y; + for (i = 0; i <= width; i++) + gfx_fb_bezier(x1, y1 - i, x2 + i, y1 - i, x2 + i, y2, width-i); +} + +void +gfx_fb_line(uint32_t x0, uint32_t y0, uint32_t x1, uint32_t y1, uint32_t width) +{ + int dx, sx, dy, sy; + int err, e2, x2, y2, ed; + + if (fb.fd < 0) + return; + + sx = x0 < x1? 1 : -1; + sy = y0 < y1? 1 : -1; + dx = abs(x1 - x0); + dy = abs(y1 - y0); + err = dx - dy; + ed = dx + dy == 0 ? 1 : isqrt(dx * dx + dy * dy); + + if (dx != 0 && dy != 0) + width = (width + 1) >> 1; + + for (;;) { + gfx_fb_setpixel(x0, y0); + e2 = err; + x2 = x0; + if ((e2 << 1) >= -dx) { /* x step */ + e2 += dy; + y2 = y0; + while (e2 < ed * width && (y1 != y2 || dx > dy)) { + y2 += sy; + gfx_fb_setpixel(x0, y2); + e2 += dx; + } + if (x0 == x1) + break; + e2 = err; + err -= dy; + x0 += sx; + } + if ((e2 << 1) <= dy) { /* y step */ + e2 = dx-e2; + while (e2 < ed * width && (x1 != x2 || dx < dy)) { + x2 += sx; + gfx_fb_setpixel(x2, y0); + e2 += dy; + } + if (y0 == y1) + break; + err += dx; + y0 += sy; + } + } +} + +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) +{ + int sx, sy, xx, yy, xy, width; + int dx, dy, err, curvature; + int i; + + if (fb.fd < 0) + return; + + width = wd; + sx = x2 - x1; + sy = y2 - y1; + xx = x0 - x1; + yy = y0 - y1; + curvature = xx*sy - yy*sx; + + if (sx * sx + sy * sy > xx * xx + yy * yy) { + x2 = x0; + x0 = sx + x1; + y2 = y0; + y0 = sy + y1; + curvature = -curvature; + } + if (curvature != 0) { + xx += sx; + sx = x0 < x2? 1 : -1; + xx *= sx; + yy += sy; + sy = y0 < y2? 1 : -1; + yy *= sy; + xy = 2 * xx * yy; + xx *= xx; + yy *= yy; + if (curvature * sx * sy < 0) { + xx = -xx; + yy = -yy; + xy = -xy; + curvature = -curvature; + } + dx = 4 * sy * curvature * (x1 - x0) + xx - xy; + dy = 4 * sx * curvature * (y0 - y1) + yy - xy; + xx += xx; + yy += yy; + err = dx + dy + xy; + do { + for (i = 0; i <= width; i++) + gfx_fb_setpixel(x0 + i, y0); + if (x0 == x2 && y0 == y2) + return; /* last pixel -> curve finished */ + y1 = 2 * err < dx; + if (2 * err > dy) { + x0 += sx; + dx -= xy; + dy += yy; + err += dy; + } + if (y1 != 0) { + y0 += sy; + dy -= xy; + dx += xx; + err += dx; + } + } while (dy < dx); /* gradient negates -> algorithm fails */ + } + gfx_fb_line(x0, y0, x2, y2, width); +} + +#define FL_PUTIMAGE_BORDER 0x1 +#define FL_PUTIMAGE_NOSCROLL 0x2 +#define FL_PUTIMAGE_DEBUG 0x80 + +int +gfx_fb_putimage(png_t *png, uint32_t ux1, uint32_t uy1, uint32_t ux2, + uint32_t uy2, uint32_t flags) +{ + uint32_t i, j, x, y, fheight, fwidth, color; + uint8_t r, g, b, a, *p, *data; + bool scale = false; + bool trace = false; + + trace = (flags & FL_PUTIMAGE_DEBUG) != 0; + + if (fb.fd < 0) { + if (trace) + printf("Framebuffer not active.\n"); + return (1); + } + + if (png->color_type != PNG_TRUECOLOR_ALPHA) { + if (trace) + printf("Not truecolor image.\n"); + return (1); + } + + if (ux1 > fb.fb_width || uy1 > fb.fb_height) { + if (trace) + printf("Top left coordinate off screen.\n"); + return (1); + } + + if (png->width > UINT16_MAX || png->height > UINT16_MAX) { + if (trace) + printf("Image too large.\n"); + return (1); + } + + if (png->width < 1 || png->height < 1) { + if (trace) + printf("Image too small.\n"); + return (1); + } + + /* + * If 0 was passed for either ux2 or uy2, then calculate the missing + * part of the bottom right coordinate. + */ + scale = true; + if (ux2 == 0 && uy2 == 0) { + /* Both 0, use the native resolution of the image */ + ux2 = ux1 + png->width; + uy2 = uy1 + png->height; + scale = false; + } else if (ux2 == 0) { + /* Set ux2 from uy2/uy1 to maintain aspect ratio */ + ux2 = ux1 + (png->width * (uy2 - uy1)) / png->height; + } else if (uy2 == 0) { + /* Set uy2 from ux2/ux1 to maintain aspect ratio */ + uy2 = uy1 + (png->height * (ux2 - ux1)) / png->width; + } + + if (ux2 > fb.fb_width || uy2 > fb.fb_height) { + if (trace) + printf("Bottom right coordinate off screen.\n"); + return (1); + } + + fwidth = ux2 - ux1; + fheight = uy2 - uy1; + + /* + * If the original image dimensions have been passed explicitly, + * disable scaling. + */ + if (fwidth == png->width && fheight == png->height) + scale = false; + + if (ux1 == 0) { + /* + * No top left X co-ordinate (real coordinates start at 1), + * place as far right as it will fit. + */ + ux2 = fb.fb_width - fb.terminal_origin_x; + ux1 = ux2 - fwidth; + } + + if (uy1 == 0) { + /* + * No top left Y co-ordinate (real coordinates start at 1), + * place as far down as it will fit. + */ + uy2 = fb.fb_height - fb.terminal_origin_y; + uy1 = uy2 - fheight; + } + + if (ux1 >= ux2 || uy1 >= uy2) { + if (trace) + printf("Image dimensions reversed.\n"); + return (1); + } + + if (fwidth < 2 || fheight < 2) { + if (trace) + printf("Target area too small\n"); + return (1); + } + + if (trace) + printf("Image %ux%u -> %ux%u @%ux%u\n", + png->width, png->height, fwidth, fheight, ux1, uy1); + + if ((flags & FL_PUTIMAGE_BORDER)) + gfx_fb_drawrect(ux1, uy1, ux2, uy2, 0); + + data = malloc(fwidth * fheight * fb.fb_bpp); + if (data == NULL) { + if (trace) + printf("Out of memory.\n"); + return (1); + } + + /* + * Build image for our framebuffer. + */ + + /* Helper to calculate the pixel index from the source png */ +#define GETPIXEL(xx, yy) (((yy) * png->width + (xx)) * png->bpp) + + /* + * For each of the x and y directions, calculate the number of pixels + * in the source image that correspond to a single pixel in the target. + * Use fixed-point arithmetic with 16-bits for each of the integer and + * fractional parts. + */ + const uint32_t wcstep = ((png->width - 1) << 16) / (fwidth - 1); + const uint32_t hcstep = ((png->height - 1) << 16) / (fheight - 1); + + uint32_t hc = 0; + for (y = 0; y < fheight; y++) { + uint32_t hc2 = (hc >> 9) & 0x7f; + uint32_t hc1 = 0x80 - hc2; + + uint32_t offset_y = hc >> 16; + uint32_t offset_y1 = offset_y + 1; + + uint32_t wc = 0; + for (x = 0; x < fwidth; x++) { + uint32_t wc2 = (wc >> 9) & 0x7f; + uint32_t wc1 = 0x80 - wc2; + + uint32_t offset_x = wc >> 16; + uint32_t offset_x1 = offset_x + 1; + + /* Target pixel index */ + j = (y * fwidth + x) * fb.fb_bpp; + + if (!scale) { + i = GETPIXEL(x, y); + r = png->image[i]; + g = png->image[i + 1]; + b = png->image[i + 2]; + a = png->image[i + 3]; + } else { + uint8_t pixel[4]; + + uint32_t p00 = GETPIXEL(offset_x, offset_y); + uint32_t p01 = GETPIXEL(offset_x, offset_y1); + uint32_t p10 = GETPIXEL(offset_x1, offset_y); + uint32_t p11 = GETPIXEL(offset_x1, offset_y1); + + /* + * Given a 2x2 array of pixels in the source + * image, combine them to produce a single + * value for the pixel in the target image. + * Each column of pixels is combined using + * a weighted average where the top and bottom + * pixels contribute hc1 and hc2 respectively. + * The calculation for bottom pixel pB and + * top pixel pT is: + * (pT * hc1 + pB * hc2) / (hc1 + hc2) + * Once the values are determined for the two + * columns of pixels, then the columns are + * averaged together in the same way but using + * wc1 and wc2 for the weightings. + * + * Since hc1 and hc2 are chosen so that + * hc1 + hc2 == 128 (and same for wc1 + wc2), + * the >> 14 below is a quick way to divide by + * (hc1 + hc2) * (wc1 + wc2) + */ + for (i = 0; i < 4; i++) + pixel[i] = ( + (png->image[p00 + i] * hc1 + + png->image[p01 + i] * hc2) * wc1 + + (png->image[p10 + i] * hc1 + + png->image[p11 + i] * hc2) * wc2) + >> 14; + + r = pixel[0]; + g = pixel[1]; + b = pixel[2]; + a = pixel[3]; + } + + color = + r >> (8 - fb.red_mask_size) + << fb.red_field_position | + g >> (8 - fb.green_mask_size) + << fb.green_field_position | + b >> (8 - fb.blue_mask_size) + << fb.blue_field_position; + + switch (fb.fb_depth) { + case 8: { + uint32_t best, dist, k; + int diff; + + color = 0; + best = 256 * 256 * 256; + for (k = 0; k < 16; k++) { + diff = r - cmap4_to_24.red[k]; + dist = diff * diff; + diff = g - cmap4_to_24.green[k]; + dist += diff * diff; + diff = b - cmap4_to_24.blue[k]; + dist += diff * diff; + + if (dist < best) { + color = k; + best = dist; + if (dist == 0) + break; + } + } + data[j] = solaris_color_to_pc_color[color]; + break; + } + case 15: + case 16: + *(uint16_t *)(data+j) = color; + break; + case 24: + p = (uint8_t *)&color; + data[j] = p[0]; + data[j+1] = p[1]; + data[j+2] = p[2]; + break; + case 32: + color |= a << 24; + *(uint32_t *)(data+j) = color; + break; + } + wc += wcstep; + } + hc += hcstep; + } + + gfx_fb_cons_display(uy1, ux1, fwidth, fheight, data); + free(data); + return (0); +} + +/* + * Implements alpha blending for RGBA data, could use pixels for arguments, + * but byte stream seems more generic. + * The generic alpha blending is: + * blend = alpha * fg + (1.0 - alpha) * bg. + * Since our alpha is not from range [0..1], we scale appropriately. + */ +static uint8_t +alpha_blend(uint8_t fg, uint8_t bg, uint8_t alpha) +{ + uint16_t blend, h, l; + + /* trivial corner cases */ + if (alpha == 0) + return (bg); + if (alpha == 0xFF) + return (fg); + blend = (alpha * fg + (0xFF - alpha) * bg); + /* Division by 0xFF */ + h = blend >> 8; + l = blend & 0xFF; + if (h + l >= 0xFF) + h++; + return (h); +} + +/* Copy memory to framebuffer or to memory. */ +static void +bitmap_cpy(uint8_t *dst, uint8_t *src, uint32_t len, int bpp) +{ + uint32_t i; + uint8_t a; + + switch (bpp) { + case 4: + for (i = 0; i < len; i += bpp) { + a = src[i+3]; + dst[i] = alpha_blend(src[i], dst[i], a); + dst[i+1] = alpha_blend(src[i+1], dst[i+1], a); + dst[i+2] = alpha_blend(src[i+2], dst[i+2], a); + dst[i+3] = a; + } + break; + default: + (void) memcpy(dst, src, len); + break; + } +} + +/* + * gfx_fb_cons_display implements direct draw on frame buffer memory. + * It is needed till we have way to send bitmaps to tem, tem already has + * function to send data down to framebuffer. + */ +static void +gfx_fb_cons_display(uint32_t row, uint32_t col, + uint32_t width, uint32_t height, uint8_t *data) +{ + uint32_t size; /* write size per scanline */ + uint8_t *fbp; /* fb + calculated offset */ + int i; + + /* make sure we will not write past FB */ + if (col >= fb.fb_width || row >= fb.fb_height || + col + width > fb.fb_width || row + height > fb.fb_height) + return; + + size = width * fb.fb_bpp; + fbp = fb.fb_addr + col * fb.fb_bpp + row * fb.fb_pitch; + + /* write all scanlines in rectangle */ + for (i = 0; i < height; i++) { + uint8_t *dest = fbp + i * fb.fb_pitch; + uint8_t *src = data + i * size; + bitmap_cpy(dest, src, size, fb.fb_bpp); + } +} diff --git a/usr/src/common/ficl/emu/gfx_fb.h b/usr/src/common/ficl/emu/gfx_fb.h new file mode 100644 index 0000000000..4dfb386f5b --- /dev/null +++ b/usr/src/common/ficl/emu/gfx_fb.h @@ -0,0 +1,68 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Toomas Some <tsoome@me.com> + */ + +#ifndef _GFX_FB_H +#define _GFX_FB_H + +/* + * Graphics support for loader emulation. + */ +#include <sys/visual_io.h> +#include <pnglite.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct framebuffer { + struct vis_identifier ident; + int fd; /* frame buffer device descriptor */ + uint8_t *fb_addr; /* mapped framebuffer */ + + int fb_height; /* in pixels */ + int fb_width; /* in pixels */ + int fb_depth; /* bits per pixel */ + int fb_bpp; /* bytes per pixel */ + int fb_size; /* total size in bytes */ + int fb_pitch; /* bytes per scanline */ + uint16_t terminal_origin_x; + uint16_t terminal_origin_y; + uint16_t font_width; + uint16_t font_height; + uint8_t red_mask_size; + uint8_t red_field_position; + uint8_t green_mask_size; + uint8_t green_field_position; + uint8_t blue_mask_size; + uint8_t blue_field_position; +}; + +extern struct framebuffer fb; + +void gfx_framework_init(void); +void gfx_framework_fini(void); +void gfx_fb_setpixel(uint32_t, uint32_t); +void gfx_fb_drawrect(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_term_drawrect(uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_fb_line(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void gfx_fb_bezier(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, + uint32_t); +int gfx_fb_putimage(png_t *, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _GFX_FB_H */ diff --git a/usr/src/common/ficl/emu/loader_emu.c b/usr/src/common/ficl/emu/loader_emu.c index 84653dca2d..f64f15255e 100644 --- a/usr/src/common/ficl/emu/loader_emu.c +++ b/usr/src/common/ficl/emu/loader_emu.c @@ -40,6 +40,7 @@ #include <sys/systeminfo.h> #include <sys/queue.h> #include <sys/mnttab.h> +#include "gfx_fb.h" #include "ficl.h" /* Commands and return values; nonzero return sets command_errmsg != NULL */ @@ -104,6 +105,7 @@ static int command_unload(int argc, char *argv[]); static int command_load(int argc, char *argv[]); static int command_reboot(int argc, char *argv[]); static int command_sifting(int argc, char *argv[]); +static int command_framebuffer(int argc, char *argv[]); #define BF_PARSE 100 #define BF_DICTSIZE 30000 @@ -753,6 +755,8 @@ bf_init(const char *rc, ficlOutputFunction out) COMMAND_SET(cmdp, "reboot", "reboot the system", command_reboot); STAILQ_INSERT_TAIL(&commands, cmdp, next); COMMAND_SET(cmdp, "sifting", "find words", command_sifting); + COMMAND_SET(cmdp, "framebuffer", "framebuffer mode management", + command_framebuffer); STAILQ_INSERT_TAIL(&commands, cmdp, next); fsi = malloc(sizeof (ficlSystemInformation)); @@ -841,6 +845,7 @@ bf_init(const char *rc, ficlOutputFunction out) } } + gfx_framework_init(); return (bf_vm); } @@ -848,6 +853,7 @@ void bf_fini(void) { ficlSystemDestroy(bf_sys); + gfx_framework_fini(); } /* @@ -1993,3 +1999,34 @@ command_sifting(int argc, char *argv[]) ficlPrimitiveSiftingImpl(bf_vm, argv[1]); return (CMD_OK); } + +/* Only implement get and list. Ignore arguments on, off and set. */ +static int +command_framebuffer(int argc, char *argv[]) +{ + if (fb.fd < 0) { + printf("Framebuffer is not available.\n"); + return (CMD_OK); + } + + if (argc == 2 && strcmp(argv[1], "get") == 0) { + printf("\nSystem frame buffer: %s\n", fb.ident.name); + printf("%dx%dx%d, stride=%d\n", fb.fb_width, fb.fb_height, + fb.fb_depth, (fb.fb_pitch << 3) / fb.fb_depth); + return (CMD_OK); + } + if (argc == 2 && strcmp(argv[1], "list") == 0) { + printf("0: %dx%dx%d\n", fb.fb_width, fb.fb_height, fb.fb_depth); + return (CMD_OK); + } + if (argc == 3 && strcmp(argv[1], "set") == 0) + return (CMD_OK); + if (argc == 2 && strcmp(argv[1], "on") == 0) + return (CMD_OK); + if (argc == 2 && strcmp(argv[1], "off") == 0) + return (CMD_OK); + + snprintf(command_errbuf, sizeof (command_errbuf), + "usage: %s get | list", argv[0]); + return (CMD_ERROR); +} diff --git a/usr/src/common/ficl/loader.c b/usr/src/common/ficl/loader.c index 1ce8373615..fe2268297b 100644 --- a/usr/src/common/ficl/loader.c +++ b/usr/src/common/ficl/loader.c @@ -51,6 +51,7 @@ #include <uuid/uuid.h> #endif #include <string.h> +#include <gfx_fb.h> #include "ficl.h" /* @@ -69,7 +70,6 @@ * .# ( value -- ) */ -#ifdef _STANDALONE /* ( flags x1 y1 x2 y2 -- flag ) */ void ficl_fb_putimage(ficlVm *pVM) @@ -177,7 +177,6 @@ ficl_term_drawrect(ficlVm *pVM) x1 = ficlStackPopUnsigned(ficlVmGetDataStack(pVM)); gfx_term_drawrect(x1, y1, x2, y2); } -#endif /* _STANDALONE */ void ficlSetenv(ficlVm *pVM) @@ -1024,7 +1023,6 @@ ficlSystemCompilePlatform(ficlSystem *pSys) FICL_WORD_DEFAULT); ficlDictionarySetPrimitive(dp, "uuid-to-string", ficlUuidToString, FICL_WORD_DEFAULT); -#ifdef _STANDALONE ficlDictionarySetPrimitive(dp, "fb-setpixel", ficl_fb_setpixel, FICL_WORD_DEFAULT); ficlDictionarySetPrimitive(dp, "fb-line", ficl_fb_line, @@ -1037,6 +1035,7 @@ ficlSystemCompilePlatform(ficlSystem *pSys) FICL_WORD_DEFAULT); ficlDictionarySetPrimitive(dp, "term-drawrect", ficl_term_drawrect, FICL_WORD_DEFAULT); +#ifdef _STANDALONE /* Register words from linker set. */ SET_FOREACH(fnpp, Xficl_compile_set) (*fnpp)(pSys); diff --git a/usr/src/lib/libficl/Makefile.com b/usr/src/lib/libficl/Makefile.com index 2a077c47ee..d0ac5a8791 100644 --- a/usr/src/lib/libficl/Makefile.com +++ b/usr/src/lib/libficl/Makefile.com @@ -22,7 +22,7 @@ VERS=.$(MAJOR).$(MINOR) OBJECTS= dictionary.o system.o fileaccess.o float.o double.o prefix.o search.o \ softcore.o stack.o tools.o vm.o primitives.o unix.o utility.o \ hash.o callback.o word.o loader.o pager.o extras.o \ - loader_emu.o pnglite.o lz4.o + loader_emu.o gfx_fb.o pnglite.o lz4.o include $(SRC)/lib/Makefile.lib @@ -31,7 +31,7 @@ LIBS= $(DYNLIB) $(LINTLIB) FICLDIR= $(SRC)/common/ficl CSTD= $(CSTD_GNU99) PNGLITE= $(SRC)/common/pnglite -CPPFLAGS += -I.. -I$(FICLDIR) -D_LARGEFILE64_SOURCE=1 +CPPFLAGS += -I.. -I$(FICLDIR) -I$(FICLDIR)/emu -D_LARGEFILE64_SOURCE=1 CPPFLAGS += -I$(PNGLITE) # As variable "count" is marked volatile, gcc 4.4.4 will complain about |