1 /*
2 * Copyright (c) 2020, Rockchip Electronics Co., Ltd
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #ifndef _GNU_SOURCE
16 #define _GNU_SOURCE 1
17 #endif
18
19 #include <dlfcn.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include <xf86drm.h>
27 #include <sys/mman.h>
28
29 #ifdef HAS_GBM
30 #include <gbm.h>
31 #endif
32
33 #ifdef HAS_EGL
34 #include <EGL/egl.h>
35 #include <EGL/eglext.h>
36 #endif
37
38 #ifdef HAS_X11
39 #include <pthread.h>
40
41 #include <X11/Xlib.h>
42 #include <X11/Xlibint.h>
43 #endif
44
45 #ifndef ARRAY_SIZE
46 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
47 #endif
48
49 #ifndef DRM_FORMAT_MOD_LINEAR
50 #define DRM_FORMAT_MOD_LINEAR 0
51 #endif
52
53 #ifndef DRM_FORMAT_MOD_INVALID
54 #define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
55 #endif
56
57 /* A stub symbol to ensure that the hook library would not be removed as unused */
58 int mali_injected = 0;
59
60 /* Override libmali symbols */
61
62 #ifdef HAS_GBM
63 static struct gbm_surface * (* _gbm_surface_create)(struct gbm_device *, uint32_t, uint32_t, uint32_t, uint32_t) = NULL;
64 static struct gbm_bo * (* _gbm_bo_create) (struct gbm_device *, uint32_t, uint32_t, uint32_t, uint32_t) = NULL;
65 #ifdef HAS_gbm_bo_get_modifier
66 static uint64_t (* _gbm_bo_get_modifier) (struct gbm_bo *bo) = NULL;
67 #endif
68 #endif
69
70 #ifdef HAS_EGL
71 static PFNEGLGETDISPLAYPROC _eglGetDisplay = NULL;
72
73 #ifdef HAS_X11
74 static PFNEGLGETPROCADDRESSPROC _eglGetProcAddress = NULL;
75 static PFNEGLGETPLATFORMDISPLAYPROC _eglGetPlatformDisplay = NULL;
76 static PFNEGLGETPLATFORMDISPLAYEXTPROC _eglGetPlatformDisplayEXT = NULL;
77 #endif
78 #endif
79
80 #define MALI_SYMBOL(func) { #func, (void **)(&_ ## func), }
81 static struct {
82 const char *func;
83 void **symbol;
84 } mali_symbols[] = {
85 #ifdef HAS_GBM
86 MALI_SYMBOL(gbm_surface_create),
87 MALI_SYMBOL(gbm_bo_create),
88 #ifdef HAS_gbm_bo_get_modifier
89 MALI_SYMBOL(gbm_bo_get_modifier),
90 #endif
91 #endif
92 #ifdef HAS_EGL
93 MALI_SYMBOL(eglGetDisplay),
94 #ifdef HAS_X11
95 MALI_SYMBOL(eglGetProcAddress),
96 #endif
97 #endif
98 };
99
100 __attribute__((constructor)) static void
load_mali_symbols(void)101 load_mali_symbols(void)
102 {
103 void *handle, *symbol;
104 int i;
105
106 /* The libmali should be already loaded */
107 handle = dlopen(LIBMALI_SO, RTLD_LAZY | RTLD_NOLOAD);
108 if (!handle) {
109 /* Should not reach here */
110 fprintf(stderr, "FATAL: dlopen(" LIBMALI_SO ") failed(%s)\n", dlerror());
111 exit(-1);
112 }
113
114 for (i = 0; i < ARRAY_SIZE(mali_symbols); i++) {
115 const char *func = mali_symbols[i].func;
116
117 /* Clear error */
118 dlerror();
119
120 symbol = dlsym(handle, func);
121 if (!symbol) {
122 /* Should not reach here */
123 fprintf(stderr, "FATAL: " LIBMALI_SO " dlsym(%s) failed(%s)\n",
124 func, dlerror());
125 exit(-1);
126 }
127
128 *mali_symbols[i].symbol = symbol;
129 }
130
131 dlclose(handle);
132
133 #ifdef HAS_EGL
134 #ifdef HAS_X11
135 _eglGetPlatformDisplay =
136 (PFNEGLGETPLATFORMDISPLAYPROC)_eglGetProcAddress("eglGetPlatformDisplay");
137 _eglGetPlatformDisplayEXT =
138 (PFNEGLGETPLATFORMDISPLAYEXTPROC)_eglGetProcAddress("eglGetPlatformDisplayEXT");
139 #endif
140 #endif
141 }
142
143 #ifdef HAS_GBM
144
145 /* Implement new GBM APIs */
146
147 __attribute__((unused)) static inline bool
can_ignore_modifiers(const uint64_t * modifiers,const unsigned int count)148 can_ignore_modifiers(const uint64_t *modifiers,
149 const unsigned int count)
150 {
151 for (int i = 0; i < count; i++) {
152 /* linear or invalid */
153 if (!modifiers[i] || modifiers[i] == DRM_FORMAT_MOD_INVALID) {
154 return true;
155 }
156 }
157
158 return !count;
159 }
160
161 #ifndef HAS_gbm_bo_get_offset
162 uint32_t
gbm_bo_get_offset(struct gbm_bo * bo,int plane)163 gbm_bo_get_offset(struct gbm_bo *bo, int plane)
164 {
165 return 0;
166 }
167 #endif
168
169 #ifndef HAS_gbm_bo_get_plane_count
170 int
gbm_bo_get_plane_count(struct gbm_bo * bo)171 gbm_bo_get_plane_count(struct gbm_bo *bo)
172 {
173 return 1;
174 }
175 #endif
176
177 #ifndef HAS_gbm_bo_get_stride_for_plane
178 uint32_t
gbm_bo_get_stride_for_plane(struct gbm_bo * bo,int plane)179 gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane)
180 {
181 if (plane)
182 return 0;
183
184 return gbm_bo_get_stride(bo);
185 }
186 #endif
187
188 #ifndef HAS_gbm_bo_get_fd_for_plane
189 int
gbm_bo_get_fd_for_plane(struct gbm_bo * bo,int plane)190 gbm_bo_get_fd_for_plane(struct gbm_bo *bo, int plane)
191 {
192 if (plane)
193 return -1;
194
195 return gbm_bo_get_fd(bo);
196 }
197 #endif
198
199 #ifndef HAS_gbm_bo_get_handle_for_plane
200 union gbm_bo_handle
gbm_bo_get_handle_for_plane(struct gbm_bo * bo,int plane)201 gbm_bo_get_handle_for_plane(struct gbm_bo *bo, int plane)
202 {
203 union gbm_bo_handle ret;
204 ret.s32 = -1;
205
206 if (plane)
207 return ret;
208
209 return gbm_bo_get_handle(bo);
210 }
211 #endif
212
213 #ifndef HAS_gbm_device_get_format_modifier_plane_count
214 int
gbm_device_get_format_modifier_plane_count(struct gbm_device * gbm,uint32_t format,uint64_t modifier)215 gbm_device_get_format_modifier_plane_count(struct gbm_device *gbm,
216 uint32_t format,
217 uint64_t modifier)
218 {
219 return can_ignore_modifiers(&modifier, 1) ? 1 : 0;
220 }
221 #endif
222
223 #ifndef HAS_gbm_bo_create_with_modifiers
224 struct gbm_bo *
gbm_bo_create_with_modifiers(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,const uint64_t * modifiers,const unsigned int count)225 gbm_bo_create_with_modifiers(struct gbm_device *gbm,
226 uint32_t width, uint32_t height,
227 uint32_t format,
228 const uint64_t *modifiers,
229 const unsigned int count)
230 {
231 if (!can_ignore_modifiers(modifiers, count))
232 return NULL;
233
234 return gbm_bo_create(gbm, width, height, format, GBM_BO_USE_LINEAR);
235 }
236 #endif
237
238 #ifndef HAS_gbm_surface_create_with_modifiers
239 struct gbm_surface *
gbm_surface_create_with_modifiers(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,const uint64_t * modifiers,const unsigned int count)240 gbm_surface_create_with_modifiers(struct gbm_device *gbm,
241 uint32_t width, uint32_t height,
242 uint32_t format,
243 const uint64_t *modifiers,
244 const unsigned int count)
245 {
246 if (!can_ignore_modifiers(modifiers, count))
247 return NULL;
248
249 return gbm_surface_create(gbm, width, height, format, 0);
250 }
251 #endif
252
253 #ifndef HAS_gbm_bo_map
254 void *
gbm_bo_map(struct gbm_bo * bo,uint32_t x,uint32_t y,uint32_t width,uint32_t height,uint32_t flags,uint32_t * stride,void ** map_data)255 gbm_bo_map(struct gbm_bo *bo,
256 uint32_t x, uint32_t y, uint32_t width, uint32_t height,
257 uint32_t flags, uint32_t *stride, void **map_data)
258 {
259 struct drm_mode_map_dumb arg;
260 struct gbm_device *gbm_dev;
261 void *map;
262 int fd, ret;
263
264 if (!bo || !map_data || width <= 0 || width > gbm_bo_get_width(bo) ||
265 height <= 0 || height > gbm_bo_get_height(bo)) {
266 errno = EINVAL;
267 return MAP_FAILED;
268 }
269
270 gbm_dev = gbm_bo_get_device(bo);
271 if (!gbm_dev)
272 return MAP_FAILED;
273
274 fd = gbm_device_get_fd(gbm_dev);
275 if (fd < 0)
276 return MAP_FAILED;
277
278 memset(&arg, 0, sizeof(arg));
279 arg.handle = gbm_bo_get_handle(bo).u32;
280 ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &arg);
281 if (ret)
282 return MAP_FAILED;
283
284 map = mmap(NULL, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo),
285 PROT_READ | PROT_WRITE, MAP_SHARED, fd, arg.offset);
286 if (map == MAP_FAILED)
287 return map;
288
289 *map_data = map;
290
291 if (stride)
292 *stride = gbm_bo_get_stride(bo);
293
294 return map + y * gbm_bo_get_stride(bo) + x * (gbm_bo_get_bpp(bo) >> 3);
295 }
296 #endif
297
298 #ifndef HAS_gbm_bo_unmap
299 void
gbm_bo_unmap(struct gbm_bo * bo,void * map_data)300 gbm_bo_unmap(struct gbm_bo *bo, void *map_data)
301 {
302 if (map_data)
303 munmap(map_data, gbm_bo_get_stride(bo) * gbm_bo_get_height(bo));
304 }
305 #endif
306
307 /* From mesa3d 20.1.5 : src/gbm/main/gbm.c */
308 #ifndef HAS_gbm_bo_get_bpp
309 uint32_t
gbm_bo_get_bpp(struct gbm_bo * bo)310 gbm_bo_get_bpp(struct gbm_bo *bo)
311 {
312 switch (gbm_bo_get_format(bo)) {
313 default:
314 return 0;
315 case GBM_FORMAT_C8:
316 case GBM_FORMAT_R8:
317 case GBM_FORMAT_RGB332:
318 case GBM_FORMAT_BGR233:
319 return 8;
320 case GBM_FORMAT_GR88:
321 case GBM_FORMAT_XRGB4444:
322 case GBM_FORMAT_XBGR4444:
323 case GBM_FORMAT_RGBX4444:
324 case GBM_FORMAT_BGRX4444:
325 case GBM_FORMAT_ARGB4444:
326 case GBM_FORMAT_ABGR4444:
327 case GBM_FORMAT_RGBA4444:
328 case GBM_FORMAT_BGRA4444:
329 case GBM_FORMAT_XRGB1555:
330 case GBM_FORMAT_XBGR1555:
331 case GBM_FORMAT_RGBX5551:
332 case GBM_FORMAT_BGRX5551:
333 case GBM_FORMAT_ARGB1555:
334 case GBM_FORMAT_ABGR1555:
335 case GBM_FORMAT_RGBA5551:
336 case GBM_FORMAT_BGRA5551:
337 case GBM_FORMAT_RGB565:
338 case GBM_FORMAT_BGR565:
339 return 16;
340 case GBM_FORMAT_RGB888:
341 case GBM_FORMAT_BGR888:
342 return 24;
343 case GBM_FORMAT_XRGB8888:
344 case GBM_FORMAT_XBGR8888:
345 case GBM_FORMAT_RGBX8888:
346 case GBM_FORMAT_BGRX8888:
347 case GBM_FORMAT_ARGB8888:
348 case GBM_FORMAT_ABGR8888:
349 case GBM_FORMAT_RGBA8888:
350 case GBM_FORMAT_BGRA8888:
351 case GBM_FORMAT_XRGB2101010:
352 case GBM_FORMAT_XBGR2101010:
353 case GBM_FORMAT_RGBX1010102:
354 case GBM_FORMAT_BGRX1010102:
355 case GBM_FORMAT_ARGB2101010:
356 case GBM_FORMAT_ABGR2101010:
357 case GBM_FORMAT_RGBA1010102:
358 case GBM_FORMAT_BGRA1010102:
359 return 32;
360 case GBM_FORMAT_XBGR16161616F:
361 case GBM_FORMAT_ABGR16161616F:
362 return 64;
363 }
364 }
365 #endif
366
367 /* From mesa3d 20.1.5 : src/gbm/main/gbm.c */
368 #ifndef HAS_gbm_format_get_name
369 static uint32_t
gbm_format_canonicalize(uint32_t gbm_format)370 gbm_format_canonicalize(uint32_t gbm_format)
371 {
372 switch (gbm_format) {
373 case GBM_BO_FORMAT_XRGB8888:
374 return GBM_FORMAT_XRGB8888;
375 case GBM_BO_FORMAT_ARGB8888:
376 return GBM_FORMAT_ARGB8888;
377 default:
378 return gbm_format;
379 }
380 }
381
382 char *
gbm_format_get_name(uint32_t gbm_format,struct gbm_format_name_desc * desc)383 gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc)
384 {
385 gbm_format = gbm_format_canonicalize(gbm_format);
386
387 desc->name[0] = gbm_format;
388 desc->name[1] = gbm_format >> 8;
389 desc->name[2] = gbm_format >> 16;
390 desc->name[3] = gbm_format >> 24;
391 desc->name[4] = 0;
392
393 return desc->name;
394 }
395 #endif
396
397 /* Wrappers for invalid modifier */
398
399 uint64_t
gbm_bo_get_modifier(struct gbm_bo * bo)400 gbm_bo_get_modifier(struct gbm_bo *bo)
401 {
402 #ifdef HAS_gbm_bo_get_modifier
403 uint64_t modifier = _gbm_bo_get_modifier(bo);
404 if (modifier != DRM_FORMAT_MOD_INVALID)
405 return modifier;
406 #endif
407 return DRM_FORMAT_MOD_LINEAR;
408 }
409
410 /* Wrappers for unsupported flags */
411
412 struct gbm_surface *
gbm_surface_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)413 gbm_surface_create(struct gbm_device *gbm,
414 uint32_t width, uint32_t height,
415 uint32_t format, uint32_t flags)
416 {
417 struct gbm_surface *surface;
418
419 surface = _gbm_surface_create(gbm, width, height, format, flags);
420 if (surface)
421 return surface;
422
423 flags &= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING;
424 return _gbm_surface_create(gbm, width, height, format, flags);
425 }
426
427 struct gbm_bo *
gbm_bo_create(struct gbm_device * gbm,uint32_t width,uint32_t height,uint32_t format,uint32_t flags)428 gbm_bo_create(struct gbm_device *gbm,
429 uint32_t width, uint32_t height,
430 uint32_t format, uint32_t flags)
431 {
432 struct gbm_bo *bo;
433
434 bo = _gbm_bo_create(gbm, width, height, format, flags);
435 if (bo)
436 return bo;
437
438 flags &= GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING |
439 GBM_BO_USE_WRITE | GBM_BO_USE_CURSOR_64X64;
440 return _gbm_bo_create(gbm, width, height, format, flags);
441 }
442
443 #endif // HAS_GBM
444
445 #ifdef HAS_EGL
446 #ifdef HAS_X11
447
448 /* Hacked displays (should not be much) */
449 #define MAX_X11_DISPLAY 32
450 static Display *_x11_displays[MAX_X11_DISPLAY] = { NULL, };
451
452 static pthread_mutex_t _x11_mutex = PTHREAD_MUTEX_INITIALIZER;
453
454 static inline int
force_x11_threads(void)455 force_x11_threads(void)
456 {
457 return !getenv("MALI_X11_NO_FORCE_THREADS");
458 }
459
460 __attribute__((constructor)) static void
init_x11_threads(void)461 init_x11_threads(void)
462 {
463 if (force_x11_threads())
464 XInitThreads();
465 }
466
467 __attribute__((destructor)) static void
cleanup_x11_display(void)468 cleanup_x11_display(void)
469 {
470 int i;
471
472 for (i = 0; i < MAX_X11_DISPLAY; i++) {
473 Display *display = _x11_displays[i];
474 if (display)
475 XCloseDisplay(display);
476 }
477 }
478
479 static Display *
fixup_x11_display(Display * display)480 fixup_x11_display(Display *display)
481 {
482 int i;
483
484 if (!force_x11_threads())
485 return display;
486
487 if (!display || display->lock_fns)
488 return display;
489
490 pthread_mutex_lock(&_x11_mutex);
491 /* Create a new threaded display */
492 display = XOpenDisplay(DisplayString(display));
493
494 for (i = 0; i < MAX_X11_DISPLAY; i++) {
495 if (!_x11_displays[i]) {
496 _x11_displays[i] = display;
497 break;
498 }
499 }
500 pthread_mutex_unlock(&_x11_mutex);
501
502 return display;
503 }
504
505 /* Override EGL symbols */
506
507 EGLAPI EGLDisplay EGLAPIENTRY
eglGetPlatformDisplay(EGLenum platform,void * native_display,const EGLAttrib * attrib_list)508 eglGetPlatformDisplay(EGLenum platform, void *native_display, const EGLAttrib *attrib_list)
509 {
510 if (!_eglGetPlatformDisplay)
511 return EGL_NO_DISPLAY;
512
513 if (platform == EGL_PLATFORM_X11_KHR && native_display) {
514 native_display = (void *)fixup_x11_display(native_display);
515 if (!native_display)
516 return EGL_NO_DISPLAY;
517 }
518
519 return _eglGetPlatformDisplay(platform, native_display, attrib_list);
520 }
521
522 EGLAPI EGLDisplay EGLAPIENTRY
eglGetPlatformDisplayEXT(EGLenum platform,void * native_display,const EGLint * attrib_list)523 eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list)
524 {
525 if (!_eglGetPlatformDisplayEXT)
526 return EGL_NO_DISPLAY;
527
528 if (platform == EGL_PLATFORM_X11_KHR && native_display) {
529 native_display = (void *)fixup_x11_display(native_display);
530 if (!native_display)
531 return EGL_NO_DISPLAY;
532 }
533
534 return _eglGetPlatformDisplayEXT(platform, native_display, attrib_list);
535 }
536
537 EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
eglGetProcAddress(const char * procname)538 eglGetProcAddress(const char *procname)
539 {
540 if (!procname)
541 return NULL;
542
543 if (!strcmp(procname, __func__))
544 return (__eglMustCastToProperFunctionPointerType)eglGetProcAddress;
545
546 if (!strcmp(procname, "eglGetDisplay"))
547 return (__eglMustCastToProperFunctionPointerType)eglGetDisplay;
548
549 if (!strcmp(procname, "eglGetPlatformDisplay")) {
550 if (!_eglGetPlatformDisplay)
551 return NULL;
552 return (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplay;
553 }
554
555 if (!strcmp(procname, "eglGetPlatformDisplayEXT")) {
556 if (!_eglGetPlatformDisplayEXT)
557 return NULL;
558 return (__eglMustCastToProperFunctionPointerType)eglGetPlatformDisplayEXT;
559 }
560
561 return _eglGetProcAddress(procname);
562 }
563
564 #endif // HAS_X11
565
566 EGLAPI EGLDisplay EGLAPIENTRY
eglGetDisplay(EGLNativeDisplayType display_id)567 eglGetDisplay (EGLNativeDisplayType display_id)
568 {
569 const char *type = getenv("MALI_DEFAULT_WINSYS");
570
571 static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
572 if (!get_platform_display)
573 get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC)
574 eglGetProcAddress("eglGetPlatformDisplayEXT");
575 if (!get_platform_display)
576 goto bail;
577
578 #ifdef HAS_GBM
579 if (type && !strcmp(type, "gbm"))
580 return get_platform_display(EGL_PLATFORM_GBM_KHR, display_id, NULL);
581 #endif
582
583 #ifdef HAS_WAYLAND
584 if (type && !strcmp(type, "wayland"))
585 return get_platform_display(EGL_PLATFORM_WAYLAND_EXT, display_id, NULL);
586 #endif
587
588 #ifdef HAS_X11
589 /* Use X11 by default when avaiable */
590 return get_platform_display(EGL_PLATFORM_X11_KHR, display_id, NULL);
591 #endif
592
593 bail:
594 return _eglGetDisplay(display_id);
595 }
596
597 #endif // HAS_EGL
598