diff --git a/include/render/gles2.h b/include/render/gles2.h index 6631d34ce..b3ac31195 100644 --- a/include/render/gles2.h +++ b/include/render/gles2.h @@ -112,6 +112,12 @@ struct wlr_gles2_texture { struct wlr_addon buffer_addon; }; +enum wlr_gles2_shader_source { + WLR_GLES2_SHADER_SOURCE_SINGLE_COLOR = 1, + WLR_GLES2_SHADER_SOURCE_TEXTURE_RGBA = 2, + WLR_GLES2_SHADER_SOURCE_TEXTURE_RGBX = 3, + WLR_GLES2_SHADER_SOURCE_TEXTURE_EXTERNAL = 4, +}; bool is_gles2_pixel_format_supported(const struct wlr_gles2_renderer *renderer, const struct wlr_gles2_pixel_format *format); diff --git a/meson.build b/meson.build index a180b43c0..45eeabaa6 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '0.16.0-dev', license: 'MIT', - meson_version: '>=0.58.1', + meson_version: '>=0.59.0', default_options: [ 'c_std=c11', 'warning_level=2', diff --git a/render/gles2/meson.build b/render/gles2/meson.build index 504f0c11e..c92269837 100644 --- a/render/gles2/meson.build +++ b/render/gles2/meson.build @@ -10,6 +10,7 @@ wlr_deps += glesv2 wlr_files += files( 'pixel_format.c', 'renderer.c', - 'shaders.c', 'texture.c', ) + +subdir('shaders') diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c index aa1adabea..21bfdff5e 100644 --- a/render/gles2/renderer.c +++ b/render/gles2/renderer.c @@ -19,6 +19,9 @@ #include "render/pixel_format.h" #include "types/wlr_matrix.h" +#include "common_vert_src.h" +#include "common_frag_src.h" + static const GLfloat verts[] = { 1, 0, // top right 0, 0, // top left @@ -580,11 +583,11 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity, } static GLuint compile_shader(struct wlr_gles2_renderer *renderer, - GLuint type, const GLchar *src) { + GLuint type, const GLchar **srcs, size_t srcs_len) { push_gles2_debug(renderer); GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &src, NULL); + glShaderSource(shader, srcs_len, srcs, NULL); glCompileShader(shader); GLint ok; @@ -600,15 +603,22 @@ static GLuint compile_shader(struct wlr_gles2_renderer *renderer, } static GLuint link_program(struct wlr_gles2_renderer *renderer, - const GLchar *vert_src, const GLchar *frag_src) { + enum wlr_gles2_shader_source source) { + static char frag_preamble[1024]; + snprintf(frag_preamble, sizeof(frag_preamble), + "#define SOURCE %d\n", source); + push_gles2_debug(renderer); - GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src); + const GLchar *vert_src = common_vert_src; + GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, &vert_src, 1); if (!vert) { goto error; } - GLuint frag = compile_shader(renderer, GL_FRAGMENT_SHADER, frag_src); + const GLchar *frag_srcs[2] = { frag_preamble, common_frag_src }; + GLuint frag = + compile_shader(renderer, GL_FRAGMENT_SHADER, frag_srcs, 2); if (!frag) { glDeleteShader(vert); goto error; @@ -640,6 +650,23 @@ error: return 0; } +static bool link_tex_program(struct wlr_gles2_renderer *renderer, + struct wlr_gles2_tex_shader *shader, + enum wlr_gles2_shader_source source) { + shader->program = link_program(renderer, source); + if (!shader->program) { + return false; + } + + shader->proj = glGetUniformLocation(shader->program, "proj"); + shader->tex = glGetUniformLocation(shader->program, "tex"); + shader->alpha = glGetUniformLocation(shader->program, "alpha"); + shader->pos_attrib = glGetAttribLocation(shader->program, "pos"); + shader->tex_attrib = glGetAttribLocation(shader->program, "texcoord"); + + return true; +} + static bool check_gl_ext(const char *exts, const char *ext) { size_t extlen = strlen(ext); const char *end = exts + strlen(exts); @@ -667,13 +694,6 @@ static void load_gl_proc(void *proc_ptr, const char *name) { *(void **)proc_ptr = proc; } -extern const GLchar quad_vertex_src[]; -extern const GLchar quad_fragment_src[]; -extern const GLchar tex_vertex_src[]; -extern const GLchar tex_fragment_src_rgba[]; -extern const GLchar tex_fragment_src_rgbx[]; -extern const GLchar tex_fragment_src_external[]; - struct wlr_renderer *wlr_gles2_renderer_create_with_drm_fd(int drm_fd) { struct wlr_egl *egl = wlr_egl_create_with_drm_fd(drm_fd); if (egl == NULL) { @@ -786,7 +806,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { GLuint prog; renderer->shaders.quad.program = prog = - link_program(renderer, quad_vertex_src, quad_fragment_src); + link_program(renderer, WLR_GLES2_SHADER_SOURCE_SINGLE_COLOR); if (!renderer->shaders.quad.program) { goto error; } @@ -794,39 +814,18 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) { renderer->shaders.quad.color = glGetUniformLocation(prog, "color"); renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_rgba.program = prog = - link_program(renderer, tex_vertex_src, tex_fragment_src_rgba); - if (!renderer->shaders.tex_rgba.program) { + if (!link_tex_program(renderer, &renderer->shaders.tex_rgba, + WLR_GLES2_SHADER_SOURCE_TEXTURE_RGBA)) { goto error; } - renderer->shaders.tex_rgba.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_rgba.tex_attrib = glGetAttribLocation(prog, "texcoord"); - - renderer->shaders.tex_rgbx.program = prog = - link_program(renderer, tex_vertex_src, tex_fragment_src_rgbx); - if (!renderer->shaders.tex_rgbx.program) { + if (!link_tex_program(renderer, &renderer->shaders.tex_rgbx, + WLR_GLES2_SHADER_SOURCE_TEXTURE_RGBX)) { goto error; } - renderer->shaders.tex_rgbx.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_rgbx.tex_attrib = glGetAttribLocation(prog, "texcoord"); - - if (renderer->exts.OES_egl_image_external) { - renderer->shaders.tex_ext.program = prog = - link_program(renderer, tex_vertex_src, tex_fragment_src_external); - if (!renderer->shaders.tex_ext.program) { - goto error; - } - renderer->shaders.tex_ext.proj = glGetUniformLocation(prog, "proj"); - renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex"); - renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha"); - renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos"); - renderer->shaders.tex_ext.tex_attrib = glGetAttribLocation(prog, "texcoord"); + if (renderer->exts.OES_egl_image_external && + !link_tex_program(renderer, &renderer->shaders.tex_ext, + WLR_GLES2_SHADER_SOURCE_TEXTURE_EXTERNAL)) { + goto error; } pop_gles2_debug(renderer); diff --git a/render/gles2/shaders.c b/render/gles2/shaders.c deleted file mode 100644 index 7898059ed..000000000 --- a/render/gles2/shaders.c +++ /dev/null @@ -1,69 +0,0 @@ -#include -#include "render/gles2.h" - -// Colored quads -const GLchar quad_vertex_src[] = -"uniform mat3 proj;\n" -"uniform vec4 color;\n" -"attribute vec2 pos;\n" -"attribute vec2 texcoord;\n" -"varying vec4 v_color;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" -" v_color = color;\n" -" v_texcoord = texcoord;\n" -"}\n"; - -const GLchar quad_fragment_src[] = -"precision mediump float;\n" -"varying vec4 v_color;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_FragColor = v_color;\n" -"}\n"; - -// Textured quads -const GLchar tex_vertex_src[] = -"uniform mat3 proj;\n" -"attribute vec2 pos;\n" -"attribute vec2 texcoord;\n" -"varying vec2 v_texcoord;\n" -"\n" -"void main() {\n" -" gl_Position = vec4(proj * vec3(pos, 1.0), 1.0);\n" -" v_texcoord = texcoord;\n" -"}\n"; - -const GLchar tex_fragment_src_rgba[] = -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform sampler2D tex;\n" -"uniform float alpha;\n" -"\n" -"void main() {\n" -" gl_FragColor = texture2D(tex, v_texcoord) * alpha;\n" -"}\n"; - -const GLchar tex_fragment_src_rgbx[] = -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform sampler2D tex;\n" -"uniform float alpha;\n" -"\n" -"void main() {\n" -" gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;\n" -"}\n"; - -const GLchar tex_fragment_src_external[] = -"#extension GL_OES_EGL_image_external : require\n\n" -"precision mediump float;\n" -"varying vec2 v_texcoord;\n" -"uniform samplerExternalOES texture0;\n" -"uniform float alpha;\n" -"\n" -"void main() {\n" -" gl_FragColor = texture2D(texture0, v_texcoord) * alpha;\n" -"}\n"; diff --git a/render/gles2/shaders/common.frag b/render/gles2/shaders/common.frag new file mode 100644 index 000000000..bd178a722 --- /dev/null +++ b/render/gles2/shaders/common.frag @@ -0,0 +1,45 @@ +/* enum wlr_gles2_shader_source */ +#define SOURCE_SINGLE_COLOR 1 +#define SOURCE_TEXTURE_RGBA 2 +#define SOURCE_TEXTURE_RGBX 3 +#define SOURCE_TEXTURE_EXTERNAL 4 + +#if !defined(SOURCE) +#error "Missing shader preamble" +#endif + +#if SOURCE == SOURCE_TEXTURE_EXTERNAL +#extension GL_OES_EGL_image_external : require +#endif + +precision mediump float; + +varying vec2 v_texcoord; + +#if SOURCE == SOURCE_TEXTURE_EXTERNAL +uniform samplerExternalOES tex; +#elif SOURCE == SOURCE_TEXTURE_RGBA || SOURCE == SOURCE_TEXTURE_RGBX +uniform sampler2D tex; +#elif SOURCE == SOURCE_SINGLE_COLOR +uniform vec4 color; +#endif + +#if SOURCE != SOURCE_SINGLE_COLOR +uniform float alpha; +#else +const float alpha = 1.0; +#endif + +vec4 sample_texture() { +#if SOURCE == SOURCE_TEXTURE_RGBA || SOURCE == SOURCE_TEXTURE_EXTERNAL + return texture2D(tex, v_texcoord); +#elif SOURCE == SOURCE_TEXTURE_RGBX + return vec4(texture2D(tex, v_texcoord).rgb, 1.0); +#elif SOURCE == SOURCE_SINGLE_COLOR + return color; +#endif +} + +void main() { + gl_FragColor = sample_texture() * alpha; +} diff --git a/render/gles2/shaders/common.vert b/render/gles2/shaders/common.vert new file mode 100644 index 000000000..9cebb458f --- /dev/null +++ b/render/gles2/shaders/common.vert @@ -0,0 +1,9 @@ +uniform mat3 proj; +attribute vec2 pos; +attribute vec2 texcoord; +varying vec2 v_texcoord; + +void main() { + gl_Position = vec4(proj * vec3(pos, 1.0), 1.0); + v_texcoord = texcoord; +} diff --git a/render/gles2/shaders/embed.sh b/render/gles2/shaders/embed.sh new file mode 100755 index 000000000..acd7a1199 --- /dev/null +++ b/render/gles2/shaders/embed.sh @@ -0,0 +1,11 @@ +#!/bin/sh -eu + +var=${1:-data} +hex="$(od -A n -t x1 -v)" + +echo "static const char $var[] = {" +for byte in $hex; do + echo " 0x$byte," +done +echo " 0x00," +echo "};" diff --git a/render/gles2/shaders/meson.build b/render/gles2/shaders/meson.build new file mode 100644 index 000000000..62fbe8ce2 --- /dev/null +++ b/render/gles2/shaders/meson.build @@ -0,0 +1,19 @@ +embed = find_program('./embed.sh', native: true) + +shaders = [ + 'common.vert', + 'common.frag', +] + +foreach name : shaders + output = name.underscorify() + '_src.h' + var = name.underscorify() + '_src' + wlr_files += custom_target( + output, + command: [embed, var], + input: name, + output: output, + feed: true, + capture: true, + ) +endforeach