GtkSnapshot: Add gtk_snapshot_push_glshader()

This is a helper to create GskGLShader nodes
This commit is contained in:
Alexander Larsson
2020-09-18 17:56:02 +02:00
parent 61ae25d55e
commit f7978c784f
2 changed files with 130 additions and 0 deletions

View File

@@ -91,6 +91,14 @@ struct _GtkSnapshotState {
struct {
graphene_rect_t bounds;
} clip;
struct {
GskGLShader *shader;
graphene_vec4_t args;
graphene_rect_t bounds;
int n_children;
int node_idx;
GskRenderNode **nodes;
} glshader;
struct {
GskRoundedRect bounds;
} rounded_clip;
@@ -812,6 +820,122 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &state->data.clip.bounds);
}
static GskRenderNode *
maybe_clip (GskRenderNode *node,
const graphene_rect_t *bounds)
{
if (node &&
!graphene_rect_contains_rect (bounds, &node->bounds))
{
return gsk_clip_node_new (node, bounds);
}
return gsk_render_node_ref (node);
}
static GskRenderNode *
gtk_snapshot_collect_glshader (GtkSnapshot *snapshot,
GtkSnapshotState *state,
GskRenderNode **nodes,
guint n_nodes)
{
GskRenderNode *shader_node = NULL, *child_node;
GdkRGBA transparent = { 0, 0, 0, 0 };
child_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
if (child_node == NULL)
child_node = gsk_color_node_new (&transparent, &state->data.glshader.bounds);
state->data.glshader.nodes[state->data.glshader.node_idx] = child_node;
if (state->data.glshader.node_idx != state->data.glshader.n_children)
return NULL; /* Not last */
/* This is the last pop */
shader_node = NULL;
if (state->data.glshader.bounds.size.width != 0 &&
state->data.glshader.bounds.size.height != 0)
{
GskRenderNode *fallback_node = maybe_clip (state->data.glshader.nodes[0],
&state->data.glshader.bounds);
shader_node = gsk_glshader_node_new (state->data.glshader.shader,
&state->data.glshader.args,
&state->data.glshader.bounds,
fallback_node,
&state->data.glshader.nodes[1],
state->data.glshader.n_children);
gsk_render_node_unref (fallback_node);
}
g_object_unref (state->data.glshader.shader);
for (guint i = 0; i < state->data.glshader.n_children + 1; i++)
gsk_render_node_unref (state->data.glshader.nodes[i]);
g_free (state->data.glshader.nodes);
return shader_node;
}
/**
* gtk_snapshot_push_glshader:
* @snapshot: a #GtkSnapshot
* @shader: The code to run
* @args: A vec4 argument given to the shader
* @bounds: the rectangle to render into
* @n_children: The number of extra nodes given as argument to the shader as textures.
*
* Renders a rectagle with output from a GLSL shader. If shaders are not supported
* the fallback will be used instead. The fallback is pushed to the snapshot
* until the first call to gtk_snapshot_pop(). After that the extra nodes
* pushed, and @n_children mode gtk_snapshot_pop() calls are expected for
* these.
*/
void
gtk_snapshot_push_glshader (GtkSnapshot *snapshot,
GskGLShader *shader,
const graphene_vec4_t *args,
const graphene_rect_t *bounds,
int n_children)
{
GtkSnapshotState *state;
float scale_x, scale_y, dx, dy;
GskRenderNode **nodes;
int node_idx;
graphene_rect_t transformed_bounds;
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
state = gtk_snapshot_push_state (snapshot,
gtk_snapshot_get_current_state (snapshot)->transform,
gtk_snapshot_collect_glshader);
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &transformed_bounds);
state->data.glshader.bounds = transformed_bounds;
state->data.glshader.shader = g_object_ref (shader);
if (args)
state->data.glshader.args = *args;
else
graphene_vec4_init (&state->data.glshader.args, 0, 0, 0, 0);
state->data.glshader.n_children = n_children;
nodes = g_new0 (GskRenderNode *, n_children + 1);
node_idx = n_children; /* We pop in reverse order */
state->data.glshader.node_idx = node_idx--;
state->data.glshader.nodes = nodes;
for (int i = 0; i < n_children; i++)
{
state = gtk_snapshot_push_state (snapshot,
gtk_snapshot_get_current_state (snapshot)->transform,
gtk_snapshot_collect_glshader);
state->data.glshader.node_idx = node_idx--;
state->data.glshader.n_children = n_children;
state->data.glshader.nodes = nodes;
state->data.glshader.bounds = transformed_bounds;
}
}
static GskRenderNode *
gtk_snapshot_collect_rounded_clip (GtkSnapshot *snapshot,
GtkSnapshotState *state,

View File

@@ -99,6 +99,12 @@ GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_cross_fade (GtkSnapshot *snapshot,
double progress);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_glshader (GtkSnapshot *snapshot,
GskGLShader *shader,
const graphene_vec4_t *args,
const graphene_rect_t *bounds,
int n_children);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_pop (GtkSnapshot *snapshot);
GDK_AVAILABLE_IN_ALL