summaryrefslogtreecommitdiffstats
path: root/minui/graphics.c
diff options
context:
space:
mode:
Diffstat (limited to 'minui/graphics.c')
-rw-r--r--minui/graphics.c219
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);
}