blob: 05e876300ff53ac432900af8d638af1fb49dec69 [file] [log] [blame]
The Android Open Source Project23580ca2008-10-21 07:00:00 -07001/*
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 <stdlib.h>
18#include <unistd.h>
19
20#include <fcntl.h>
21#include <stdio.h>
22
23#include <sys/ioctl.h>
24#include <sys/mman.h>
25#include <sys/types.h>
26
27#include <linux/fb.h>
28#include <linux/kd.h>
29
30#include <pixelflinger/pixelflinger.h>
31
32#include "font_10x18.h"
33#include "minui.h"
34
35typedef struct {
36 GGLSurface texture;
37 unsigned cwidth;
38 unsigned cheight;
39 unsigned ascent;
40} GRFont;
41
42static GRFont *gr_font = 0;
43static GGLContext *gr_context = 0;
44static GGLSurface gr_font_texture;
45static GGLSurface gr_framebuffer[2];
46static unsigned gr_active_fb = 0;
47
48static int gr_fb_fd = -1;
49static int gr_vt_fd = -1;
50
51static struct fb_var_screeninfo vi;
52
53static int get_framebuffer(GGLSurface *fb)
54{
55 int fd;
56 struct fb_fix_screeninfo fi;
57 void *bits;
58
59 fd = open("/dev/graphics/fb0", O_RDWR);
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080060 if (fd < 0) {
The Android Open Source Project23580ca2008-10-21 07:00:00 -070061 perror("cannot open fb0");
62 return -1;
63 }
64
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080065 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
The Android Open Source Project23580ca2008-10-21 07:00:00 -070066 perror("failed to get fb0 info");
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080067 close(fd);
The Android Open Source Project23580ca2008-10-21 07:00:00 -070068 return -1;
69 }
70
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080071 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
The Android Open Source Project23580ca2008-10-21 07:00:00 -070072 perror("failed to get fb0 info");
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080073 close(fd);
The Android Open Source Project23580ca2008-10-21 07:00:00 -070074 return -1;
75 }
76
77 bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080078 if (bits == MAP_FAILED) {
The Android Open Source Project23580ca2008-10-21 07:00:00 -070079 perror("failed to mmap framebuffer");
The Android Open Source Projectff3d9382008-12-17 18:03:49 -080080 close(fd);
The Android Open Source Project23580ca2008-10-21 07:00:00 -070081 return -1;
82 }
83
84 fb->version = sizeof(*fb);
85 fb->width = vi.xres;
86 fb->height = vi.yres;
87 fb->stride = vi.xres;
88 fb->data = bits;
89 fb->format = GGL_PIXEL_FORMAT_RGB_565;
90
91 fb++;
92
93 fb->version = sizeof(*fb);
94 fb->width = vi.xres;
95 fb->height = vi.yres;
96 fb->stride = vi.xres;
97 fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
98 fb->format = GGL_PIXEL_FORMAT_RGB_565;
99
100 return fd;
101}
102
103static void set_active_framebuffer(unsigned n)
104{
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800105 if (n > 1) return;
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700106 vi.yres_virtual = vi.yres * 2;
107 vi.yoffset = n * vi.yres;
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800108 if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
109 perror("active fb swap failed");
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700110 }
111}
112
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700113void gr_flip(void)
114{
115 GGLContext *gl = gr_context;
116
117 /* currently active buffer becomes the backbuffer */
118 gl->colorBuffer(gl, gr_framebuffer + gr_active_fb);
119
120 /* swap front and back buffers */
121 gr_active_fb = (gr_active_fb + 1) & 1;
122
123 /* inform the display driver */
124 set_active_framebuffer(gr_active_fb);
125}
126
127void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
128{
129 GGLContext *gl = gr_context;
130 GGLint color[4];
131 color[0] = ((r << 8) | r) + 1;
132 color[1] = ((g << 8) | g) + 1;
133 color[2] = ((b << 8) | b) + 1;
134 color[3] = ((a << 8) | a) + 1;
135 gl->color4xv(gl, color);
136}
137
138int gr_measure(const char *s)
139{
140 return gr_font->cwidth * strlen(s);
141}
142
143int gr_text(int x, int y, const char *s)
144{
145 GGLContext *gl = gr_context;
146 GRFont *font = gr_font;
147 unsigned off;
148
149 y -= font->ascent;
150
151 gl->bindTexture(gl, &font->texture);
152 gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
153 gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
154 gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
155 gl->enable(gl, GGL_TEXTURE_2D);
156
157 while((off = *s++)) {
158 off -= 32;
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800159 if (off < 96) {
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700160 gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
161 gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
162 }
163 x += font->cwidth;
164 }
165
166 return x;
167}
168
169void gr_fill(int x, int y, int w, int h)
170{
171 GGLContext *gl = gr_context;
172 gl->disable(gl, GGL_TEXTURE_2D);
173 gl->recti(gl, x, y, w, h);
174}
175
176void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
177 if (gr_context == NULL) {
178 return;
179 }
180 GGLContext *gl = gr_context;
181
182 gl->bindTexture(gl, (GGLSurface*) source);
183 gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
184 gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
185 gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
186 gl->enable(gl, GGL_TEXTURE_2D);
187 gl->texCoord2i(gl, sx - dx, sy - dy);
188 gl->recti(gl, dx, dy, dx + w, dy + h);
189}
190
191unsigned int gr_get_width(gr_surface surface) {
192 if (surface == NULL) {
193 return 0;
194 }
195 return ((GGLSurface*) surface)->width;
196}
197
198unsigned int gr_get_height(gr_surface surface) {
199 if (surface == NULL) {
200 return 0;
201 }
202 return ((GGLSurface*) surface)->height;
203}
204
205static void gr_init_font(void)
206{
207 GGLSurface *ftex;
208 unsigned char *bits, *rle;
209 unsigned char *in, data;
210
211 gr_font = calloc(sizeof(*gr_font), 1);
212 ftex = &gr_font->texture;
213
214 bits = malloc(font.width * font.height);
215
216 ftex->version = sizeof(*ftex);
217 ftex->width = font.width;
218 ftex->height = font.height;
219 ftex->stride = font.width;
220 ftex->data = (void*) bits;
221 ftex->format = GGL_PIXEL_FORMAT_A_8;
222
223 in = font.rundata;
224 while((data = *in++)) {
225 memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
226 bits += (data & 0x7f);
227 }
228
229 gr_font->cwidth = font.cwidth;
230 gr_font->cheight = font.cheight;
231 gr_font->ascent = font.cheight - 2;
232}
233
234int gr_init(void)
235{
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700236 gglInit(&gr_context);
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800237 GGLContext *gl = gr_context;
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700238
239 gr_init_font();
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800240 gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
241 if (gr_vt_fd < 0) {
242 // This is non-fatal; post-Cupcake kernels don't have tty0.
243 perror("can't open /dev/tty0");
244 } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
245 // However, if we do open tty0, we expect the ioctl to work.
246 perror("failed KDSETMODE to KD_GRAPHICS on tty0");
247 gr_exit();
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700248 return -1;
249 }
250
251 gr_fb_fd = get_framebuffer(gr_framebuffer);
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800252 if (gr_fb_fd < 0) {
253 gr_exit();
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700254 return -1;
255 }
256
The Android Open Source Projectff3d9382008-12-17 18:03:49 -0800257 fprintf(stderr, "framebuffer: fd %d (%d x %d)\n",
258 gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height);
The Android Open Source Project23580ca2008-10-21 07:00:00 -0700259
260 /* start with 0 as front (displayed) and 1 as back (drawing) */
261 gr_active_fb = 0;
262 set_active_framebuffer(0);
263 gl->colorBuffer(gl, gr_framebuffer + 1);
264
265 gl->activeTexture(gl, 0);
266 gl->enable(gl, GGL_BLEND);
267 gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
268
269 return 0;
270}
271
272void gr_exit(void)
273{
274 close(gr_fb_fd);
275 gr_fb_fd = -1;
276
277 ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
278 close(gr_vt_fd);
279 gr_vt_fd = -1;
280}
281
282int gr_fb_width(void)
283{
284 return gr_framebuffer[0].width;
285}
286
287int gr_fb_height(void)
288{
289 return gr_framebuffer[0].height;
290}
291
292gr_pixel *gr_fb_data(void)
293{
294 return (unsigned short *) gr_framebuffer[1 - gr_active_fb].data;
295}