added gles3 impl

This commit is contained in:
William McKinnon 2025-10-27 00:58:07 -04:00
parent 00c96e3ac0
commit 78bffc2df5
21 changed files with 190 additions and 25 deletions

View file

@ -9,7 +9,7 @@ wlroots reads these environment variables
* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead * *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead
of following shell search semantics for "Xwayland") of following shell search semantics for "Xwayland")
* *WLR_RENDERER*: forces the creation of a specified renderer (available * *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 * *WLR_RENDER_DRM_DEVICE*: specifies the DRM node to use for
hardware-accelerated renderers. hardware-accelerated renderers.
* *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization * *WLR_RENDER_NO_EXPLICIT_SYNC*: set to 1 to disable explicit synchronization

View file

@ -14,7 +14,7 @@ endif
if not features.get('xwayland') if not features.get('xwayland')
exclude_files += 'xwayland.h' exclude_files += 'xwayland.h'
endif 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'] exclude_files += ['render/egl.h', 'render/gles.h']
endif endif
if not features.get('vulkan-renderer') if not features.get('vulkan-renderer')

View file

@ -47,6 +47,7 @@ struct wlr_egl {
bool has_modifiers; bool has_modifiers;
struct wlr_drm_format_set dmabuf_texture_formats; struct wlr_drm_format_set dmabuf_texture_formats;
struct wlr_drm_format_set dmabuf_render_formats; struct wlr_drm_format_set dmabuf_render_formats;
enum egl_version version;
}; };
struct wlr_egl_context { struct wlr_egl_context {
@ -61,7 +62,7 @@ struct wlr_egl_context {
* *
* Will attempt to load all possibly required API functions. * 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 * Frees all related EGL resources, makes the context not-current and

View file

@ -30,6 +30,13 @@
* Required for <wlr/render/gles.h>. * Required for <wlr/render/gles.h>.
*/ */
#mesondefine WLR_HAS_GLES2_RENDERER #mesondefine WLR_HAS_GLES2_RENDERER
/**
* Whether the GLES3 renderer is compile-time enabled. Equivalent to the
* pkg-config "have_gles3_renderer" variable.
*
* Required for <wlr/render/gles.h>.
*/
#mesondefine WLR_HAS_GLES3_RENDERER
/** /**
* Whether the Vulkan renderer is compile-time enabled. Equivalent to the * Whether the Vulkan renderer is compile-time enabled. Equivalent to the
* pkg-config "have_vulkan_renderer" variable. * pkg-config "have_vulkan_renderer" variable.

View file

@ -28,6 +28,8 @@
struct wlr_egl; struct wlr_egl;
enum egl_version { GLES2 = 2, GLES3 = 3 };
/** /**
* Create a struct wlr_egl with an existing EGL display and context. * Create a struct wlr_egl with an existing EGL display and context.
* *
@ -35,7 +37,7 @@ struct wlr_egl;
* initialization. * initialization.
*/ */
struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, 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. * Get the EGL display used by the struct wlr_egl.

View file

@ -15,6 +15,8 @@
struct wlr_egl; struct wlr_egl;
enum egl_version;
/** /**
* OpenGL ES renderer. * OpenGL ES renderer.
* *
@ -28,7 +30,8 @@ struct wlr_egl;
* render pass can't be used before the nested render pass is submitted. * 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_renderer *wlr_gles_renderer_create(struct wlr_egl *egl);
struct wlr_egl *wlr_gles_renderer_get_egl(struct wlr_renderer *renderer); struct wlr_egl *wlr_gles_renderer_get_egl(struct wlr_renderer *renderer);

View file

@ -72,6 +72,7 @@ features = {
'libinput-backend': false, 'libinput-backend': false,
'xwayland': false, 'xwayland': false,
'gles2-renderer': false, 'gles2-renderer': false,
'gles3-renderer': false,
'vulkan-renderer': false, 'vulkan-renderer': false,
'gbm-allocator': false, 'gbm-allocator': false,
'udmabuf-allocator': false, 'udmabuf-allocator': false,

View file

@ -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('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications')
option('examples', type: 'boolean', value: true, description: 'Build example 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('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('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'], option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'],
description: 'Select built-in allocators') description: 'Select built-in allocators')

View file

@ -10,6 +10,7 @@
#include <wlr/util/region.h> #include <wlr/util/region.h>
#include <xf86drm.h> #include <xf86drm.h>
#include "render/egl.h" #include "render/egl.h"
#include "render/gles.h"
#include "util/env.h" #include "util/env.h"
static enum wlr_log_importance egl_log_importance_to_wlr(EGLint type) { 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); const char *client_exts_str = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (client_exts_str == NULL) { if (client_exts_str == NULL) {
if (eglGetError() == EGL_BAD_DISPLAY) { if (eglGetError() == EGL_BAD_DISPLAY) {
@ -257,6 +258,8 @@ static struct wlr_egl *egl_create(void) {
return NULL; return NULL;
} }
egl->version = version;
return egl; return egl;
} }
@ -411,7 +414,7 @@ static bool egl_init(struct wlr_egl *egl, EGLenum platform,
size_t atti = 0; size_t atti = 0;
EGLint attribs[7]; EGLint attribs[7];
attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION; attribs[atti++] = EGL_CONTEXT_CLIENT_VERSION;
attribs[atti++] = 2; attribs[atti++] = egl->version;
// Request a high priority context if possible // Request a high priority context if possible
// TODO: only do this if we're running as the DRM master // 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; 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; bool allow_software = drm_fd < 0;
struct wlr_egl *egl = egl_create(); struct wlr_egl *egl = egl_create(version);
if (egl == NULL) { if (egl == NULL) {
wlr_log(WLR_ERROR, "Failed to create EGL context"); wlr_log(WLR_ERROR, "Failed to create EGL context");
return NULL; return NULL;
@ -615,7 +618,7 @@ error:
} }
struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
EGLContext context) { EGLContext context, enum egl_version version) {
EGLint client_type; EGLint client_type;
if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &client_type) || if (!eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &client_type) ||
client_type != EGL_OPENGL_ES_API) { client_type != EGL_OPENGL_ES_API) {
@ -630,7 +633,7 @@ struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
return NULL; return NULL;
} }
struct wlr_egl *egl = egl_create(); struct wlr_egl *egl = egl_create(version);
if (egl == NULL) { if (egl == NULL) {
return NULL; return NULL;
} }

View file

@ -1,4 +1,5 @@
glesv2 = dependency('glesv2', required: 'gles2' in renderers) 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']) if not ((glesv2.found() or glesv3.found()) and internal_features['egl'])
subdir_done() subdir_done()
@ -6,8 +7,14 @@ endif
glslang = find_program('glslang', 'glslangValidator', native: true, required: false, disabler: true) glslang = find_program('glslang', 'glslangValidator', native: true, required: false, disabler: true)
features += { 'gles2-renderer': true } if glesv2.found()
wlr_deps += glesv2 features += { 'gles2-renderer': true }
wlr_deps += glesv2
endif
if glesv3.found()
features += { 'gles3-renderer': true }
wlr_deps += glesv3
endif
wlr_files += files( wlr_files += files(
'pass.c', 'pass.c',

View file

@ -1,6 +1,14 @@
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <wlr/config.h>
#if WLR_HAS_GLES2_RENDERER
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#else
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#endif
#include "render/gles.h" #include "render/gles.h"
#include "render/pixel_format.h" #include "render/pixel_format.h"

View file

@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include <wayland-server-protocol.h> #include <wayland-server-protocol.h>
#include <wayland-util.h> #include <wayland-util.h>
#include <wlr/config.h>
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <wlr/render/interface.h> #include <wlr/render/interface.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
@ -20,11 +21,21 @@
#include "render/pixel_format.h" #include "render/pixel_format.h"
#include "util/time.h" #include "util/time.h"
#if WLR_HAS_GLES2_RENDERER
#include "gles2_common_vert_src.h" #include "gles2_common_vert_src.h"
#include "gles2_quad_frag_src.h" #include "gles2_quad_frag_src.h"
#include "gles2_tex_rgba_frag_src.h" #include "gles2_tex_rgba_frag_src.h"
#include "gles2_tex_rgbx_frag_src.h" #include "gles2_tex_rgbx_frag_src.h"
#include "gles2_tex_external_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_renderer_impl renderer_impl;
static const struct wlr_render_timer_impl render_timer_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); 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; GLuint prog;
renderer->shaders.quad.program = 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) { if (!renderer->shaders.quad.program) {
goto error; 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.quad.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.tex_rgba.program = prog = 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) { if (!renderer->shaders.tex_rgba.program) {
goto error; 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_rgba.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.tex_rgbx.program = prog = 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) { if (!renderer->shaders.tex_rgbx.program) {
goto error; goto error;
} }
@ -667,7 +702,7 @@ struct wlr_renderer *wlr_gles_renderer_create(struct wlr_egl *egl) {
if (renderer->exts.OES_egl_image_external) { if (renderer->exts.OES_egl_image_external) {
renderer->shaders.tex_ext.program = prog = 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) { if (!renderer->shaders.tex_ext.program) {
goto error; goto error;
} }

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -6,6 +6,11 @@ shaders = [
'gles2_tex_rgba.frag', 'gles2_tex_rgba.frag',
'gles2_tex_rgbx.frag', 'gles2_tex_rgbx.frag',
'gles2_tex_external.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 foreach name : shaders

View file

@ -1,7 +1,16 @@
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <wlr/config.h>
#if WLR_HAS_GLES2_RENDERER
#include <GLES2/gl2.h> #include <GLES2/gl2.h>
#include <GLES2/gl2ext.h> #include <GLES2/gl2ext.h>
#else
#include <GLES3/gl3.h>
#include <GLES3/gl3ext.h>
#endif
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <wayland-server-protocol.h> #include <wayland-server-protocol.h>

View file

@ -1,6 +1,6 @@
renderers = get_option('renderers') renderers = get_option('renderers')
if 'auto' in renderers and get_option('auto_features').enabled() 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() elif 'auto' in renderers and get_option('auto_features').disabled()
renderers = [] renderers = []
endif endif
@ -25,8 +25,8 @@ endif
internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h')) internal_config.set10('HAVE_EVENTFD', cc.has_header('sys/eventfd.h'))
if 'gles2' in renderers or 'auto' in renderers if 'gles2' in renderers or 'gles3' in renderers or 'auto' in renderers
egl = dependency('egl', required: 'gles2' in renderers) egl = dependency('egl', required: 'gles2' in renderers or 'gles3' in renderers)
if egl.found() if egl.found()
eglext_version = cc.get_define( eglext_version = cc.get_define(
'EGL_EGLEXT_VERSION', 'EGL_EGLEXT_VERSION',
@ -36,12 +36,12 @@ if 'gles2' in renderers or 'auto' in renderers
if eglext_version < 20210604 if eglext_version < 20210604
egl = dependency( egl = dependency(
'', '',
required: 'gles2' in renderers, required: 'gles2' in renderers or 'gles3' in renderers,
not_found_message: 'EGL headers too old', not_found_message: 'EGL headers too old',
) )
endif endif
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() if egl.found() and gbm.found()
wlr_deps += [egl, gbm] wlr_deps += [egl, gbm]
wlr_files += files('egl.c') wlr_files += files('egl.c')

View file

@ -16,7 +16,7 @@
#include <wlr/config.h> #include <wlr/config.h>
#if WLR_HAS_GLES2_RENDERER #if WLR_HAS_GLES2_RENDERER || WLR_HAS_GLES3_RENDERER
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
#include <wlr/render/gles.h> #include <wlr/render/gles.h>
#endif #endif
@ -220,6 +220,7 @@ static struct wlr_renderer *renderer_autocreate(struct wlr_backend *backend, int
const char *renderer_options[] = { const char *renderer_options[] = {
"auto", "auto",
"gles2", "gles2",
"gles3",
"vulkan", "vulkan",
"pixman", "pixman",
NULL 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"); log_creation_failure(is_auto, "Cannot create GLES2 renderer: no DRM FD available");
} else { } else {
#if WLR_HAS_GLES2_RENDERER #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 #else
wlr_log(WLR_ERROR, "Cannot create GLES2 renderer: disabled at compile-time"); wlr_log(WLR_ERROR, "Cannot create GLES2 renderer: disabled at compile-time");
#endif #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 ((is_auto && WLR_HAS_VULKAN_RENDERER) || strcmp(renderer_name, "vulkan") == 0) {
if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) { if (!open_preferred_drm_fd(backend, &drm_fd, &own_drm_fd)) {
log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM FD available"); log_creation_failure(is_auto, "Cannot create Vulkan renderer: no DRM FD available");