diff options
Diffstat (limited to '')
-rw-r--r-- | minui/graphics_drm.cpp | 92 |
1 files changed, 69 insertions, 23 deletions
diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp index e7d4b38ef..81b49fd95 100644 --- a/minui/graphics_drm.cpp +++ b/minui/graphics_drm.cpp @@ -17,6 +17,7 @@ #include "graphics_drm.h" #include <fcntl.h> +#include <poll.h> #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> @@ -45,15 +46,17 @@ void MinuiBackendDrm::DrmDisableCrtc(int drm_fd, drmModeCrtc* crtc) { } } -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); +int MinuiBackendDrm::DrmEnableCrtc(int drm_fd, drmModeCrtc* crtc, GRSurfaceDrm* surface) { + int 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); } + + return ret; } void MinuiBackendDrm::Blank(bool blank) { @@ -67,8 +70,8 @@ void MinuiBackendDrm::Blank(bool blank) { void MinuiBackendDrm::DrmDestroySurface(GRSurfaceDrm* surface) { if (!surface) return; - if (surface->data) { - munmap(surface->data, surface->row_bytes * surface->height); + if (surface->mmapped_buffer_) { + munmap(surface->mmapped_buffer_, surface->row_bytes * surface->height); } if (surface->fb_id) { @@ -113,15 +116,20 @@ GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int height) { *surface = {}; uint32_t format; -#if defined(RECOVERY_ABGR) - format = DRM_FORMAT_RGBA8888; -#elif defined(RECOVERY_BGRA) - format = DRM_FORMAT_ARGB8888; -#elif defined(RECOVERY_RGBX) - format = DRM_FORMAT_XBGR8888; -#else - format = DRM_FORMAT_RGB565; -#endif + PixelFormat pixel_format = gr_pixel_format(); + // PixelFormat comes in byte order, whereas DRM_FORMAT_* uses little-endian + // (external/libdrm/include/drm/drm_fourcc.h). Note that although drm_fourcc.h also defines a + // macro of DRM_FORMAT_BIG_ENDIAN, it doesn't seem to be actually supported (see the discussion + // in https://lists.freedesktop.org/archives/amd-gfx/2017-May/008560.html). + if (pixel_format == PixelFormat::ABGR) { + format = DRM_FORMAT_RGBA8888; + } else if (pixel_format == PixelFormat::BGRA) { + format = DRM_FORMAT_ARGB8888; + } else if (pixel_format == PixelFormat::RGBX) { + format = DRM_FORMAT_XBGR8888; + } else { + format = DRM_FORMAT_RGB565; + } drm_mode_create_dumb create_dumb = {}; create_dumb.height = height; @@ -164,15 +172,14 @@ GRSurfaceDrm* MinuiBackendDrm::DrmCreateSurface(int width, int 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) { + auto mmapped = mmap(nullptr, surface->height * surface->row_bytes, PROT_READ | PROT_WRITE, + MAP_SHARED, drm_fd, map_dumb.offset); + if (mmapped == MAP_FAILED) { perror("mmap() failed"); DrmDestroySurface(surface); return nullptr; } - + surface->mmapped_buffer_ = static_cast<uint8_t*>(mmapped); return surface; } @@ -368,18 +375,57 @@ GRSurface* MinuiBackendDrm::Init() { current_buffer = 0; - DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]); + // We will likely encounter errors in the backend functions (i.e. Flip) if EnableCrtc fails. + if (DrmEnableCrtc(drm_fd, main_monitor_crtc, GRSurfaceDrms[1]) != 0) { + return nullptr; + } return GRSurfaceDrms[0]; } +static void page_flip_complete(__unused int fd, + __unused unsigned int sequence, + __unused unsigned int tv_sec, + __unused unsigned int tv_usec, + void *user_data) { + *static_cast<bool*>(user_data) = false; +} + GRSurface* MinuiBackendDrm::Flip() { + bool ongoing_flip = true; + int ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id, - GRSurfaceDrms[current_buffer]->fb_id, 0, nullptr); + GRSurfaceDrms[current_buffer]->fb_id, + DRM_MODE_PAGE_FLIP_EVENT, &ongoing_flip); if (ret < 0) { printf("drmModePageFlip failed ret=%d\n", ret); return nullptr; } + + while (ongoing_flip) { + struct pollfd fds = { + .fd = drm_fd, + .events = POLLIN + }; + + ret = poll(&fds, 1, -1); + if (ret == -1 || !(fds.revents & POLLIN)) { + printf("poll() failed on drm fd\n"); + break; + } + + drmEventContext evctx = { + .version = DRM_EVENT_CONTEXT_VERSION, + .page_flip_handler = page_flip_complete + }; + + ret = drmHandleEvent(drm_fd, &evctx); + if (ret != 0) { + printf("drmHandleEvent failed ret=%d\n", ret); + break; + } + } + current_buffer = 1 - current_buffer; return GRSurfaceDrms[current_buffer]; } |