From 6c13f89f91ba19cd8f6043958ab0476748e29a3d Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Fri, 18 Sep 2020 18:03:30 +0200 Subject: [PATCH] Support GLShaderNode in backends For vulkan/broadway this just means to ignore it, but for the gl backend we support (with up to 4 texture inputs, which is similar to what shadertoy does, so should be widely supported). --- gsk/broadway/gskbroadwayrenderer.c | 10 + gsk/gl/gskglrenderer.c | 328 +++++++++++++++++++++++++---- gsk/gl/gskglrenderops.c | 28 +++ gsk/gl/gskglrenderopsprivate.h | 15 +- gsk/gl/gskglshaderbuilder.c | 7 +- gsk/gl/gskglshaderbuilderprivate.h | 1 + gsk/gl/opbuffer.c | 2 + gsk/gl/opbuffer.h | 15 ++ gsk/meson.build | 1 + gsk/resources/glsl/custom.glsl | 21 ++ gsk/vulkan/gskvulkanrenderpass.c | 4 + 11 files changed, 391 insertions(+), 41 deletions(-) create mode 100644 gsk/resources/glsl/custom.glsl diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c index e18b03f826..fb3e4fd0ab 100644 --- a/gsk/broadway/gskbroadwayrenderer.c +++ b/gsk/broadway/gskbroadwayrenderer.c @@ -272,6 +272,11 @@ collect_reused_child_nodes (GskRenderer *renderer, /* Bin nodes */ + case GSK_GLSHADER_NODE: + collect_reused_node (renderer, + gsk_glshader_node_get_fallback_child (node)); + break; + case GSK_SHADOW_NODE: collect_reused_node (renderer, gsk_shadow_node_get_child (node)); @@ -792,6 +797,11 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } return; + case GSK_GLSHADER_NODE: + gsk_broadway_renderer_add_node (renderer, + gsk_glshader_node_get_fallback_child (node), offset_x, offset_y, clip_bounds); + return; + /* Generic nodes */ case GSK_CONTAINER_NODE: diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index bc1831e347..2ec393941f 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -19,6 +19,7 @@ #include "gskglnodesampleprivate.h" #include "gsktransform.h" #include "glutilsprivate.h" +#include "gskglshaderprivate.h" #include "gskprivate.h" @@ -64,6 +65,11 @@ glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\ }G_STMT_END +static Program *gsk_gl_renderer_lookup_custom_program (GskGLRenderer *self, + GskGLShader *shader); +static Program *gsk_gl_renderer_create_custom_program (GskGLRenderer *self, + GskGLShader *shader); + typedef enum { FORCE_OFFSCREEN = 1 << 0, @@ -130,6 +136,13 @@ print_render_node_tree (GskRenderNode *root, int level) print_render_node_tree (gsk_shadow_node_get_child (root), level + 1); break; + case GSK_GLSHADER_NODE: + g_print ("%*s GLShader\n", level * INDENT, " "); + print_render_node_tree (gsk_glshader_node_get_fallback_child (root), level + 1); + for (i = 0; i < gsk_glshader_node_get_n_children (root); i++) + print_render_node_tree (gsk_glshader_node_get_child (root, i), level + 1); + break; + case GSK_TEXTURE_NODE: g_print ("%*s Texture %p\n", level * INDENT, " ", gsk_texture_node_get_texture (root)); break; @@ -495,6 +508,40 @@ struct _GskGLRendererClass G_DEFINE_TYPE (GskGLRenderer, gsk_gl_renderer, GSK_TYPE_RENDERER) +static void +init_shader_builder (GskGLRenderer *self, + GskGLShaderBuilder *shader_builder) +{ +#ifdef G_ENABLE_DEBUG + if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS)) + shader_builder->debugging = TRUE; +#endif + + if (gdk_gl_context_get_use_es (self->gl_context)) + { + gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GLES); + shader_builder->gles = TRUE; + } + else if (gdk_gl_context_is_legacy (self->gl_context)) + { + int maj, min; + + gdk_gl_context_get_version (self->gl_context, &maj, &min); + + if (maj == 3) + gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3_LEGACY); + else + gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL2_LEGACY); + + shader_builder->legacy = TRUE; + } + else + { + gsk_gl_shader_builder_set_glsl_version (shader_builder, SHADER_VERSION_GL3); + shader_builder->gl3 = TRUE; + } +} + static void G_GNUC_UNUSED add_rect_ops (RenderOpBuilder *builder, const graphene_rect_t *r) @@ -1006,6 +1053,128 @@ render_texture_node (GskGLRenderer *self, } } +static inline void +render_glshader_node (GskGLRenderer *self, + GskRenderNode *node, + RenderOpBuilder *builder) +{ + GskGLShader *shader = gsk_glshader_node_get_shader (node); + Program *program = gsk_gl_renderer_lookup_custom_program (self, shader); + GskRenderNode *fallback = gsk_glshader_node_get_fallback_child (node); + int n_children = gsk_glshader_node_get_n_children (node); + + if (program == NULL) + { + GskGLShaderBuilder shader_builder; + const char *shader_source; + GError *error = NULL; + int n_uniforms; + const GskGLUniform *uniforms; + int n_required_sources = gsk_glshader_get_n_required_sources (shader); + + /* We always create the program, so that any compiler warnings or other is only reported once */ + program = gsk_gl_renderer_create_custom_program (self, shader); + + shader_source = gsk_glshader_get_sourcecode (shader); + uniforms = gsk_glshader_get_uniforms (shader, &n_uniforms); + + if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations)) + { + g_set_error (&error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT, + "GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS (program->glshader.args_locations)); + } + else if (n_required_sources > 1 + G_N_ELEMENTS (program->glshader.extra_source_locations)) + { + g_set_error (&error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT, + "GLShaderNode supports max %d texture sources", (int)(1 + G_N_ELEMENTS (program->glshader.extra_source_locations))); + } + else + { + gsk_gl_shader_builder_init (&shader_builder, + "/org/gtk/libgsk/glsl/preamble.glsl", + "/org/gtk/libgsk/glsl/preamble.vs.glsl", + "/org/gtk/libgsk/glsl/preamble.fs.glsl"); + + init_shader_builder (self, &shader_builder); + + program->id = gsk_gl_shader_builder_create_program (&shader_builder, + "/org/gtk/libgsk/glsl/custom.glsl", + shader_source, + &error); + gsk_gl_shader_builder_finish (&shader_builder); + + if (program->id >= 0) + { + INIT_COMMON_UNIFORM_LOCATION (program, alpha); + INIT_COMMON_UNIFORM_LOCATION (program, source); + INIT_COMMON_UNIFORM_LOCATION (program, clip_rect); + INIT_COMMON_UNIFORM_LOCATION (program, viewport); + INIT_COMMON_UNIFORM_LOCATION (program, projection); + INIT_COMMON_UNIFORM_LOCATION (program, modelview); + program->glshader.size_location = glGetUniformLocation(program->id, "u_size"); + program->glshader.extra_source_locations[0] = glGetUniformLocation(program->id, "u_source2"); + program->glshader.extra_source_locations[1] = glGetUniformLocation(program->id, "u_source3"); + program->glshader.extra_source_locations[2] = glGetUniformLocation(program->id, "u_source4"); + for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++) + { + if (i < n_uniforms) + { + program->glshader.args_locations[i] = glGetUniformLocation(program->id, uniforms[i].name); + if (program->glshader.args_locations[i] == -1) + g_warning ("Expected uniform `%s` not found in shader", uniforms[i].name); + } + else + program->glshader.args_locations[i] = -1; + } + } + } + + if (program->id <= 0) + { + g_warning ("Failed to compile gl shader: %s\n", error->message); + g_error_free (error); + } + } + + if (program->id >= 0 && n_children <= 4) + { + const guchar *uniform_data; + TextureRegion regions[4]; + gboolean is_offscreen[4]; + + for (guint i = 0; i < n_children; i++) + { + GskRenderNode *child = gsk_glshader_node_get_child (node, i); + if (!add_offscreen_ops (self, builder, + &node->bounds, + child, + ®ions[i], &is_offscreen[i], + FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY)) + { + if (fallback) + gsk_gl_renderer_add_render_ops (self, fallback, builder); + return; + } + } + + uniform_data = gsk_glshader_node_get_uniform_data (node); + ops_set_program (builder, program); + + ops_set_glshader_args (builder, shader, node->bounds.size.width, node->bounds.size.height, uniform_data); + if (n_children >= 0) + ops_set_texture (builder, regions[0].texture_id); + for (guint i = 1; i < n_children; i++) + ops_set_extra_texture (builder, regions[i].texture_id, i-1); + + load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder); + } + else + { + if (fallback) + gsk_gl_renderer_add_render_ops (self, fallback, builder); + } +} + /* Returns TRUE is applying transform to bounds * yields an axis-aligned rectangle */ @@ -2671,6 +2840,18 @@ apply_source_texture_op (const Program *program, glBindTexture (GL_TEXTURE_2D, op->texture_id); } +static inline void +apply_source_extra_texture_op (const Program *program, + const OpExtraTexture *op) +{ + g_assert(op->texture_id != 0); + OP_PRINT (" -> New extra texture %d: %d", op->idx, op->texture_id); + /* Use texture unit 1 + op->idx for the source */ + glUniform1i (program->glshader.extra_source_locations[op->idx], 1 + op->idx); + glActiveTexture (GL_TEXTURE0 + 1 + op->idx); + glBindTexture (GL_TEXTURE_2D, op->texture_id); +} + static inline void apply_color_matrix_op (const Program *program, const OpColorMatrix *op) @@ -2815,6 +2996,51 @@ apply_border_op (const Program *program, glUniform4fv (program->border.outline_rect_location, 3, (float *)&op->outline.bounds); } +static inline void +apply_glshader_args_op (const Program *program, + const OpGLShader *op) +{ + int n_uniforms, i; + const GskGLUniform *uniforms; + + OP_PRINT (" -> GLShader Args"); + + glUniform2fv (program->glshader.size_location, 1, op->size); + + uniforms = gsk_glshader_get_uniforms (op->shader, &n_uniforms); + for (i = 0; i < n_uniforms; i++) + { + const GskGLUniform *u = &uniforms[i]; + const guchar *data = op->uniform_data + u->offset; + + switch (u->type) + { + default: + case GSK_GLUNIFORM_TYPE_NONE: + break; + case GSK_GLUNIFORM_TYPE_FLOAT: + glUniform1fv (program->glshader.args_locations[i], 1, (const float *)data); + break; + case GSK_GLUNIFORM_TYPE_INT: + glUniform1iv (program->glshader.args_locations[i], 1, (const gint32 *)data); + break; + case GSK_GLUNIFORM_TYPE_UINT: + case GSK_GLUNIFORM_TYPE_BOOL: + glUniform1uiv (program->glshader.args_locations[i], 1, (const guint32 *) data); + break; + case GSK_GLUNIFORM_TYPE_VEC2: + glUniform2fv (program->glshader.args_locations[i], 1, (const float *)data); + break; + case GSK_GLUNIFORM_TYPE_VEC3: + glUniform3fv (program->glshader.args_locations[i], 1, (const float *)data); + break; + case GSK_GLUNIFORM_TYPE_VEC4: + glUniform4fv (program->glshader.args_locations[i], 1, (const float *)data); + break; + } + } +} + static inline void apply_border_width_op (const Program *program, const OpBorder *op) @@ -2886,6 +3112,28 @@ gsk_gl_renderer_dispose (GObject *gobject) G_OBJECT_CLASS (gsk_gl_renderer_parent_class)->dispose (gobject); } +static void +program_init (Program *program) +{ + program->index = -1; + program->state.opacity = 1.0f; +} + +static void +program_finalize (Program *program) +{ + if (program->id > 0) + glDeleteProgram (program->id); + gsk_transform_unref (program->state.modelview); +} + +static void +program_free (Program *program) +{ + program_finalize (program); + g_free (program); +} + static GskGLRendererPrograms * gsk_gl_renderer_programs_new (void) { @@ -2895,9 +3143,11 @@ gsk_gl_renderer_programs_new (void) programs = g_new0 (GskGLRendererPrograms, 1); programs->ref_count = 1; for (i = 0; i < GL_N_PROGRAMS; i ++) - { - programs->programs[i].state.opacity = 1.0f; - } + program_init (&programs->programs[i]); + + /* We use direct hash for performance, not string hash on the source, because we assume each caller + * reuses a single GskGLShader for all uses and different callers will use different source content. */ + programs->custom_programs = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)program_free); return programs; } @@ -2918,15 +3168,33 @@ gsk_gl_renderer_programs_unref (GskGLRendererPrograms *programs) if (programs->ref_count == 0) { for (i = 0; i < GL_N_PROGRAMS; i ++) - { - if (programs->programs[i].id > 0) - glDeleteProgram (programs->programs[i].id); - gsk_transform_unref (programs->programs[i].state.modelview); - } + program_finalize (&programs->programs[i]); + + g_hash_table_destroy (programs->custom_programs); g_free (programs); } } +static Program * +gsk_gl_renderer_lookup_custom_program (GskGLRenderer *self, + GskGLShader *shader) +{ + return g_hash_table_lookup (self->programs->custom_programs, shader); +} + +static Program * +gsk_gl_renderer_create_custom_program (GskGLRenderer *self, + GskGLShader *shader) +{ + Program *program = g_new0 (Program, 1); + + program_init (program); + + g_hash_table_insert (self->programs->custom_programs, g_object_ref (shader), program); + + return program; +} + static GskGLRendererPrograms * gsk_gl_renderer_create_programs (GskGLRenderer *self, GError **error) @@ -2961,35 +3229,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, g_assert (G_N_ELEMENTS (program_definitions) == GL_N_PROGRAMS); -#ifdef G_ENABLE_DEBUG - if (GSK_RENDERER_DEBUG_CHECK (GSK_RENDERER (self), SHADERS)) - shader_builder.debugging = TRUE; -#endif - - if (gdk_gl_context_get_use_es (self->gl_context)) - { - - gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GLES); - shader_builder.gles = TRUE; - } - else if (gdk_gl_context_is_legacy (self->gl_context)) - { - int maj, min; - - gdk_gl_context_get_version (self->gl_context, &maj, &min); - - if (maj == 3) - gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL3_LEGACY); - else - gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL2_LEGACY); - - shader_builder.legacy = TRUE; - } - else - { - gsk_gl_shader_builder_set_glsl_version (&shader_builder, SHADER_VERSION_GL3); - shader_builder.gl3 = TRUE; - } + init_shader_builder (self, &shader_builder); programs = gsk_gl_renderer_programs_new (); @@ -3000,7 +3240,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, prog->index = i; prog->id = gsk_gl_shader_builder_create_program (&shader_builder, program_definitions[i].resource_path, - error); + NULL, error); if (prog->id < 0) { g_clear_pointer (&programs, gsk_gl_renderer_programs_unref); @@ -3445,6 +3685,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, render_repeat_node (self, node, builder); break; + case GSK_GLSHADER_NODE: + render_glshader_node (self, node, builder); + break; + case GSK_REPEATING_LINEAR_GRADIENT_NODE: case GSK_REPEATING_RADIAL_GRADIENT_NODE: case GSK_CAIRO_NODE: @@ -3727,6 +3971,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self) apply_source_texture_op (program, ptr); break; + case OP_CHANGE_EXTRA_SOURCE_TEXTURE: + apply_source_extra_texture_op (program, ptr); + break; + case OP_CHANGE_CROSS_FADE: g_assert (program == &self->programs->cross_fade_program); apply_cross_fade_op (program, ptr); @@ -3773,6 +4021,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self) apply_repeat_op (program, ptr); break; + case OP_CHANGE_GLSHADER_ARGS: + apply_glshader_args_op (program, ptr); + break; + case OP_DRAW: { const OpDraw *op = ptr; diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index d8ec3b9ec6..a822754567 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -558,6 +558,18 @@ ops_set_texture (RenderOpBuilder *builder, builder->current_texture = texture_id; } +void +ops_set_extra_texture (RenderOpBuilder *builder, + int texture_id, + int idx) +{ + OpExtraTexture *op; + + op = ops_begin (builder, OP_CHANGE_EXTRA_SOURCE_TEXTURE); + op->texture_id = texture_id; + op->idx = idx; +} + int ops_set_render_target (RenderOpBuilder *builder, int render_target_id) @@ -621,6 +633,22 @@ ops_set_color (RenderOpBuilder *builder, op->rgba = color; } +void +ops_set_glshader_args (RenderOpBuilder *builder, + GskGLShader *shader, + float width, + float height, + const guchar *uniform_data) +{ + OpGLShader *op; + + op = ops_begin (builder, OP_CHANGE_GLSHADER_ARGS); + op->shader = shader; + op->size[0] = width; + op->size[1] = height; + op->uniform_data = uniform_data; +} + void ops_set_color_matrix (RenderOpBuilder *builder, const graphene_matrix_t *matrix, diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index f2dff2862d..ff1184536a 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -159,6 +159,11 @@ struct _Program int child_bounds_location; int texture_rect_location; } repeat; + struct { + int size_location; + int args_locations[8]; + int extra_source_locations[3]; + } glshader; }; ProgramState state; @@ -185,7 +190,7 @@ typedef struct { Program unblurred_outset_shadow_program; }; }; - ProgramState state[GL_N_PROGRAMS]; + GHashTable *custom_programs; /* GskGLShader -> Program* */ } GskGLRendererPrograms; typedef struct @@ -257,6 +262,9 @@ graphene_rect_t ops_set_viewport (RenderOpBuilder *builder, void ops_set_texture (RenderOpBuilder *builder, int texture_id); +void ops_set_extra_texture (RenderOpBuilder *builder, + int texture_id, + int idx); int ops_set_render_target (RenderOpBuilder *builder, int render_target_id); @@ -283,6 +291,11 @@ void ops_set_inset_shadow (RenderOpBuilder *self, const GdkRGBA *color, float dx, float dy); +void ops_set_glshader_args (RenderOpBuilder *builder, + GskGLShader *shader, + float width, + float height, + const guchar *uniform_data); void ops_set_unblurred_outset_shadow (RenderOpBuilder *self, const GskRoundedRect outline, float spread, diff --git a/gsk/gl/gskglshaderbuilder.c b/gsk/gl/gskglshaderbuilder.c index 443048865e..c0e763a85e 100644 --- a/gsk/gl/gskglshaderbuilder.c +++ b/gsk/gl/gskglshaderbuilder.c @@ -96,6 +96,7 @@ check_shader_error (int shader_id, int gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, const char *resource_path, + const char *extra_fragment_snippet, GError **error) { @@ -156,7 +157,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, } fragment_id = glCreateShader (GL_FRAGMENT_SHADER); - glShaderSource (fragment_id, 8, + glShaderSource (fragment_id, 9, (const char *[]) { version_buffer, self->debugging ? "#define GSK_DEBUG 1\n" : "", @@ -165,7 +166,8 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, self->gles ? "#define GSK_GLES 1\n" : "", g_bytes_get_data (self->preamble, NULL), g_bytes_get_data (self->fs_preamble, NULL), - fragment_shader_start + fragment_shader_start, + extra_fragment_snippet ? extra_fragment_snippet : "" }, (int[]) { -1, @@ -176,6 +178,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, -1, -1, -1, + -1, }); glCompileShader (fragment_id); diff --git a/gsk/gl/gskglshaderbuilderprivate.h b/gsk/gl/gskglshaderbuilderprivate.h index ec9cd66845..1a774dc4a7 100644 --- a/gsk/gl/gskglshaderbuilderprivate.h +++ b/gsk/gl/gskglshaderbuilderprivate.h @@ -33,6 +33,7 @@ void gsk_gl_shader_builder_set_glsl_version (GskGLShaderBuilder *self, int gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, const char *resource_path, + const char *extra_fragment_snippet, GError **error); G_END_DECLS diff --git a/gsk/gl/opbuffer.c b/gsk/gl/opbuffer.c index f212e96eec..8a7f8c9b1f 100644 --- a/gsk/gl/opbuffer.c +++ b/gsk/gl/opbuffer.c @@ -31,6 +31,8 @@ static guint op_sizes[OP_LAST] = { sizeof (OpDebugGroup), 0, sizeof (OpBlend), + sizeof (OpGLShader), + sizeof (OpExtraTexture), }; void diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h index dcdedc6c50..aaca21cc94 100644 --- a/gsk/gl/opbuffer.h +++ b/gsk/gl/opbuffer.h @@ -39,6 +39,8 @@ typedef enum OP_PUSH_DEBUG_GROUP = 25, OP_POP_DEBUG_GROUP = 26, OP_CHANGE_BLEND = 27, + OP_CHANGE_GLSHADER_ARGS = 28, + OP_CHANGE_EXTRA_SOURCE_TEXTURE = 29, OP_LAST } OpKind; @@ -124,6 +126,12 @@ typedef struct int texture_id; } OpTexture; +typedef struct +{ + int texture_id; + int idx; +} OpExtraTexture; + typedef struct { gsize vao_offset; @@ -198,6 +206,13 @@ typedef struct float texture_rect[4]; } OpRepeat; +typedef struct +{ + float size[2]; + GskGLShader *shader; + const guchar *uniform_data; +} OpGLShader; + void op_buffer_init (OpBuffer *buffer); void op_buffer_destroy (OpBuffer *buffer); void op_buffer_clear (OpBuffer *buffer); diff --git a/gsk/meson.build b/gsk/meson.build index b52d379eb9..e71ac50c78 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -16,6 +16,7 @@ gsk_private_gl_shaders = [ 'resources/glsl/cross_fade.glsl', 'resources/glsl/blend.glsl', 'resources/glsl/repeat.glsl', + 'resources/glsl/custom.glsl', ] gsk_public_sources = files([ diff --git a/gsk/resources/glsl/custom.glsl b/gsk/resources/glsl/custom.glsl new file mode 100644 index 0000000000..d2aed97fc8 --- /dev/null +++ b/gsk/resources/glsl/custom.glsl @@ -0,0 +1,21 @@ +// VERTEX_SHADER: +void main() { + gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); + vUv = vec2(aUv.x, aUv.y); +} + +// FRAGMENT_SHADER: +// The shader supplies: +void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv); + +uniform vec2 u_size; +uniform sampler2D u_source2; +uniform sampler2D u_source3; +uniform sampler2D u_source4; + +void main() { + vec4 fragColor; + vec2 fragCoord = vec2(vUv.x * u_size.x, (1.0-vUv.y) * u_size.y); + mainImage(fragColor, fragCoord, u_size, vUv); + gskSetOutputColor(fragColor); +} diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 2ea547881c..7617316378 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -539,6 +539,10 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, } return; + case GSK_GLSHADER_NODE: + gsk_vulkan_render_pass_add_node (self, render, constants, gsk_glshader_node_get_fallback_child (node)); + return; + case GSK_DEBUG_NODE: gsk_vulkan_render_pass_add_node (self, render, constants, gsk_debug_node_get_child (node)); return;