clear fb on exit
[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
24 struct Graphics {
25         Rect screen_rect;
26         Rect clipping_rect;
27         int color_depth;
28         Pixmap *pixmap;
29 };
30
31 static Graphics *gfx;
32
33 bool init_gfx()
34 {
35         if(!(gfx = (Graphics*)sh_malloc(sizeof *gfx))) {
36                 return false;
37         }
38
39         dev_fd = -1;
40
41         if((dev_fd = open("/dev/fb0", O_RDWR)) == -1) {
42                 fprintf(stderr, "Cannot open /dev/fb0 : %s\n", strerror(errno));
43                 return false;
44         }
45
46         fb_var_screeninfo sinfo;
47         if(ioctl(dev_fd, FBIOGET_VSCREENINFO, &sinfo) == -1) {
48                 close(dev_fd);
49                 dev_fd = -1;
50                 fprintf(stderr, "Unable to get screen info : %s\n", strerror(errno));
51                 return false;
52         }
53
54         printf("width : %d height : %d\n : bpp : %d\n", sinfo.xres, sinfo.yres, sinfo.bits_per_pixel);
55         printf("virtual w: %d virtual h: %d\n", sinfo.xres_virtual, sinfo.yres_virtual);
56
57         gfx->screen_rect.x = gfx->screen_rect.y = 0;
58         gfx->screen_rect.width = sinfo.xres_virtual;
59         gfx->screen_rect.height = sinfo.yres_virtual;
60         gfx->color_depth = sinfo.bits_per_pixel;
61
62         set_clipping_rect(gfx->screen_rect);
63
64         int sz = FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth);
65         framebuffer = (unsigned char*)mmap(0, sz, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0);
66
67         if(framebuffer == (void*)-1) {
68                 close(dev_fd);
69                 dev_fd = -1;
70                 fprintf(stderr, "Cannot map the framebuffer to memory : %s\n", strerror(errno));
71                 return false;
72         }
73
74 // TODO: uncomment when I find how to use intelfb instead of i915 GRRRR.-       
75         fb_vblank vblank;
76         if(ioctl(dev_fd, FBIOGET_VBLANK, &vblank) == -1) {
77 //              fprintf(stderr, "FBIOGET_VBLANK error: %s\n", strerror(errno));
78         }
79 /*      
80         else {
81                 printf("flags: %x\n", vblank.flags);
82                 printf("count: %d\n", vblank.count);
83                 printf("beam position: %d, %d\n", vblank.hcount, vblank.vcount);
84         }
85 */
86
87         if(!(gfx->pixmap = (Pixmap*)sh_malloc(sizeof(Pixmap)))) {
88                 fprintf(stderr, "Failed to allocate pixmap.\n");
89                 return false;
90         }
91
92         gfx->pixmap->width = gfx->screen_rect.width;
93         gfx->pixmap->height = gfx->screen_rect.height;
94
95         int fbsize = gfx->pixmap->width * gfx->pixmap->height * gfx->color_depth / 8;
96         if(!(gfx->pixmap->pixels = (unsigned char*)sh_malloc(fbsize))) {
97                 fprintf(stderr, "failed to allocate the pixmap framebuffer.\n");
98                 return false;
99         }
100
101         return true;
102 }
103
104 void destroy_gfx()
105 {
106         clear_screen(0, 0, 0);
107         gfx_update();
108
109         if(dev_fd != -1) {
110                 close(dev_fd);
111         }
112
113         dev_fd = -1;
114
115         munmap(framebuffer, FRAMEBUFFER_SIZE(gfx->screen_rect.width, gfx->screen_rect.height, gfx->color_depth));
116         framebuffer = 0;
117
118         sh_free(gfx->pixmap->pixels);
119         gfx->pixmap->pixels = 0;
120         sh_free(gfx->pixmap);
121         sh_free(gfx);
122 }
123
124 unsigned char *get_framebuffer()
125 {
126         return gfx->pixmap->pixels;
127 }
128
129 Pixmap *get_framebuffer_pixmap()
130 {
131         return gfx->pixmap;
132 }
133
134 Rect get_screen_size()
135 {
136         return gfx->screen_rect;
137 }
138
139 int get_color_depth()
140 {
141         return gfx->color_depth;
142 }
143
144 void set_clipping_rect(const Rect &rect)
145 {
146         gfx->clipping_rect = rect_intersection(rect, get_screen_size());
147 }
148
149 const Rect &get_clipping_rect()
150 {
151         return gfx->clipping_rect;
152 }
153
154 void set_cursor_visibility(bool visible)
155 {
156         fb_cursor curs;
157         curs.enable = visible ? 1 : 0;
158
159         if(ioctl(dev_fd, FBIO_CURSOR, &curs) == -1) {
160                 fprintf(stderr, "Cannot toggle cursor visibility : %s\n", strerror(errno));
161         }
162 }
163
164 void gfx_update()
165 {
166         memcpy(framebuffer, gfx->pixmap->pixels, gfx->pixmap->width * gfx->pixmap->height * (gfx->color_depth / 8));
167 }
168
169 void wait_vsync()
170 {
171         unsigned long arg = 0;
172         if(ioctl(dev_fd, FBIO_WAITFORVSYNC, &arg) == -1) {
173 //              printf("ioctl error %s\n", strerror(errno));
174         }
175 }
176
177 #endif // WINNIE_FBDEV