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 definitions of the uniforms * A the data for the unifors, 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:
@@ -75,7 +75,8 @@ typedef enum {
|
||||
GSK_CROSS_FADE_NODE,
|
||||
GSK_TEXT_NODE,
|
||||
GSK_BLUR_NODE,
|
||||
GSK_DEBUG_NODE
|
||||
GSK_DEBUG_NODE,
|
||||
GSK_GLSHADER_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
@@ -218,4 +219,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__ */
|
||||
|
||||
529
gsk/gskglshader.c
Normal file
529
gsk/gskglshader.c
Normal file
@@ -0,0 +1,529 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:GskGLShader
|
||||
* @Title: GskGLShader
|
||||
* @Short_description: A description of GskGLShader
|
||||
*
|
||||
* A #GskGLShader is a snippet of GLSL that is meant to run in the
|
||||
* fragment shader of the rendering pipeline. A fragment shaader it
|
||||
* gets the coordinates being rendered as input and produces a the
|
||||
* pixel values for that particular pixel. Additionally the
|
||||
* shader can declare a set of other input arguments, called
|
||||
* uniforms (as they are uniform over all the calls to your shader in
|
||||
* each instance of use). A shader can also receieve up to 4
|
||||
* textures that it can use as input when producing the pixel data.
|
||||
*
|
||||
* The typical way a #GskGLShader is used is as an argument to a
|
||||
* #GskGLShaderNode in the rendering hierarchy, and then the textures
|
||||
* it gets as input are constructed by rendering the child nodes to
|
||||
* textures before rendering the shader node itself. (Although you can
|
||||
* also pass texture nodes as children if you want to directly use a
|
||||
* texture as input). Note that the #GskGLShaderNode API is a bit
|
||||
* lowlevel, and highlevel code normally uses
|
||||
* gtk_snapshot_push_glshader() to produce the nodes.
|
||||
*
|
||||
* The actual shader code is GLSL code that gets combined with
|
||||
* some other code into the fragment shader. Since the exact
|
||||
* capabilities of the GPU driver differs between different OpenGL
|
||||
* drivers and hardware Gtk adds some defines that you can use
|
||||
* to ensure your GLSL code runs on as many drivers as it can.
|
||||
*
|
||||
* If the OpenGL driver is GLES, then the shader language version
|
||||
* is set to 100, and GSK_GLES will be defined in the shader.
|
||||
*
|
||||
* Otherwise, if the OpenGL driver does not support the 3.2 core profile,
|
||||
* then the shader will run with language version 110 for GL2 and 130 for GL3,
|
||||
* and GSK_LEGACY will be defined in the shader.
|
||||
*
|
||||
* If the OpenGL driver supports the 3.2 code profile, it will be used,
|
||||
* the shader language version is set to 150, and GSK_GL3 will be defined
|
||||
* in the shader.
|
||||
*
|
||||
* The main function the shader should implement is:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* void mainImage(out vec4 fragColor,
|
||||
* in vec2 fragCoord,
|
||||
* in vec2 resolution,
|
||||
* in vec2 uv)
|
||||
* ]|
|
||||
*
|
||||
* Where the input @fragCoord is the coordinate of the pixel we're
|
||||
* currently rendering, relative to the boundary rectangle that was
|
||||
* specified in the #GskGLShaderNode, and @resolution is the width and
|
||||
* height of that rectangle. This is in the typical Gtk+ coordinate
|
||||
* system with the origin in the top left. @uv contains the u and v
|
||||
* coordinates that can be used to index a texture at the
|
||||
* corresponding point. These coordinates are in the [0..1]x[0..1]
|
||||
* region, with 0, 0 being in the lower left cornder (which is typical
|
||||
* for OpenGL).
|
||||
*
|
||||
* The output @fragColor should be a RGBA color (and alpha) that will
|
||||
* be used as the output for the specified pixel location. Note that
|
||||
* this output will be automatically clipped to the clip region of the
|
||||
* glshader node.
|
||||
*
|
||||
* In addition to the function arguments the shader can use one of the
|
||||
* pre-defined uniforms for tetxure sources (u_source, u_source2,
|
||||
* u_source3 or u_source4), as well as any custom uniforms you
|
||||
* declare.
|
||||
*
|
||||
* Gtk uses the the "gsk" namespace in the symbols it uses in the
|
||||
* shader, so your code should not use any symbols with the prefix gsk
|
||||
* or GSK. There are some helper functions declared that you can use:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* vec4 GskTexture(sampler2D sampler, vec2 texCoords);
|
||||
* ]|
|
||||
*
|
||||
* This samples a texture (e.g. u_source) at the specified
|
||||
* coordinates, and containes some helper ifdefs to ensure that
|
||||
* it works on all OpenGL versions.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "gskglshader.h"
|
||||
#include "gskglshaderprivate.h"
|
||||
|
||||
struct _GskGLShader
|
||||
{
|
||||
GObject parent_instance;
|
||||
char *sourcecode;
|
||||
int n_required_sources;
|
||||
int uniforms_size;
|
||||
GArray *uniforms;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GskGLShader, gsk_glshader, G_TYPE_OBJECT)
|
||||
|
||||
enum {
|
||||
GLSHADER_PROP_0,
|
||||
GLSHADER_PROP_SOURCECODE,
|
||||
GLSHADER_PROP_N_REQUIRED_SOURCES,
|
||||
GLSHADER_N_PROPS
|
||||
};
|
||||
static GParamSpec *gsk_glshader_properties[GLSHADER_N_PROPS];
|
||||
|
||||
static void
|
||||
gsk_glshader_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLShader *shader = GSK_GLSHADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case GLSHADER_PROP_SOURCECODE:
|
||||
g_value_set_string (value, shader->sourcecode);
|
||||
break;
|
||||
|
||||
case GLSHADER_PROP_N_REQUIRED_SOURCES:
|
||||
g_value_set_int (value, shader->n_required_sources);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GskGLShader *shader = GSK_GLSHADER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case GLSHADER_PROP_SOURCECODE:
|
||||
g_free (shader->sourcecode);
|
||||
shader->sourcecode = g_value_dup_string (value);
|
||||
break;
|
||||
|
||||
case GLSHADER_PROP_N_REQUIRED_SOURCES:
|
||||
gsk_glshader_set_n_required_sources (shader, g_value_get_int (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_finalize (GObject *object)
|
||||
{
|
||||
GskGLShader *shader = GSK_GLSHADER (object);
|
||||
|
||||
g_free (shader->sourcecode);
|
||||
for (int i = 0; i < shader->uniforms->len; i ++)
|
||||
g_free (g_array_index (shader->uniforms, GskGLUniform, i).name);
|
||||
g_array_free (shader->uniforms, TRUE);
|
||||
|
||||
G_OBJECT_CLASS (gsk_glshader_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_class_init (GskGLShaderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = gsk_glshader_get_property;
|
||||
object_class->set_property = gsk_glshader_set_property;
|
||||
object_class->finalize = gsk_glshader_finalize;
|
||||
|
||||
/**
|
||||
* GskGLShader:sourcecode:
|
||||
*
|
||||
* The source code for the shader.
|
||||
*/
|
||||
gsk_glshader_properties[GLSHADER_PROP_SOURCECODE] =
|
||||
g_param_spec_string ("sourcecode",
|
||||
"Sourcecode",
|
||||
"The sourcecode code for the shader",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GskGLShader:n-required-sources:
|
||||
*
|
||||
* The number of texture sources (u_source*) that are required to be set for the
|
||||
* shader to work.
|
||||
*/
|
||||
gsk_glshader_properties[GLSHADER_PROP_N_REQUIRED_SOURCES] =
|
||||
g_param_spec_int ("n-required-sources",
|
||||
"Number of required sources",
|
||||
"Minimum number of source textures required for the shader to work",
|
||||
0, 4, 0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, GLSHADER_N_PROPS, gsk_glshader_properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_init (GskGLShader *shader)
|
||||
{
|
||||
shader->uniforms = g_array_new (FALSE, FALSE, sizeof (GskGLUniform));
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_new:
|
||||
* @sourcecode: The sourcecode for the shader
|
||||
*
|
||||
* Creates a #GskGLShader that will render pixels using the specified code.
|
||||
*
|
||||
* Returns: (transfer full): A new #GskGLShader
|
||||
*/
|
||||
GskGLShader *
|
||||
gsk_glshader_new (const char *sourcecode)
|
||||
{
|
||||
GskGLShader *shader = g_object_new (GSK_TYPE_GLSHADER,
|
||||
"sourcecode", sourcecode,
|
||||
NULL);
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_sourcecode:
|
||||
* @shader: A #GskGLShader
|
||||
*
|
||||
* Get the source code being used to render this shader.
|
||||
*
|
||||
* Returns: (transfer none): The source code for the shader
|
||||
*/
|
||||
const char *
|
||||
gsk_glshader_get_sourcecode (GskGLShader *shader)
|
||||
{
|
||||
return shader->sourcecode;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_n_required_sources:
|
||||
* @shader: A #GskGLShader
|
||||
*
|
||||
* Returns the number of texture sources that the shader requires. This can be set
|
||||
* with gsk_glshader_set_n_required_sources() and can be used to check that the
|
||||
* a passed shader works in your usecase.
|
||||
*
|
||||
* Returns: (transfer none): The set nr of texture sources this shader requires.
|
||||
*/
|
||||
int
|
||||
gsk_glshader_get_n_required_sources (GskGLShader *shader)
|
||||
{
|
||||
return shader->n_required_sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_set_n_required_sources:
|
||||
* @shader: A #GskGLShader
|
||||
* @n_required_sources: The number of sources.
|
||||
*
|
||||
* Sets the number of texture sources that the shader requires. This can be used
|
||||
* to signal to other users that this shader needs this much input.
|
||||
*/
|
||||
void
|
||||
gsk_glshader_set_n_required_sources (GskGLShader *shader,
|
||||
int n_required_sources)
|
||||
{
|
||||
shader->n_required_sources = n_required_sources;
|
||||
}
|
||||
|
||||
static int
|
||||
uniform_type_size (GskGLUniformType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GSK_GLUNIFORM_TYPE_FLOAT:
|
||||
return sizeof (float);
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_INT:
|
||||
return sizeof (gint32);
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_UINT:
|
||||
case GSK_GLUNIFORM_TYPE_BOOL:
|
||||
return sizeof (guint32);
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC2:
|
||||
return sizeof (float) * 2;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC3:
|
||||
return sizeof (float) * 3;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC4:
|
||||
return sizeof (float) * 4;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_add_uniform:
|
||||
* @shader: A #GskGLShader
|
||||
* @name: Then name of the uniform.
|
||||
* @type: The uniform type
|
||||
*
|
||||
* This declares that the shader uses a uniform of a particular @name
|
||||
* and @type. You need to declare each uniform that your shader
|
||||
* uses or you will not be able to pass data to it.
|
||||
*/
|
||||
void
|
||||
gsk_glshader_add_uniform (GskGLShader *shader,
|
||||
const char *name,
|
||||
GskGLUniformType type)
|
||||
{
|
||||
GskGLUniform uniform = {
|
||||
g_strdup (name),
|
||||
type,
|
||||
shader->uniforms_size
|
||||
};
|
||||
|
||||
shader->uniforms_size += uniform_type_size (type);
|
||||
|
||||
g_array_append_val (shader->uniforms, uniform);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_n_uniforms:
|
||||
* @shader: A #GskGLShader
|
||||
*
|
||||
* Get the number of declared uniforms for this shader.
|
||||
*
|
||||
* Returns: The nr of declared uniforms
|
||||
*/
|
||||
int
|
||||
gsk_glshader_get_n_uniforms (GskGLShader *shader)
|
||||
{
|
||||
return shader->uniforms->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_uniform_name:
|
||||
* @shader: A #GskGLShader
|
||||
* @idx: A zero-based index of the uniforms
|
||||
*
|
||||
* Get the name of a declared uniforms for this shader at index @indx.
|
||||
*
|
||||
* Returns: (transfer none): The name of the declared uniform
|
||||
*/
|
||||
const char *
|
||||
gsk_glshader_get_uniform_name (GskGLShader *shader,
|
||||
int idx)
|
||||
{
|
||||
return g_array_index (shader->uniforms, GskGLUniform, idx).name;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_uniform_type:
|
||||
* @shader: A #GskGLShader
|
||||
* @idx: A zero-based index of the uniforms
|
||||
*
|
||||
* Get the type of a declared uniforms for this shader at index @indx.
|
||||
*
|
||||
* Returns: The type of the declared uniform
|
||||
*/
|
||||
GskGLUniformType
|
||||
gsk_glshader_get_uniform_type (GskGLShader *shader,
|
||||
int idx)
|
||||
{
|
||||
return g_array_index (shader->uniforms, GskGLUniform, idx).type;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_uniform_offset:
|
||||
* @shader: A #GskGLShader
|
||||
* @idx: A zero-based index of the uniforms
|
||||
*
|
||||
* Get the offset into the data block where data for this uniforms is stored.
|
||||
*
|
||||
* Returns: The data offset
|
||||
*/
|
||||
int
|
||||
gsk_glshader_get_uniform_offset (GskGLShader *shader,
|
||||
int idx)
|
||||
{
|
||||
return g_array_index (shader->uniforms, GskGLUniform, idx).offset;
|
||||
}
|
||||
|
||||
const GskGLUniform *
|
||||
gsk_glshader_get_uniforms (GskGLShader *shader,
|
||||
int *n_uniforms)
|
||||
{
|
||||
*n_uniforms = shader->uniforms->len;
|
||||
return &g_array_index (shader->uniforms, GskGLUniform, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_get_uniforms_size:
|
||||
* @shader: A #GskGLShader
|
||||
*
|
||||
* Get the size of the data block used to specify uniform data for this shader.
|
||||
*
|
||||
* Returns: The size of the data block
|
||||
*/
|
||||
int
|
||||
gsk_glshader_get_uniforms_size (GskGLShader *shader)
|
||||
{
|
||||
return shader->uniforms_size;
|
||||
}
|
||||
|
||||
static const GskGLUniform *
|
||||
gsk_glshader_find_uniform (GskGLShader *shader,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < shader->uniforms->len; i++)
|
||||
{
|
||||
const GskGLUniform *u = &g_array_index (shader->uniforms, GskGLUniform, i);
|
||||
if (strcmp (u->name, name) == 0)
|
||||
return u;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_format_uniform_data_va:
|
||||
* @shader: A #GskGLShader
|
||||
* @uniforms: %NULL terminated va_list with (name, pointer-to-data) arguments pairs
|
||||
*
|
||||
* Formats the uniform data as needed for feeding the named uniforms values into the shader.
|
||||
* The argument list is a list of pairs of names, and pointers to data of the types
|
||||
* that match the declared uniforms (i.e. `float *` for float uniforms and `graphene_vec4_t *` f
|
||||
* or vec3 uniforms).
|
||||
*
|
||||
* Returns: (transfer full): A newly allocated block of data which can be passed to gsk_glshader_node_new().
|
||||
*/
|
||||
guchar *
|
||||
gsk_glshader_format_uniform_data_va (GskGLShader *shader,
|
||||
va_list uniforms)
|
||||
{
|
||||
guchar *args = g_malloc0 (shader->uniforms_size);
|
||||
const char *name;
|
||||
|
||||
while ((name = va_arg (uniforms, const char *)) != NULL)
|
||||
{
|
||||
const GskGLUniform *u;
|
||||
gpointer value = va_arg (uniforms, gpointer);
|
||||
guchar *args_dest;
|
||||
|
||||
u = gsk_glshader_find_uniform (shader, name);
|
||||
if (u == NULL)
|
||||
{
|
||||
/* This isn't really an error, because we can easily imaging
|
||||
a shader interface that have input which isn't needed for
|
||||
a particular shader */
|
||||
g_debug ("No uniform named `%s` in shader", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
args_dest = args + u->offset;
|
||||
|
||||
/* We use pointers-to-value so that all values are the same
|
||||
size, otherwise we couldn't handle the missing uniform case above */
|
||||
|
||||
switch (u->type)
|
||||
{
|
||||
case GSK_GLUNIFORM_TYPE_FLOAT:
|
||||
*(float *)args_dest = *(float *)value;
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_INT:
|
||||
*(gint32 *)args_dest = *(gint32 *)value;
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_UINT:
|
||||
*(guint32 *)args_dest = *(guint32 *)value;
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_BOOL:
|
||||
*(guint32 *)args_dest = *(gboolean *)value;
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC2:
|
||||
graphene_vec2_to_float ((const graphene_vec2_t *)value,
|
||||
(float *)args_dest);
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC3:
|
||||
graphene_vec3_to_float ((const graphene_vec3_t *)value,
|
||||
(float *)args_dest);
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_VEC4:
|
||||
graphene_vec4_to_float ((const graphene_vec4_t *)value,
|
||||
(float *)args_dest);
|
||||
break;
|
||||
|
||||
case GSK_GLUNIFORM_TYPE_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
70
gsk/gskglshader.h
Normal file
70
gsk/gskglshader.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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_GLSHADER_H__
|
||||
#define __GSK_GLSHADER_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_glshader_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GskGLShader, gsk_glshader, GSK, GLSHADER, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_glshader_new (const char *sourcecode);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gsk_glshader_get_sourcecode (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_glshader_get_n_required_sources (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_glshader_set_n_required_sources (GskGLShader *shader,
|
||||
int n_required_sources);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_glshader_add_uniform (GskGLShader *shader,
|
||||
const char *name,
|
||||
GskGLUniformType type);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_glshader_get_n_uniforms (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const char * gsk_glshader_get_uniform_name (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLUniformType gsk_glshader_get_uniform_type (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_glshader_get_uniform_offset (GskGLShader *shader,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gsk_glshader_get_uniforms_size (GskGLShader *shader);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guchar * gsk_glshader_format_uniform_data_va (GskGLShader *shader,
|
||||
va_list uniforms);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_GLSHADER_H__ */
|
||||
@@ -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_glshader_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_glshader_node_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_glshader_node_new (GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
guchar *uniform_data,
|
||||
GskRenderNode *fallback,
|
||||
GskRenderNode **children,
|
||||
int n_children);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_glshader_node_get_fallback_child (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
guint gsk_glshader_node_get_n_children (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskRenderNode * gsk_glshader_node_get_child (GskRenderNode *node,
|
||||
int idx);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
const guchar * gsk_glshader_node_get_uniform_data (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_glshader_node_get_shader (GskRenderNode *node);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_H__ */
|
||||
|
||||
@@ -4470,6 +4470,244 @@ gsk_debug_node_get_message (GskRenderNode *node)
|
||||
return self->message;
|
||||
}
|
||||
|
||||
/*** GSK_GLSHADER_NODE ***/
|
||||
|
||||
struct _GskGLShaderNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
GskGLShader *shader;
|
||||
union {
|
||||
guchar inlined[8]; /* Most shaders have few args, so avoid extra alloc */
|
||||
guchar *external;
|
||||
} args;
|
||||
GskRenderNode *fallback;
|
||||
GskRenderNode **children;
|
||||
guint n_children;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_glshader_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_GLSHADER_NODE));
|
||||
int uniforms_size;
|
||||
|
||||
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);
|
||||
|
||||
uniforms_size = gsk_glshader_get_uniforms_size (self->shader);
|
||||
if (uniforms_size > sizeof (self->args.inlined))
|
||||
g_free (self->args.external);
|
||||
|
||||
g_object_unref (self->shader);
|
||||
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
gsk_render_node_draw (self->fallback, cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_glshader_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GskGLShaderNode *self1 = (GskGLShaderNode *) node1;
|
||||
GskGLShaderNode *self2 = (GskGLShaderNode *) node2;
|
||||
int uniforms_size = gsk_glshader_get_uniforms_size (self1->shader);
|
||||
|
||||
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
|
||||
self1->shader == self2->shader &&
|
||||
((uniforms_size <= sizeof (self1->args.inlined)) ?
|
||||
memcmp (&self1->args.inlined[0], &self2->args.inlined[0], uniforms_size) == 0:
|
||||
memcmp (self1->args.external, self2->args.external, uniforms_size) == 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_glshader_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_glshader_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_glshader_node_new (GskGLShader *shader,
|
||||
const graphene_rect_t *bounds,
|
||||
guchar *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_GLSHADER_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, bounds);
|
||||
self->shader = g_object_ref (shader);
|
||||
|
||||
uniforms_size = gsk_glshader_get_uniforms_size (shader);
|
||||
if (uniforms_size <= sizeof (self->args.inlined))
|
||||
memcpy (self->args.inlined, uniform_data, uniforms_size);
|
||||
else
|
||||
self->args.external = g_memdup (uniform_data, uniforms_size);
|
||||
|
||||
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_glshader_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_glshader_node_get_fallback_child (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GLSHADER_NODE), NULL);
|
||||
|
||||
return self->fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_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_glshader_node_get_n_children (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GLSHADER_NODE), 0);
|
||||
|
||||
return self->n_children;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_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_glshader_node_get_child (GskRenderNode *node,
|
||||
int idx)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GLSHADER_NODE), NULL);
|
||||
g_return_val_if_fail (idx < self->n_children, NULL);
|
||||
|
||||
return self->children[idx];
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_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_glshader_node_get_shader (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GLSHADER_NODE), 0);
|
||||
|
||||
return self->shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_glshader_node_get_uniform_data:
|
||||
* @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
|
||||
*
|
||||
* Gets args for the node.
|
||||
*/
|
||||
const guchar *
|
||||
gsk_glshader_node_get_uniform_data (GskRenderNode *node)
|
||||
{
|
||||
GskGLShaderNode *self = (GskGLShaderNode *) node;
|
||||
int uniforms_size;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GLSHADER_NODE), NULL);
|
||||
|
||||
uniforms_size = gsk_glshader_get_uniforms_size (self->shader);
|
||||
if (uniforms_size > sizeof (self->args.inlined))
|
||||
return self->args.external;
|
||||
else
|
||||
return &self->args.inlined[0];
|
||||
}
|
||||
|
||||
GType gsk_render_node_types[GSK_RENDER_NODE_TYPE_N_TYPES];
|
||||
|
||||
#ifndef I_
|
||||
@@ -4506,6 +4744,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_glshader_node, GSK_GLSHADER_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
|
||||
|
||||
static void
|
||||
@@ -4863,6 +5102,22 @@ gsk_render_node_init_types_once (void)
|
||||
gsk_render_node_types[GSK_BLUR_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
GSK_GLSHADER_NODE,
|
||||
sizeof (GskGLShaderNode),
|
||||
NULL,
|
||||
gsk_glshader_node_finalize,
|
||||
gsk_glshader_node_draw,
|
||||
NULL,
|
||||
gsk_glshader_node_diff,
|
||||
};
|
||||
|
||||
GType node_type = gsk_render_node_type_register_static (I_("GskGLShaderNode"), &node_info);
|
||||
gsk_render_node_types[GSK_GLSHADER_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
|
||||
@@ -1089,6 +1089,15 @@ parse_inset_shadow_node (GtkCssParser *parser)
|
||||
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
|
||||
}
|
||||
|
||||
|
||||
static GskRenderNode *
|
||||
parse_glshader_node (GtkCssParser *parser)
|
||||
{
|
||||
/* TODO */
|
||||
gtk_css_parser_error_syntax (parser, "glshader node parsing not implemented yet");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_border_node (GtkCssParser *parser)
|
||||
{
|
||||
@@ -1603,6 +1612,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 +1847,19 @@ append_point (GString *str,
|
||||
string_append_double (str, p->y);
|
||||
}
|
||||
|
||||
static void
|
||||
append_string (GString *str,
|
||||
const char *value)
|
||||
{
|
||||
char *escaped = g_strescape (value, NULL);
|
||||
|
||||
g_string_append_c (str, '"');
|
||||
g_string_append (str, escaped);
|
||||
g_string_append_c (str, '"');
|
||||
|
||||
g_free (escaped);
|
||||
}
|
||||
|
||||
static void
|
||||
append_vec4 (GString *str,
|
||||
const graphene_vec4_t *v)
|
||||
@@ -1914,6 +1937,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 +2476,24 @@ render_node_print (Printer *p,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_GLSHADER_NODE:
|
||||
{
|
||||
start_node (p, "glshader");
|
||||
|
||||
GskGLShader *shader = gsk_glshader_node_get_shader (node);
|
||||
append_string_param (p, "shader", gsk_glshader_get_sourcecode (shader));
|
||||
append_node_param (p, "fallback", gsk_glshader_node_get_fallback_child (node));
|
||||
for (guint i = 0; i < gsk_glshader_node_get_n_children (node); i ++)
|
||||
{
|
||||
GskRenderNode *child = gsk_glshader_node_get_child (node, i);
|
||||
_indent (p);
|
||||
render_node_print (p, child);
|
||||
}
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
{
|
||||
GskRenderNode *child = gsk_repeat_node_get_child (node);
|
||||
|
||||
@@ -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_GLSHADER_NODE + 1)
|
||||
|
||||
extern GType gsk_render_node_types[];
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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_GLSHADER_NODE:
|
||||
{
|
||||
GListStore *store = G_LIST_STORE (create_render_node_list_model ((GskRenderNode *[1]) { gsk_glshader_node_get_fallback_child (node) }, 1));
|
||||
|
||||
for (guint i = 0; i < gsk_glshader_node_get_n_children (node); i++)
|
||||
{
|
||||
GskRenderNode *child = gsk_glshader_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_GLSHADER_NODE:
|
||||
return "GLShader";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +322,7 @@ node_name (GskRenderNode *node)
|
||||
case GSK_CROSS_FADE_NODE:
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GLSHADER_NODE:
|
||||
return g_strdup (node_type_name (gsk_render_node_get_node_type (node)));
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
@@ -759,6 +781,9 @@ populate_render_node_properties (GtkListStore *store,
|
||||
add_float_row (store, "Radius", gsk_blur_node_get_radius (node));
|
||||
break;
|
||||
|
||||
case GSK_GLSHADER_NODE:
|
||||
break;
|
||||
|
||||
case GSK_INSET_SHADOW_NODE:
|
||||
{
|
||||
const GdkRGBA *color = gsk_inset_shadow_node_peek_color (node);
|
||||
|
||||
Reference in New Issue
Block a user