diff options
Diffstat (limited to '')
-rw-r--r-- | minui/graphics.c | 219 |
1 files changed, 218 insertions, 1 deletions
diff --git a/minui/graphics.c b/minui/graphics.c index 6049d85ca..470e735c9 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -18,6 +18,7 @@ #include <stdlib.h> #include <unistd.h> +#include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -56,6 +57,170 @@ static unsigned char gr_current_a = 255; static GRSurface* gr_draw = NULL; +static struct fb_var_screeninfo vi; +static struct fb_fix_screeninfo fi; + +static bool has_overlay = false; + +bool target_has_overlay(char *version); +int free_ion_mem(void); +int alloc_ion_mem(unsigned int size); +int allocate_overlay(int fd, GGLSurface gr_fb[]); +int free_overlay(int fd); +int overlay_display_frame(int fd, GGLubyte* data, size_t size); + +static int get_framebuffer(GGLSurface *fb) +{ + int fd; + void *bits; + + fd = open("/dev/graphics/fb0", O_RDWR); + if (fd < 0) { + perror("cannot open fb0"); + return -1; + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return -1; + } + + vi.bits_per_pixel = PIXEL_SIZE * 8; + if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_BGRA_8888) { + vi.red.offset = 8; + vi.red.length = 8; + vi.green.offset = 16; + vi.green.length = 8; + vi.blue.offset = 24; + vi.blue.length = 8; + vi.transp.offset = 0; + vi.transp.length = 8; + } else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBX_8888) { + vi.red.offset = 24; + vi.red.length = 8; + vi.green.offset = 16; + vi.green.length = 8; + vi.blue.offset = 8; + vi.blue.length = 8; + vi.transp.offset = 0; + vi.transp.length = 8; + } else { /* RGB565*/ + vi.red.offset = 11; + vi.red.length = 5; + vi.green.offset = 5; + vi.green.length = 6; + vi.blue.offset = 0; + vi.blue.length = 5; + vi.transp.offset = 0; + vi.transp.length = 0; + } + if (ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) { + perror("failed to put fb0 info"); + close(fd); + return -1; + } + + if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return -1; + } + + has_overlay = target_has_overlay(fi.id); + + if (!has_overlay) { + bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (bits == MAP_FAILED) { + perror("failed to mmap framebuffer"); + close(fd); + return -1; + } + } + + overscan_offset_x = vi.xres * overscan_percent / 100; + overscan_offset_y = vi.yres * overscan_percent / 100; + + fb->version = sizeof(*fb); + fb->width = vi.xres; + fb->height = vi.yres; + fb->stride = fi.line_length/PIXEL_SIZE; + fb->format = PIXEL_FORMAT; + if (!has_overlay) { + fb->data = bits; + memset(fb->data, 0, vi.yres * fi.line_length); + } + + fb++; + + /* check if we can use double buffering */ + if (vi.yres * fi.line_length * 2 > fi.smem_len) + return fd; + + fb->version = sizeof(*fb); + fb->width = vi.xres; + fb->height = vi.yres; + fb->stride = fi.line_length/PIXEL_SIZE; + fb->format = PIXEL_FORMAT; + if (!has_overlay) { + fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length); + memset(fb->data, 0, vi.yres * fi.line_length); + } + + return fd; +} + +static void get_memory_surface(GGLSurface* ms) { + ms->version = sizeof(*ms); + ms->width = vi.xres; + ms->height = vi.yres; + ms->stride = fi.line_length/PIXEL_SIZE; + ms->data = malloc(fi.line_length * vi.yres); + ms->format = PIXEL_FORMAT; +} + +static void set_active_framebuffer(unsigned n) +{ + if (n > 1 || !double_buffering) return; + vi.yres_virtual = vi.yres * NUM_BUFFERS; + vi.yoffset = n * vi.yres; + vi.bits_per_pixel = PIXEL_SIZE * 8; + if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { + perror("active fb swap failed"); + } +} + +void gr_flip(void) +{ + if (-EINVAL == overlay_display_frame(gr_fb_fd, gr_mem_surface.data, + (fi.line_length * vi.yres))) { + GGLContext *gl = gr_context; + + /* swap front and back buffers */ + if (double_buffering) + gr_active_fb = (gr_active_fb + 1) & 1; + + /* copy data from the in-memory surface to the buffer we're about + * to make active. */ + memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data, + fi.line_length * vi.yres); + + /* inform the display driver */ + set_active_framebuffer(gr_active_fb); + } +} + +void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + GGLContext *gl = gr_context; + GGLint color[4]; + color[0] = ((r << 8) | r) + 1; + color[1] = ((g << 8) | g) + 1; + color[2] = ((b << 8) | b) + 1; + color[3] = ((a << 8) | a) + 1; + gl->color4xv(gl, color); +} + static bool outside(int x, int y) { return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; @@ -72,6 +237,11 @@ void gr_font_size(int *x, int *y) *y = gr_font->cheight; } +int gr_text(int x, int y, const char *s, ...) +{ + return gr_text_impl(x, y, s, 0); +} + static void text_blend(unsigned char* src_p, int src_row_bytes, unsigned char* dst_p, int dst_row_bytes, int width, int height) @@ -106,7 +276,7 @@ static void text_blend(unsigned char* src_p, int src_row_bytes, } -void gr_text(int x, int y, const char *s, int bold) +int gr_text_impl(int x, int y, const char *s, int bold) { GRFont *font = gr_font; unsigned off; @@ -377,6 +547,17 @@ int gr_init(void) } } + get_memory_surface(&gr_mem_surface); + + fprintf(stderr, "framebuffer: fd %d (%d x %d)\n", + gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); + + /* start with 0 as front (displayed) and 1 as back (drawing) */ + gr_active_fb = 0; + if (!has_overlay) + set_active_framebuffer(0); + gl->colorBuffer(gl, &gr_mem_surface); + if (!gr_draw) { gr_backend = open_fbdev(); gr_draw = gr_backend->init(gr_backend); @@ -391,11 +572,22 @@ int gr_init(void) gr_flip(); gr_flip(); + if (!alloc_ion_mem(fi.line_length * vi.yres)) + allocate_overlay(gr_fb_fd, gr_framebuffer); + return 0; } void gr_exit(void) { + free_overlay(gr_fb_fd); + free_ion_mem(); + + close(gr_fb_fd); + gr_fb_fd = -1; + + free(gr_mem_surface.data); + gr_backend->exit(gr_backend); ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); @@ -415,5 +607,30 @@ int gr_fb_height(void) void gr_fb_blank(bool blank) { +#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS) + int fd; + char brightness[4]; + snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2); + + fd = open(TW_BRIGHTNESS_PATH, O_RDWR); + if (fd < 0) { + perror("cannot open LCD backlight"); + return; + } + write(fd, blank ? "000" : brightness, 3); + close(fd); +#else gr_backend->blank(gr_backend, blank); + + if (blank) + free_overlay(gr_fb_fd); + + if (!blank) + allocate_overlay(gr_fb_fd, gr_framebuffer); +#endif +} + +void gr_get_memory_surface(gr_surface surface) +{ + get_memory_surface( (GGLSurface*) surface); } |