Add GskGLShaderNode and GskGLShader

A GskGLShader is an abstraction of a GLSL fragment shader that
can produce pixel values given inputs:
 * N (currently max 4) textures
 * Current arguments for the shader uniform
Uniform types are: float,(u)int,bool,vec234)
There is also a builder for the uniform arguments which are
passed around as immutable GBytes in the built form.

A GskGLShaderNode is a render node that renders a GskGLShader inside a
specified rectangular bounds. It renders its child nodes as textures
and passes those as texture arguments to the shader. You also pass it
a uniform arguments object.
This commit is contained in:
Alexander Larsson 2020-09-18 17:46:57 +02:00
parent 6e9b58b6f0
commit 7ea755e206
14 changed files with 2375 additions and 3 deletions

View File

@ -20,6 +20,7 @@
<xi:include href="xml/GskRenderNode.xml" />
<xi:include href="xml/GskRoundedRect.xml" />
<xi:include href="xml/GskTransform.xml" />
<xi:include href="xml/GskGLShader.xml" />
</reference>
<index id="api-index-full">

View File

@ -48,6 +48,7 @@ GskShadowNode
GskTextNode
GskTextureNode
GskTransformNode
GskGLShaderNode
gsk_render_node_ref
gsk_render_node_unref
GskRenderNodeType
@ -152,6 +153,11 @@ gsk_blur_node_get_radius
gsk_debug_node_new
gsk_debug_node_get_child
gsk_debug_node_get_message
gsk_gl_shader_node_new
gsk_gl_shader_node_get_n_children
gsk_gl_shader_node_get_child
gsk_gl_shader_node_get_args
gsk_gl_shader_node_get_shader
<SUBSECTION Standard>
GSK_IS_RENDER_NODE
GSK_RENDER_NODE
@ -177,6 +183,7 @@ GSK_TYPE_SHADOW_NODE
GSK_TYPE_TEXT_NODE
GSK_TYPE_TEXTURE_NODE
GSK_TYPE_TRANSFORM_NODE
GSK_TYPE_GLSHADER_NODE
GskRenderNodeClass
gsk_blend_node_get_type
gsk_blur_node_get_type
@ -202,6 +209,7 @@ gsk_shadow_node_get_type
gsk_text_node_get_type
gsk_texture_node_get_type
gsk_transform_node_get_type
gsk_gl_shader_node_get_type
GSK_TYPE_BLEND_MODE
<SUBSECTION Standard>
gsk_serialization_error_quark
@ -266,3 +274,46 @@ gsk_transform_get_type
gsk_transform_new
</SECTION>
<SECTION>
<FILE>GskGLShader</FILE>
GskGLShader
gsk_gl_shader_new_from_bytes
gsk_gl_shader_new_from_resource
gsk_gl_shader_compile
gsk_gl_shader_get_source
gsk_gl_shader_get_n_textures
gsk_gl_shader_get_n_uniforms
gsk_gl_shader_get_uniform_name
gsk_gl_shader_find_uniform_by_name
gsk_gl_shader_get_uniform_type
gsk_gl_shader_get_uniform_offset
gsk_gl_shader_get_args_size
<SUBSECTION Uniform Data>
gsk_gl_shader_get_arg_float
gsk_gl_shader_get_arg_int
gsk_gl_shader_get_arg_uint
gsk_gl_shader_get_arg_bool
gsk_gl_shader_get_arg_vec2
gsk_gl_shader_get_arg_vec3
gsk_gl_shader_get_arg_vec4
gsk_gl_shader_format_args_va
gsk_gl_shader_format_args
<SUBSECTION Shader Args Builder>
GskShaderArgsBuilder
gsk_shader_args_builder_new
gsk_shader_args_builder_to_args
gsk_shader_args_builder_free_to_args
gsk_shader_args_builder_unref
gsk_shader_args_builder_ref
gsk_shader_args_builder_set_float
gsk_shader_args_builder_set_int
gsk_shader_args_builder_set_uint
gsk_shader_args_builder_set_bool
gsk_shader_args_builder_set_vec2
gsk_shader_args_builder_set_vec3
gsk_shader_args_builder_set_vec4
</SECTION>

