• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 
21 #include <fcntl.h>
22 #include <stdio.h>
23 
24 #include <sys/ioctl.h>
25 #include <sys/mman.h>
26 #include <sys/types.h>
27 
28 #include <linux/fb.h>
29 #include <linux/kd.h>
30 
31 #include <pixelflinger/pixelflinger.h>
32 
33 #include "font_10x18.h"
34 #include "minui.h"
35 
36 #if defined(RECOVERY_BGRA)
37 #define PIXEL_FORMAT GGL_PIXEL_FORMAT_BGRA_8888
38 #define PIXEL_SIZE   4
39 #elif defined(RECOVERY_RGBX)
40 #define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGBX_8888
41 #define PIXEL_SIZE   4
42 #else
43 #define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGB_565
44 #define PIXEL_SIZE   2
45 #endif
46 
47 #define NUM_BUFFERS 2
48 
49 typedef struct {
50     GGLSurface texture;
51     unsigned cwidth;
52     unsigned cheight;
53     unsigned ascent;
54 } GRFont;
55 
56 static GRFont *gr_font = 0;
57 static GGLContext *gr_context = 0;
58 static GGLSurface gr_font_texture;
59 static GGLSurface gr_framebuffer[NUM_BUFFERS];
60 static GGLSurface gr_mem_surface;
61 static unsigned gr_active_fb = 0;
62 static unsigned double_buffering = 0;
63 
64 static int gr_fb_fd = -1;
65 static int gr_vt_fd = -1;
66 
67 static struct fb_var_screeninfo vi;
68 static struct fb_fix_screeninfo fi;
69 
get_framebuffer(GGLSurface * fb)70 static int get_framebuffer(GGLSurface *fb)
71 {
72     int fd;
73     void *bits;
74 
75     fd = open("/dev/graphics/fb0", O_RDWR);
76     if (fd < 0) {
77         perror("cannot open fb0");
78         return -1;
79     }
80 
81     if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
82         perror("failed to get fb0 info");
83         close(fd);
84         return -1;
85     }
86 
87     vi.bits_per_pixel = PIXEL_SIZE * 8;
88     if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_BGRA_8888) {
89       vi.red.offset     = 8;
90       vi.red.length     = 8;
91       vi.green.offset   = 16;
92       vi.green.length   = 8;
93       vi.blue.offset    = 24;
94       vi.blue.length    = 8;
95       vi.transp.offset  = 0;
96       vi.transp.length  = 8;
97     } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBX_8888) {
98       vi.red.offset     = 24;
99       vi.red.length     = 8;
100       vi.green.offset   = 16;
101       vi.green.length   = 8;
102       vi.blue.offset    = 8;
103       vi.blue.length    = 8;
104       vi.transp.offset  = 0;
105       vi.transp.length  = 8;
106     } else { /* RGB565*/
107       vi.red.offset     = 11;
108       vi.red.length     = 5;
109       vi.green.offset   = 5;
110       vi.green.length   = 6;
111       vi.blue.offset    = 0;
112       vi.blue.length    = 5;
113       vi.transp.offset  = 0;
114       vi.transp.length  = 0;
115     }
116     if (ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
117         perror("failed to put fb0 info");
118         close(fd);
119         return -1;
120     }
121 
122     if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
123         perror("failed to get fb0 info");
124         close(fd);
125         return -1;
126     }
127 
128     bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
129     if (bits == MAP_FAILED) {
130         perror("failed to mmap framebuffer");
131         close(fd);
132         return -1;
133     }
134 
135     fb->version = sizeof(*fb);
136     fb->width = vi.xres;
137     fb->height = vi.yres;
138     fb->stride = fi.line_length/PIXEL_SIZE;
139     fb->data = bits;
140     fb->format = PIXEL_FORMAT;
141     memset(fb->data, 0, vi.yres * fi.line_length);
142 
143     fb++;
144 
145     /* check if we can use double buffering */
146     if (vi.yres * fi.line_length * 2 > fi.smem_len)
147         return fd;
148 
149     double_buffering = 1;
150 
151     fb->version = sizeof(*fb);
152     fb->width = vi.xres;
153     fb->height = vi.yres;
154     fb->stride = fi.line_length/PIXEL_SIZE;
155     fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length);
156     fb->format = PIXEL_FORMAT;
157     memset(fb->data, 0, vi.yres * fi.line_length);
158 
159     return fd;
160 }
161 
get_memory_surface(GGLSurface * ms)162 static void get_memory_surface(GGLSurface* ms) {
163   ms->version = sizeof(*ms);
164   ms->width = vi.xres;
165   ms->height = vi.yres;
166   ms->stride = fi.line_length/PIXEL_SIZE;
167   ms->data = malloc(fi.line_length * vi.yres);
168   ms->format = PIXEL_FORMAT;
169 }
170 
set_active_framebuffer(unsigned n)171 static void set_active_framebuffer(unsigned n)
172 {
173     if (n > 1 || !double_buffering) return;
174     vi.yres_virtual = vi.yres * NUM_BUFFERS;
175     vi.yoffset = n * vi.yres;
176     vi.bits_per_pixel = PIXEL_SIZE * 8;
177     if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
178         perror("active fb swap failed");
179     }
180 }
181 
gr_flip(void)182 void gr_flip(void)
183 {
184     GGLContext *gl = gr_context;
185 
186     /* swap front and back buffers */
187     if (double_buffering)
188         gr_active_fb = (gr_active_fb + 1) & 1;
189 
190     /* copy data from the in-memory surface to the buffer we're about
191      * to make active. */
192     memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
193            fi.line_length * vi.yres);
194 
195     /* inform the display driver */
196     set_active_framebuffer(gr_active_fb);
197 }
198 
gr_color(unsigned char r,unsigned char g,unsigned char b,unsigned char a)199 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
200 {
201     GGLContext *gl = gr_context;
202     GGLint color[4];
203     color[0] = ((r << 8) | r) + 1;
204     color[1] = ((g << 8) | g) + 1;
205     color[2] = ((b << 8) | b) + 1;
206     color[3] = ((a << 8) | a) + 1;
207     gl->color4xv(gl, color);
208 }
209 
gr_measure(const char * s)210 int gr_measure(const char *s)
211 {
212     return gr_font->cwidth * strlen(s);
213 }
214 
gr_font_size(int * x,int * y)215 void gr_font_size(int *x, int *y)
216 {
217     *x = gr_font->cwidth;
218     *y = gr_font->cheight;
219 }
220 
gr_text(int x,int y,const char * s)221 int gr_text(int x, int y, const char *s)
222 {
223     GGLContext *gl = gr_context;
224     GRFont *font = gr_font;
225     unsigned off;
226 
227     y -= font->ascent;
228 
229     gl->bindTexture(gl, &font->texture);
230     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
231     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
232     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
233     gl->enable(gl, GGL_TEXTURE_2D);
234 
235     while((off = *s++)) {
236         off -= 32;
237         if (off < 96) {
238             gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
239             gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
240         }
241         x += font->cwidth;
242     }
243 
244     return x;
245 }
246 
gr_texticon(int x,int y,gr_surface icon)247 void gr_texticon(int x, int y, gr_surface icon) {
248     if (gr_context == NULL || icon == NULL) {
249         return;
250     }
251     GGLContext* gl = gr_context;
252 
253     gl->bindTexture(gl, (GGLSurface*) icon);
254     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
255     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
256     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
257     gl->enable(gl, GGL_TEXTURE_2D);
258 
259     int w = gr_get_width(icon);
260     int h = gr_get_height(icon);
261 
262     gl->texCoord2i(gl, -x, -y);
263     gl->recti(gl, x, y, x+gr_get_width(icon), y+gr_get_height(icon));
264 }
265 
gr_fill(int x,int y,int w,int h)266 void gr_fill(int x, int y, int w, int h)
267 {
268     GGLContext *gl = gr_context;
269     gl->disable(gl, GGL_TEXTURE_2D);
270     gl->recti(gl, x, y, w, h);
271 }
272 
gr_blit(gr_surface source,int sx,int sy,int w,int h,int dx,int dy)273 void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
274     if (gr_context == NULL || source == NULL) {
275         return;
276     }
277     GGLContext *gl = gr_context;
278 
279     gl->bindTexture(gl, (GGLSurface*) source);
280     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
281     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
282     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
283     gl->enable(gl, GGL_TEXTURE_2D);
284     gl->texCoord2i(gl, sx - dx, sy - dy);
285     gl->recti(gl, dx, dy, dx + w, dy + h);
286 }
287 
gr_get_width(gr_surface surface)288 unsigned int gr_get_width(gr_surface surface) {
289     if (surface == NULL) {
290         return 0;
291     }
292     return ((GGLSurface*) surface)->width;
293 }
294 
gr_get_height(gr_surface surface)295 unsigned int gr_get_height(gr_surface surface) {
296     if (surface == NULL) {
297         return 0;
298     }
299     return ((GGLSurface*) surface)->height;
300 }
301 
gr_init_font(void)302 static void gr_init_font(void)
303 {
304     GGLSurface *ftex;
305     unsigned char *bits, *rle;
306     unsigned char *in, data;
307 
308     gr_font = calloc(sizeof(*gr_font), 1);
309     ftex = &gr_font->texture;
310 
311     bits = malloc(font.width * font.height);
312 
313     ftex->version = sizeof(*ftex);
314     ftex->width = font.width;
315     ftex->height = font.height;
316     ftex->stride = font.width;
317     ftex->data = (void*) bits;
318     ftex->format = GGL_PIXEL_FORMAT_A_8;
319 
320     in = font.rundata;
321     while((data = *in++)) {
322         memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
323         bits += (data & 0x7f);
324     }
325 
326     gr_font->cwidth = font.cwidth;
327     gr_font->cheight = font.cheight;
328     gr_font->ascent = font.cheight - 2;
329 }
330 
gr_init(void)331 int gr_init(void)
332 {
333     gglInit(&gr_context);
334     GGLContext *gl = gr_context;
335 
336     gr_init_font();
337     gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
338     if (gr_vt_fd < 0) {
339         // This is non-fatal; post-Cupcake kernels don't have tty0.
340         perror("can't open /dev/tty0");
341     } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
342         // However, if we do open tty0, we expect the ioctl to work.
343         perror("failed KDSETMODE to KD_GRAPHICS on tty0");
344         gr_exit();
345         return -1;
346     }
347 
348     gr_fb_fd = get_framebuffer(gr_framebuffer);
349     if (gr_fb_fd < 0) {
350         gr_exit();
351         return -1;
352     }
353 
354     get_memory_surface(&gr_mem_surface);
355 
356     fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
357             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
358 
359         /* start with 0 as front (displayed) and 1 as back (drawing) */
360     gr_active_fb = 0;
361     set_active_framebuffer(0);
362     gl->colorBuffer(gl, &gr_mem_surface);
363 
364     gl->activeTexture(gl, 0);
365     gl->enable(gl, GGL_BLEND);
366     gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
367 
368     gr_fb_blank(true);
369     gr_fb_blank(false);
370 
371     return 0;
372 }
373 
gr_exit(void)374 void gr_exit(void)
375 {
376     close(gr_fb_fd);
377     gr_fb_fd = -1;
378 
379     free(gr_mem_surface.data);
380 
381     ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
382     close(gr_vt_fd);
383     gr_vt_fd = -1;
384 }
385 
gr_fb_width(void)386 int gr_fb_width(void)
387 {
388     return gr_framebuffer[0].width;
389 }
390 
gr_fb_height(void)391 int gr_fb_height(void)
392 {
393     return gr_framebuffer[0].height;
394 }
395 
gr_fb_data(void)396 gr_pixel *gr_fb_data(void)
397 {
398     return (unsigned short *) gr_mem_surface.data;
399 }
400 
gr_fb_blank(bool blank)401 void gr_fb_blank(bool blank)
402 {
403     int ret;
404 
405     ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
406     if (ret < 0)
407         perror("ioctl(): blank");
408 }
409