diff options
Diffstat (limited to 'minui')
-rw-r--r-- | minui/Android.bp | 12 | ||||
-rw-r--r-- | minui/events.cpp | 29 | ||||
-rw-r--r-- | minui/graphics.cpp | 94 | ||||
-rw-r--r-- | minui/graphics.h | 11 | ||||
-rw-r--r-- | minui/graphics_drm.cpp | 189 | ||||
-rw-r--r-- | minui/graphics_drm.h | 19 | ||||
-rw-r--r-- | minui/graphics_fbdev.cpp | 6 | ||||
-rw-r--r-- | minui/graphics_fbdev.h | 1 | ||||
-rw-r--r-- | minui/include/minui/minui.h | 19 | ||||
-rw-r--r-- | minui/resources.cpp | 56 |
10 files changed, 332 insertions, 104 deletions
diff --git a/minui/Android.bp b/minui/Android.bp index f68f6c81d..02fb3638f 100644 --- a/minui/Android.bp +++ b/minui/Android.bp @@ -24,6 +24,7 @@ package { cc_library { name: "libminui", recovery_available: true, + vendor_available: true, defaults: [ "recovery_defaults", @@ -51,4 +52,15 @@ cc_library { "libpng", "libz", ], + + target: { + vendor: { + exclude_static_libs: [ + "libsync", + ], + shared_libs: [ + "libsync", + ], + }, + }, } diff --git a/minui/events.cpp b/minui/events.cpp index 863ac7474..b307a4977 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -267,6 +267,35 @@ int ev_get_input(int fd, uint32_t epevents, input_event* ev) { return -1; } +int ev_sync_sw_state(const ev_set_sw_callback& set_sw_cb) { + // Use unsigned long to match ioctl's parameter type. + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT + unsigned long sw_bits[BITS_TO_LONGS(SW_MAX)]; // NOLINT + + for (size_t i = 0; i < g_ev_dev_count; ++i) { + memset(ev_bits, 0, sizeof(ev_bits)); + memset(sw_bits, 0, sizeof(sw_bits)); + + if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + continue; + } + if (!test_bit(EV_SW, ev_bits)) { + continue; + } + if (ioctl(ev_fdinfo[i].fd, EVIOCGSW(sizeof(sw_bits)), sw_bits) == -1) { + continue; + } + + for (int code = 0; code <= SW_MAX; code++) { + if (test_bit(code, sw_bits)) { + set_sw_cb(code, 1); + } + } + } + + return 0; +} + 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 diff --git a/minui/graphics.cpp b/minui/graphics.cpp index dce1e619a..b24c2b114 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -36,12 +36,14 @@ static int overscan_offset_x = 0; static int overscan_offset_y = 0; static uint32_t gr_current = ~0; -static constexpr uint32_t alpha_mask = 0xff000000; // gr_draw is owned by backends. static GRSurface* gr_draw = nullptr; static GRRotation rotation = GRRotation::NONE; static PixelFormat pixel_format = PixelFormat::UNKNOWN; +// The graphics backend list that provides fallback options for the default backend selection. +// For example, it will fist try DRM, then try FBDEV if DRM is unavailable. +constexpr auto default_backends = { GraphicsBackend::DRM, GraphicsBackend::FBDEV }; static bool outside(int x, int y) { auto swapped = (rotation == GRRotation::LEFT || rotation == GRRotation::RIGHT); @@ -76,7 +78,7 @@ int gr_font_size(const GRFont* font, int* x, int* y) { } // Blends gr_current onto pix value, assumes alpha as most significant byte. -static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) { +static inline uint32_t pixel_blend_argb(uint8_t alpha, uint32_t pix) { if (alpha == 255) return gr_current; if (alpha == 0) return pix; uint32_t pix_r = pix & 0xff; @@ -93,6 +95,48 @@ static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) { return (out_r & 0xff) | (out_g & 0xff00) | (out_b & 0xff0000) | (gr_current & 0xff000000); } +static inline uint32_t pixel_blend_rgba(uint8_t alpha, uint32_t pix) { + if (alpha == 255) return gr_current; + if (alpha == 0) return pix; + uint32_t pix_r = pix & 0xff00; + uint32_t pix_g = pix & 0xff0000; + uint32_t pix_b = pix & 0xff000000; + uint32_t cur_r = gr_current & 0xff00; + uint32_t cur_g = gr_current & 0xff0000; + uint32_t cur_b = gr_current & 0xff000000; + + uint32_t out_r = (pix_r * (255 - alpha) + cur_r * alpha) / 255; + uint32_t out_g = (pix_g * (255 - alpha) + cur_g * alpha) / 255; + uint32_t out_b = (pix_b * (255 - alpha) + cur_b * alpha) / 255; + + return (gr_current & 0xff) | (out_r & 0xff00) | (out_g & 0xff0000) | (out_b & 0xff000000); +} + +static inline uint32_t pixel_blend(uint8_t alpha, uint32_t pix) { + if (pixel_format == PixelFormat::RGBA) { + return pixel_blend_rgba(alpha, pix); + } + return pixel_blend_argb(alpha, pix); +} + +static inline uint32_t get_alphamask() { + if (pixel_format == PixelFormat::RGBA) { + return 0x000000ff; + } + return 0xff000000; +} + +static inline uint8_t get_alpha_shift() { + if (pixel_format == PixelFormat::RGBA) { + return 0; + } + return 24; +} + +static inline uint8_t get_alpha(uint32_t pix) { + return static_cast<uint8_t>((pix & (gr_current & get_alphamask())) >> get_alpha_shift()); +} + // Increments pixel pointer right, with current rotation. static void incr_x(uint32_t** p, int row_pixels) { if (rotation == GRRotation::LEFT) { @@ -140,7 +184,7 @@ static uint32_t* PixelAt(GRSurface* surface, int x, int y, int row_pixels) { static void TextBlend(const uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, int dst_row_pixels, int width, int height) { - uint8_t alpha_current = static_cast<uint8_t>((alpha_mask & gr_current) >> 24); + uint8_t alpha_current = get_alpha(gr_current); for (int j = 0; j < height; ++j) { const uint8_t* sx = src_p; uint32_t* px = dst_p; @@ -155,7 +199,7 @@ static void TextBlend(const uint8_t* src_p, int src_row_bytes, uint32_t* dst_p, } void gr_text(const GRFont* font, int x, int y, const char* s, bool bold) { - if (!font || !font->texture || (gr_current & alpha_mask) == 0) return; + if (!font || !font->texture || (gr_current & get_alphamask()) == 0) return; if (font->texture->pixel_bytes != 1) { printf("gr_text: font has wrong format\n"); @@ -210,6 +254,8 @@ void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a uint32_t r32 = r, g32 = g, b32 = b, a32 = a; if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32; + } else if (pixel_format == PixelFormat::RGBA) { + gr_current = (b32 << 24) | (g32 << 16) | (r32 << 8) | a32; } else { gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32; } @@ -244,7 +290,7 @@ void gr_fill(int x1, int y1, int x2, int y2) { int row_pixels = gr_draw->row_bytes / gr_draw->pixel_bytes; uint32_t* p = PixelAt(gr_draw, x1, y1, row_pixels); - uint8_t alpha = static_cast<uint8_t>(((gr_current & alpha_mask) >> 24)); + uint8_t alpha = get_alpha(gr_current); if (alpha > 0) { for (int y = y1; y < y2; ++y) { uint32_t* px = p; @@ -340,7 +386,22 @@ void gr_flip() { gr_draw = gr_backend->Flip(); } +std::unique_ptr<MinuiBackend> create_backend(GraphicsBackend backend) { + switch (backend) { + case GraphicsBackend::DRM: + return std::make_unique<MinuiBackendDrm>(); + case GraphicsBackend::FBDEV: + return std::make_unique<MinuiBackendFbdev>(); + default: + return nullptr; + } +} + int gr_init() { + return gr_init(default_backends); +} + +int gr_init(std::initializer_list<GraphicsBackend> backends) { // pixel_format needs to be set before loading any resources or initializing backends. std::string format = android::base::GetProperty("ro.minui.pixel_format", ""); if (format == "ABGR_8888") { @@ -351,6 +412,8 @@ int gr_init() { pixel_format = PixelFormat::ARGB; } else if (format == "BGRA_8888") { pixel_format = PixelFormat::BGRA; + } else if (format == "RGBA_8888") { + pixel_format = PixelFormat::RGBA; } else { pixel_format = PixelFormat::UNKNOWN; } @@ -361,19 +424,22 @@ int gr_init() { ret); } - auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendDrm>() }; - gr_draw = backend->Init(); - - if (!gr_draw) { - backend = std::make_unique<MinuiBackendFbdev>(); - gr_draw = backend->Init(); + std::unique_ptr<MinuiBackend> minui_backend; + for (GraphicsBackend backend : backends) { + minui_backend = create_backend(backend); + if (!minui_backend) { + printf("gr_init: minui_backend %d is a nullptr\n", backend); + continue; + } + gr_draw = minui_backend->Init(); + if (gr_draw) break; } if (!gr_draw) { return -1; } - gr_backend = backend.release(); + gr_backend = minui_backend.release(); int overscan_percent = android::base::GetIntProperty("ro.minui.overscan_percent", 0); overscan_offset_x = gr_draw->width * overscan_percent / 100; @@ -429,6 +495,10 @@ void gr_fb_blank(bool blank) { gr_backend->Blank(blank); } +void gr_fb_blank(bool blank, int index) { + gr_backend->Blank(blank, static_cast<MinuiBackend::DrmConnector>(index)); +} + void gr_rotate(GRRotation rot) { rotation = rot; } diff --git a/minui/graphics.h b/minui/graphics.h index 3c45a406b..5408c93e9 100644 --- a/minui/graphics.h +++ b/minui/graphics.h @@ -21,6 +21,12 @@ class MinuiBackend { public: + enum DrmConnector { + DRM_MAIN = 0, + DRM_SEC, + DRM_MAX, + }; + // Initializes the backend and returns a GRSurface* to draw into. virtual GRSurface* Init() = 0; @@ -28,9 +34,12 @@ class MinuiBackend { // be displayed, and returns a new drawing surface. virtual GRSurface* Flip() = 0; - // Blank (or unblank) the screen. + // Blank (or unblank) the default screen. virtual void Blank(bool) = 0; + // Blank (or unblank) the specific screen. + virtual void Blank(bool blank, DrmConnector index) = 0; + // Device cleanup when drawing is done. virtual ~MinuiBackend() {}; }; diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp index 95759e382..c55702276 100644 --- a/minui/graphics_drm.cpp +++ b/minui/graphics_drm.cpp @@ -105,6 +105,8 @@ std::unique_ptr<GRSurfaceDrm> GRSurfaceDrm::Create(int drm_fd, int width, int he perror("Failed to DRM_IOCTL_MODE_CREATE_DUMB"); return nullptr; } + printf("Allocating buffer with resolution %d x %d pitch: %d bpp: %d, size: %llu\n", width, height, + create_dumb.pitch, create_dumb.bpp, create_dumb.size); // Cannot use std::make_unique to access non-public ctor. auto surface = std::unique_ptr<GRSurfaceDrm>(new GRSurfaceDrm( @@ -128,13 +130,14 @@ std::unique_ptr<GRSurfaceDrm> GRSurfaceDrm::Create(int drm_fd, int width, int he return nullptr; } - auto mmapped = mmap(nullptr, surface->height * surface->row_bytes, PROT_READ | PROT_WRITE, - MAP_SHARED, drm_fd, map_dumb.offset); + auto mmapped = + mmap(nullptr, create_dumb.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset); if (mmapped == MAP_FAILED) { perror("Failed to mmap()"); return nullptr; } surface->mmapped_buffer_ = static_cast<uint8_t*>(mmapped); + printf("Framebuffer of size %llu allocated @ %p\n", create_dumb.size, surface->mmapped_buffer_); return surface; } @@ -150,22 +153,50 @@ void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) { } bool MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, - const std::unique_ptr<GRSurfaceDrm>& surface) { + const std::unique_ptr<GRSurfaceDrm>& surface, + uint32_t* connector_id) { if (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) != 0) { - perror("Failed to drmModeSetCrtc"); + connector_id, 1, // connector_count + &crtc->mode) != 0) { + fprintf(stderr, "Failed to drmModeSetCrtc(%d)\n", *connector_id); return false; } + return true; } void MinuiBackendDrm::Blank(bool blank) { + Blank(blank, DRM_MAIN); +} + +void MinuiBackendDrm::Blank(bool blank, DrmConnector index) { + const auto* drmInterface = &drm[DRM_MAIN]; + + switch (index) { + case DRM_MAIN: + drmInterface = &drm[DRM_MAIN]; + break; + case DRM_SEC: + drmInterface = &drm[DRM_SEC]; + break; + default: + fprintf(stderr, "Invalid index: %d\n", index); + return; + } + + if (!drmInterface->monitor_connector) { + fprintf(stderr, "Unsupported. index = %d\n", index); + return; + } + if (blank) { - DrmDisableCrtc(drm_fd, main_monitor_crtc); + DrmDisableCrtc(drm_fd, drmInterface->monitor_crtc); } else { - DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]); + DrmEnableCrtc(drm_fd, drmInterface->monitor_crtc, + drmInterface->GRSurfaceDrms[drmInterface->current_buffer], + &drmInterface->monitor_connector->connector_id); + + active_display = index; } } @@ -207,18 +238,21 @@ static drmModeCrtc* find_crtc_for_connector(int fd, drmModeRes* resources, return nullptr; } -static drmModeConnector* find_used_connector_by_type(int fd, drmModeRes* resources, unsigned type) { +std::vector<drmModeConnector*> find_used_connector_by_type(int fd, drmModeRes* resources, + unsigned type) { + std::vector<drmModeConnector*> drmConnectors; 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; + drmConnectors.push_back(connector); + } else { + drmModeFreeConnector(connector); } - drmModeFreeConnector(connector); } } - return nullptr; + return drmConnectors; } static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* resources) { @@ -236,8 +270,7 @@ static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* reso return nullptr; } -drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources, - uint32_t* mode_index) { +bool MinuiBackendDrm::FindAndSetMonitor(int fd, drmModeRes* resources) { /* Look for LVDS/eDP/DSI connectors. Those are the main screens. */ static constexpr unsigned kConnectorPriority[] = { DRM_MODE_CONNECTOR_LVDS, @@ -245,30 +278,41 @@ drmModeConnector* MinuiBackendDrm::FindMainMonitor(int fd, drmModeRes* resources 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 < arraysize(kConnectorPriority)); + std::vector<drmModeConnector*> drmConnectors; + for (int i = 0; i < arraysize(kConnectorPriority) && drmConnectors.size() < DRM_MAX; i++) { + auto connectors = find_used_connector_by_type(fd, resources, kConnectorPriority[i]); + for (auto connector : connectors) { + drmConnectors.push_back(connector); + if (drmConnectors.size() >= DRM_MAX) break; + } + } /* 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 (drmConnectors.empty()) { + drmModeConnector* connector = find_first_connected_connector(fd, resources); + if (connector) { + drmConnectors.push_back(connector); + } } - /* 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; + for (int drm_index = 0; drm_index < drmConnectors.size(); drm_index++) { + drm[drm_index].monitor_connector = drmConnectors[drm_index]; + + drm[drm_index].selected_mode = 0; + for (int modes = 0; modes < drmConnectors[drm_index]->count_modes; modes++) { + printf("Display Mode %d resolution: %d x %d @ %d FPS\n", modes, + drmConnectors[drm_index]->modes[modes].hdisplay, + drmConnectors[drm_index]->modes[modes].vdisplay, + drmConnectors[drm_index]->modes[modes].vrefresh); + if (drmConnectors[drm_index]->modes[modes].type & DRM_MODE_TYPE_PREFERRED) { + printf("Choosing display mode #%d\n", modes); + drm[drm_index].selected_mode = modes; + break; + } } } - return main_monitor_connector; + return drmConnectors.size() > 0; } void MinuiBackendDrm::DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc) { @@ -319,46 +363,49 @@ GRSurface* MinuiBackendDrm::Init() { return nullptr; } - uint32_t selected_mode; - main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode); - if (!main_monitor_connector) { - fprintf(stderr, "Failed to find main_monitor_connector\n"); - drmModeFreeResources(res); - close(drm_fd); - return nullptr; - } - - main_monitor_crtc = find_crtc_for_connector(drm_fd, res, main_monitor_connector); - if (!main_monitor_crtc) { - fprintf(stderr, "Failed to find main_monitor_crtc\n"); + if (!FindAndSetMonitor(drm_fd, res)) { + fprintf(stderr, "Failed to find main monitor_connector\n"); drmModeFreeResources(res); - close(drm_fd); return nullptr; } - DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc); + for (int i = 0; i < DRM_MAX; i++) { + if (drm[i].monitor_connector) { + drm[i].monitor_crtc = find_crtc_for_connector(drm_fd, res, drm[i].monitor_connector); + if (!drm[i].monitor_crtc) { + fprintf(stderr, "Failed to find monitor_crtc, drm index=%d\n", i); + drmModeFreeResources(res); + return nullptr; + } - main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; + drm[i].monitor_crtc->mode = drm[i].monitor_connector->modes[drm[i].selected_mode]; - int width = main_monitor_crtc->mode.hdisplay; - int height = main_monitor_crtc->mode.vdisplay; + int width = drm[i].monitor_crtc->mode.hdisplay; + int height = drm[i].monitor_crtc->mode.vdisplay; - drmModeFreeResources(res); + drm[i].GRSurfaceDrms[0] = GRSurfaceDrm::Create(drm_fd, width, height); + drm[i].GRSurfaceDrms[1] = GRSurfaceDrm::Create(drm_fd, width, height); + if (!drm[i].GRSurfaceDrms[0] || !drm[i].GRSurfaceDrms[1]) { + fprintf(stderr, "Failed to create GRSurfaceDrm, drm index=%d\n", i); + drmModeFreeResources(res); + return nullptr; + } - GRSurfaceDrms[0] = GRSurfaceDrm::Create(drm_fd, width, height); - GRSurfaceDrms[1] = GRSurfaceDrm::Create(drm_fd, width, height); - if (!GRSurfaceDrms[0] || !GRSurfaceDrms[1]) { - return nullptr; + drm[i].current_buffer = 0; + } } - current_buffer = 0; + DisableNonMainCrtcs(drm_fd, res, drm[DRM_MAIN].monitor_crtc); + + drmModeFreeResources(res); // We will likely encounter errors in the backend functions (i.e. Flip) if EnableCrtc fails. - if (!DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1])) { + if (!DrmEnableCrtc(drm_fd, drm[DRM_MAIN].monitor_crtc, drm[DRM_MAIN].GRSurfaceDrms[1], + &drm[DRM_MAIN].monitor_connector->connector_id)) { return nullptr; } - return GRSurfaceDrms[0].get(); + return drm[DRM_MAIN].GRSurfaceDrms[0].get(); } static void page_flip_complete(__unused int fd, @@ -370,10 +417,19 @@ static void page_flip_complete(__unused int fd, } GRSurface* MinuiBackendDrm::Flip() { + GRSurface* surface = NULL; + DrmInterface* current_drm = &drm[active_display]; bool ongoing_flip = true; - if (drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, GRSurfaceDrms[current_buffer]->fb_id, + + if (!current_drm->monitor_connector) { + fprintf(stderr, "Unsupported. active_display = %d\n", active_display); + return nullptr; + } + + if (drmModePageFlip(drm_fd, current_drm->monitor_crtc->crtc_id, + current_drm->GRSurfaceDrms[current_drm->current_buffer]->fb_id, DRM_MODE_PAGE_FLIP_EVENT, &ongoing_flip) != 0) { - perror("Failed to drmModePageFlip"); + fprintf(stderr, "Failed to drmModePageFlip, active_display=%d", active_display); return nullptr; } @@ -399,14 +455,19 @@ GRSurface* MinuiBackendDrm::Flip() { } } - current_buffer = 1 - current_buffer; - return GRSurfaceDrms[current_buffer].get(); + current_drm->current_buffer = 1 - current_drm->current_buffer; + surface = current_drm->GRSurfaceDrms[current_drm->current_buffer].get(); + return surface; } MinuiBackendDrm::~MinuiBackendDrm() { - DrmDisableCrtc(drm_fd, main_monitor_crtc); - drmModeFreeCrtc(main_monitor_crtc); - drmModeFreeConnector(main_monitor_connector); + for (int i = 0; i < DRM_MAX; i++) { + if (drm[i].monitor_connector) { + DrmDisableCrtc(drm_fd, drm[i].monitor_crtc); + drmModeFreeCrtc(drm[i].monitor_crtc); + drmModeFreeConnector(drm[i].monitor_connector); + } + } close(drm_fd); drm_fd = -1; } diff --git a/minui/graphics_drm.h b/minui/graphics_drm.h index 57ba39b83..fe3beaff9 100644 --- a/minui/graphics_drm.h +++ b/minui/graphics_drm.h @@ -59,16 +59,23 @@ class MinuiBackendDrm : public MinuiBackend { GRSurface* Init() override; GRSurface* Flip() override; void Blank(bool) override; + void Blank(bool blank, DrmConnector index) override; private: void DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc); - bool DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, const std::unique_ptr<GRSurfaceDrm>& surface); + bool DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, const std::unique_ptr<GRSurfaceDrm>& surface, + uint32_t* conntcors); void DisableNonMainCrtcs(int fd, drmModeRes* resources, drmModeCrtc* main_crtc); - drmModeConnector* FindMainMonitor(int fd, drmModeRes* resources, uint32_t* mode_index); + bool FindAndSetMonitor(int fd, drmModeRes* resources); + + struct DrmInterface { + std::unique_ptr<GRSurfaceDrm> GRSurfaceDrms[2]; + int current_buffer{ 0 }; + drmModeCrtc* monitor_crtc{ nullptr }; + drmModeConnector* monitor_connector{ nullptr }; + uint32_t selected_mode{ 0 }; + } drm[DRM_MAX]; - std::unique_ptr<GRSurfaceDrm> GRSurfaceDrms[2]; - int current_buffer{ 0 }; - drmModeCrtc* main_monitor_crtc{ nullptr }; - drmModeConnector* main_monitor_connector{ nullptr }; int drm_fd{ -1 }; + DrmConnector active_display = DRM_MAIN; }; diff --git a/minui/graphics_fbdev.cpp b/minui/graphics_fbdev.cpp index 2584017d6..1cb0c0ab8 100644 --- a/minui/graphics_fbdev.cpp +++ b/minui/graphics_fbdev.cpp @@ -43,6 +43,10 @@ void MinuiBackendFbdev::Blank(bool blank) { if (ret < 0) perror("ioctl(): blank"); } +void MinuiBackendFbdev::Blank(bool blank, DrmConnector index) { + fprintf(stderr, "Unsupported multiple connectors, blank = %d, index = %d\n", blank, index); +} + void MinuiBackendFbdev::SetDisplayedFramebuffer(size_t n) { if (n > 1 || !double_buffered) return; @@ -131,8 +135,6 @@ GRSurface* MinuiBackendFbdev::Init() { SetDisplayedFramebuffer(0); printf("framebuffer: %d (%zu x %zu)\n", fb_fd.get(), gr_draw->width, gr_draw->height); - - Blank(true); Blank(false); return gr_draw; diff --git a/minui/graphics_fbdev.h b/minui/graphics_fbdev.h index 596ba74ea..7e193c4ff 100644 --- a/minui/graphics_fbdev.h +++ b/minui/graphics_fbdev.h @@ -56,6 +56,7 @@ class MinuiBackendFbdev : public MinuiBackend { GRSurface* Init() override; GRSurface* Flip() override; void Blank(bool) override; + void Blank(bool blank, DrmConnector index) override; private: void SetDisplayedFramebuffer(size_t n); diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h index 163e41dc6..f9be82f52 100644 --- a/minui/include/minui/minui.h +++ b/minui/include/minui/minui.h @@ -102,12 +102,22 @@ enum class PixelFormat : int { RGBX = 2, BGRA = 3, ARGB = 4, + RGBA = 5, // LSB Alpha }; -// Initializes the graphics backend and loads font file. Returns 0 on success, or -1 on error. Note -// that the font initialization failure would be non-fatal, as caller may not need to draw any text -// at all. Caller can check the font initialization result via gr_sys_font() as needed. +enum class GraphicsBackend : int { + UNKNOWN = 0, + DRM = 1, + FBDEV = 2, +}; + +// Initializes the default graphics backend and loads font file. Returns 0 on success, or -1 on +// error. Note that the font initialization failure would be non-fatal, as caller may not need to +// draw any text at all. Caller can check the font initialization result via gr_sys_font() as +// needed. int gr_init(); +// Supports backend selection for minui client. +int gr_init(std::initializer_list<GraphicsBackend> backends); // Frees the allocated resources. The function is idempotent, and safe to be called if gr_init() // didn't finish successfully. @@ -118,6 +128,7 @@ int gr_fb_height(); void gr_flip(); void gr_fb_blank(bool blank); +void gr_fb_blank(bool blank, int index); // Clears entire surface to current color. void gr_clear(); @@ -152,6 +163,7 @@ struct input_event; using ev_callback = std::function<int(int fd, uint32_t epevents)>; using ev_set_key_callback = std::function<int(int code, int value)>; +using ev_set_sw_callback = std::function<int(int code, int value)>; int ev_init(ev_callback input_cb, bool allow_touch_inputs = false); void ev_exit(); @@ -159,6 +171,7 @@ int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb); void ev_iterate_available_keys(const std::function<void(int)>& f); void ev_iterate_touch_inputs(const std::function<void(int)>& action); int ev_sync_key_state(const ev_set_key_callback& set_key_cb); +int ev_sync_sw_state(const ev_set_sw_callback& set_sw_cb); // 'timeout' has the same semantics as poll(2). // 0 : don't block diff --git a/minui/resources.cpp b/minui/resources.cpp index d7b927700..1521c8f17 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -153,32 +153,57 @@ static void TransformRgbToDraw(const uint8_t* input_row, uint8_t* output_row, in int width) { const uint8_t* ip = input_row; uint8_t* op = output_row; + PixelFormat pixel_format = gr_pixel_format(); switch (channels) { case 1: // expand gray level to RGBX for (int x = 0; x < width; ++x) { - *op++ = *ip; - *op++ = *ip; - *op++ = *ip; - *op++ = 0xff; + if (pixel_format == PixelFormat::RGBA) { + *op++ = 0xff; + *op++ = *ip; + *op++ = *ip; + *op++ = *ip; + } else { + *op++ = *ip; + *op++ = *ip; + *op++ = *ip; + *op++ = 0xff; + } ip++; } break; case 3: - // expand RGBA to RGBX for (int x = 0; x < width; ++x) { - *op++ = *ip++; - *op++ = *ip++; - *op++ = *ip++; - *op++ = 0xff; + // expand RGBA to RGBX + if (pixel_format == PixelFormat::RGBA) { + *op++ = 0xff; + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + } else { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + *op++ = 0xff; + } } break; case 4: - // copy RGBA to RGBX - memcpy(output_row, input_row, width * 4); + if (pixel_format == PixelFormat::RGBA) { + for (int x = 0; x < width; ++x) { + *op++ = *(ip + 3); + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + ip++; + } + } else { + // copy RGBA to RGBX + memcpy(output_row, input_row, width * 4); + } break; } } @@ -201,6 +226,8 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) { PixelFormat pixel_format = gr_pixel_format(); if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { png_set_bgr(png_ptr); + } else if (pixel_format == PixelFormat::RGBA) { + png_set_swap_alpha(png_ptr); } for (png_uint_32 y = 0; y < height; ++y) { @@ -273,6 +300,8 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, if (gr_pixel_format() == PixelFormat::ARGB || gr_pixel_format() == PixelFormat::BGRA) { png_set_bgr(png_ptr); + } else if (gr_pixel_format() == PixelFormat::RGBA) { + png_set_swap_alpha(png_ptr); } for (png_uint_32 y = 0; y < height; ++y) { @@ -316,11 +345,6 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) { return -8; } - PixelFormat pixel_format = gr_pixel_format(); - if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { - png_set_bgr(png_ptr); - } - for (png_uint_32 y = 0; y < height; ++y) { uint8_t* p_row = surface->data() + y * surface->row_bytes; png_read_row(png_ptr, p_row, nullptr); |