View File

@ -1,2 +1,3 @@
gsk_render_node_get_type
gsk_renderer_get_type
gsk_gl_shader_get_type

View File

@ -25,6 +25,7 @@
#include <gsk/gskrendernode.h>
#include <gsk/gskroundedrect.h>
#include <gsk/gsktransform.h>
#include <gsk/gskglshader.h>
#include <gsk/gskcairorenderer.h>

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_GL_UNIFORM_TYPE_NONE: No type, used for uninitialized or unspecified values.
* @GSK_GL_UNIFORM_TYPE_FLOAT: A float uniform
* @GSK_GL_UNIFORM_TYPE_INT: A GLSL int / gint32 uniform
* @GSK_GL_UNIFORM_TYPE_UINT: A GLSL uint / guint32 uniform
* @GSK_GL_UNIFORM_TYPE_BOOL: A GLSL bool / gboolean uniform
* @GSK_GL_UNIFORM_TYPE_VEC2: A GLSL vec2 / graphene_vec2_t uniform
* @GSK_GL_UNIFORM_TYPE_VEC3: A GLSL vec3 / graphene_vec3_t uniform
* @GSK_GL_UNIFORM_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_GL_UNIFORM_TYPE_NONE,
GSK_GL_UNIFORM_TYPE_FLOAT,
GSK_GL_UNIFORM_TYPE_INT,
GSK_GL_UNIFORM_TYPE_UINT,
GSK_GL_UNIFORM_TYPE_BOOL,
GSK_GL_UNIFORM_TYPE_VEC2,
GSK_GL_UNIFORM_TYPE_VEC3,
GSK_GL_UNIFORM_TYPE_VEC4,
} GskGLUniformType;
#endif /* __GSK_TYPES_H__ */

1394
gsk/gskglshader.c Normal file

File diff suppressed because it is too large Load Diff

162
gsk/gskglshader.h Normal file
View File

