From c0e5feea37dbc95675face03bc4707ad09db20b8 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sun, 8 Oct 2017 13:19:25 +1300 Subject: [PATCH] Add GL/EGL extension loader generator --- backend/drm/renderer.c | 3 +- backend/meson.build | 2 +- glgen.sh | 91 +++++++++++++++++++++++++++++++++++++++++ include/wlr/egl.h | 9 ---- meson.build | 6 ++- render/egl.c | 61 +++++++-------------------- render/glapi.txt | 8 ++++ render/gles2/renderer.c | 20 +-------- render/meson.build | 20 +++++++++ 9 files changed, 143 insertions(+), 77 deletions(-) create mode 100755 glgen.sh create mode 100644 render/glapi.txt diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c index c5840436..0d338490 100644 --- a/backend/drm/renderer.c +++ b/backend/drm/renderer.c @@ -14,6 +14,7 @@ #include #include #include "backend/drm/drm.h" +#include "render/glapi.h" bool wlr_drm_renderer_init(struct wlr_drm_backend *drm, struct wlr_drm_renderer *renderer) { @@ -191,7 +192,7 @@ static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, str EGL_NONE, }; - tex->img = renderer->egl.eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT, + tex->img = eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); if (!tex->img) { wlr_log(L_ERROR, "Failed to create EGL image: %s", egl_error()); diff --git a/backend/meson.build b/backend/meson.build index c5c73288..cf62a56f 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -38,5 +38,5 @@ lib_wlr_backend = static_library( 'wlr_backend', backend_files, include_directories: wlr_inc, - dependencies: [wayland_server, egl, gbm, libinput, systemd, elogind, wlr_protos], + dependencies: [wayland_server, egl, gbm, libinput, systemd, elogind, wlr_render, wlr_protos], ) diff --git a/glgen.sh b/glgen.sh new file mode 100755 index 00000000..d9de6f9f --- /dev/null +++ b/glgen.sh @@ -0,0 +1,91 @@ +#!/bin/sh + +# Generates a simple GL/EGL extension function loader. +# +# The input is a .txt file, with each function to load on its own line. +# If a line starts with a -, it is optional, and will not cause the loader +# to fail if it can't load the function. You'll need to check if that function +# is NULL before using it. + +if [ $# -ne 2 ]; then + exit 1 +fi + +SPEC=$1 +OUT=$2 + +BASE=$(basename "$SPEC" .txt) +INCLUDE_GUARD=$(printf %s "$SPEC" | tr -c [:alnum:] _ | tr [:lower:] [:upper:]) + +DECL="" +DEFN="" +LOADER="" + +DECL_FMT='extern %s %s;' +DEFN_FMT='%s %s;' +LOADER_FMT='%s = (%s)eglGetProcAddress("%s");' +CHECK_FMT='if (!%s) { + wlr_log(L_ERROR, "Unable to load %s"); + return false; +}' + +while read -r COMMAND; do + [ ${COMMAND::1} = "-" ] + OPTIONAL=$? + + COMMAND=${COMMAND#-} + if [ ${COMMAND: -2} = "WL" ]; then + FUNC_PTR_FMT='PFN%s' + else + FUNC_PTR_FMT='PFN%sPROC' + fi + + FUNC_PTR=$(printf "$FUNC_PTR_FMT" "$COMMAND" | tr [:lower:] [:upper:]) + + DECL="$DECL$(printf "\n$DECL_FMT" "$FUNC_PTR" "$COMMAND")" + DEFN="$DEFN$(printf "\n$DEFN_FMT" "$FUNC_PTR" "$COMMAND")" + LOADER="$LOADER$(printf "\n$LOADER_FMT" "$COMMAND" "$FUNC_PTR" "$COMMAND")" + + if [ $OPTIONAL -ne 0 ]; then + LOADER="$LOADER$(printf "\n$CHECK_FMT" "$COMMAND" "$COMMAND")" + fi +done < $SPEC + +if [ ${OUT: -2} = '.h' ]; then + cat > $OUT << EOF + #ifndef $INCLUDE_GUARD + #define $INCLUDE_GUARD + + #include + + #include + #include + #include + #include + #include + + bool load_$BASE(void); + $DECL + + #endif +EOF +elif [ ${OUT: -2} = '.c' ]; then + cat > $OUT << EOF + #include + #include "$BASE.h" + $DEFN + + bool load_$BASE(void) { + static bool done = false; + if (done) { + return true; + } + $LOADER + + done = true; + return true; + } +EOF +else + exit 1 +fi diff --git a/include/wlr/egl.h b/include/wlr/egl.h index 25329175..9ab4d9ce 100644 --- a/include/wlr/egl.h +++ b/include/wlr/egl.h @@ -10,15 +10,6 @@ struct wlr_egl { EGLConfig config; EGLContext context; - PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display; - PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window_surface; - - PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; - PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; - PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL; - PFNEGLBINDWAYLANDDISPLAYWL eglBindWaylandDisplayWL; - PFNEGLUNBINDWAYLANDDISPLAYWL eglUnbindWaylandDisplayWL; - const char *egl_exts; const char *gl_exts; diff --git a/meson.build b/meson.build index 57c26b0f..179550d6 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,10 @@ add_project_arguments( '-DWLR_SRC_DIR="@0@"'.format(meson.source_root()), language: 'c', ) +add_project_arguments( + '-I@0@'.format(meson.build_root()), + language: 'c', +) add_project_link_arguments( '-Wl,-rpath,@0@'.format(meson.build_root()), language: 'c', @@ -69,8 +73,8 @@ if elogind.found() and get_option('enable_elogind') endif subdir('protocol') -subdir('backend') subdir('render') +subdir('backend') subdir('types') subdir('util') subdir('xcursor') diff --git a/render/egl.c b/render/egl.c index 82dea50c..9815b923 100644 --- a/render/egl.c +++ b/render/egl.c @@ -4,6 +4,7 @@ #include #include #include +#include "render/glapi.h" // Extension documentation // https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt. @@ -46,27 +47,6 @@ const char *egl_error(void) { } } -static bool egl_exts(struct wlr_egl *egl) { - egl->get_platform_display = (PFNEGLGETPLATFORMDISPLAYEXTPROC) - eglGetProcAddress("eglGetPlatformDisplayEXT"); - - if (!egl->get_platform_display) { - wlr_log(L_ERROR, "Failed to load EGL extension 'eglGetPlatformDisplayEXT'"); - return false; - } - - egl->create_platform_window_surface = (PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) - eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"); - - if (!egl->create_platform_window_surface) { - wlr_log(L_ERROR, - "Failed to load EGL extension 'eglCreatePlatformWindowSurfaceEXT'"); - return false; - } - - return true; -} - static bool egl_get_config(EGLDisplay disp, EGLConfig *out, EGLint visual_id) { EGLint count = 0, matched = 0, ret; @@ -103,7 +83,7 @@ static bool egl_get_config(EGLDisplay disp, EGLConfig *out, EGLint visual_id) { bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, EGLint visual_id, void *remote_display) { - if (!egl_exts(egl)) { + if (!load_glapi()) { return false; } @@ -112,7 +92,7 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, EGLint visual_id, goto error; } - egl->display = egl->get_platform_display(platform, remote_display, NULL); + egl->display = eglGetPlatformDisplayEXT(platform, remote_display, NULL); if (egl->display == EGL_NO_DISPLAY) { wlr_log(L_ERROR, "Failed to create EGL display: %s", egl_error()); goto error; @@ -142,22 +122,11 @@ bool wlr_egl_init(struct wlr_egl *egl, EGLenum platform, EGLint visual_id, eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl->context); egl->egl_exts = eglQueryString(egl->display, EGL_EXTENSIONS); if (strstr(egl->egl_exts, "EGL_WL_bind_wayland_display") == NULL || - strstr(egl->egl_exts, "EGL_KHR_image_base") == NULL) { + strstr(egl->egl_exts, "EGL_KHR_image_base") == NULL) { wlr_log(L_ERROR, "Required egl extensions not supported"); goto error; } - egl->eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) - eglGetProcAddress("eglCreateImageKHR"); - egl->eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) - eglGetProcAddress("eglDestroyImageKHR"); - egl->eglQueryWaylandBufferWL = (PFNEGLQUERYWAYLANDBUFFERWL) - (void*) eglGetProcAddress("eglQueryWaylandBufferWL"); - egl->eglBindWaylandDisplayWL = (PFNEGLBINDWAYLANDDISPLAYWL) - (void*) eglGetProcAddress("eglBindWaylandDisplayWL"); - egl->eglUnbindWaylandDisplayWL = (PFNEGLUNBINDWAYLANDDISPLAYWL) - (void*) eglGetProcAddress("eglUnbindWaylandDisplayWL"); - egl->gl_exts = (const char*) glGetString(GL_EXTENSIONS); wlr_log(L_INFO, "Using EGL %d.%d", (int)major, (int)minor); wlr_log(L_INFO, "Supported EGL extensions: %s", egl->egl_exts); @@ -174,8 +143,8 @@ error: void wlr_egl_free(struct wlr_egl *egl) { eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (egl->wl_display && egl->eglUnbindWaylandDisplayWL) { - egl->eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); + if (egl->wl_display && eglUnbindWaylandDisplayWL) { + eglUnbindWaylandDisplayWL(egl->display, egl->wl_display); } eglDestroyContext(egl->display, egl->context); @@ -184,11 +153,11 @@ void wlr_egl_free(struct wlr_egl *egl) { } bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) { - if (!egl->eglBindWaylandDisplayWL) { + if (!eglBindWaylandDisplayWL) { return false; } - if (egl->eglBindWaylandDisplayWL(egl->display, local_display)) { + if (eglBindWaylandDisplayWL(egl->display, local_display)) { egl->wl_display = local_display; return true; } @@ -198,33 +167,33 @@ bool wlr_egl_bind_display(struct wlr_egl *egl, struct wl_display *local_display) bool wlr_egl_query_buffer(struct wlr_egl *egl, struct wl_resource *buf, int attrib, int *value) { - if (!egl->eglQueryWaylandBufferWL) { + if (!eglQueryWaylandBufferWL) { return false; } - return egl->eglQueryWaylandBufferWL(egl->display, buf, attrib, value); + return eglQueryWaylandBufferWL(egl->display, buf, attrib, value); } EGLImage wlr_egl_create_image(struct wlr_egl *egl, EGLenum target, EGLClientBuffer buffer, const EGLint *attribs) { - if (!egl->eglCreateImageKHR) { + if (!eglCreateImageKHR) { return false; } - return egl->eglCreateImageKHR(egl->display, egl->context, target, + return eglCreateImageKHR(egl->display, egl->context, target, buffer, attribs); } bool wlr_egl_destroy_image(struct wlr_egl *egl, EGLImage image) { - if (!egl->eglDestroyImageKHR) { + if (!eglDestroyImageKHR) { return false; } - egl->eglDestroyImageKHR(egl->display, image); + eglDestroyImageKHR(egl->display, image); return true; } EGLSurface wlr_egl_create_surface(struct wlr_egl *egl, void *window) { - EGLSurface surf = egl->create_platform_window_surface(egl->display, egl->config, + EGLSurface surf = eglCreatePlatformWindowSurfaceEXT(egl->display, egl->config, window, NULL); if (surf == EGL_NO_SURFACE) { wlr_log(L_ERROR, "Failed to create EGL surface: %s", egl_error()); diff --git a/render/glapi.txt b/render/glapi.txt new file mode 100644 index 00000000..81791204 --- /dev/null +++ b/render/glapi.txt @@ -0,0 +1,8 @@ +eglGetPlatformDisplayEXT +eglCreatePlatformWindowSurfaceEXT +-eglCreateImageKHR +-eglDestroyImageKHR +-eglQueryWaylandBufferWL +-eglBindWaylandDisplayWL +-eglUnbindWaylandDisplayWL +-glEGLImageTargetTexture2DOES diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index d6c22ebe..325e1571 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -12,8 +12,8 @@ #include #include #include "render/gles2.h" +#include "render/glapi.h" -PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL; struct shaders shaders; static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { @@ -101,25 +101,7 @@ error: wlr_log(L_ERROR, "Failed to set up default shaders!"); } -static void init_image_ext() { - if (glEGLImageTargetTexture2DOES) { - return; - } - - const char *exts = (const char*) glGetString(GL_EXTENSIONS); - if (strstr(exts, "GL_OES_EGL_image_external")) { - glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) - eglGetProcAddress("glEGLImageTargetTexture2DOES"); - } - - if (!glEGLImageTargetTexture2DOES) { - wlr_log(L_INFO, "Failed to load glEGLImageTargetTexture2DOES " - "Will not be able to attach drm buffers"); - } -} - static void init_globals() { - init_image_ext(); init_default_shaders(); } diff --git a/render/meson.build b/render/meson.build index dc0ceeb9..749d1393 100644 --- a/render/meson.build +++ b/render/meson.build @@ -1,3 +1,16 @@ +glgen = find_program('../glgen.sh') + +glapi_c = custom_target('glapi.c', + input: 'glapi.txt', + output: '@BASENAME@.c', + command: [glgen, '@INPUT@', '@OUTPUT@'], +) +glapi_h = custom_target('glapi.h', + input: 'glapi.txt', + output: '@BASENAME@.h', + command: [glgen, '@INPUT@', '@OUTPUT@'], +) + lib_wlr_render = static_library( 'wlr_render', files( @@ -11,6 +24,13 @@ lib_wlr_render = static_library( 'wlr_renderer.c', 'wlr_texture.c', ), + glapi_c, + glapi_h, include_directories: wlr_inc, dependencies: [glesv2, egl], ) + +wlr_render = declare_dependency( + link_with: lib_wlr_render, + sources: glapi_h, +)