From 0e53103957dd75be9140a474be343a6b7cc3cc9e Mon Sep 17 00:00:00 2001 From: JohnnyonFlame Date: Tue, 8 Aug 2023 03:55:43 -0300 Subject: [PATCH 5/7] KMSDRM: Rotation should respect panel orientation. --- src/video/kmsdrm/SDL_kmsdrmdyn.h | 8 ++ src/video/kmsdrm/SDL_kmsdrmmouse.c | 60 +++++++++++++- src/video/kmsdrm/SDL_kmsdrmvideo.c | 122 +++++++++++++++++++++++------ src/video/kmsdrm/SDL_kmsdrmvideo.h | 2 + 4 files changed, 166 insertions(+), 26 deletions(-) diff --git a/src/video/kmsdrm/SDL_kmsdrmdyn.h b/src/video/kmsdrm/SDL_kmsdrmdyn.h index 319e3f0e3..e17e97e8e 100644 --- a/src/video/kmsdrm/SDL_kmsdrmdyn.h +++ b/src/video/kmsdrm/SDL_kmsdrmdyn.h @@ -32,6 +32,14 @@ extern "C" { #endif +enum drm_panel_orientation { + DRM_MODE_PANEL_ORIENTATION_UNKNOWN = -1, + DRM_MODE_PANEL_ORIENTATION_NORMAL = 0, + DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP, + DRM_MODE_PANEL_ORIENTATION_LEFT_UP, + DRM_MODE_PANEL_ORIENTATION_RIGHT_UP, +}; + int SDL_KMSDRM_LoadSymbols(void); void SDL_KMSDRM_UnloadSymbols(void); diff --git a/src/video/kmsdrm/SDL_kmsdrmmouse.c b/src/video/kmsdrm/SDL_kmsdrmmouse.c index 4c445ecf1..5dcaaaab6 100644 --- a/src/video/kmsdrm/SDL_kmsdrmmouse.c +++ b/src/video/kmsdrm/SDL_kmsdrmmouse.c @@ -170,10 +170,30 @@ static int KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor) } /* Copy from the cursor buffer to a buffer that we can dump to the GBM BO. */ + uintptr_t src_buf = (uintptr_t)curdata->buffer; + uintptr_t dst_buf = (uintptr_t)ready_buffer; for (i = 0; i < curdata->h; i++) { for (j = 0; j < curdata->w; j++) { - src_row = ((uint32_t*)curdata->buffer)[i * curdata->w + j]; - SDL_memcpy(ready_buffer + ((curdata->w - j + 1) * bo_stride) + i, &src_row, 4); + uintptr_t src_pixel = src_buf + (i * curdata->w + j) * 4; + uintptr_t dst_pixel; + + int x, y; + if (dispdata->orientation == 0) { + x = j; + y = i; + } else if (dispdata->orientation == 1) { + x = curdata->w - i - 1; + y = j; + } else if (dispdata->orientation == 2) { + x = curdata->h - j - 1; + y = curdata->w - i - 1; + } else if (dispdata->orientation == 3) { + x = i; + y = curdata->h - j - 1; + } + + dst_pixel = dst_buf + (y * bo_stride + x * sizeof(uint32_t)); + *(uint32_t*)dst_pixel = *(uint32_t*)src_pixel; } } @@ -382,7 +402,23 @@ static int KMSDRM_WarpMouseGlobal(int x, int y) if (dispdata->cursor_bo) { int ret = 0; - ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, y, dispdata->mode.vdisplay + curdata->w - x); + if (dispdata->orientation == 0) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + x, + y); + } else if (dispdata->orientation == 1) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + dispdata->mode.hdisplay - curdata->h - y, + x); + } else if (dispdata->orientation == 2) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + dispdata->mode.hdisplay - curdata->w - x, + dispdata->mode.vdisplay - curdata->h - y); + } else if (dispdata->orientation == 3) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + y, + dispdata->mode.vdisplay - curdata->w - x); + } if (ret) { SDL_SetError("drmModeMoveCursor() failed."); @@ -443,7 +479,23 @@ static void KMSDRM_MoveCursor(SDL_Cursor *cursor) return; } - ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, mouse->y, dispdata->mode.vdisplay - curdata->w - mouse->x); + if (dispdata->orientation == 0) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + mouse->x, + mouse->y); + } else if (dispdata->orientation == 1) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + dispdata->mode.hdisplay - curdata->h - mouse->y, + mouse->x); + } else if (dispdata->orientation == 2) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + dispdata->mode.hdisplay - curdata->w - mouse->x, + dispdata->mode.vdisplay - curdata->h - mouse->y); + } else if (dispdata->orientation == 3) { + ret = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, + mouse->y, + dispdata->mode.vdisplay - curdata->w - mouse->x); + } if (ret) { SDL_SetError("drmModeMoveCursor() failed."); diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c index c5340afa8..663c4707c 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.c +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c @@ -336,24 +336,27 @@ static void KMSDRM_FBDestroyCallback(struct gbm_bo *bo, void *data) } static void -KMSDRM_InitRotateBuffer(_THIS, int frameWidth, int frameHeight) +KMSDRM_InitRotateBuffer(_THIS, int orientation, int frameWidth, int frameHeight) { - int l_frameHeight; + int l_frameHeight, l_frameWidth; SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata); // initialize 2D raster graphic acceleration unit (RGA) c_RkRgaInit(); - l_frameHeight = frameHeight; - if(l_frameHeight % 32 != 0) { - l_frameHeight = (frameHeight + 32) & (~31); + if (orientation & 1) { + l_frameWidth = frameWidth; + l_frameHeight = (frameHeight + 31) & (~31); + } else { + l_frameWidth = (frameWidth + 31) & (~31); + l_frameHeight = frameHeight; } // create buffers for RGA with adjusted stride for (int i = 0; i < RGA_BUFFERS_MAX; ++i) { viddata->rga_buffers[i] = KMSDRM_gbm_bo_create(viddata->gbm_dev, - frameWidth, l_frameHeight, + l_frameWidth, l_frameHeight, GBM_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); assert(viddata->rga_buffers[i]); @@ -364,10 +367,18 @@ KMSDRM_InitRotateBuffer(_THIS, int frameWidth, int frameHeight) // setup rotation src_info.fd = -1; src_info.mmuFlag = 1; - src_info.rotation = HAL_TRANSFORM_ROT_270; + switch (orientation) { + default: src_info.rotation = 0; break; + case 1: src_info.rotation = HAL_TRANSFORM_ROT_90; break; + case 2: src_info.rotation = HAL_TRANSFORM_ROT_180; break; + case 3: src_info.rotation = HAL_TRANSFORM_ROT_270; break; + } // swap width and height and adjust stride here because our source buffer is 480x854 - rga_set_rect(&src_info.rect, 0, 0, frameHeight, frameWidth, l_frameHeight, frameWidth, RK_FORMAT_BGRA_8888); + if (orientation & 1) + rga_set_rect(&src_info.rect, 0, 0, frameHeight, frameWidth, l_frameHeight, l_frameWidth, RK_FORMAT_BGRA_8888); + else + rga_set_rect(&src_info.rect, 0, 0, frameWidth, frameHeight, l_frameWidth, l_frameHeight, RK_FORMAT_BGRA_8888); dst_info.fd = -1; dst_info.mmuFlag = 1; @@ -617,6 +628,52 @@ static SDL_bool KMSDRM_VrrPropId(uint32_t drm_fd, uint32_t crtc_id, uint32_t *vr return SDL_TRUE; } +static int KMSDRM_ConnectorGetOrientation(uint32_t drm_fd, + uint32_t output_id) +{ + uint32_t i; + SDL_bool found = SDL_FALSE; + uint64_t orientation = DRM_MODE_PANEL_ORIENTATION_NORMAL; + + drmModeObjectPropertiesPtr props = KMSDRM_drmModeObjectGetProperties(drm_fd, + output_id, + DRM_MODE_OBJECT_CONNECTOR); + + // Allow forcing specific orientations for debugging. + const char *override = SDL_getenv("SDL_KMSDRM_ORIENTATION"); + if (override && override[0] != '\0') { + int val = SDL_atoi(override); + return SDL_clamp(val, 0, 3); + } + + if (!props) { + return 0; + } + + for (i = 0; !found && i < props->count_props; ++i) { + drmModePropertyPtr drm_prop = KMSDRM_drmModeGetProperty(drm_fd, props->props[i]); + + if (!drm_prop) { + continue; + } + + if (SDL_strcasecmp(drm_prop->name, "panel orientation") == 0) { + orientation = props->prop_values[i]; + found = SDL_TRUE; + } + + KMSDRM_drmModeFreeProperty(drm_prop); + } + + /* librga expresses rotations clockwise. (e.g., dts = 90? rga = 270!) */ + switch (orientation) { + default: return 0; + case DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP: return 2; + case DRM_MODE_PANEL_ORIENTATION_LEFT_UP: return 1; + case DRM_MODE_PANEL_ORIENTATION_RIGHT_UP: return 3; + } +} + static SDL_bool KMSDRM_ConnectorCheckVrrCapable(uint32_t drm_fd, uint32_t output_id, char const *name) @@ -869,6 +926,8 @@ static void KMSDRM_AddDisplay(_THIS, drmModeConnector *connector, drmModeRes *re dispdata->connector = connector; dispdata->crtc = crtc; + /* store current connector orientation */ + dispdata->orientation = KMSDRM_ConnectorGetOrientation(viddata->drm_fd, connector->connector_id); /* save previous vrr state */ dispdata->saved_vrr = KMSDRM_CrtcGetVrr(viddata->drm_fd, crtc->crtc_id); /* try to enable vrr */ @@ -893,8 +952,13 @@ static void KMSDRM_AddDisplay(_THIS, drmModeConnector *connector, drmModeRes *re modedata->mode_index = mode_index; display.driverdata = dispdata; - display.desktop_mode.w = dispdata->mode.vdisplay; - display.desktop_mode.h = dispdata->mode.hdisplay; + if (dispdata->orientation & 1) { + display.desktop_mode.w = dispdata->mode.vdisplay; + display.desktop_mode.h = dispdata->mode.hdisplay; + } else { + display.desktop_mode.w = dispdata->mode.hdisplay; + display.desktop_mode.h = dispdata->mode.vdisplay; + } display.desktop_mode.refresh_rate = dispdata->mode.vrefresh; display.desktop_mode.format = SDL_PIXELFORMAT_ARGB8888; display.desktop_mode.driverdata = modedata; @@ -1158,8 +1222,10 @@ static void KMSDRM_GetModeToSet(SDL_Window *window, drmModeModeInfo *out_mode) static void KMSDRM_DirtySurfaces(SDL_Window *window) { - SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; drmModeModeInfo mode; + SDL_WindowData *windata = (SDL_WindowData *)window->driverdata; + SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window); + SDL_DisplayData *dispdata = (SDL_DisplayData *)display->driverdata; /* Can't recreate EGL surfaces right now, need to wait until SwapWindow so the correct thread-local surface and context state are available */ @@ -1169,8 +1235,10 @@ static void KMSDRM_DirtySurfaces(SDL_Window *window) or SetWindowFullscreen, send a fake event for now since the actual recreation is deferred */ KMSDRM_GetModeToSet(window, &mode); - SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode.vdisplay, mode.hdisplay); - + if (dispdata->orientation & 1) + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode.vdisplay, mode.hdisplay); + else + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, mode.hdisplay, mode.vdisplay); } /* This determines the size of the fb, which comes from the GBM surface @@ -1204,14 +1272,18 @@ int KMSDRM_CreateSurfaces(_THIS, SDL_Window *window) SDL_video.c expects. Hulk-smash the display's current_mode to keep the mode that's set in sync with what SDL_video.c thinks is set */ KMSDRM_GetModeToSet(window, &dispdata->mode); - - display->current_mode.w = dispdata->mode.vdisplay; - display->current_mode.h = dispdata->mode.hdisplay; + if (dispdata->orientation & 1) { + display->current_mode.w = dispdata->mode.vdisplay; + display->current_mode.h = dispdata->mode.hdisplay; + } else { + display->current_mode.w = dispdata->mode.hdisplay; + display->current_mode.h = dispdata->mode.vdisplay; + } display->current_mode.refresh_rate = dispdata->mode.vrefresh; display->current_mode.format = SDL_PIXELFORMAT_ARGB8888; windata->gs = KMSDRM_gbm_surface_create(viddata->gbm_dev, - dispdata->mode.vdisplay, dispdata->mode.hdisplay, + display->current_mode.w, display->current_mode.h, surface_fmt, surface_flags); if (!windata->gs) { @@ -1235,7 +1307,7 @@ int KMSDRM_CreateSurfaces(_THIS, SDL_Window *window) ret = SDL_EGL_MakeCurrent(_this, windata->egl_surface, egl_context); SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, - dispdata->mode.vdisplay, dispdata->mode.hdisplay); + display->current_mode.w, display->current_mode.h); windata->egl_surface_dirty = SDL_FALSE; @@ -1318,8 +1390,14 @@ void KMSDRM_GetDisplayModes(_THIS, SDL_VideoDisplay *display) modedata->mode_index = i; } - mode.w = conn->modes[i].vdisplay; - mode.h = conn->modes[i].hdisplay; + if (dispdata->orientation & 1) { + mode.w = conn->modes[i].vdisplay; + mode.h = conn->modes[i].hdisplay; + } else { + mode.w = conn->modes[i].hdisplay; + mode.h = conn->modes[i].vdisplay; + } + mode.refresh_rate = conn->modes[i].vrefresh; mode.format = SDL_PIXELFORMAT_ARGB8888; mode.driverdata = modedata; @@ -1573,8 +1651,8 @@ int KMSDRM_CreateWindow(_THIS, SDL_Window *window) SDL_SetMouseFocus(window); SDL_SetKeyboardFocus(window); - data = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; - KMSDRM_InitRotateBuffer(_this, data->mode.hdisplay, data->mode.vdisplay); + data = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata; + KMSDRM_InitRotateBuffer(_this, dispdata->orientation, data->mode.hdisplay, data->mode.vdisplay); /* Tell the app that the window has moved to top-left. */ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, 0, 0); diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h index 890575fb8..8d2dc646f 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvideo.h +++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h @@ -78,6 +78,8 @@ typedef struct SDL_DisplayData drmModeCrtc *saved_crtc; /* CRTC to restore on quit */ SDL_bool saved_vrr; + + uint64_t orientation; /* DRM & GBM cursor stuff lives here, not in an SDL_Cursor's driverdata struct, because setting/unsetting up these is done on window creation/destruction, -- 2.20.1