@ -0,0 +1,162 @@
/* 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_SHADER_ARGS_BUILDER (gsk_shader_args_builder_get_type ())
typedef struct _GskShaderArgsBuilder GskShaderArgsBuilder;
#define GSK_TYPE_GL_SHADER (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
gboolean gsk_gl_shader_compile (GskGLShader *shader,
GskRenderer *renderer,
GError **error);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_get_source (GskGLShader *shader);
GDK_AVAILABLE_IN_ALL
const char * gsk_gl_shader_get_resource (GskGLShader *shader);
GDK_AVAILABLE_IN_ALL
int gsk_gl_shader_get_n_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
gsize gsk_gl_shader_get_args_size (GskGLShader *shader);
/* Helpers for managing shader args */
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_format_args_va (GskGLShader *shader,
va_list uniforms);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_format_args (GskGLShader *shader,
...) G_GNUC_NULL_TERMINATED;
GDK_AVAILABLE_IN_ALL
float gsk_gl_shader_get_arg_float (GskGLShader *shader,
GBytes *args,
int idx);
GDK_AVAILABLE_IN_ALL
gint32 gsk_gl_shader_get_arg_int (GskGLShader *shader,
GBytes *args,
int idx);
GDK_AVAILABLE_IN_ALL
guint32 gsk_gl_shader_get_arg_uint (GskGLShader *shader,
GBytes *args,
int idx);
GDK_AVAILABLE_IN_ALL
gboolean gsk_gl_shader_get_arg_bool (GskGLShader *shader,
GBytes *args,
int idx);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_arg_vec2 (GskGLShader *shader,
GBytes *args,
int idx,
graphene_vec2_t *out_value);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_arg_vec3 (GskGLShader *shader,
GBytes *args,
int idx,
graphene_vec3_t *out_value);
GDK_AVAILABLE_IN_ALL
void gsk_gl_shader_get_arg_vec4 (GskGLShader *shader,
GBytes *args,
int idx,
graphene_vec4_t *out_value);
GDK_AVAILABLE_IN_ALL
GType gsk_shader_args_builder_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GskShaderArgsBuilder *gsk_shader_args_builder_new (GskGLShader *shader,
GBytes *initial_values);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_shader_args_builder_to_args (GskShaderArgsBuilder *builder);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_shader_args_builder_free_to_args (GskShaderArgsBuilder *builder);
GDK_AVAILABLE_IN_ALL
GskShaderArgsBuilder *gsk_shader_args_builder_ref (GskShaderArgsBuilder *builder);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_unref (GskShaderArgsBuilder *builder);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_float (GskShaderArgsBuilder *builder,
int idx,
float value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_int (GskShaderArgsBuilder *builder,
int idx,
gint32 value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_uint (GskShaderArgsBuilder *builder,
int idx,
guint32 value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_bool (GskShaderArgsBuilder *builder,
int idx,
gboolean value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_vec2 (GskShaderArgsBuilder *builder,
int idx,
const graphene_vec2_t *value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_vec3 (GskShaderArgsBuilder *builder,
int idx,
const graphene_vec3_t *value);
GDK_AVAILABLE_IN_ALL
void gsk_shader_args_builder_set_vec4 (GskShaderArgsBuilder *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_GL_SHADER_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,24 @@ 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 *args,
GskRenderNode **children,
guint n_children);
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,
guint idx);
GDK_AVAILABLE_IN_ALL
GBytes * gsk_gl_shader_node_get_args (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,209 @@ gsk_debug_node_get_message (GskRenderNode *node)
return self->message;
}
/*** GSK_GL_SHADER_NODE ***/
struct _GskGLShaderNode
{
GskRenderNode render_node;
GskGLShader *shader;
GBytes *args;
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_GL_SHADER_NODE));
for (guint i = 0; i < self->n_children; i++)
gsk_render_node_unref (self->children[i]);
g_free (self->children);
g_bytes_unref (self->args);
g_object_unref (self->shader);
parent_class->finalize (node);
}
static void
gsk_gl_shader_node_draw (GskRenderNode *node,
cairo_t *cr)
{
cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.);
gsk_cairo_rectangle (cr, &node->bounds);
cairo_fill (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->args, self2->args) == 0 &&
self1->n_children == self2->n_children)
{
cairo_region_t *child_region = cairo_region_create();
for (guint i = 0; i < self1->n_children; i++)
gsk_render_node_diff (self1->children[i], self2->children[i], child_region);
if (!cairo_region_is_empty (child_region))
gsk_render_node_diff_impossible (node1, node2, region);
cairo_region_destroy (child_region);
}
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
* @args: Arguments for the uniforms
* @children: (array length=n_children): array of child nodes, these will
* be rendered to textures and used as input.
* @n_children: Length of @children (currenly the GL backend supports
* up to 4 children)
*
* Creates a #GskRenderNode that will render the given @shader into the
* area given by @bounds. The @args 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_args() or #GskGLShaderArgBuilder.
*
* See #GskGLShader for details about how the shader should be written.
*
* All the children will be rendered into textures (if they aren't already
* #GskTextureNodes, which will be used directly). These textures will be
* sent as input to the shader.
*
* If the renderer doesn't support GL shaders, or if there is any problem
* when compiling the shader, then the node will draw pink. You should use
* gsk_gl_shader_compile() to ensure the @shader will work for the
* renderer before using it.
*
* Returns: (transfer full) (type GskGLShaderNode): A new #GskRenderNode
*/
GskRenderNode *
gsk_gl_shader_node_new (GskGLShader *shader,
const graphene_rect_t *bounds,
GBytes *args,
GskRenderNode **children,
guint n_children)
{
GskGLShaderNode *self;
GskRenderNode *node;
g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
g_return_val_if_fail (bounds != NULL, NULL);
g_return_val_if_fail ((args == NULL && gsk_gl_shader_get_n_uniforms (shader) == 0) ||
(args != NULL && g_bytes_get_size (args) == gsk_gl_shader_get_args_size (shader)), NULL);
g_return_val_if_fail ((children == NULL && n_children == 0) ||
(children != NULL && n_children == gsk_gl_shader_get_n_textures (shader)), 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);
self->args = g_bytes_ref (args);
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_n_children:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Returns the number of 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 children.
*
* Returns: (transfer none): the @idx'th child of @node
*/
GskRenderNode *
gsk_gl_shader_node_get_child (GskRenderNode *node,
guint 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_args:
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
*
* Gets args for the node.
*
* Returns: (transfer none): A #GBytes with the uniform arguments
*/
GBytes *
gsk_gl_shader_node_get_args (GskRenderNode *node)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
return self->args;
}
GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
#ifndef I_
@ -4506,6 +4709,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 +5067,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,209 @@ 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;
GskShaderArgsBuilder *args;
} ShaderInfo;
static void
clear_shader_info (gpointer data)
{
ShaderInfo *info = data;
g_clear_object (&info->shader);
g_clear_pointer (&info->args, gsk_shader_args_builder_unref);
}
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,
int idx,
ShaderInfo *shader_info)
{
switch (gsk_gl_shader_get_uniform_type (shader_info->shader, idx))
{
case GSK_GL_UNIFORM_TYPE_FLOAT:
{
double f;
if (!gtk_css_parser_consume_number (parser, &f))
return FALSE;
gsk_shader_args_builder_set_float (shader_info->args, idx, f);
}
break;
case GSK_GL_UNIFORM_TYPE_INT:
{
int i;
if (!gtk_css_parser_consume_integer (parser, &i))
return FALSE;
gsk_shader_args_builder_set_int (shader_info->args, idx, i);
}
break;
case GSK_GL_UNIFORM_TYPE_UINT:
{
int i;
if (!gtk_css_parser_consume_integer (parser, &i) || i < 0)
return FALSE;
gsk_shader_args_builder_set_uint (shader_info->args, idx, i);
}
break;
case GSK_GL_UNIFORM_TYPE_BOOL:
{
int i;
if (!gtk_css_parser_consume_integer (parser, &i) || (i != 0 && i != 1))
return FALSE;
gsk_shader_args_builder_set_bool (shader_info->args, idx, i);
}
break;
case GSK_GL_UNIFORM_TYPE_VEC2:
{
double f0, f1;
graphene_vec2_t v;
if (!gtk_css_parser_consume_number (parser, &f0) ||
!gtk_css_parser_consume_number (parser, &f1))
return FALSE;
graphene_vec2_init (&v, f0, f1);
gsk_shader_args_builder_set_vec2 (shader_info->args, idx, &v);
}
break;
case GSK_GL_UNIFORM_TYPE_VEC3:
{
double f0, f1, f2;
graphene_vec3_t v;
if (!gtk_css_parser_consume_number (parser, &f0) ||
!gtk_css_parser_consume_number (parser, &f1) ||
!gtk_css_parser_consume_number (parser, &f2))
return FALSE;
graphene_vec3_init (&v, f0, f1, f2);
gsk_shader_args_builder_set_vec3 (shader_info->args, idx, &v);
}
break;
case GSK_GL_UNIFORM_TYPE_VEC4:
{
double f0, f1, f2, f3;
graphene_vec4_t v;
if (!gtk_css_parser_consume_number (parser, &f0) ||
!gtk_css_parser_consume_number (parser, &f1) ||
!gtk_css_parser_consume_number (parser, &f2) ||
!gtk_css_parser_consume_number (parser, &f3))
return FALSE;
graphene_vec4_init (&v, f0, f1, f2, f3);
gsk_shader_args_builder_set_vec4 (shader_info->args, idx, &v);
}
break;
case GSK_GL_UNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
}
if (idx < gsk_gl_shader_get_n_uniforms (shader_info->shader))
{
if (!gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA))
return FALSE;
}
return TRUE;
}
static gboolean
parse_shader_args (GtkCssParser *parser, gpointer data)
{
ShaderInfo *shader_info = data;
int n_uniforms;
int i;
shader_info->args = gsk_shader_args_builder_new (shader_info->shader, NULL);
n_uniforms = gsk_gl_shader_get_n_uniforms (shader_info->shader);
for (i = 0; i < n_uniforms; i++)
{
if (!parse_uniform_value (parser, i, shader_info))
return FALSE;
}
return TRUE;
}
static GskRenderNode *
parse_glshader_node (GtkCssParser *parser)
{
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
GskRenderNode *child[4] = { NULL, };
ShaderInfo shader_info = {
NULL,
NULL,
};
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "sourcecode", parse_shader, NULL, &shader_info },
{ "args", parse_shader_args, clear_shader_info, &shader_info },
{ "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;
GBytes *args = 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;
args = gsk_shader_args_builder_free_to_args (shader_info.args);
node = gsk_gl_shader_node_new (shader, &bounds, args, child, len);
g_bytes_unref (args);
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 +1806,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;
@ -1914,6 +2118,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);
_gtk_css_print_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 +2657,124 @@ render_node_print (Printer *p,
}
break;
case GSK_GL_SHADER_NODE:
{
GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
GBytes *args = gsk_gl_shader_node_get_args (node);
start_node (p, "glshader");
append_rect_param (p, "bounds", &node->bounds);
GBytes *bytes = gsk_gl_shader_get_source (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_GL_UNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
case GSK_GL_UNIFORM_TYPE_FLOAT:
{
float value = gsk_gl_shader_get_arg_float (shader, args, i);
string_append_double (data, value);
}
break;
case GSK_GL_UNIFORM_TYPE_INT:
{
gint32 value = gsk_gl_shader_get_arg_int (shader, args, i);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GL_UNIFORM_TYPE_UINT:
{
guint32 value = gsk_gl_shader_get_arg_uint (shader, args, i);
g_string_append_printf (data, "%u", value);
}
break;
case GSK_GL_UNIFORM_TYPE_BOOL:
{
gboolean value = gsk_gl_shader_get_arg_bool (shader, args, i);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GL_UNIFORM_TYPE_VEC2:
{
graphene_vec2_t value;
gsk_gl_shader_get_arg_vec2 (shader, args, 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_GL_UNIFORM_TYPE_VEC3:
{
graphene_vec3_t value;
gsk_gl_shader_get_arg_vec3 (shader, args, 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_GL_UNIFORM_TYPE_VEC4:
{
graphene_vec4_t value;
gsk_gl_shader_get_arg_vec4 (shader, args, 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, "args: %s;\n", data->str);
g_string_free (data, TRUE);
}
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_new (GDK_TYPE_PAINTABLE);
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 *args = gsk_gl_shader_node_get_args (node);
int i;
add_int_row (store, "Required textures", gsk_gl_shader_get_n_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_GL_UNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
case GSK_GL_UNIFORM_TYPE_FLOAT:
add_float_row (store, title,
gsk_gl_shader_get_arg_float (shader, args, i));
break;
case GSK_GL_UNIFORM_TYPE_INT:
add_int_row (store, title,
gsk_gl_shader_get_arg_int (shader, args, i));
break;
case GSK_GL_UNIFORM_TYPE_UINT:
add_uint_row (store, title,
gsk_gl_shader_get_arg_uint (shader, args, i));
break;
case GSK_GL_UNIFORM_TYPE_BOOL:
add_boolean_row (store, title,
gsk_gl_shader_get_arg_bool (shader, args, i));
break;
case GSK_GL_UNIFORM_TYPE_VEC2:
{
graphene_vec2_t v;
gsk_gl_shader_get_arg_vec2 (shader, args, 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_GL_UNIFORM_TYPE_VEC3:
{
graphene_vec3_t v;
gsk_gl_shader_get_arg_vec3 (shader, args, 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_GL_UNIFORM_TYPE_VEC4:
{
graphene_vec4_t v;
gsk_gl_shader_get_arg_vec4 (shader, args, 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);