/* GSK - The GTK Scene Kit
*
* Copyright 2016 Endless
*
* 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/>.
*/
#include "config.h"
#include "gskglshadernode.h"
#include "gskcontainernodeprivate.h"
#include "gskrectprivate.h"
#include "gskrendernodeprivate.h"
#include "gskrenderreplay.h"
#include <gdk/gdkcairoprivate.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/**
* GskGLShaderNode :
*
* A render node using a GL shader when drawing its children nodes .
*/
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,
GskCairoData *data)
{
GdkRGBA pink = { 255 / 255 ., 105 / 255 ., 180 / 255 ., 1 .0 };
gdk_cairo_set_source_rgba_ccs (cr, data->ccs, &pink);
gdk_cairo_rect (cr, &node->bounds);
cairo_fill (cr);
}
static void
gsk_gl_shader_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
GskDiffData *data)
{
GskGLShaderNode *self1 = (GskGLShaderNode *) node1;
GskGLShaderNode *self2 = (GskGLShaderNode *) node2;
if (gsk_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], &(GskDiffData) { child_region, data->copies, data->surface });
if (!cairo_region_is_empty (child_region))
gsk_render_node_diff_impossible (node1, node2, data);
cairo_region_destroy (child_region);
}
else
{
gsk_render_node_diff_impossible (node1, node2, data);
}
}
static GskRenderNode **
gsk_gl_shader_node_get_children (GskRenderNode *node,
gsize *n_children)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
*n_children = self->n_children;
return self->children;
}
static GskRenderNode *
gsk_gl_shader_node_replay (GskRenderNode *node,
GskRenderReplay *replay)
{
GskGLShaderNode *self = (GskGLShaderNode *) node;
GskRenderNode *result;
GskRenderNode **children;
gboolean changed, all_empty;
guint i;
children = g_new (GskRenderNode *, self->n_children);
changed = FALSE ;
all_empty = TRUE ;
for (i = 0 ; i < self->n_children; i++)
{
children[i] = gsk_render_replay_filter_node (replay, self->children[i]);
if (children[i] == NULL)
children[i] = gsk_container_node_new (NULL, 0 );
else
all_empty = FALSE ;
if (children[i] != self->children[i])
changed = TRUE ;
}
if (!changed)
result = gsk_render_node_ref (node);
else if (all_empty)
result = NULL;
else
result = gsk_gl_shader_node_new (self->shader,
&node->bounds,
self->args,
children,
self->n_children);
for (i = 0 ; i < self->n_children; i++)
gsk_render_node_unref (children[i]);
g_free (children);
return result;
}
static void
gsk_gl_shader_node_class_init (gpointer g_class,
gpointer class_data)
{
GskRenderNodeClass *node_class = g_class;
node_class->node_type = GSK_GL_SHADER_NODE;
node_class->finalize = gsk_gl_shader_node_finalize;
node_class->draw = gsk_gl_shader_node_draw;
node_class->diff = gsk_gl_shader_node_diff;
node_class->get_children = gsk_gl_shader_node_get_children;
node_class->replay = gsk_gl_shader_node_replay;
}
GSK_DEFINE_RENDER_NODE_TYPE (GskGLShaderNode, gsk_gl_shader_node)
/**
* gsk_gl_shader_node_new :
* @ shader : the ` GskGLShader `
* @ bounds : the rectangle to render the shader into
* @ args : Arguments for the uniforms
* @ children : ( nullable ) ( array length = n_children ) : array of child nodes ,
* these will be rendered to textures and used as input .
* @ n_children : Length of @ children ( currently 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
* [ method @ Gsk . GLShader . format_args ] or [ struct @ Gsk . ShaderArgsBuilder ] .
*
* See [ class @ Gsk . GLShader ] 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
* [ method @ Gsk . GLShader . compile ] to ensure the @ shader will work for the
* renderer before using it .
*
* Returns : ( transfer full ) ( type GskGLShaderNode ) : A new ` GskRenderNode `
*
* Deprecated : 4 . 16 : GTK ' s new Vulkan - focused rendering
* does not support this feature . Use [ GtkGLArea ] ( . . / gtk4 / class . GLArea . html )
* for OpenGL rendering .
*/
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, NULL);
g_return_val_if_fail (g_bytes_get_size (args) == gsk_gl_shader_get_args_size (shader), NULL);
g_return_val_if_fail ((children == NULL && n_children == 0 ) ||
(n_children == gsk_gl_shader_get_n_textures (shader)), NULL);
self = gsk_render_node_alloc (GSK_TYPE_GL_SHADER_NODE);
node = (GskRenderNode *) self;
node->preferred_depth = gdk_color_state_get_depth (GDK_COLOR_STATE_SRGB);
gsk_rect_init_from_rect (&node->bounds, bounds);
gsk_rect_normalize (&node->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]);
node->preferred_depth = gdk_memory_depth_merge (node->preferred_depth,
gsk_render_node_get_preferred_depth (children[i]));
node->contains_subsurface_node |= gsk_render_node_contains_subsurface_node (children[i]);
node->contains_paste_node |= gsk_render_node_contains_paste_node (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
*
* Deprecated : 4 . 16 : GTK ' s new Vulkan - focused rendering
* does not support this feature . Use [ GtkGLArea ] ( . . / gtk4 / class . GLArea . html )
* for OpenGL rendering .
*/
guint
gsk_gl_shader_node_get_n_children (const GskRenderNode *node)
{
const GskGLShaderNode *self = (const GskGLShaderNode *) node;
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
*
* Deprecated : 4 . 16 : GTK ' s new Vulkan - focused rendering
* does not support this feature . Use [ GtkGLArea ] ( . . / gtk4 / class . GLArea . html )
* for OpenGL rendering .
*/
GskRenderNode *
gsk_gl_shader_node_get_child (const GskRenderNode *node,
guint idx)
{
const GskGLShaderNode *self = (const GskGLShaderNode *) node;
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
*
* Deprecated : 4 . 16
*/
GskGLShader *
gsk_gl_shader_node_get_shader (const GskRenderNode *node)
{
const GskGLShaderNode *self = (const GskGLShaderNode *) node;
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
*
* Deprecated : 4 . 16 : GTK ' s new Vulkan - focused rendering
* does not support this feature . Use [ GtkGLArea ] ( . . / gtk4 / class . GLArea . html )
* for OpenGL rendering .
*/
GBytes *
gsk_gl_shader_node_get_args (const GskRenderNode *node)
{
const GskGLShaderNode *self = (const GskGLShaderNode *) node;
return self->args;
}
G_GNUC_END_IGNORE_DEPRECATIONS
Messung V0.5 in Prozent C=98 H=94 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland