Complete serialization for GskGLShaderNode

Make the node serialization and parsing handle
shader nodes.
This commit is contained in:
Matthias Clasen
2020-09-22 21:31:02 -04:00
parent 3e3df6ba1e
commit aeae3522b6

View File

@@ -358,6 +358,13 @@ parse_double (GtkCssParser *parser,
return gtk_css_parser_consume_number (parser, out_double);
}
static gboolean
parse_int (GtkCssParser *parser,
gpointer out_int)
{
return gtk_css_parser_consume_integer (parser, out_int);
}
static gboolean
parse_point (GtkCssParser *parser,
gpointer out_point)
@@ -824,9 +831,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,13 +1096,249 @@ parse_inset_shadow_node (GtkCssParser *parser)
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
typedef struct {
GskGLUniformType type;
char *name;
union {
int i;
double v[4];
} value;
} Uniform;
static gboolean
parse_uniform_decl (GtkCssParser *parser, Uniform *decl)
{
Uniform decls[] = {
{ GSK_GLUNIFORM_TYPE_FLOAT, (char *) "float" },
{ GSK_GLUNIFORM_TYPE_INT, (char *) "int" },
{ GSK_GLUNIFORM_TYPE_UINT, (char*) "uint" },
{ GSK_GLUNIFORM_TYPE_BOOL, (char *) "bool" },
{ GSK_GLUNIFORM_TYPE_VEC2, (char *) "vec2" },
{ GSK_GLUNIFORM_TYPE_VEC3, (char *) "vec3" },
{ GSK_GLUNIFORM_TYPE_VEC4, (char *) "vec4" },
};
int i;
for (i = 0; i < G_N_ELEMENTS (decls); i++)
{
if (gtk_css_parser_try_ident (parser, decls[i].name))
{
decl->type = decls[i].type;
decl->name = gtk_css_parser_consume_ident (parser);
gtk_css_parser_try_token (parser, GTK_CSS_TOKEN_COMMA);
return TRUE;
}
}
return FALSE;
}
static void
clear_uniform_decl (gpointer data)
{
Uniform *decl = data;
g_free (decl->name);
}
static gboolean
parse_uniforms (GtkCssParser *parser, gpointer data)
{
GArray *uniforms = data;
Uniform decl;
while (parse_uniform_decl (parser, &decl))
g_array_append_val (uniforms, decl);
return TRUE;
}
static void
clear_array (gpointer data)
{
GArray *array = data;
g_array_set_size (array, 0);
}
static gboolean
parse_uniform_value (GtkCssParser *parser, Uniform *uniform)
{
switch (uniform->type)
{
case GSK_GLUNIFORM_TYPE_FLOAT:
if (!gtk_css_parser_consume_number (parser, &uniform->value.v[0]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_INT:
if (!gtk_css_parser_consume_integer (parser, &uniform->value.i))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_UINT:
if (!gtk_css_parser_consume_integer (parser, &uniform->value.i) ||
uniform->value.i < 0)
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_BOOL:
if (!gtk_css_parser_consume_integer (parser, &uniform->value.i) ||
(uniform->value.i != 0 && uniform->value.i != 1))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC2:
if (!gtk_css_parser_consume_number (parser, &uniform->value.v[0]) ||
!gtk_css_parser_consume_number (parser, &uniform->value.v[1]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC3:
if (!gtk_css_parser_consume_number (parser, &uniform->value.v[0]) ||
!gtk_css_parser_consume_number (parser, &uniform->value.v[1]) ||
!gtk_css_parser_consume_number (parser, &uniform->value.v[2]))
return FALSE;
break;
case GSK_GLUNIFORM_TYPE_VEC4:
if (!gtk_css_parser_consume_number (parser, &uniform->value.v[0]) ||
!gtk_css_parser_consume_number (parser, &uniform->value.v[1]) ||
!gtk_css_parser_consume_number (parser, &uniform->value.v[2]) ||
!gtk_css_parser_consume_number (parser, &uniform->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)
{
GArray *uniforms = data;
int i;
for (i = 0; i < uniforms->len; i++)
{
Uniform *uniform = &g_array_index (uniforms, Uniform, i);
if (!parse_uniform_value (parser, uniform))
return FALSE;
}
return TRUE;
}
static GskRenderNode *
parse_glshader_node (GtkCssParser *parser)
{
/* TODO */
gtk_css_parser_error_syntax (parser, "glshader node parsing not implemented yet");
return NULL;
graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
char *sourcecode = NULL;
int required_sources = 0;
GskRenderNode *fallback = NULL;
GskRenderNode *child[4] = { NULL, };
GArray *uniforms = g_array_new (FALSE, FALSE, sizeof (Uniform));
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "sourcecode", parse_string, NULL, &sourcecode },
{ "required-sources", parse_int, NULL, &required_sources },
{ "uniforms", parse_uniforms, clear_array, uniforms },
{ "uniform-data", parse_uniform_data, clear_array, uniforms },
{ "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;
guchar *uniform_data;
int len, i;
g_array_set_clear_func (uniforms, clear_uniform_decl);
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
for (len = 0; len < 4; len++)
{
if (child[len] == NULL)
break;
}
shader = gsk_glshader_new (sourcecode);
gsk_glshader_set_n_required_sources (shader, required_sources);
for (i = 0; i < uniforms->len; i++)
{
Uniform *uniform = &g_array_index (uniforms, Uniform, i);
gsk_glshader_add_uniform (shader, uniform->name, uniform->type);
}
uniform_data = g_new (guchar, gsk_glshader_get_uniforms_size (shader));
for (i = 0; i < uniforms->len; i++)
{
Uniform *uniform = &g_array_index (uniforms, Uniform, i);
guchar *dest;
dest = uniform_data + gsk_glshader_get_uniform_offset (shader, i);
switch (uniform->type)
{
case GSK_GLUNIFORM_TYPE_FLOAT:
*(float *)dest = uniform->value.v[0];
break;
case GSK_GLUNIFORM_TYPE_INT:
*(gint32 *)dest = uniform->value.i;
break;
case GSK_GLUNIFORM_TYPE_UINT:
*(guint32 *)dest = uniform->value.i;
break;
case GSK_GLUNIFORM_TYPE_BOOL:
*(guint32 *)dest = uniform->value.i;
break;
case GSK_GLUNIFORM_TYPE_VEC4:
((float *)dest)[3] = uniform->value.v[3];
G_GNUC_FALLTHROUGH;
case GSK_GLUNIFORM_TYPE_VEC3:
((float *)dest)[2] = uniform->value.v[2];
G_GNUC_FALLTHROUGH;
case GSK_GLUNIFORM_TYPE_VEC2:
((float *)dest)[1] = uniform->value.v[1];
((float *)dest)[0] = uniform->value.v[0];
break;
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
}
}
node = gsk_glshader_node_new (shader, &bounds, uniform_data,
fallback, child, len);
g_array_unref (uniforms);
g_free (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 *
@@ -1849,15 +2092,47 @@ append_point (GString *str,
static void
append_string (GString *str,
const char *value)
const char *string)
{
char *escaped = g_strescape (value, NULL);
gsize len;
g_return_if_fail (str != NULL);
g_return_if_fail (string != NULL);
g_string_append_c (str, '"');
g_string_append (str, escaped);
g_string_append_c (str, '"');
g_free (escaped);
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
@@ -1889,6 +2164,19 @@ append_float_param (Printer *p,
g_string_append (p->str, ";\n");
}
static void
append_int_param (Printer *p,
const char *param_name,
int value,
int default_value)
{
if (value == default_value)
return;
_indent (p);
g_string_append_printf (p->str, "%s: %d;\n", param_name, value);
}
static void
append_rgba_param (Printer *p,
const char *param_name,
@@ -2478,16 +2766,123 @@ render_node_print (Printer *p,
case GSK_GLSHADER_NODE:
{
GskGLShader *shader = gsk_glshader_node_get_shader (node);
const guchar *uniform_data = gsk_glshader_node_get_uniform_data (node);
start_node (p, "glshader");
GskGLShader *shader = gsk_glshader_node_get_shader (node);
append_string_param (p, "shader", gsk_glshader_get_sourcecode (shader));
append_rect_param (p, "bounds", &node->bounds);
append_string_param (p, "sourcecode", gsk_glshader_get_sourcecode (shader));
append_int_param (p, "required-sources", gsk_glshader_get_n_required_sources (shader), 0);
if (gsk_glshader_get_n_uniforms (shader) > 0)
{
GString *decl = g_string_new ("");
GString *data = g_string_new ("");
for (guint i = 0; i < gsk_glshader_get_n_uniforms (shader); i++)
{
const char *name = gsk_glshader_get_uniform_name (shader, i);
int offset = gsk_glshader_get_uniform_offset (shader, i);
if (i > 0)
{
g_string_append (decl, ", ");
g_string_append (data, ", ");
}
switch (gsk_glshader_get_uniform_type (shader, i))
{
case GSK_GLUNIFORM_TYPE_NONE:
default:
g_assert_not_reached ();
break;
case GSK_GLUNIFORM_TYPE_FLOAT:
{
float value = *(float *)(uniform_data + offset);
g_string_append_printf (decl, "float %s", name);
g_string_append_printf (data, "%f", value);
}
break;
case GSK_GLUNIFORM_TYPE_INT:
{
gint32 value = *(gint32 *)(uniform_data + offset);
g_string_append_printf (decl, "int %s", name);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GLUNIFORM_TYPE_UINT:
{
guint32 value = *(guint32 *)(uniform_data + offset);
g_string_append_printf (decl, "uint %s", name);
g_string_append_printf (data, "%u", value);
}
break;
case GSK_GLUNIFORM_TYPE_BOOL:
{
gboolean value = *(gboolean *)(uniform_data + offset);
g_string_append_printf (decl, "bool %s", name);
g_string_append_printf (data, "%d", value);
}
break;
case GSK_GLUNIFORM_TYPE_VEC2:
{
graphene_vec2_t *v = (graphene_vec2_t *)(uniform_data + offset);
g_string_append_printf (decl, "vec2 %s", name);
g_string_append_printf (data, "%f %f",
graphene_vec2_get_x (v),
graphene_vec2_get_y (v));
}
break;
case GSK_GLUNIFORM_TYPE_VEC3:
{
graphene_vec3_t *v = (graphene_vec3_t *)(uniform_data + offset);
g_string_append_printf (decl, "vec3 %s", name);
g_string_append_printf (data, "%f %f %f",
graphene_vec3_get_x (v),
graphene_vec3_get_y (v),
graphene_vec3_get_z (v));
}
break;
case GSK_GLUNIFORM_TYPE_VEC4:
{
graphene_vec4_t *v = (graphene_vec4_t *)(uniform_data + offset);
g_string_append_printf (decl, "vec4 %s", name);
g_string_append_printf (data, "%f %f %f %f",
graphene_vec4_get_x (v),
graphene_vec4_get_y (v),
graphene_vec4_get_z (v),
graphene_vec4_get_w (v));
}
break;
}
}
_indent (p);
g_string_append_printf (p->str, "uniforms: %s;\n", decl->str);
_indent (p);
g_string_append_printf (p->str, "uniform-data: %s;\n", data->str);
g_string_free (decl, TRUE);
g_string_free (data, TRUE);
}
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);
char *name;
name = g_strdup_printf ("child%d", i + 1);
append_node_param (p, name, child);
g_free (name);
}
end_node (p);