Loading minui/graphics.cpp +38 −40 Original line number Diff line number Diff line Loading @@ -20,11 +20,16 @@ #include <stdlib.h> #include <string.h> #include <memory> #include "font_10x18.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; Loading Loading @@ -308,33 +313,30 @@ static void gr_init_font(void) } void gr_flip() { gr_draw = gr_backend->flip(gr_backend); gr_draw = gr_backend->Flip(); } int gr_init(void) { int gr_init() { gr_init_font(); gr_backend = open_adf(); if (gr_backend) { gr_draw = gr_backend->init(gr_backend); auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() }; gr_draw = backend->Init(); if (!gr_draw) { gr_backend->exit(gr_backend); } backend = std::make_unique<MinuiBackendDrm>(); gr_draw = backend->Init(); } if (!gr_draw) { gr_backend = open_drm(); gr_draw = gr_backend->init(gr_backend); backend = std::make_unique<MinuiBackendFbdev>(); gr_draw = backend->Init(); } if (!gr_draw) { gr_backend = open_fbdev(); gr_draw = gr_backend->init(gr_backend); if (gr_draw == NULL) { return -1; } } gr_backend = backend.release(); overscan_offset_x = gr_draw->width * overscan_percent / 100; overscan_offset_y = gr_draw->height * overscan_percent / 100; Loading @@ -345,22 +347,18 @@ int gr_init(void) return 0; } void gr_exit(void) { gr_backend->exit(gr_backend); void gr_exit() { delete gr_backend; } int gr_fb_width(void) { int gr_fb_width() { return gr_draw->width - 2 * overscan_offset_x; } int gr_fb_height(void) { 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); } minui/graphics.h +12 −17 Original line number Diff line number Diff line Loading @@ -19,25 +19,20 @@ #include "minui/minui.h" // TODO: lose the function pointers. struct minui_backend { class MinuiBackend { public: // Initializes the backend and returns a GRSurface* to draw into. GRSurface* (*init)(minui_backend*); 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); virtual void Blank(bool) = 0; // Device cleanup when drawing is done. void (*exit)(minui_backend*); virtual ~MinuiBackend() {}; }; minui_backend* open_fbdev(); minui_backend* open_adf(); minui_backend* open_drm(); #endif #endif // _GRAPHICS_H_ minui/graphics_adf.cpp +60 −102 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include "graphics_adf.h" #include <errno.h> #include <fcntl.h> #include <stdio.h> Loading @@ -24,49 +26,27 @@ #include <adf/adf.h> #include <sync/sync.h> #include "graphics.h" struct adf_surface_pdata { GRSurface base; int fence_fd; int fd; __u32 offset; __u32 pitch; }; struct adf_pdata { minui_backend base; int intf_fd; adf_id_t eng_id; __u32 format; #include "minui/minui.h" adf_device dev; MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), n_surfaces(0), surfaces() {} 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) { int MinuiBackendAdf::SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf) { *surf = {}; surf->fence_fd = -1; surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); 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->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->width = mode->hdisplay; surf->height = mode->vdisplay; surf->row_bytes = surf->pitch; surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4; surf->base.data = static_cast<uint8_t*>(mmap(nullptr, surf->pitch * surf->base.height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset)); if (surf->base.data == MAP_FAILED) { 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; Loading @@ -75,26 +55,26 @@ static int adf_surface_init(adf_pdata* pdata, drm_mode_modeinfo* mode, adf_surfa return 0; } static int adf_interface_init(adf_pdata* pdata) { int MinuiBackendAdf::InterfaceInit() { adf_interface_data intf_data; int err = adf_get_interface_data(pdata->intf_fd, &intf_data); int err = adf_get_interface_data(intf_fd, &intf_data); if (err < 0) return err; int ret = 0; err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[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 = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[1]); err = SurfaceInit(&intf_data.current_mode, &surfaces[1]); if (err < 0) { fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); pdata->surfaces[1] = {}; pdata->n_surfaces = 1; surfaces[1] = {}; n_surfaces = 1; } else { pdata->n_surfaces = 2; n_surfaces = 2; } done: Loading @@ -102,37 +82,35 @@ done: return ret; } static int adf_device_init(adf_pdata* pdata, adf_device* dev) { int MinuiBackendAdf::DeviceInit(adf_device* dev) { adf_id_t intf_id; int err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id, &pdata->eng_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); 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); err = InterfaceInit(); if (err < 0) { close(pdata->intf_fd); pdata->intf_fd = -1; close(intf_fd); intf_fd = -1; } return err; } static GRSurface* adf_init(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); 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 adf_id_t* dev_ids = nullptr; Loading @@ -144,35 +122,35 @@ static GRSurface* adf_init(minui_backend* backend) { return nullptr; } pdata->intf_fd = -1; intf_fd = -1; for (ssize_t i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { int err = adf_device_open(dev_ids[i], O_RDWR, &pdata->dev); 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; } err = adf_device_init(pdata, &pdata->dev); err = DeviceInit(&dev); if (err < 0) { fprintf(stderr, "initializing adf device %u failed: %s\n", dev_ids[i], strerror(-err)); adf_device_close(&pdata->dev); adf_device_close(&dev); } } free(dev_ids); if (pdata->intf_fd < 0) return nullptr; if (intf_fd < 0) return nullptr; GRSurface* ret = adf_flip(backend); GRSurface* ret = Flip(); adf_blank(backend, true); adf_blank(backend, false); Blank(true); Blank(false); return ret; } static void adf_sync(adf_surface_pdata* surf) { void MinuiBackendAdf::Sync(GRSurfaceAdf* surf) { static constexpr unsigned int warningTimeout = 3000; if (surf == nullptr) return; Loading @@ -188,52 +166,32 @@ static void adf_sync(adf_surface_pdata* surf) { } } static GRSurface* adf_flip(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_surface_pdata* surf = &pdata->surfaces[pdata->current_surface]; GRSurface* MinuiBackendAdf::Flip() { GRSurfaceAdf* surf = &surfaces[current_surface]; int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, surf->base.width, surf->base.height, pdata->format, surf->fd, surf->offset, surf->pitch, -1); 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; pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; adf_sync(&pdata->surfaces[pdata->current_surface]); return &pdata->surfaces[pdata->current_surface].base; current_surface = (current_surface + 1) % n_surfaces; Sync(&surfaces[current_surface]); return &surfaces[current_surface]; } static void adf_blank(minui_backend* backend, bool blank) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_interface_blank(pdata->intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); void MinuiBackendAdf::Blank(bool blank) { adf_interface_blank(intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); } static void adf_surface_destroy(adf_surface_pdata* surf) { munmap(surf->base.data, surf->pitch * surf->base.height); void MinuiBackendAdf::SurfaceDestroy(GRSurfaceAdf* surf) { munmap(surf->data, surf->pitch * surf->height); close(surf->fence_fd); close(surf->fd); } static void adf_exit(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_device_close(&pdata->dev); for (unsigned int i = 0; i < pdata->n_surfaces; i++) { adf_surface_destroy(&pdata->surfaces[i]); MinuiBackendAdf::~MinuiBackendAdf() { adf_device_close(&dev); for (unsigned int i = 0; i < n_surfaces; i++) { SurfaceDestroy(&surfaces[i]); } if (pdata->intf_fd >= 0) close(pdata->intf_fd); free(pdata); } minui_backend* open_adf() { adf_pdata* pdata = static_cast<adf_pdata*>(calloc(1, sizeof(*pdata))); if (!pdata) { perror("allocating adf backend failed"); return nullptr; } pdata->base.init = adf_init; pdata->base.flip = adf_flip; pdata->base.blank = adf_blank; pdata->base.exit = adf_exit; return &pdata->base; if (intf_fd >= 0) close(intf_fd); } minui/graphics_adf.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * 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_ minui/graphics_drm.cpp +49 −75 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include "graphics_drm.h" #include <fcntl.h> #include <stdio.h> #include <stdlib.h> Loading @@ -26,25 +28,13 @@ #include <xf86drmMode.h> #include "minui/minui.h" #include "graphics.h" #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) struct drm_surface { GRSurface base; uint32_t fb_id; uint32_t handle; }; static drm_surface *drm_surfaces[2]; static int current_buffer; static drmModeCrtc *main_monitor_crtc; static drmModeConnector *main_monitor_connector; MinuiBackendDrm::MinuiBackendDrm() : GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {} static int drm_fd = -1; static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) { if (crtc) { drmModeSetCrtc(drm_fd, crtc->crtc_id, 0, // fb_id Loading @@ -55,7 +45,7 @@ static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { } } static void drm_enable_crtc(int drm_fd, drmModeCrtc* crtc, struct drm_surface* surface) { 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 Loading @@ -66,19 +56,19 @@ static void drm_enable_crtc(int drm_fd, drmModeCrtc* crtc, struct drm_surface* s } } static void drm_blank(minui_backend* backend __unused, bool blank) { void MinuiBackendDrm::Blank(bool blank) { if (blank) { drm_disable_crtc(drm_fd, main_monitor_crtc); DrmDisableCrtc(drm_fd, main_monitor_crtc); } else { drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[current_buffer]); DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]); } } static void drm_destroy_surface(struct drm_surface *surface) { 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) { Loading @@ -98,7 +88,7 @@ static void drm_destroy_surface(struct drm_surface *surface) { } } free(surface); delete surface; } static int drm_format_to_bpp(uint32_t format) { Loading @@ -118,12 +108,9 @@ static int drm_format_to_bpp(uint32_t format) { } } static drm_surface *drm_create_surface(int width, int height) { drm_surface* surface = static_cast<drm_surface*>(calloc(1, sizeof(*surface))); if (!surface) { printf("Can't allocate memory\n"); return nullptr; } GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) { GRSurfaceDrm* surface = new GRSurfaceDrm; *surface = {}; uint32_t format; #if defined(RECOVERY_ABGR) Loading @@ -145,7 +132,7 @@ static drm_surface *drm_create_surface(int width, int height) { 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); drm_destroy_surface(surface); DrmDestroySurface(surface); return nullptr; } surface->handle = create_dumb.handle; Loading @@ -160,7 +147,7 @@ static drm_surface *drm_create_surface(int width, int height) { 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); DrmDestroySurface(surface); return nullptr; } Loading @@ -169,20 +156,20 @@ static drm_surface *drm_create_surface(int width, int height) { 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); DrmDestroySurface(surface); return nullptr; } 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 = static_cast<unsigned char*>(mmap(nullptr, surface->base.height * surface->base.row_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset)); if (surface->base.data == MAP_FAILED) { 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"); drm_destroy_surface(surface); DrmDestroySurface(surface); return nullptr; } Loading Loading @@ -256,7 +243,8 @@ static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* reso return nullptr; } static drmModeConnector* find_main_monitor(int fd, drmModeRes* resources, uint32_t* mode_index) { 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, Loading Loading @@ -290,18 +278,18 @@ static drmModeConnector* find_main_monitor(int fd, drmModeRes* resources, uint32 return main_monitor_connector; } static void disable_non_main_crtcs(int fd, drmModeRes* resources, drmModeCrtc* main_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) { drm_disable_crtc(fd, crtc); DrmDisableCrtc(fd, crtc); } drmModeFreeCrtc(crtc); } } static GRSurface* drm_init(minui_backend* backend __unused) { GRSurface* MinuiBackendDrm::Init() { drmModeRes* res = nullptr; /* Consider DRM devices in order. */ Loading Loading @@ -344,7 +332,7 @@ static GRSurface* drm_init(minui_backend* backend __unused) { } uint32_t selected_mode; main_monitor_connector = find_main_monitor(drm_fd, res, &selected_mode); main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode); if (!main_monitor_connector) { printf("main_monitor_connector not found\n"); Loading @@ -362,7 +350,7 @@ static GRSurface* drm_init(minui_backend* backend __unused) { return nullptr; } disable_non_main_crtcs(drm_fd, res, main_monitor_crtc); DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc); main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; Loading @@ -371,51 +359,37 @@ static GRSurface* drm_init(minui_backend* backend __unused) { drmModeFreeResources(res); drm_surfaces[0] = drm_create_surface(width, height); drm_surfaces[1] = drm_create_surface(width, height); if (!drm_surfaces[0] || !drm_surfaces[1]) { drm_destroy_surface(drm_surfaces[0]); drm_destroy_surface(drm_surfaces[1]); drmModeFreeResources(res); close(drm_fd); 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; } current_buffer = 0; drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]); return &(drm_surfaces[0]->base); return GRSurfaceDrms[0]; } static GRSurface* drm_flip(minui_backend* backend __unused) { int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, drm_surfaces[current_buffer]->fb_id, 0, nullptr); 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 &(drm_surfaces[current_buffer]->base); return GRSurfaceDrms[current_buffer]; } 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]); 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; } static minui_backend drm_backend = { .init = drm_init, .flip = drm_flip, .blank = drm_blank, .exit = drm_exit, }; minui_backend* open_drm() { return &drm_backend; } Loading
minui/graphics.cpp +38 −40 Original line number Diff line number Diff line Loading @@ -20,11 +20,16 @@ #include <stdlib.h> #include <string.h> #include <memory> #include "font_10x18.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; Loading Loading @@ -308,33 +313,30 @@ static void gr_init_font(void) } void gr_flip() { gr_draw = gr_backend->flip(gr_backend); gr_draw = gr_backend->Flip(); } int gr_init(void) { int gr_init() { gr_init_font(); gr_backend = open_adf(); if (gr_backend) { gr_draw = gr_backend->init(gr_backend); auto backend = std::unique_ptr<MinuiBackend>{ std::make_unique<MinuiBackendAdf>() }; gr_draw = backend->Init(); if (!gr_draw) { gr_backend->exit(gr_backend); } backend = std::make_unique<MinuiBackendDrm>(); gr_draw = backend->Init(); } if (!gr_draw) { gr_backend = open_drm(); gr_draw = gr_backend->init(gr_backend); backend = std::make_unique<MinuiBackendFbdev>(); gr_draw = backend->Init(); } if (!gr_draw) { gr_backend = open_fbdev(); gr_draw = gr_backend->init(gr_backend); if (gr_draw == NULL) { return -1; } } gr_backend = backend.release(); overscan_offset_x = gr_draw->width * overscan_percent / 100; overscan_offset_y = gr_draw->height * overscan_percent / 100; Loading @@ -345,22 +347,18 @@ int gr_init(void) return 0; } void gr_exit(void) { gr_backend->exit(gr_backend); void gr_exit() { delete gr_backend; } int gr_fb_width(void) { int gr_fb_width() { return gr_draw->width - 2 * overscan_offset_x; } int gr_fb_height(void) { 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); }
minui/graphics.h +12 −17 Original line number Diff line number Diff line Loading @@ -19,25 +19,20 @@ #include "minui/minui.h" // TODO: lose the function pointers. struct minui_backend { class MinuiBackend { public: // Initializes the backend and returns a GRSurface* to draw into. GRSurface* (*init)(minui_backend*); 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); virtual void Blank(bool) = 0; // Device cleanup when drawing is done. void (*exit)(minui_backend*); virtual ~MinuiBackend() {}; }; minui_backend* open_fbdev(); minui_backend* open_adf(); minui_backend* open_drm(); #endif #endif // _GRAPHICS_H_
minui/graphics_adf.cpp +60 −102 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include "graphics_adf.h" #include <errno.h> #include <fcntl.h> #include <stdio.h> Loading @@ -24,49 +26,27 @@ #include <adf/adf.h> #include <sync/sync.h> #include "graphics.h" struct adf_surface_pdata { GRSurface base; int fence_fd; int fd; __u32 offset; __u32 pitch; }; struct adf_pdata { minui_backend base; int intf_fd; adf_id_t eng_id; __u32 format; #include "minui/minui.h" adf_device dev; MinuiBackendAdf::MinuiBackendAdf() : intf_fd(-1), dev(), n_surfaces(0), surfaces() {} 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) { int MinuiBackendAdf::SurfaceInit(const drm_mode_modeinfo* mode, GRSurfaceAdf* surf) { *surf = {}; surf->fence_fd = -1; surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay, mode->vdisplay, pdata->format, &surf->offset, &surf->pitch); 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->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->width = mode->hdisplay; surf->height = mode->vdisplay; surf->row_bytes = surf->pitch; surf->pixel_bytes = (format == DRM_FORMAT_RGB565) ? 2 : 4; surf->base.data = static_cast<uint8_t*>(mmap(nullptr, surf->pitch * surf->base.height, PROT_WRITE, MAP_SHARED, surf->fd, surf->offset)); if (surf->base.data == MAP_FAILED) { 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; Loading @@ -75,26 +55,26 @@ static int adf_surface_init(adf_pdata* pdata, drm_mode_modeinfo* mode, adf_surfa return 0; } static int adf_interface_init(adf_pdata* pdata) { int MinuiBackendAdf::InterfaceInit() { adf_interface_data intf_data; int err = adf_get_interface_data(pdata->intf_fd, &intf_data); int err = adf_get_interface_data(intf_fd, &intf_data); if (err < 0) return err; int ret = 0; err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[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 = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[1]); err = SurfaceInit(&intf_data.current_mode, &surfaces[1]); if (err < 0) { fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err)); pdata->surfaces[1] = {}; pdata->n_surfaces = 1; surfaces[1] = {}; n_surfaces = 1; } else { pdata->n_surfaces = 2; n_surfaces = 2; } done: Loading @@ -102,37 +82,35 @@ done: return ret; } static int adf_device_init(adf_pdata* pdata, adf_device* dev) { int MinuiBackendAdf::DeviceInit(adf_device* dev) { adf_id_t intf_id; int err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id, &pdata->eng_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); 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); err = InterfaceInit(); if (err < 0) { close(pdata->intf_fd); pdata->intf_fd = -1; close(intf_fd); intf_fd = -1; } return err; } static GRSurface* adf_init(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); 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 adf_id_t* dev_ids = nullptr; Loading @@ -144,35 +122,35 @@ static GRSurface* adf_init(minui_backend* backend) { return nullptr; } pdata->intf_fd = -1; intf_fd = -1; for (ssize_t i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) { int err = adf_device_open(dev_ids[i], O_RDWR, &pdata->dev); 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; } err = adf_device_init(pdata, &pdata->dev); err = DeviceInit(&dev); if (err < 0) { fprintf(stderr, "initializing adf device %u failed: %s\n", dev_ids[i], strerror(-err)); adf_device_close(&pdata->dev); adf_device_close(&dev); } } free(dev_ids); if (pdata->intf_fd < 0) return nullptr; if (intf_fd < 0) return nullptr; GRSurface* ret = adf_flip(backend); GRSurface* ret = Flip(); adf_blank(backend, true); adf_blank(backend, false); Blank(true); Blank(false); return ret; } static void adf_sync(adf_surface_pdata* surf) { void MinuiBackendAdf::Sync(GRSurfaceAdf* surf) { static constexpr unsigned int warningTimeout = 3000; if (surf == nullptr) return; Loading @@ -188,52 +166,32 @@ static void adf_sync(adf_surface_pdata* surf) { } } static GRSurface* adf_flip(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_surface_pdata* surf = &pdata->surfaces[pdata->current_surface]; GRSurface* MinuiBackendAdf::Flip() { GRSurfaceAdf* surf = &surfaces[current_surface]; int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id, surf->base.width, surf->base.height, pdata->format, surf->fd, surf->offset, surf->pitch, -1); 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; pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces; adf_sync(&pdata->surfaces[pdata->current_surface]); return &pdata->surfaces[pdata->current_surface].base; current_surface = (current_surface + 1) % n_surfaces; Sync(&surfaces[current_surface]); return &surfaces[current_surface]; } static void adf_blank(minui_backend* backend, bool blank) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_interface_blank(pdata->intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); void MinuiBackendAdf::Blank(bool blank) { adf_interface_blank(intf_fd, blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON); } static void adf_surface_destroy(adf_surface_pdata* surf) { munmap(surf->base.data, surf->pitch * surf->base.height); void MinuiBackendAdf::SurfaceDestroy(GRSurfaceAdf* surf) { munmap(surf->data, surf->pitch * surf->height); close(surf->fence_fd); close(surf->fd); } static void adf_exit(minui_backend* backend) { adf_pdata* pdata = reinterpret_cast<adf_pdata*>(backend); adf_device_close(&pdata->dev); for (unsigned int i = 0; i < pdata->n_surfaces; i++) { adf_surface_destroy(&pdata->surfaces[i]); MinuiBackendAdf::~MinuiBackendAdf() { adf_device_close(&dev); for (unsigned int i = 0; i < n_surfaces; i++) { SurfaceDestroy(&surfaces[i]); } if (pdata->intf_fd >= 0) close(pdata->intf_fd); free(pdata); } minui_backend* open_adf() { adf_pdata* pdata = static_cast<adf_pdata*>(calloc(1, sizeof(*pdata))); if (!pdata) { perror("allocating adf backend failed"); return nullptr; } pdata->base.init = adf_init; pdata->base.flip = adf_flip; pdata->base.blank = adf_blank; pdata->base.exit = adf_exit; return &pdata->base; if (intf_fd >= 0) close(intf_fd); }
minui/graphics_adf.h 0 → 100644 +58 −0 Original line number Diff line number Diff line /* * 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_
minui/graphics_drm.cpp +49 −75 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * limitations under the License. */ #include "graphics_drm.h" #include <fcntl.h> #include <stdio.h> #include <stdlib.h> Loading @@ -26,25 +28,13 @@ #include <xf86drmMode.h> #include "minui/minui.h" #include "graphics.h" #define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A))) struct drm_surface { GRSurface base; uint32_t fb_id; uint32_t handle; }; static drm_surface *drm_surfaces[2]; static int current_buffer; static drmModeCrtc *main_monitor_crtc; static drmModeConnector *main_monitor_connector; MinuiBackendDrm::MinuiBackendDrm() : GRSurfaceDrms(), main_monitor_crtc(nullptr), main_monitor_connector(nullptr), drm_fd(-1) {} static int drm_fd = -1; static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) { if (crtc) { drmModeSetCrtc(drm_fd, crtc->crtc_id, 0, // fb_id Loading @@ -55,7 +45,7 @@ static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) { } } static void drm_enable_crtc(int drm_fd, drmModeCrtc* crtc, struct drm_surface* surface) { 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 Loading @@ -66,19 +56,19 @@ static void drm_enable_crtc(int drm_fd, drmModeCrtc* crtc, struct drm_surface* s } } static void drm_blank(minui_backend* backend __unused, bool blank) { void MinuiBackendDrm::Blank(bool blank) { if (blank) { drm_disable_crtc(drm_fd, main_monitor_crtc); DrmDisableCrtc(drm_fd, main_monitor_crtc); } else { drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[current_buffer]); DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[current_buffer]); } } static void drm_destroy_surface(struct drm_surface *surface) { 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) { Loading @@ -98,7 +88,7 @@ static void drm_destroy_surface(struct drm_surface *surface) { } } free(surface); delete surface; } static int drm_format_to_bpp(uint32_t format) { Loading @@ -118,12 +108,9 @@ static int drm_format_to_bpp(uint32_t format) { } } static drm_surface *drm_create_surface(int width, int height) { drm_surface* surface = static_cast<drm_surface*>(calloc(1, sizeof(*surface))); if (!surface) { printf("Can't allocate memory\n"); return nullptr; } GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) { GRSurfaceDrm* surface = new GRSurfaceDrm; *surface = {}; uint32_t format; #if defined(RECOVERY_ABGR) Loading @@ -145,7 +132,7 @@ static drm_surface *drm_create_surface(int width, int height) { 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); drm_destroy_surface(surface); DrmDestroySurface(surface); return nullptr; } surface->handle = create_dumb.handle; Loading @@ -160,7 +147,7 @@ static drm_surface *drm_create_surface(int width, int height) { 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); DrmDestroySurface(surface); return nullptr; } Loading @@ -169,20 +156,20 @@ static drm_surface *drm_create_surface(int width, int height) { 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); DrmDestroySurface(surface); return nullptr; } 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 = static_cast<unsigned char*>(mmap(nullptr, surface->base.height * surface->base.row_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_dumb.offset)); if (surface->base.data == MAP_FAILED) { 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"); drm_destroy_surface(surface); DrmDestroySurface(surface); return nullptr; } Loading Loading @@ -256,7 +243,8 @@ static drmModeConnector* find_first_connected_connector(int fd, drmModeRes* reso return nullptr; } static drmModeConnector* find_main_monitor(int fd, drmModeRes* resources, uint32_t* mode_index) { 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, Loading Loading @@ -290,18 +278,18 @@ static drmModeConnector* find_main_monitor(int fd, drmModeRes* resources, uint32 return main_monitor_connector; } static void disable_non_main_crtcs(int fd, drmModeRes* resources, drmModeCrtc* main_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) { drm_disable_crtc(fd, crtc); DrmDisableCrtc(fd, crtc); } drmModeFreeCrtc(crtc); } } static GRSurface* drm_init(minui_backend* backend __unused) { GRSurface* MinuiBackendDrm::Init() { drmModeRes* res = nullptr; /* Consider DRM devices in order. */ Loading Loading @@ -344,7 +332,7 @@ static GRSurface* drm_init(minui_backend* backend __unused) { } uint32_t selected_mode; main_monitor_connector = find_main_monitor(drm_fd, res, &selected_mode); main_monitor_connector = FindMainMonitor(drm_fd, res, &selected_mode); if (!main_monitor_connector) { printf("main_monitor_connector not found\n"); Loading @@ -362,7 +350,7 @@ static GRSurface* drm_init(minui_backend* backend __unused) { return nullptr; } disable_non_main_crtcs(drm_fd, res, main_monitor_crtc); DisableNonMainCrtcs(drm_fd, res, main_monitor_crtc); main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode]; Loading @@ -371,51 +359,37 @@ static GRSurface* drm_init(minui_backend* backend __unused) { drmModeFreeResources(res); drm_surfaces[0] = drm_create_surface(width, height); drm_surfaces[1] = drm_create_surface(width, height); if (!drm_surfaces[0] || !drm_surfaces[1]) { drm_destroy_surface(drm_surfaces[0]); drm_destroy_surface(drm_surfaces[1]); drmModeFreeResources(res); close(drm_fd); 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; } current_buffer = 0; drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]); DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]); return &(drm_surfaces[0]->base); return GRSurfaceDrms[0]; } static GRSurface* drm_flip(minui_backend* backend __unused) { int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, drm_surfaces[current_buffer]->fb_id, 0, nullptr); 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 &(drm_surfaces[current_buffer]->base); return GRSurfaceDrms[current_buffer]; } 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]); 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; } static minui_backend drm_backend = { .init = drm_init, .flip = drm_flip, .blank = drm_blank, .exit = drm_exit, }; minui_backend* open_drm() { return &drm_backend; }