bug fixes, added background image
[winnie] / src / fbdev / gfx.cc
1 #ifdef WINNIE_FBDEV
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <sys/mman.h>
11 #include <sys/time.h>
12 #include <unistd.h>
13
14 #include <linux/fb.h>
15
16 #include "gfx.h"
17 #include "shalloc.h"
18
19 #define FRAMEBUFFER_SIZE(xsz, ysz, bpp) ((xsz) * (ysz) * (bpp) / CHAR_BIT)
20
21 static unsigned char *framebuffer;
22 static int dev_fd;
23 static int rgb_order[3];
24
25 struct Graphics {
26         Rect screen_rect;
27         Rect clipping_rect;
28         int color_depth;
29         Pixmap *pixmap;
30 };
31
32 static Graphics *gfx;
33
34 bool init_gfx()
35 {
36         if(!(gfx = (Graphics*)sh_malloc(sizeof *gfx))) {
37                 return false;
38         }
39
40         dev_fd = -1;
41
42         if((dev_fd = open("/dev/fb0", O_RDWR)) == -1) {
43                 fprintf(stderr, "Cannot open /dev/fb0 : %s\n", strerror(errno));
44                 return false;
45         }
46
47         fb_var_screeninfo sinfo;
48         if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo) == -1) {
49                 close(dev_fd);
50                 dev_fd = -1;
51                 fprintf(stderr, "Unable to get screen info : %s\n", strerror(errno));
52                 return false;
53         }
54
55         printf("width : %d height : %d\n : bpp : %d\n", sinfo.xres, sinfo.yres, sinfo.bits_per_pixel);
56         printf("virtual w: %d virtual h: %d\n", sinfo.xres_virtual, sinfo.yres_virtual);
57
58         gfx->screen_rect.x = gfx->screen_rect.y = 0;
59         gfx->screen_rect.width = sinfo.xres_virtual;
60         gfx->screen_rect.height = sinfo.yres_virtual;
61         gfx->color_depth = sinfo.bits_per_pixel;
62
63         rgb_order[0] = sinfo.red.offset / 8;
64         rgb_order[1] = sinfo.green.offset / 8;
65         rgb_order[2] = sinfo.blue.offset / 8;
66
67         set_clipping_rect(gfx->screen_rect);
68
69         int sz = FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth);
70         framebuffer = (unsigned char*)mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
71
72         if(framebuffer == (void*)-1) {
73                 close(dev_fd);
74                 dev_fd = -1;
75                 fprintf(stderr, "Cannot map the framebuffer to memory : %s\n", strerror(errno));
76                 return false;
77         }
78
79 // TODO: uncomment when I find how to use intelfb instead of i915 GRRRR.-       
80         fb_vblank vblank;
81         if(ioctl(dev_fd, FBIOGET_VBLANK, &vblank) == -1) {
82 //              fprintf(stderr, "FBIOGET_VBLANK error: %s\n", strerror(errno));
83         }
84 /*      
85         else {
86                 printf("flags: %x\n", vblank.flags);
87                 printf("count: %d\n", vblank.count);
88                 printf("beam position: %d, %d\n", vblank.hcount, vblank.vcount);
89         }
90 */
91
92         if(!(gfx->pixmap = (Pixmap*)sh_malloc(sizeof(Pixmap)))) {
93                 fprintf(stderr, "Failed to allocate pixmap.\n");
94                 return false;
95         }
96
97         gfx->pixmap->width = gfx->screen_rect.width;
98         gfx->pixmap->height = gfx->screen_rect.height;
99
100         int fbsize = gfx->pixmap->width * gfx->pixmap->height * gfx->color_depth / 8;
101         if(!(gfx->pixmap->pixels = (unsigned char*)sh_malloc(fbsize))) {
102                 fprintf(stderr, "failed to allocate the pixmap framebuffer.\n");
103                 return false;
104         }
105
106         return true;
107 }
108
109 void destroy_gfx()
110 {
111         clear_screen(0, 0, 0);
112         gfx_update(gfx->screen_rect);
113
114         if(dev_fd != -1) {
115                 close(dev_fd);
116         }
117
118         dev_fd = -1;
119
120         munmap(framebuffer, FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth));
121         framebuffer = 0;
122
123         sh_free(gfx->pixmap->pixels);
124         gfx->pixmap->pixels = 0;
125         sh_free(gfx->pixmap);
126         sh_free(gfx);
127 }
128
129 unsigned char *get_framebuffer()
130 {
131         return gfx->pixmap->pixels;
132 }
133
134 Pixmap *get_framebuffer_pixmap()
135 {
136         return gfx->pixmap;
137 }
138
139 Rect get_screen_size()
140 {
141         return gfx->screen_rect;
142 }
143
144 int get_color_depth()
145 {
146         return gfx->color_depth;
147 }
148
149 void set_clipping_rect(const Rect &rect)
150 {
151         gfx->clipping_rect = rect_intersection(rect, get_screen_size());
152 }
153
154 const Rect &get_clipping_rect()
155 {
156         return gfx->clipping_rect;
157 }
158
159 void set_cursor_visibility(bool visible)
160 {
161         fb_cursor curs;
162         curs.enable = visible ? 1 : 0;
163
164         if(ioctl(dev_fd, FBIO_CURSOR, &curs) == -1) {
165                 fprintf(stderr, "Cannot toggle cursor visibility : %s\n", strerror(errno));
166         }
167 }
168
169 void gfx_update(const Rect &upd_rect)
170 {
171         Rect rect = rect_intersection(upd_rect, gfx->screen_rect);
172         unsigned char *sptr = gfx->pixmap->pixels + (rect.y * gfx->screen_rect.width + rect.x) * 4;
173         unsigned char *dptr = framebuffer + (rect.y * gfx->screen_rect.width + rect.x) * 4;
174
175         for(int i=0; i<rect.height; i++) {
176                 memcpy(dptr, sptr, rect.width * 4);
177                 sptr += gfx->screen_rect.width * 4;
178                 dptr += gfx->screen_rect.width * 4;
179         }
180 }
181
182 void wait_vsync()
183 {
184         unsigned long arg = 0;
185         if(ioctl(dev_fd, FBIO_WAITFORVSYNC, &arg) == -1) {
186 //              printf("ioctl error %s\n", strerror(errno));
187         }
188 }
189
190 void get_rgb_order(int *r, int *g, int *b)
191 {
192         *r = rgb_order[0];
193         *g = rgb_order[1];
194         *b = rgb_order[2];
195 }
196
197 #endif // WINNIE_FBDEV