| |
| /* |
| * Virtual Frame Buffer Export |
| * |
| * (C) Copyright 2024 Glider bv |
| * |
| * This file is subject to the terms and conditions of the GNU General Public |
| * License. See the file COPYING in the main directory of this archive for |
| * more details. |
| */ |
| |
| #define _GNU_SOURCE |
| |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "types.h" |
| #include "export.h" |
| #include "fb.h" |
| #include "util.h" |
| |
| |
| static const char *export_prefix; |
| static unsigned int export_xres = DEFAULT_EXPORT_XRES; |
| static unsigned int export_yres = DEFAULT_EXPORT_YRES; |
| |
| static void export_setup(void) |
| { |
| const char *param = Opt_Export; |
| char *end; |
| |
| /* Prefix */ |
| end = strchr(param, ','); |
| if (end) |
| *end++ = '\0'; |
| |
| export_prefix = param; |
| Debug("export_prefix = %s\n", export_prefix); |
| |
| /* Optional horizontal resolution */ |
| param = end; |
| if (!param) |
| return; |
| |
| end = strchr(param, ','); |
| if (end) |
| *end++ = '\0'; |
| |
| export_xres = atoi(param); |
| Debug("export_xres = %u\n", export_xres); |
| |
| /* Optional vertical resolution */ |
| param = end; |
| if (!param) |
| return; |
| |
| end = strchr(param, ','); |
| if (end) |
| *end++ = '\0'; |
| |
| export_yres = atoi(param); |
| Debug("export_yres = %u\n", export_yres); |
| } |
| |
| void export_init(void) |
| { |
| export_setup(); |
| |
| fb_var.xres = export_xres; |
| fb_var.yres = export_yres; |
| fb_var.xres_virtual = export_xres; |
| fb_var.yres_virtual = export_yres; |
| fb_var.xoffset = 0; |
| fb_var.yoffset = 0; |
| fb_var.bits_per_pixel = 32; |
| fb_var.grayscale = 0; |
| fb_var.red.offset = 16; |
| fb_var.red.length = 8; |
| fb_var.red.msb_right = 0; |
| fb_var.green.offset = 8; |
| fb_var.green.length = 8; |
| fb_var.green.msb_right = 0; |
| fb_var.blue.offset = 0; |
| fb_var.blue.length = 8; |
| fb_var.blue.msb_right = 0; |
| fb_var.transp.offset = 0; |
| fb_var.transp.length = 0; |
| fb_var.transp.msb_right = 0; |
| fb_var.nonstd = 0; |
| fb_var.activate = 0; |
| fb_var.height = fb_var.xres / 4; |
| fb_var.width = fb_var.yres / 4; |
| fb_var.accel_flags = 0; |
| fb_var.pixclock = 0; |
| fb_var.left_margin = 0; |
| fb_var.right_margin = 0; |
| fb_var.upper_margin = 0; |
| fb_var.lower_margin = 0; |
| fb_var.hsync_len = 0; |
| fb_var.vsync_len = 0; |
| fb_var.sync = 0; |
| fb_var.vmode = FB_VMODE_NONINTERLACED; |
| fb_var.rotate = 0; |
| fb_var.colorspace = 0; |
| fb_var.reserved[0] = 0; |
| fb_var.reserved[1] = 0; |
| fb_var.reserved[2] = 0; |
| fb_var.reserved[3] = 0; |
| |
| strcpy(fb_fix.id, "fbtest"); |
| fb_fix.smem_start = 0; |
| fb_fix.smem_len = fb_var.xres * fb_var.yres * 4; |
| fb_fix.type = FB_TYPE_PACKED_PIXELS; |
| fb_fix.type_aux = 0; |
| fb_fix.visual = FB_VISUAL_TRUECOLOR; |
| fb_fix.xpanstep = 0; |
| fb_fix.ypanstep = 0; |
| fb_fix.ywrapstep = 0; |
| fb_fix.line_length = fb_var.xres * 4; |
| fb_fix.mmio_start = 0; |
| fb_fix.mmio_len = 0; |
| fb_fix.accel = FB_ACCEL_NONE; |
| fb_fix.capabilities = 0; |
| fb_fix.reserved[0] = 0; |
| fb_fix.reserved[1] = 0; |
| |
| fb = malloc(fb_fix.smem_len); |
| if (!fb) |
| Fatal("malloc %u: %s\n", fb_fix.smem_len, strerror(errno)); |
| } |
| |
| void export_fb(const char *name) |
| { |
| unsigned int x, y; |
| u32 *src, pixel; |
| char *filename; |
| u8 *line, *dst; |
| FILE *stream; |
| int res; |
| |
| res = asprintf(&filename, "%s%s.ppm", export_prefix, name); |
| if (res < 0) |
| Fatal("asprintf: %s\n", strerror(errno)); |
| |
| line = malloc(fb_var.xres * 3); |
| if (!line) |
| Fatal("malloc %u: %s\n", fb_var.xres * 3, strerror(errno)); |
| |
| Debug("Exporting to %s\n", filename); |
| stream = fopen(filename, "w"); |
| if (!stream) |
| Fatal("fopen %s: %s\n", filename, strerror(errno)); |
| |
| fputs("P6\n", stream); |
| fprintf(stream, "%u %u 255\n", fb_var.xres, fb_var.yres); |
| |
| src = (u32 *)fb; |
| for (y = 0; y < fb_var.yres; y++) { |
| dst = line; |
| for (x = 0; x < fb_var.xres; x++) { |
| pixel = *src++; |
| *dst++ = (pixel >> fb_var.red.offset) & 0xff; |
| *dst++ = (pixel >> fb_var.green.offset) & 0xff; |
| *dst++ = (pixel >> fb_var.blue.offset) & 0xff; |
| } |
| res = fwrite(line, 3, fb_var.xres, stream); |
| if (res < fb_var.xres) |
| Fatal("fwrite: %s\n", strerror(errno)); |
| } |
| |
| fclose(stream); |
| free(line); |
| free(filename); |
| } |