Add GskGLShaderNode

This is a rendernode that is supposed to run a GLSL fragment
shader with a set of inputs and produce outputs.
The inputs are:
 * A GskGLShader object with the source and uniforms definitions
   computed from the source.
 * A the data for the uniforms, formated according to the GskGLShader
 * a list of render nodes that are rendered to textures

Additionally there is a fallback node which is used in case
OpenGL is not supported or there is some kind of failure
with the shader code.
This commit is contained in:
Alexander Larsson
2020-09-18 17:46:57 +02:00
parent 0693deb02f
commit 111dfdf3f5
10 changed files with 2148 additions and 3 deletions

View File

@@ -48,6 +48,7 @@
* @GSK_TEXT_NODE: A node containing a glyph string
* @GSK_BLUR_NODE: A node that applies a blur
* @GSK_DEBUG_NODE: Debug information that does not affect the rendering
* @GSK_GL_SHADER_NODE: A node that uses OpenGL fragment shaders to render
* The type of a node determines what the node is rendering.
*/
@@ -75,7 +76,8 @@ typedef enum {
GSK_CROSS_FADE_NODE,
GSK_TEXT_NODE,
GSK_BLUR_NODE,
GSK_DEBUG_NODE
GSK_DEBUG_NODE,
GSK_GL_SHADER_NODE
} GskRenderNodeType;
/**
@@ -218,4 +220,32 @@ typedef enum
GSK_TRANSFORM_CATEGORY_IDENTITY
} GskTransformCategory;
/**
* GskGLUniformType:
* @GSK_GLUNIFORM_TYPE_NONE: No type, used for uninitialized or unspecified values.
* @GSK_GLUNIFORM_TYPE_FLOAT: A float uniform
* @GSK_GLUNIFORM_TYPE_INT: A GLSL int / gint32 uniform
* @GSK_GLUNIFORM_TYPE_UINT: A GLSL uint / guint32 uniform
* @GSK_GLUNIFORM_TYPE_BOOL: A GLSL bool / gboolean uniform
* @GSK_GLUNIFORM_TYPE_VEC2: A GLSL vec2 / graphene_vec2_t uniform
* @GSK_GLUNIFORM_TYPE_VEC3: A GLSL vec3 / graphene_vec3_t uniform
* @GSK_GLUNIFORM_TYPE_VEC4: A GLSL vec4 / graphene_vec4_t uniform
*
* This defines the types of the uniforms that #GskGLShaders
* declare. It defines both what the type is called in the GLSL shader
* code, and what the corresponding C type is on the Gtk side.
*/
typedef enum
{
GSK_GLUNIFORM_TYPE_NONE,
GSK_GLUNIFORM_TYPE_FLOAT,
GSK_GLUNIFORM_TYPE_INT,
GSK_GLUNIFORM_TYPE_UINT,
GSK_GLUNIFORM_TYPE_BOOL,
GSK_GLUNIFORM_TYPE_VEC2,
GSK_GLUNIFORM_TYPE_VEC3,
GSK_GLUNIFORM_TYPE_VEC4,
} GskGLUniformType;
#endif /* __GSK_TYPES_H__ */

1134
gsk/gskglshader.c Normal file

File diff suppressed because it is too large Load Diff

153
gsk/gskglshader.h Normal file
View File

