diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2019-02-04 12:00:07 +0100 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2019-02-04 12:00:07 +0100 |
commit | f33f5609a374ce8c80beecccc85fe49cae60e1ce (patch) | |
tree | e56aea1d2a04047d40b103933c9a6a2c7cac99ff | |
parent | 91856e84f0474fe64f95c5f3acc6981469e7ce46 (diff) | |
download | drminfo-f33f5609a374ce8c80beecccc85fe49cae60e1ce.tar.gz |
add fbtest
-rw-r--r-- | drminfo.spec | 1 | ||||
-rw-r--r-- | drmtest.c | 2 | ||||
-rw-r--r-- | fbtest.c | 107 | ||||
-rw-r--r-- | fbtools.c | 234 | ||||
-rw-r--r-- | fbtools.h | 10 | ||||
-rw-r--r-- | meson.build | 10 |
6 files changed, 363 insertions, 1 deletions
diff --git a/drminfo.spec b/drminfo.spec index e3b84e3..ecef075 100644 --- a/drminfo.spec +++ b/drminfo.spec @@ -38,4 +38,5 @@ ninja-build -C build-rpm install %{_bindir}/drm* %{_bindir}/prime %{_bindir}/virtiotest +%{_bindir}/fbtest %{_mandir}/man1/drm*.1* @@ -172,7 +172,7 @@ int main(int argc, char **argv) int c,i; for (;;) { - c = getopt(argc, argv, "hgdc:s:o:i:f:m:"); + c = getopt(argc, argv, "hc:s:o:i:f:m:"); if (c == -1) break; switch (c) { diff --git a/fbtest.c b/fbtest.c new file mode 100644 index 0000000..41afcd5 --- /dev/null +++ b/fbtest.c @@ -0,0 +1,107 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <inttypes.h> +#include <getopt.h> + +#include <sys/ioctl.h> +#include <sys/mman.h> + +#include <cairo.h> +#include <pixman.h> + +#include "fbtools.h" +#include "ttytools.h" +#include "render.h" +#include "image.h" + +/* ------------------------------------------------------------------ */ + +/* cairo */ +static cairo_surface_t *cs; + +/* user options */ +static cairo_surface_t *image; + +/* ------------------------------------------------------------------ */ + +static void fb_draw(const char *text) +{ + char info[80]; + cairo_t *cr; + + snprintf(info, sizeof(info), "fbtest: %dx%d", fb_var.xres, fb_var.yres); + cr = cairo_create(cs); + if (image) { + render_image(cr, fb_var.xres, fb_var.yres, image); + } else { + render_test(cr, fb_var.xres, fb_var.yres, info, text); + } + cairo_destroy(cr); +} + +/* ------------------------------------------------------------------ */ + +static void usage(FILE *fp) +{ + fprintf(fp, + "\n" + "usage: fbtest [ options ]\n" + "\n" + "options:\n" + " -h print this\n" + " -f <nr> pick framebuffer\n" + " -s <secs> set sleep time\n" + " -i <file> load and display image <file>\n" + "\n"); +} + +int main(int argc, char **argv) +{ + int framebuffer = 0; + int secs = 60; + char buf[32]; + int c; + + for (;;) { + c = getopt(argc, argv, "hs:i:f:"); + if (c == -1) + break; + switch (c) { + case 'f': + framebuffer = atoi(optarg); + break; + case 's': + secs = atoi(optarg); + break; + case 'i': + image = load_image(optarg); + break; + case 'h': + usage(stdout); + exit(0); + default: + usage(stderr); + exit(1); + } + } + + fb_init(framebuffer); + cs = cairo_image_surface_create_for_data(fb_mem + fb_mem_offset, + fb_format, + fb_var.xres, + fb_var.yres, + fb_fix.line_length); + fb_draw("*"); + + tty_raw(); + kbd_wait(secs); + read(0, buf, sizeof(buf)); + tty_restore(); + + fb_fini(); + return 0; +} diff --git a/fbtools.c b/fbtools.c new file mode 100644 index 0000000..8fb86f3 --- /dev/null +++ b/fbtools.c @@ -0,0 +1,234 @@ +/* + * some generic framebuffer device stuff + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <termios.h> +#include <signal.h> +#include <errno.h> +#include <setjmp.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <linux/kd.h> +#include <linux/vt.h> +#include <linux/fb.h> + +#include <cairo.h> + +#include "fbtools.h" + +/* -------------------------------------------------------------------- */ +/* internal variables */ + +struct fb_fix_screeninfo fb_fix; +struct fb_var_screeninfo fb_var; +unsigned char *fb_mem; +int fb_mem_offset = 0; +cairo_format_t fb_format = CAIRO_FORMAT_INVALID; + +static int fb; +static int kd_mode; +static bool kd_mode_restore = false; + +static struct termios term; +static struct fb_var_screeninfo fb_ovar; +static unsigned short ored[256], ogreen[256], oblue[256]; +static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue }; + +static unsigned short p_red[256], p_green[256], p_blue[256]; +static struct fb_cmap p_cmap = { 0, 256, p_red, p_green, p_blue }; + +/* -------------------------------------------------------------------- */ +/* palette handling */ + +static unsigned short color_scale(int n, int max) +{ + int ret = 65535.0 * (float)n/(max); + if (ret > 65535) ret = 65535; + if (ret < 0) ret = 0; + return ret; +} + +static void fb_linear_palette(int r, int g, int b) +{ + int i, size; + + size = 256 >> (8 - r); + for (i = 0; i < size; i++) + p_red[i] = color_scale(i,size); + p_cmap.len = size; + + size = 256 >> (8 - g); + for (i = 0; i < size; i++) + p_green[i] = color_scale(i,size); + if (p_cmap.len < size) + p_cmap.len = size; + + size = 256 >> (8 - b); + for (i = 0; i < size; i++) + p_blue[i] = color_scale(i,size); + if (p_cmap.len < size) + p_cmap.len = size; +} + +static void fb_set_palette(void) +{ + if (fb_fix.visual != FB_VISUAL_DIRECTCOLOR && fb_var.bits_per_pixel != 8) + return; + if (-1 == ioctl(fb,FBIOPUTCMAP,&p_cmap)) { + perror("ioctl FBIOPUTCMAP"); + exit(1); + } +} + +/* -------------------------------------------------------------------- */ +/* initialisation & cleanup */ + +static void +fb_memset (void *addr, int c, size_t len) +{ +#if 1 /* defined(__powerpc__) */ + unsigned int i, *p; + + i = (c & 0xff) << 8; + i |= i << 16; + len >>= 2; + for (p = addr; len--; p++) + *p = i; +#else + memset(addr, c, len); +#endif +} + +void fb_fini(void) +{ + /* restore console */ + if (-1 == ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar)) + perror("ioctl FBIOPUT_VSCREENINFO"); + if (-1 == ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix)) + perror("ioctl FBIOGET_FSCREENINFO"); + if (fb_ovar.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fb, FBIOPUTCMAP, &ocmap)) + perror("ioctl FBIOPUTCMAP"); + } + close(fb); + + if (kd_mode_restore) { + if (-1 == ioctl(STDIN_FILENO, KDSETMODE, kd_mode)) + perror("ioctl KDSETMODE"); + } + + tcsetattr(STDIN_FILENO, TCSANOW, &term); +} + +/* -------------------------------------------------------------------- */ + +void fb_init(int cardno) +{ + unsigned long page_mask; + char device[64]; + + snprintf(device, sizeof(device), "/dev/fb%d", cardno); + fprintf(stderr, "trying fbdev: %s ...\n", device); + + if (-1 == ioctl(STDIN_FILENO, KDGETMODE, &kd_mode)) { + perror("ioctl KDGETMODE"); + } else { + kd_mode_restore = true; + } + + /* get current settings (which we have to restore) */ + if (-1 == (fb = open(device,O_RDWR | O_CLOEXEC))) { + fprintf(stderr,"open %s: %s\n",device,strerror(errno)); + exit(1); + } + if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { + perror("ioctl FBIOGET_FSCREENINFO"); + exit(1); + } + if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) { + perror("ioctl FBIOGET_VSCREENINFO"); + exit(1); + } + if (fb_ovar.bits_per_pixel == 8 || + fb_fix.visual == FB_VISUAL_DIRECTCOLOR) { + if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) { + perror("ioctl FBIOGETCMAP"); + exit(1); + } + } + tcgetattr(STDIN_FILENO, &term); + + /* checks & initialisation */ + if (kd_mode_restore) { + if (-1 == ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS)) + perror("ioctl KDSETMODE"); + } + if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) { + perror("ioctl FBIOGET_FSCREENINFO"); + exit(1); + } + if (fb_fix.type != FB_TYPE_PACKED_PIXELS) { + fprintf(stderr,"can handle only packed pixel frame buffers\n"); + goto err; + } + page_mask = getpagesize()-1; + fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask; + fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset, + PROT_READ|PROT_WRITE,MAP_SHARED,fb,0); + if (-1L == (long)fb_mem) { + perror("mmap"); + goto err; + } + /* move viewport to upper left corner */ + if (fb_var.xoffset != 0 || fb_var.yoffset != 0) { + fb_var.xoffset = 0; + fb_var.yoffset = 0; + if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) { + perror("ioctl FBIOPAN_DISPLAY"); + goto err; + } + } + + /* cls */ + fb_memset(fb_mem+fb_mem_offset, 0, fb_fix.line_length * fb_var.yres); + + /* init palette */ + switch (fb_var.bits_per_pixel) { + case 16: + fb_format = CAIRO_FORMAT_RGB16_565; + fb_linear_palette(5,6,5); + break; + case 32: + fb_format = CAIRO_FORMAT_RGB24; + fb_linear_palette(8,8,8); + break; + default: + fprintf(stderr, "unsupported framebuffer format (%d bpp)\n", + fb_var.bits_per_pixel); + goto err; + + } + fb_set_palette(); + return; + + err: + fb_fini(); + exit(1); +} diff --git a/fbtools.h b/fbtools.h new file mode 100644 index 0000000..1dc6f17 --- /dev/null +++ b/fbtools.h @@ -0,0 +1,10 @@ +#include <linux/fb.h> + +extern struct fb_fix_screeninfo fb_fix; +extern struct fb_var_screeninfo fb_var; +extern unsigned char *fb_mem; +extern int fb_mem_offset; +extern cairo_format_t fb_format; + +void fb_init(int devnr); +void fb_fini(void); diff --git a/meson.build b/meson.build index 9392108..02ad834 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,9 @@ project('drminfo', 'c', default_options : [ 'c_std=c99' ] ) +# tweak warnings +add_global_arguments('-D_POSIX_SOURCE=1', language : 'c') +add_global_arguments('-D_GNU_SOURCE=1', language : 'c') + # pkg-config deps libdrm_dep = dependency('libdrm') gbm_dep = dependency('gbm') @@ -13,6 +17,7 @@ jpeg_dep = declare_dependency(link_args : '-ljpeg') drminfo_srcs = [ 'drminfo.c', 'drmtools.c' ] drmtest_srcs = [ 'drmtest.c', 'drmtools.c', 'ttytools.c', 'render.c', 'image.c' ] +fbtest_srcs = [ 'fbtest.c', 'fbtools.c', 'ttytools.c', 'render.c', 'image.c' ] prime_srcs = [ 'prime.c' ] viotest_srcs = [ 'virtiotest.c', 'drmtools.c', 'ttytools.c', 'render.c' ] gtktest_srcs = [ 'gtktest.c', 'render.c', 'image.c' ] @@ -20,6 +25,7 @@ gtktest_srcs = [ 'gtktest.c', 'render.c', 'image.c' ] drminfo_deps = [ libdrm_dep, cairo_dep, pixman_dep ] drmtest_deps = [ libdrm_dep, gbm_dep, epoxy_dep, cairo_dep, pixman_dep, jpeg_dep ] +fbtest_deps = [ cairo_dep, pixman_dep, jpeg_dep ] prime_deps = [ libdrm_dep, gbm_dep ] viotest_deps = [ libdrm_dep, gbm_dep, epoxy_dep, cairo_dep, pixman_dep, jpeg_dep ] @@ -34,6 +40,10 @@ executable('drmtest', sources : drmtest_srcs, dependencies : drmtest_deps, install : true) +executable('fbtest', + sources : fbtest_srcs, + dependencies : fbtest_deps, + install : true) executable('prime', sources : prime_srcs, dependencies : prime_deps, |