diff options
Diffstat (limited to 'minui')
-rw-r--r-- | minui/Android.mk | 51 | ||||
-rw-r--r-- | minui/events.cpp | 245 | ||||
-rw-r--r-- | minui/graphics.cpp | 168 | ||||
-rw-r--r-- | minui/graphics.h | 32 | ||||
-rw-r--r-- | minui/graphics_adf.cpp | 318 | ||||
-rw-r--r-- | minui/graphics_adf.h | 58 | ||||
-rw-r--r-- | minui/graphics_drm.cpp | 674 | ||||
-rw-r--r-- | minui/graphics_drm.h | 58 | ||||
-rw-r--r-- | minui/graphics_fbdev.cpp | 259 | ||||
-rw-r--r-- | minui/graphics_fbdev.h | 44 | ||||
-rw-r--r-- | minui/graphics_overlay.cpp | 148 | ||||
-rw-r--r-- | minui/graphics_overlay.h | 74 | ||||
-rw-r--r-- | minui/include/minui/minui.h | 246 | ||||
-rw-r--r-- | minui/main.cpp | 2 | ||||
-rw-r--r-- | minui/minui.h | 21 | ||||
-rw-r--r-- | minui/resources.cpp | 84 |
16 files changed, 1397 insertions, 1085 deletions
diff --git a/minui/Android.mk b/minui/Android.mk index 249feeb0e..e359887e5 100644 --- a/minui/Android.mk +++ b/minui/Android.mk @@ -1,3 +1,17 @@ +# 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. + LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -6,6 +20,7 @@ LOCAL_SRC_FILES := \ graphics.cpp \ graphics_drm.cpp \ graphics_fbdev.cpp \ + graphics_overlay.cpp \ resources.cpp LOCAL_C_INCLUDES := external/libcxx/include external/libpng @@ -35,8 +50,21 @@ ifeq ($(TW_NEW_ION_HEAP), true) LOCAL_CFLAGS += -DNEW_ION_HEAP endif -LOCAL_WHOLE_STATIC_LIBRARIES += libdrm LOCAL_STATIC_LIBRARIES += libpng +LOCAL_WHOLE_STATIC_LIBRARIES += \ + libdrm +ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 26; echo $$?),0) + LOCAL_CFLAGS += -DHAS_LIBSYNC + LOCAL_WHOLE_STATIC_LIBRARIES += libsync_recovery +endif + +LOCAL_STATIC_LIBRARIES := \ + libpng \ + libbase + +LOCAL_CFLAGS := -Werror -std=c++14 +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_MODULE := libminui @@ -90,7 +118,14 @@ include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_MODULE := libminui LOCAL_WHOLE_STATIC_LIBRARIES += libminui -LOCAL_SHARED_LIBRARIES := libpng +LOCAL_SHARED_LIBRARIES := \ + libpng \ + libbase + +LOCAL_CFLAGS := -Werror + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) @@ -98,7 +133,15 @@ LOCAL_MODULE := minuitest LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_SRC_FILES := main.cpp -LOCAL_STATIC_LIBRARIES := libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc +LOCAL_SHARED_LIBRARIES := libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc LOCAL_C_INCLUDES := external/libcxx/include external/libpng -LOCAL_FORCE_STATIC_EXECUTABLE := true +ifneq ($(TARGET_ARCH), arm64) + ifneq ($(TARGET_ARCH), x86_64) + LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker + else + LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64 + endif +else + LOCAL_LDFLAGS += -Wl,-dynamic-linker,/sbin/linker64 +endif include $(BUILD_EXECUTABLE) diff --git a/minui/events.cpp b/minui/events.cpp index 3b2262a4b..470a17a69 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -15,17 +15,19 @@ */ #include <dirent.h> -#include <errno.h> #include <fcntl.h> +#include <linux/input.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/epoll.h> +#include <sys/ioctl.h> #include <unistd.h> +#include <errno.h> -#include <linux/input.h> +#include <functional> -#include "minui.h" +#include "minui/minui.h" #define MAX_DEVICES 16 #define MAX_MISC_FDS 16 @@ -34,9 +36,11 @@ #define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG) struct fd_info { - int fd; - ev_callback cb; - void* data; + int fd; + ev_callback cb; +#ifdef TW_USE_MINUI_WITH_DATA + void* data; +#endif }; static int g_epoll_fd; @@ -49,92 +53,105 @@ 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) { +static bool test_bit(size_t bit, unsigned long* array) { // NOLINT return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0; } +#ifdef TW_USE_MINUI_WITH_DATA int ev_init(ev_callback input_cb, void* data) { - bool epollctlfail = false; +#else +int ev_init(ev_callback input_cb) { +#endif + bool epollctlfail = false; - g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS); - if (g_epoll_fd == -1) { - return -1; + 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) { + dirent* de; + while ((de = readdir(dir))) { + // Use unsigned long to match ioctl's parameter type. + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT + + // 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; + } + + 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 = std::move(input_cb); +#ifdef TW_USE_MINUI_WITH_DATA + ev_fdinfo[ev_count].data = data; +#endif + ev_count++; + ev_dev_count++; + if (ev_dev_count == MAX_DEVICES) break; } - DIR* dir = opendir("/dev/input"); - if (dir != NULL) { - 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; - } + closedir(dir); + } - 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; - } + if (epollctlfail && !ev_count) { + close(g_epoll_fd); + g_epoll_fd = -1; + return -1; + } - return 0; + return 0; } int ev_get_epollfd(void) { return g_epoll_fd; } +#ifdef TW_USE_MINUI_WITH_DATA int ev_add_fd(int fd, ev_callback cb, void* data) { - if (ev_misc_count == MAX_MISC_FDS || cb == NULL) { - return -1; - } - - 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; +#else +int ev_add_fd(int fd, ev_callback cb) { +#endif + if (ev_misc_count == MAX_MISC_FDS || cb == NULL) { + return -1; + } + + epoll_event ev; + ev.events = EPOLLIN | EPOLLWAKEUP; + ev.data.ptr = static_cast<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 = std::move(cb); +#ifdef TW_USE_MINUI_WITH_DATA + ev_fdinfo[ev_count].data = data; +#endif + ev_count++; + ev_misc_count++; + } + + return ret; } void ev_exit(void) { @@ -155,13 +172,17 @@ int ev_wait(int timeout) { } void ev_dispatch(void) { - for (int n = 0; n < npolledevents; n++) { - fd_info* fdi = reinterpret_cast<fd_info*>(polledevents[n].data.ptr); - ev_callback cb = fdi->cb; - if (cb) { - cb(fdi->fd, polledevents[n].events, fdi->data); - } + for (int n = 0; n < npolledevents; n++) { + fd_info* fdi = static_cast<fd_info*>(polledevents[n].data.ptr); + const ev_callback& cb = fdi->cb; + if (cb) { +#ifdef TW_USE_MINUI_WITH_DATA + cb(fdi->fd, polledevents[n].events, fdi->data); +#else + cb(fdi->fd, polledevents[n].events); +#endif } + } } int ev_get_input(int fd, uint32_t epevents, input_event* ev) { @@ -174,37 +195,47 @@ int ev_get_input(int fd, uint32_t epevents, input_event* ev) { return -1; } +#ifdef TW_USE_MINUI_WITH_DATA 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; - } +#else +int ev_sync_key_state(const ev_set_key_callback& set_key_cb) { +#endif + // Use unsigned long to match ioctl's parameter type. + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT + unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT + + 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); - } - } + for (int code = 0; code <= KEY_MAX; code++) { + if (test_bit(code, key_bits)) { +#ifdef TW_USE_MINUI_WITH_DATA + set_key_cb(code, 1, data); +#else + set_key_cb(code, 1); +#endif + } } + } - return 0; + return 0; } -void ev_iterate_available_keys(std::function<void(int)> f) { - unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; - unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; +void ev_iterate_available_keys(const std::function<void(int)>& f) { + // Use unsigned long to match ioctl's parameter type. + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT + unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT for (size_t i = 0; i < ev_dev_count; ++i) { memset(ev_bits, 0, sizeof(ev_bits)); diff --git a/minui/graphics.cpp b/minui/graphics.cpp index 95251764d..bb96af141 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -14,22 +14,13 @@ * limitations under the License. */ -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include "graphics.h" -#include <fcntl.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <sys/types.h> - -#include <linux/fb.h> -#include <linux/kd.h> - -#include <time.h> +#include <memory> #ifdef BOARD_USE_CUSTOM_RECOVERY_FONT #include BOARD_USE_CUSTOM_RECOVERY_FONT @@ -37,11 +28,14 @@ #include "font_10x18.h" #endif -#include "minui.h" -#include "graphics.h" +#include "graphics_adf.h" +#include "graphics_drm.h" +#include "graphics_fbdev.h" +#include "graphics_overlay.h" +#include "minui/minui.h" static GRFont* gr_font = NULL; -static minui_backend* gr_backend = NULL; +static MinuiBackend* gr_backend = nullptr; static int overscan_percent = OVERSCAN_PERCENT; static int overscan_offset_x = 0; @@ -470,7 +464,7 @@ void gr_set_font(__attribute__ ((unused))const char* name) { } #else // TW_NO_MINUI_CUSTOM_FONTS int gr_init_font(const char* name, GRFont** dest) { - GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font))); + GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); if (font == nullptr) { return -1; } @@ -503,15 +497,15 @@ static void gr_init_font(void) // fall back to the compiled-in font. - gr_font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font))); - gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture))); + gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); + gr_font->texture = static_cast<GRSurface*>(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<unsigned char*>(malloc(font.width * font.height)); - gr_font->texture->data = reinterpret_cast<unsigned char*>(bits); + unsigned char* bits = static_cast<unsigned char*>(malloc(font.width * font.height)); + gr_font->texture->data = bits; unsigned char data; unsigned char* in = font.rundata; @@ -525,131 +519,75 @@ static void gr_init_font(void) } #endif // TW_NO_MINUI_CUSTOM_FONTS -#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); - GRSurface* 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); + gr_draw = gr_backend->Flip(); } int gr_init(void) { - gr_init_font(); - gr_draw = NULL; + gr_init_font(); + + auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendOverlay>() }; + gr_draw = backend->Init(); #ifdef MSM_BSP - gr_backend = open_overlay(); - if (gr_backend) { - gr_draw = gr_backend->init(gr_backend); - if (!gr_draw) { - gr_backend->exit(gr_backend); - } else - printf("Using overlay graphics.\n"); + if (gr_draw) { + printf("Using overlay graphics.\n"); } #endif #ifndef MSM_BSP - if (!gr_backend || !gr_draw) { - gr_backend = open_adf(); - if (gr_backend) { - gr_draw = gr_backend->init(gr_backend); - if (!gr_draw) { - gr_backend->exit(gr_backend); - } else - printf("Using adf graphics.\n"); - } + if (!gr_draw) { + backend = std::make_unique<MinuiBackendAdf>(); + gr_draw = backend->Init(); + if (gr_draw) + printf("Using adf graphics.\n"); } #else printf("Skipping adf graphics because TW_TARGET_USES_QCOM_BSP := true\n"); #endif - if (!gr_backend || !gr_draw) { - gr_backend = open_drm(); - gr_draw = gr_backend->init(gr_backend); + if (!gr_draw) { + backend = std::make_unique<MinuiBackendDrm>(); + gr_draw = backend->Init(); if (gr_draw) printf("Using drm graphics.\n"); } - if (!gr_backend || !gr_draw) { - gr_backend = open_fbdev(); - gr_draw = gr_backend->init(gr_backend); - if (gr_draw == NULL) { - return -1; - } else + if (!gr_draw) { + backend = std::make_unique<MinuiBackendFbdev>(); + gr_draw = backend->Init(); + if (gr_draw) printf("Using fbdev graphics.\n"); } - overscan_offset_x = gr_draw->width * overscan_percent / 100; - overscan_offset_y = gr_draw->height * overscan_percent / 100; + if (!gr_draw) { + return -1; + } - gr_flip(); - gr_flip(); + gr_backend = backend.release(); - return 0; + 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); +void gr_exit() { + delete gr_backend; } -int gr_fb_width(void) -{ - return gr_draw->width - 2*overscan_offset_x; +int gr_fb_width() { + return gr_draw->width - 2 * overscan_offset_x; } -int gr_fb_height(void) -{ - return gr_draw->height - 2*overscan_offset_y; +int gr_fb_height() { + return gr_draw->height - 2 * overscan_offset_y; } -void gr_fb_blank(bool blank) -{ - gr_backend->blank(gr_backend, blank); +void gr_fb_blank(bool blank) { + gr_backend->Blank(blank); } diff --git a/minui/graphics.h b/minui/graphics.h index a4115fd50..3c45a406b 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -17,28 +17,22 @@ #ifndef _GRAPHICS_H_ #define _GRAPHICS_H_ -#include "minui.h" +#include "minui/minui.h" -// TODO: lose the function pointers. -struct minui_backend { - // Initializes the backend and returns a GRSurface* to draw into. - GRSurface* (*init)(minui_backend*); +class MinuiBackend { + public: + // Initializes the backend and returns a GRSurface* to draw into. + virtual GRSurface* Init() = 0; - // Causes the current drawing surface (returned by the most recent - // call to flip() or init()) to be displayed, and returns a new - // drawing surface. - GRSurface* (*flip)(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. + virtual GRSurface* Flip() = 0; - // Blank (or unblank) the screen. - void (*blank)(minui_backend*, bool); + // Blank (or unblank) the screen. + virtual void Blank(bool) = 0; - // Device cleanup when drawing is done. - void (*exit)(minui_backend*); + // Device cleanup when drawing is done. + virtual ~MinuiBackend() {}; }; -minui_backend* open_fbdev(); -minui_backend* open_adf(); -minui_backend* open_drm(); -minui_backend* open_overlay(); - -#endif +#endif // _GRAPHICS_H_ diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp index 10e1c4b23..79f4db8b5 100644 --- a/minui/graphics_adf.cpp +++ b/minui/graphics_adf.cpp @@ -14,238 +14,190 @@ * limitations under the License. */ +#include "graphics_adf.h" + #include <errno.h> #include <fcntl.h> -#include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <sys/cdefs.h> #include <sys/mman.h> +#include <unistd.h> #include <adf/adf.h> +#ifdef HAS_LIBSYNC +#include <sync/sync.h> +#endif -#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 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) { - 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<uint8_t*>(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; - } +#include "minui/minui.h" - return 0; -} +MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), n_surfaces(0), surfaces() {} -static int adf_interface_init(adf_pdata *pdata) -{ - adf_interface_data intf_data; - int ret = 0; - int err; +int MinuiBackendAdf::SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf) { + *surf = {}; + surf->fence_fd = -1; + surf->fd = adf_interface_simple_buffer_alloc(intf_fd, mode->hdisplay, mode->vdisplay, format, + &surf->offset, &surf->pitch); + if (surf->fd < 0) { + return surf->fd; + } - err = adf_get_interface_data(pdata->intf_fd, &intf_data); - if (err < 0) - return err; + surf->width = mode->hdisplay; + surf->height = mode->vdisplay; + surf->row_bytes = surf->pitch; + surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4; - 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; - } + surf->data = static_cast<uint8_t*>( + mmap(nullptr, surf->pitch * surf->height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset)); + if (surf->data == MAP_FAILED) { + int saved_errno = errno; + close(surf->fd); + return -saved_errno; + } - 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; - } + return 0; +} + +int MinuiBackendAdf::InterfaceInit() { + adf_interface_data intf_data; + int err = adf_get_interface_data(intf_fd, &intf_data); + if (err < 0) return err; + + int ret = 0; + err = SurfaceInit(&intf_data.current_mode, &surfaces[0]); + if (err < 0) { + fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err)); + ret = err; + goto done; + } + + err = SurfaceInit(&intf_data.current_mode, &surfaces[1]); + if (err < 0) { + fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); + surfaces[1] = {}; + n_surfaces = 1; + } else { + n_surfaces = 2; + } done: - adf_free_interface_data(&intf_data); - return ret; + 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; +int MinuiBackendAdf::DeviceInit(adf_device* dev) { + adf_id_t intf_id; + int err = adf_find_simple_post_configuration(dev, &format, 1, &intf_id, &eng_id); + if (err < 0) return err; - err = adf_device_attach(dev, pdata->eng_id, intf_id); - if (err < 0 && err != -EALREADY) - return err; + err = adf_device_attach(dev, 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; + intf_fd = adf_interface_open(dev, intf_id, O_RDWR); + if (intf_fd < 0) return intf_fd; - err = adf_interface_init(pdata); - if (err < 0) { - close(pdata->intf_fd); - pdata->intf_fd = -1; - } + err = InterfaceInit(); + if (err < 0) { + close(intf_fd); + intf_fd = -1; + } - return err; + return err; } -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; - GRSurface* ret; - +GRSurface* MinuiBackendAdf::Init() { #if defined(RECOVERY_ABGR) - pdata->format = DRM_FORMAT_ABGR8888; + format = DRM_FORMAT_ABGR8888; #elif defined(RECOVERY_BGRA) - pdata->format = DRM_FORMAT_BGRA8888; + format = DRM_FORMAT_BGRA8888; #elif defined(RECOVERY_RGBA) - pdata->format = DRM_FORMAT_RGBA8888; + format = DRM_FORMAT_RGBA8888; #elif defined(RECOVERY_RGBX) - pdata->format = DRM_FORMAT_RGBX8888; + format = DRM_FORMAT_RGBX8888; #else - pdata->format = DRM_FORMAT_RGB565; + 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; + adf_id_t* dev_ids = nullptr; + ssize_t n_dev_ids = adf_devices(&dev_ids); + if (n_dev_ids == 0) { + return nullptr; + } else if (n_dev_ids < 0) { + fprintf(stderr, "enumerating adf devices failed: %s\n", strerror(-n_dev_ids)); + return nullptr; + } - for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { - adf_device dev; + intf_fd = -1; - 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)); + for (ssize_t i = 0; i < n_dev_ids && intf_fd < 0; i++) { + 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; + } - adf_device_close(&dev); + err = DeviceInit(&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); + free(dev_ids); - if (pdata->intf_fd < 0) - return NULL; + if (intf_fd < 0) return nullptr; - ret = adf_flip(backend); + GRSurface* ret = Flip(); - adf_blank(backend, true); - adf_blank(backend, false); + Blank(true); + Blank(false); - return ret; + return ret; } -static GRSurface* adf_flip(minui_backend *backend) -{ - adf_pdata *pdata = (adf_pdata *)backend; - adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface]; +void MinuiBackendAdf::Sync(__unused GRSurfaceAdf* surf) { +#ifdef HAS_LIBSYNC + static constexpr unsigned int warningTimeout = 3000; - 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); + if (surf == nullptr) return; - pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; - return &pdata->surfaces[pdata->current_surface].base; -} + if (surf->fence_fd >= 0) { + int err = sync_wait(surf->fence_fd, warningTimeout); + if (err < 0) { + perror("adf sync fence wait error\n"); + } -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); + close(surf->fence_fd); + surf->fence_fd = -1; + } +#endif } -static void adf_surface_destroy(adf_surface_pdata *surf) -{ - munmap(surf->base.data, surf->pitch * surf->base.height); - close(surf->fd); -} +GRSurface* MinuiBackendAdf::Flip() { + GRSurfaceAdf* surf = &surfaces[current_surface]; -static void adf_exit(minui_backend *backend) -{ - adf_pdata *pdata = (adf_pdata *)backend; - unsigned int i; + int fence_fd = adf_interface_simple_post(intf_fd, eng_id, surf->width, surf->height, format, + surf->fd, surf->offset, surf->pitch, -1); + if (fence_fd >= 0) surf->fence_fd = fence_fd; - 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); + current_surface = (current_surface + 1) % n_surfaces; + Sync(&surfaces[current_surface]); + return &surfaces[current_surface]; } -minui_backend *open_adf() -{ - adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata))); - if (!pdata) { - perror("allocating adf backend failed"); - return NULL; - } +void MinuiBackendAdf::Blank(bool blank) { + adf_interface_blank(intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); +} + +void MinuiBackendAdf::SurfaceDestroy(GRSurfaceAdf* surf) { + munmap(surf->data, surf->pitch * surf->height); + close(surf->fence_fd); + close(surf->fd); +} - pdata->base.init = adf_init; - pdata->base.flip = adf_flip; - pdata->base.blank = adf_blank; - pdata->base.exit = adf_exit; - return &pdata->base; +MinuiBackendAdf::~MinuiBackendAdf() { + adf_device_close(&dev); + for (unsigned int i = 0; i < n_surfaces; i++) { + SurfaceDestroy(&surfaces[i]); + } + if (intf_fd >= 0) close(intf_fd); } diff --git a/minui/graphics_adf.h b/minui/graphics_adf.h new file mode 100644 index 000000000..2f019ed0b --- /dev/null +++ b/minui/graphics_adf.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef _GRAPHICS_ADF_H_ +#define _GRAPHICS_ADF_H_ + +#include <adf/adf.h> + +#include "graphics.h" + +class GRSurfaceAdf : public GRSurface { + private: + int fence_fd; + int fd; + __u32 offset; + __u32 pitch; + + friend class MinuiBackendAdf; +}; + +class MinuiBackendAdf : public MinuiBackend { + public: + GRSurface* Init() override; + GRSurface* Flip() override; + void Blank(bool) override; + ~MinuiBackendAdf() override; + MinuiBackendAdf(); + + private: + int SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf); + int InterfaceInit(); + int DeviceInit(adf_device* dev); + void SurfaceDestroy(GRSurfaceAdf* surf); + void Sync(GRSurfaceAdf* surf); + + int intf_fd; + adf_id_t eng_id; + __u32 format; + adf_device dev; + unsigned int current_surface; + unsigned int n_surfaces; + GRSurfaceAdf surfaces[2]; +}; + +#endif // _GRAPHICS_ADF_H_ diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp index ddda18721..ef377b77d 100644 --- a/minui/graphics_drm.cpp +++ b/minui/graphics_drm.cpp @@ -14,466 +14,384 @@ * limitations under the License. */ -#include <drm_fourcc.h> +#include "graphics_drm.h" + #include <fcntl.h> -#include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <sys/cdefs.h> -#include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> #include <unistd.h> + +#include <drm_fourcc.h> #include <xf86drm.h> #include <xf86drmMode.h> -#include "minui.h" -#include "graphics.h" +#include "minui/minui.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 - } +MinuiBackendDrm::MinuiBackendDrm() + : GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {} + +void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) { + if (crtc) { + drmModeSetCrtc(drm_fd, crtc->crtc_id, + 0, // fb_id + 0, 0, // x,y + nullptr, // connectors + 0, // connector_count + nullptr); // mode + } } -static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc, - struct drm_surface *surface) { - int32_t ret; +void MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface) { + int32_t 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); - 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); + 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]); +void MinuiBackendDrm::Blank(bool blank) { + if (blank) { + DrmDisableCrtc(drm_fd, main_monitor_crtc); + } else { + DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]); + } } -static void drm_destroy_surface(struct drm_surface *surface) { - struct drm_gem_close gem_close; - int ret; - - if(!surface) - return; +void MinuiBackendDrm::DrmDestroySurface(GRSurfaceDrm* surface) { + if (!surface) return; - if (surface->base.data) - munmap(surface->base.data, - surface->base.row_bytes * surface->base.height); + if (surface->data) { + munmap(surface->data, surface->row_bytes * surface->height); + } - if (surface->fb_id) { - ret = drmModeRmFB(drm_fd, surface->fb_id); - if (ret) - printf("drmModeRmFB failed ret=%d\n", ret); + if (surface->fb_id) { + int 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; + if (surface->handle) { + drm_gem_close 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); + int ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + if (ret) { + printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret); } + } - free(surface); + delete 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_ARGB8888: - case DRM_FORMAT_XRGB8888: - return 32; - case DRM_FORMAT_RGB565: - return 16; - default: - printf("Unknown format %d\n", format); - return 32; - } + 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; - } +GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) { + GRSurfaceDrm* surface = new GRSurfaceDrm; + *surface = {}; + uint32_t format; #if defined(RECOVERY_ABGR) - format = DRM_FORMAT_RGBA8888; + format = DRM_FORMAT_RGBA8888; #elif defined(RECOVERY_BGRA) - format = DRM_FORMAT_ARGB8888; + format = DRM_FORMAT_ARGB8888; #elif defined(RECOVERY_RGBA) - format = DRM_FORMAT_ABGR8888; + format = DRM_FORMAT_ARGB8888; #elif defined(RECOVERY_RGBX) - format = DRM_FORMAT_XBGR8888; + format = DRM_FORMAT_XBGR8888; #else - format = DRM_FORMAT_RGB565; + 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; + drm_mode_create_dumb create_dumb = {}; + create_dumb.height = height; + create_dumb.width = width; + create_dumb.bpp = drm_format_to_bpp(format); + create_dumb.flags = 0; + + int ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb); + if (ret) { + printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n", ret); + DrmDestroySurface(surface); + return nullptr; + } + 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); + DrmDestroySurface(surface); + return nullptr; + } + + drm_mode_map_dumb 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); + DrmDestroySurface(surface); + return nullptr; + } + + surface->height = height; + surface->width = width; + surface->row_bytes = create_dumb.pitch; + surface->pixel_bytes = create_dumb.bpp / 8; + surface->data = static_cast<unsigned char*>(mmap(nullptr, surface->height * surface->row_bytes, + PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, + map_dumb.offset)); + if (surface->data == MAP_FAILED) { + perror("mmap() failed"); + DrmDestroySurface(surface); + return nullptr; + } + + 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; +static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources, + drmModeConnector* connector) { + // Find the encoder. If we already have one, just use it. + drmModeEncoder* encoder; + if (connector->encoder_id) { + encoder = drmModeGetEncoder(fd, connector->encoder_id); + } else { + encoder = nullptr; + } + + int32_t crtc; + 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 (int i = 0; i < connector->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + + if (encoder) { + for (int 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); + } } + } - /* - * 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; + return nullptr; } -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); - } +static drmModeConnector* find_used_connector_by_type(int fd, drmModeRes* resources, unsigned type) { + for (int i = 0; i < resources->count_connectors; i++) { + drmModeConnector* 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; + } + return nullptr; } -static drmModeConnector *find_first_connected_connector(int fd, - drmModeRes *resources) { - int i; - for (i = 0; i < resources->count_connectors; i++) { - drmModeConnector *connector; +static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* resources) { + for (int 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; + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (connector) { + if ((connector->count_modes > 0) && (connector->connection == DRM_MODE_CONNECTED)) + return connector; - drmModeFreeConnector(connector); - } + drmModeFreeConnector(connector); } - return NULL; + } + return nullptr; } -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; - } +drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources, + uint32_t* mode_index) { + /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */ + static constexpr unsigned kConnectorPriority[] = { + DRM_MODE_CONNECTOR_LVDS, + DRM_MODE_CONNECTOR_eDP, + DRM_MODE_CONNECTOR_DSI, + }; + + drmModeConnector* main_monitor_connector = nullptr; + unsigned i = 0; + 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 nullptr; + + *mode_index = 0; + for (int 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; + 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); +void MinuiBackendDrm::DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc) { + for (int i = 0; i < resources->count_connectors; i++) { + drmModeConnector* connector = drmModeGetConnector(fd, resources->connectors[i]); + drmModeCrtc* crtc = find_crtc_for_connector(fd, resources, connector); + if (crtc->crtc_id != main_crtc->crtc_id) { + DrmDisableCrtc(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; +GRSurface* MinuiBackendDrm::Init() { + drmModeRes* res = nullptr; + + /* Consider DRM devices in order. */ + for (int i = 0; i < DRM_MAX_MINOR; i++) { + char* dev_name; + int 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; + + uint64_t cap = 0; + /* We need dumb buffers. */ + ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap); + if (ret || cap == 0) { + close(drm_fd); + continue; } - if (drm_fd < 0 || res == NULL) { - perror("cannot find/open a drm device"); - return NULL; + res = drmModeGetResources(drm_fd); + if (!res) { + close(drm_fd); + continue; } - 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; + /* 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; } - main_monitor_crtc = find_crtc_for_connector(drm_fd, res, - main_monitor_connector); + drmModeFreeResources(res); + close(drm_fd); + res = nullptr; + } - if (!main_monitor_crtc) { - printf("main_monitor_crtc not found\n"); - drmModeFreeResources(res); - close(drm_fd); - return NULL; - } + if (drm_fd < 0 || res == nullptr) { + perror("cannot find/open a drm device"); + return nullptr; + } - disable_non_main_crtcs(drm_fd, - res, main_monitor_crtc); + uint32_t selected_mode; + main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode); - main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; + if (!main_monitor_connector) { + printf("main_monitor_connector not found\n"); + drmModeFreeResources(res); + close(drm_fd); + return nullptr; + } - width = main_monitor_crtc->mode.hdisplay; - height = main_monitor_crtc->mode.vdisplay; + 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 nullptr; + } - 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; - } + DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc); - current_buffer = 0; + main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; - drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); + int width = main_monitor_crtc->mode.hdisplay; + int height = main_monitor_crtc->mode.vdisplay; - return &(drm_surfaces[0]->base); -} + drmModeFreeResources(res); -static GRSurface* drm_flip(minui_backend* backend __unused) { - int ret; + GRSurfaceDrms[0] = DrmCreateSurface(width, height); + GRSurfaceDrms[1] = DrmCreateSurface(width, height); + if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) { + // GRSurfaceDrms and drm_fd should be freed in d'tor. + return nullptr; + } - 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); -} + current_buffer = 0; -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; + DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]); + + return GRSurfaceDrms[0]; } -static minui_backend drm_backend = { - .init = drm_init, - .flip = drm_flip, - .blank = drm_blank, - .exit = drm_exit, -}; +GRSurface* MinuiBackendDrm::Flip() { + int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, + GRSurfaceDrms[current_buffer]->fb_id, 0, nullptr); + if (ret < 0) { + printf("drmModePageFlip failed ret=%d\n", ret); + return nullptr; + } + current_buffer = 1 - current_buffer; + return GRSurfaceDrms[current_buffer]; +} -minui_backend* open_drm() { - return &drm_backend; +MinuiBackendDrm::~MinuiBackendDrm() { + DrmDisableCrtc(drm_fd, main_monitor_crtc); + DrmDestroySurface(GRSurfaceDrms[0]); + DrmDestroySurface(GRSurfaceDrms[1]); + drmModeFreeCrtc(main_monitor_crtc); + drmModeFreeConnector(main_monitor_connector); + close(drm_fd); + drm_fd = -1; } diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h new file mode 100644 index 000000000..de9621205 --- /dev/null +++ b/minui/graphics_drm.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef _GRAPHICS_DRM_H_ +#define _GRAPHICS_DRM_H_ + +#include <stdint.h> + +#include <xf86drmMode.h> + +#include "graphics.h" +#include "minui/minui.h" + +class GRSurfaceDrm : public GRSurface { + private: + uint32_t fb_id; + uint32_t handle; + + friend class MinuiBackendDrm; +}; + +class MinuiBackendDrm : public MinuiBackend { + public: + GRSurface* Init() override; + GRSurface* Flip() override; + void Blank(bool) override; + ~MinuiBackendDrm() override; + MinuiBackendDrm(); + + private: + void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc); + void DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface); + GRSurfaceDrm* DrmCreateSurface(int width, int height); + void DrmDestroySurface(GRSurfaceDrm* surface); + void DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc); + drmModeConnector* FindMainMonitor(int fd, drmModeRes* resources, uint32_t* mode_index); + + GRSurfaceDrm* GRSurfaceDrms[2]; + int current_buffer; + drmModeCrtc* main_monitor_crtc; + drmModeConnector* main_monitor_connector; + int drm_fd; +}; + +#endif // _GRAPHICS_DRM_H_ diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp index 5f64e1e22..bb91a574d 100644 --- a/minui/graphics_fbdev.cpp +++ b/minui/graphics_fbdev.cpp @@ -14,51 +14,23 @@ * limitations under the License. */ -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include "graphics_fbdev.h" #include <fcntl.h> +#include <linux/fb.h> #include <stdio.h> - -#include <sys/cdefs.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> +#include <unistd.h> -#include <linux/fb.h> -#include <linux/kd.h> - -#include "minui.h" -#include "graphics.h" - -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*); - -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, -}; +#include "minui/minui.h" -minui_backend* open_fbdev() { - return &my_backend; -} +MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {} -static void fbdev_blank(minui_backend* backend __unused, bool blank) -{ +void MinuiBackendFbdev::Blank(bool blank) { #if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS) int fd; char brightness[4]; @@ -80,136 +52,133 @@ static void fbdev_blank(minui_backend* backend __unused, bool blank) #endif } -static void set_displayed_framebuffer(unsigned n) -{ - if (n > 1 || !double_buffered) return; +void MinuiBackendFbdev::SetDisplayedFramebuffer(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; + 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 GRSurface* fbdev_init(minui_backend* backend) { - int fd = open("/dev/graphics/fb0", O_RDWR); - if (fd == -1) { - perror("cannot open fb0"); - return NULL; - } +GRSurface* MinuiBackendFbdev::Init() { + int fd = open("/dev/graphics/fb0", O_RDWR); + if (fd == -1) { + perror("cannot open fb0"); + return nullptr; + } - 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; - } + fb_fix_screeninfo fi; + if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return nullptr; + } - // 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; - } + if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) { + perror("failed to get fb0 info"); + close(fd); + return nullptr; + } + + // 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 nullptr; + } - memset(bits, 0, fi.smem_len); + 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<uint8_t*>(bits); - memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes); + 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 = static_cast<uint8_t*>(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; + /* 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; + 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; + gr_draw = gr_framebuffer + 1; - } else { - double_buffered = false; + } 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. + // 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; - } + gr_draw = static_cast<GRSurface*>(malloc(sizeof(GRSurface))); + memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface)); + gr_draw->data = static_cast<unsigned char*>(malloc(gr_draw->height * gr_draw->row_bytes)); + if (!gr_draw->data) { + perror("failed to allocate in-memory surface"); + return nullptr; } + } - memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); - fb_fd = fd; - set_displayed_framebuffer(0); + memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); + fb_fd = fd; + SetDisplayedFramebuffer(0); - printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); + printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); - fbdev_blank(backend, true); - fbdev_blank(backend, false); + Blank(true); + Blank(false); - return gr_draw; + return gr_draw; } -static GRSurface* fbdev_flip(minui_backend* backend __unused) { - if (double_buffered) { - // 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; +GRSurface* MinuiBackendFbdev::Flip() { + if (double_buffered) { + // 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; + SetDisplayedFramebuffer(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; +MinuiBackendFbdev::~MinuiBackendFbdev() { + close(fb_fd); + fb_fd = -1; - if (!double_buffered && gr_draw) { - free(gr_draw->data); - free(gr_draw); - } - gr_draw = NULL; + if (!double_buffered && gr_draw) { + free(gr_draw->data); + free(gr_draw); + } + gr_draw = nullptr; } diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h new file mode 100644 index 000000000..107e19567 --- /dev/null +++ b/minui/graphics_fbdev.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef _GRAPHICS_FBDEV_H_ +#define _GRAPHICS_FBDEV_H_ + +#include <linux/fb.h> + +#include "graphics.h" +#include "minui/minui.h" + +class MinuiBackendFbdev : public MinuiBackend { + public: + GRSurface* Init() override; + GRSurface* Flip() override; + void Blank(bool) override; + ~MinuiBackendFbdev() override; + MinuiBackendFbdev(); + + private: + void SetDisplayedFramebuffer(unsigned n); + + GRSurface gr_framebuffer[2]; + bool double_buffered; + GRSurface* gr_draw; + int displayed_buffer; + fb_var_screeninfo vi; + int fb_fd; +}; + +#endif // _GRAPHICS_FBDEV_H_ diff --git a/minui/graphics_overlay.cpp b/minui/graphics_overlay.cpp index 978a3bb10..39ec5e494 100644 --- a/minui/graphics_overlay.cpp +++ b/minui/graphics_overlay.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "graphics_overlay.h" + #include <stdbool.h> #include <stdlib.h> #include <string.h> @@ -34,50 +36,28 @@ #ifdef MSM_BSP #include <linux/msm_mdp.h> #include <linux/msm_ion.h> +#else +#define MSMFB_NEW_REQUEST 0 #endif -#include "minui.h" -#include "graphics.h" +#include "minui/minui.h" #define MDP_V4_0 400 #define MAX_DISPLAY_DIM 2048 - -static GRSurface* overlay_init(minui_backend*); -static GRSurface* overlay_flip(minui_backend*); -static void overlay_blank(minui_backend*, bool); -static void overlay_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 bool isMDP5 = false; -static int leftSplit = 0; -static int rightSplit = 0; #define ALIGN(x, align) (((x) + ((align)-1)) & ~((align)-1)) -static size_t frame_size = 0; +MinuiBackendOverlay::MinuiBackendOverlay() : + gr_draw(nullptr), + fb_fd(-1), + isMDP5(false), + leftSplit(0), + rightSplit(0), + frame_size(0), + overlayL_id(MSMFB_NEW_REQUEST), + overlayR_id(MSMFB_NEW_REQUEST) {} #ifdef MSM_BSP -typedef struct { - unsigned char *mem_buf; - int size; - int ion_fd; - int mem_fd; - struct ion_handle_data handle_data; -} memInfo; - -//Left and right overlay id -static int overlayL_id = MSMFB_NEW_REQUEST; -static int overlayR_id = MSMFB_NEW_REQUEST; - -static memInfo mem_info; -# - -static int map_mdp_pixel_format() +int MinuiBackendOverlay::map_mdp_pixel_format() { int format = MDP_RGB_565; #if defined(RECOVERY_BGRA) @@ -91,66 +71,49 @@ static int map_mdp_pixel_format() } #endif // MSM_BSP -static minui_backend my_backend = { - .init = overlay_init, - .flip = overlay_flip, - .blank = overlay_blank, - .exit = overlay_exit, -}; - -bool target_has_overlay(char *version) +bool MinuiBackendOverlay::target_has_overlay() { int ret; int mdp_version; bool overlay_supported = false; - - if (strlen(version) >= 8) { - if(!strncmp(version, "msmfb", strlen("msmfb"))) { - char str_ver[4]; - memcpy(str_ver, version + strlen("msmfb"), 3); - str_ver[3] = '\0'; - mdp_version = atoi(str_ver); - if (mdp_version >= MDP_V4_0) { - overlay_supported = true; - } - } else if (!strncmp(version, "mdssfb", strlen("mdssfb"))) { - overlay_supported = true; - isMDP5 = true; - } - } - - return overlay_supported; -} - -minui_backend* open_overlay() { fb_fix_screeninfo fi; int fd; fd = open("/dev/graphics/fb0", O_RDWR); if (fd < 0) { perror("open_overlay cannot open fb0"); - return NULL; + return false; } if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) { perror("failed to get fb0 info"); close(fd); - return NULL; + return false; } + close(fd); - if (target_has_overlay(fi.id)) { -#ifdef MSM_BSP - close(fd); - return &my_backend; -#else + if (strlen(fi.id) >= 8) { + if(!strncmp(fi.id, "msmfb", strlen("msmfb"))) { + char str_ver[4]; + memcpy(str_ver, fi.id + strlen("msmfb"), 3); + str_ver[3] = '\0'; + mdp_version = atoi(str_ver); + if (mdp_version >= MDP_V4_0) { + overlay_supported = true; + } + } else if (!strncmp(fi.id, "mdssfb", strlen("mdssfb"))) { + overlay_supported = true; + isMDP5 = true; + } + } +#ifndef MSM_BSP + if (overlay_supported) printf("Overlay graphics may work (%s), but not enabled. Use TW_TARGET_USES_QCOM_BSP := true to enable.\n", fi.id); #endif - } - close(fd); - return NULL; + return overlay_supported; } -static void overlay_blank(minui_backend* backend __unused, bool blank) +void MinuiBackendOverlay::Blank(bool blank) { #if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS) int fd; @@ -173,7 +136,7 @@ static void overlay_blank(minui_backend* backend __unused, bool blank) #endif } -static void set_displayed_framebuffer(unsigned n) +void MinuiBackendOverlay::SetDisplayedFramebuffer(unsigned n) { if (n > 1 || !double_buffered) return; @@ -187,7 +150,7 @@ static void set_displayed_framebuffer(unsigned n) } #ifdef MSM_BSP -void setDisplaySplit(void) { +void MinuiBackendOverlay::setDisplaySplit(void) { char split[64] = {0}; if (!isMDP5) return; @@ -209,7 +172,7 @@ void setDisplaySplit(void) { fclose(fp); } -int getLeftSplit(void) { +int MinuiBackendOverlay::getLeftSplit(void) { //Default even split for all displays with high res int lSplit = vi.xres / 2; @@ -220,11 +183,11 @@ int getLeftSplit(void) { return lSplit; } -int getRightSplit(void) { +int MinuiBackendOverlay::getRightSplit(void) { return rightSplit; } -int free_ion_mem(void) { +int MinuiBackendOverlay::free_ion_mem(void) { int ret = 0; if (mem_info.mem_buf) @@ -247,7 +210,7 @@ int free_ion_mem(void) { return 0; } -int alloc_ion_mem(unsigned int size) +int MinuiBackendOverlay::alloc_ion_mem(unsigned int size) { int result; struct ion_fd_data fd_data; @@ -298,7 +261,7 @@ int alloc_ion_mem(unsigned int size) return 0; } -bool isDisplaySplit(void) { +bool MinuiBackendOverlay::isDisplaySplit(void) { if (vi.xres > MAX_DISPLAY_DIM) return true; //check if right split is set by driver @@ -308,7 +271,7 @@ bool isDisplaySplit(void) { return false; } -int allocate_overlay(int fd, GRSurface gr_fb[]) +int MinuiBackendOverlay::allocate_overlay(int fd, GRSurface gr_fb[]) { int ret = 0; @@ -407,7 +370,7 @@ int allocate_overlay(int fd, GRSurface gr_fb[]) return 0; } -int overlay_display_frame(int fd, void* data, size_t size) +int MinuiBackendOverlay::overlay_display_frame(int fd, void* data, size_t size) { int ret = 0; struct msmfb_overlay_data ovdataL, ovdataR; @@ -480,7 +443,7 @@ int overlay_display_frame(int fd, void* data, size_t size) return ret; } -static GRSurface* overlay_flip(minui_backend* backend __unused) { +GRSurface* MinuiBackendOverlay::Flip() { if (double_buffered) { #if defined(RECOVERY_BGRA) // In case of BGRA, do some byte swapping @@ -507,7 +470,7 @@ static GRSurface* overlay_flip(minui_backend* backend __unused) { return gr_draw; } -int free_overlay(int fd) +int MinuiBackendOverlay::free_overlay(int fd) { int ret = 0; struct mdp_display_commit ext_commit; @@ -557,7 +520,10 @@ int free_overlay(int fd) return 0; } -static GRSurface* overlay_init(minui_backend* backend) { +GRSurface* MinuiBackendOverlay::Init() { + if (!target_has_overlay()) + return NULL; + int fd = open("/dev/graphics/fb0", O_RDWR); if (fd == -1) { perror("cannot open fb0"); @@ -662,7 +628,7 @@ static GRSurface* overlay_init(minui_backend* backend) { return gr_draw; } -static void overlay_exit(minui_backend* backend __unused) { +MinuiBackendOverlay::~MinuiBackendOverlay() { free_overlay(fb_fd); free_ion_mem(); @@ -680,15 +646,17 @@ static void overlay_exit(minui_backend* backend __unused) { } } #else // MSM_BSP -static GRSurface* overlay_flip(minui_backend* backend __unused) { + +GRSurface* MinuiBackendOverlay::Flip() { return NULL; } -static GRSurface* overlay_init(minui_backend* backend __unused) { +GRSurface* MinuiBackendOverlay::Init() { + target_has_overlay(); // Don't care about return value, just for logging return NULL; } -static void overlay_exit(minui_backend* backend __unused) { +MinuiBackendOverlay::~MinuiBackendOverlay() { return; } #endif // MSM_BSP diff --git a/minui/graphics_overlay.h b/minui/graphics_overlay.h new file mode 100644 index 000000000..56f7401df --- /dev/null +++ b/minui/graphics_overlay.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2017 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. + */ + +#ifndef _GRAPHICS_OVERLAY_H_ +#define _GRAPHICS_OVERLAY_H_ + +#include <linux/fb.h> + +#include "graphics.h" +#include "minui/minui.h" + +#ifdef MSM_BSP +typedef struct { + unsigned char *mem_buf; + int size; + int ion_fd; + int mem_fd; + struct ion_handle_data handle_data; +} memInfo; +#endif + +class MinuiBackendOverlay : public MinuiBackend { + public: + GRSurface* Init() override; + GRSurface* Flip() override; + void Blank(bool) override; + ~MinuiBackendOverlay() override; + MinuiBackendOverlay(); + + private: + void SetDisplayedFramebuffer(unsigned n); + bool target_has_overlay(); + +#ifdef MSM_BSP + int map_mdp_pixel_format(); + void setDisplaySplit(void); + int getLeftSplit(void); + int getRightSplit(void); + int free_ion_mem(void); + int alloc_ion_mem(unsigned int size); + bool isDisplaySplit(void); + int allocate_overlay(int fd, GRSurface gr_fb[]); + int overlay_display_frame(int fd, void* data, size_t size); + int free_overlay(int fd); +#endif + + GRSurface gr_framebuffer[2]; + bool double_buffered; + GRSurface* gr_draw; + int displayed_buffer; + fb_var_screeninfo vi; + int fb_fd; + bool isMDP5; + int leftSplit; + int rightSplit; + size_t frame_size; + int overlayL_id; + int overlayR_id; +}; + +#endif // _GRAPHICS_OVERLAY_H_ diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h new file mode 100644 index 000000000..766b943ff --- /dev/null +++ b/minui/include/minui/minui.h @@ -0,0 +1,246 @@ +/* + * 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. + */ + +#ifndef _MINUI_H_ +#define _MINUI_H_ + +#ifndef TW_USE_MINUI_21 + +#include <sys/types.h> + +#include <functional> +#include <string> + +// +// Graphics. +// + +struct GRSurface { + int width; + int height; + int row_bytes; + int pixel_bytes; + unsigned char* data; +}; + +struct GRFont { + GRSurface* texture; + int char_width; + int char_height; +}; + +int gr_init(); +void gr_exit(); + +int gr_fb_width(); +int gr_fb_height(); + +void gr_flip(); +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_texticon(int x, int y, GRSurface* icon); +#ifdef TW_NO_MINUI_CUSTOM_FONTS +void gr_text(int x, int y, const char *s, bool bold); +int gr_measure(const char *s); +void gr_font_size(int *x, int *y); +void gr_set_font(__attribute__ ((unused))const char* name); +#else + +const GRFont* gr_sys_font(); +int gr_init_font(const char* name, GRFont** dest); +void gr_text(const GRFont* font, int x, int y, const char *s, bool bold); +int gr_measure(const GRFont* font, const char *s); +void gr_font_size(const GRFont* font, int *x, int *y); +#endif + +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. +// + +struct input_event; + +#ifdef TW_USE_MINUI_WITH_DATA +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); +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); +#else +using ev_callback = std::function<int(int fd, uint32_t epevents)>; +using ev_set_key_callback = std::function<int(int code, int value)>; + +int ev_init(ev_callback input_cb); +int ev_add_fd(int fd, ev_callback cb); +int ev_sync_key_state(const ev_set_key_callback& set_key_cb); +#endif +void ev_exit(); +void ev_iterate_available_keys(const std::function<void(int)>& f); + +// '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, input_event* ev); +void ev_dispatch(); +int ev_get_epollfd(); + +// +// Resources +// + +bool matches_locale(const std::string& prefix, const std::string& locale); + +// res_create_*_surface() functions return 0 if no error, else +// negative. +// +// A "display" surface is one that is intended to be drawn to the +// screen with gr_blit(). An "alpha" surface is a grayscale image +// interpreted as an alpha mask used to render text in the current +// color (with gr_text() or gr_texticon()). +// +// 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, 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, + int* fps, GRSurface*** pSurface); +int res_create_multi_display_surface(const char* name, int* frames, + GRSurface*** pSurface); + +// Load a single alpha surface from a grayscale PNG image. +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 +// translations of the same text, with special added rows that encode +// the subimages' size and intended locale in the pixel data. See +// bootable/recovery/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, + GRSurface** pSurface); + +// Free a surface allocated by any of the res_create_*_surface() +// functions. +void res_free_surface(GRSurface* surface); + +#else //ifndef TW_USE_MINUI_21 + +// This the old minui21/minui.h for compatibility with building TWRP +// in pre 6.0 trees. + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* gr_surface; +typedef unsigned short gr_pixel; + +int gr_init(void); +void gr_exit(void); + +int gr_fb_width(void); +int gr_fb_height(void); +gr_pixel *gr_fb_data(void); +void gr_flip(void); +void gr_fb_blank(bool blank); + +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); + +// system/core/charger uses different gr_print signatures in diferent +// Android versions, either with or without int bold. +int gr_text(int x, int y, const char *s, ...); +int gr_text_impl(int x, int y, const char *s, int 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); +void gr_get_memory_surface(gr_surface); + +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 <linux/input.h> for the definition. +// see http://www.mjmwired.net/kernel/Documentation/input/ for info. +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); + +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_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 + +// Returns 0 if no error, else negative. +int res_create_surface(const char* name, gr_surface* 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 res_create_localized_surface(const char* name, gr_surface* pSurface); +void res_free_surface(gr_surface surface); +static inline int res_create_display_surface(const char* name, gr_surface* pSurface) { + return res_create_surface(name, pSurface); +} + +// These are new graphics functions from 5.0 that were not available in +// 4.4 that are required by charger and healthd +void gr_clear(); + + +#ifdef __cplusplus +} +#endif + +#endif // ifndef TW_USE_MINUI_21 +#endif // ifndef _MINUI_H_ diff --git a/minui/main.cpp b/minui/main.cpp index 74b830e39..13fee8746 100644 --- a/minui/main.cpp +++ b/minui/main.cpp @@ -15,7 +15,7 @@ #include <time.h> -#include "minui.h" +#include <minui/minui.h> #include "graphics.h" int main() { diff --git a/minui/minui.h b/minui/minui.h index bf796010e..766b943ff 100644 --- a/minui/minui.h +++ b/minui/minui.h @@ -22,6 +22,7 @@ #include <sys/types.h> #include <functional> +#include <string> // // Graphics. @@ -79,15 +80,23 @@ unsigned int gr_get_height(GRSurface* surface); struct input_event; -// TODO: move these over to std::function. +#ifdef TW_USE_MINUI_WITH_DATA 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(); int ev_add_fd(int fd, ev_callback cb, void* data); -void ev_iterate_available_keys(std::function<void(int)> f); int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data); +#else +using ev_callback = std::function<int(int fd, uint32_t epevents)>; +using ev_set_key_callback = std::function<int(int code, int value)>; + +int ev_init(ev_callback input_cb); +int ev_add_fd(int fd, ev_callback cb); +int ev_sync_key_state(const ev_set_key_callback& set_key_cb); +#endif +void ev_exit(); +void ev_iterate_available_keys(const std::function<void(int)>& f); // 'timeout' has the same semantics as poll(2). // 0 : don't block @@ -103,7 +112,7 @@ int ev_get_epollfd(); // Resources // -bool matches_locale(const char* prefix, const char* locale); +bool matches_locale(const std::string& prefix, const std::string& locale); // res_create_*_surface() functions return 0 if no error, else // negative. @@ -134,8 +143,8 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface); // given locale. The image is expected to be a composite of multiple // translations of the same text, with special added rows that encode // the subimages' size and intended locale in the pixel data. See -// development/tools/recovery_l10n for an app that will generate these -// specialized images from Android resources. +// bootable/recovery/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, GRSurface** pSurface); diff --git a/minui/resources.cpp b/minui/resources.cpp index e25512f51..026e1dc2b 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -14,29 +14,31 @@ * limitations under the License. */ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - #include <fcntl.h> +#include <linux/fb.h> +#include <linux/kd.h> #include <stdio.h> - +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/types.h> +#include <unistd.h> -#include <linux/fb.h> -#include <linux/kd.h> +#include <regex> +#include <string> +#include <vector> +//#include <android-base/strings.h> // does not exist in 6.0 #include <png.h> -#include "minui.h" +#include "minui/minui.h" #define SURFACE_DATA_ALIGNMENT 8 static GRSurface* malloc_surface(size_t data_size) { size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT; - unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size)); + unsigned char* temp = static_cast<unsigned char*>(malloc(size)); if (temp == NULL) return NULL; GRSurface* surface = reinterpret_cast<GRSurface*>(temp); surface->data = temp + sizeof(GRSurface) + @@ -220,7 +222,7 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) { png_set_bgr(png_ptr); #endif - p_row = reinterpret_cast<unsigned char*>(malloc(width * 4)); + p_row = static_cast<unsigned char*>(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); @@ -280,7 +282,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, goto exit; } - surface = reinterpret_cast<GRSurface**>(malloc(*frames * sizeof(GRSurface*))); + surface = static_cast<GRSurface**>(calloc(*frames, sizeof(GRSurface*))); if (surface == NULL) { result = -8; goto exit; @@ -297,7 +299,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, png_set_bgr(png_ptr); #endif - p_row = reinterpret_cast<unsigned char*>(malloc(width * 4)); + p_row = static_cast<unsigned char*>(malloc(width * 4)); for (y = 0; y < height; ++y) { png_read_row(png_ptr, p_row, NULL); int frame = y % *frames; @@ -307,7 +309,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, } free(p_row); - *pSurface = reinterpret_cast<GRSurface**>(surface); + *pSurface = surface; exit: png_destroy_read_struct(&png_ptr, &info_ptr, NULL); @@ -315,7 +317,7 @@ exit: if (result < 0) { if (surface) { for (int i = 0; i < *frames; ++i) { - if (surface[i]) free(surface[i]); + free(surface[i]); } free(surface); } @@ -378,14 +380,27 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) { // This function tests if a locale string stored in PNG (prefix) matches // the locale string provided by the system (locale). -bool matches_locale(const char* prefix, const char* locale) { - if (locale == NULL) return false; - - // Return true if the whole string of prefix matches the top part of - // locale. For instance, prefix == "en" matches locale == "en_US"; - // and prefix == "zh_CN" matches locale == "zh_CN_#Hans". - - return (strncmp(prefix, locale, strlen(prefix)) == 0); +bool matches_locale(const std::string& prefix, const std::string& locale) { + // According to the BCP 47 format, A locale string may consists of: + // language-{extlang}-{script}-{region}-{variant} + // The locale headers in PNG mostly consist of language-{region} except for sr-Latn, and some + // android's system locale can have the format language-{script}-{region}. + + // Return true if the whole string of prefix matches the top part of locale. Otherwise try to + // match the locale string without the {script} section. + // For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale + // == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN". + //if (android::base::StartsWith(locale, prefix.c_str())) { // does not exist in 6.0 + if (strncmp(prefix.c_str(), locale.c_str(), prefix.length()) == 0) { + return true; + } + + size_t separator = prefix.find('-'); + if (separator == std::string::npos) { + return false; + } + std::regex loc_regex(prefix.substr(0, separator) + "-[A-Za-z]*" + prefix.substr(separator)); + return std::regex_match(locale, loc_regex); } int res_create_localized_alpha_surface(const char* name, @@ -397,18 +412,13 @@ int res_create_localized_alpha_surface(const char* name, png_infop info_ptr = NULL; png_uint_32 width, height; png_byte channels; - unsigned char* row; png_uint_32 y; + std::vector<unsigned char> row; *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; + return result; } result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels); @@ -419,13 +429,13 @@ int res_create_localized_alpha_surface(const char* name, goto exit; } - row = reinterpret_cast<unsigned char*>(malloc(width)); + row.resize(width); for (y = 0; y < height; ++y) { - png_read_row(png_ptr, row, NULL); + png_read_row(png_ptr, row.data(), NULL); int w = (row[1] << 8) | row[0]; int h = (row[3] << 8) | row[2]; - int len = row[4]; - char* loc = (char*)row+5; + __unused int len = row[4]; + char* loc = reinterpret_cast<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); @@ -442,16 +452,16 @@ int res_create_localized_alpha_surface(const char* name, int i; for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); - memcpy(surface->data + i*w, row, w); + png_read_row(png_ptr, row.data(), NULL); + memcpy(surface->data + i*w, row.data(), w); } - *pSurface = reinterpret_cast<GRSurface*>(surface); + *pSurface = surface; break; } else { int i; for (i = 0; i < h; ++i, ++y) { - png_read_row(png_ptr, row, NULL); + png_read_row(png_ptr, row.data(), NULL); } } } |