draw: merge put/get cmap ioctls
[fbpad.git] / draw.c
blobf6d1786a787f9b311bc989c67fe8d8530b83de4c
1 #include <fcntl.h>
2 #include <linux/fb.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <sys/ioctl.h>
6 #include <sys/mman.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include "config.h"
10 #include "draw.h"
11 #include "util.h"
13 #define MAXFBWIDTH (1 << 12)
14 #define BPP sizeof(fbval_t)
15 #define NLEVELS (1 << 8)
17 static int fd;
18 static unsigned char *fb;
19 static struct fb_var_screeninfo vinfo;
20 static struct fb_fix_screeninfo finfo;
22 static int fb_len()
24 return vinfo.xres_virtual * vinfo.yres_virtual * BPP;
27 static void fb_cmap_save(int save)
29 static unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
30 struct fb_cmap cmap;
31 int mr = 1 << vinfo.red.length;
32 int mg = 1 << vinfo.green.length;
33 int mb = 1 << vinfo.blue.length;
34 if (finfo.visual == FB_VISUAL_TRUECOLOR)
35 return;
36 cmap.start = 0;
37 cmap.len = MAX(mr, MAX(mg, mb));
38 cmap.red = red;
39 cmap.green = green;
40 cmap.blue = blue;
41 cmap.transp = 0;
42 ioctl(fd, save ? FBIOGETCMAP : FBIOPUTCMAP, &cmap);
45 void fb_cmap(void)
47 unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
48 struct fb_cmap cmap;
49 int mr = 1 << vinfo.red.length;
50 int mg = 1 << vinfo.green.length;
51 int mb = 1 << vinfo.blue.length;
52 int i;
53 if (finfo.visual == FB_VISUAL_TRUECOLOR)
54 return;
56 for (i = 0; i < mr; i++)
57 red[i] = (65535 / (mr - 1)) * i;
58 for (i = 0; i < mg; i++)
59 green[i] = (65535 / (mg - 1)) * i;
60 for (i = 0; i < mb; i++)
61 blue[i] = (65535 / (mb - 1)) * i;
63 cmap.start = 0;
64 cmap.len = MAX(mr, MAX(mg, mb));
65 cmap.red = red;
66 cmap.green = green;
67 cmap.blue = blue;
68 cmap.transp = 0;
70 ioctl(fd, FBIOPUTCMAP, &cmap);
73 static void xerror(char *msg)
75 perror(msg);
76 exit(1);
79 static void xdie(char *msg)
81 fprintf(stderr, "%s\n", msg);
82 exit(1);
85 void fb_init(void)
87 fd = open(FBDEV_PATH, O_RDWR);
88 if (fd == -1)
89 xerror("can't open " FBDEV_PATH);
90 if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
91 xerror("ioctl failed");
92 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
93 xerror("ioctl failed");
94 if ((vinfo.bits_per_pixel + 7) >> 3 != BPP)
95 xdie("fbval_t does not match framebuffer depth");
96 fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
97 if (fb == MAP_FAILED)
98 xerror("can't map the framebuffer");
99 fb_cmap_save(1);
100 fb_cmap();
103 void fb_set(int r, int c, fbval_t *mem, int len)
105 long loc = (c + vinfo.xoffset) * BPP +
106 (r + vinfo.yoffset) * finfo.line_length;
107 memcpy(fb + loc, mem, len * BPP);
110 void fb_free()
112 fb_cmap_save(0);
113 munmap(fb, fb_len());
114 close(fd);
117 static fbval_t color_bits(struct fb_bitfield *bf, fbval_t v)
119 fbval_t moved = v >> (8 - bf->length);
120 return moved << bf->offset;
123 fbval_t fb_color(unsigned char r, unsigned char g, unsigned char b)
125 return color_bits(&vinfo.red, r) |
126 color_bits(&vinfo.green, g) |
127 color_bits(&vinfo.blue, b);
130 int fb_rows(void)
132 return vinfo.yres;
135 int fb_cols(void)
137 return vinfo.xres;
140 static unsigned char *rowaddr(int r)
142 return fb + (r + vinfo.yoffset) * finfo.line_length;
145 static unsigned long cache[MAXFBWIDTH];
146 void fb_box(int sr, int sc, int er, int ec, fbval_t val)
148 int i;
149 int pc = sizeof(cache[0]) / sizeof(val);
150 int cn = MIN((ec - sc) / pc + 1, MAXFBWIDTH);
151 unsigned long nv = val;
152 for (i = 1; i < pc; i++)
153 nv = (nv << (sizeof(val) * 8)) | val;
154 for (i = 0; i < cn; i++)
155 cache[i] = nv;
156 for (i = sr; i < er; i++)
157 memcpy(rowaddr(i) + sc * BPP, cache, (ec - sc) * BPP);