SDL  2.0
SDL_udev.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /*
23  * To list the properties of a device, try something like:
24  * udevadm info -a -n snd/hwC0D0 (for a sound card)
25  * udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
26  * udevadm info --query=property -n input/event2
27  */
28 #include "SDL_udev.h"
29 
30 #ifdef SDL_USE_LIBUDEV
31 
32 #include <linux/input.h>
33 
34 #include "SDL_assert.h"
35 #include "SDL_loadso.h"
36 #include "SDL_timer.h"
37 #include "SDL_hints.h"
38 #include "../unix/SDL_poll.h"
39 
40 static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
41 
42 #define _THIS SDL_UDEV_PrivateData *_this
43 static _THIS = NULL;
44 
45 static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
46 static int SDL_UDEV_load_syms(void);
47 static SDL_bool SDL_UDEV_hotplug_update_available(void);
48 static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
49 
50 static SDL_bool
51 SDL_UDEV_load_sym(const char *fn, void **addr)
52 {
53  *addr = SDL_LoadFunction(_this->udev_handle, fn);
54  if (*addr == NULL) {
55  /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
56  return SDL_FALSE;
57  }
58 
59  return SDL_TRUE;
60 }
61 
62 static int
63 SDL_UDEV_load_syms(void)
64 {
65  /* cast funcs to char* first, to please GCC's strict aliasing rules. */
66  #define SDL_UDEV_SYM(x) \
67  if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->syms.x)) return -1
68 
69  SDL_UDEV_SYM(udev_device_get_action);
70  SDL_UDEV_SYM(udev_device_get_devnode);
71  SDL_UDEV_SYM(udev_device_get_subsystem);
72  SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype);
73  SDL_UDEV_SYM(udev_device_get_property_value);
74  SDL_UDEV_SYM(udev_device_get_sysattr_value);
75  SDL_UDEV_SYM(udev_device_new_from_syspath);
76  SDL_UDEV_SYM(udev_device_unref);
77  SDL_UDEV_SYM(udev_enumerate_add_match_property);
78  SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
79  SDL_UDEV_SYM(udev_enumerate_get_list_entry);
80  SDL_UDEV_SYM(udev_enumerate_new);
81  SDL_UDEV_SYM(udev_enumerate_scan_devices);
82  SDL_UDEV_SYM(udev_enumerate_unref);
83  SDL_UDEV_SYM(udev_list_entry_get_name);
84  SDL_UDEV_SYM(udev_list_entry_get_next);
85  SDL_UDEV_SYM(udev_monitor_enable_receiving);
86  SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
87  SDL_UDEV_SYM(udev_monitor_get_fd);
88  SDL_UDEV_SYM(udev_monitor_new_from_netlink);
89  SDL_UDEV_SYM(udev_monitor_receive_device);
90  SDL_UDEV_SYM(udev_monitor_unref);
91  SDL_UDEV_SYM(udev_new);
92  SDL_UDEV_SYM(udev_unref);
93  SDL_UDEV_SYM(udev_device_new_from_devnum);
94  SDL_UDEV_SYM(udev_device_get_devnum);
95  #undef SDL_UDEV_SYM
96 
97  return 0;
98 }
99 
100 static SDL_bool
101 SDL_UDEV_hotplug_update_available(void)
102 {
103  if (_this->udev_mon != NULL) {
104  const int fd = _this->syms.udev_monitor_get_fd(_this->udev_mon);
105  if (SDL_IOReady(fd, SDL_FALSE, 0)) {
106  return SDL_TRUE;
107  }
108  }
109  return SDL_FALSE;
110 }
111 
112 
113 int
114 SDL_UDEV_Init(void)
115 {
116  int retval = 0;
117 
118  if (_this == NULL) {
119  _this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
120  if(_this == NULL) {
121  return SDL_OutOfMemory();
122  }
123 
124  retval = SDL_UDEV_LoadLibrary();
125  if (retval < 0) {
126  SDL_UDEV_Quit();
127  return retval;
128  }
129 
130  /* Set up udev monitoring
131  * Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
132  */
133 
134  _this->udev = _this->syms.udev_new();
135  if (_this->udev == NULL) {
136  SDL_UDEV_Quit();
137  return SDL_SetError("udev_new() failed");
138  }
139 
140  _this->udev_mon = _this->syms.udev_monitor_new_from_netlink(_this->udev, "udev");
141  if (_this->udev_mon == NULL) {
142  SDL_UDEV_Quit();
143  return SDL_SetError("udev_monitor_new_from_netlink() failed");
144  }
145 
146  _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
147  _this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
148  _this->syms.udev_monitor_enable_receiving(_this->udev_mon);
149 
150  /* Do an initial scan of existing devices */
151  SDL_UDEV_Scan();
152 
153  }
154 
155  _this->ref_count += 1;
156 
157  return retval;
158 }
159 
160 void
161 SDL_UDEV_Quit(void)
162 {
163  SDL_UDEV_CallbackList *item;
164 
165  if (_this == NULL) {
166  return;
167  }
168 
169  _this->ref_count -= 1;
170 
171  if (_this->ref_count < 1) {
172 
173  if (_this->udev_mon != NULL) {
174  _this->syms.udev_monitor_unref(_this->udev_mon);
175  _this->udev_mon = NULL;
176  }
177  if (_this->udev != NULL) {
178  _this->syms.udev_unref(_this->udev);
179  _this->udev = NULL;
180  }
181 
182  /* Remove existing devices */
183  while (_this->first != NULL) {
184  item = _this->first;
185  _this->first = _this->first->next;
186  SDL_free(item);
187  }
188 
189  SDL_UDEV_UnloadLibrary();
190  SDL_free(_this);
191  _this = NULL;
192  }
193 }
194 
195 void
196 SDL_UDEV_Scan(void)
197 {
198  struct udev_enumerate *enumerate = NULL;
199  struct udev_list_entry *devs = NULL;
200  struct udev_list_entry *item = NULL;
201 
202  if (_this == NULL) {
203  return;
204  }
205 
206  enumerate = _this->syms.udev_enumerate_new(_this->udev);
207  if (enumerate == NULL) {
208  SDL_UDEV_Quit();
209  SDL_SetError("udev_enumerate_new() failed");
210  return;
211  }
212 
213  _this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
214  _this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
215 
216  _this->syms.udev_enumerate_scan_devices(enumerate);
217  devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
218  for (item = devs; item; item = _this->syms.udev_list_entry_get_next(item)) {
219  const char *path = _this->syms.udev_list_entry_get_name(item);
220  struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
221  if (dev != NULL) {
222  device_event(SDL_UDEV_DEVICEADDED, dev);
223  _this->syms.udev_device_unref(dev);
224  }
225  }
226 
227  _this->syms.udev_enumerate_unref(enumerate);
228 }
229 
230 
231 void
232 SDL_UDEV_UnloadLibrary(void)
233 {
234  if (_this == NULL) {
235  return;
236  }
237 
238  if (_this->udev_handle != NULL) {
239  SDL_UnloadObject(_this->udev_handle);
240  _this->udev_handle = NULL;
241  }
242 }
243 
244 int
245 SDL_UDEV_LoadLibrary(void)
246 {
247  int retval = 0, i;
248 
249  if (_this == NULL) {
250  return SDL_SetError("UDEV not initialized");
251  }
252 
253  /* See if there is a udev library already loaded */
254  if (SDL_UDEV_load_syms() == 0) {
255  return 0;
256  }
257 
258 #ifdef SDL_UDEV_DYNAMIC
259  /* Check for the build environment's libudev first */
260  if (_this->udev_handle == NULL) {
261  _this->udev_handle = SDL_LoadObject(SDL_UDEV_DYNAMIC);
262  if (_this->udev_handle != NULL) {
263  retval = SDL_UDEV_load_syms();
264  if (retval < 0) {
265  SDL_UDEV_UnloadLibrary();
266  }
267  }
268  }
269 #endif
270 
271  if (_this->udev_handle == NULL) {
272  for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
273  _this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
274  if (_this->udev_handle != NULL) {
275  retval = SDL_UDEV_load_syms();
276  if (retval < 0) {
277  SDL_UDEV_UnloadLibrary();
278  }
279  else {
280  break;
281  }
282  }
283  }
284 
285  if (_this->udev_handle == NULL) {
286  retval = -1;
287  /* Don't call SDL_SetError(): SDL_LoadObject already did. */
288  }
289  }
290 
291  return retval;
292 }
293 
294 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
295 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
296 #define OFF(x) ((x)%BITS_PER_LONG)
297 #define LONG(x) ((x)/BITS_PER_LONG)
298 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
299 
300 static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len)
301 {
302  const char *value;
303  char text[4096];
304  char *word;
305  int i;
306  unsigned long v;
307 
308  SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask));
309  value = _this->syms.udev_device_get_sysattr_value(pdev, attr);
310  if (!value) {
311  return;
312  }
313 
314  SDL_strlcpy(text, value, sizeof(text));
315  i = 0;
316  while ((word = SDL_strrchr(text, ' ')) != NULL) {
317  v = SDL_strtoul(word+1, NULL, 16);
318  if (i < bitmask_len) {
319  bitmask[i] = v;
320  }
321  ++i;
322  *word = '\0';
323  }
324  v = SDL_strtoul(text, NULL, 16);
325  if (i < bitmask_len) {
326  bitmask[i] = v;
327  }
328 }
329 
330 static int
331 guess_device_class(struct udev_device *dev)
332 {
333  int devclass = 0;
334  struct udev_device *pdev;
335  unsigned long bitmask_ev[NBITS(EV_MAX)];
336  unsigned long bitmask_abs[NBITS(ABS_MAX)];
337  unsigned long bitmask_key[NBITS(KEY_MAX)];
338  unsigned long bitmask_rel[NBITS(REL_MAX)];
339  unsigned long keyboard_mask;
340 
341  /* walk up the parental chain until we find the real input device; the
342  * argument is very likely a subdevice of this, like eventN */
343  pdev = dev;
344  while (pdev && !_this->syms.udev_device_get_sysattr_value(pdev, "capabilities/ev")) {
345  pdev = _this->syms.udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
346  }
347  if (!pdev) {
348  return 0;
349  }
350 
351  get_caps(dev, pdev, "capabilities/ev", bitmask_ev, SDL_arraysize(bitmask_ev));
352  get_caps(dev, pdev, "capabilities/abs", bitmask_abs, SDL_arraysize(bitmask_abs));
353  get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel));
354  get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key));
355 
356  if (test_bit(EV_ABS, bitmask_ev) &&
357  test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
358  if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
359  ; /* ID_INPUT_TABLET */
360  } else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
361  ; /* ID_INPUT_TOUCHPAD */
362  } else if (test_bit(BTN_MOUSE, bitmask_key)) {
363  devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
364  } else if (test_bit(BTN_TOUCH, bitmask_key)) {
365  /* TODO: better determining between touchscreen and multitouch touchpad,
366  see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */
367  devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */
368  }
369 
370  if (test_bit(BTN_TRIGGER, bitmask_key) ||
371  test_bit(BTN_A, bitmask_key) ||
372  test_bit(BTN_1, bitmask_key) ||
373  test_bit(ABS_RX, bitmask_abs) ||
374  test_bit(ABS_RY, bitmask_abs) ||
375  test_bit(ABS_RZ, bitmask_abs) ||
376  test_bit(ABS_THROTTLE, bitmask_abs) ||
377  test_bit(ABS_RUDDER, bitmask_abs) ||
378  test_bit(ABS_WHEEL, bitmask_abs) ||
379  test_bit(ABS_GAS, bitmask_abs) ||
380  test_bit(ABS_BRAKE, bitmask_abs)) {
381  devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
382  }
383  }
384 
385  if (test_bit(EV_REL, bitmask_ev) &&
386  test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
387  test_bit(BTN_MOUSE, bitmask_key)) {
388  devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
389  }
390 
391  /* the first 32 bits are ESC, numbers, and Q to D; if we have any of
392  * those, consider it a keyboard device; do not test KEY_RESERVED, though */
393  keyboard_mask = 0xFFFFFFFE;
394  if ((bitmask_key[0] & keyboard_mask) != 0)
395  devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */
396 
397  return devclass;
398 }
399 
400 static void
401 device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
402 {
403  const char *subsystem;
404  const char *val = NULL;
405  int devclass = 0;
406  const char *path;
407  SDL_UDEV_CallbackList *item;
408 
409  path = _this->syms.udev_device_get_devnode(dev);
410  if (path == NULL) {
411  return;
412  }
413 
414  subsystem = _this->syms.udev_device_get_subsystem(dev);
415  if (SDL_strcmp(subsystem, "sound") == 0) {
416  devclass = SDL_UDEV_DEVICE_SOUND;
417  } else if (SDL_strcmp(subsystem, "input") == 0) {
418  /* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
419 
420  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
421  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
422  devclass |= SDL_UDEV_DEVICE_JOYSTICK;
423  }
424 
425  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
427  val != NULL && SDL_strcmp(val, "1") == 0 ) {
428  devclass |= SDL_UDEV_DEVICE_JOYSTICK;
429  }
430 
431  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
432  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
433  devclass |= SDL_UDEV_DEVICE_MOUSE;
434  }
435 
436  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
437  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
438  devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN;
439  }
440 
441  /* The undocumented rule is:
442  - All devices with keys get ID_INPUT_KEY
443  - From this subset, if they have ESC, numbers, and Q to D, it also gets ID_INPUT_KEYBOARD
444 
445  Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183
446  */
447  val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_KEY");
448  if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
449  devclass |= SDL_UDEV_DEVICE_KEYBOARD;
450  }
451 
452  if (devclass == 0) {
453  /* Fall back to old style input classes */
454  val = _this->syms.udev_device_get_property_value(dev, "ID_CLASS");
455  if (val != NULL) {
456  if (SDL_strcmp(val, "joystick") == 0) {
457  devclass = SDL_UDEV_DEVICE_JOYSTICK;
458  } else if (SDL_strcmp(val, "mouse") == 0) {
459  devclass = SDL_UDEV_DEVICE_MOUSE;
460  } else if (SDL_strcmp(val, "kbd") == 0) {
461  devclass = SDL_UDEV_DEVICE_KEYBOARD;
462  } else {
463  return;
464  }
465  } else {
466  /* We could be linked with libudev on a system that doesn't have udev running */
467  devclass = guess_device_class(dev);
468  }
469  }
470  } else {
471  return;
472  }
473 
474  /* Process callbacks */
475  for (item = _this->first; item != NULL; item = item->next) {
476  item->callback(type, devclass, path);
477  }
478 }
479 
480 void
481 SDL_UDEV_Poll(void)
482 {
483  struct udev_device *dev = NULL;
484  const char *action = NULL;
485 
486  if (_this == NULL) {
487  return;
488  }
489 
490  while (SDL_UDEV_hotplug_update_available()) {
491  dev = _this->syms.udev_monitor_receive_device(_this->udev_mon);
492  if (dev == NULL) {
493  break;
494  }
495  action = _this->syms.udev_device_get_action(dev);
496 
497  if (SDL_strcmp(action, "add") == 0) {
498  /* Wait for the device to finish initialization */
499  SDL_Delay(100);
500 
501  device_event(SDL_UDEV_DEVICEADDED, dev);
502  } else if (SDL_strcmp(action, "remove") == 0) {
503  device_event(SDL_UDEV_DEVICEREMOVED, dev);
504  }
505 
506  _this->syms.udev_device_unref(dev);
507  }
508 }
509 
510 int
511 SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
512 {
513  SDL_UDEV_CallbackList *item;
514  item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
515  if (item == NULL) {
516  return SDL_OutOfMemory();
517  }
518 
519  item->callback = cb;
520 
521  if (_this->last == NULL) {
522  _this->first = _this->last = item;
523  } else {
524  _this->last->next = item;
525  _this->last = item;
526  }
527 
528  return 1;
529 }
530 
531 void
532 SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
533 {
534  SDL_UDEV_CallbackList *item;
535  SDL_UDEV_CallbackList *prev = NULL;
536 
537  for (item = _this->first; item != NULL; item = item->next) {
538  /* found it, remove it. */
539  if (item->callback == cb) {
540  if (prev != NULL) {
541  prev->next = item->next;
542  } else {
543  SDL_assert(_this->first == item);
544  _this->first = item->next;
545  }
546  if (item == _this->last) {
547  _this->last = prev;
548  }
549  SDL_free(item);
550  return;
551  }
552  prev = item;
553  }
554 
555 }
556 
557 const SDL_UDEV_Symbols *
558 SDL_UDEV_GetUdevSyms(void)
559 {
560  if (SDL_UDEV_Init() < 0) {
561  SDL_SetError("Could not initialize UDEV");
562  return NULL;
563  }
564 
565  return &_this->syms;
566 }
567 
568 void
569 SDL_UDEV_ReleaseUdevSyms(void)
570 {
571  SDL_UDEV_Quit();
572 }
573 
574 #endif /* SDL_USE_LIBUDEV */
575 
576 /* vi: set ts=4 sw=4 expandtab: */
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
SDL_strlcpy
#define SDL_strlcpy
Definition: SDL_dynapi_overrides.h:394
NULL
#define NULL
Definition: begin_code.h:167
SDL_timer.h
SDL_UnloadObject
#define SDL_UnloadObject
Definition: SDL_dynapi_overrides.h:234
path
GLsizei const GLchar *const * path
Definition: SDL_opengl_glext.h:3733
v
const GLdouble * v
Definition: SDL_opengl.h:2064
SDL_LoadObject
#define SDL_LoadObject
Definition: SDL_dynapi_overrides.h:232
SDL_HINT_ACCELEROMETER_AS_JOYSTICK
#define SDL_HINT_ACCELEROMETER_AS_JOYSTICK
A variable controlling whether the Android / iOS built-in accelerometer should be listed as a joystic...
Definition: SDL_hints.h:441
SDL_GetHintBoolean
#define SDL_GetHintBoolean
Definition: SDL_dynapi_overrides.h:608
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
_this
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
retval
SDL_bool retval
Definition: testgamecontroller.c:65
SDL_IOReady
int SDL_IOReady(int fd, SDL_bool forWrite, int timeoutMS)
Definition: SDL_poll.c:38
SDL_free
#define SDL_free
Definition: SDL_dynapi_overrides.h:377
SDL_udev.h
SDL_assert.h
addr
GLenum const void * addr
Definition: SDL_opengl_glext.h:7948
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
text
static char text[MAX_TEXT_LENGTH]
Definition: testime.c:47
SDL_Delay
#define SDL_Delay
Definition: SDL_dynapi_overrides.h:486
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_OutOfMemory
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
action
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF base if bpp PF set rept prefetch_distance PF set OFFSET endr endif endm macro preload_leading_step2 base if bpp ifc DST PF PF else if bpp lsl PF PF lsl PF PF lsl PF PF PF else PF lsl PF lsl PF lsl PF endif SIZE macro preload_middle scratch_holds_offset if bpp if else PF PF endif endif endif endm macro preload_trailing base if bpp if bpp *pix_per_block PF PF lsl PF PF PF PF PF else PF lsl PF lsl PF PF PF PF PF base if bpp if narrow_case &&bpp<=dst_w_bpp) PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, LSL #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 90f PF pld,[WK1]90:.else PF bic, WK0, base, #31 PF pld,[WK0] PF add, WK1, base, X, lsl #bpp_shift PF sub, WK1, WK1, #1 PF bic, WK1, WK1, #31 PF cmp, WK1, WK0 PF beq, 92f91:PF add, WK0, WK0, #32 PF cmp, WK0, WK1 PF pld,[WK0] PF bne, 91b92:.endif .endif.endm.macro conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx process_head cond, numbytes, firstreg, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond X, X, #8 *numbytes/dst_w_bpp .endif process_tail cond, numbytes, firstreg .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst cond, numbytes, firstreg, DST .endif.endm.macro conditional_process1 cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_BRANCH_OVER .ifc cond, mi bpl 100f .endif .ifc cond, cs bcc 100f .endif .ifc cond, ne beq 100f .endif conditional_process1_helper, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx100:.else conditional_process1_helper cond, process_head, process_tail, numbytes, firstreg, unaligned_src, unaligned_mask, decrementx .endif.endm.macro conditional_process2 test, cond1, cond2, process_head, process_tail, numbytes1, numbytes2, firstreg1, firstreg2, unaligned_src, unaligned_mask, decrementx .if(flags) &(FLAG_DST_READWRITE|FLAG_BRANCH_OVER|FLAG_PROCESS_CORRUPTS_PSR|FLAG_PROCESS_DOES_STORE) test conditional_process1 cond1, process_head, process_tail, numbytes1, firstreg1, unaligned_src, unaligned_mask, decrementx .if(flags) &FLAG_PROCESS_CORRUPTS_PSR test .endif conditional_process1 cond2, process_head, process_tail, numbytes2, firstreg2, unaligned_src, unaligned_mask, decrementx .else test process_head cond1, numbytes1, firstreg1, unaligned_src, unaligned_mask, 0 process_head cond2, numbytes2, firstreg2, unaligned_src, unaligned_mask, 0 .if decrementx sub &cond1 X, X, #8 *numbytes1/dst_w_bpp sub &cond2 X, X, #8 *numbytes2/dst_w_bpp .endif process_tail cond1, numbytes1, firstreg1 process_tail cond2, numbytes2, firstreg2 pixst cond1, numbytes1, firstreg1, DST pixst cond2, numbytes2, firstreg2, DST .endif.endm.macro test_bits_1_0_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-1 .else movs SCRATCH, WK0, lsl #32-1 .endif.endm.macro test_bits_3_2_ptr .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 movs SCRATCH, X, lsl #32-3 .else movs SCRATCH, WK0, lsl #32-3 .endif.endm.macro leading_15bytes process_head, process_tail .set DECREMENT_X, 1 .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 .set DECREMENT_X, 0 sub X, X, WK0, lsr #dst_bpp_shift str X,[sp, #LINE_SAVED_REG_COUNT *4] mov X, WK0 .endif .if dst_w_bpp==8 conditional_process2 test_bits_1_0_ptr, mi, cs, process_head, process_tail, 1, 2, 1, 2, 1, 1, DECREMENT_X .elseif dst_w_bpp==16 test_bits_1_0_ptr conditional_process1 cs, process_head, process_tail, 2, 2, 1, 1, DECREMENT_X .endif conditional_process2 test_bits_3_2_ptr, mi, cs, process_head, process_tail, 4, 8, 1, 2, 1, 1, DECREMENT_X .if(flags) &FLAG_PROCESS_CORRUPTS_WK0 ldr X,[sp, #LINE_SAVED_REG_COUNT *4] .endif.endm.macro test_bits_3_2_pix movs SCRATCH, X, lsl #dst_bpp_shift+32-3.endm.macro test_bits_1_0_pix .if dst_w_bpp==8 movs SCRATCH, X, lsl #dst_bpp_shift+32-1 .else movs SCRATCH, X, lsr #1 .endif.endm.macro trailing_15bytes process_head, process_tail, unaligned_src, unaligned_mask conditional_process2 test_bits_3_2_pix, cs, mi, process_head, process_tail, 8, 4, 0, 2, unaligned_src, unaligned_mask, 0 .if dst_w_bpp==16 test_bits_1_0_pix conditional_process1 cs, process_head, process_tail, 2, 0, unaligned_src, unaligned_mask, 0 .elseif dst_w_bpp==8 conditional_process2 test_bits_1_0_pix, cs, mi, process_head, process_tail, 2, 1, 0, 1, unaligned_src, unaligned_mask, 0 .endif.endm.macro wide_case_inner_loop process_head, process_tail, unaligned_src, unaligned_mask, dst_alignment110:.set SUBBLOCK, 0 .rept pix_per_block *dst_w_bpp/128 process_head, 16, 0, unaligned_src, unaligned_mask, 1 .if(src_bpp > 0) &&(mask_bpp==0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle src_bpp, SRC, 1 .elseif(src_bpp==0) &&(mask_bpp > 0) &&((flags) &FLAG_PROCESS_PRESERVES_SCRATCH) preload_middle mask_bpp, MASK, 1 .else preload_middle src_bpp, SRC, 0 preload_middle mask_bpp, MASK, 0 .endif .if(dst_r_bpp > 0) &&((SUBBLOCK % 2)==0) &&(((flags) &FLAG_NO_PRELOAD_DST)==0) PF pld,[DST, #32 *prefetch_distance - dst_alignment] .endif process_tail, 16, 0 .if !((flags) &FLAG_PROCESS_DOES_STORE) pixst, 16, 0, DST .endif .set SUBBLOCK, SUBBLOCK+1 .endr subs X, X, #pix_per_block bhs 110b.endm.macro wide_case_inner_loop_and_trailing_pixels process_head, process_tail, process_inner_loop, exit_label, unaligned_src, unaligned_mask .if dst_r_bpp > tst bne process_inner_loop DST_PRELOAD_BIAS endif preload_trailing SRC preload_trailing MASK DST endif add medium_case_inner_loop_and_trailing_pixels unaligned_mask endm macro medium_case_inner_loop_and_trailing_pixels DST endif subs bhs tst beq exit_label trailing_15bytes unaligned_mask endm macro narrow_case_inner_loop_and_trailing_pixels unaligned_mask tst conditional_process1 trailing_15bytes unaligned_mask endm macro switch_on_alignment action
Definition: pixman-arm-simd-asm.h:510
SDL_arraysize
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
SDL_calloc
#define SDL_calloc
Definition: SDL_dynapi_overrides.h:375
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_UDEV_DYNAMIC
#define SDL_UDEV_DYNAMIC
Definition: SDL_config.h:423
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:701
val
GLuint GLfloat * val
Definition: SDL_opengl_glext.h:1495
SDL_SetError
#define SDL_SetError
Definition: SDL_dynapi_overrides.h:30
SDL_LoadFunction
void * SDL_LoadFunction(void *handle, const char *name)
SDL_hints.h
SDL_strrchr
#define SDL_strrchr
Definition: SDL_dynapi_overrides.h:402
SDL_strcmp
#define SDL_strcmp
Definition: SDL_dynapi_overrides.h:417
fd
GLuint64 GLenum GLint fd
Definition: gl2ext.h:1508
SDL_strtoul
#define SDL_strtoul
Definition: SDL_dynapi_overrides.h:413
SDL_loadso.h
type
GLuint GLuint GLsizei GLenum type
Definition: SDL_opengl.h:1571
i
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:161