mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
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).
This commit is contained in:
parent
950cc41e15
commit
4d697283ae
@ -258,6 +258,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
case GSK_LINEAR_GRADIENT_NODE:
|
||||
|
||||
/* Fallbacks (=> leaf for now */
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_COLOR_MATRIX_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
@ -847,6 +848,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
case GSK_BLEND_NODE:
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
default:
|
||||
break; /* Fallback */
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskglrenderer.h"
|
||||
#include "gskglrendererprivate.h"
|
||||
|
||||
#include "gskdebugprivate.h"
|
||||
#include "gskenums.h"
|
||||
@ -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,12 @@ print_render_node_tree (GskRenderNode *root, int level)
|
||||
print_render_node_tree (gsk_shadow_node_get_child (root), level + 1);
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
g_print ("%*s GL Shader\n", level * INDENT, " ");
|
||||
for (i = 0; i < gsk_gl_shader_node_get_n_children (root); i++)
|
||||
print_render_node_tree (gsk_gl_shader_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 +507,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)
|
||||
@ -1011,6 +1057,178 @@ render_texture_node (GskGLRenderer *self,
|
||||
}
|
||||
}
|
||||
|
||||
static Program *
|
||||
compile_glshader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error)
|
||||
{
|
||||
GskGLShaderBuilder shader_builder;
|
||||
const char *shader_source;
|
||||
gsize shader_source_len;
|
||||
int n_uniforms;
|
||||
const GskGLUniform *uniforms;
|
||||
GBytes *bytes;
|
||||
int n_required_textures = gsk_gl_shader_get_n_textures (shader);
|
||||
int program_id;
|
||||
Program *program;
|
||||
|
||||
bytes = gsk_gl_shader_get_source (shader);
|
||||
shader_source = g_bytes_get_data (bytes, &shader_source_len);
|
||||
uniforms = gsk_gl_shader_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));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
|
||||
{
|
||||
g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
|
||||
"GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS (program->glshader.texture_locations)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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, shader_source_len,
|
||||
error);
|
||||
gsk_gl_shader_builder_finish (&shader_builder);
|
||||
|
||||
if (program_id < 0)
|
||||
return NULL;
|
||||
|
||||
program = gsk_gl_renderer_create_custom_program (self, shader);
|
||||
|
||||
program->id = program_id;
|
||||
INIT_COMMON_UNIFORM_LOCATION (program, alpha);
|
||||
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.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
|
||||
program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
|
||||
program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
|
||||
program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
|
||||
|
||||
/* We use u_textue1 for the texture 0 in the glshaders, so alias it here so we can use the regular setters */
|
||||
program->source_location = program->glshader.texture_locations[0];
|
||||
|
||||
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);
|
||||
/* This isn't necessary a hard error, you might declare uniforms that are not actually
|
||||
always used, for instance if you have an "API" in uniforms for multiple shaders. */
|
||||
if (program->glshader.args_locations[i] == -1)
|
||||
g_debug ("Declared uniform `%s` not found in GskGLShader", uniforms[i].name);
|
||||
}
|
||||
else
|
||||
program->glshader.args_locations[i] = -1;
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gsk_gl_render_try_compile_gl_shader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error)
|
||||
{
|
||||
Program *program;
|
||||
|
||||
gdk_gl_context_make_current (self->gl_context);
|
||||
|
||||
/* Maybe we tried to compile it already? */
|
||||
program = gsk_gl_renderer_lookup_custom_program (self, shader);
|
||||
if (program != NULL)
|
||||
{
|
||||
if (program->id > 0)
|
||||
return TRUE;
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_error_copy (program->glshader.compile_error));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
program = compile_glshader (self, shader, error);
|
||||
return program != NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
render_gl_shader_node (GskGLRenderer *self,
|
||||
GskRenderNode *node,
|
||||
RenderOpBuilder *builder)
|
||||
{
|
||||
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
|
||||
Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
|
||||
int n_children = gsk_gl_shader_node_get_n_children (node);
|
||||
|
||||
if (program == NULL)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
program = compile_glshader (self, shader, &error);
|
||||
if (program == NULL)
|
||||
{
|
||||
/* We create the program anyway (in a failed state), so that any compiler warnings or other are only reported once */
|
||||
program = gsk_gl_renderer_create_custom_program (self, shader);
|
||||
program->id = -1;
|
||||
program->glshader.compile_error = error;
|
||||
|
||||
g_warning ("Failed to compile gl shader: %s", error->message);
|
||||
}
|
||||
}
|
||||
|
||||
if (program->id >= 0 && n_children <= G_N_ELEMENTS (program->glshader.texture_locations))
|
||||
{
|
||||
GBytes *args;
|
||||
TextureRegion regions[4];
|
||||
gboolean is_offscreen[4];
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
GskRenderNode *child = gsk_gl_shader_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))
|
||||
return;
|
||||
}
|
||||
|
||||
args = gsk_gl_shader_node_get_args (node);
|
||||
ops_set_program (builder, program);
|
||||
|
||||
ops_set_gl_shader_args (builder, shader, node->bounds.size.width, node->bounds.size.height, g_bytes_get_data (args, NULL));
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
ops_set_texture (builder, regions[i].texture_id);
|
||||
else
|
||||
ops_set_extra_texture (builder, regions[i].texture_id, i);
|
||||
}
|
||||
|
||||
load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
else
|
||||
{
|
||||
static GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
|
||||
ops_set_program (builder, &self->programs->color_program);
|
||||
ops_set_color (builder, &pink);
|
||||
load_vertex_data (ops_draw (builder, NULL), node, builder);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns TRUE is applying transform to bounds
|
||||
* yields an axis-aligned rectangle
|
||||
*/
|
||||
@ -2694,6 +2912,17 @@ 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);
|
||||
glUniform1i (program->glshader.texture_locations[op->idx], op->idx);
|
||||
glActiveTexture (GL_TEXTURE0 + op->idx);
|
||||
glBindTexture (GL_TEXTURE_2D, op->texture_id);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_color_matrix_op (const Program *program,
|
||||
const OpColorMatrix *op)
|
||||
@ -2838,6 +3067,51 @@ apply_border_op (const Program *program,
|
||||
glUniform4fv (program->border.outline_rect_location, 3, (float *)&op->outline.bounds);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_gl_shader_args_op (const Program *program,
|
||||
const OpGLShader *op)
|
||||
{
|
||||
int n_uniforms, i;
|
||||
const GskGLUniform *uniforms;
|
||||
|
||||
OP_PRINT (" -> GL Shader Args");
|
||||
|
||||
glUniform2fv (program->glshader.size_location, 1, op->size);
|
||||
|
||||
uniforms = gsk_gl_shader_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_GL_UNIFORM_TYPE_NONE:
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_FLOAT:
|
||||
glUniform1fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_INT:
|
||||
glUniform1iv (program->glshader.args_locations[i], 1, (const gint32 *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_UINT:
|
||||
case GSK_GL_UNIFORM_TYPE_BOOL:
|
||||
glUniform1uiv (program->glshader.args_locations[i], 1, (const guint32 *) data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_VEC2:
|
||||
glUniform2fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_TYPE_VEC3:
|
||||
glUniform3fv (program->glshader.args_locations[i], 1, (const float *)data);
|
||||
break;
|
||||
case GSK_GL_UNIFORM_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)
|
||||
@ -2909,6 +3183,32 @@ 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);
|
||||
if (program->index == -1 &&
|
||||
program->glshader.compile_error != NULL)
|
||||
g_error_free (program->glshader.compile_error);
|
||||
|
||||
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)
|
||||
{
|
||||
@ -2918,9 +3218,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;
|
||||
}
|
||||
@ -2941,15 +3243,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)
|
||||
@ -2984,35 +3304,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 ();
|
||||
|
||||
@ -3023,7 +3315,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, 0, error);
|
||||
if (prog->id < 0)
|
||||
{
|
||||
g_clear_pointer (&programs, gsk_gl_renderer_programs_unref);
|
||||
@ -3468,6 +3760,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
||||
render_repeat_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
render_gl_shader_node (self, node, builder);
|
||||
break;
|
||||
|
||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
case GSK_CAIRO_NODE:
|
||||
@ -3750,6 +4046,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);
|
||||
@ -3796,6 +4096,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
|
||||
apply_repeat_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_CHANGE_GL_SHADER_ARGS:
|
||||
apply_gl_shader_args_op (program, ptr);
|
||||
break;
|
||||
|
||||
case OP_DRAW:
|
||||
{
|
||||
const OpDraw *op = ptr;
|
||||
|
14
gsk/gl/gskglrendererprivate.h
Normal file
14
gsk/gl/gskglrendererprivate.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef __GSK_GL_RENDERER_PRIVATE_H__
|
||||
#define __GSK_GL_RENDERER_PRIVATE_H__
|
||||
|
||||
#include "gskglrenderer.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean gsk_gl_render_try_compile_gl_shader (GskGLRenderer *self,
|
||||
GskGLShader *shader,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
|
@ -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_gl_shader_args (RenderOpBuilder *builder,
|
||||
GskGLShader *shader,
|
||||
float width,
|
||||
float height,
|
||||
const guchar *uniform_data)
|
||||
{
|
||||
OpGLShader *op;
|
||||
|
||||
op = ops_begin (builder, OP_CHANGE_GL_SHADER_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,
|
||||
|
@ -84,7 +84,7 @@ typedef struct
|
||||
|
||||
struct _Program
|
||||
{
|
||||
int index; /* Into the renderer's program array */
|
||||
int index; /* Into the renderer's program array -1 for custom */
|
||||
|
||||
int id;
|
||||
/* Common locations (gl_common)*/
|
||||
@ -159,6 +159,12 @@ struct _Program
|
||||
int child_bounds_location;
|
||||
int texture_rect_location;
|
||||
} repeat;
|
||||
struct {
|
||||
int size_location;
|
||||
int args_locations[8];
|
||||
int texture_locations[4];
|
||||
GError *compile_error;
|
||||
} glshader;
|
||||
};
|
||||
ProgramState state;
|
||||
};
|
||||
@ -184,7 +190,7 @@ typedef struct {
|
||||
Program unblurred_outset_shadow_program;
|
||||
};
|
||||
};
|
||||
ProgramState state[GL_N_PROGRAMS];
|
||||
GHashTable *custom_programs; /* GskGLShader -> Program* */
|
||||
} GskGLRendererPrograms;
|
||||
|
||||
typedef struct
|
||||
@ -256,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);
|
||||
@ -282,6 +291,11 @@ void ops_set_inset_shadow (RenderOpBuilder *self,
|
||||
const GdkRGBA *color,
|
||||
float dx,
|
||||
float dy);
|
||||
void ops_set_gl_shader_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,
|
||||
|
@ -129,6 +129,8 @@ print_shader_info (const char *prefix,
|
||||
int
|
||||
gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
const char *resource_path,
|
||||
const char *extra_fragment_snippet,
|
||||
gsize extra_fragment_length,
|
||||
GError **error)
|
||||
{
|
||||
|
||||
@ -191,7 +193,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
print_shader_info ("Vertex shader", vertex_id, resource_path);
|
||||
|
||||
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" : "",
|
||||
@ -200,7 +202,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,
|
||||
@ -211,6 +214,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self,
|
||||
-1,
|
||||
-1,
|
||||
-1,
|
||||
extra_fragment_length,
|
||||
});
|
||||
glCompileShader (fragment_id);
|
||||
|
||||
|
@ -33,6 +33,8 @@ 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,
|
||||
gsize extra_fragment_length,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -31,6 +31,8 @@ static guint op_sizes[OP_LAST] = {
|
||||
sizeof (OpDebugGroup),
|
||||
0,
|
||||
sizeof (OpBlend),
|
||||
sizeof (OpGLShader),
|
||||
sizeof (OpExtraTexture),
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -39,6 +39,8 @@ typedef enum
|
||||
OP_PUSH_DEBUG_GROUP = 25,
|
||||
OP_POP_DEBUG_GROUP = 26,
|
||||
OP_CHANGE_BLEND = 27,
|
||||
OP_CHANGE_GL_SHADER_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);
|
||||
|
@ -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([
|
||||
|
21
gsk/resources/glsl/custom.glsl
Normal file
21
gsk/resources/glsl/custom.glsl
Normal file
@ -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);
|
||||
}
|
@ -256,6 +256,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
|
||||
case GSK_NOT_A_RENDER_NODE:
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_SHADOW_NODE:
|
||||
case GSK_RADIAL_GRADIENT_NODE:
|
||||
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
|
||||
|
Loading…
Reference in New Issue
Block a user