• 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 typedef struct {
48     GGLSurface texture;
49     unsigned cwidth;
50     unsigned cheight;
51     unsigned ascent;
52 } GRFont;
53 
54 static GRFont *gr_font = 0;
55 static GGLContext *gr_context = 0;
56 static GGLSurface gr_font_texture;
57 static GGLSurface gr_framebuffer[2];
58 static GGLSurface gr_mem_surface;
59 static unsigned gr_active_fb = 0;
60 
61 static int gr_fb_fd = -1;
62 static int gr_vt_fd = -1;
63 
64 static struct fb_var_screeninfo vi;
65 static struct fb_fix_screeninfo fi;
66 
get_framebuffer(GGLSurface * fb)67 static int get_framebuffer(GGLSurface *fb)
68 {
69     int fd;
70     void *bits;
71 
72     fd = open("/dev/graphics/fb0", O_RDWR);
73     if (fd < 0) {
74         perror("cannot open fb0");
75         return -1;
76     }
77 
78     if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
79         perror("failed to get fb0 info");
80         close(fd);
81         return -1;
82     }
83 
84     vi.bits_per_pixel = PIXEL_SIZE * 8;
85     if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_BGRA_8888) {
86       vi.red.offset     = 8;
87       vi.red.length     = 8;
88       vi.green.offset   = 16;
89       vi.green.length   = 8;
90       vi.blue.offset    = 24;
91       vi.blue.length    = 8;
92       vi.transp.offset  = 0;
93       vi.transp.length  = 8;
94     } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBX_8888) {
95       vi.red.offset     = 24;
96       vi.red.length     = 8;
97       vi.green.offset   = 16;
98       vi.green.length   = 8;
99       vi.blue.offset    = 8;
100       vi.blue.length    = 8;
101       vi.transp.offset  = 0;
102       vi.transp.length  = 8;
103     } else { /* RGB565*/
104       vi.red.offset     = 11;
105       vi.red.length     = 5;
106       vi.green.offset   = 5;
107       vi.green.length   = 6;
108       vi.blue.offset    = 0;
109       vi.blue.length    = 5;
110       vi.transp.offset  = 0;
111       vi.transp.length  = 0;
112     }
113     if (ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
114         perror("failed to put fb0 info");
115         close(fd);
116         return -1;
117     }
118 
119     if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
120         perror("failed to get fb0 info");
121         close(fd);
122         return -1;
123     }
124 
125     bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
126     if (bits == MAP_FAILED) {
127         perror("failed to mmap framebuffer");
128         close(fd);
129         return -1;
130     }
131 
132     fb->version = sizeof(*fb);
133     fb->width = vi.xres;
134     fb->height = vi.yres;
135     fb->stride = fi.line_length/PIXEL_SIZE;
136     fb->data = bits;
137     fb->format = PIXEL_FORMAT;
138     memset(fb->data, 0, vi.yres * fi.line_length);
139 
140     fb++;
141 
142     fb->version = sizeof(*fb);
143     fb->width = vi.xres;
144     fb->height = vi.yres;
145     fb->stride = fi.line_length/PIXEL_SIZE;
146     fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length);
147     fb->format = PIXEL_FORMAT;
148     memset(fb->data, 0, vi.yres * fi.line_length);
149 
150     return fd;
151 }
152 
get_memory_surface(GGLSurface * ms)153 static void get_memory_surface(GGLSurface* ms) {
154   ms->version = sizeof(*ms);
155   ms->width = vi.xres;
156   ms->height = vi.yres;
157   ms->stride = fi.line_length/PIXEL_SIZE;
158   ms->data = malloc(fi.line_length * vi.yres);
159   ms->format = PIXEL_FORMAT;
160 }
161 
set_active_framebuffer(unsigned n)162 static void set_active_framebuffer(unsigned n)
163 {
164     if (n > 1) return;
165     vi.yres_virtual = vi.yres * PIXEL_SIZE;
166     vi.yoffset = n * vi.yres;
167     vi.bits_per_pixel = PIXEL_SIZE * 8;
168     if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
169         perror("active fb swap failed");
170     }
171 }
172 
gr_flip(void)173 void gr_flip(void)
174 {
175     GGLContext *gl = gr_context;
176 
177     /* swap front and back buffers */
178     gr_active_fb = (gr_active_fb + 1) & 1;
179 
180     /* copy data from the in-memory surface to the buffer we're about
181      * to make active. */
182     memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
183            fi.line_length * vi.yres);
184 
185     /* inform the display driver */
186     set_active_framebuffer(gr_active_fb);
187 }
188 
gr_color(unsigned char r,unsigned char g,unsigned char b,unsigned char a)189 void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
190 {
191     GGLContext *gl = gr_context;
192     GGLint color[4];
193     color[0] = ((r << 8) | r) + 1;
194     color[1] = ((g << 8) | g) + 1;
195     color[2] = ((b << 8) | b) + 1;
196     color[3] = ((a << 8) | a) + 1;
197     gl->color4xv(gl, color);
198 }
199 
gr_measure(const char * s)200 int gr_measure(const char *s)
201 {
202     return gr_font->cwidth * strlen(s);
203 }
204 
gr_font_size(int * x,int * y)205 void gr_font_size(int *x, int *y)
206 {
207     *x = gr_font->cwidth;
208     *y = gr_font->cheight;
209 }
210 
gr_text(int x,int y,const char * s)211 int gr_text(int x, int y, const char *s)
212 {
213     GGLContext *gl = gr_context;
214     GRFont *font = gr_font;
215     unsigned off;
216 
217     y -= font->ascent;
218 
219     gl->bindTexture(gl, &font->texture);
220     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
221     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
222     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
223     gl->enable(gl, GGL_TEXTURE_2D);
224 
225     while((off = *s++)) {
226         off -= 32;
227         if (off < 96) {
228             gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
229             gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
230         }
231         x += font->cwidth;
232     }
233 
234     return x;
235 }
236 
gr_fill(int x,int y,int w,int h)237 void gr_fill(int x, int y, int w, int h)
238 {
239     GGLContext *gl = gr_context;
240     gl->disable(gl, GGL_TEXTURE_2D);
241     gl->recti(gl, x, y, w, h);
242 }
243 
gr_blit(gr_surface source,int sx,int sy,int w,int h,int dx,int dy)244 void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
245     if (gr_context == NULL) {
246         return;
247     }
248     GGLContext *gl = gr_context;
249 
250     gl->bindTexture(gl, (GGLSurface*) source);
251     gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
252     gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
253     gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
254     gl->enable(gl, GGL_TEXTURE_2D);
255     gl->texCoord2i(gl, sx - dx, sy - dy);
256     gl->recti(gl, dx, dy, dx + w, dy + h);
257 }
258 
gr_get_width(gr_surface surface)259 unsigned int gr_get_width(gr_surface surface) {
260     if (surface == NULL) {
261         return 0;
262     }
263     return ((GGLSurface*) surface)->width;
264 }
265 
gr_get_height(gr_surface surface)266 unsigned int gr_get_height(gr_surface surface) {
267     if (surface == NULL) {
268         return 0;
269     }
270     return ((GGLSurface*) surface)->height;
271 }
272 
gr_init_font(void)273 static void gr_init_font(void)
274 {
275     GGLSurface *ftex;
276     unsigned char *bits, *rle;
277     unsigned char *in, data;
278 
279     gr_font = calloc(sizeof(*gr_font), 1);
280     ftex = &gr_font->texture;
281 
282     bits = malloc(font.width * font.height);
283 
284     ftex->version = sizeof(*ftex);
285     ftex->width = font.width;
286     ftex->height = font.height;
287     ftex->stride = font.width;
288     ftex->data = (void*) bits;
289     ftex->format = GGL_PIXEL_FORMAT_A_8;
290 
291     in = font.rundata;
292     while((data = *in++)) {
293         memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
294         bits += (data & 0x7f);
295     }
296 
297     gr_font->cwidth = font.cwidth;
298     gr_font->cheight = font.cheight;
299     gr_font->ascent = font.cheight - 2;
300 }
301 
gr_init(void)302 int gr_init(void)
303 {
304     gglInit(&gr_context);
305     GGLContext *gl = gr_context;
306 
307     gr_init_font();
308     gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
309     if (gr_vt_fd < 0) {
310         // This is non-fatal; post-Cupcake kernels don't have tty0.
311         perror("can't open /dev/tty0");
312     } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
313         // However, if we do open tty0, we expect the ioctl to work.
314         perror("failed KDSETMODE to KD_GRAPHICS on tty0");
315         gr_exit();
316         return -1;
317     }
318 
319     gr_fb_fd = get_framebuffer(gr_framebuffer);
320     if (gr_fb_fd < 0) {
321         gr_exit();
322         return -1;
323     }
324 
325     get_memory_surface(&gr_mem_surface);
326 
327     fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
328             gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
329 
330         /* start with 0 as front (displayed) and 1 as back (drawing) */
331     gr_active_fb = 0;
332     set_active_framebuffer(0);
333     gl->colorBuffer(gl, &gr_mem_surface);
334 
335     gl->activeTexture(gl, 0);
336     gl->enable(gl, GGL_BLEND);
337     gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
338 
339     gr_fb_blank(true);
340     gr_fb_blank(false);
341 
342     return 0;
343 }
344 
gr_exit(void)345 void gr_exit(void)
346 {
347     close(gr_fb_fd);
348     gr_fb_fd = -1;
349 
350     free(gr_mem_surface.data);
351 
352     ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
353     close(gr_vt_fd);
354     gr_vt_fd = -1;
355 }
356 
gr_fb_width(void)357 int gr_fb_width(void)
358 {
359     return gr_framebuffer[0].width;
360 }
361 
gr_fb_height(void)362 int gr_fb_height(void)
363 {
364     return gr_framebuffer[0].height;
365 }
366 
gr_fb_data(void)367 gr_pixel *gr_fb_data(void)
368 {
369     return (unsigned short *) gr_mem_surface.data;
370 }
371 
gr_fb_blank(bool blank)372 void gr_fb_blank(bool blank)
373 {
374     int ret;
375 
376     ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
377     if (ret < 0)
378         perror("ioctl(): blank");
379 }
380