blob: c2fc9ea9e58b4ac4843f2ddc34385f516255f8c0 [file] [log] [blame]
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -08001/*
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
Dima Zavin4daf48a2011-08-30 11:59:20 -070017#include <stdbool.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080018#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
Doug Zongker16f97c32014-03-06 16:16:05 -080031#include <time.h>
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080032
Doug Zongker6fd59ac2013-03-06 15:01:11 -080033#include "font_10x18.h"
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080034#include "minui.h"
35
36typedef struct {
Doug Zongker16f97c32014-03-06 16:16:05 -080037 GRSurface* texture;
38 int cwidth;
39 int cheight;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080040} GRFont;
41
Doug Zongker16f97c32014-03-06 16:16:05 -080042static GRFont* gr_font = NULL;
43
Doug Zongkerc560a672012-12-18 16:31:27 -080044static int overscan_percent = OVERSCAN_PERCENT;
45static int overscan_offset_x = 0;
46static int overscan_offset_y = 0;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080047
48static int gr_fb_fd = -1;
49static int gr_vt_fd = -1;
50
Doug Zongker16f97c32014-03-06 16:16:05 -080051static GRSurface gr_framebuffer[2];
52static bool double_buffered;
53static GRSurface* gr_draw = NULL;
54static int displayed_buffer;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080055
Doug Zongker16f97c32014-03-06 16:16:05 -080056static unsigned char gr_current_r = 255;
57static unsigned char gr_current_g = 255;
58static unsigned char gr_current_b = 255;
59static unsigned char gr_current_a = 255;
60
61static struct fb_var_screeninfo vi;
62
63static bool outside(int x, int y)
64{
65 return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
66}
67
68static void set_displayed_framebuffer(unsigned n)
69{
70 if (n > 1 || !double_buffered) return;
71
72 vi.yres_virtual = gr_framebuffer[0].height * 2;
73 vi.yoffset = n * gr_framebuffer[0].height;
74 vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
75 if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
76 perror("active fb swap failed");
77 }
78 displayed_buffer = n;
79}
80
81static int get_framebuffer()
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080082{
83 int fd;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080084 void *bits;
85
Doug Zongker16f97c32014-03-06 16:16:05 -080086 struct fb_fix_screeninfo fi;
87
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -080088 fd = open("/dev/graphics/fb0", O_RDWR);
89 if (fd < 0) {
90 perror("cannot open fb0");
91 return -1;
92 }
93
Doug Zongker16f97c32014-03-06 16:16:05 -080094 if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
95 perror("failed to get fb0 info");
96 close(fd);
97 return -1;
98 }
99
Michael Ward3dbe66b2011-06-23 19:28:53 -0700100 if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800101 perror("failed to get fb0 info");
102 close(fd);
103 return -1;
104 }
105
Doug Zongker16f97c32014-03-06 16:16:05 -0800106 // We print this out for informational purposes only, but
107 // throughout we assume that the framebuffer device uses an RGBX
108 // pixel format. This is the case for every development device I
109 // have access to. For some of those devices (eg, hammerhead aka
110 // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
111 // different format (XBGR) but actually produces the correct
112 // results on the display when you write RGBX.
113 //
114 // If you have a device that actually *needs* another pixel format
115 // (ie, BGRX, or 565), patches welcome...
Michael Ward3dbe66b2011-06-23 19:28:53 -0700116
Doug Zongker16f97c32014-03-06 16:16:05 -0800117 printf("fb0 reports (possibly inaccurate):\n"
118 " vi.bits_per_pixel = %d\n"
119 " vi.red.offset = %3d .length = %3d\n"
120 " vi.green.offset = %3d .length = %3d\n"
121 " vi.blue.offset = %3d .length = %3d\n",
122 vi.bits_per_pixel,
123 vi.red.offset, vi.red.length,
124 vi.green.offset, vi.green.length,
125 vi.blue.offset, vi.blue.length);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800126
127 bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
128 if (bits == MAP_FAILED) {
129 perror("failed to mmap framebuffer");
130 close(fd);
131 return -1;
132 }
133
Doug Zongkerc560a672012-12-18 16:31:27 -0800134 overscan_offset_x = vi.xres * overscan_percent / 100;
135 overscan_offset_y = vi.yres * overscan_percent / 100;
136
Doug Zongker16f97c32014-03-06 16:16:05 -0800137 gr_framebuffer[0].width = vi.xres;
138 gr_framebuffer[0].height = vi.yres;
139 gr_framebuffer[0].row_bytes = fi.line_length;
140 gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
141 gr_framebuffer[0].data = bits;
142 memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800143
Octavian Purdila0e348802011-07-01 17:57:45 +0300144 /* check if we can use double buffering */
Doug Zongker16f97c32014-03-06 16:16:05 -0800145 if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
146 double_buffered = true;
Octavian Purdila0e348802011-07-01 17:57:45 +0300147
Doug Zongker16f97c32014-03-06 16:16:05 -0800148 memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface));
149 gr_framebuffer[1].data = gr_framebuffer[0].data +
150 gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
Octavian Purdila0e348802011-07-01 17:57:45 +0300151
Doug Zongker16f97c32014-03-06 16:16:05 -0800152 gr_draw = gr_framebuffer+1;
153
154 } else {
155 double_buffered = false;
156
157 // Without double-buffering, we allocate RAM for a buffer to
158 // draw in, and then "flipping" the buffer consists of a
159 // memcpy from the buffer we allocated to the framebuffer.
160
161 gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
162 memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
163 gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
164 if (!gr_draw->data) {
165 perror("failed to allocate in-memory surface");
166 return -1;
167 }
168 }
169
170 memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
171 gr_fb_fd = fd;
172 set_displayed_framebuffer(0);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800173
174 return fd;
175}
176
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800177void gr_flip(void)
178{
Doug Zongker16f97c32014-03-06 16:16:05 -0800179 if (double_buffered) {
180 // Change gr_draw to point to the buffer currently displayed,
181 // then flip the driver so we're displaying the other buffer
182 // instead.
183 gr_draw = gr_framebuffer + displayed_buffer;
184 set_displayed_framebuffer(1-displayed_buffer);
185 } else {
186 // Copy from the in-memory surface to the framebuffer.
187 memcpy(gr_framebuffer[0].data, gr_draw->data,
188 gr_draw->height * gr_draw->row_bytes);
189 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800190}
191
192int gr_measure(const char *s)
193{
194 return gr_font->cwidth * strlen(s);
195}
196
Dima Zavin3c7f00e2011-08-30 11:58:24 -0700197void gr_font_size(int *x, int *y)
198{
199 *x = gr_font->cwidth;
200 *y = gr_font->cheight;
201}
202
Doug Zongker16f97c32014-03-06 16:16:05 -0800203static void text_blend(unsigned char* src_p, int src_row_bytes,
204 unsigned char* dst_p, int dst_row_bytes,
205 int width, int height)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800206{
Doug Zongker16f97c32014-03-06 16:16:05 -0800207 int i, j;
208 for (j = 0; j < height; ++j) {
209 unsigned char* sx = src_p;
210 unsigned char* px = dst_p;
211 for (i = 0; i < width; ++i) {
212 unsigned char a = *sx++;
213 if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255;
214 if (a == 255) {
215 *px++ = gr_current_r;
216 *px++ = gr_current_g;
217 *px++ = gr_current_b;
218 px++;
219 } else if (a > 0) {
220 *px = (*px * (255-a) + gr_current_r * a) / 255;
221 ++px;
222 *px = (*px * (255-a) + gr_current_g * a) / 255;
223 ++px;
224 *px = (*px * (255-a) + gr_current_b * a) / 255;
225 ++px;
226 ++px;
227 } else {
228 px += 4;
229 }
230 }
231 src_p += src_row_bytes;
232 dst_p += dst_row_bytes;
233 }
234}
235
236
237void gr_text(int x, int y, const char *s, int bold)
238{
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800239 GRFont *font = gr_font;
240 unsigned off;
241
Doug Zongker16f97c32014-03-06 16:16:05 -0800242 if (!font->texture) return;
243 if (gr_current_a == 0) return;
Doug Zongker55a36ac2013-03-04 15:49:02 -0800244
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800245 bold = bold && (font->texture->height != font->cheight);
246
Doug Zongkerc560a672012-12-18 16:31:27 -0800247 x += overscan_offset_x;
248 y += overscan_offset_y;
249
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800250 while((off = *s++)) {
251 off -= 32;
Doug Zongker16f97c32014-03-06 16:16:05 -0800252 if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800253 if (off < 96) {
Doug Zongker16f97c32014-03-06 16:16:05 -0800254
255 unsigned char* src_p = font->texture->data + (off * font->cwidth) +
256 (bold ? font->cheight * font->texture->row_bytes : 0);
257 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
258
259 text_blend(src_p, font->texture->row_bytes,
260 dst_p, gr_draw->row_bytes,
261 font->cwidth, font->cheight);
262
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800263 }
264 x += font->cwidth;
265 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800266}
267
Doug Zongker16f97c32014-03-06 16:16:05 -0800268void gr_texticon(int x, int y, GRSurface* icon) {
269 if (icon == NULL) return;
270
271 if (icon->pixel_bytes != 1) {
272 printf("gr_texticon: source has wrong format\n");
Doug Zongker52eeea4f2012-09-04 14:28:25 -0700273 return;
274 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700275
Doug Zongkerc560a672012-12-18 16:31:27 -0800276 x += overscan_offset_x;
277 y += overscan_offset_y;
278
Doug Zongker16f97c32014-03-06 16:16:05 -0800279 if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700280
Doug Zongker16f97c32014-03-06 16:16:05 -0800281 unsigned char* src_p = icon->data;
282 unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
Doug Zongker02ec6b82012-08-22 17:26:40 -0700283
Doug Zongker16f97c32014-03-06 16:16:05 -0800284 text_blend(src_p, icon->row_bytes,
285 dst_p, gr_draw->row_bytes,
286 icon->width, icon->height);
287}
288
289void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
290{
291 gr_current_r = r;
292 gr_current_g = g;
293 gr_current_b = b;
294 gr_current_a = a;
295}
296
297void gr_clear()
298{
299 if (gr_current_r == gr_current_g &&
300 gr_current_r == gr_current_b) {
301 memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
302 } else {
303 int x, y;
304 unsigned char* px = gr_draw->data;
305 for (y = 0; y < gr_draw->height; ++y) {
306 for (x = 0; x < gr_draw->width; ++x) {
307 *px++ = gr_current_r;
308 *px++ = gr_current_g;
309 *px++ = gr_current_b;
310 px++;
311 }
312 px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
313 }
314 }
Doug Zongker02ec6b82012-08-22 17:26:40 -0700315}
316
Doug Zongkerc560a672012-12-18 16:31:27 -0800317void gr_fill(int x1, int y1, int x2, int y2)
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800318{
Doug Zongkerc560a672012-12-18 16:31:27 -0800319 x1 += overscan_offset_x;
320 y1 += overscan_offset_y;
321
322 x2 += overscan_offset_x;
323 y2 += overscan_offset_y;
324
Doug Zongker16f97c32014-03-06 16:16:05 -0800325 if (outside(x1, y1) || outside(x2-1, y2-1)) return;
326
327 unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
328 if (gr_current_a == 255) {
329 int x, y;
330 for (y = y1; y < y2; ++y) {
331 unsigned char* px = p;
332 for (x = x1; x < x2; ++x) {
333 *px++ = gr_current_r;
334 *px++ = gr_current_g;
335 *px++ = gr_current_b;
336 px++;
337 }
338 p += gr_draw->row_bytes;
339 }
340 } else if (gr_current_a > 0) {
341 int x, y;
342 for (y = y1; y < y2; ++y) {
343 unsigned char* px = p;
344 for (x = x1; x < x2; ++x) {
345 *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
346 ++px;
347 *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
348 ++px;
349 *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
350 ++px;
351 ++px;
352 }
353 p += gr_draw->row_bytes;
354 }
355 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800356}
357
Doug Zongker16f97c32014-03-06 16:16:05 -0800358void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
359 if (source == NULL) return;
360
361 if (gr_draw->pixel_bytes != source->pixel_bytes) {
362 printf("gr_blit: source has wrong format\n");
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800363 return;
364 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800365
Doug Zongkerc560a672012-12-18 16:31:27 -0800366 dx += overscan_offset_x;
367 dy += overscan_offset_y;
368
Doug Zongker16f97c32014-03-06 16:16:05 -0800369 if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
370
371 unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
372 unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
373
374 int i;
375 for (i = 0; i < h; ++i) {
376 memcpy(dst_p, src_p, w * source->pixel_bytes);
377 src_p += source->row_bytes;
378 dst_p += gr_draw->row_bytes;
379 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800380}
381
Doug Zongker16f97c32014-03-06 16:16:05 -0800382unsigned int gr_get_width(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800383 if (surface == NULL) {
384 return 0;
385 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800386 return surface->width;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800387}
388
Doug Zongker16f97c32014-03-06 16:16:05 -0800389unsigned int gr_get_height(GRSurface* surface) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800390 if (surface == NULL) {
391 return 0;
392 }
Doug Zongker16f97c32014-03-06 16:16:05 -0800393 return surface->height;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800394}
395
396static void gr_init_font(void)
397{
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800398 gr_font = calloc(sizeof(*gr_font), 1);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800399
Doug Zongker16f97c32014-03-06 16:16:05 -0800400 int res = res_create_surface("font", &(gr_font->texture));
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800401 if (res == 0) {
402 // The font image should be a 96x2 array of character images. The
403 // columns are the printable ASCII characters 0x20 - 0x7f. The
404 // top row is regular text; the bottom row is bold.
405 gr_font->cwidth = gr_font->texture->width / 96;
406 gr_font->cheight = gr_font->texture->height / 2;
407 } else {
Doug Zongker55a36ac2013-03-04 15:49:02 -0800408 printf("failed to read font: res=%d\n", res);
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800409
410 // fall back to the compiled-in font.
411 gr_font->texture = malloc(sizeof(*gr_font->texture));
412 gr_font->texture->width = font.width;
413 gr_font->texture->height = font.height;
Doug Zongker16f97c32014-03-06 16:16:05 -0800414 gr_font->texture->row_bytes = font.width;
415 gr_font->texture->pixel_bytes = 1;
Doug Zongker6fd59ac2013-03-06 15:01:11 -0800416
417 unsigned char* bits = malloc(font.width * font.height);
418 gr_font->texture->data = (void*) bits;
419
420 unsigned char data;
421 unsigned char* in = font.rundata;
422 while((data = *in++)) {
423 memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
424 bits += (data & 0x7f);
425 }
426
427 gr_font->cwidth = font.cwidth;
428 gr_font->cheight = font.cheight;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800429 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800430}
431
Doug Zongker16f97c32014-03-06 16:16:05 -0800432#if 0
433// Exercises many of the gr_*() functions; useful for testing.
434static void gr_test() {
435 GRSurface** images;
436 int frames;
437 int result = res_create_multi_surface("icon_installing", &frames, &images);
438 if (result < 0) {
439 printf("create surface %d\n", result);
440 gr_exit();
441 return;
442 }
443
444 time_t start = time(NULL);
445 int x;
446 for (x = 0; x <= 1200; ++x) {
447 if (x < 400) {
448 gr_color(0, 0, 0, 255);
449 } else {
450 gr_color(0, (x-400)%128, 0, 255);
451 }
452 gr_clear();
453
454 gr_color(255, 0, 0, 255);
455 gr_surface frame = images[x%frames];
456 gr_blit(frame, 0, 0, frame->width, frame->height, x, 0);
457
458 gr_color(255, 0, 0, 128);
459 gr_fill(400, 150, 600, 350);
460
461 gr_color(255, 255, 255, 255);
462 gr_text(500, 225, "hello, world!", 0);
463 gr_color(255, 255, 0, 128);
464 gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1);
465
466 gr_color(0, 0, 255, 128);
467 gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500);
468
469 gr_flip();
470 }
471 printf("getting end time\n");
472 time_t end = time(NULL);
473 printf("got end time\n");
474 printf("start %ld end %ld\n", (long)start, (long)end);
475 if (end > start) {
476 printf("%.2f fps\n", ((double)x) / (end-start));
477 }
478}
479#endif
480
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800481int gr_init(void)
482{
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800483 gr_init_font();
Doug Zongker16f97c32014-03-06 16:16:05 -0800484
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800485 gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC);
486 if (gr_vt_fd < 0) {
487 // This is non-fatal; post-Cupcake kernels don't have tty0.
488 perror("can't open /dev/tty0");
489 } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) {
490 // However, if we do open tty0, we expect the ioctl to work.
491 perror("failed KDSETMODE to KD_GRAPHICS on tty0");
492 gr_exit();
493 return -1;
494 }
495
Doug Zongker16f97c32014-03-06 16:16:05 -0800496 if (get_framebuffer(&gr_framebuffer) < 0) {
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800497 gr_exit();
498 return -1;
499 }
500
Doug Zongkerfafc85b2013-07-09 12:29:45 -0700501 printf("framebuffer: fd %d (%d x %d)\n",
Doug Zongker16f97c32014-03-06 16:16:05 -0800502 gr_fb_fd, gr_draw->width, gr_draw->height);
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800503
Doug Zongker16f97c32014-03-06 16:16:05 -0800504 gr_flip();
505 gr_flip();
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800506
Doug Zongkerf6abd402011-09-27 13:09:48 -0700507 gr_fb_blank(true);
508 gr_fb_blank(false);
509
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800510 return 0;
511}
512
513void gr_exit(void)
514{
515 close(gr_fb_fd);
516 gr_fb_fd = -1;
517
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800518 ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT);
519 close(gr_vt_fd);
520 gr_vt_fd = -1;
Doug Zongker16f97c32014-03-06 16:16:05 -0800521
522 if (!double_buffered) {
523 if (gr_draw) free(gr_draw->data);
524 free(gr_draw);
525 }
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800526}
527
528int gr_fb_width(void)
529{
Doug Zongker16f97c32014-03-06 16:16:05 -0800530 return gr_draw->width - 2*overscan_offset_x;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800531}
532
533int gr_fb_height(void)
534{
Doug Zongker16f97c32014-03-06 16:16:05 -0800535 return gr_draw->height - 2*overscan_offset_y;
The Android Open Source Projectc24a8e62009-03-03 19:28:42 -0800536}
Dima Zavin4daf48a2011-08-30 11:59:20 -0700537
538void gr_fb_blank(bool blank)
539{
540 int ret;
541
542 ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
543 if (ret < 0)
544 perror("ioctl(): blank");
545}