@@ -0,0 +1,153 @@
/* GSK - The GTK Scene Kit
*
* Copyright 2020 Red Hat Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GSK_GL_SHADER_H__
#define __GSK_GL_SHADER_H__
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gsk/gsk.h> can be included directly."
#endif
#include <stdarg.h>
#include <gsk/gsktypes.h>
#include <gsk/gskenums.h>
G_BEGIN_DECLS
#define GSK_TYPE_GLSHADER (gsk_gl_shader_get_type ())
GDK_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (GskGLShader, gsk_gl_shader, GSK, GL_SHADER, GObject)
GDK_AVAILABLE_IN_ALL
GskGLShader * gsk_gl_shader_new_from_bytes (GBytes *sourcecode);
GDK_AVAILABLE_IN_ALL
GskGLShader * gsk_gl_shader_new_from_resource (const char *resource_path);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_get_bytes (GskGLShader *shader);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_get_n_required_textures (GskGLShader *shader);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_get_n_uniforms (GskGLShader *shader);
GDK_AVAILABLE_IN_ALL
const char * gsk_gl_shader_get_uniform_name (GskGLShader *shader,
int idx);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_find_uniform_by_name (GskGLShader *shader,
const char *name);
GDK_AVAILABLE_IN_ALL
GskGLUniformType gsk_gl_shader_get_uniform_type (GskGLShader *shader,
int idx);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_get_uniform_offset (GskGLShader *shader,
int idx);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_get_uniforms_size (GskGLShader *shader);
/* Helpers for managing uniform data */
GDK_AVAILABLE_IN_ALL
float gsk_gl_shader_get_uniform_data_float (GskGLShader *shader,
GBytes *uniform_data,
int idx);
GDK_AVAILABLE_IN_ALL
gint32 gsk_gl_shader_get_uniform_data_int (GskGLShader *shader,
GBytes *uniform_data,
int idx);
GDK_AVAILABLE_IN_ALL
guint32 gsk_gl_shader_get_uniform_data_uint (GskGLShader *shader,
GBytes *uniform_data,
int idx);
GDK_AVAILABLE_IN_ALL
gboolean gsk_gl_shader_get_uniform_data_bool (GskGLShader *shader,
GBytes *uniform_data,
int idx);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_uniform_data_vec2 (GskGLShader *shader,
GBytes *uniform_data,
int idx,
graphene_vec2_t *out_value);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_uniform_data_vec3 (GskGLShader *shader,
GBytes *uniform_data,
int idx,
graphene_vec3_t *out_value);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_uniform_data_vec4 (GskGLShader *shader,
GBytes *uniform_data,
int idx,
graphene_vec4_t *out_value);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_format_uniform_data_va (GskGLShader *shader,
va_list uniforms);
typedef struct _GskUniformDataBuilder GskUniformDataBuilder;
GDK_AVAILABLE_IN_ALL
GskUniformDataBuilder *gsk_gl_shader_build_uniform_data (GskGLShader *shader);
#define GSK_TYPE_UNIFORM_DATA_BUILDER (gsk_uniform_data_builder_get_type ())
GDK_AVAILABLE_IN_ALL
GType gsk_uniform_data_builder_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GBytes * gsk_uniform_data_builder_finish (GskUniformDataBuilder *builder);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_free (GskUniformDataBuilder *builder);
GDK_AVAILABLE_IN_ALL
GskUniformDataBuilder *gsk_uniform_data_builder_copy (GskUniformDataBuilder *builder);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_float (GskUniformDataBuilder *builder,
int idx,
float value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_int (GskUniformDataBuilder *builder,
int idx,
gint32 value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_uint (GskUniformDataBuilder *builder,
int idx,
guint32 value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_bool (GskUniformDataBuilder *builder,
int idx,
gboolean value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_vec2 (GskUniformDataBuilder *builder,
int idx,
const graphene_vec2_t *value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_vec3 (GskUniformDataBuilder *builder,
int idx,
const graphene_vec3_t *value);
GDK_AVAILABLE_IN_ALL
void gsk_uniform_data_builder_set_vec4 (GskUniformDataBuilder *builder,
int idx,
const graphene_vec4_t *value);
G_END_DECLS
#endif /* __GSK_GL_SHADER_H__ */

19
gsk/gskglshaderprivate.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef __GSK_GLSHADER_PRIVATE_H__
#define __GSK_GLSHADER_PRIVATE_H__
#include <gsk/gskglshader.h>
G_BEGIN_DECLS
typedef struct {
char *name;
GskGLUniformType type;
gsize offset;
} GskGLUniform;
const GskGLUniform *gsk_gl_shader_get_uniforms (GskGLShader *shader,
int *n_uniforms);
G_END_DECLS
#endif /* __GSK_GLSHADER_PRIVATE_H__ */

View File

@@ -25,6 +25,7 @@
#include <gsk/gskroundedrect.h>
#include <gsk/gsktypes.h>
#include <gsk/gskglshader.h>
#include <gtk/css/gtkcss.h>
G_BEGIN_DECLS
@@ -122,6 +123,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
#define GSK_TYPE_CROSS_FADE_NODE (gsk_cross_fade_node_get_type())
#define GSK_TYPE_TEXT_NODE (gsk_text_node_get_type())
#define GSK_TYPE_BLUR_NODE (gsk_blur_node_get_type())
#define GSK_TYPE_GLSHADER_NODE (gsk_gl_shader_node_get_type())
typedef struct _GskDebugNode GskDebugNode;
typedef struct _GskColorNode GskColorNode;
@@ -146,6 +148,7 @@ typedef struct _GskBlendNode GskBlendNode;
typedef struct _GskCrossFadeNode GskCrossFadeNode;
typedef struct _GskTextNode GskTextNode;
typedef struct _GskBlurNode GskBlurNode;
typedef struct _GskGLShaderNode GskGLShaderNode;
GDK_AVAILABLE_IN_ALL
GType gsk_debug_node_get_type (void) G_GNUC_CONST;
@@ -451,6 +454,28 @@ GskRenderNode * gsk_blur_node_get_child (GskRenderNode
GDK_AVAILABLE_IN_ALL
float gsk_blur_node_get_radius (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GType gsk_gl_shader_node_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_gl_shader_node_new (GskGLShader *shader,
const graphene_rect_t *bounds,
GBytes *uniform_data,
GskRenderNode *fallback,
GskRenderNode **children,
int n_children);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_gl_shader_node_get_fallback_child (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
guint gsk_gl_shader_node_get_n_children (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_gl_shader_node_get_child (GskRenderNode *node,
int idx);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_node_get_uniform_data (GskRenderNode *node);
GDK_AVAILABLE_IN_ALL
GskGLShader * gsk_gl_shader_node_get_shader (GskRenderNode *node);
G_END_DECLS
#endif /* __GSK_RENDER_NODE_H__ */

View File

@@ -4470,6 +4470,229 @@ gsk_debug_node_get_message (GskRenderNode *node)
return self->message;
}
/*** GSK_GL_SHADER_NODE ***/
struct _GskGLShaderNode
{
GskRenderNode render_node;
GskGLShader *shader;
GBytes *uniform_data;
GskRenderNode *fallback;
GskRenderNode **children;
guint n_children;
};
static void
gsk_gl_shader_node_finalize (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_GLSHADER_NODE));
for (guint i = 0; i < self->n_children; i++)
gsk_render_node_unref (self->children[i]);
g_free (self->children);
gsk_render_node_unref (self->fallback);
g_bytes_unref (self->uniform_data);
g_object_unref (self->shader);
parent_class->finalize (node);
}
static void
gsk_gl_shader_node_draw (GskRenderNode *node,
cairo_t *cr)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
gsk_render_node_draw (self->fallback, cr);
}
static void
gsk_gl_shader_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region)
{
GskGLShaderNode *self1 = (GskGLShaderNode *) node1;
GskGLShaderNode *self2 = (GskGLShaderNode *) node2;
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
self1->shader == self2->shader &&
g_bytes_compare (self1->uniform_data, self2->uniform_data) == 0 &&
self1->n_children == self2->n_children)
{
gsk_render_node_diff (self1->fallback, self2->fallback, region);
for (guint i = 0; i < self1->n_children; i++)
{
if (self1->children[i] != self2->children[i])
{
gsk_render_node_diff_impossible (node1, node2, region);
break;
}
}
}
else
{
gsk_render_node_diff_impossible (node1, node2, region);
}
}
/**
* gsk_gl_shader_node_new:
* @shader: the #GskGLShader
* @bounds: the rectangle to render the shader into
* @uniform_data: Data for the uniforms
* @fallback: Render node to use if OpenGL is not supported
* @children: List of child nodes, these will be rendered to textures and used as input.
* @n_children: Length of @children (currenly the GL backend only supports max 4 children)
*
* Creates a #GskRenderNode that will render the given @gl_program into the area given by @bounds.
* The @uniform_data is a block of data to use for uniform input, as per types and offsets
* defined by the @shader. Normally this is generated by gsk_gl_shader_format_uniform_data_va().
*
* See #GskGLShader for details about how the shader should be written.
*
* All the children will be rendered into textures, if they aren't already #GskTextureNode:s
* then they will be used directly. These textures will be sent as input to the shader.
*
* If the backend doesn't support GL shaders, or if there is any problem when compiling
* the shader, then the fallback shader node will be used instead.
*
* Returns: (transfer full) (type GskGLShaderNode): A new #GskRenderNode
*/
GskRenderNode *
gsk_gl_shader_node_new (GskGLShader *shader,
const graphene_rect_t *bounds,
GBytes *uniform_data,
GskRenderNode *fallback,
GskRenderNode **children,
int n_children)
{
GskGLShaderNode *self;
GskRenderNode *node;
int uniforms_size;
g_return_val_if_fail (bounds != NULL, NULL);
self = gsk_render_node_alloc (GSK_GL_SHADER_NODE);
node = (GskRenderNode *) self;
graphene_rect_init_from_rect (&node->bounds, bounds);
self->shader = g_object_ref (shader);
uniforms_size = gsk_gl_shader_get_uniforms_size (shader);
g_assert (g_bytes_get_size (uniform_data) == uniforms_size);
self->uniform_data = g_bytes_ref (uniform_data);
self->fallback = gsk_render_node_ref (fallback);
self->n_children = n_children;
if (n_children > 0)
{
self->children = g_malloc_n (n_children, sizeof (GskRenderNode *));
for (guint i = 0; i < n_children; i++)
self->children[i] = gsk_render_node_ref (children[i]);
}
return node;
}
/**
* gsk_gl_shader_node_get_fallback_child:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Gets the fallback child node
*
* Returns: (transfer none): The fallback node
*/
GskRenderNode *
gsk_gl_shader_node_get_fallback_child (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
return self->fallback;
}
/**
* gsk_gl_shader_node_get_n_children:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Returns the number of (non-fallback) children
*
* Returns: The number of children
*/
guint
gsk_gl_shader_node_get_n_children (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), 0);
return self->n_children;
}
/**
* gsk_gl_shader_node_get_child:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
* @idx: the position of the child to get
*
* Gets one of the (non-fallback) children.
*
* Returns: (transfer none): the @idx'th child of @node
*/
GskRenderNode *
gsk_gl_shader_node_get_child (GskRenderNode *node,
int idx)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
g_return_val_if_fail (idx < self->n_children, NULL);
return self->children[idx];
}
/**
* gsk_gl_shader_node_get_shader:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Gets shader code for the node.
*
* Returns: (transfer none): the #GskGLShader shader
*/
GskGLShader *
gsk_gl_shader_node_get_shader (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), 0);
return self->shader;
}
/**
* gsk_gl_shader_node_get_uniform_data:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Gets args for the node.
*
* Returns: (transfer none): A #GBytes with the uniform data
*/
GBytes *
gsk_gl_shader_node_get_uniform_data (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
return self->uniform_data;
}
GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
#ifndef I_
@@ -4506,6 +4729,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_blend_node, GSK_BLEND_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE)
GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
static void
@@ -4863,6 +5087,22 @@ gsk_render_node_init_types_once (void)
gsk_render_node_types[GSK_BLUR_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{
GSK_GL_SHADER_NODE,
sizeof (GskGLShaderNode),
NULL,
gsk_gl_shader_node_finalize,
gsk_gl_shader_node_draw,
NULL,
gsk_gl_shader_node_diff,
};
GType node_type = gsk_render_node_type_register_static (I_("GskGLShaderNode"), &node_info);
gsk_render_node_types[GSK_GL_SHADER_NODE] = node_type;
}
{
const GskRenderNodeTypeInfo node_info =
{

View File

@@ -824,9 +824,9 @@ clear_node (gpointer inout_node)
static GskRenderNode *
parse_container_node (GtkCssParser *parser)
{
GskRenderNode *node;
GPtrArray *nodes;
const GtkCssToken *token;
GskRenderNode *node;
nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
@@ -1089,6 +1089,235 @@ parse_inset_shadow_node (GtkCssParser *parser)
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
typedef union {
gint32 i;
double v[4];
} UniformValue;
typedef struct {
GskGLShader *shader;
GArray *uniform_values;
} ShaderInfo;
static void
clear_shader_info (gpointer data)
{
ShaderInfo *info = data;
g_array_set_size (info->uniform_values, 0);
}
static gboolean
parse_shader (GtkCssParser *parser,
gpointer out_shader_info)
{
ShaderInfo *shader_info = out_shader_info;
char *sourcecode = NULL;
GBytes *bytes;
GskGLShader *shader;
if (!parse_string (parser, &sourcecode))
return FALSE;
bytes = g_bytes_new_take (sourcecode, strlen (sourcecode));
shader = gsk_gl_shader_new_from_bytes (bytes);
g_bytes_unref (bytes);
shader_info->shader = shader;
return TRUE;
}
static gboolean
parse_uniform_value (GtkCssParser *parser,
GskGLUniformType uniform_type,
UniformValue *value)
{
switch (uniform_type)
{
case GSK_GLUNIFORM_TYPE_FLOAT:
if (!gtk_css_parser_consume_number (parser, &value->v[0]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_INT:
if (!gtk_css_parser_consume_integer (parser, &value->i))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_UINT:
if (!gtk_css_parser_consume_integer (parser, &value->i) ||
value->i < 0)
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_BOOL:
if (!gtk_css_parser_consume_integer (parser, &value->i) ||
(value->i != 0 && value->i != 1))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC2:
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
!gtk_css_parser_consume_number (parser, &value->v[1]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC3:
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
!gtk_css_parser_consume_number (parser, &value->v[1]) ||
!gtk_css_parser_consume_number (parser, &value->v[2]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC4:
if (!gtk_css_parser_consume_number (parser, &value->v[0]) ||
!gtk_css_parser_consume_number (parser, &value->v[1]) ||
!gtk_css_parser_consume_number (parser, &value->v[2]) ||
!gtk_css_parser_consume_number (parser, &value->v[3]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
}
gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA);
return TRUE;
}
static gboolean
parse_uniform_data (GtkCssParser *parser, gpointer data)
{
ShaderInfo *shader_info = data;
int n_uniforms = gsk_gl_shader_get_n_uniforms (shader_info->shader);
int i;
g_array_set_size (shader_info->uniform_values, n_uniforms);
for (i = 0; i < n_uniforms; i++)
{
GskGLUniformType uniform_type = gsk_gl_shader_get_uniform_type (shader_info->shader, i);
UniformValue *uniform_value = &g_array_index (shader_info->uniform_values, UniformValue, i);
if (!parse_uniform_value (parser, uniform_type, uniform_value))
return FALSE;
}
return TRUE;
}
static GskRenderNode *
parse_glshader_node (GtkCssParser *parser)
{
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
GskRenderNode *fallback = NULL;
GskRenderNode *child[4] = { NULL, };
ShaderInfo shader_info = {
NULL,
g_array_new (FALSE, FALSE, sizeof (UniformValue))
};
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "sourcecode", parse_shader, NULL, &shader_info },
{ "uniform-data", parse_uniform_data, clear_shader_info, &shader_info },
{ "fallback", parse_node, clear_node, &fallback },
{ "child1", parse_node, clear_node, &child[0] },
{ "child2", parse_node, clear_node, &child[1] },
{ "child3", parse_node, clear_node, &child[2] },
{ "child4", parse_node, clear_node, &child[3] },
};
GskGLShader *shader;
GskRenderNode *node;
GskUniformDataBuilder *builder;
GBytes *uniform_data = NULL;
int len, i;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
for (len = 0; len < 4; len++)
{
if (child[len] == NULL)
break;
}
shader = shader_info.shader;
builder = gsk_gl_shader_build_uniform_data (shader);
for (i = 0; i < shader_info.uniform_values->len; i++)
{
GskGLUniformType uniform_type = gsk_gl_shader_get_uniform_type (shader, i);
UniformValue *value = &g_array_index (shader_info.uniform_values, UniformValue, i);
switch (uniform_type)
{
case GSK_GLUNIFORM_TYPE_FLOAT:
gsk_uniform_data_builder_set_float (builder, i, value->v[0]);
break;
case GSK_GLUNIFORM_TYPE_INT:
gsk_uniform_data_builder_set_int (builder, i, value->i);
break;
case GSK_GLUNIFORM_TYPE_UINT:
gsk_uniform_data_builder_set_uint (builder, i, value->i);
break;
case GSK_GLUNIFORM_TYPE_BOOL:
gsk_uniform_data_builder_set_bool (builder, i, value->i);
break;
case GSK_GLUNIFORM_TYPE_VEC2:
{
graphene_vec2_t v;
graphene_vec2_init (&v, value->v[0], value->v[1]);
gsk_uniform_data_builder_set_vec2 (builder, i, &v);
}
break;
case GSK_GLUNIFORM_TYPE_VEC3:
{
graphene_vec3_t v;
graphene_vec3_init (&v, value->v[0], value->v[1], value->v[2]);
gsk_uniform_data_builder_set_vec3 (builder, i, &v);
}
break;
case GSK_GLUNIFORM_TYPE_VEC4:
{
graphene_vec4_t v;
graphene_vec4_init (&v, value->v[0], value->v[1], value->v[2], value->v[3]);
gsk_uniform_data_builder_set_vec4 (builder, i, &v);
}
break;
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
}
}
uniform_data = gsk_uniform_data_builder_finish (builder);
gsk_uniform_data_builder_free (builder);
node = gsk_gl_shader_node_new (shader, &bounds, uniform_data,
fallback, child, len);
g_array_unref (shader_info.uniform_values);
g_bytes_unref (uniform_data);
g_object_unref (shader);
for (i = 0; i < 4; i++)
{
if (child[i])
gsk_render_node_unref (child[i]);
}
return node;
}
static GskRenderNode *
parse_border_node (GtkCssParser *parser)
{
@@ -1603,6 +1832,7 @@ parse_node (GtkCssParser *parser,
{ "text", parse_text_node },
{ "texture", parse_texture_node },
{ "transform", parse_transform_node },
{ "glshader", parse_glshader_node },
};
GskRenderNode **node_p = out_node;
guint i;
@@ -1837,6 +2067,51 @@ append_point (GString *str,
string_append_double (str, p->y);
}
static void
append_string (GString *str,
const char *string)
{
gsize len;
g_return_if_fail (str != NULL);
g_return_if_fail (string != NULL);
g_string_append_c (str, '"');
do {
len = strcspn (string, "\\\"\n\r\f");
g_string_append_len (str, string, len);
string += len;
switch (*string)
{
case '\0':
goto out;
case '\n':
g_string_append (str, "\\A ");
break;
case '\r':
g_string_append (str, "\\D ");
break;
case '\f':
g_string_append (str, "\\C ");
break;
case '\"':
g_string_append (str, "\\\"");
break;
case '\\':
g_string_append (str, "\\\\");
break;
default:
g_assert_not_reached ();
break;
}
string++;
} while (*string);
out:
g_string_append_c (str, '"');
}
static void
append_vec4 (GString *str,
const graphene_vec4_t *v)
@@ -1914,6 +2189,18 @@ append_point_param (Printer *p,
g_string_append_c (p->str, '\n');
}
static void
append_string_param (Printer *p,
const char *param_name,
const char *value)
{
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
append_string (p->str, value);
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
append_vec4_param (Printer *p,
const char *param_name,
@@ -2441,6 +2728,125 @@ render_node_print (Printer *p,
}
break;
case GSK_GL_SHADER_NODE:
{
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
GBytes *uniform_data = gsk_gl_shader_node_get_uniform_data (node);
start_node (p, "glshader");
append_rect_param (p, "bounds", &node->bounds);
GBytes *bytes = gsk_gl_shader_get_bytes (shader);
/* Ensure we are zero-terminated */
char *sourcecode = g_strndup (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes));
append_string_param (p, "sourcecode", sourcecode);
g_free (sourcecode);
if (gsk_gl_shader_get_n_uniforms (shader) > 0)
{
GString *data = g_string_new ("");
for (guint i = 0; i < gsk_gl_shader_get_n_uniforms (shader); i++)
{
if (i > 0)
g_string_append (data, ", ");
switch (gsk_gl_shader_get_uniform_type (shader, i))
{
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
case GSK_GLUNIFORM_TYPE_FLOAT:
{
float value = gsk_gl_shader_get_uniform_data_float (shader, uniform_data, i);
string_append_double (data, value);
}
break;
case GSK_GLUNIFORM_TYPE_INT:
{
gint32 value = gsk_gl_shader_get_uniform_data_int (shader, uniform_data, i);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GLUNIFORM_TYPE_UINT:
{
guint32 value = gsk_gl_shader_get_uniform_data_uint (shader, uniform_data, i);
g_string_append_printf (data, "%u", value);
}
break;
case GSK_GLUNIFORM_TYPE_BOOL:
{
gboolean value = gsk_gl_shader_get_uniform_data_bool (shader, uniform_data, i);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GLUNIFORM_TYPE_VEC2:
{
graphene_vec2_t value;
gsk_gl_shader_get_uniform_data_vec2 (shader, uniform_data, i,
&value);
string_append_double (data, graphene_vec2_get_x (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec2_get_y (&value));
}
break;
case GSK_GLUNIFORM_TYPE_VEC3:
{
graphene_vec3_t value;
gsk_gl_shader_get_uniform_data_vec3 (shader, uniform_data, i,
&value);
string_append_double (data, graphene_vec3_get_x (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec3_get_y (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec3_get_z (&value));
}
break;
case GSK_GLUNIFORM_TYPE_VEC4:
{
graphene_vec4_t value;
gsk_gl_shader_get_uniform_data_vec4 (shader, uniform_data, i,
&value);
string_append_double (data, graphene_vec4_get_x (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec4_get_y (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec4_get_z (&value));
g_string_append (data, " ");
string_append_double (data, graphene_vec4_get_w (&value));
}
break;
}
}
_indent (p);
g_string_append_printf (p->str, "uniform-data: %s;\n", data->str);
g_string_free (data, TRUE);
}
append_node_param (p, "fallback", gsk_gl_shader_node_get_fallback_child (node));
for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i ++)
{
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
char *name;
name = g_strdup_printf ("child%d", i + 1);
append_node_param (p, name, child);
g_free (name);
}
end_node (p);
}
break;
case GSK_REPEAT_NODE:
{
GskRenderNode *child = gsk_repeat_node_get_child (node);

View File

@@ -13,7 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
* We don't add an "n-types" value to avoid having to handle
* it in every single switch.
*/
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_DEBUG_NODE + 1)
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_GL_SHADER_NODE + 1)
extern GType gsk_render_node_types[];

View File

@@ -21,6 +21,7 @@ gsk_private_gl_shaders = [
gsk_public_sources = files([
'gskdiff.c',
'gskcairorenderer.c',
'gskglshader.c',
'gskrenderer.c',
'gskrendernode.c',
'gskrendernodeimpl.c',
@@ -52,6 +53,7 @@ gsk_private_sources = files([
gsk_public_headers = files([
'gskcairorenderer.h',
'gskenums.h',
'gskglshader.h',
'gskrenderer.h',
'gskrendernode.h',
'gskroundedrect.h',

View File

@@ -171,6 +171,25 @@ create_list_model_for_render_node (GskRenderNode *node)
return create_render_node_list_model ((GskRenderNode *[2]) { gsk_cross_fade_node_get_start_child (node),
gsk_cross_fade_node_get_end_child (node) }, 2);
case GSK_GL_SHADER_NODE:
{
GListStore *store = G_LIST_STORE (create_render_node_list_model ((GskRenderNode *[1]) { gsk_gl_shader_node_get_fallback_child (node) }, 1));
for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i++)
{
GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
graphene_rect_t bounds;
GdkPaintable *paintable;
gsk_render_node_get_bounds (child, &bounds);
paintable = gtk_render_node_paintable_new (child, &bounds);
g_list_store_append (store, paintable);
g_object_unref (paintable);
}
return G_LIST_MODEL (store);
}
case GSK_CONTAINER_NODE:
{
GListStore *store;
@@ -270,6 +289,8 @@ node_type_name (GskRenderNodeType type)
return "Text";
case GSK_BLUR_NODE:
return "Blur";
case GSK_GL_SHADER_NODE:
return "GL Shader";
}
}
@@ -301,6 +322,7 @@ node_name (GskRenderNode *node)
case GSK_CROSS_FADE_NODE:
case GSK_TEXT_NODE:
case GSK_BLUR_NODE:
case GSK_GL_SHADER_NODE:
return g_strdup (node_type_name (gsk_render_node_get_node_type (node)));
case GSK_DEBUG_NODE:
@@ -511,6 +533,34 @@ add_color_row (GtkListStore *store,
g_object_unref (texture);
}
static void
add_int_row (GtkListStore *store,
const char *name,
int value)
{
char *text = g_strdup_printf ("%d", value);
add_text_row (store, name, text);
g_free (text);
}
static void
add_uint_row (GtkListStore *store,
const char *name,
guint value)
{
char *text = g_strdup_printf ("%u", value);
add_text_row (store, name, text);
g_free (text);
}
static void
add_boolean_row (GtkListStore *store,
const char *name,
gboolean value)
{
add_text_row (store, name, value ? "TRUE" : "FALSE");
}
static void
add_float_row (GtkListStore *store,
const char *name,
@@ -759,6 +809,92 @@ populate_render_node_properties (GtkListStore *store,
add_float_row (store, "Radius", gsk_blur_node_get_radius (node));
break;
case GSK_GL_SHADER_NODE:
{
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
GBytes *uniform_data = gsk_gl_shader_node_get_uniform_data (node);
int i;
add_int_row (store, "Required textures", gsk_gl_shader_get_n_required_textures (shader));
for (i = 0; i < gsk_gl_shader_get_n_uniforms (shader); i++)
{
const char *name;
char *title;
name = gsk_gl_shader_get_uniform_name (shader, i);
title = g_strdup_printf ("Uniform %s", name);
switch (gsk_gl_shader_get_uniform_type (shader, i))
{
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
case GSK_GLUNIFORM_TYPE_FLOAT:
add_float_row (store, title,
gsk_gl_shader_get_uniform_data_float (shader, uniform_data, i));
break;
case GSK_GLUNIFORM_TYPE_INT:
add_int_row (store, title,
gsk_gl_shader_get_uniform_data_int (shader, uniform_data, i));
break;
case GSK_GLUNIFORM_TYPE_UINT:
add_uint_row (store, title,
gsk_gl_shader_get_uniform_data_uint (shader, uniform_data, i));
break;
case GSK_GLUNIFORM_TYPE_BOOL:
add_boolean_row (store, title,
gsk_gl_shader_get_uniform_data_bool (shader, uniform_data, i));
break;
case GSK_GLUNIFORM_TYPE_VEC2:
{
graphene_vec2_t v;
gsk_gl_shader_get_uniform_data_vec2 (shader, uniform_data, i, &v);
float x = graphene_vec2_get_x (&v);
float y = graphene_vec2_get_x (&v);
char *s = g_strdup_printf ("%.2f %.2f", x, y);
add_text_row (store, title, s);
g_free (s);
}
break;
case GSK_GLUNIFORM_TYPE_VEC3:
{
graphene_vec3_t v;
gsk_gl_shader_get_uniform_data_vec3 (shader, uniform_data, i, &v);
float x = graphene_vec3_get_x (&v);
float y = graphene_vec3_get_y (&v);
float z = graphene_vec3_get_z (&v);
char *s = g_strdup_printf ("%.2f %.2f %.2f", x, y, z);
add_text_row (store, title, s);
g_free (s);
}
break;
case GSK_GLUNIFORM_TYPE_VEC4:
{
graphene_vec4_t v;
gsk_gl_shader_get_uniform_data_vec4 (shader, uniform_data, i, &v);
float x = graphene_vec4_get_x (&v);
float y = graphene_vec4_get_y (&v);
float z = graphene_vec4_get_z (&v);
float w = graphene_vec4_get_w (&v);
char *s = g_strdup_printf ("%.2f %.2f %.2f %.2f", x, y, z, w);
add_text_row (store, title, s);
g_free (s);
}
break;
}
g_free (title);
}
}
break;
case GSK_INSET_SHADOW_NODE:
{
const GdkRGBA *color = gsk_inset_shadow_node_peek_color (node);