Skip to content

Latest commit

 

History

History
447 lines (375 loc) · 15.2 KB

SDL_kmsdrmmouse.c

File metadata and controls

447 lines (375 loc) · 15.2 KB
 
1
2
/*
Simple DirectMedia Layer
Jan 17, 2020
Jan 17, 2020
3
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Aug 25, 2020
Aug 25, 2020
4
Atomic KMSDRM backend by Manuel Alfayate Corchete <redwindwanderer@gmail.com>
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
Aug 22, 2017
Aug 22, 2017
22
23
24
25
26
27
28
29
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_KMSDRM
#include "SDL_kmsdrmvideo.h"
#include "SDL_kmsdrmmouse.h"
#include "SDL_kmsdrmdyn.h"
Jul 19, 2020
Jul 19, 2020
30
#include "SDL_assert.h"
31
32
33
34
35
36
37
38
39
40
41
42
#include "../../events/SDL_mouse_c.h"
#include "../../events/default_cursor.h"
static SDL_Cursor *KMSDRM_CreateDefaultCursor(void);
static SDL_Cursor *KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
static int KMSDRM_ShowCursor(SDL_Cursor * cursor);
static void KMSDRM_MoveCursor(SDL_Cursor * cursor);
static void KMSDRM_FreeCursor(SDL_Cursor * cursor);
static void KMSDRM_WarpMouse(SDL_Window * window, int x, int y);
static int KMSDRM_WarpMouseGlobal(int x, int y);
Aug 23, 2020
Aug 23, 2020
43
44
45
46
47
/**********************************/
/* Atomic helper functions block. */
/**********************************/
int
Aug 24, 2020
Aug 24, 2020
48
drm_atomic_movecursor(KMSDRM_CursorData *curdata, uint16_t x, uint16_t y)
Aug 23, 2020
Aug 23, 2020
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
{
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
if (!dispdata->cursor_plane) /* We can't move a non-existing cursor, but that's ok. */
return 0;
/* Do we have a set of changes already in the making? If not, allocate a new one. */
if (!dispdata->atomic_req)
dispdata->atomic_req = KMSDRM_drmModeAtomicAlloc();
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_X", x - curdata->hot_x);
add_plane_property(dispdata->atomic_req, dispdata->cursor_plane, "CRTC_Y", y - curdata->hot_y);
return 0;
}
/***************************************/
/* Atomic helper functions block ends. */
/***************************************/
Jul 19, 2020
Jul 19, 2020
69
70
71
72
73
/* Converts a pixel from straight-alpha [AA, RR, GG, BB], which the SDL cursor surface has,
to premultiplied-alpha [AA. AA*RR, AA*GG, AA*BB].
These multiplications have to be done with floats instead of uint32_t's, and the resulting values have
to be converted to be relative to the 0-255 interval, where 255 is 1.00 and anything between 0 and 255 is 0.xx. */
void alpha_premultiply_ARGB8888 (uint32_t *pixel) {
Jul 19, 2020
Jul 19, 2020
75
uint32_t A, R, G, B;
Nov 24, 2017
Nov 24, 2017
76
Jul 19, 2020
Jul 19, 2020
77
78
79
80
81
/* Component bytes extraction. */
A = (*pixel >> (3 << 3)) & 0xFF;
R = (*pixel >> (2 << 3)) & 0xFF;
G = (*pixel >> (1 << 3)) & 0xFF;
B = (*pixel >> (0 << 3)) & 0xFF;
Feb 9, 2020
Feb 9, 2020
82
Jul 19, 2020
Jul 19, 2020
83
84
85
86
/* Alpha pre-multiplication of each component. */
R = (float)A * ((float)R /255);
G = (float)A * ((float)G /255);
B = (float)A * ((float)B /255);
Nov 24, 2017
Nov 24, 2017
87
Jul 19, 2020
Jul 19, 2020
88
89
90
/* ARGB8888 pixel recomposition. */
(*pixel) = (((uint32_t)A << 24) | ((uint32_t)R << 16) | ((uint32_t)G << 8)) | ((uint32_t)B << 0);
}
Nov 24, 2017
Nov 24, 2017
91
Jul 19, 2020
Jul 19, 2020
92
93
94
95
static SDL_Cursor *
KMSDRM_CreateDefaultCursor(void)
{
return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
Nov 24, 2017
Nov 24, 2017
96
97
}
Jul 19, 2020
Jul 19, 2020
98
99
100
/* Create a GBM cursor from a surface, which means creating a hardware cursor.
Most programs use software cursors, but protracker-clone for example uses
an optional hardware cursor. */
101
102
103
104
static SDL_Cursor *
KMSDRM_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
{
SDL_VideoDevice *dev = SDL_GetVideoDevice();
Feb 9, 2020
Feb 9, 2020
105
SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
106
107
KMSDRM_CursorData *curdata;
SDL_Cursor *cursor;
Jul 19, 2020
Jul 19, 2020
108
109
110
uint64_t usable_cursor_w, usable_cursor_h;
uint32_t bo_stride, pixel;
uint32_t *buffer = NULL;
111
size_t bufsize;
Sep 26, 2020
Sep 26, 2020
112
unsigned int i, j;
Jul 19, 2020
Jul 19, 2020
114
115
116
117
118
/* All code below assumes ARGB8888 format for the cursor surface, like other backends do.
Also, the GBM BO pixels have to be alpha-premultiplied, but the SDL surface we receive has
straight-alpha pixels, so we always have to convert. */
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
SDL_assert(surface->pitch == surface->w * 4);
Jul 20, 2020
Jul 20, 2020
120
if (!KMSDRM_gbm_device_is_format_supported(viddata->gbm_dev, GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) {
Aug 23, 2020
Aug 23, 2020
121
SDL_SetError("Unsupported pixel format for cursor");
122
123
124
125
return NULL;
}
cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
Feb 9, 2020
Feb 9, 2020
126
if (!cursor) {
127
128
129
130
SDL_OutOfMemory();
return NULL;
}
curdata = (KMSDRM_CursorData *) SDL_calloc(1, sizeof(*curdata));
Feb 9, 2020
Feb 9, 2020
131
if (!curdata) {
132
133
134
135
136
SDL_OutOfMemory();
SDL_free(cursor);
return NULL;
}
Jul 19, 2020
Jul 19, 2020
137
138
139
140
141
/* Find out what GBM cursor size is recommended by the driver. */
if (KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_WIDTH, &usable_cursor_w) ||
KMSDRM_drmGetCap(viddata->drm_fd, DRM_CAP_CURSOR_HEIGHT, &usable_cursor_h)) {
SDL_SetError("Could not get the recommended GBM cursor size");
goto cleanup;
Nov 24, 2017
Nov 24, 2017
142
143
}
Sep 13, 2020
Sep 13, 2020
144
if (usable_cursor_w == 0 || usable_cursor_h == 0) {
Jul 19, 2020
Jul 19, 2020
145
146
SDL_SetError("Could not get an usable GBM cursor size");
goto cleanup;
Nov 24, 2017
Nov 24, 2017
147
148
}
Aug 23, 2020
Aug 23, 2020
149
/* hox_x and hot_y are the coordinates of the "tip of the cursor" from it's base. */
150
151
curdata->hot_x = hot_x;
curdata->hot_y = hot_y;
Nov 24, 2017
Nov 24, 2017
152
153
curdata->w = usable_cursor_w;
curdata->h = usable_cursor_h;
Jul 20, 2020
Jul 20, 2020
155
curdata->bo = KMSDRM_gbm_bo_create(viddata->gbm_dev, usable_cursor_w, usable_cursor_h, GBM_FORMAT_ARGB8888,
156
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
Nov 24, 2017
Nov 24, 2017
157
Feb 9, 2020
Feb 9, 2020
158
if (!curdata->bo) {
159
160
161
162
163
SDL_SetError("Could not create GBM cursor BO");
goto cleanup;
}
bo_stride = KMSDRM_gbm_bo_get_stride(curdata->bo);
Nov 24, 2017
Nov 24, 2017
164
bufsize = bo_stride * curdata->h;
Aug 17, 2020
Aug 17, 2020
166
167
168
/* Always use a temp buffer: it serves the purpose of storing the
alpha-premultiplied pixels (so we can copy them to the gbm BO
with a single gb_bo_write() call), and also copying from the
Jul 19, 2020
Jul 19, 2020
169
170
171
172
173
174
SDL surface, line by line, to a gbm BO with different pitch. */
buffer = (uint32_t*)SDL_malloc(bufsize);
if (!buffer) {
SDL_OutOfMemory();
goto cleanup;
}
Jul 19, 2020
Jul 19, 2020
176
177
178
179
180
181
if (SDL_MUSTLOCK(surface)) {
if (SDL_LockSurface(surface) < 0) {
/* Could not lock surface */
goto cleanup;
}
}
Jul 19, 2020
Jul 19, 2020
183
184
/* Clean the whole temporary buffer. */
SDL_memset(buffer, 0x00, bo_stride * curdata->h);
Jul 19, 2020
Jul 19, 2020
186
/* Copy from SDL surface to buffer, pre-multiplying by alpha each pixel as we go. */
Sep 26, 2020
Sep 26, 2020
187
188
for (i = 0; i < surface->h; i++) {
for (j = 0; j < surface->w; j++) {
Jul 19, 2020
Jul 19, 2020
189
190
191
pixel = ((uint32_t*)surface->pixels)[i * surface->w + j];
alpha_premultiply_ARGB8888 (&pixel);
SDL_memcpy(buffer + (i * curdata->w) + j, &pixel, 4);
Jul 19, 2020
Jul 19, 2020
193
}
Jul 19, 2020
Jul 19, 2020
195
196
197
if (SDL_MUSTLOCK(surface)) {
SDL_UnlockSurface(surface);
}
Jul 19, 2020
Jul 19, 2020
199
200
201
if (KMSDRM_gbm_bo_write(curdata->bo, buffer, bufsize)) {
SDL_SetError("Could not write to GBM cursor BO");
goto cleanup;
Jul 19, 2020
Jul 19, 2020
204
205
206
207
/* Free temporary buffer */
SDL_free(buffer);
buffer = NULL;
208
209
210
211
212
cursor->driverdata = curdata;
return cursor;
cleanup:
Feb 9, 2020
Feb 9, 2020
213
if (buffer) {
214
215
SDL_free(buffer);
}
Feb 9, 2020
Feb 9, 2020
216
if (cursor) {
217
218
SDL_free(cursor);
}
Feb 9, 2020
Feb 9, 2020
219
220
if (curdata) {
if (curdata->bo) {
221
222
223
224
225
226
227
KMSDRM_gbm_bo_destroy(curdata->bo);
}
SDL_free(curdata);
}
return NULL;
}
Aug 17, 2020
Aug 17, 2020
228
229
230
231
232
/* Show the specified cursor, or hide if cursor is NULL.
cur_cursor is the current cursor, and cursor is the new cursor.
A cursor is displayed on a display, so we have to add a pointer to dispdata
to the driverdata
*/
233
234
235
static int
KMSDRM_ShowCursor(SDL_Cursor * cursor)
{
Aug 17, 2020
Aug 17, 2020
236
237
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
//SDL_VideoData *viddata = ((SDL_VideoData *)dev->driverdata);
238
239
240
SDL_Mouse *mouse;
KMSDRM_CursorData *curdata;
SDL_VideoDisplay *display = NULL;
Feb 9, 2020
Feb 9, 2020
241
SDL_DisplayData *dispdata = NULL;
Aug 23, 2020
Aug 23, 2020
242
243
KMSDRM_FBInfo *fb;
KMSDRM_PlaneInfo info = {0};
244
245
mouse = SDL_GetMouse();
Feb 9, 2020
Feb 9, 2020
246
if (!mouse) {
247
248
249
return SDL_SetError("No mouse.");
}
Feb 9, 2020
Feb 9, 2020
250
if (mouse->focus) {
251
display = SDL_GetDisplayForWindow(mouse->focus);
Feb 9, 2020
Feb 9, 2020
252
253
if (display) {
dispdata = (SDL_DisplayData*) display->driverdata;
254
255
256
}
}
Aug 23, 2020
Aug 23, 2020
257
258
259
/**********************************/
/* if cursor == NULL, HIDE cursor */
/**********************************/
Feb 9, 2020
Feb 9, 2020
260
if (!cursor) {
Aug 17, 2020
Aug 17, 2020
261
/* Hide CURRENT cursor, a cursor that is already on screen
Sep 12, 2020
Sep 12, 2020
262
and SDL is stored in mouse->cur_cursor. */
Feb 9, 2020
Feb 9, 2020
263
if (mouse->cur_cursor && mouse->cur_cursor->driverdata) {
Sep 12, 2020
Sep 12, 2020
264
265
266
267
268
if (dispdata && dispdata->cursor_plane) {
info.plane = dispdata->cursor_plane; /* The rest of the members are zeroed. */
drm_atomic_set_plane_props(&info);
if (drm_atomic_commit(display->device, SDL_TRUE))
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
Sep 6, 2020
Sep 6, 2020
269
}
270
271
272
273
return 0;
}
return SDL_SetError("Couldn't find cursor to hide.");
}
Aug 17, 2020
Aug 17, 2020
274
Aug 23, 2020
Aug 23, 2020
275
276
277
/************************************************/
/* If cursor != NULL, DO show cursor on display */
/************************************************/
Feb 9, 2020
Feb 9, 2020
278
if (!display) {
279
280
return SDL_SetError("Could not get display for mouse.");
}
Feb 9, 2020
Feb 9, 2020
281
if (!dispdata) {
282
283
return SDL_SetError("Could not get display driverdata.");
}
Aug 23, 2020
Aug 23, 2020
284
285
286
if (!dispdata->cursor_plane) {
return SDL_SetError("Hardware cursor plane not initialized.");
}
Aug 17, 2020
Aug 17, 2020
287
288
curdata = (KMSDRM_CursorData *) cursor->driverdata;
Aug 23, 2020
Aug 23, 2020
289
Feb 9, 2020
Feb 9, 2020
290
if (!curdata || !curdata->bo) {
291
292
293
return SDL_SetError("Cursor not initialized properly.");
}
Aug 17, 2020
Aug 17, 2020
294
curdata->crtc_id = dispdata->crtc->crtc->crtc_id;
Aug 23, 2020
Aug 23, 2020
295
296
297
298
299
300
301
302
303
304
305
306
307
308
curdata->plane = dispdata->cursor_plane;
curdata->video = video_device;
fb = KMSDRM_FBFromBO(curdata->video, curdata->bo);
info.plane = dispdata->cursor_plane;
info.crtc_id = curdata->crtc_id;
info.fb_id = fb->fb_id;
info.src_w = curdata->w;
info.src_h = curdata->h;
info.crtc_x = mouse->x - curdata->hot_x;
info.crtc_y = mouse->y - curdata->hot_y;
info.crtc_w = curdata->w;
info.crtc_h = curdata->h;
Aug 17, 2020
Aug 17, 2020
309
Sep 12, 2020
Sep 12, 2020
310
drm_atomic_set_plane_props(&info);
Aug 17, 2020
Aug 17, 2020
311
Sep 6, 2020
Sep 6, 2020
312
313
if (drm_atomic_commit(display->device, SDL_TRUE)) {
return SDL_SetError("Failed atomic commit in KMSDRM_ShowCursor.");
314
315
316
317
}
return 0;
}
Aug 23, 2020
Aug 23, 2020
318
/* Unset the cursor from the cursor plane, and ONLY WHEN THAT'S DONE,
Aug 17, 2020
Aug 17, 2020
319
320
DONE FOR REAL, and not only requested, destroy it by destroying the curso BO.
Destroying the cursor BO is an special an delicate situation,
Aug 23, 2020
Aug 23, 2020
321
because drm_atomic_set_plane_props() returns immediately, and we DON'T
Aug 17, 2020
Aug 17, 2020
322
want to get to gbm_bo_destroy() before the prop changes requested
Aug 23, 2020
Aug 23, 2020
323
in drm_atomic_set_plane_props() have effectively been done. So we
Aug 17, 2020
Aug 17, 2020
324
325
326
327
issue a BLOCKING atomic_commit here to avoid that situation.
REMEMBER you yan issue an atomic_commit whenever you want, and
the changes requested until that moment (for any planes, crtcs, etc.)
will be done. */
328
329
330
static void
KMSDRM_FreeCursor(SDL_Cursor * cursor)
{
Aug 17, 2020
Aug 17, 2020
331
KMSDRM_CursorData *curdata = NULL;
Sep 12, 2020
Sep 12, 2020
332
SDL_VideoDevice *video_device = SDL_GetVideoDevice();
Aug 23, 2020
Aug 23, 2020
333
KMSDRM_PlaneInfo info = {0};
Feb 9, 2020
Feb 9, 2020
334
if (cursor) {
335
curdata = (KMSDRM_CursorData *) cursor->driverdata;
Sep 12, 2020
Sep 12, 2020
336
if (video_device && curdata->bo && curdata->plane) {
Aug 23, 2020
Aug 23, 2020
337
338
info.plane = curdata->plane; /* The other members are zeroed. */
drm_atomic_set_plane_props(&info);
Aug 17, 2020
Aug 17, 2020
339
/* Wait until the cursor is unset from the cursor plane before destroying it's BO. */
Sep 12, 2020
Sep 12, 2020
340
341
342
if (drm_atomic_commit(video_device, SDL_TRUE)) {
SDL_SetError("Failed atomic commit in KMSDRM_FreeCursor.");
}
Aug 17, 2020
Aug 17, 2020
343
344
KMSDRM_gbm_bo_destroy(curdata->bo);
curdata->bo = NULL;
Sep 12, 2020
Sep 12, 2020
346
347
348
349
/* Even if the cursor is not ours, free it. */
SDL_free(cursor->driverdata);
SDL_free(cursor);
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
}
}
/* Warp the mouse to (x,y) */
static void
KMSDRM_WarpMouse(SDL_Window * window, int x, int y)
{
/* Only one global/fullscreen window is supported */
KMSDRM_WarpMouseGlobal(x, y);
}
/* Warp the mouse to (x,y) */
static int
KMSDRM_WarpMouseGlobal(int x, int y)
{
KMSDRM_CursorData *curdata;
SDL_Mouse *mouse = SDL_GetMouse();
Feb 9, 2020
Feb 9, 2020
368
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
Dec 5, 2017
Dec 5, 2017
369
370
371
372
/* Update internal mouse position. */
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, 0, x, y);
/* And now update the cursor graphic position on screen. */
373
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
Feb 9, 2020
Feb 9, 2020
374
if (curdata->bo) {
Dec 5, 2017
Dec 5, 2017
375
Sep 6, 2020
Sep 6, 2020
376
377
if (drm_atomic_movecursor(curdata, x, y)) {
return SDL_SetError("drm_atomic_movecursor() failed.");
Aug 17, 2020
Aug 17, 2020
378
379
}
380
381
382
383
384
385
} else {
return SDL_SetError("Cursor not initialized properly.");
}
} else {
return SDL_SetError("No mouse or current cursor.");
}
Aug 23, 2020
Aug 23, 2020
386
return 0;
387
388
389
390
391
392
393
394
}
void
KMSDRM_InitMouse(_THIS)
{
/* FIXME: Using UDEV it should be possible to scan all mice
* but there's no point in doing so as there's no multimice support...yet!
*/
Aug 23, 2020
Aug 23, 2020
395
396
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
397
398
399
400
401
402
403
404
405
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = KMSDRM_CreateCursor;
mouse->ShowCursor = KMSDRM_ShowCursor;
mouse->MoveCursor = KMSDRM_MoveCursor;
mouse->FreeCursor = KMSDRM_FreeCursor;
mouse->WarpMouse = KMSDRM_WarpMouse;
mouse->WarpMouseGlobal = KMSDRM_WarpMouseGlobal;
Aug 23, 2020
Aug 23, 2020
406
407
408
409
410
/* Init cursor plane, if we haven't yet. */
if (!dispdata->cursor_plane) {
setup_plane(_this, &(dispdata->cursor_plane), DRM_PLANE_TYPE_CURSOR);
}
411
412
413
414
415
416
SDL_SetDefaultCursor(KMSDRM_CreateDefaultCursor());
}
void
KMSDRM_QuitMouse(_THIS)
{
Aug 23, 2020
Aug 23, 2020
417
418
419
/* Free the plane on which the cursor was being shown. */
SDL_DisplayData *dispdata = (SDL_DisplayData *)SDL_GetDisplayDriverData(0);
free_plane(&dispdata->cursor_plane);
420
421
422
423
424
425
426
}
/* This is called when a mouse motion event occurs */
static void
KMSDRM_MoveCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = SDL_GetMouse();
Dec 5, 2017
Dec 5, 2017
427
428
429
430
KMSDRM_CursorData *curdata;
/* We must NOT call SDL_SendMouseMotion() here or we will enter recursivity!
That's why we move the cursor graphic ONLY. */
Feb 9, 2020
Feb 9, 2020
431
if (mouse && mouse->cur_cursor && mouse->cur_cursor->driverdata) {
Dec 5, 2017
Dec 5, 2017
432
curdata = (KMSDRM_CursorData *) mouse->cur_cursor->driverdata;
Aug 18, 2020
Aug 18, 2020
433
434
435
436
437
/* Some programs expect cursor movement even while they don't do SwapWindow() calls,
and since we ride on the atomic_commit() in SwapWindow() for cursor movement,
cursor won't move in these situations. We could do an atomic_commit() for each
cursor movement request, but it cripples the movement to 30FPS, so a future solution
is needed. SDLPoP "QUIT?" menu is an example of this situation. */
Aug 17, 2020
Aug 17, 2020
438
Sep 6, 2020
Sep 6, 2020
439
if (drm_atomic_movecursor(curdata, mouse->x, mouse->y)) {
Aug 17, 2020
Aug 17, 2020
440
441
SDL_SetError("drm_atomic_movecursor() failed.");
}
Dec 5, 2017
Dec 5, 2017
442
}
443
444
445
446
447
}
#endif /* SDL_VIDEO_DRIVER_KMSDRM */
/* vi: set ts=4 sw=4 expandtab: */