Skip to content

Commit ed93dde

Browse files
committed
kmsdrm: Restore atomic support.
1 parent 8d5b82b commit ed93dde

File tree

6 files changed

+1084
-94
lines changed

6 files changed

+1084
-94
lines changed

src/video/kmsdrm/SDL_kmsdrmmouse.c

Lines changed: 113 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ void KMSDRM_DestroyCursorBO(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
6767

6868
// Destroy the curso GBM BO.
6969
if (dispdata->cursor_bo) {
70+
SDL_VideoData *viddata = (SDL_VideoData *) _this->internal;
71+
if (viddata->is_atomic) {
72+
if (dispdata->cursor_plane) {
73+
// Unset the the cursor BO from the cursor plane.
74+
KMSDRM_PlaneInfo info;
75+
SDL_zero(info);
76+
info.plane = dispdata->cursor_plane;
77+
drm_atomic_set_plane_props(&info);
78+
// Wait until the cursor is unset from the cursor plane before destroying it's BO.
79+
if (drm_atomic_commit(_this, true, false)) {
80+
SDL_SetError("Failed atomic commit in KMSDRM_DenitMouse.");
81+
}
82+
// Free the cursor plane, on which the cursor was being shown.
83+
free_plane(&dispdata->cursor_plane);
84+
}
85+
}
86+
7087
KMSDRM_gbm_bo_destroy(dispdata->cursor_bo);
7188
dispdata->cursor_bo = NULL;
7289
dispdata->cursor_bo_drm_fd = -1;
@@ -78,11 +95,14 @@ void KMSDRM_DestroyCursorBO(SDL_VideoDevice *_this, SDL_VideoDisplay *display)
7895
build a window and assign a display to it. */
7996
bool KMSDRM_CreateCursorBO(SDL_VideoDisplay *display)
8097
{
81-
8298
SDL_VideoDevice *dev = SDL_GetVideoDevice();
8399
SDL_VideoData *viddata = dev->internal;
84100
SDL_DisplayData *dispdata = display->internal;
85101

102+
if (viddata->is_atomic) {
103+
setup_plane(dev, &dispdata->cursor_plane, DRM_PLANE_TYPE_CURSOR);
104+
}
105+
86106
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev,
87107
GBM_FORMAT_ARGB8888,
88108
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) {
@@ -121,15 +141,29 @@ static bool KMSDRM_RemoveCursorFromBO(SDL_VideoDisplay *display)
121141
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
122142
SDL_VideoData *viddata = video_device->internal;
123143

124-
const int rc = KMSDRM_drmModeSetCursor(viddata->drm_fd, dispdata->crtc->crtc_id, 0, 0, 0);
125-
if (rc < 0) {
126-
result = SDL_SetError("drmModeSetCursor() failed: %s", strerror(-rc));
144+
if (viddata->is_atomic) {
145+
if (dispdata->cursor_plane) {
146+
KMSDRM_PlaneInfo info;
147+
SDL_zero(info);
148+
info.plane = dispdata->cursor_plane;
149+
// The rest of the members are zeroed, so this takes away the cursor from the cursor plane.
150+
drm_atomic_set_plane_props(&info);
151+
if (drm_atomic_commit(video_device, true, false)) {
152+
result = SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
153+
}
154+
}
155+
} else {
156+
const int rc = KMSDRM_drmModeSetCursor(viddata->drm_fd, dispdata->crtc.crtc->crtc_id, 0, 0, 0);
157+
if (rc < 0) {
158+
result = SDL_SetError("drmModeSetCursor() failed: %s", strerror(-rc));
159+
}
127160
}
161+
128162
return result;
129163
}
130164

131165
// Dump a cursor buffer to a display's DRM cursor BO.
132-
static bool KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
166+
static bool KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Mouse *mouse, SDL_Cursor *cursor)
133167
{
134168
SDL_DisplayData *dispdata = display->internal;
135169
SDL_CursorData *curdata = cursor->internal;
@@ -173,22 +207,42 @@ static bool KMSDRM_DumpCursorToBO(SDL_VideoDisplay *display, SDL_Cursor *cursor)
173207
goto cleanup;
174208
}
175209

176-
// Put the GBM BO buffer on screen using the DRM interface.
177-
bo_handle = KMSDRM_gbm_bo_get_handle(dispdata->cursor_bo).u32;
178-
if (curdata->hot_x == 0 && curdata->hot_y == 0) {
179-
rc = KMSDRM_drmModeSetCursor(viddata->drm_fd, dispdata->crtc->crtc_id,
180-
bo_handle, dispdata->cursor_w, dispdata->cursor_h);
210+
if (viddata->is_atomic) {
211+
// Get the fb_id for the GBM BO so we can show it on the cursor plane.
212+
KMSDRM_FBInfo *fb = KMSDRM_FBFromBO(video_device, dispdata->cursor_bo);
213+
KMSDRM_PlaneInfo info;
214+
215+
// Show the GBM BO buffer on the cursor plane.
216+
SDL_zero(info);
217+
info.plane = dispdata->cursor_plane;
218+
info.crtc_id = dispdata->crtc.crtc->crtc_id;
219+
info.fb_id = fb->fb_id;
220+
info.src_w = dispdata->cursor_w;
221+
info.src_h = dispdata->cursor_h;
222+
info.crtc_x = ((int32_t) SDL_roundf(mouse->x)) - curdata->hot_x;
223+
info.crtc_y = ((int32_t) SDL_roundf(mouse->y)) - curdata->hot_y;
224+
info.crtc_w = curdata->w;
225+
info.crtc_h = curdata->h;
226+
drm_atomic_set_plane_props(&info);
227+
if (drm_atomic_commit(video_device, true, false)) {
228+
result = SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
229+
goto cleanup;
230+
}
181231
} else {
182-
rc = KMSDRM_drmModeSetCursor2(viddata->drm_fd, dispdata->crtc->crtc_id,
183-
bo_handle, dispdata->cursor_w, dispdata->cursor_h, curdata->hot_x, curdata->hot_y);
184-
}
185-
if (rc < 0) {
186-
result = SDL_SetError("Failed to set DRM cursor: %s", strerror(-rc));
187-
goto cleanup;
232+
// Put the GBM BO buffer on screen using the DRM interface.
233+
bo_handle = KMSDRM_gbm_bo_get_handle(dispdata->cursor_bo).u32;
234+
if (curdata->hot_x == 0 && curdata->hot_y == 0) {
235+
rc = KMSDRM_drmModeSetCursor(viddata->drm_fd, dispdata->crtc.crtc->crtc_id, bo_handle, dispdata->cursor_w, dispdata->cursor_h);
236+
} else {
237+
rc = KMSDRM_drmModeSetCursor2(viddata->drm_fd, dispdata->crtc.crtc->crtc_id, bo_handle, dispdata->cursor_w, dispdata->cursor_h, curdata->hot_x, curdata->hot_y);
238+
}
239+
if (rc < 0) {
240+
result = SDL_SetError("Failed to set DRM cursor: %s", strerror(-rc));
241+
goto cleanup;
242+
}
188243
}
189244

190245
cleanup:
191-
192246
if (ready_buffer) {
193247
SDL_free(ready_buffer);
194248
}
@@ -316,7 +370,7 @@ static bool KMSDRM_ShowCursor(SDL_Cursor *cursor)
316370
if (cursor) {
317371
/* Dump the cursor to the display DRM cursor BO so it becomes visible
318372
on that display. */
319-
result = KMSDRM_DumpCursorToBO(display, cursor);
373+
result = KMSDRM_DumpCursorToBO(display, mouse, cursor);
320374
} else {
321375
// Hide the cursor on that display.
322376
result = KMSDRM_RemoveCursorFromBO(display);
@@ -327,6 +381,19 @@ static bool KMSDRM_ShowCursor(SDL_Cursor *cursor)
327381
return result;
328382
}
329383

384+
static void drm_atomic_movecursor(const SDL_CursorData *curdata, uint16_t x, uint16_t y)
385+
{
386+
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
387+
if (dispdata->cursor_plane) { // We can't move a non-existing cursor, but that's ok.
388+
// Do we have a set of changes already in the making? If not, allocate a new one.
389+
if (!dispdata->atomic_req) {
390+
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
391+
}
392+
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_X", x - curdata->hot_x);
393+
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_Y", y - curdata->hot_y);
394+
}
395+
}
396+
330397
static bool KMSDRM_WarpMouseGlobal(float x, float y)
331398
{
332399
SDL_Mouse *mouse = SDL_GetMouse();
@@ -340,17 +407,25 @@ static bool KMSDRM_WarpMouseGlobal(float x, float y)
340407

341408
// And now update the cursor graphic position on screen.
342409
if (dispdata->cursor_bo) {
343-
const int rc = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, (int)x, (int)y);
344-
if (rc < 0) {
345-
return SDL_SetError("drmModeMoveCursor() failed: %s", strerror(-rc));
410+
SDL_VideoDevice *dev = SDL_GetVideoDevice();
411+
SDL_VideoData *viddata = dev->internal;
412+
if (viddata->is_atomic) {
413+
const SDL_CursorData *curdata = (const SDL_CursorData *) mouse->cur_cursor->internal;
414+
drm_atomic_movecursor(curdata, (uint16_t) (int) x, (uint16_t) (int) y);
415+
} else {
416+
const int rc = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc.crtc->crtc_id, (int)x, (int)y);
417+
if (rc < 0) {
418+
return SDL_SetError("drmModeMoveCursor() failed: %s", strerror(-rc));
419+
}
346420
}
347-
return true;
348421
} else {
349422
return SDL_SetError("Cursor not initialized properly.");
350423
}
351424
} else {
352425
return SDL_SetError("No mouse or current cursor.");
353426
}
427+
428+
return true;
354429
}
355430

356431
static bool KMSDRM_WarpMouse(SDL_Window *window, float x, float y)
@@ -394,14 +469,27 @@ static bool KMSDRM_MoveCursor(SDL_Cursor *cursor)
394469
if (mouse && mouse->cur_cursor && mouse->focus) {
395470
SDL_Window *window = mouse->focus;
396471
SDL_DisplayData *dispdata = SDL_GetDisplayDriverDataForWindow(window);
472+
SDL_VideoDevice *dev = SDL_GetVideoDevice();
473+
SDL_VideoData *viddata = dev->internal;
397474

398475
if (!dispdata->cursor_bo) {
399476
return SDL_SetError("Cursor not initialized properly.");
400477
}
401478

402-
const int rc = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc->crtc_id, (int)mouse->x, (int)mouse->y);
403-
if (rc < 0) {
404-
return SDL_SetError("drmModeMoveCursor() failed: %s", strerror(-rc));
479+
if (viddata->is_atomic) {
480+
/* !!! FIXME: Some programs expect cursor movement even while they don't do SwapWindow() calls,
481+
and since we ride on the atomic_commit() in SwapWindow() for cursor movement,
482+
cursor won't move in these situations. We could do an atomic_commit() here
483+
for each cursor movement request, but it cripples the movement to 30FPS,
484+
so a future solution is needed. SDLPoP "QUIT?" menu is an example of this
485+
situation. */
486+
const SDL_CursorData *curdata = (const SDL_CursorData *) mouse->cur_cursor->internal;
487+
drm_atomic_movecursor(curdata, (uint16_t) (int) mouse->x, (uint16_t) (int) mouse->y);
488+
} else {
489+
const int rc = KMSDRM_drmModeMoveCursor(dispdata->cursor_bo_drm_fd, dispdata->crtc.crtc->crtc_id, (int)mouse->x, (int)mouse->y);
490+
if (rc < 0) {
491+
return SDL_SetError("drmModeMoveCursor() failed: %s", strerror(-rc));
492+
}
405493
}
406494
}
407495
return true;

0 commit comments

Comments
 (0)