@@ -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 (dispdata , & info );
78+ // Wait until the cursor is unset from the cursor plane before destroying it's BO.
79+ if (drm_atomic_commit (_this , dispdata , 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. */
7996bool 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 , & 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 (dispdata , & info );
151+ if (drm_atomic_commit (video_device , dispdata , 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 (dispdata , & info );
227+ if (drm_atomic_commit (video_device , dispdata , 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
190245cleanup :
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,18 @@ static bool KMSDRM_ShowCursor(SDL_Cursor *cursor)
327381 return result ;
328382}
329383
384+ static void drm_atomic_movecursor (SDL_DisplayData * dispdata , const SDL_CursorData * curdata , uint16_t x , uint16_t y )
385+ {
386+ if (dispdata -> cursor_plane ) { // We can't move a non-existing cursor, but that's ok.
387+ // Do we have a set of changes already in the making? If not, allocate a new one.
388+ if (!dispdata -> atomic_req ) {
389+ dispdata -> atomic_req = KMSDRM_drmModeAtomicAlloc ();
390+ }
391+ add_plane_property (dispdata -> atomic_req , dispdata -> cursor_plane , "CRTC_X" , x - curdata -> hot_x );
392+ add_plane_property (dispdata -> atomic_req , dispdata -> cursor_plane , "CRTC_Y" , y - curdata -> hot_y );
393+ }
394+ }
395+
330396static bool KMSDRM_WarpMouseGlobal (float x , float y )
331397{
332398 SDL_Mouse * mouse = SDL_GetMouse ();
@@ -340,17 +406,25 @@ static bool KMSDRM_WarpMouseGlobal(float x, float y)
340406
341407 // And now update the cursor graphic position on screen.
342408 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 ));
409+ SDL_VideoDevice * dev = SDL_GetVideoDevice ();
410+ SDL_VideoData * viddata = dev -> internal ;
411+ if (viddata -> is_atomic ) {
412+ const SDL_CursorData * curdata = (const SDL_CursorData * ) mouse -> cur_cursor -> internal ;
413+ drm_atomic_movecursor (dispdata , curdata , (uint16_t ) (int ) x , (uint16_t ) (int ) y );
414+ } else {
415+ const int rc = KMSDRM_drmModeMoveCursor (dispdata -> cursor_bo_drm_fd , dispdata -> crtc .crtc -> crtc_id , (int )x , (int )y );
416+ if (rc < 0 ) {
417+ return SDL_SetError ("drmModeMoveCursor() failed: %s" , strerror (- rc ));
418+ }
346419 }
347- return true;
348420 } else {
349421 return SDL_SetError ("Cursor not initialized properly." );
350422 }
351423 } else {
352424 return SDL_SetError ("No mouse or current cursor." );
353425 }
426+
427+ return true;
354428}
355429
356430static bool KMSDRM_WarpMouse (SDL_Window * window , float x , float y )
@@ -394,14 +468,27 @@ static bool KMSDRM_MoveCursor(SDL_Cursor *cursor)
394468 if (mouse && mouse -> cur_cursor && mouse -> focus ) {
395469 SDL_Window * window = mouse -> focus ;
396470 SDL_DisplayData * dispdata = SDL_GetDisplayDriverDataForWindow (window );
471+ SDL_VideoDevice * dev = SDL_GetVideoDevice ();
472+ SDL_VideoData * viddata = dev -> internal ;
397473
398474 if (!dispdata -> cursor_bo ) {
399475 return SDL_SetError ("Cursor not initialized properly." );
400476 }
401477
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 ));
478+ if (viddata -> is_atomic ) {
479+ /* !!! FIXME: Some programs expect cursor movement even while they don't do SwapWindow() calls,
480+ and since we ride on the atomic_commit() in SwapWindow() for cursor movement,
481+ cursor won't move in these situations. We could do an atomic_commit() here
482+ for each cursor movement request, but it cripples the movement to 30FPS,
483+ so a future solution is needed. SDLPoP "QUIT?" menu is an example of this
484+ situation. */
485+ const SDL_CursorData * curdata = (const SDL_CursorData * ) mouse -> cur_cursor -> internal ;
486+ drm_atomic_movecursor (dispdata , curdata , (uint16_t ) (int ) mouse -> x , (uint16_t ) (int ) mouse -> y );
487+ } else {
488+ const int rc = KMSDRM_drmModeMoveCursor (dispdata -> cursor_bo_drm_fd , dispdata -> crtc .crtc -> crtc_id , (int )mouse -> x , (int )mouse -> y );
489+ if (rc < 0 ) {
490+ return SDL_SetError ("drmModeMoveCursor() failed: %s" , strerror (- rc ));
491+ }
405492 }
406493 }
407494 return true;
0 commit comments