From cd3c55ab40efd12f5a2d396dbb57509e4d071641 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 29 Jan 2015 20:50:08 -0800 Subject: Add missing includes. Change-Id: I06ea08400efa511e627be37a4fd70fbdfadea2e6 --- minui/events.c | 2 ++ minui/graphics.c | 1 + minui/graphics_adf.c | 1 + minui/graphics_fbdev.c | 1 + minui/resources.c | 1 + 5 files changed, 6 insertions(+) (limited to 'minui') diff --git a/minui/events.c b/minui/events.c index df7dad448..d98a774ef 100644 --- a/minui/events.c +++ b/minui/events.c @@ -16,6 +16,8 @@ #include #include +#include +#include #include #include #include diff --git a/minui/graphics.c b/minui/graphics.c index 6049d85ca..ec39433b8 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/minui/graphics_adf.c b/minui/graphics_adf.c index ac6d64e9e..289c3be63 100644 --- a/minui/graphics_adf.c +++ b/minui/graphics_adf.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff --git a/minui/graphics_fbdev.c b/minui/graphics_fbdev.c index c0c1bcb1a..a087899bd 100644 --- a/minui/graphics_fbdev.c +++ b/minui/graphics_fbdev.c @@ -16,6 +16,7 @@ #include #include +#include #include #include diff --git a/minui/resources.c b/minui/resources.c index 2bae4ded0..f645c4b67 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -15,6 +15,7 @@ */ #include +#include #include #include -- cgit v1.2.3 From 9905f3a4ee90e4f569bb187e6fa15616cc54bbb7 Mon Sep 17 00:00:00 2001 From: Ajay Dudani Date: Wed, 4 Feb 2015 16:49:44 -0800 Subject: recovery: Generate libminui dynamic library Allow factory test images to use minui functionaltiy by making use of libminui dynamic library. Change-Id: I63e77420d5addbcc6eebeedc213f629085766b4c --- minui/Android.mk | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index df4aac169..aee2a34ab 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -30,3 +30,10 @@ else endif include $(BUILD_STATIC_LIBRARY) + +# Used by OEMs for factory test images. +include $(CLEAR_VARS) +LOCAL_MODULE := libminui +LOCAL_WHOLE_STATIC_LIBRARIES += libminui +LOCAL_SHARED_LIBRARIES := libpng +include $(BUILD_SHARED_LIBRARY) -- cgit v1.2.3 From 07d9627d7cf31e03b778bc4b1c918d552680cd28 Mon Sep 17 00:00:00 2001 From: Ajay Dudani Date: Wed, 4 Feb 2015 16:51:34 -0800 Subject: recovery: Handle EV_SW events Change-Id: I29c13a941067cd1bbdced3bd67fd93293347d7b6 --- minui/events.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'minui') diff --git a/minui/events.c b/minui/events.c index d98a774ef..9e4255dd7 100644 --- a/minui/events.c +++ b/minui/events.c @@ -80,8 +80,8 @@ int ev_init(ev_callback input_cb, void *data) } /* TODO: add ability to specify event masks. For now, just assume - * that only EV_KEY and EV_REL event types are ever needed. */ - if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) { + * that only EV_KEY, EV_REL & EV_SW event types are ever needed. */ + if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) { close(fd); continue; } -- cgit v1.2.3 From fd778e3e406a7e83536ea66776996f032f24af64 Mon Sep 17 00:00:00 2001 From: Tony Kuo Date: Thu, 5 Feb 2015 21:25:56 +0800 Subject: Fix Droid and animation color in recovery mode [Problem] Droid and animation color in recovery mode are incorrect [Modify] - Add support for flipping (zero copy) with RECOVERY_ABGR. - Decodes PNG files to BGRA directly, and other fills, text and alpha blending are also done directly in BGRA (i.e. blits can still bypass conversion) - Remove the BGRA workaround added previous for single buffer mode (f766396) Bug:19216535 Change-Id: Ie864419fc6da776ff58b2d02e130f203c194500f Signed-off-by: Tony Kuo --- minui/Android.mk | 3 +++ minui/graphics.c | 7 +++++++ minui/graphics_adf.c | 4 +++- minui/graphics_fbdev.c | 13 ------------- minui/resources.c | 12 ++++++++++++ 5 files changed, 25 insertions(+), 14 deletions(-) (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index aee2a34ab..ddee165f9 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -16,6 +16,9 @@ LOCAL_MODULE := libminui # ordinary characters in this context). Strip double-quotes from the # value so that either will work. +ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),ABGR_8888) + LOCAL_CFLAGS += -DRECOVERY_ABGR +endif ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888) LOCAL_CFLAGS += -DRECOVERY_RGBX endif diff --git a/minui/graphics.c b/minui/graphics.c index ec39433b8..870ffa089 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -161,10 +161,17 @@ void gr_texticon(int x, int y, GRSurface* icon) { void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + gr_current_r = b; + gr_current_g = g; + gr_current_b = r; + gr_current_a = a; +#else gr_current_r = r; gr_current_g = g; gr_current_b = b; gr_current_a = a; +#endif } void gr_clear() diff --git a/minui/graphics_adf.c b/minui/graphics_adf.c index 289c3be63..c023d4db9 100644 --- a/minui/graphics_adf.c +++ b/minui/graphics_adf.c @@ -142,7 +142,9 @@ static gr_surface adf_init(minui_backend *backend) ssize_t n_dev_ids, i; gr_surface ret; -#if defined(RECOVERY_BGRA) +#if defined(RECOVERY_ABGR) + pdata->format = DRM_FORMAT_ABGR8888; +#elif defined(RECOVERY_BGRA) pdata->format = DRM_FORMAT_BGRA8888; #elif defined(RECOVERY_RGBX) pdata->format = DRM_FORMAT_RGBX8888; diff --git a/minui/graphics_fbdev.c b/minui/graphics_fbdev.c index a087899bd..ecd40c3eb 100644 --- a/minui/graphics_fbdev.c +++ b/minui/graphics_fbdev.c @@ -187,21 +187,8 @@ static gr_surface fbdev_flip(minui_backend* backend __unused) { set_displayed_framebuffer(1-displayed_buffer); } else { // Copy from the in-memory surface to the framebuffer. - -#if defined(RECOVERY_BGRA) - unsigned int idx; - unsigned char* ucfb_vaddr = (unsigned char*)gr_framebuffer[0].data; - unsigned char* ucbuffer_vaddr = (unsigned char*)gr_draw->data; - for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes); idx += 4) { - ucfb_vaddr[idx ] = ucbuffer_vaddr[idx + 2]; - ucfb_vaddr[idx + 1] = ucbuffer_vaddr[idx + 1]; - ucfb_vaddr[idx + 2] = ucbuffer_vaddr[idx ]; - ucfb_vaddr[idx + 3] = ucbuffer_vaddr[idx + 3]; - } -#else memcpy(gr_framebuffer[0].data, gr_draw->data, gr_draw->height * gr_draw->row_bytes); -#endif } return gr_draw; } diff --git a/minui/resources.c b/minui/resources.c index f645c4b67..886c3255d 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -216,6 +216,10 @@ int res_create_display_surface(const char* name, gr_surface* pSurface) { goto exit; } +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + unsigned char* p_row = malloc(width * 4); unsigned int y; for (y = 0; y < height; ++y) { @@ -279,6 +283,10 @@ int res_create_multi_display_surface(const char* name, int* frames, gr_surface** } } +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + unsigned char* p_row = malloc(width * 4); unsigned int y; for (y = 0; y < height; ++y) { @@ -334,6 +342,10 @@ int res_create_alpha_surface(const char* name, gr_surface* pSurface) { surface->row_bytes = width; surface->pixel_bytes = 1; +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + unsigned char* p_row; unsigned int y; for (y = 0; y < height; ++y) { -- cgit v1.2.3 From fee324f1b6a345c4306c71abad9f9640cddd1018 Mon Sep 17 00:00:00 2001 From: Trevor Drake Date: Thu, 26 Feb 2015 15:57:58 +0000 Subject: Drop hardcoded LOCAL_C_INCLUDES from minui/Android.mk The zlib include was not required. libpng is now handled by referencing the libpng static library Change-Id: Ie4e0abad3fff5b763eba363d3d0fa96128ff49bc --- minui/Android.mk | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index ddee165f9..9b2e09b70 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -4,11 +4,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := graphics.c graphics_adf.c graphics_fbdev.c events.c \ resources.c -LOCAL_C_INCLUDES +=\ - external/libpng\ - external/zlib - LOCAL_WHOLE_STATIC_LIBRARIES += libadf +LOCAL_STATIC_LIBRARIES += libpng LOCAL_MODULE := libminui -- cgit v1.2.3 From 01a4d08010d1c26cc2cb37ca62b624829a7e1506 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 24 Mar 2015 15:21:48 -0700 Subject: Fix recovery image text rendering. Previously most devices would lose the character before a line wrap. The log's text rendering was starting at offset 4 but none of the arithmetic was taking this into account. It just happened to work on the Nexus 9's 1536-pixel wide display (1536/18=85.3) but not on a device such as the Nexus 5 (1080/18=60). The only active part of this change is the change from 4 to 0 in the gr_text call. The rest is just a few bits of trivial cleanup while I was working out what was going on. Change-Id: I9279ae323c77bc8b6ea87dc0fe009aaaec6bfa0e --- minui/Android.mk | 5 +++-- minui/graphics.c | 42 +++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 25 deletions(-) (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index 9b2e09b70..53d072fac 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -1,14 +1,15 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := graphics.c graphics_adf.c graphics_fbdev.c events.c \ - resources.c +LOCAL_SRC_FILES := graphics.c graphics_adf.c graphics_fbdev.c events.c resources.c LOCAL_WHOLE_STATIC_LIBRARIES += libadf LOCAL_STATIC_LIBRARIES += libpng LOCAL_MODULE := libminui +LOCAL_CFLAGS := -std=gnu11 + # This used to compare against values in double-quotes (which are just # ordinary characters in this context). Strip double-quotes from the # value so that either will work. diff --git a/minui/graphics.c b/minui/graphics.c index 870ffa089..1a9be6cb2 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -77,11 +77,10 @@ static void text_blend(unsigned char* src_p, int src_row_bytes, unsigned char* dst_p, int dst_row_bytes, int width, int height) { - int i, j; - for (j = 0; j < height; ++j) { + for (int j = 0; j < height; ++j) { unsigned char* sx = src_p; unsigned char* px = dst_p; - for (i = 0; i < width; ++i) { + for (int i = 0; i < width; ++i) { unsigned char a = *sx++; if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255; if (a == 255) { @@ -106,34 +105,33 @@ static void text_blend(unsigned char* src_p, int src_row_bytes, } } - void gr_text(int x, int y, const char *s, int bold) { - GRFont *font = gr_font; - unsigned off; + GRFont* font = gr_font; - if (!font->texture) return; - if (gr_current_a == 0) return; + if (!font->texture || gr_current_a == 0) return; bold = bold && (font->texture->height != font->cheight); x += overscan_offset_x; y += overscan_offset_y; - while((off = *s++)) { - off -= 32; + unsigned char ch; + while ((ch = *s++)) { if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break; - if (off < 96) { - unsigned char* src_p = font->texture->data + (off * font->cwidth) + - (bold ? font->cheight * font->texture->row_bytes : 0); - unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; + if (ch < ' ' || ch > '~') { + ch = '?'; + } - text_blend(src_p, font->texture->row_bytes, - dst_p, gr_draw->row_bytes, - font->cwidth, font->cheight); + unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) + + (bold ? font->cheight * font->texture->row_bytes : 0); + unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; + + text_blend(src_p, font->texture->row_bytes, + dst_p, gr_draw->row_bytes, + font->cwidth, font->cheight); - } x += font->cwidth; } } @@ -176,14 +174,12 @@ void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a void gr_clear() { - if (gr_current_r == gr_current_g && - gr_current_r == gr_current_b) { + if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) { memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes); } else { - int x, y; unsigned char* px = gr_draw->data; - for (y = 0; y < gr_draw->height; ++y) { - for (x = 0; x < gr_draw->width; ++x) { + for (int y = 0; y < gr_draw->height; ++y) { + for (int x = 0; x < gr_draw->width; ++x) { *px++ = gr_current_r; *px++ = gr_current_g; *px++ = gr_current_b; -- cgit v1.2.3 From 59156bdedad7e4f0d5ae042d79a5aee24c685884 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 24 Mar 2015 15:58:15 -0700 Subject: Remove support for Cupcake kernels. Change-Id: I7376b9d3c1e11d19e164072d6e9d09c1183114a0 --- minui/graphics.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'minui') diff --git a/minui/graphics.c b/minui/graphics.c index 1a9be6cb2..9d1e1b480 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -48,8 +48,6 @@ static int overscan_percent = OVERSCAN_PERCENT; static int overscan_offset_x = 0; static int overscan_offset_y = 0; -static int gr_vt_fd = -1; - static unsigned char gr_current_r = 255; static unsigned char gr_current_g = 255; static unsigned char gr_current_b = 255; @@ -362,17 +360,6 @@ int gr_init(void) { gr_init_font(); - gr_vt_fd = open("/dev/tty0", O_RDWR | O_SYNC); - if (gr_vt_fd < 0) { - // This is non-fatal; post-Cupcake kernels don't have tty0. - perror("can't open /dev/tty0"); - } else if (ioctl(gr_vt_fd, KDSETMODE, (void*) KD_GRAPHICS)) { - // However, if we do open tty0, we expect the ioctl to work. - perror("failed KDSETMODE to KD_GRAPHICS on tty0"); - gr_exit(); - return -1; - } - gr_backend = open_adf(); if (gr_backend) { gr_draw = gr_backend->init(gr_backend); @@ -401,10 +388,6 @@ int gr_init(void) void gr_exit(void) { gr_backend->exit(gr_backend); - - ioctl(gr_vt_fd, KDSETMODE, (void*) KD_TEXT); - close(gr_vt_fd); - gr_vt_fd = -1; } int gr_fb_width(void) -- cgit v1.2.3 From 0713819fd256bfdfcf241c71195b7e8c4e18c742 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Apr 2015 09:40:53 -0700 Subject: Add ev_iterate_available_keys to minui. This lets us recognize whether we have up/down/power, say, and tailor the UI accordingly. Change-Id: If94e454f14243b59d2f473ac9a436bd60591da01 --- minui/Android.mk | 9 ++- minui/events.c | 213 -------------------------------------------------- minui/events.cpp | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ minui/minui.h | 35 +++++---- 4 files changed, 260 insertions(+), 228 deletions(-) delete mode 100644 minui/events.c create mode 100644 minui/events.cpp (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index 53d072fac..66dea741a 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -1,14 +1,19 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := graphics.c graphics_adf.c graphics_fbdev.c events.c resources.c +LOCAL_SRC_FILES := \ + events.cpp \ + graphics.c \ + graphics_adf.c \ + graphics_fbdev.c \ + resources.c \ LOCAL_WHOLE_STATIC_LIBRARIES += libadf LOCAL_STATIC_LIBRARIES += libpng LOCAL_MODULE := libminui -LOCAL_CFLAGS := -std=gnu11 +LOCAL_CLANG := true # This used to compare against values in double-quotes (which are just # ordinary characters in this context). Strip double-quotes from the diff --git a/minui/events.c b/minui/events.c deleted file mode 100644 index 9e4255dd7..000000000 --- a/minui/events.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "minui.h" - -#define MAX_DEVICES 16 -#define MAX_MISC_FDS 16 - -#define BITS_PER_LONG (sizeof(unsigned long) * 8) -#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG) - -#define test_bit(bit, array) \ - ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG))) - -struct fd_info { - int fd; - ev_callback cb; - void *data; -}; - -static int epollfd; -static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS]; -static int npolledevents; - -static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS]; - -static unsigned ev_count = 0; -static unsigned ev_dev_count = 0; -static unsigned ev_misc_count = 0; - -int ev_init(ev_callback input_cb, void *data) -{ - DIR *dir; - struct dirent *de; - int fd; - struct epoll_event ev; - bool epollctlfail = false; - - epollfd = epoll_create(MAX_DEVICES + MAX_MISC_FDS); - if (epollfd == -1) - return -1; - - dir = opendir("/dev/input"); - if(dir != 0) { - while((de = readdir(dir))) { - unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; - -// fprintf(stderr,"/dev/input/%s\n", de->d_name); - if(strncmp(de->d_name,"event",5)) continue; - fd = openat(dirfd(dir), de->d_name, O_RDONLY); - if(fd < 0) continue; - - /* read the evbits of the input device */ - if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) { - close(fd); - continue; - } - - /* TODO: add ability to specify event masks. For now, just assume - * that only EV_KEY, EV_REL & EV_SW event types are ever needed. */ - if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) { - close(fd); - continue; - } - - ev.events = EPOLLIN | EPOLLWAKEUP; - ev.data.ptr = (void *)&ev_fdinfo[ev_count]; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) { - close(fd); - epollctlfail = true; - continue; - } - - ev_fdinfo[ev_count].fd = fd; - ev_fdinfo[ev_count].cb = input_cb; - ev_fdinfo[ev_count].data = data; - ev_count++; - ev_dev_count++; - if(ev_dev_count == MAX_DEVICES) break; - } - } - - if (epollctlfail && !ev_count) { - close(epollfd); - epollfd = -1; - return -1; - } - - return 0; -} - -int ev_add_fd(int fd, ev_callback cb, void *data) -{ - struct epoll_event ev; - int ret; - - if (ev_misc_count == MAX_MISC_FDS || cb == NULL) - return -1; - - ev.events = EPOLLIN | EPOLLWAKEUP; - ev.data.ptr = (void *)&ev_fdinfo[ev_count]; - ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); - if (!ret) { - ev_fdinfo[ev_count].fd = fd; - ev_fdinfo[ev_count].cb = cb; - ev_fdinfo[ev_count].data = data; - ev_count++; - ev_misc_count++; - } - - return ret; -} - -int ev_get_epollfd(void) -{ - return epollfd; -} - -void ev_exit(void) -{ - while (ev_count > 0) { - close(ev_fdinfo[--ev_count].fd); - } - ev_misc_count = 0; - ev_dev_count = 0; - close(epollfd); -} - -int ev_wait(int timeout) -{ - npolledevents = epoll_wait(epollfd, polledevents, ev_count, timeout); - if (npolledevents <= 0) - return -1; - return 0; -} - -void ev_dispatch(void) -{ - int n; - int ret; - - for (n = 0; n < npolledevents; n++) { - struct fd_info *fdi = polledevents[n].data.ptr; - ev_callback cb = fdi->cb; - if (cb) - cb(fdi->fd, polledevents[n].events, fdi->data); - } -} - -int ev_get_input(int fd, uint32_t epevents, struct input_event *ev) -{ - int r; - - if (epevents & EPOLLIN) { - r = read(fd, ev, sizeof(*ev)); - if (r == sizeof(*ev)) - return 0; - } - return -1; -} - -int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data) -{ - unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; - unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; - unsigned i; - int ret; - - for (i = 0; i < ev_dev_count; i++) { - int code; - - memset(key_bits, 0, sizeof(key_bits)); - memset(ev_bits, 0, sizeof(ev_bits)); - - ret = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); - if (ret < 0 || !test_bit(EV_KEY, ev_bits)) - continue; - - ret = ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits); - if (ret < 0) - continue; - - for (code = 0; code <= KEY_MAX; code++) { - if (test_bit(code, key_bits)) - set_key_cb(code, 1, data); - } - } - - return 0; -} diff --git a/minui/events.cpp b/minui/events.cpp new file mode 100644 index 000000000..2c41eb8a7 --- /dev/null +++ b/minui/events.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "minui.h" + +#define MAX_DEVICES 16 +#define MAX_MISC_FDS 16 + +#define BITS_PER_LONG (sizeof(unsigned long) * 8) +#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG) + +struct fd_info { + int fd; + ev_callback cb; + void* data; +}; + +static int g_epoll_fd; +static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS]; +static int npolledevents; + +static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS]; + +static unsigned ev_count = 0; +static unsigned ev_dev_count = 0; +static unsigned ev_misc_count = 0; + +static bool test_bit(size_t bit, unsigned long* array) { + return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0; +} + +int ev_init(ev_callback input_cb, void* data) { + bool epollctlfail = false; + + g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS); + if (g_epoll_fd == -1) { + return -1; + } + + DIR* dir = opendir("/dev/input"); + if (dir != NULL) { + struct dirent* de; + while ((de = readdir(dir))) { + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; + +// fprintf(stderr,"/dev/input/%s\n", de->d_name); + if (strncmp(de->d_name, "event", 5)) continue; + int fd = openat(dirfd(dir), de->d_name, O_RDONLY); + if (fd == -1) continue; + + // Read the evbits of the input device. + if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + close(fd); + continue; + } + + // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. + if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) { + close(fd); + continue; + } + + struct epoll_event ev; + ev.events = EPOLLIN | EPOLLWAKEUP; + ev.data.ptr = &ev_fdinfo[ev_count]; + if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { + close(fd); + epollctlfail = true; + continue; + } + + ev_fdinfo[ev_count].fd = fd; + ev_fdinfo[ev_count].cb = input_cb; + ev_fdinfo[ev_count].data = data; + ev_count++; + ev_dev_count++; + if (ev_dev_count == MAX_DEVICES) break; + } + + closedir(dir); + } + + if (epollctlfail && !ev_count) { + close(g_epoll_fd); + g_epoll_fd = -1; + return -1; + } + + return 0; +} + +int ev_get_epollfd(void) { + return g_epoll_fd; +} + +int ev_add_fd(int fd, ev_callback cb, void* data) { + if (ev_misc_count == MAX_MISC_FDS || cb == NULL) { + return -1; + } + + struct epoll_event ev; + ev.events = EPOLLIN | EPOLLWAKEUP; + ev.data.ptr = (void *)&ev_fdinfo[ev_count]; + int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev); + if (!ret) { + ev_fdinfo[ev_count].fd = fd; + ev_fdinfo[ev_count].cb = cb; + ev_fdinfo[ev_count].data = data; + ev_count++; + ev_misc_count++; + } + + return ret; +} + +void ev_exit(void) { + while (ev_count > 0) { + close(ev_fdinfo[--ev_count].fd); + } + ev_misc_count = 0; + ev_dev_count = 0; + close(g_epoll_fd); +} + +int ev_wait(int timeout) { + npolledevents = epoll_wait(g_epoll_fd, polledevents, ev_count, timeout); + if (npolledevents <= 0) { + return -1; + } + return 0; +} + +void ev_dispatch(void) { + for (int n = 0; n < npolledevents; n++) { + fd_info* fdi = reinterpret_cast(polledevents[n].data.ptr); + ev_callback cb = fdi->cb; + if (cb) { + cb(fdi->fd, polledevents[n].events, fdi->data); + } + } +} + +int ev_get_input(int fd, uint32_t epevents, struct input_event* ev) { + if (epevents & EPOLLIN) { + ssize_t r = read(fd, ev, sizeof(*ev)); + if (r == sizeof(*ev)) { + return 0; + } + } + return -1; +} + +int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) { + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; + unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; + + for (size_t i = 0; i < ev_dev_count; ++i) { + memset(ev_bits, 0, sizeof(ev_bits)); + memset(key_bits, 0, sizeof(key_bits)); + + if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + continue; + } + if (!test_bit(EV_KEY, ev_bits)) { + continue; + } + if (ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits) == -1) { + continue; + } + + for (int code = 0; code <= KEY_MAX; code++) { + if (test_bit(code, key_bits)) { + set_key_cb(code, 1, data); + } + } + } + + return 0; +} + +void ev_iterate_available_keys(ev_key_callback cb, void* data) { + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; + unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; + + for (size_t i = 0; i < ev_dev_count; ++i) { + memset(ev_bits, 0, sizeof(ev_bits)); + memset(key_bits, 0, sizeof(key_bits)); + + // Does this device even have keys? + if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + continue; + } + if (!test_bit(EV_KEY, ev_bits)) { + continue; + } + + int rc = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits); + if (rc == -1) { + continue; + } + + for (int key_code = 0; key_code <= KEY_MAX; ++key_code) { + if (test_bit(key_code, key_bits)) { + cb(key_code, data); + } + } + } +} diff --git a/minui/minui.h b/minui/minui.h index 733b675f3..8f2ff1139 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -25,6 +25,10 @@ extern "C" { #endif +// +// Graphics. +// + typedef struct { int width; int height; @@ -56,30 +60,35 @@ void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy); unsigned int gr_get_width(gr_surface surface); unsigned int gr_get_height(gr_surface surface); -// input event structure, include for the definition. -// see http://www.mjmwired.net/kernel/Documentation/input/ for info. +// +// Input events. +// + struct input_event; -typedef int (*ev_callback)(int fd, uint32_t epevents, void *data); -typedef int (*ev_set_key_callback)(int code, int value, void *data); +typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); +typedef int (*ev_set_key_callback)(int code, int value, void* data); +typedef void (*ev_key_callback)(int code, void* data); -int ev_init(ev_callback input_cb, void *data); +int ev_init(ev_callback input_cb, void* data); void ev_exit(void); -int ev_add_fd(int fd, ev_callback cb, void *data); -int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data); - -/* timeout has the same semantics as for poll - * 0 : don't block - * < 0 : block forever - * > 0 : block for 'timeout' milliseconds - */ +int ev_add_fd(int fd, ev_callback cb, void* data); +int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); +void ev_iterate_available_keys(ev_key_callback cb, void* data); + +// 'timeout' has the same semantics as poll(2). +// 0 : don't block +// < 0 : block forever +// > 0 : block for 'timeout' milliseconds int ev_wait(int timeout); int ev_get_input(int fd, uint32_t epevents, struct input_event *ev); void ev_dispatch(void); int ev_get_epollfd(void); +// // Resources +// // res_create_*_surface() functions return 0 if no error, else // negative. -- cgit v1.2.3 From 642aaa7a3e11b2de719fc9decc45174bcc235c0c Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Apr 2015 12:47:46 -0700 Subject: Fix ScreenRecoveryUI to handle devices without power/up/down. Currently fugu has a custom subclass to handle this. The default code supports devices with trackballs but not all shipping Nexus devices? That's just silly. Change-Id: Id2779c91284899a26b4bb1af41e7033aa889df10 --- minui/events.cpp | 4 ++-- minui/minui.h | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'minui') diff --git a/minui/events.cpp b/minui/events.cpp index 2c41eb8a7..daa10c6cf 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -201,7 +201,7 @@ int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) { return 0; } -void ev_iterate_available_keys(ev_key_callback cb, void* data) { +void ev_iterate_available_keys(std::function f) { unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; @@ -224,7 +224,7 @@ void ev_iterate_available_keys(ev_key_callback cb, void* data) { for (int key_code = 0; key_code <= KEY_MAX; ++key_code) { if (test_bit(key_code, key_bits)) { - cb(key_code, data); + f(key_code); } } } diff --git a/minui/minui.h b/minui/minui.h index 8f2ff1139..82abb8a63 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -68,13 +68,11 @@ struct input_event; typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); typedef int (*ev_set_key_callback)(int code, int value, void* data); -typedef void (*ev_key_callback)(int code, void* data); int ev_init(ev_callback input_cb, void* data); void ev_exit(void); int ev_add_fd(int fd, ev_callback cb, void* data); int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); -void ev_iterate_available_keys(ev_key_callback cb, void* data); // 'timeout' has the same semantics as poll(2). // 0 : don't block @@ -130,4 +128,11 @@ void res_free_surface(gr_surface surface); } #endif +#ifdef __cplusplus + +#include +void ev_iterate_available_keys(std::function f); + +#endif + #endif -- cgit v1.2.3 From 07cfb8fe799901948afd6af05ef4674173713bcb Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 10 Apr 2015 13:12:05 -0700 Subject: Switch minui over to C++. Change-Id: I59e08a304ae514a3fdb6fab58721f11670bc1b01 --- minui/Android.mk | 8 +- minui/events.cpp | 12 +- minui/graphics.c | 406 ----------------------------------------- minui/graphics.cpp | 406 +++++++++++++++++++++++++++++++++++++++++ minui/graphics.h | 22 +-- minui/graphics_adf.c | 250 ------------------------- minui/graphics_adf.cpp | 249 +++++++++++++++++++++++++ minui/graphics_fbdev.c | 217 ---------------------- minui/graphics_fbdev.cpp | 213 ++++++++++++++++++++++ minui/minui.h | 42 ++--- minui/resources.c | 456 ---------------------------------------------- minui/resources.cpp | 461 +++++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1361 insertions(+), 1381 deletions(-) delete mode 100644 minui/graphics.c create mode 100644 minui/graphics.cpp delete mode 100644 minui/graphics_adf.c create mode 100644 minui/graphics_adf.cpp delete mode 100644 minui/graphics_fbdev.c create mode 100644 minui/graphics_fbdev.cpp delete mode 100644 minui/resources.c create mode 100644 minui/resources.cpp (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index 66dea741a..52f066256 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -3,10 +3,10 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ events.cpp \ - graphics.c \ - graphics_adf.c \ - graphics_fbdev.c \ - resources.c \ + graphics.cpp \ + graphics_adf.cpp \ + graphics_fbdev.cpp \ + resources.cpp \ LOCAL_WHOLE_STATIC_LIBRARIES += libadf LOCAL_STATIC_LIBRARIES += libpng diff --git a/minui/events.cpp b/minui/events.cpp index daa10c6cf..2d47a587f 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -39,10 +39,10 @@ struct fd_info { }; static int g_epoll_fd; -static struct epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS]; +static epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS]; static int npolledevents; -static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS]; +static fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS]; static unsigned ev_count = 0; static unsigned ev_dev_count = 0; @@ -62,7 +62,7 @@ int ev_init(ev_callback input_cb, void* data) { DIR* dir = opendir("/dev/input"); if (dir != NULL) { - struct dirent* de; + dirent* de; while ((de = readdir(dir))) { unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; @@ -83,7 +83,7 @@ int ev_init(ev_callback input_cb, void* data) { continue; } - struct epoll_event ev; + epoll_event ev; ev.events = EPOLLIN | EPOLLWAKEUP; ev.data.ptr = &ev_fdinfo[ev_count]; if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { @@ -121,7 +121,7 @@ int ev_add_fd(int fd, ev_callback cb, void* data) { return -1; } - struct epoll_event ev; + epoll_event ev; ev.events = EPOLLIN | EPOLLWAKEUP; ev.data.ptr = (void *)&ev_fdinfo[ev_count]; int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev); @@ -163,7 +163,7 @@ void ev_dispatch(void) { } } -int ev_get_input(int fd, uint32_t epevents, struct input_event* ev) { +int ev_get_input(int fd, uint32_t epevents, input_event* ev) { if (epevents & EPOLLIN) { ssize_t r = read(fd, ev, sizeof(*ev)); if (r == sizeof(*ev)) { diff --git a/minui/graphics.c b/minui/graphics.c deleted file mode 100644 index 9d1e1b480..000000000 --- a/minui/graphics.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include "font_10x18.h" -#include "minui.h" -#include "graphics.h" - -typedef struct { - GRSurface* texture; - int cwidth; - int cheight; -} GRFont; - -static GRFont* gr_font = NULL; -static minui_backend* gr_backend = NULL; - -static int overscan_percent = OVERSCAN_PERCENT; -static int overscan_offset_x = 0; -static int overscan_offset_y = 0; - -static unsigned char gr_current_r = 255; -static unsigned char gr_current_g = 255; -static unsigned char gr_current_b = 255; -static unsigned char gr_current_a = 255; - -static GRSurface* gr_draw = NULL; - -static bool outside(int x, int y) -{ - return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; -} - -int gr_measure(const char *s) -{ - return gr_font->cwidth * strlen(s); -} - -void gr_font_size(int *x, int *y) -{ - *x = gr_font->cwidth; - *y = gr_font->cheight; -} - -static void text_blend(unsigned char* src_p, int src_row_bytes, - unsigned char* dst_p, int dst_row_bytes, - int width, int height) -{ - for (int j = 0; j < height; ++j) { - unsigned char* sx = src_p; - unsigned char* px = dst_p; - for (int i = 0; i < width; ++i) { - unsigned char a = *sx++; - if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255; - if (a == 255) { - *px++ = gr_current_r; - *px++ = gr_current_g; - *px++ = gr_current_b; - px++; - } else if (a > 0) { - *px = (*px * (255-a) + gr_current_r * a) / 255; - ++px; - *px = (*px * (255-a) + gr_current_g * a) / 255; - ++px; - *px = (*px * (255-a) + gr_current_b * a) / 255; - ++px; - ++px; - } else { - px += 4; - } - } - src_p += src_row_bytes; - dst_p += dst_row_bytes; - } -} - -void gr_text(int x, int y, const char *s, int bold) -{ - GRFont* font = gr_font; - - if (!font->texture || gr_current_a == 0) return; - - bold = bold && (font->texture->height != font->cheight); - - x += overscan_offset_x; - y += overscan_offset_y; - - unsigned char ch; - while ((ch = *s++)) { - if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break; - - if (ch < ' ' || ch > '~') { - ch = '?'; - } - - unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) + - (bold ? font->cheight * font->texture->row_bytes : 0); - unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; - - text_blend(src_p, font->texture->row_bytes, - dst_p, gr_draw->row_bytes, - font->cwidth, font->cheight); - - x += font->cwidth; - } -} - -void gr_texticon(int x, int y, GRSurface* icon) { - if (icon == NULL) return; - - if (icon->pixel_bytes != 1) { - printf("gr_texticon: source has wrong format\n"); - return; - } - - x += overscan_offset_x; - y += overscan_offset_y; - - if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return; - - unsigned char* src_p = icon->data; - unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; - - text_blend(src_p, icon->row_bytes, - dst_p, gr_draw->row_bytes, - icon->width, icon->height); -} - -void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ -#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) - gr_current_r = b; - gr_current_g = g; - gr_current_b = r; - gr_current_a = a; -#else - gr_current_r = r; - gr_current_g = g; - gr_current_b = b; - gr_current_a = a; -#endif -} - -void gr_clear() -{ - if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) { - memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes); - } else { - unsigned char* px = gr_draw->data; - for (int y = 0; y < gr_draw->height; ++y) { - for (int x = 0; x < gr_draw->width; ++x) { - *px++ = gr_current_r; - *px++ = gr_current_g; - *px++ = gr_current_b; - px++; - } - px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes); - } - } -} - -void gr_fill(int x1, int y1, int x2, int y2) -{ - x1 += overscan_offset_x; - y1 += overscan_offset_y; - - x2 += overscan_offset_x; - y2 += overscan_offset_y; - - if (outside(x1, y1) || outside(x2-1, y2-1)) return; - - unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes; - if (gr_current_a == 255) { - int x, y; - for (y = y1; y < y2; ++y) { - unsigned char* px = p; - for (x = x1; x < x2; ++x) { - *px++ = gr_current_r; - *px++ = gr_current_g; - *px++ = gr_current_b; - px++; - } - p += gr_draw->row_bytes; - } - } else if (gr_current_a > 0) { - int x, y; - for (y = y1; y < y2; ++y) { - unsigned char* px = p; - for (x = x1; x < x2; ++x) { - *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255; - ++px; - *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255; - ++px; - *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255; - ++px; - ++px; - } - p += gr_draw->row_bytes; - } - } -} - -void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { - if (source == NULL) return; - - if (gr_draw->pixel_bytes != source->pixel_bytes) { - printf("gr_blit: source has wrong format\n"); - return; - } - - dx += overscan_offset_x; - dy += overscan_offset_y; - - if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return; - - unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes; - unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes; - - int i; - for (i = 0; i < h; ++i) { - memcpy(dst_p, src_p, w * source->pixel_bytes); - src_p += source->row_bytes; - dst_p += gr_draw->row_bytes; - } -} - -unsigned int gr_get_width(GRSurface* surface) { - if (surface == NULL) { - return 0; - } - return surface->width; -} - -unsigned int gr_get_height(GRSurface* surface) { - if (surface == NULL) { - return 0; - } - return surface->height; -} - -static void gr_init_font(void) -{ - gr_font = calloc(sizeof(*gr_font), 1); - - int res = res_create_alpha_surface("font", &(gr_font->texture)); - if (res == 0) { - // The font image should be a 96x2 array of character images. The - // columns are the printable ASCII characters 0x20 - 0x7f. The - // top row is regular text; the bottom row is bold. - gr_font->cwidth = gr_font->texture->width / 96; - gr_font->cheight = gr_font->texture->height / 2; - } else { - printf("failed to read font: res=%d\n", res); - - // fall back to the compiled-in font. - gr_font->texture = malloc(sizeof(*gr_font->texture)); - gr_font->texture->width = font.width; - gr_font->texture->height = font.height; - gr_font->texture->row_bytes = font.width; - gr_font->texture->pixel_bytes = 1; - - unsigned char* bits = malloc(font.width * font.height); - gr_font->texture->data = (void*) bits; - - unsigned char data; - unsigned char* in = font.rundata; - while((data = *in++)) { - memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); - bits += (data & 0x7f); - } - - gr_font->cwidth = font.cwidth; - gr_font->cheight = font.cheight; - } -} - -#if 0 -// Exercises many of the gr_*() functions; useful for testing. -static void gr_test() { - GRSurface** images; - int frames; - int result = res_create_multi_surface("icon_installing", &frames, &images); - if (result < 0) { - printf("create surface %d\n", result); - gr_exit(); - return; - } - - time_t start = time(NULL); - int x; - for (x = 0; x <= 1200; ++x) { - if (x < 400) { - gr_color(0, 0, 0, 255); - } else { - gr_color(0, (x-400)%128, 0, 255); - } - gr_clear(); - - gr_color(255, 0, 0, 255); - gr_surface frame = images[x%frames]; - gr_blit(frame, 0, 0, frame->width, frame->height, x, 0); - - gr_color(255, 0, 0, 128); - gr_fill(400, 150, 600, 350); - - gr_color(255, 255, 255, 255); - gr_text(500, 225, "hello, world!", 0); - gr_color(255, 255, 0, 128); - gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1); - - gr_color(0, 0, 255, 128); - gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500); - - gr_draw = gr_backend->flip(gr_backend); - } - printf("getting end time\n"); - time_t end = time(NULL); - printf("got end time\n"); - printf("start %ld end %ld\n", (long)start, (long)end); - if (end > start) { - printf("%.2f fps\n", ((double)x) / (end-start)); - } -} -#endif - -void gr_flip() { - gr_draw = gr_backend->flip(gr_backend); -} - -int gr_init(void) -{ - gr_init_font(); - - gr_backend = open_adf(); - if (gr_backend) { - gr_draw = gr_backend->init(gr_backend); - if (!gr_draw) { - gr_backend->exit(gr_backend); - } - } - - if (!gr_draw) { - gr_backend = open_fbdev(); - gr_draw = gr_backend->init(gr_backend); - if (gr_draw == NULL) { - return -1; - } - } - - overscan_offset_x = gr_draw->width * overscan_percent / 100; - overscan_offset_y = gr_draw->height * overscan_percent / 100; - - gr_flip(); - gr_flip(); - - return 0; -} - -void gr_exit(void) -{ - gr_backend->exit(gr_backend); -} - -int gr_fb_width(void) -{ - return gr_draw->width - 2*overscan_offset_x; -} - -int gr_fb_height(void) -{ - return gr_draw->height - 2*overscan_offset_y; -} - -void gr_fb_blank(bool blank) -{ - gr_backend->blank(gr_backend, blank); -} diff --git a/minui/graphics.cpp b/minui/graphics.cpp new file mode 100644 index 000000000..d7d6e8d5a --- /dev/null +++ b/minui/graphics.cpp @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "font_10x18.h" +#include "minui.h" +#include "graphics.h" + +struct GRFont { + GRSurface* texture; + int cwidth; + int cheight; +}; + +static GRFont* gr_font = NULL; +static minui_backend* gr_backend = NULL; + +static int overscan_percent = OVERSCAN_PERCENT; +static int overscan_offset_x = 0; +static int overscan_offset_y = 0; + +static unsigned char gr_current_r = 255; +static unsigned char gr_current_g = 255; +static unsigned char gr_current_b = 255; +static unsigned char gr_current_a = 255; + +static GRSurface* gr_draw = NULL; + +static bool outside(int x, int y) +{ + return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height; +} + +int gr_measure(const char *s) +{ + return gr_font->cwidth * strlen(s); +} + +void gr_font_size(int *x, int *y) +{ + *x = gr_font->cwidth; + *y = gr_font->cheight; +} + +static void text_blend(unsigned char* src_p, int src_row_bytes, + unsigned char* dst_p, int dst_row_bytes, + int width, int height) +{ + for (int j = 0; j < height; ++j) { + unsigned char* sx = src_p; + unsigned char* px = dst_p; + for (int i = 0; i < width; ++i) { + unsigned char a = *sx++; + if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255; + if (a == 255) { + *px++ = gr_current_r; + *px++ = gr_current_g; + *px++ = gr_current_b; + px++; + } else if (a > 0) { + *px = (*px * (255-a) + gr_current_r * a) / 255; + ++px; + *px = (*px * (255-a) + gr_current_g * a) / 255; + ++px; + *px = (*px * (255-a) + gr_current_b * a) / 255; + ++px; + ++px; + } else { + px += 4; + } + } + src_p += src_row_bytes; + dst_p += dst_row_bytes; + } +} + +void gr_text(int x, int y, const char *s, int bold) +{ + GRFont* font = gr_font; + + if (!font->texture || gr_current_a == 0) return; + + bold = bold && (font->texture->height != font->cheight); + + x += overscan_offset_x; + y += overscan_offset_y; + + unsigned char ch; + while ((ch = *s++)) { + if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break; + + if (ch < ' ' || ch > '~') { + ch = '?'; + } + + unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) + + (bold ? font->cheight * font->texture->row_bytes : 0); + unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; + + text_blend(src_p, font->texture->row_bytes, + dst_p, gr_draw->row_bytes, + font->cwidth, font->cheight); + + x += font->cwidth; + } +} + +void gr_texticon(int x, int y, GRSurface* icon) { + if (icon == NULL) return; + + if (icon->pixel_bytes != 1) { + printf("gr_texticon: source has wrong format\n"); + return; + } + + x += overscan_offset_x; + y += overscan_offset_y; + + if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return; + + unsigned char* src_p = icon->data; + unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes; + + text_blend(src_p, icon->row_bytes, + dst_p, gr_draw->row_bytes, + icon->width, icon->height); +} + +void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + gr_current_r = b; + gr_current_g = g; + gr_current_b = r; + gr_current_a = a; +#else + gr_current_r = r; + gr_current_g = g; + gr_current_b = b; + gr_current_a = a; +#endif +} + +void gr_clear() +{ + if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) { + memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes); + } else { + unsigned char* px = gr_draw->data; + for (int y = 0; y < gr_draw->height; ++y) { + for (int x = 0; x < gr_draw->width; ++x) { + *px++ = gr_current_r; + *px++ = gr_current_g; + *px++ = gr_current_b; + px++; + } + px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes); + } + } +} + +void gr_fill(int x1, int y1, int x2, int y2) +{ + x1 += overscan_offset_x; + y1 += overscan_offset_y; + + x2 += overscan_offset_x; + y2 += overscan_offset_y; + + if (outside(x1, y1) || outside(x2-1, y2-1)) return; + + unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes; + if (gr_current_a == 255) { + int x, y; + for (y = y1; y < y2; ++y) { + unsigned char* px = p; + for (x = x1; x < x2; ++x) { + *px++ = gr_current_r; + *px++ = gr_current_g; + *px++ = gr_current_b; + px++; + } + p += gr_draw->row_bytes; + } + } else if (gr_current_a > 0) { + int x, y; + for (y = y1; y < y2; ++y) { + unsigned char* px = p; + for (x = x1; x < x2; ++x) { + *px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255; + ++px; + *px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255; + ++px; + *px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255; + ++px; + ++px; + } + p += gr_draw->row_bytes; + } + } +} + +void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) { + if (source == NULL) return; + + if (gr_draw->pixel_bytes != source->pixel_bytes) { + printf("gr_blit: source has wrong format\n"); + return; + } + + dx += overscan_offset_x; + dy += overscan_offset_y; + + if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return; + + unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes; + unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes; + + int i; + for (i = 0; i < h; ++i) { + memcpy(dst_p, src_p, w * source->pixel_bytes); + src_p += source->row_bytes; + dst_p += gr_draw->row_bytes; + } +} + +unsigned int gr_get_width(GRSurface* surface) { + if (surface == NULL) { + return 0; + } + return surface->width; +} + +unsigned int gr_get_height(GRSurface* surface) { + if (surface == NULL) { + return 0; + } + return surface->height; +} + +static void gr_init_font(void) +{ + gr_font = reinterpret_cast(calloc(sizeof(*gr_font), 1)); + + int res = res_create_alpha_surface("font", &(gr_font->texture)); + if (res == 0) { + // The font image should be a 96x2 array of character images. The + // columns are the printable ASCII characters 0x20 - 0x7f. The + // top row is regular text; the bottom row is bold. + gr_font->cwidth = gr_font->texture->width / 96; + gr_font->cheight = gr_font->texture->height / 2; + } else { + printf("failed to read font: res=%d\n", res); + + // fall back to the compiled-in font. + gr_font->texture = reinterpret_cast(malloc(sizeof(*gr_font->texture))); + gr_font->texture->width = font.width; + gr_font->texture->height = font.height; + gr_font->texture->row_bytes = font.width; + gr_font->texture->pixel_bytes = 1; + + unsigned char* bits = reinterpret_cast(malloc(font.width * font.height)); + gr_font->texture->data = reinterpret_cast(bits); + + unsigned char data; + unsigned char* in = font.rundata; + while((data = *in++)) { + memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f); + bits += (data & 0x7f); + } + + gr_font->cwidth = font.cwidth; + gr_font->cheight = font.cheight; + } +} + +#if 0 +// Exercises many of the gr_*() functions; useful for testing. +static void gr_test() { + GRSurface** images; + int frames; + int result = res_create_multi_surface("icon_installing", &frames, &images); + if (result < 0) { + printf("create surface %d\n", result); + gr_exit(); + return; + } + + time_t start = time(NULL); + int x; + for (x = 0; x <= 1200; ++x) { + if (x < 400) { + gr_color(0, 0, 0, 255); + } else { + gr_color(0, (x-400)%128, 0, 255); + } + gr_clear(); + + gr_color(255, 0, 0, 255); + gr_surface frame = images[x%frames]; + gr_blit(frame, 0, 0, frame->width, frame->height, x, 0); + + gr_color(255, 0, 0, 128); + gr_fill(400, 150, 600, 350); + + gr_color(255, 255, 255, 255); + gr_text(500, 225, "hello, world!", 0); + gr_color(255, 255, 0, 128); + gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1); + + gr_color(0, 0, 255, 128); + gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500); + + gr_draw = gr_backend->flip(gr_backend); + } + printf("getting end time\n"); + time_t end = time(NULL); + printf("got end time\n"); + printf("start %ld end %ld\n", (long)start, (long)end); + if (end > start) { + printf("%.2f fps\n", ((double)x) / (end-start)); + } +} +#endif + +void gr_flip() { + gr_draw = gr_backend->flip(gr_backend); +} + +int gr_init(void) +{ + gr_init_font(); + + gr_backend = open_adf(); + if (gr_backend) { + gr_draw = gr_backend->init(gr_backend); + if (!gr_draw) { + gr_backend->exit(gr_backend); + } + } + + if (!gr_draw) { + gr_backend = open_fbdev(); + gr_draw = gr_backend->init(gr_backend); + if (gr_draw == NULL) { + return -1; + } + } + + overscan_offset_x = gr_draw->width * overscan_percent / 100; + overscan_offset_y = gr_draw->height * overscan_percent / 100; + + gr_flip(); + gr_flip(); + + return 0; +} + +void gr_exit(void) +{ + gr_backend->exit(gr_backend); +} + +int gr_fb_width(void) +{ + return gr_draw->width - 2*overscan_offset_x; +} + +int gr_fb_height(void) +{ + return gr_draw->height - 2*overscan_offset_y; +} + +void gr_fb_blank(bool blank) +{ + gr_backend->blank(gr_backend, blank); +} diff --git a/minui/graphics.h b/minui/graphics.h index 993e986ee..ed229a0c8 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -17,34 +17,26 @@ #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ -#ifdef __cplusplus -extern "C" { -#endif - -#include #include "minui.h" -typedef struct minui_backend { +// TODO: lose the function pointers. +struct minui_backend { // Initializes the backend and returns a gr_surface to draw into. - gr_surface (*init)(struct minui_backend*); + gr_surface (*init)(minui_backend*); // Causes the current drawing surface (returned by the most recent // call to flip() or init()) to be displayed, and returns a new // drawing surface. - gr_surface (*flip)(struct minui_backend*); + gr_surface (*flip)(minui_backend*); // Blank (or unblank) the screen. - void (*blank)(struct minui_backend*, bool); + void (*blank)(minui_backend*, bool); // Device cleanup when drawing is done. - void (*exit)(struct minui_backend*); -} minui_backend; + void (*exit)(minui_backend*); +}; minui_backend* open_fbdev(); minui_backend* open_adf(); -#ifdef __cplusplus -} -#endif - #endif diff --git a/minui/graphics_adf.c b/minui/graphics_adf.c deleted file mode 100644 index c023d4db9..000000000 --- a/minui/graphics_adf.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "graphics.h" - -struct adf_surface_pdata { - GRSurface base; - int fd; - __u32 offset; - __u32 pitch; -}; - -struct adf_pdata { - minui_backend base; - int intf_fd; - adf_id_t eng_id; - __u32 format; - - unsigned int current_surface; - unsigned int n_surfaces; - struct adf_surface_pdata surfaces[2]; -}; - -static gr_surface adf_flip(struct minui_backend *backend); -static void adf_blank(struct minui_backend *backend, bool blank); - -static int adf_surface_init(struct adf_pdata *pdata, - struct drm_mode_modeinfo *mode, struct adf_surface_pdata *surf) -{ - memset(surf, 0, sizeof(*surf)); - - surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, - mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); - if (surf->fd < 0) - return surf->fd; - - surf->base.width = mode->hdisplay; - surf->base.height = mode->vdisplay; - surf->base.row_bytes = surf->pitch; - surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4; - - surf->base.data = mmap(NULL, surf->pitch * surf->base.height, PROT_WRITE, - MAP_SHARED, surf->fd, surf->offset); - if (surf->base.data == MAP_FAILED) { - close(surf->fd); - return -errno; - } - - return 0; -} - -static int adf_interface_init(struct adf_pdata *pdata) -{ - struct adf_interface_data intf_data; - int ret = 0; - int err; - - err = adf_get_interface_data(pdata->intf_fd, &intf_data); - if (err < 0) - return err; - - err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]); - if (err < 0) { - fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err)); - ret = err; - goto done; - } - - err = adf_surface_init(pdata, &intf_data.current_mode, - &pdata->surfaces[1]); - if (err < 0) { - fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); - memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1])); - pdata->n_surfaces = 1; - } else { - pdata->n_surfaces = 2; - } - -done: - adf_free_interface_data(&intf_data); - return ret; -} - -static int adf_device_init(struct adf_pdata *pdata, struct adf_device *dev) -{ - adf_id_t intf_id; - int intf_fd; - int err; - - err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id, - &pdata->eng_id); - if (err < 0) - return err; - - err = adf_device_attach(dev, pdata->eng_id, intf_id); - if (err < 0 && err != -EALREADY) - return err; - - pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR); - if (pdata->intf_fd < 0) - return pdata->intf_fd; - - err = adf_interface_init(pdata); - if (err < 0) { - close(pdata->intf_fd); - pdata->intf_fd = -1; - } - - return err; -} - -static gr_surface adf_init(minui_backend *backend) -{ - struct adf_pdata *pdata = (struct adf_pdata *)backend; - adf_id_t *dev_ids = NULL; - ssize_t n_dev_ids, i; - gr_surface ret; - -#if defined(RECOVERY_ABGR) - pdata->format = DRM_FORMAT_ABGR8888; -#elif defined(RECOVERY_BGRA) - pdata->format = DRM_FORMAT_BGRA8888; -#elif defined(RECOVERY_RGBX) - pdata->format = DRM_FORMAT_RGBX8888; -#else - pdata->format = DRM_FORMAT_RGB565; -#endif - - n_dev_ids = adf_devices(&dev_ids); - if (n_dev_ids == 0) { - return NULL; - } else if (n_dev_ids < 0) { - fprintf(stderr, "enumerating adf devices failed: %s\n", - strerror(-n_dev_ids)); - return NULL; - } - - pdata->intf_fd = -1; - - for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { - struct adf_device dev; - - int err = adf_device_open(dev_ids[i], O_RDWR, &dev); - if (err < 0) { - fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i], - strerror(-err)); - continue; - } - - err = adf_device_init(pdata, &dev); - if (err < 0) - fprintf(stderr, "initializing adf device %u failed: %s\n", - dev_ids[i], strerror(-err)); - - adf_device_close(&dev); - } - - free(dev_ids); - - if (pdata->intf_fd < 0) - return NULL; - - ret = adf_flip(backend); - - adf_blank(backend, true); - adf_blank(backend, false); - - return ret; -} - -static gr_surface adf_flip(struct minui_backend *backend) -{ - struct adf_pdata *pdata = (struct adf_pdata *)backend; - struct adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; - - int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, - surf->base.width, surf->base.height, pdata->format, surf->fd, - surf->offset, surf->pitch, -1); - if (fence_fd >= 0) - close(fence_fd); - - pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; - return &pdata->surfaces[pdata->current_surface].base; -} - -static void adf_blank(struct minui_backend *backend, bool blank) -{ - struct adf_pdata *pdata = (struct adf_pdata *)backend; - adf_interface_blank(pdata->intf_fd, - blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); -} - -static void adf_surface_destroy(struct adf_surface_pdata *surf) -{ - munmap(surf->base.data, surf->pitch * surf->base.height); - close(surf->fd); -} - -static void adf_exit(struct minui_backend *backend) -{ - struct adf_pdata *pdata = (struct adf_pdata *)backend; - unsigned int i; - - for (i = 0; i < pdata->n_surfaces; i++) - adf_surface_destroy(&pdata->surfaces[i]); - if (pdata->intf_fd >= 0) - close(pdata->intf_fd); - free(pdata); -} - -minui_backend *open_adf() -{ - struct adf_pdata *pdata = calloc(1, sizeof(*pdata)); - if (!pdata) { - perror("allocating adf backend failed"); - return NULL; - } - - pdata->base.init = adf_init; - pdata->base.flip = adf_flip; - pdata->base.blank = adf_blank; - pdata->base.exit = adf_exit; - return &pdata->base; -} diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp new file mode 100644 index 000000000..ea7c0abe1 --- /dev/null +++ b/minui/graphics_adf.cpp @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "graphics.h" + +struct adf_surface_pdata { + GRSurface base; + int fd; + __u32 offset; + __u32 pitch; +}; + +struct adf_pdata { + minui_backend base; + int intf_fd; + adf_id_t eng_id; + __u32 format; + + unsigned int current_surface; + unsigned int n_surfaces; + adf_surface_pdata surfaces[2]; +}; + +static gr_surface adf_flip(minui_backend *backend); +static void adf_blank(minui_backend *backend, bool blank); + +static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) { + memset(surf, 0, sizeof(*surf)); + + surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, + mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); + if (surf->fd < 0) + return surf->fd; + + surf->base.width = mode->hdisplay; + surf->base.height = mode->vdisplay; + surf->base.row_bytes = surf->pitch; + surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4; + + surf->base.data = reinterpret_cast(mmap(NULL, + surf->pitch * surf->base.height, PROT_WRITE, + MAP_SHARED, surf->fd, surf->offset)); + if (surf->base.data == MAP_FAILED) { + close(surf->fd); + return -errno; + } + + return 0; +} + +static int adf_interface_init(adf_pdata *pdata) +{ + adf_interface_data intf_data; + int ret = 0; + int err; + + err = adf_get_interface_data(pdata->intf_fd, &intf_data); + if (err < 0) + return err; + + err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]); + if (err < 0) { + fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err)); + ret = err; + goto done; + } + + err = adf_surface_init(pdata, &intf_data.current_mode, + &pdata->surfaces[1]); + if (err < 0) { + fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); + memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1])); + pdata->n_surfaces = 1; + } else { + pdata->n_surfaces = 2; + } + +done: + adf_free_interface_data(&intf_data); + return ret; +} + +static int adf_device_init(adf_pdata *pdata, adf_device *dev) +{ + adf_id_t intf_id; + int intf_fd; + int err; + + err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id, + &pdata->eng_id); + if (err < 0) + return err; + + err = adf_device_attach(dev, pdata->eng_id, intf_id); + if (err < 0 && err != -EALREADY) + return err; + + pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR); + if (pdata->intf_fd < 0) + return pdata->intf_fd; + + err = adf_interface_init(pdata); + if (err < 0) { + close(pdata->intf_fd); + pdata->intf_fd = -1; + } + + return err; +} + +static gr_surface adf_init(minui_backend *backend) +{ + adf_pdata *pdata = (adf_pdata *)backend; + adf_id_t *dev_ids = NULL; + ssize_t n_dev_ids, i; + gr_surface ret; + +#if defined(RECOVERY_ABGR) + pdata->format = DRM_FORMAT_ABGR8888; +#elif defined(RECOVERY_BGRA) + pdata->format = DRM_FORMAT_BGRA8888; +#elif defined(RECOVERY_RGBX) + pdata->format = DRM_FORMAT_RGBX8888; +#else + pdata->format = DRM_FORMAT_RGB565; +#endif + + n_dev_ids = adf_devices(&dev_ids); + if (n_dev_ids == 0) { + return NULL; + } else if (n_dev_ids < 0) { + fprintf(stderr, "enumerating adf devices failed: %s\n", + strerror(-n_dev_ids)); + return NULL; + } + + pdata->intf_fd = -1; + + for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { + adf_device dev; + + int err = adf_device_open(dev_ids[i], O_RDWR, &dev); + if (err < 0) { + fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i], + strerror(-err)); + continue; + } + + err = adf_device_init(pdata, &dev); + if (err < 0) + fprintf(stderr, "initializing adf device %u failed: %s\n", + dev_ids[i], strerror(-err)); + + adf_device_close(&dev); + } + + free(dev_ids); + + if (pdata->intf_fd < 0) + return NULL; + + ret = adf_flip(backend); + + adf_blank(backend, true); + adf_blank(backend, false); + + return ret; +} + +static gr_surface adf_flip(minui_backend *backend) +{ + adf_pdata *pdata = (adf_pdata *)backend; + adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; + + int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, + surf->base.width, surf->base.height, pdata->format, surf->fd, + surf->offset, surf->pitch, -1); + if (fence_fd >= 0) + close(fence_fd); + + pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; + return &pdata->surfaces[pdata->current_surface].base; +} + +static void adf_blank(minui_backend *backend, bool blank) +{ + adf_pdata *pdata = (adf_pdata *)backend; + adf_interface_blank(pdata->intf_fd, + blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); +} + +static void adf_surface_destroy(adf_surface_pdata *surf) +{ + munmap(surf->base.data, surf->pitch * surf->base.height); + close(surf->fd); +} + +static void adf_exit(minui_backend *backend) +{ + adf_pdata *pdata = (adf_pdata *)backend; + unsigned int i; + + for (i = 0; i < pdata->n_surfaces; i++) + adf_surface_destroy(&pdata->surfaces[i]); + if (pdata->intf_fd >= 0) + close(pdata->intf_fd); + free(pdata); +} + +minui_backend *open_adf() +{ + adf_pdata* pdata = reinterpret_cast(calloc(1, sizeof(*pdata))); + if (!pdata) { + perror("allocating adf backend failed"); + return NULL; + } + + pdata->base.init = adf_init; + pdata->base.flip = adf_flip; + pdata->base.blank = adf_blank; + pdata->base.exit = adf_exit; + return &pdata->base; +} diff --git a/minui/graphics_fbdev.c b/minui/graphics_fbdev.c deleted file mode 100644 index 4a5b5b513..000000000 --- a/minui/graphics_fbdev.c +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "minui.h" -#include "graphics.h" - -static gr_surface fbdev_init(minui_backend*); -static gr_surface fbdev_flip(minui_backend*); -static void fbdev_blank(minui_backend*, bool); -static void fbdev_exit(minui_backend*); - -static GRSurface gr_framebuffer[2]; -static bool double_buffered; -static GRSurface* gr_draw = NULL; -static int displayed_buffer; - -static struct fb_var_screeninfo vi; -static int fb_fd = -1; - -static minui_backend my_backend = { - .init = fbdev_init, - .flip = fbdev_flip, - .blank = fbdev_blank, - .exit = fbdev_exit, -}; - -minui_backend* open_fbdev() { - return &my_backend; -} - -static void fbdev_blank(minui_backend* backend __unused, bool blank) -{ - int ret; - - ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); - if (ret < 0) - perror("ioctl(): blank"); -} - -static void set_displayed_framebuffer(unsigned n) -{ - if (n > 1 || !double_buffered) return; - - vi.yres_virtual = gr_framebuffer[0].height * 2; - vi.yoffset = n * gr_framebuffer[0].height; - vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8; - if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { - perror("active fb swap failed"); - } - displayed_buffer = n; -} - -static gr_surface fbdev_init(minui_backend* backend) { - int fd; - void *bits; - - struct fb_fix_screeninfo fi; - - fd = open("/dev/graphics/fb0", O_RDWR); - if (fd < 0) { - perror("cannot open fb0"); - return NULL; - } - - if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { - perror("failed to get fb0 info"); - close(fd); - return NULL; - } - - if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { - perror("failed to get fb0 info"); - close(fd); - return NULL; - } - - // We print this out for informational purposes only, but - // throughout we assume that the framebuffer device uses an RGBX - // pixel format. This is the case for every development device I - // have access to. For some of those devices (eg, hammerhead aka - // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a - // different format (XBGR) but actually produces the correct - // results on the display when you write RGBX. - // - // If you have a device that actually *needs* another pixel format - // (ie, BGRX, or 565), patches welcome... - - printf("fb0 reports (possibly inaccurate):\n" - " vi.bits_per_pixel = %d\n" - " vi.red.offset = %3d .length = %3d\n" - " vi.green.offset = %3d .length = %3d\n" - " vi.blue.offset = %3d .length = %3d\n", - vi.bits_per_pixel, - vi.red.offset, vi.red.length, - vi.green.offset, vi.green.length, - vi.blue.offset, vi.blue.length); - - 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 NULL; - } - - memset(bits, 0, fi.smem_len); - - gr_framebuffer[0].width = vi.xres; - gr_framebuffer[0].height = vi.yres; - gr_framebuffer[0].row_bytes = fi.line_length; - gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8; - gr_framebuffer[0].data = bits; - memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); - - /* check if we can use double buffering */ - if (vi.yres * fi.line_length * 2 <= fi.smem_len) { - double_buffered = true; - - memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface)); - gr_framebuffer[1].data = gr_framebuffer[0].data + - gr_framebuffer[0].height * gr_framebuffer[0].row_bytes; - - gr_draw = gr_framebuffer+1; - - } else { - double_buffered = false; - - // Without double-buffering, we allocate RAM for a buffer to - // draw in, and then "flipping" the buffer consists of a - // memcpy from the buffer we allocated to the framebuffer. - - gr_draw = (GRSurface*) malloc(sizeof(GRSurface)); - memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface)); - gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes); - if (!gr_draw->data) { - perror("failed to allocate in-memory surface"); - return NULL; - } - } - - memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); - fb_fd = fd; - set_displayed_framebuffer(0); - - printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); - - fbdev_blank(backend, true); - fbdev_blank(backend, false); - - return gr_draw; -} - -static gr_surface fbdev_flip(minui_backend* backend __unused) { - if (double_buffered) { -#if defined(RECOVERY_BGRA) - // In case of BGRA, do some byte swapping - unsigned int idx; - unsigned char tmp; - unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data; - for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes); - idx += 4) { - tmp = ucfb_vaddr[idx]; - ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2]; - ucfb_vaddr[idx + 2] = tmp; - } -#endif - // Change gr_draw to point to the buffer currently displayed, - // then flip the driver so we're displaying the other buffer - // instead. - gr_draw = gr_framebuffer + displayed_buffer; - set_displayed_framebuffer(1-displayed_buffer); - } else { - // Copy from the in-memory surface to the framebuffer. - memcpy(gr_framebuffer[0].data, gr_draw->data, - gr_draw->height * gr_draw->row_bytes); - } - return gr_draw; -} - -static void fbdev_exit(minui_backend* backend __unused) { - close(fb_fd); - fb_fd = -1; - - if (!double_buffered && gr_draw) { - free(gr_draw->data); - free(gr_draw); - } - gr_draw = NULL; -} diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp new file mode 100644 index 000000000..9dbdde810 --- /dev/null +++ b/minui/graphics_fbdev.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "minui.h" +#include "graphics.h" + +static gr_surface fbdev_init(minui_backend*); +static gr_surface fbdev_flip(minui_backend*); +static void fbdev_blank(minui_backend*, bool); +static void fbdev_exit(minui_backend*); + +static GRSurface gr_framebuffer[2]; +static bool double_buffered; +static GRSurface* gr_draw = NULL; +static int displayed_buffer; + +static fb_var_screeninfo vi; +static int fb_fd = -1; + +static minui_backend my_backend = { + .init = fbdev_init, + .flip = fbdev_flip, + .blank = fbdev_blank, + .exit = fbdev_exit, +}; + +minui_backend* open_fbdev() { + return &my_backend; +} + +static void fbdev_blank(minui_backend* backend __unused, bool blank) +{ + int ret; + + ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); + if (ret < 0) + perror("ioctl(): blank"); +} + +static void set_displayed_framebuffer(unsigned n) +{ + if (n > 1 || !double_buffered) return; + + vi.yres_virtual = gr_framebuffer[0].height * 2; + vi.yoffset = n * gr_framebuffer[0].height; + vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8; + if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) { + perror("active fb swap failed"); + } + displayed_buffer = n; +} + +static gr_surface fbdev_init(minui_backend* backend) { + int fd = open("/dev/graphics/fb0", O_RDWR); + if (fd == -1) { + perror("cannot open fb0"); + return NULL; + } + + fb_fix_screeninfo fi; + if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return NULL; + } + + if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return NULL; + } + + // We print this out for informational purposes only, but + // throughout we assume that the framebuffer device uses an RGBX + // pixel format. This is the case for every development device I + // have access to. For some of those devices (eg, hammerhead aka + // Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a + // different format (XBGR) but actually produces the correct + // results on the display when you write RGBX. + // + // If you have a device that actually *needs* another pixel format + // (ie, BGRX, or 565), patches welcome... + + printf("fb0 reports (possibly inaccurate):\n" + " vi.bits_per_pixel = %d\n" + " vi.red.offset = %3d .length = %3d\n" + " vi.green.offset = %3d .length = %3d\n" + " vi.blue.offset = %3d .length = %3d\n", + vi.bits_per_pixel, + vi.red.offset, vi.red.length, + vi.green.offset, vi.green.length, + vi.blue.offset, vi.blue.length); + + void* 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 NULL; + } + + memset(bits, 0, fi.smem_len); + + gr_framebuffer[0].width = vi.xres; + gr_framebuffer[0].height = vi.yres; + gr_framebuffer[0].row_bytes = fi.line_length; + gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8; + gr_framebuffer[0].data = reinterpret_cast(bits); + memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); + + /* check if we can use double buffering */ + if (vi.yres * fi.line_length * 2 <= fi.smem_len) { + double_buffered = true; + + memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface)); + gr_framebuffer[1].data = gr_framebuffer[0].data + + gr_framebuffer[0].height * gr_framebuffer[0].row_bytes; + + gr_draw = gr_framebuffer+1; + + } else { + double_buffered = false; + + // Without double-buffering, we allocate RAM for a buffer to + // draw in, and then "flipping" the buffer consists of a + // memcpy from the buffer we allocated to the framebuffer. + + gr_draw = (GRSurface*) malloc(sizeof(GRSurface)); + memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface)); + gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes); + if (!gr_draw->data) { + perror("failed to allocate in-memory surface"); + return NULL; + } + } + + memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); + fb_fd = fd; + set_displayed_framebuffer(0); + + printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); + + fbdev_blank(backend, true); + fbdev_blank(backend, false); + + return gr_draw; +} + +static gr_surface fbdev_flip(minui_backend* backend __unused) { + if (double_buffered) { +#if defined(RECOVERY_BGRA) + // In case of BGRA, do some byte swapping + unsigned int idx; + unsigned char tmp; + unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data; + for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes); + idx += 4) { + tmp = ucfb_vaddr[idx]; + ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2]; + ucfb_vaddr[idx + 2] = tmp; + } +#endif + // Change gr_draw to point to the buffer currently displayed, + // then flip the driver so we're displaying the other buffer + // instead. + gr_draw = gr_framebuffer + displayed_buffer; + set_displayed_framebuffer(1-displayed_buffer); + } else { + // Copy from the in-memory surface to the framebuffer. + memcpy(gr_framebuffer[0].data, gr_draw->data, + gr_draw->height * gr_draw->row_bytes); + } + return gr_draw; +} + +static void fbdev_exit(minui_backend* backend __unused) { + close(fb_fd); + fb_fd = -1; + + if (!double_buffered && gr_draw) { + free(gr_draw->data); + free(gr_draw); + } + gr_draw = NULL; +} diff --git a/minui/minui.h b/minui/minui.h index 82abb8a63..eca3a5030 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -19,33 +19,30 @@ #include -#include - -#ifdef __cplusplus -extern "C" { -#endif +#include // // Graphics. // -typedef struct { +struct GRSurface { int width; int height; int row_bytes; int pixel_bytes; unsigned char* data; -} GRSurface; +}; +// TODO: remove this. typedef GRSurface* gr_surface; -int gr_init(void); -void gr_exit(void); +int gr_init(); +void gr_exit(); -int gr_fb_width(void); -int gr_fb_height(void); +int gr_fb_width(); +int gr_fb_height(); -void gr_flip(void); +void gr_flip(); void gr_fb_blank(bool blank); void gr_clear(); // clear entire surface to current color @@ -66,12 +63,14 @@ unsigned int gr_get_height(gr_surface surface); struct input_event; +// TODO: move these over to std::function. typedef int (*ev_callback)(int fd, uint32_t epevents, void* data); typedef int (*ev_set_key_callback)(int code, int value, void* data); int ev_init(ev_callback input_cb, void* data); -void ev_exit(void); +void ev_exit(); int ev_add_fd(int fd, ev_callback cb, void* data); +void ev_iterate_available_keys(std::function f); int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); // 'timeout' has the same semantics as poll(2). @@ -80,9 +79,9 @@ int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); // > 0 : block for 'timeout' milliseconds int ev_wait(int timeout); -int ev_get_input(int fd, uint32_t epevents, struct input_event *ev); -void ev_dispatch(void); -int ev_get_epollfd(void); +int ev_get_input(int fd, uint32_t epevents, input_event* ev); +void ev_dispatch(); +int ev_get_epollfd(); // // Resources @@ -124,15 +123,4 @@ int res_create_localized_alpha_surface(const char* name, const char* locale, // functions. void res_free_surface(gr_surface surface); -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus - -#include -void ev_iterate_available_keys(std::function f); - -#endif - #endif diff --git a/minui/resources.c b/minui/resources.c deleted file mode 100644 index 886c3255d..000000000 --- a/minui/resources.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include "minui.h" - -extern char* locale; - -#define SURFACE_DATA_ALIGNMENT 8 - -static gr_surface malloc_surface(size_t data_size) { - unsigned char* temp = malloc(sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT); - if (temp == NULL) return NULL; - gr_surface surface = (gr_surface) temp; - surface->data = temp + sizeof(GRSurface) + - (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); - return surface; -} - -static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, - png_uint_32* width, png_uint_32* height, png_byte* channels) { - char resPath[256]; - unsigned char header[8]; - int result = 0; - - snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); - resPath[sizeof(resPath)-1] = '\0'; - FILE* fp = fopen(resPath, "rb"); - if (fp == NULL) { - result = -1; - goto exit; - } - - size_t bytesRead = fread(header, 1, sizeof(header), fp); - if (bytesRead != sizeof(header)) { - result = -2; - goto exit; - } - - if (png_sig_cmp(header, 0, sizeof(header))) { - result = -3; - goto exit; - } - - *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!*png_ptr) { - result = -4; - goto exit; - } - - *info_ptr = png_create_info_struct(*png_ptr); - if (!*info_ptr) { - result = -5; - goto exit; - } - - if (setjmp(png_jmpbuf(*png_ptr))) { - result = -6; - goto exit; - } - - png_init_io(*png_ptr, fp); - png_set_sig_bytes(*png_ptr, sizeof(header)); - png_read_info(*png_ptr, *info_ptr); - - int color_type, bit_depth; - png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, - &color_type, NULL, NULL, NULL); - - *channels = png_get_channels(*png_ptr, *info_ptr); - - if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { - // 8-bit RGB images: great, nothing to do. - } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { - // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. - png_set_expand_gray_1_2_4_to_8(*png_ptr); - } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { - // paletted images: expand to 8-bit RGB. Note that we DON'T - // currently expand the tRNS chunk (if any) to an alpha - // channel, because minui doesn't support alpha channels in - // general. - png_set_palette_to_rgb(*png_ptr); - *channels = 3; - } else { - fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", - bit_depth, *channels, color_type); - result = -7; - goto exit; - } - - return result; - - exit: - if (result < 0) { - png_destroy_read_struct(png_ptr, info_ptr, NULL); - } - if (fp != NULL) { - fclose(fp); - } - - return result; -} - -// "display" surfaces are transformed into the framebuffer's required -// pixel format (currently only RGBX is supported) at load time, so -// gr_blit() can be nothing more than a memcpy() for each row. The -// next two functions are the only ones that know anything about the -// framebuffer pixel format; they need to be modified if the -// framebuffer format changes (but nothing else should). - -// Allocate and return a gr_surface sufficient for storing an image of -// the indicated size in the framebuffer pixel format. -static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { - gr_surface surface; - - surface = malloc_surface(width * height * 4); - if (surface == NULL) return NULL; - - surface->width = width; - surface->height = height; - surface->row_bytes = width * 4; - surface->pixel_bytes = 4; - - return surface; -} - -// Copy 'input_row' to 'output_row', transforming it to the -// framebuffer pixel format. The input format depends on the value of -// 'channels': -// -// 1 - input is 8-bit grayscale -// 3 - input is 24-bit RGB -// 4 - input is 32-bit RGBA/RGBX -// -// 'width' is the number of pixels in the row. -static void transform_rgb_to_draw(unsigned char* input_row, - unsigned char* output_row, - int channels, int width) { - int x; - unsigned char* ip = input_row; - unsigned char* op = output_row; - - switch (channels) { - case 1: - // expand gray level to RGBX - for (x = 0; x < width; ++x) { - *op++ = *ip; - *op++ = *ip; - *op++ = *ip; - *op++ = 0xff; - ip++; - } - break; - - case 3: - // expand RGBA to RGBX - for (x = 0; x < width; ++x) { - *op++ = *ip++; - *op++ = *ip++; - *op++ = *ip++; - *op++ = 0xff; - } - break; - - case 4: - // copy RGBA to RGBX - memcpy(output_row, input_row, width*4); - break; - } -} - -int res_create_display_surface(const char* name, gr_surface* pSurface) { - gr_surface surface = NULL; - int result = 0; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_uint_32 width, height; - png_byte channels; - - *pSurface = NULL; - - result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); - if (result < 0) return result; - - surface = init_display_surface(width, height); - if (surface == NULL) { - result = -8; - goto exit; - } - -#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) - png_set_bgr(png_ptr); -#endif - - unsigned char* p_row = malloc(width * 4); - unsigned int y; - for (y = 0; y < height; ++y) { - png_read_row(png_ptr, p_row, NULL); - transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width); - } - free(p_row); - - *pSurface = surface; - - exit: - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (result < 0 && surface != NULL) free(surface); - return result; -} - -int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { - gr_surface* surface = NULL; - int result = 0; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_uint_32 width, height; - png_byte channels; - int i; - - *pSurface = NULL; - *frames = -1; - - result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); - if (result < 0) return result; - - *frames = 1; - png_textp text; - int num_text; - if (png_get_text(png_ptr, info_ptr, &text, &num_text)) { - for (i = 0; i < num_text; ++i) { - if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) { - *frames = atoi(text[i].text); - break; - } - } - printf(" found frames = %d\n", *frames); - } - - if (height % *frames != 0) { - printf("bad height (%d) for frame count (%d)\n", height, *frames); - result = -9; - goto exit; - } - - surface = malloc(*frames * sizeof(gr_surface)); - if (surface == NULL) { - result = -8; - goto exit; - } - for (i = 0; i < *frames; ++i) { - surface[i] = init_display_surface(width, height / *frames); - if (surface[i] == NULL) { - result = -8; - goto exit; - } - } - -#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) - png_set_bgr(png_ptr); -#endif - - unsigned char* p_row = malloc(width * 4); - unsigned int y; - for (y = 0; y < height; ++y) { - png_read_row(png_ptr, p_row, NULL); - int frame = y % *frames; - unsigned char* out_row = surface[frame]->data + - (y / *frames) * surface[frame]->row_bytes; - transform_rgb_to_draw(p_row, out_row, channels, width); - } - free(p_row); - - *pSurface = (gr_surface*) surface; - -exit: - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - - if (result < 0) { - if (surface) { - for (i = 0; i < *frames; ++i) { - if (surface[i]) free(surface[i]); - } - free(surface); - } - } - return result; -} - -int res_create_alpha_surface(const char* name, gr_surface* pSurface) { - gr_surface surface = NULL; - int result = 0; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_uint_32 width, height; - png_byte channels; - - *pSurface = NULL; - - result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); - if (result < 0) return result; - - if (channels != 1) { - result = -7; - goto exit; - } - - surface = malloc_surface(width * height); - if (surface == NULL) { - result = -8; - goto exit; - } - surface->width = width; - surface->height = height; - surface->row_bytes = width; - surface->pixel_bytes = 1; - -#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) - png_set_bgr(png_ptr); -#endif - - unsigned char* p_row; - unsigned int y; - for (y = 0; y < height; ++y) { - p_row = surface->data + y * surface->row_bytes; - png_read_row(png_ptr, p_row, NULL); - } - - *pSurface = surface; - - exit: - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (result < 0 && surface != NULL) free(surface); - return result; -} - -static int matches_locale(const char* loc, const char* locale) { - if (locale == NULL) return 0; - - if (strcmp(loc, locale) == 0) return 1; - - // if loc does *not* have an underscore, and it matches the start - // of locale, and the next character in locale *is* an underscore, - // that's a match. For instance, loc == "en" matches locale == - // "en_US". - - int i; - for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i); - if (loc[i] == '_') return 0; - - return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); -} - -int res_create_localized_alpha_surface(const char* name, - const char* locale, - gr_surface* pSurface) { - gr_surface surface = NULL; - int result = 0; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - png_uint_32 width, height; - png_byte channels; - - *pSurface = NULL; - - if (locale == NULL) { - surface = malloc_surface(0); - surface->width = 0; - surface->height = 0; - surface->row_bytes = 0; - surface->pixel_bytes = 1; - goto exit; - } - - result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); - if (result < 0) return result; - - if (channels != 1) { - result = -7; - goto exit; - } - - unsigned char* row = malloc(width); - png_uint_32 y; - for (y = 0; y < height; ++y) { - png_read_row(png_ptr, row, NULL); - int w = (row[1] << 8) | row[0]; - int h = (row[3] << 8) | row[2]; - int len = row[4]; - char* loc = (char*)row+5; - - if (y+1+h >= height || matches_locale(loc, locale)) { - printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); - - surface = malloc_surface(w*h); - if (surface == NULL) { - result = -8; - goto exit; - } - surface->width = w; - surface->height = h; - surface->row_bytes = w; - surface->pixel_bytes = 1; - - int i; - for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); - memcpy(surface->data + i*w, row, w); - } - - *pSurface = (gr_surface) surface; - break; - } else { - int i; - for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); - } - } - } - -exit: - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); - if (result < 0 && surface != NULL) free(surface); - return result; -} - -void res_free_surface(gr_surface surface) { - free(surface); -} diff --git a/minui/resources.cpp b/minui/resources.cpp new file mode 100644 index 000000000..fa413b608 --- /dev/null +++ b/minui/resources.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "minui.h" + +extern char* locale; + +#define SURFACE_DATA_ALIGNMENT 8 + +static gr_surface malloc_surface(size_t data_size) { + size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT; + unsigned char* temp = reinterpret_cast(malloc(size)); + if (temp == NULL) return NULL; + gr_surface surface = (gr_surface) temp; + surface->data = temp + sizeof(GRSurface) + + (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); + return surface; +} + +static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, + png_uint_32* width, png_uint_32* height, png_byte* channels) { + char resPath[256]; + unsigned char header[8]; + int result = 0; + int color_type, bit_depth; + size_t bytesRead; + + snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); + resPath[sizeof(resPath)-1] = '\0'; + FILE* fp = fopen(resPath, "rb"); + if (fp == NULL) { + result = -1; + goto exit; + } + + bytesRead = fread(header, 1, sizeof(header), fp); + if (bytesRead != sizeof(header)) { + result = -2; + goto exit; + } + + if (png_sig_cmp(header, 0, sizeof(header))) { + result = -3; + goto exit; + } + + *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!*png_ptr) { + result = -4; + goto exit; + } + + *info_ptr = png_create_info_struct(*png_ptr); + if (!*info_ptr) { + result = -5; + goto exit; + } + + if (setjmp(png_jmpbuf(*png_ptr))) { + result = -6; + goto exit; + } + + png_init_io(*png_ptr, fp); + png_set_sig_bytes(*png_ptr, sizeof(header)); + png_read_info(*png_ptr, *info_ptr); + + png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth, + &color_type, NULL, NULL, NULL); + + *channels = png_get_channels(*png_ptr, *info_ptr); + + if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) { + // 8-bit RGB images: great, nothing to do. + } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) { + // 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray. + png_set_expand_gray_1_2_4_to_8(*png_ptr); + } else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) { + // paletted images: expand to 8-bit RGB. Note that we DON'T + // currently expand the tRNS chunk (if any) to an alpha + // channel, because minui doesn't support alpha channels in + // general. + png_set_palette_to_rgb(*png_ptr); + *channels = 3; + } else { + fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n", + bit_depth, *channels, color_type); + result = -7; + goto exit; + } + + return result; + + exit: + if (result < 0) { + png_destroy_read_struct(png_ptr, info_ptr, NULL); + } + if (fp != NULL) { + fclose(fp); + } + + return result; +} + +// "display" surfaces are transformed into the framebuffer's required +// pixel format (currently only RGBX is supported) at load time, so +// gr_blit() can be nothing more than a memcpy() for each row. The +// next two functions are the only ones that know anything about the +// framebuffer pixel format; they need to be modified if the +// framebuffer format changes (but nothing else should). + +// Allocate and return a gr_surface sufficient for storing an image of +// the indicated size in the framebuffer pixel format. +static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { + gr_surface surface; + + surface = malloc_surface(width * height * 4); + if (surface == NULL) return NULL; + + surface->width = width; + surface->height = height; + surface->row_bytes = width * 4; + surface->pixel_bytes = 4; + + return surface; +} + +// Copy 'input_row' to 'output_row', transforming it to the +// framebuffer pixel format. The input format depends on the value of +// 'channels': +// +// 1 - input is 8-bit grayscale +// 3 - input is 24-bit RGB +// 4 - input is 32-bit RGBA/RGBX +// +// 'width' is the number of pixels in the row. +static void transform_rgb_to_draw(unsigned char* input_row, + unsigned char* output_row, + int channels, int width) { + int x; + unsigned char* ip = input_row; + unsigned char* op = output_row; + + switch (channels) { + case 1: + // expand gray level to RGBX + for (x = 0; x < width; ++x) { + *op++ = *ip; + *op++ = *ip; + *op++ = *ip; + *op++ = 0xff; + ip++; + } + break; + + case 3: + // expand RGBA to RGBX + for (x = 0; x < width; ++x) { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + *op++ = 0xff; + } + break; + + case 4: + // copy RGBA to RGBX + memcpy(output_row, input_row, width*4); + break; + } +} + +int res_create_display_surface(const char* name, gr_surface* pSurface) { + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + unsigned char* p_row; + unsigned int y; + + *pSurface = NULL; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; + + surface = init_display_surface(width, height); + if (surface == NULL) { + result = -8; + goto exit; + } + +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + + p_row = reinterpret_cast(malloc(width * 4)); + for (y = 0; y < height; ++y) { + png_read_row(png_ptr, p_row, NULL); + transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width); + } + free(p_row); + + *pSurface = surface; + + exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) free(surface); + return result; +} + +int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { + gr_surface* surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + int i; + png_textp text; + int num_text; + unsigned char* p_row; + unsigned int y; + + *pSurface = NULL; + *frames = -1; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; + + *frames = 1; + if (png_get_text(png_ptr, info_ptr, &text, &num_text)) { + for (i = 0; i < num_text; ++i) { + if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) { + *frames = atoi(text[i].text); + break; + } + } + printf(" found frames = %d\n", *frames); + } + + if (height % *frames != 0) { + printf("bad height (%d) for frame count (%d)\n", height, *frames); + result = -9; + goto exit; + } + + surface = reinterpret_cast(malloc(*frames * sizeof(gr_surface))); + if (surface == NULL) { + result = -8; + goto exit; + } + for (i = 0; i < *frames; ++i) { + surface[i] = init_display_surface(width, height / *frames); + if (surface[i] == NULL) { + result = -8; + goto exit; + } + } + +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + + p_row = reinterpret_cast(malloc(width * 4)); + for (y = 0; y < height; ++y) { + png_read_row(png_ptr, p_row, NULL); + int frame = y % *frames; + unsigned char* out_row = surface[frame]->data + + (y / *frames) * surface[frame]->row_bytes; + transform_rgb_to_draw(p_row, out_row, channels, width); + } + free(p_row); + + *pSurface = (gr_surface*) surface; + +exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + if (result < 0) { + if (surface) { + for (i = 0; i < *frames; ++i) { + if (surface[i]) free(surface[i]); + } + free(surface); + } + } + return result; +} + +int res_create_alpha_surface(const char* name, gr_surface* pSurface) { + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + + *pSurface = NULL; + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; + + if (channels != 1) { + result = -7; + goto exit; + } + + surface = malloc_surface(width * height); + if (surface == NULL) { + result = -8; + goto exit; + } + surface->width = width; + surface->height = height; + surface->row_bytes = width; + surface->pixel_bytes = 1; + +#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA) + png_set_bgr(png_ptr); +#endif + + unsigned char* p_row; + unsigned int y; + for (y = 0; y < height; ++y) { + p_row = surface->data + y * surface->row_bytes; + png_read_row(png_ptr, p_row, NULL); + } + + *pSurface = surface; + + exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) free(surface); + return result; +} + +static int matches_locale(const char* loc, const char* locale) { + if (locale == NULL) return 0; + + if (strcmp(loc, locale) == 0) return 1; + + // if loc does *not* have an underscore, and it matches the start + // of locale, and the next character in locale *is* an underscore, + // that's a match. For instance, loc == "en" matches locale == + // "en_US". + + int i; + for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i); + if (loc[i] == '_') return 0; + + return (strncmp(locale, loc, i) == 0 && locale[i] == '_'); +} + +int res_create_localized_alpha_surface(const char* name, + const char* locale, + gr_surface* pSurface) { + gr_surface surface = NULL; + int result = 0; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_uint_32 width, height; + png_byte channels; + unsigned char* row; + png_uint_32 y; + + *pSurface = NULL; + + if (locale == NULL) { + surface = malloc_surface(0); + surface->width = 0; + surface->height = 0; + surface->row_bytes = 0; + surface->pixel_bytes = 1; + goto exit; + } + + result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); + if (result < 0) return result; + + if (channels != 1) { + result = -7; + goto exit; + } + + row = reinterpret_cast(malloc(width)); + for (y = 0; y < height; ++y) { + png_read_row(png_ptr, row, NULL); + int w = (row[1] << 8) | row[0]; + int h = (row[3] << 8) | row[2]; + int len = row[4]; + char* loc = (char*)row+5; + + if (y+1+h >= height || matches_locale(loc, locale)) { + printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); + + surface = malloc_surface(w*h); + if (surface == NULL) { + result = -8; + goto exit; + } + surface->width = w; + surface->height = h; + surface->row_bytes = w; + surface->pixel_bytes = 1; + + int i; + for (i = 0; i < h; ++i, ++y) { + png_read_row(png_ptr, row, NULL); + memcpy(surface->data + i*w, row, w); + } + + *pSurface = (gr_surface) surface; + break; + } else { + int i; + for (i = 0; i < h; ++i, ++y) { + png_read_row(png_ptr, row, NULL); + } + } + } + +exit: + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + if (result < 0 && surface != NULL) free(surface); + return result; +} + +void res_free_surface(gr_surface surface) { + free(surface); +} -- cgit v1.2.3 From 8fd86d77f1a2f15c6fa95bc390bcbe646374873a Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 13 Apr 2015 14:36:02 -0700 Subject: Move the menu header out of the menu. This makes it easier for us to deal with arbitrary information at the top, and means that headers added by specific commands don't overwrite the default ones. Add the fingerprint back, but broken up so it fits even on sprout's display. Change-Id: Id71da79ab1aa455a611d72756a3100a97ceb4c1c --- minui/graphics.cpp | 2 +- minui/minui.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'minui') diff --git a/minui/graphics.cpp b/minui/graphics.cpp index d7d6e8d5a..f240f4bbd 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -103,7 +103,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) +void gr_text(int x, int y, const char *s, bool bold) { GRFont* font = gr_font; diff --git a/minui/minui.h b/minui/minui.h index eca3a5030..936f7eec8 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -48,7 +48,7 @@ void gr_fb_blank(bool blank); void gr_clear(); // clear entire surface to current color void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void gr_fill(int x1, int y1, int x2, int y2); -void gr_text(int x, int y, const char *s, int bold); +void gr_text(int x, int y, const char *s, bool bold); void gr_texticon(int x, int y, gr_surface icon); int gr_measure(const char *s); void gr_font_size(int *x, int *y); -- cgit v1.2.3 From 0a5cb0c7cd995ae0330a7d54a8d0db5d892a48a9 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 15 Apr 2015 10:58:56 -0700 Subject: Don't use typedefs that hide *s. gr_surface was causing confusion for no good reason. Change-Id: If7120187f9a00dd16297877fc49352185a4d4ea6 --- minui/graphics.cpp | 2 +- minui/graphics.h | 6 +++--- minui/graphics_adf.cpp | 8 ++++---- minui/graphics_fbdev.cpp | 8 ++++---- minui/minui.h | 21 +++++++++------------ minui/resources.cpp | 36 +++++++++++++++++------------------- 6 files changed, 38 insertions(+), 43 deletions(-) (limited to 'minui') diff --git a/minui/graphics.cpp b/minui/graphics.cpp index f240f4bbd..f09f1c6b0 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -326,7 +326,7 @@ static void gr_test() { gr_clear(); gr_color(255, 0, 0, 255); - gr_surface frame = images[x%frames]; + GRSurface* frame = images[x%frames]; gr_blit(frame, 0, 0, frame->width, frame->height, x, 0); gr_color(255, 0, 0, 128); diff --git a/minui/graphics.h b/minui/graphics.h index ed229a0c8..81a923383 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -21,13 +21,13 @@ // TODO: lose the function pointers. struct minui_backend { - // Initializes the backend and returns a gr_surface to draw into. - gr_surface (*init)(minui_backend*); + // Initializes the backend and returns a GRSurface* to draw into. + GRSurface* (*init)(minui_backend*); // Causes the current drawing surface (returned by the most recent // call to flip() or init()) to be displayed, and returns a new // drawing surface. - gr_surface (*flip)(minui_backend*); + GRSurface* (*flip)(minui_backend*); // Blank (or unblank) the screen. void (*blank)(minui_backend*, bool); diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp index ea7c0abe1..5d0867f58 100644 --- a/minui/graphics_adf.cpp +++ b/minui/graphics_adf.cpp @@ -47,7 +47,7 @@ struct adf_pdata { adf_surface_pdata surfaces[2]; }; -static gr_surface adf_flip(minui_backend *backend); +static GRSurface* adf_flip(minui_backend *backend); static void adf_blank(minui_backend *backend, bool blank); static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) { @@ -134,12 +134,12 @@ static int adf_device_init(adf_pdata *pdata, adf_device *dev) return err; } -static gr_surface adf_init(minui_backend *backend) +static GRSurface* adf_init(minui_backend *backend) { adf_pdata *pdata = (adf_pdata *)backend; adf_id_t *dev_ids = NULL; ssize_t n_dev_ids, i; - gr_surface ret; + GRSurface* ret; #if defined(RECOVERY_ABGR) pdata->format = DRM_FORMAT_ABGR8888; @@ -193,7 +193,7 @@ static gr_surface adf_init(minui_backend *backend) return ret; } -static gr_surface adf_flip(minui_backend *backend) +static GRSurface* adf_flip(minui_backend *backend) { adf_pdata *pdata = (adf_pdata *)backend; adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp index 9dbdde810..997e9cac2 100644 --- a/minui/graphics_fbdev.cpp +++ b/minui/graphics_fbdev.cpp @@ -33,8 +33,8 @@ #include "minui.h" #include "graphics.h" -static gr_surface fbdev_init(minui_backend*); -static gr_surface fbdev_flip(minui_backend*); +static GRSurface* fbdev_init(minui_backend*); +static GRSurface* fbdev_flip(minui_backend*); static void fbdev_blank(minui_backend*, bool); static void fbdev_exit(minui_backend*); @@ -79,7 +79,7 @@ static void set_displayed_framebuffer(unsigned n) displayed_buffer = n; } -static gr_surface fbdev_init(minui_backend* backend) { +static GRSurface* fbdev_init(minui_backend* backend) { int fd = open("/dev/graphics/fb0", O_RDWR); if (fd == -1) { perror("cannot open fb0"); @@ -174,7 +174,7 @@ static gr_surface fbdev_init(minui_backend* backend) { return gr_draw; } -static gr_surface fbdev_flip(minui_backend* backend __unused) { +static GRSurface* fbdev_flip(minui_backend* backend __unused) { if (double_buffered) { #if defined(RECOVERY_BGRA) // In case of BGRA, do some byte swapping diff --git a/minui/minui.h b/minui/minui.h index 936f7eec8..bdde083f3 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -33,9 +33,6 @@ struct GRSurface { unsigned char* data; }; -// TODO: remove this. -typedef GRSurface* gr_surface; - int gr_init(); void gr_exit(); @@ -49,13 +46,13 @@ void gr_clear(); // clear entire surface to current color void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a); void gr_fill(int x1, int y1, int x2, int y2); void gr_text(int x, int y, const char *s, bool bold); -void gr_texticon(int x, int y, gr_surface icon); +void gr_texticon(int x, int y, GRSurface* icon); int gr_measure(const char *s); void gr_font_size(int *x, int *y); -void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy); -unsigned int gr_get_width(gr_surface surface); -unsigned int gr_get_height(gr_surface surface); +void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy); +unsigned int gr_get_width(GRSurface* surface); +unsigned int gr_get_height(GRSurface* surface); // // Input events. @@ -98,17 +95,17 @@ int ev_get_epollfd(); // All these functions load PNG images from "/res/images/${name}.png". // Load a single display surface from a PNG image. -int res_create_display_surface(const char* name, gr_surface* pSurface); +int res_create_display_surface(const char* name, GRSurface** pSurface); // Load an array of display surfaces from a single PNG image. The PNG // should have a 'Frames' text chunk whose value is the number of // frames this image represents. The pixel data itself is interlaced // by row. int res_create_multi_display_surface(const char* name, - int* frames, gr_surface** pSurface); + int* frames, GRSurface*** pSurface); // Load a single alpha surface from a grayscale PNG image. -int res_create_alpha_surface(const char* name, gr_surface* pSurface); +int res_create_alpha_surface(const char* name, GRSurface** pSurface); // Load part of a grayscale PNG image that is the first match for the // given locale. The image is expected to be a composite of multiple @@ -117,10 +114,10 @@ int res_create_alpha_surface(const char* name, gr_surface* pSurface); // development/tools/recovery_l10n for an app that will generate these // specialized images from Android resources. int res_create_localized_alpha_surface(const char* name, const char* locale, - gr_surface* pSurface); + GRSurface** pSurface); // Free a surface allocated by any of the res_create_*_surface() // functions. -void res_free_surface(gr_surface surface); +void res_free_surface(GRSurface* surface); #endif diff --git a/minui/resources.cpp b/minui/resources.cpp index fa413b608..5e4789277 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -36,11 +36,11 @@ extern char* locale; #define SURFACE_DATA_ALIGNMENT 8 -static gr_surface malloc_surface(size_t data_size) { +static GRSurface* malloc_surface(size_t data_size) { size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT; unsigned char* temp = reinterpret_cast(malloc(size)); if (temp == NULL) return NULL; - gr_surface surface = (gr_surface) temp; + GRSurface* surface = reinterpret_cast(temp); surface->data = temp + sizeof(GRSurface) + (SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT)); return surface; @@ -138,12 +138,10 @@ static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr, // framebuffer pixel format; they need to be modified if the // framebuffer format changes (but nothing else should). -// Allocate and return a gr_surface sufficient for storing an image of +// Allocate and return a GRSurface* sufficient for storing an image of // the indicated size in the framebuffer pixel format. -static gr_surface init_display_surface(png_uint_32 width, png_uint_32 height) { - gr_surface surface; - - surface = malloc_surface(width * height * 4); +static GRSurface* init_display_surface(png_uint_32 width, png_uint_32 height) { + GRSurface* surface = malloc_surface(width * height * 4); if (surface == NULL) return NULL; surface->width = width; @@ -199,8 +197,8 @@ static void transform_rgb_to_draw(unsigned char* input_row, } } -int res_create_display_surface(const char* name, gr_surface* pSurface) { - gr_surface surface = NULL; +int res_create_display_surface(const char* name, GRSurface** pSurface) { + GRSurface* surface = NULL; int result = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; @@ -239,8 +237,8 @@ int res_create_display_surface(const char* name, gr_surface* pSurface) { return result; } -int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) { - gr_surface* surface = NULL; +int res_create_multi_display_surface(const char* name, int* frames, GRSurface*** pSurface) { + GRSurface** surface = NULL; int result = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; @@ -275,7 +273,7 @@ int res_create_multi_display_surface(const char* name, int* frames, gr_surface** goto exit; } - surface = reinterpret_cast(malloc(*frames * sizeof(gr_surface))); + surface = reinterpret_cast(malloc(*frames * sizeof(GRSurface*))); if (surface == NULL) { result = -8; goto exit; @@ -302,7 +300,7 @@ int res_create_multi_display_surface(const char* name, int* frames, gr_surface** } free(p_row); - *pSurface = (gr_surface*) surface; + *pSurface = reinterpret_cast(surface); exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); @@ -318,8 +316,8 @@ exit: return result; } -int res_create_alpha_surface(const char* name, gr_surface* pSurface) { - gr_surface surface = NULL; +int res_create_alpha_surface(const char* name, GRSurface** pSurface) { + GRSurface* surface = NULL; int result = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; @@ -384,8 +382,8 @@ static int matches_locale(const char* loc, const char* locale) { int res_create_localized_alpha_surface(const char* name, const char* locale, - gr_surface* pSurface) { - gr_surface surface = NULL; + GRSurface** pSurface) { + GRSurface* surface = NULL; int result = 0; png_structp png_ptr = NULL; png_infop info_ptr = NULL; @@ -440,7 +438,7 @@ int res_create_localized_alpha_surface(const char* name, memcpy(surface->data + i*w, row, w); } - *pSurface = (gr_surface) surface; + *pSurface = reinterpret_cast(surface); break; } else { int i; @@ -456,6 +454,6 @@ exit: return result; } -void res_free_surface(gr_surface surface) { +void res_free_surface(GRSurface* surface) { free(surface); } -- cgit v1.2.3 From 2f5feedf1d705b53e5bf90c8b5207dd91f4522f1 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 28 Apr 2015 17:24:24 -0700 Subject: Check all lseek calls succeed. Also add missing TEMP_FAILURE_RETRYs on read, write, and lseek. Bug: http://b/20625546 Change-Id: I03b198e11c1921b35518ee2dd005a7cfcf4fd94b (cherry picked from commit 7bad7c4646ee8fd8d6e6ed0ffd3ddbb0c1b41a2f) --- minui/events.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'minui') diff --git a/minui/events.cpp b/minui/events.cpp index 2d47a587f..3b2262a4b 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -165,7 +166,7 @@ void ev_dispatch(void) { int ev_get_input(int fd, uint32_t epevents, input_event* ev) { if (epevents & EPOLLIN) { - ssize_t r = read(fd, ev, sizeof(*ev)); + ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev))); if (r == sizeof(*ev)) { return 0; } -- cgit v1.2.3 From 1a92c4458dcc983f624a60fb75f9679c213e6814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Marchesin?= Date: Mon, 29 Jun 2015 20:05:48 -0700 Subject: Add drm support to minui MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: 22231636 Change-Id: I103c8e906b7dd9862b7bb89d8642268e9a3006b4 Signed-off-by: Stéphane Marchesin --- minui/Android.mk | 2 + minui/graphics.cpp | 5 + minui/graphics.h | 1 + minui/graphics_drm.cpp | 476 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 minui/graphics_drm.cpp (limited to 'minui') diff --git a/minui/Android.mk b/minui/Android.mk index 52f066256..97724fbf0 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -5,10 +5,12 @@ LOCAL_SRC_FILES := \ events.cpp \ graphics.cpp \ graphics_adf.cpp \ + graphics_drm.cpp \ graphics_fbdev.cpp \ resources.cpp \ LOCAL_WHOLE_STATIC_LIBRARIES += libadf +LOCAL_WHOLE_STATIC_LIBRARIES += libdrm LOCAL_STATIC_LIBRARIES += libpng LOCAL_MODULE := libminui diff --git a/minui/graphics.cpp b/minui/graphics.cpp index f09f1c6b0..c0eea9e38 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -368,6 +368,11 @@ int gr_init(void) } } + if (!gr_draw) { + gr_backend = open_drm(); + gr_draw = gr_backend->init(gr_backend); + } + if (!gr_draw) { gr_backend = open_fbdev(); gr_draw = gr_backend->init(gr_backend); diff --git a/minui/graphics.h b/minui/graphics.h index 81a923383..52968eb10 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -38,5 +38,6 @@ struct minui_backend { minui_backend* open_fbdev(); minui_backend* open_adf(); +minui_backend* open_drm(); #endif diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp new file mode 100644 index 000000000..03e33b775 --- /dev/null +++ b/minui/graphics_drm.cpp @@ -0,0 +1,476 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "minui.h" +#include "graphics.h" + +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) + +struct drm_surface { + GRSurface base; + uint32_t fb_id; + uint32_t handle; +}; + +static drm_surface *drm_surfaces[2]; +static int current_buffer; + +static drmModeCrtc *main_monitor_crtc; +static drmModeConnector *main_monitor_connector; + +static int drm_fd = -1; + +static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { + if (crtc) { + drmModeSetCrtc(drm_fd, crtc->crtc_id, + 0, // fb_id + 0, 0, // x,y + NULL, // connectors + 0, // connector_count + NULL); // mode + } +} + +static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc, + struct drm_surface *surface) { + int32_t ret; + + ret = drmModeSetCrtc(drm_fd, crtc->crtc_id, + surface->fb_id, + 0, 0, // x,y + &main_monitor_connector->connector_id, + 1, // connector_count + &main_monitor_crtc->mode); + + if (ret) + printf("drmModeSetCrtc failed ret=%d\n", ret); +} + +static void drm_blank(minui_backend* backend __unused, bool blank) { + if (blank) + drm_disable_crtc(drm_fd, main_monitor_crtc); + else + drm_enable_crtc(drm_fd, main_monitor_crtc, + drm_surfaces[current_buffer]); +} + +static void drm_destroy_surface(struct drm_surface *surface) { + struct drm_gem_close gem_close; + int ret; + + if(!surface) + return; + + if (surface->base.data) + munmap(surface->base.data, + surface->base.row_bytes * surface->base.height); + + if (surface->fb_id) { + ret = drmModeRmFB(drm_fd, surface->fb_id); + if (ret) + printf("drmModeRmFB failed ret=%d\n", ret); + } + + if (surface->handle) { + memset(&gem_close, 0, sizeof(gem_close)); + gem_close.handle = surface->handle; + + ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret) + printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret); + } + + free(surface); +} + +static int drm_format_to_bpp(uint32_t format) { + switch(format) { + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + return 32; + case DRM_FORMAT_RGB565: + return 16; + default: + printf("Unknown format %d\n", format); + return 32; + } +} + +static drm_surface *drm_create_surface(int width, int height) { + struct drm_surface *surface; + struct drm_mode_create_dumb create_dumb; + uint32_t format; + int ret; + + surface = (struct drm_surface*)calloc(1, sizeof(*surface)); + if (!surface) { + printf("Can't allocate memory\n"); + return NULL; + } + +#if defined(RECOVERY_ABGR) + format = DRM_FORMAT_RGBA8888; +#elif defined(RECOVERY_BGRA) + format = DRM_FORMAT_ARGB8888; +#elif defined(RECOVERY_RGBX) + format = DRM_FORMAT_XBGR8888; +#else + format = DRM_FORMAT_RGB565; +#endif + + memset(&create_dumb, 0, sizeof(create_dumb)); + create_dumb.height = height; + create_dumb.width = width; + create_dumb.bpp = drm_format_to_bpp(format); + create_dumb.flags = 0; + + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret) { + printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL; + } + surface->handle = create_dumb.handle; + + uint32_t handles[4], pitches[4], offsets[4]; + + handles[0] = surface->handle; + pitches[0] = create_dumb.pitch; + offsets[0] = 0; + + ret = drmModeAddFB2(drm_fd, width, height, + format, handles, pitches, offsets, + &(surface->fb_id), 0); + if (ret) { + printf("drmModeAddFB2 failed ret=%d\n", ret); + drm_destroy_surface(surface); + return NULL; + } + + struct drm_mode_map_dumb map_dumb; + memset(&map_dumb, 0, sizeof(map_dumb)); + map_dumb.handle = create_dumb.handle; + ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb); + if (ret) { + printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n",ret); + drm_destroy_surface(surface); + return NULL;; + } + + surface->base.height = height; + surface->base.width = width; + surface->base.row_bytes = create_dumb.pitch; + surface->base.pixel_bytes = create_dumb.bpp / 8; + surface->base.data = (unsigned char*) + mmap(NULL, + surface->base.height * surface->base.row_bytes, + PROT_READ | PROT_WRITE, MAP_SHARED, + drm_fd, map_dumb.offset); + if (surface->base.data == MAP_FAILED) { + perror("mmap() failed"); + drm_destroy_surface(surface); + return NULL; + } + + return surface; +} + +static drmModeCrtc *find_crtc_for_connector(int fd, + drmModeRes *resources, + drmModeConnector *connector) { + int i, j; + drmModeEncoder *encoder; + int32_t crtc; + + /* + * Find the encoder. If we already have one, just use it. + */ + if (connector->encoder_id) + encoder = drmModeGetEncoder(fd, connector->encoder_id); + else + encoder = NULL; + + if (encoder && encoder->crtc_id) { + crtc = encoder->crtc_id; + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + + /* + * Didn't find anything, try to find a crtc and encoder combo. + */ + crtc = -1; + for (i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + + if (encoder) { + for (j = 0; j < resources->count_crtcs; j++) { + if (!(encoder->possible_crtcs & (1 << j))) + continue; + crtc = resources->crtcs[j]; + break; + } + if (crtc >= 0) { + drmModeFreeEncoder(encoder); + return drmModeGetCrtc(fd, crtc); + } + } + } + + return NULL; +} + +static drmModeConnector *find_used_connector_by_type(int fd, + drmModeRes *resources, + unsigned type) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->connector_type == type) && + (connector->connection == DRM_MODE_CONNECTED) && + (connector->count_modes > 0)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_first_connected_connector(int fd, + drmModeRes *resources) { + int i; + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->count_modes > 0) && + (connector->connection == DRM_MODE_CONNECTED)) + return connector; + + drmModeFreeConnector(connector); + } + } + return NULL; +} + +static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources, + uint32_t *mode_index) { + unsigned i = 0; + int modes; + /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */ + unsigned kConnectorPriority[] = { + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_DSI, + }; + + drmModeConnector *main_monitor_connector = NULL; + do { + main_monitor_connector = find_used_connector_by_type(fd, + resources, + kConnectorPriority[i]); + i++; + } while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority)); + + /* If we didn't find a connector, grab the first one that is connected. */ + if (!main_monitor_connector) + main_monitor_connector = + find_first_connected_connector(fd, resources); + + /* If we still didn't find a connector, give up and return. */ + if (!main_monitor_connector) + return NULL; + + *mode_index = 0; + for (modes = 0; modes < main_monitor_connector->count_modes; modes++) { + if (main_monitor_connector->modes[modes].type & + DRM_MODE_TYPE_PREFERRED) { + *mode_index = modes; + break; + } + } + + return main_monitor_connector; +} + +static void disable_non_main_crtcs(int fd, + drmModeRes *resources, + drmModeCrtc* main_crtc) { + int i; + drmModeCrtc* crtc; + + for (i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + crtc = find_crtc_for_connector(fd, resources, connector); + if (crtc->crtc_id != main_crtc->crtc_id) + drm_disable_crtc(fd, crtc); + drmModeFreeCrtc(crtc); + } +} + +static GRSurface* drm_init(minui_backend* backend __unused) { + drmModeRes *res = NULL; + uint32_t selected_mode; + char *dev_name; + int width, height; + int ret, i; + + /* Consider DRM devices in order. */ + for (i = 0; i < DRM_MAX_MINOR; i++) { + uint64_t cap = 0; + + ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i); + if (ret < 0) + continue; + + drm_fd = open(dev_name, O_RDWR, 0); + free(dev_name); + if (drm_fd < 0) + continue; + + /* We need dumb buffers. */ + ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + close(drm_fd); + continue; + } + + res = drmModeGetResources(drm_fd); + if (!res) { + close(drm_fd); + continue; + } + + /* Use this device if it has at least one connected monitor. */ + if (res->count_crtcs > 0 && res->count_connectors > 0) + if (find_first_connected_connector(drm_fd, res)) + break; + + drmModeFreeResources(res); + close(drm_fd); + res = NULL; + } + + if (drm_fd < 0 || res == NULL) { + perror("cannot find/open a drm device"); + return NULL; + } + + main_monitor_connector = find_main_monitor(drm_fd, + res, &selected_mode); + + if (!main_monitor_connector) { + printf("main_monitor_connector not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + main_monitor_crtc = find_crtc_for_connector(drm_fd, res, + main_monitor_connector); + + if (!main_monitor_crtc) { + printf("main_monitor_crtc not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + disable_non_main_crtcs(drm_fd, + res, main_monitor_crtc); + + main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; + + width = main_monitor_crtc->mode.hdisplay; + height = main_monitor_crtc->mode.vdisplay; + + drmModeFreeResources(res); + + drm_surfaces[0] = drm_create_surface(width, height); + drm_surfaces[1] = drm_create_surface(width, height); + if (!drm_surfaces[0] || !drm_surfaces[1]) { + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeResources(res); + close(drm_fd); + return NULL; + } + + current_buffer = 0; + + drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); + + return &(drm_surfaces[0]->base); +} + +static GRSurface* drm_flip(minui_backend* backend __unused) { + int ret; + + ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, + drm_surfaces[current_buffer]->fb_id, 0, NULL); + if (ret < 0) { + printf("drmModePageFlip failed ret=%d\n", ret); + return NULL; + } + current_buffer = 1 - current_buffer; + return &(drm_surfaces[current_buffer]->base); +} + +static void drm_exit(minui_backend* backend __unused) { + drm_disable_crtc(drm_fd, main_monitor_crtc); + drm_destroy_surface(drm_surfaces[0]); + drm_destroy_surface(drm_surfaces[1]); + drmModeFreeCrtc(main_monitor_crtc); + drmModeFreeConnector(main_monitor_connector); + close(drm_fd); + drm_fd = -1; +} + +static minui_backend drm_backend = { + .init = drm_init, + .flip = drm_flip, + .blank = drm_blank, + .exit = drm_exit, +}; + +minui_backend* open_drm() { + return &drm_backend; +} -- cgit v1.2.3