diff --git a/docs/env_vars.md b/docs/env_vars.md index 59c8f078f..482f6820e 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -9,7 +9,7 @@ wlroots reads these environment variables * *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead of following shell search semantics for "Xwayland") * *WLR_RENDERER*: forces the creation of a specified renderer (available - renderers: gles2, pixman, vulkan) + renderers: gles2, gles3, pixman, vulkan) * *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for hardware-accelerated renderers. * *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization diff --git a/include/meson.build b/include/meson.build index b0f600aaf..f49328223 100644 --- a/include/meson.build +++ b/include/meson.build @@ -14,7 +14,7 @@ endif if not features.get('xwayland') exclude_files += 'xwayland.h' endif -if not features.get('gles2-renderer') +if not features.get('gles2-renderer') and not features.get('gles3-renderer') exclude_files += ['render/egl.h', 'render/gles.h'] endif if not features.get('vulkan-renderer') diff --git a/include/render/egl.h b/include/render/egl.h index 103ab57df..c5b1da902 100644 --- a/include/render/egl.h +++ b/include/render/egl.h @@ -47,6 +47,7 @@ struct wlr_egl { bool has_modifiers; struct wlr_drm_format_set dmabuf_texture_formats; struct wlr_drm_format_set dmabuf_render_formats; + enum egl_version version; }; struct wlr_egl_context { @@ -61,7 +62,7 @@ struct wlr_egl_context { * * Will attempt to load all possibly required API functions. */ -struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd); +struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd, enum egl_version version); /** * Frees all related EGL resources, makes the context not-current and diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index 198f14334..84f617193 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -30,6 +30,13 @@ * Required for . */ #mesondefine WLR_HAS_GLES2_RENDERER +/** + * Whether the GLES3 renderer is compile-time enabled. Equivalent to the + * pkg-config "have_gles3_renderer" variable. + * + * Required for . + */ +#mesondefine WLR_HAS_GLES3_RENDERER /** * Whether the Vulkan renderer is compile-time enabled. Equivalent to the * pkg-config "have_vulkan_renderer" variable. diff --git a/include/wlr/render/egl.h b/include/wlr/render/egl.h index 9bf1b8019..b63854252 100644 --- a/include/wlr/render/egl.h +++ b/include/wlr/render/egl.h @@ -28,6 +28,8 @@ struct wlr_egl; +enum egl_version { GLES2 = 2, GLES3 = 3 }; + /** * Create a struct wlr_egl with an existing EGL display and context. * @@ -35,7 +37,7 @@ struct wlr_egl; * initialization. */ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, - EGLContext context); + EGLContext context, enum egl_version version); /** * Get the EGL display used by the struct wlr_egl. diff --git a/include/wlr/render/gles.h b/include/wlr/render/gles.h index b45bc0861..21074e6d1 100644 --- a/include/wlr/render/gles.h +++ b/include/wlr/render/gles.h @@ -15,6 +15,8 @@ struct wlr_egl; +enum egl_version; + /** * OpenGL ES renderer. * @@ -28,7 +30,8 @@ struct wlr_egl; * render pass can't be used before the nested render pass is submitted. */ -struct wlr_renderer *wlr_gles_renderer_create_with_drm_fd(int drm_fd); +struct wlr_renderer *wlr_gles_renderer_create_with_drm_fd(int drm_fd, + enum egl_version version); struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl); struct wlr_egl *wlr_gles_renderer_get_egl(struct wlr_renderer *renderer); diff --git a/meson.build b/meson.build index 4b24e5046..e229034b6 100644 --- a/meson.build +++ b/meson.build @@ -72,6 +72,7 @@ features = { 'libinput-backend': false, 'xwayland': false, 'gles2-renderer': false, + 'gles3-renderer': false, 'vulkan-renderer': false, 'gbm-allocator': false, 'udmabuf-allocator': false, diff --git a/meson.options b/meson.options index 5863764aa..38f3364a8 100644 --- a/meson.options +++ b/meson.options @@ -2,7 +2,7 @@ option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-error option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications') option('examples', type: 'boolean', value: true, description: 'Build example applications') option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') -option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') +option('renderers', type: 'array', choices: ['auto', 'gles2', 'gles3', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'], description: 'Select built-in allocators') diff --git a/render/egl.c b/render/egl.c index 6f3e9c8ca..ec64e2f46 100644 --- a/render/egl.c +++ b/render/egl.c @@ -10,6 +10,7 @@ #include #include #include "render/egl.h" +#include "render/gles.h" #include "util/env.h" static enum wlr_log_importance egl_log_importance_to_wlr(EGLint type) { @@ -191,7 +192,7 @@ static void init_dmabuf_formats(struct wlr_egl *egl) { } } -static struct wlr_egl *egl_create(void) { +static struct wlr_egl *egl_create(enum egl_version version) { const char *client_exts_str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (client_exts_str == NULL) { if (eglGetError() == EGL_BAD_DISPLAY) { @@ -257,6 +258,8 @@ static struct wlr_egl *egl_create(void) { return NULL; } + egl->version = version; + return egl; } @@ -411,7 +414,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform, size_t atti = 0; EGLint attribs[7]; attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; - attribs[atti++] = 2; + attribs[atti++] = egl->version; // Request a high priority context if possible // TODO: only do this if we're running as the DRM master @@ -555,10 +558,10 @@ static int open_render_node(int drm_fd) { return render_fd; } -struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd) { +struct wlr_egl *wlr_egl_create_with_drm_fd(int drm_fd, enum egl_version version) { bool allow_software = drm_fd < 0; - struct wlr_egl *egl = egl_create(); + struct wlr_egl *egl = egl_create(version); if (egl == NULL) { wlr_log(WLR_ERROR, "Failed to create EGL context"); return NULL; @@ -615,7 +618,7 @@ error: } struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, - EGLContext context) { + EGLContext context, enum egl_version version) { EGLint client_type; if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &client_type) || client_type != EGL_OPENGL_ES_API) { @@ -630,7 +633,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, return NULL; } - struct wlr_egl *egl = egl_create(); + struct wlr_egl *egl = egl_create(version); if (egl == NULL) { return NULL; } diff --git a/render/gles/meson.build b/render/gles/meson.build index d4c53c894..7911f4ab0 100644 --- a/render/gles/meson.build +++ b/render/gles/meson.build @@ -1,4 +1,5 @@ glesv2 = dependency('glesv2', required: 'gles2' in renderers) +glesv3 = dependency('glesv2', required: 'gles3' in renderers) if not ((glesv2.found() or glesv3.found()) and internal_features['egl']) subdir_done() @@ -6,8 +7,14 @@ endif glslang = find_program('glslang', 'glslangValidator', native: true, required: false, disabler: true) -features += { 'gles2-renderer': true } -wlr_deps += glesv2 +if glesv2.found() + features += { 'gles2-renderer': true } + wlr_deps += glesv2 +endif +if glesv3.found() + features += { 'gles3-renderer': true } + wlr_deps += glesv3 +endif wlr_files += files( 'pass.c', diff --git a/render/gles/pixel_format.c b/render/gles/pixel_format.c index 220568014..28f23c48b 100644 --- a/render/gles/pixel_format.c +++ b/render/gles/pixel_format.c @@ -1,6 +1,14 @@ #include +#include + +#if WLR_HAS_GLES2_RENDERER #include #include +#else +#include +#include +#endif + #include "render/gles.h" #include "render/pixel_format.h" diff --git a/render/gles/renderer.c b/render/gles/renderer.c index a30293303..af2113e7d 100644 --- a/render/gles/renderer.c +++ b/render/gles/renderer.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,11 +21,21 @@ #include "render/pixel_format.h" #include "util/time.h" +#if WLR_HAS_GLES2_RENDERER #include "gles2_common_vert_src.h" #include "gles2_quad_frag_src.h" #include "gles2_tex_rgba_frag_src.h" #include "gles2_tex_rgbx_frag_src.h" #include "gles2_tex_external_frag_src.h" +#endif + +#if WLR_HAS_GLES3_RENDERER +#include "gles3_common_vert_src.h" +#include "gles3_quad_frag_src.h" +#include "gles3_tex_rgba_frag_src.h" +#include "gles3_tex_rgbx_frag_src.h" +#include "gles3_tex_external_frag_src.h" +#endif static const struct wlr_renderer_impl renderer_impl; static const struct wlr_render_timer_impl render_timer_impl; @@ -633,9 +644,33 @@ struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl) { push_gles_debug(renderer); + const char* common_vert_src; + const char* quad_frag_src; + const char* tex_rgba_frag_src; + const char* tex_rgbx_frag_src; + const char* tex_external_frag_src; + + if (egl->version == GLES2) { +#if WLR_HAS_GLES2_RENDERER + common_vert_src = gles2_common_vert_src; + quad_frag_src = gles2_quad_frag_src; + tex_rgba_frag_src = gles2_tex_rgba_frag_src; + tex_rgbx_frag_src = gles2_tex_rgbx_frag_src; + tex_external_frag_src = gles2_tex_external_frag_src; +#endif + } else { +#if WLR_HAS_GLES3_RENDERER + common_vert_src = gles3_common_vert_src; + quad_frag_src = gles3_quad_frag_src; + tex_rgba_frag_src = gles3_tex_rgba_frag_src; + tex_rgbx_frag_src = gles3_tex_rgbx_frag_src; + tex_external_frag_src = gles3_tex_external_frag_src; +#endif + } + GLuint prog; renderer->shaders.quad.program = prog = - link_program(renderer, gles2_common_vert_src, gles2_quad_frag_src); + link_program(renderer, common_vert_src, quad_frag_src); if (!renderer->shaders.quad.program) { goto error; } @@ -644,7 +679,7 @@ struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl) { renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.tex_rgba.program = prog = - link_program(renderer, gles2_common_vert_src, gles2_tex_rgba_frag_src); + link_program(renderer, common_vert_src, tex_rgba_frag_src); if (!renderer->shaders.tex_rgba.program) { goto error; } @@ -655,7 +690,7 @@ struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl) { renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); renderer->shaders.tex_rgbx.program = prog = - link_program(renderer, gles2_common_vert_src, gles2_tex_rgbx_frag_src); + link_program(renderer, common_vert_src, tex_rgbx_frag_src); if (!renderer->shaders.tex_rgbx.program) { goto error; } @@ -667,7 +702,7 @@ struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl) { if (renderer->exts.OES_egl_image_external) { renderer->shaders.tex_ext.program = prog = - link_program(renderer, gles2_common_vert_src, gles2_tex_external_frag_src); + link_program(renderer, common_vert_src, tex_external_frag_src); if (!renderer->shaders.tex_ext.program) { goto error; } diff --git a/render/gles/shaders/gles3_common.vert b/render/gles/shaders/gles3_common.vert new file mode 100644 index 000000000..5022372a0 --- /dev/null +++ b/render/gles/shaders/gles3_common.vert @@ -0,0 +1,12 @@ +#version 300 es + +uniform mat3 proj; +uniform mat3 tex_proj; +in vec2 pos; +out vec2 v_texcoord; + +void main() { + vec3 pos3 = vec3(pos, 1.0); + gl_Position = vec4(pos3 * proj, 1.0); + v_texcoord = (pos3 * tex_proj).xy; +} diff --git a/render/gles/shaders/gles3_quad.frag b/render/gles/shaders/gles3_quad.frag new file mode 100644 index 000000000..660e2e04f --- /dev/null +++ b/render/gles/shaders/gles3_quad.frag @@ -0,0 +1,13 @@ +#version 300 es + +precision highp float; + +in vec4 v_color; +in vec2 v_texcoord; +uniform vec4 color; + +out vec4 frag_color; + +void main() { + frag_color = color; +} diff --git a/render/gles/shaders/gles3_tex_external.frag b/render/gles/shaders/gles3_tex_external.frag new file mode 100644 index 000000000..f471319d9 --- /dev/null +++ b/render/gles/shaders/gles3_tex_external.frag @@ -0,0 +1,15 @@ +#version 300 es + +#extension GL_OES_EGL_image_external_essl3 : require + +precision highp float; + +in vec2 v_texcoord; +uniform samplerExternalOES texture0; +uniform float alpha; + +out vec4 frag_color; + +void main() { + frag_color = texture(texture0, v_texcoord) * alpha; +} diff --git a/render/gles/shaders/gles3_tex_rgba.frag b/render/gles/shaders/gles3_tex_rgba.frag new file mode 100644 index 000000000..51b2ae037 --- /dev/null +++ b/render/gles/shaders/gles3_tex_rgba.frag @@ -0,0 +1,13 @@ +#version 300 es + +precision highp float; + +in vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +out vec4 frag_color; + +void main() { + frag_color = texture(tex, v_texcoord) * alpha; +} diff --git a/render/gles/shaders/gles3_tex_rgbx.frag b/render/gles/shaders/gles3_tex_rgbx.frag new file mode 100644 index 000000000..c0dc08a8c --- /dev/null +++ b/render/gles/shaders/gles3_tex_rgbx.frag @@ -0,0 +1,13 @@ +#version 300 es + +precision highp float; + +in vec2 v_texcoord; +uniform sampler2D tex; +uniform float alpha; + +out vec4 frag_color; + +void main() { + frag_color = vec4(texture(tex, v_texcoord).rgb, 1.0) * alpha; +} diff --git a/render/gles/shaders/meson.build b/render/gles/shaders/meson.build index cba9b6034..de1be55c5 100644 --- a/render/gles/shaders/meson.build +++ b/render/gles/shaders/meson.build @@ -6,6 +6,11 @@ shaders = [ 'gles2_tex_rgba.frag', 'gles2_tex_rgbx.frag', 'gles2_tex_external.frag', + 'gles3_common.vert', + 'gles3_quad.frag', + 'gles3_tex_rgba.frag', + 'gles3_tex_rgbx.frag', + 'gles3_tex_external.frag', ] foreach name : shaders diff --git a/render/gles/texture.c b/render/gles/texture.c index 97632c7db..d4a1e282b 100644 --- a/render/gles/texture.c +++ b/render/gles/texture.c @@ -1,7 +1,16 @@ #include #include + +#include + +#if WLR_HAS_GLES2_RENDERER #include #include +#else +#include +#include +#endif + #include #include #include diff --git a/render/meson.build b/render/meson.build index b4f89a022..5f291c7e4 100644 --- a/render/meson.build +++ b/render/meson.build @@ -1,6 +1,6 @@ renderers = get_option('renderers') if 'auto' in renderers and get_option('auto_features').enabled() - renderers = ['gles2', 'vulkan'] + renderers = ['gles2', 'gles3', 'vulkan'] elif 'auto' in renderers and get_option('auto_features').disabled() renderers = [] endif @@ -25,8 +25,8 @@ endif internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h')) -if 'gles2' in renderers or 'auto' in renderers - egl = dependency('egl', required: 'gles2' in renderers) +if 'gles2' in renderers or 'gles3' in renderers or 'auto' in renderers + egl = dependency('egl', required: 'gles2' in renderers or 'gles3' in renderers) if egl.found() eglext_version = cc.get_define( 'EGL_EGLEXT_VERSION', @@ -36,12 +36,12 @@ if 'gles2' in renderers or 'auto' in renderers if eglext_version < 20210604 egl = dependency( '', - required: 'gles2' in renderers, + required: 'gles2' in renderers or 'gles3' in renderers, not_found_message: 'EGL headers too old', ) endif endif - gbm = dependency('gbm', required: 'gles2' in renderers) + gbm = dependency('gbm', required: 'gles2' in renderers or 'gles3' in renderers) if egl.found() and gbm.found() wlr_deps += [egl, gbm] wlr_files += files('egl.c') diff --git a/render/wlr_renderer.c b/render/wlr_renderer.c index 2fdb670f0..79900b9b7 100644 --- a/render/wlr_renderer.c +++ b/render/wlr_renderer.c @@ -16,7 +16,7 @@ #include -#if WLR_HAS_GLES2_RENDERER +#if WLR_HAS_GLES2_RENDERER || WLR_HAS_GLES3_RENDERER #include #include #endif @@ -220,6 +220,7 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int const char *renderer_options[] = { "auto", "gles2", + "gles3", "vulkan", "pixman", NULL @@ -236,7 +237,7 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM FD available"); } else { #if WLR_HAS_GLES2_RENDERER - renderer = wlr_gles_renderer_create_with_drm_fd(drm_fd); + renderer = wlr_gles_renderer_create_with_drm_fd(drm_fd, GLES2); #else wlr_log(WLR_ERROR, "Cannot create GLES2 renderer: disabled at compile-time"); #endif @@ -248,6 +249,23 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int } } + if ((is_auto && WLR_HAS_GLES3_RENDERER) || strcmp(renderer_name, "gles3") == 0) { + if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { + log_creation_failure(is_auto, "Cannot create GLES3 renderer: no DRM FD available"); + } else { +#if WLR_HAS_GLES3_RENDERER + renderer = wlr_gles_renderer_create_with_drm_fd(drm_fd, GLES3); +#else + wlr_log(WLR_ERROR, "Cannot create GLES3 renderer: disabled at compile-time"); +#endif + if (renderer) { + goto out; + } else { + log_creation_failure(is_auto, "Failed to create a GLES3 renderer"); + } + } + } + if ((is_auto && WLR_HAS_VULKAN_RENDERER) || strcmp(renderer_name, "vulkan") == 0) { if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM FD available");