ioctl doesn't work for my intel
[winnie] / src / fbdev / gfx.cc
1 #ifdef WINNIE_FBDEV
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <string.h>
6
7 #include <fcntl.h>
8 #include <sys/ioctl.h>
9 #include <sys/mman.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12
13 #include <linux/fb.h>
14
15 #include "gfx.h"
16
17 #define FRAMEBUFFER_SIZE(xsz, ysz, bpp) ((xsz) * (ysz) * (bpp) / CHAR_BIT)
18
19 static unsigned char *framebuffer;
20 static int dev_fd = -1;
21
22 static Rect screen_rect;
23 static int color_depth; // bits per pixel
24
25 bool init_gfx()
26 {
27         if((dev_fd = open("/dev/fb0", O_RDWR)) == -1) {
28                 fprintf(stderr, "Cannot open /dev/fb0 : %s\n", strerror(errno));
29                 return false;
30         }
31
32         fb_var_screeninfo sinfo;
33         if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo) == -1) {
34                 close(dev_fd);
35                 dev_fd = -1;
36                 fprintf(stderr, "Unable to get screen info : %s\n", strerror(errno));
37                 return false;
38         }
39
40         printf("width : %d height : %d\n : bpp : %d\n", sinfo.xres, sinfo.yres, sinfo.bits_per_pixel);
41         printf("virtual w: %d virtual h: %d\n", sinfo.xres_virtual, sinfo.yres_virtual);
42
43         screen_rect.x = screen_rect.y = 0;
44         screen_rect.width = sinfo.xres_virtual;
45         screen_rect.height = sinfo.yres_virtual;
46         color_depth = sinfo.bits_per_pixel;
47
48         int sz = FRAMEBUFFER_SIZE(screen_rect.width, screen_rect.height, color_depth);
49         framebuffer = (unsigned char*)mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
50
51         if(framebuffer == (void*)-1) {
52                 close(dev_fd);
53                 dev_fd = -1;
54                 fprintf(stderr, "Cannot map the framebuffer to memory : %s\n", strerror(errno));
55                 return false;
56         }
57
58         fb_vblank vblank;
59         if(ioctl(dev_fd, FBIOGET_VBLANK, &vblank) == -1) {
60                 fprintf(stderr, "FBIOGET_VBLANK error: %s\n", strerror(errno));
61         }
62         else {
63                 printf("flags: %x\n", vblank.flags);
64                 printf("count: %d\n", vblank.count);
65                 printf("beam position: %d, %d\n", vblank.hcount, vblank.vcount);
66         }
67
68         return true;
69 }
70
71 void destroy_gfx()
72 {
73         clear_screen(0, 0, 0);
74
75         if(dev_fd != -1) {
76                 close(dev_fd);
77         }
78
79         dev_fd = -1;
80
81         munmap(framebuffer, FRAMEBUFFER_SIZE(screen_rect.width, screen_rect.height, color_depth));
82         framebuffer = 0;
83 }
84
85 unsigned char *get_framebuffer()
86 {
87         return framebuffer;
88 }
89
90 Rect get_screen_size()
91 {
92         return screen_rect;
93 }
94
95 int get_color_depth()
96 {
97         return color_depth;
98 }
99
100 void clear_screen(int r, int g, int b)
101 {
102         fill_rect(screen_rect, r, g, b);
103 }
104
105 void fill_rect(const Rect &rect, int r, int g, int b)
106 {
107         Rect drect = rect;
108
109         if(drect.x < screen_rect.x) {
110                 drect.width -= screen_rect.x - drect.x;
111                 drect.x = screen_rect.x;
112         }
113
114         if(drect.y < screen_rect.y) {
115                 drect.height -= screen_rect.y - drect.y;
116                 drect.y = screen_rect.y;
117         }
118
119         if(drect.x + drect.width >= screen_rect.x + screen_rect.width) {
120                 drect.width = screen_rect.width - drect.x;
121         }
122
123         if(drect.y + drect.height >= screen_rect.y + screen_rect.height) {
124                 drect.height = screen_rect.height - drect.y;
125         }
126
127         unsigned char *fb = framebuffer + (drect.x + screen_rect.width * drect.y) * 4;
128         for(int i=0; i<drect.height; i++) {
129                 for(int j=0; j<drect.width; j++) {
130                         fb[j * 4] = b;
131                         fb[j * 4 + 1] = g;
132                         fb[j * 4 + 2] = r;
133                 }
134                 fb += screen_rect.width * 4;
135         }
136 }
137
138 void set_cursor_visibility(bool visible)
139 {
140         fb_cursor curs;
141         curs.enable = visible ? 1 : 0;
142
143         if(ioctl(dev_fd, FBIO_CURSOR, &curs) == -1) {
144                 fprintf(stderr, "Cannot toggle cursor visibility : %s\n", strerror(errno));
145         }
146 }
147
148 void blit(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
149                 const Rect &dest_rect, int dest_x, int dest_y)
150 {
151         int width = src_rect.width;
152         int height = src_rect.height;
153
154         int xoffs = dest_x - dest_rect.x;
155         if(xoffs < 0) {
156                 dest_x = dest_rect.x;
157                 width += xoffs;
158         }
159
160         int yoffs = dest_y - dest_rect.y;
161         if(yoffs < 0) {
162                 dest_y = dest_rect.y;
163                 height += yoffs;
164         }
165
166         int xend = dest_x + width;
167         if(xend >= dest_rect.width) {
168                 width -= xend - dest_rect.width;
169         }
170
171         int yend = dest_y + height;
172         if(yend >= dest_rect.height) {
173                 height -= yend - dest_rect.height;
174         }
175
176         if(width <= 0 || height <= 0) {
177                 return;
178         }
179
180         unsigned char *sptr = src_img + (src_rect.y * src_rect.width + src_rect.x) * 4;
181         unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
182
183         for(int i=0; i<height; i++) {
184                 memcpy(dptr, sptr, width * 4);
185                 sptr += src_rect.width * 4;
186                 dptr += dest_rect.width * 4;
187         }
188 }
189
190 void blit_key(unsigned char *src_img, const Rect &src_rect, unsigned char* dest_img,
191                 const Rect &dest_rect, int dest_x, int dest_y, int key_r, int key_g, int key_b)
192 {
193         int width = src_rect.width;
194         int height = src_rect.height;
195
196         int xoffs = dest_x - dest_rect.x;
197         if(xoffs < 0) {
198                 dest_x = dest_rect.x;
199                 width += xoffs;
200         }
201
202         int yoffs = dest_y - dest_rect.y;
203         if(yoffs < 0) {
204                 dest_y = dest_rect.y;
205                 height += yoffs;
206         }
207
208         int xend = dest_x + width;
209         if(xend >= dest_rect.width) {
210                 width -= xend - dest_rect.width;
211         }
212
213         int yend = dest_y + height;
214         if(yend >= dest_rect.height) {
215                 height -= yend - dest_rect.height;
216         }
217
218         if(width <= 0 || height <= 0) {
219                 return;
220         }
221
222         unsigned char *sptr = src_img + (src_rect.y * src_rect.width + src_rect.x) * 4;
223         unsigned char *dptr = dest_img + (dest_y * dest_rect.width + dest_x) * 4;
224
225         for(int i=0; i<height; i++) {
226                 for(int j=0; j<width; j++) {
227                         int r = sptr[j * 4];
228                         int g = sptr[j * 4 + 1];
229                         int b = sptr[j * 4 + 2];
230
231                         if(r != key_r || g != key_g || b != key_b) {
232                                 dptr[j * 4] = b;
233                                 dptr[j * 4 + 1] = g;
234                                 dptr[j * 4 + 2] = r;
235                         }
236                 }
237
238                 sptr += src_rect.width * 4;
239                 dptr += dest_rect.width * 4;
240         }
241 }
242
243 void gfx_update()
244 {
245 }
246
247 void wait_vsync()
248 {
249         unsigned long arg = 0;
250
251         timeval tvstart, tvend;
252         gettimeofday(&tvstart, 0);
253         
254         if(ioctl(dev_fd, FBIO_WAITFORVSYNC, &arg) == -1) {
255                 printf("ioctl error %s\n", strerror(errno));
256         }
257
258         gettimeofday(&tvend, 0);
259         printf("%ld %ld\n", tvend.tv_sec - tvstart.tv_sec, tvend.tv_usec - tvstart.tv_usec);
260 }
261
262 #endif // WINNIE_FBDEV