diff options
Diffstat (limited to 'minui')
-rw-r--r-- | minui/Android.mk | 40 | ||||
-rw-r--r-- | minui/events.cpp | 217 | ||||
-rw-r--r-- | minui/graphics.cpp | 155 | ||||
-rw-r--r-- | minui/graphics.h | 31 | ||||
-rw-r--r-- | minui/graphics_adf.cpp | 318 | ||||
-rw-r--r-- | minui/graphics_adf.h | 58 | ||||
-rw-r--r-- | minui/graphics_drm.cpp | 671 | ||||
-rw-r--r-- | minui/graphics_drm.h | 58 | ||||
-rw-r--r-- | minui/graphics_fbdev.cpp | 286 | ||||
-rw-r--r-- | minui/graphics_fbdev.h | 44 | ||||
-rw-r--r-- | minui/include/minui/minui.h (renamed from minui/minui.h) | 20 | ||||
-rw-r--r-- | minui/resources.cpp | 85 |
12 files changed, 972 insertions, 1011 deletions
diff --git a/minui/Android.mk b/minui/Android.mk index 3057f452c..4dfc65f8a 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) @@ -9,13 +23,20 @@ LOCAL_SRC_FILES := \ graphics_fbdev.cpp \ resources.cpp \ -LOCAL_WHOLE_STATIC_LIBRARIES += libadf -LOCAL_WHOLE_STATIC_LIBRARIES += libdrm -LOCAL_STATIC_LIBRARIES += libpng +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libadf \ + libdrm \ + libsync_recovery -LOCAL_MODULE := libminui +LOCAL_STATIC_LIBRARIES := \ + libpng \ + libbase -LOCAL_CLANG := true +LOCAL_CFLAGS := -Werror +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include + +LOCAL_MODULE := libminui # This used to compare against values in double-quotes (which are just # ordinary characters in this context). Strip double-quotes from the @@ -41,8 +62,13 @@ include $(BUILD_STATIC_LIBRARY) # Used by OEMs for factory test images. 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) diff --git a/minui/events.cpp b/minui/events.cpp index 3b2262a4b..0e1fd44a0 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -15,17 +15,18 @@ */ #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 <linux/input.h> +#include <functional> -#include "minui.h" +#include "minui/minui.h" #define MAX_DEVICES 16 #define MAX_MISC_FDS 16 @@ -34,9 +35,8 @@ #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; }; static int g_epoll_fd; @@ -49,92 +49,91 @@ 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; } -int ev_init(ev_callback input_cb, void* data) { - bool epollctlfail = false; +int ev_init(ev_callback input_cb) { + 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); + 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; - } - - 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); + } - 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; } -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; +int ev_add_fd(int fd, ev_callback cb) { + 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); + ev_count++; + ev_misc_count++; + } + + return ret; } void ev_exit(void) { @@ -155,13 +154,13 @@ 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) { + cb(fdi->fd, polledevents[n].events); } + } } int ev_get_input(int fd, uint32_t epevents, input_event* ev) { @@ -174,37 +173,39 @@ int ev_get_input(int fd, uint32_t epevents, input_event* ev) { 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)]; +int ev_sync_key_state(const ev_set_key_callback& set_key_cb) { + // 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)); + 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; - } + 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)) { + set_key_cb(code, 1); + } } + } - 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 ab56a6fd6..3bfce11d8 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -14,29 +14,22 @@ * 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> #include "font_10x18.h" -#include "minui.h" -#include "graphics.h" +#include "graphics_adf.h" +#include "graphics_drm.h" +#include "graphics_fbdev.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; @@ -265,7 +258,7 @@ unsigned int gr_get_height(GRSurface* surface) { } 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; } @@ -298,15 +291,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; @@ -319,109 +312,53 @@ static void gr_init_font(void) gr_font->char_height = font.char_height; } -#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(); +int gr_init() { + 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); - } - } + auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() }; + gr_draw = backend->Init(); - if (!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) { - gr_backend = open_fbdev(); - gr_draw = gr_backend->init(gr_backend); - if (gr_draw == NULL) { - return -1; - } - } + if (!gr_draw) { + backend = std::make_unique<MinuiBackendFbdev>(); + gr_draw = backend->Init(); + } - 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 52968eb10..3c45a406b 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -17,27 +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(); - -#endif +#endif // _GRAPHICS_H_ diff --git a/minui/graphics_adf.cpp b/minui/graphics_adf.cpp index 5d0867f58..1b15a04fb 100644 --- a/minui/graphics_adf.cpp +++ b/minui/graphics_adf.cpp @@ -14,236 +14,184 @@ * 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> +#include <sync/sync.h> + +#include "minui/minui.h" + +MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), n_surfaces(0), surfaces() {} + +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; + } + + surf->width = mode->hdisplay; + surf->height = mode->vdisplay; + surf->row_bytes = surf->pitch; + surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4; + + 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; + } -#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; - } - - return 0; + 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; - } +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_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; - - for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { - adf_device dev; + 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; + } - 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; - } + intf_fd = -1; - 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(GRSurfaceAdf* surf) { + 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; + } } -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 03e33b775..e7d4b38ef 100644 --- a/minui/graphics_drm.cpp +++ b/minui/graphics_drm.cpp @@ -14,463 +14,382 @@ * 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_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_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 0788f7552..746f42aaa 100644 --- a/minui/graphics_fbdev.cpp +++ b/minui/graphics_fbdev.cpp @@ -14,188 +14,154 @@ * 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, -}; - -minui_backend* open_fbdev() { - return &my_backend; -} +#include "minui/minui.h" -static void fbdev_blank(minui_backend* backend __unused, bool blank) -{ - int ret; +MinuiBackendFbdev::MinuiBackendFbdev() : gr_draw(nullptr), fb_fd(-1) {} - ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK); - if (ret < 0) - perror("ioctl(): blank"); +void MinuiBackendFbdev::Blank(bool blank) { + int 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; +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 nullptr; + } + + 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); + + 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; + + 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 = 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; } + } - 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<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; - - 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; + memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes); + fb_fd = fd; + SetDisplayedFramebuffer(0); - gr_draw = gr_framebuffer+1; + printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height); - } else { - double_buffered = false; + Blank(true); + Blank(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; + 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/minui.h b/minui/include/minui/minui.h index d30426dc8..78dd4cb98 100644 --- a/minui/minui.h +++ b/minui/include/minui/minui.h @@ -20,6 +20,7 @@ #include <sys/types.h> #include <functional> +#include <string> // // Graphics. @@ -70,15 +71,14 @@ unsigned int gr_get_height(GRSurface* 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); +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, void* data); +int ev_init(ev_callback input_cb); 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); +int ev_add_fd(int fd, ev_callback cb); +void ev_iterate_available_keys(const std::function<void(int)>& f); +int ev_sync_key_state(const ev_set_key_callback& set_key_cb); // 'timeout' has the same semantics as poll(2). // 0 : don't block @@ -94,7 +94,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. @@ -123,8 +123,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 40d3c2c88..86c731b02 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> #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); @@ -268,7 +270,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, printf(" found fps = %d\n", *fps); } - if (frames <= 0 || fps <= 0) { + if (*frames <= 0 || *fps <= 0) { printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps); result = -10; goto exit; @@ -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); } @@ -372,14 +374,26 @@ 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())) { + 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, @@ -391,18 +405,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); @@ -413,13 +422,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); @@ -436,16 +445,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); } } } |