new file mode 100644
@@ -0,0 +1,176 @@
+
+/*
+ * 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);
+}
@@ -20,6 +20,7 @@
#include <unistd.h>
#include "types.h"
+#include "export.h"
#include "fb.h"
#include "util.h"
#include "colormap.h"
@@ -429,6 +430,11 @@ static void var_fix_validate(void)
void fb_init(void)
{
+ if (Opt_Export) {
+ export_init();
+ return;
+ }
+
Debug("fb_init()\n");
fb_open();
fb_get_var();
@@ -490,6 +496,9 @@ void fb_init(void)
void fb_cleanup(void)
{
+ if (Opt_Export)
+ return;
+
Debug("fb_cleanup()\n");
if (saved_fb)
fb_restore();
new file mode 100644
@@ -0,0 +1,14 @@
+
+/*
+ * (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 DEFAULT_EXPORT_XRES 640
+#define DEFAULT_EXPORT_YRES 480
+
+extern void export_init(void);
+extern void export_fb(const char *name);
@@ -103,6 +103,7 @@ extern double benchmark(void (*func)(unsigned long n, void *data), void *data);
* Command line options
*/
+extern const char *Opt_Export;
extern const char *Opt_Fbdev;
extern int Opt_Debug;
extern int Opt_List;
@@ -16,6 +16,7 @@
#include "types.h"
#include "util.h"
+#include "export.h"
#include "fb.h"
#include "drawops.h"
#include "visual.h"
@@ -28,6 +29,7 @@
const char *ProgramName;
const char *Opt_Fbdev = DEFAULT_FBDEV;
+const char *Opt_Export;
int Opt_Debug = 0;
int Opt_List = 0;
int Opt_Quiet = 0;
@@ -42,16 +44,21 @@ static void Usage(void) __attribute__ ((noreturn));
static void Usage(void)
{
- printf("%s: [options] [test ...]\n\n"
+ printf("%s: [options] [<test> ...]\n\n"
"Valid options are:\n"
- " -h, --help Display this usage information\n"
- " -f, --fbdev dev Specify frame buffer device (default: %s)\n"
- " -d, --debug Enable debug mode\n"
- " -l, --list List tests only, don't run them\n"
- " -q, --quiet Suppress messages\n"
- " -v, --verbose Enable verbose mode\n"
+ " -h, --help Display this usage information\n"
+ " -e, --export <prefix>[,<xres>[,<yres>]]\n"
+ " Do not use a frame buffer device, but operate on a\n"
+ " virtual buffer in RAM, and export the result as a PPM\n"
+ " image in <prefix><test>.ppm (default size: %ux%u)\n"
+ " -f, --fbdev <dev> Specify frame buffer device (default: %s)\n"
+ " -d, --debug Enable debug mode\n"
+ " -l, --list List tests only, don't run them\n"
+ " -q, --quiet Suppress messages\n"
+ " -v, --verbose Enable verbose mode\n"
"\n",
- ProgramName, DEFAULT_FBDEV);
+ ProgramName, DEFAULT_EXPORT_XRES, DEFAULT_EXPORT_YRES,
+ DEFAULT_FBDEV);
exit(1);
}
@@ -78,7 +85,15 @@ int main(int argc, char *argv[])
while (argc > 1 && argv[1][0] == '-') {
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
Usage();
- else if (!strcmp(argv[1], "-f") || !strcmp(argv[1], "--fbdev")) {
+ else if (!strcmp(argv[1], "-e") || !strcmp(argv[1], "--export")) {
+ if (argc <= 2)
+ Usage();
+ else {
+ Opt_Export = argv[2];
+ argv += 2;
+ argc -= 2;
+ }
+ } else if (!strcmp(argv[1], "-f") || !strcmp(argv[1], "--fbdev")) {
if (argc <= 2)
Usage();
else {
@@ -12,6 +12,7 @@
#include <stdio.h>
#include <string.h>
+#include "export.h"
#include "types.h"
#include "fb.h"
#include "visual.h"
@@ -81,6 +82,8 @@ static void run_one_test(const struct test *test)
switch (res) {
case TEST_OK:
Message("%s: PASSED\n", test->name);
+ if (Opt_Export)
+ export_fb(test->name);
break;
case TEST_FAIL:
@@ -125,6 +125,9 @@ void Fatal(const char *fmt, ...)
void wait_for_key(int timeout)
{
+ if (Opt_Export)
+ return;
+
/* FIXME: no keypress handling yet */
sleep(2);
}
@@ -138,6 +141,9 @@ void wait_ms(int ms)
{
struct timespec req;
+ if (Opt_Export)
+ return;
+
req.tv_sec = ms/1000;
req.tv_nsec = (ms % 1000)*1000000;
nanosleep(&req, NULL);
Add support for operating on a virtual buffer in RAM instead of on a real frame buffer device, and exporting the result as a PPM image. The size of the virtual buffer is configurable, but for now the format is fixed to Truecolor 8:8:8:0. This is useful for e.g. testing drawing algorithms on screen sizes not supported by your hardware. Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> --- export.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++ fb.c | 9 +++ include/export.h | 14 ++++ include/util.h | 1 + main.c | 33 ++++++--- tests.c | 3 + util.c | 6 ++ 7 files changed, 233 insertions(+), 9 deletions(-) create mode 100644 export.c create mode 100644 include/export.h