diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 62b7a47cfe..0d3591c1ff 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -123,21 +123,28 @@ gsk_cairo_renderer_render_node (GskCairoRenderer *self, } static void -gsk_cairo_renderer_resize_viewport (GskRenderer *renderer, - const graphene_rect_t *viewport) +gsk_cairo_renderer_render (GskRenderer *renderer, + GskRenderNode *root, + GdkDrawingContext *context) { GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); + cairo_t *cr = gdk_drawing_context_get_cairo_context (context); - self->viewport = *viewport; -} + gsk_renderer_get_viewport (renderer, &self->viewport); -static void -gsk_cairo_renderer_render (GskRenderer *renderer) -{ - GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); - cairo_surface_t *target = gsk_renderer_get_surface (renderer); - GskRenderNode *root = gsk_renderer_get_root_node (renderer); - cairo_t *cr = cairo_create (target); + if (gsk_renderer_get_auto_clear (renderer)) + { + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + if (gsk_renderer_get_use_alpha (renderer)) + cairo_set_source_rgba (cr, 0, 0, 0, 0); + else + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_paint (cr); + cairo_restore (cr); + } if (GSK_RENDER_MODE_CHECK (GEOMETRY)) { @@ -154,26 +161,6 @@ gsk_cairo_renderer_render (GskRenderer *renderer) } gsk_cairo_renderer_render_node (self, root, cr); - - cairo_destroy (cr); -} - -static void -gsk_cairo_renderer_clear (GskRenderer *renderer) -{ - cairo_surface_t *surface = gsk_renderer_get_surface (renderer); - cairo_t *cr = cairo_create (surface); - - cairo_set_operator (cr, CAIRO_OPERATOR_OVER); - - if (gsk_renderer_get_use_alpha (renderer)) - cairo_set_source_rgba (cr, 0, 0, 0, 0); - else - cairo_set_source_rgb (cr, 0, 0, 0); - - cairo_paint (cr); - - cairo_destroy (cr); } static void @@ -183,8 +170,6 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass) renderer_class->realize = gsk_cairo_renderer_realize; renderer_class->unrealize = gsk_cairo_renderer_unrealize; - renderer_class->resize_viewport = gsk_cairo_renderer_resize_viewport; - renderer_class->clear = gsk_cairo_renderer_clear; renderer_class->render = gsk_cairo_renderer_render; } diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index 40febcad43..a2f9a2f48c 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -432,16 +432,9 @@ gsk_gl_renderer_realize (GskRenderer *renderer) gdk_gl_context_make_current (self->context); GSK_NOTE (OPENGL, g_print ("Creating buffers and programs\n")); - gsk_gl_renderer_create_buffers (self); gsk_gl_renderer_create_program (self); - self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), 16); - g_array_set_clear_func (self->opaque_render_items, render_item_clear); - - self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), 16); - g_array_set_clear_func (self->opaque_render_items, render_item_clear); - return TRUE; } @@ -466,18 +459,22 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer) } static void -gsk_gl_renderer_resize_viewport (GskRenderer *renderer, +gsk_gl_renderer_resize_viewport (GskGLRenderer *self, const graphene_rect_t *viewport) { + GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %g, %g)\n", + viewport->size.width, + viewport->size.height)); + + glViewport (viewport->origin.x, viewport->origin.y, + viewport->size.width, viewport->size.height); } static void -gsk_gl_renderer_update (GskRenderer *renderer, - const graphene_matrix_t *modelview, - const graphene_matrix_t *projection) +gsk_gl_renderer_update_frustum (GskGLRenderer *self, + const graphene_matrix_t *modelview, + const graphene_matrix_t *projection) { - GskGLRenderer *self = GSK_GL_RENDERER (renderer); - GSK_NOTE (OPENGL, g_print ("Updating the modelview/projection\n")); graphene_matrix_multiply (modelview, projection, &self->mvp); @@ -662,6 +659,7 @@ get_gl_scaling_filters (GskRenderer *renderer, } } +#if 0 static gboolean check_in_frustum (const graphene_frustum_t *frustum, RenderItem *item) @@ -673,6 +671,7 @@ check_in_frustum (const graphene_frustum_t *frustum, return graphene_frustum_intersects_box (frustum, &aabb); } +#endif static float project_item (const graphene_matrix_t *projection, @@ -748,19 +747,6 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, gsk_renderer_get_projection (GSK_RENDERER (self), &projection); item.z = project_item (&projection, &mv); - /* Discard the item if it's outside of the frustum as determined by the - * viewport and the projection matrix - */ -#if 0 - if (!check_in_frustum (&self->frustum, &item)) - { - GSK_NOTE (OPENGL, g_print ("Node <%s>[%p] culled by frustum\n", - node->name != NULL ? node->name : "unnamed", - node)); - return; - } -#endif - /* TODO: This should really be an asset atlas, to avoid uploading a ton * of textures. Ideally we could use a single Cairo surface to get around * the GL texture limits and reorder the texture data on the CPU side and @@ -787,7 +773,7 @@ gsk_gl_renderer_add_render_item (GskGLRenderer *self, if (gsk_render_node_is_opaque (node) && gsk_render_node_get_opacity (node) == 1.f) g_array_append_val (self->opaque_render_items, item); else - g_array_append_val (self->transparent_render_items, item); + g_array_prepend_val (self->transparent_render_items, item); recurse_children: gsk_render_node_iter_init (&iter, node); @@ -795,198 +781,72 @@ recurse_children: gsk_gl_renderer_add_render_item (self, child); } -static int -opaque_item_cmp (gconstpointer _a, - gconstpointer _b) -{ - const RenderItem *a = _a; - const RenderItem *b = _b; - - if (a->z != b->z) - { - if (a->z > b->z) - return 1; - - return -1; - } - - if (a != b) - { - if ((gsize) a > (gsize) b) - return 1; - - return -1; - } - - return 0; -} - -static int -transparent_item_cmp (gconstpointer _a, - gconstpointer _b) -{ - const RenderItem *a = _a; - const RenderItem *b = _b; - - if (a->z != b->z) - { - if (a->z < b->z) - return 1; - - return -1; - } - - if (a != b) - { - if ((gsize) a < (gsize) b) - return 1; - - return -1; - } - - return 0; -} - -static void -gsk_gl_renderer_validate_tree (GskRenderer *renderer, +static gboolean +gsk_gl_renderer_validate_tree (GskGLRenderer *self, GskRenderNode *root) { - GskGLRenderer *self = GSK_GL_RENDERER (renderer); - gboolean clear_items = FALSE; - int i; + int n_children; if (self->context == NULL) - return; + return FALSE; + + n_children = gsk_render_node_get_n_children (root); + if (n_children == 0) + return FALSE; gdk_gl_context_make_current (self->context); - if (self->opaque_render_items->len > 0 || self->transparent_render_items->len > 0) - { - /* If we only changed the opacity and transformations then there is no - * reason to clear the render items - */ - for (i = 0; i < self->opaque_render_items->len; i++) - { - RenderItem *item = &g_array_index (self->opaque_render_items, RenderItem, i); - GskRenderNodeChanges changes = gsk_render_node_get_last_state (item->node); + self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_children); + self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), n_children); - if (changes == 0) - continue; - - if ((changes & GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY) != 0) - { - item->opaque = gsk_render_node_is_opaque (item->node); - item->opacity = gsk_render_node_get_opacity (item->node); - changes &= ~GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY; - } - - if (changes & GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM) - { - gsk_render_node_get_world_matrix (item->node, &item->mvp); - changes &= ~ GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM; - } - - if (changes != 0) - { - clear_items = TRUE; - break; - } - } - - for (i = 0; i < self->transparent_render_items->len; i++) - { - RenderItem *item = &g_array_index (self->transparent_render_items, RenderItem, i); - GskRenderNodeChanges changes = gsk_render_node_get_last_state (item->node); - - if (changes == 0) - continue; - - if ((changes & GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY) != 0) - { - item->opaque = gsk_render_node_is_opaque (item->node); - item->opacity = gsk_render_node_get_opacity (item->node); - changes &= ~GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY; - } - - if (changes & GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM) - { - gsk_render_node_get_world_matrix (item->node, &item->mvp); - changes &= ~ GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM; - } - - if (changes != 0) - { - clear_items = TRUE; - break; - } - } - } - else - clear_items = TRUE; - - if (!clear_items) - { - GSK_NOTE (OPENGL, g_print ("Tree is still valid\n")); - goto out; - } - - for (i = 0; i < self->opaque_render_items->len; i++) - render_item_clear (&g_array_index (self->opaque_render_items, RenderItem, i)); - for (i = 0; i < self->transparent_render_items->len; i++) - render_item_clear (&g_array_index (self->transparent_render_items, RenderItem, i)); - - g_array_set_size (self->opaque_render_items, 0); - g_array_set_size (self->transparent_render_items, 0); + g_array_set_clear_func (self->opaque_render_items, render_item_clear); + g_array_set_clear_func (self->transparent_render_items, render_item_clear); GSK_NOTE (OPENGL, g_print ("RenderNode -> RenderItem\n")); - gsk_gl_renderer_add_render_item (self, gsk_renderer_get_root_node (renderer)); + gsk_gl_renderer_add_render_item (self, root); - GSK_NOTE (OPENGL, g_print ("Sorting render nodes\n")); - g_array_sort (self->opaque_render_items, opaque_item_cmp); - g_array_sort (self->transparent_render_items, transparent_item_cmp); - -out: GSK_NOTE (OPENGL, g_print ("Total render items: %d (opaque:%d, transparent:%d)\n", self->opaque_render_items->len + self->transparent_render_items->len, self->opaque_render_items->len, self->transparent_render_items->len)); + + return TRUE; } static void -gsk_gl_renderer_clear_tree (GskRenderer *renderer, - GskRenderNode *root_node) +gsk_gl_renderer_clear_tree (GskGLRenderer *self) { - GskGLRenderer *self = GSK_GL_RENDERER (renderer); - if (self->context == NULL) return; - gdk_gl_context_make_current (self->context); - g_clear_pointer (&self->opaque_render_items, g_array_unref); g_clear_pointer (&self->transparent_render_items, g_array_unref); - - if (gsk_renderer_is_realized (renderer)) - { - self->opaque_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), 16); - g_array_set_clear_func (self->opaque_render_items, render_item_clear); - - self->transparent_render_items = g_array_sized_new (FALSE, FALSE, sizeof (RenderItem), 16); - g_array_set_clear_func (self->opaque_render_items, render_item_clear); - } } static void -gsk_gl_renderer_clear (GskRenderer *renderer) +gsk_gl_renderer_clear (GskGLRenderer *self) { + int clear_bits = GL_COLOR_BUFFER_BIT; + + if (self->has_depth_buffer) + clear_bits |= GL_DEPTH_BUFFER_BIT; + if (self->has_stencil_buffer) + clear_bits |= GL_STENCIL_BUFFER_BIT; + + GSK_NOTE (OPENGL, g_print ("Clearing viewport\n")); + glClearColor (0, 0, 0, 0); + glClear (clear_bits); } static void -gsk_gl_renderer_render (GskRenderer *renderer) +gsk_gl_renderer_render (GskRenderer *renderer, + GskRenderNode *root, + GdkDrawingContext *context) { GskGLRenderer *self = GSK_GL_RENDERER (renderer); + graphene_matrix_t modelview, projection; graphene_rect_t viewport; - int scale, status, clear_bits; + int status; guint i; if (self->context == NULL) @@ -1008,22 +868,16 @@ gsk_gl_renderer_render (GskRenderer *renderer) /* Ensure that the viewport is up to date */ status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); if (status == GL_FRAMEBUFFER_COMPLETE_EXT) - { - GSK_NOTE (OPENGL, g_print ("glViewport(0, 0, %g, %g)\n", - viewport.size.width, - viewport.size.height)); - glViewport (0, 0, viewport.size.width, viewport.size.height); - } + gsk_gl_renderer_resize_viewport (self, &viewport); - clear_bits = GL_COLOR_BUFFER_BIT; - if (self->has_depth_buffer) - clear_bits |= GL_DEPTH_BUFFER_BIT; - if (self->has_stencil_buffer) - clear_bits |= GL_STENCIL_BUFFER_BIT; + gsk_gl_renderer_clear (self); - GSK_NOTE (OPENGL, g_print ("Clearing viewport\n")); - glClearColor (0, 0, 0, 0); - glClear (clear_bits); + gsk_renderer_get_modelview (renderer, &modelview); + gsk_renderer_get_projection (renderer, &projection); + gsk_gl_renderer_update_frustum (self, &modelview, &projection); + + if (!gsk_gl_renderer_validate_tree (self, root)) + goto out; /* Opaque pass: front-to-back */ GSK_NOTE (OPENGL, g_print ("Rendering %u opaque items\n", self->opaque_render_items->len)); @@ -1050,15 +904,18 @@ gsk_gl_renderer_render (GskRenderer *renderer) /* Draw the output of the GL rendering to the window */ GSK_NOTE (OPENGL, g_print ("Drawing GL content on Cairo surface using a %s\n", self->texture_id != 0 ? "texture" : "renderbuffer")); - scale = 1; - gdk_cairo_draw_from_gl (gsk_renderer_get_draw_context (renderer), - gsk_renderer_get_window (renderer), + +out: + gdk_cairo_draw_from_gl (gdk_drawing_context_get_cairo_context (context), + gdk_drawing_context_get_window (context), self->texture_id != 0 ? self->texture_id : self->render_buffer, self->texture_id != 0 ? GL_TEXTURE : GL_RENDERBUFFER, - scale, + gsk_renderer_get_scale_factor (renderer), 0, 0, viewport.size.width, viewport.size.height); gdk_gl_context_make_current (self->context); + + gsk_gl_renderer_clear_tree (self); } static void @@ -1071,11 +928,6 @@ gsk_gl_renderer_class_init (GskGLRendererClass *klass) renderer_class->realize = gsk_gl_renderer_realize; renderer_class->unrealize = gsk_gl_renderer_unrealize; - renderer_class->resize_viewport = gsk_gl_renderer_resize_viewport; - renderer_class->update = gsk_gl_renderer_update; - renderer_class->clear = gsk_gl_renderer_clear; - renderer_class->validate_tree = gsk_gl_renderer_validate_tree; - renderer_class->clear_tree = gsk_gl_renderer_clear_tree; renderer_class->render = gsk_gl_renderer_render; } @@ -1089,27 +941,3 @@ gsk_gl_renderer_init (GskGLRenderer *self) self->has_depth_buffer = TRUE; self->has_stencil_buffer = TRUE; } - -void -gsk_gl_renderer_set_context (GskGLRenderer *renderer, - GdkGLContext *context) -{ - g_return_if_fail (GSK_IS_GL_RENDERER (renderer)); - g_return_if_fail (context == NULL || GDK_IS_GL_CONTEXT (context)); - - if (gsk_renderer_is_realized (GSK_RENDERER (renderer))) - return; - - if (gdk_gl_context_get_display (context) != gsk_renderer_get_display (GSK_RENDERER (renderer))) - return; - - g_set_object (&renderer->context, context); -} - -GdkGLContext * -gsk_gl_renderer_get_context (GskGLRenderer *renderer) -{ - g_return_val_if_fail (GSK_IS_GL_RENDERER (renderer), NULL); - - return renderer->context; -} diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index 3a84fc9547..72717bbbdf 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -29,7 +29,6 @@ #include "gskrendererprivate.h" #include "gskdebugprivate.h" -#include "gskcairorendererprivate.h" #include "gskglrendererprivate.h" #include "gskrendernodeprivate.h" @@ -50,9 +49,6 @@ typedef struct { GObject parent_instance; - GdkDisplay *display; - GdkWindow *window; - graphene_rect_t viewport; graphene_matrix_t modelview; graphene_matrix_t projection; @@ -60,16 +56,14 @@ typedef struct GskScalingFilter min_filter; GskScalingFilter mag_filter; + GdkWindow *window; + GdkDrawingContext *drawing_context; GskRenderNode *root_node; + GdkDisplay *display; - cairo_surface_t *surface; - cairo_t *draw_context; + int scale_factor; gboolean is_realized : 1; - gboolean needs_viewport_resize : 1; - gboolean needs_modelview_update : 1; - gboolean needs_projection_update : 1; - gboolean needs_tree_validation : 1; gboolean auto_clear : 1; gboolean use_alpha : 1; } GskRendererPrivate; @@ -83,11 +77,12 @@ enum { PROP_MINIFICATION_FILTER, PROP_MAGNIFICATION_FILTER, PROP_AUTO_CLEAR, + PROP_USE_ALPHA, + PROP_SCALE_FACTOR, + PROP_WINDOW, PROP_ROOT_NODE, PROP_DISPLAY, - PROP_WINDOW, - PROP_SURFACE, - PROP_USE_ALPHA, + PROP_DRAWING_CONTEXT, N_PROPS }; @@ -111,36 +106,13 @@ gsk_renderer_real_unrealize (GskRenderer *self) } static void -gsk_renderer_real_render (GskRenderer *self) +gsk_renderer_real_render (GskRenderer *self, + GskRenderNode *root, + GdkDrawingContext *context) { GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render); } -static void -gsk_renderer_real_resize_viewport (GskRenderer *self, - const graphene_rect_t *viewport) -{ -} - -static void -gsk_renderer_real_update (GskRenderer *self, - const graphene_matrix_t *mv, - const graphene_matrix_t *proj) -{ -} - -static void -gsk_renderer_real_validate_tree (GskRenderer *self, - GskRenderNode *root) -{ -} - -static void -gsk_renderer_real_clear_tree (GskRenderer *self, - GskRenderNode *old_root) -{ -} - static void gsk_renderer_dispose (GObject *gobject) { @@ -149,11 +121,7 @@ gsk_renderer_dispose (GObject *gobject) gsk_renderer_unrealize (self); - g_clear_pointer (&priv->surface, cairo_surface_destroy); - g_clear_pointer (&priv->draw_context, cairo_destroy); - g_clear_object (&priv->window); - g_clear_object (&priv->root_node); g_clear_object (&priv->display); G_OBJECT_CLASS (gsk_renderer_parent_class)->dispose (gobject); @@ -194,12 +162,12 @@ gsk_renderer_set_property (GObject *gobject, gsk_renderer_set_auto_clear (self, g_value_get_boolean (value)); break; - case PROP_ROOT_NODE: - gsk_renderer_set_root_node (self, g_value_get_object (value)); + case PROP_USE_ALPHA: + gsk_renderer_set_use_alpha (self, g_value_get_boolean (value)); break; - case PROP_SURFACE: - gsk_renderer_set_surface (self, g_value_get_boxed (value)); + case PROP_SCALE_FACTOR: + gsk_renderer_set_scale_factor (self, g_value_get_int (value)); break; case PROP_WINDOW: @@ -207,12 +175,9 @@ gsk_renderer_set_property (GObject *gobject, break; case PROP_DISPLAY: + /* Construct-only */ priv->display = g_value_dup_object (value); break; - - case PROP_USE_ALPHA: - gsk_renderer_set_use_alpha (self, g_value_get_boolean (value)); - break; } } @@ -251,24 +216,28 @@ gsk_renderer_get_property (GObject *gobject, g_value_set_boolean (value, priv->auto_clear); break; - case PROP_ROOT_NODE: - g_value_set_object (value, priv->root_node); + case PROP_USE_ALPHA: + g_value_set_boolean (value, priv->use_alpha); break; - case PROP_SURFACE: - g_value_set_boxed (value, priv->surface); - break; - - case PROP_DISPLAY: - g_value_set_object (value, priv->display); + case PROP_SCALE_FACTOR: + g_value_set_int (value, priv->scale_factor); break; case PROP_WINDOW: g_value_set_object (value, priv->window); break; - case PROP_USE_ALPHA: - g_value_set_boolean (value, priv->use_alpha); + case PROP_ROOT_NODE: + g_value_set_object (value, priv->root_node); + break; + + case PROP_DRAWING_CONTEXT: + g_value_set_object (value, priv->drawing_context); + break; + + case PROP_DISPLAY: + g_value_set_object (value, priv->display); break; } } @@ -297,10 +266,6 @@ gsk_renderer_class_init (GskRendererClass *klass) klass->realize = gsk_renderer_real_realize; klass->unrealize = gsk_renderer_real_unrealize; - klass->resize_viewport = gsk_renderer_real_resize_viewport; - klass->update = gsk_renderer_real_update; - klass->validate_tree = gsk_renderer_real_validate_tree; - klass->clear_tree = gsk_renderer_real_clear_tree; klass->render = gsk_renderer_real_render; gobject_class->constructed = gsk_renderer_constructed; @@ -448,27 +413,8 @@ gsk_renderer_class_init (GskRendererClass *klass) "Root Node", "The root render node to render", GSK_TYPE_RENDER_NODE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY); - - /** - * GskRenderer:surface: - * - * The target rendering surface. - * - * See also: #GskRenderer:window. - * - * Since: 3.22 - */ - gsk_renderer_properties[PROP_SURFACE] = - g_param_spec_boxed ("surface", - "Surface", - "The Cairo surface used to render to", - CAIRO_GOBJECT_TYPE_SURFACE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY); + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); /** * GskRenderer:display: @@ -486,22 +432,46 @@ gsk_renderer_class_init (GskRendererClass *klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - /** - * GskRenderer:window: - * - * The #GdkWindow used to create a target surface, if #GskRenderer:surface - * is not explicitly set. - * - * Since: 3.22 - */ gsk_renderer_properties[PROP_WINDOW] = g_param_spec_object ("window", "Window", - "The GdkWindow associated to the renderer", + "The window associated to the renderer", GDK_TYPE_WINDOW, G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS | - G_PARAM_EXPLICIT_NOTIFY); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + + /** + * GskRenderer:scale-factor: + * + * The scale factor used when rendering. + * + * Since: 3.22 + */ + gsk_renderer_properties[PROP_SCALE_FACTOR] = + g_param_spec_int ("scale-factor", + "Scale Factor", + "The scaling factor of the renderer", + 1, G_MAXINT, + 1, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS | + G_PARAM_EXPLICIT_NOTIFY); + + /** + * GskRenderer:drawing-context: + * + * The drawing context used when rendering. + * + * Since: 3.22 + */ + gsk_renderer_properties[PROP_DRAWING_CONTEXT] = + g_param_spec_object ("drawing-context", + "Drawing Context", + "The drawing context used by the renderer", + GDK_TYPE_DRAWING_CONTEXT, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); /** * GskRenderer:use-alpha: @@ -531,6 +501,7 @@ gsk_renderer_init (GskRenderer *self) graphene_matrix_init_identity (&priv->projection); priv->auto_clear = TRUE; + priv->scale_factor = 1; priv->min_filter = GSK_SCALING_FILTER_LINEAR; priv->mag_filter = GSK_SCALING_FILTER_LINEAR; @@ -565,9 +536,6 @@ gsk_renderer_set_viewport (GskRenderer *renderer, return; graphene_rect_init_from_rect (&priv->viewport, viewport); - priv->needs_viewport_resize = TRUE; - priv->needs_modelview_update = TRUE; - priv->needs_projection_update = TRUE; g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_VIEWPORT]); } @@ -618,8 +586,6 @@ gsk_renderer_set_modelview (GskRenderer *renderer, else graphene_matrix_init_from_matrix (&priv->modelview, modelview); - priv->needs_modelview_update = TRUE; - g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_MODELVIEW]); } @@ -666,8 +632,6 @@ gsk_renderer_set_projection (GskRenderer *renderer, else graphene_matrix_init_from_matrix (&priv->projection, projection); - priv->needs_projection_update = TRUE; - g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_PROJECTION]); } @@ -692,67 +656,6 @@ gsk_renderer_get_projection (GskRenderer *renderer, graphene_matrix_init_from_matrix (projection, &priv->projection); } -static void -gsk_renderer_invalidate_tree (GskRenderNode *node, - gpointer data) -{ - GskRenderer *self = data; - GskRendererPrivate *priv = gsk_renderer_get_instance_private (self); - - GSK_NOTE (RENDERER, g_print ("Invalidating tree.\n")); - - /* Since the scene graph has changed in some way, we need to re-validate it. */ - priv->needs_tree_validation = TRUE; -} - -/** - * gsk_renderer_set_root_node: - * @renderer: a #GskRenderer - * @root: (nullable): a #GskRenderNode - * - * Sets the root node of the scene graph to be rendered. - * - * The #GskRenderer will acquire a reference on @root. - * - * Since: 3.22 - */ -void -gsk_renderer_set_root_node (GskRenderer *renderer, - GskRenderNode *root) -{ - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - GskRenderNode *old_root; - - g_return_if_fail (GSK_IS_RENDERER (renderer)); - g_return_if_fail (GSK_IS_RENDER_NODE (root)); - - old_root = priv->root_node != NULL ? g_object_ref (priv->root_node) : NULL; - - if (g_set_object (&priv->root_node, root)) - { - /* We need to unset the invalidate function on the old instance */ - if (old_root != NULL) - { - gsk_render_node_set_invalidate_func (old_root, NULL, NULL, NULL); - gsk_renderer_clear_tree (renderer, old_root); - g_object_unref (old_root); - } - - if (priv->root_node != NULL) - gsk_render_node_set_invalidate_func (priv->root_node, - gsk_renderer_invalidate_tree, - renderer, - NULL); - - /* If we don't have a root node, there's really no point in validating a - * tree that it's not going to be drawn - */ - priv->needs_tree_validation = priv->root_node != NULL; - - g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_ROOT_NODE]); - } -} - /** * gsk_renderer_set_scaling_filters: * @renderer: a #GskRenderer @@ -819,112 +722,100 @@ gsk_renderer_get_scaling_filters (GskRenderer *renderer, *mag_filter = priv->mag_filter; } -/** - * gsk_renderer_set_surface: - * @renderer: a #GskRenderer - * @surface: (nullable): a Cairo surface - * - * Sets the #cairo_surface_t used as the target rendering surface. - * - * This function will acquire a reference to @surface. - * - * See also: gsk_renderer_set_window() - * - * Since: 3.22 - */ void -gsk_renderer_set_surface (GskRenderer *renderer, - cairo_surface_t *surface) +gsk_renderer_set_scale_factor (GskRenderer *renderer, + int scale_factor) { GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); g_return_if_fail (GSK_IS_RENDERER (renderer)); - if (priv->surface == surface) - return; - - g_clear_pointer (&priv->surface, cairo_surface_destroy); - - if (surface != NULL) - priv->surface = cairo_surface_reference (surface); - - g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_SURFACE]); -} - -/** - * gsk_renderer_get_surface: - * @renderer: a #GskRenderer - * - * Retrieve the target rendering surface used by @renderer. - * - * If you did not use gsk_renderer_set_surface(), a compatible surface - * will be created by using the #GdkWindow passed to gsk_renderer_set_window(). - * - * Returns: (transfer none) (nullable): a Cairo surface - * - * Since: 3.22 - */ -cairo_surface_t * -gsk_renderer_get_surface (GskRenderer *renderer) -{ - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); - - if (priv->surface != NULL) - return priv->surface; - - if (priv->window != NULL) + if (priv->scale_factor != scale_factor) { - int scale = gdk_window_get_scale_factor (priv->window); - int width = gdk_window_get_width (priv->window); - int height = gdk_window_get_height (priv->window); - cairo_content_t content; + priv->scale_factor = scale_factor; - if (priv->use_alpha) - content = CAIRO_CONTENT_COLOR_ALPHA; - else - content = CAIRO_CONTENT_COLOR; - - GSK_NOTE (RENDERER, g_print ("Creating surface from window [%p] (w:%d, h:%d, s:%d, a:%s)\n", - priv->window, - width, height, scale, - priv->use_alpha ? "y" : "n")); - - priv->surface = gdk_window_create_similar_surface (priv->window, - content, - width, height); + g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_SCALE_FACTOR]); } +} - return priv->surface; +int +gsk_renderer_get_scale_factor (GskRenderer *renderer) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), 1); + + return priv->scale_factor; } void -gsk_renderer_set_draw_context (GskRenderer *renderer, - cairo_t *cr) +gsk_renderer_set_window (GskRenderer *renderer, + GdkWindow *window) { GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); g_return_if_fail (GSK_IS_RENDERER (renderer)); + g_return_if_fail (!priv->is_realized); + g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); - if (priv->draw_context == cr) - return; - - g_clear_pointer (&priv->draw_context, cairo_destroy); - priv->draw_context = cr != NULL ? cairo_reference (cr) : NULL; + if (g_set_object (&priv->window, window)) + g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_WINDOW]); } -cairo_t * -gsk_renderer_get_draw_context (GskRenderer *renderer) +/** + * gsk_renderer_get_window: + * @renderer: a #GskRenderer + * + * Retrieves the #GdkWindow set using gsk_renderer_set_window(). + * + * Returns: (transfer none) (nullable): a #GdkWindow + * + * Since: 3.22 + */ +GdkWindow * +gsk_renderer_get_window (GskRenderer *renderer) { GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); - if (priv->draw_context != NULL) - return priv->draw_context; + return priv->window; +} - return cairo_create (gsk_renderer_get_surface (renderer)); +/*< private > + * gsk_renderer_get_root_node: + * @renderer: a #GskRenderer + * + * Retrieves the #GskRenderNode used by @renderer. + * + * Returns: (transfer none) (nullable): a #GskRenderNode + */ +GskRenderNode * +gsk_renderer_get_root_node (GskRenderer *renderer) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); + + return priv->root_node; +} + +/*< private > + * gsk_renderer_get_drawing_context: + * @renderer: a #GskRenderer + * + * Retrieves the #GdkDrawingContext used by @renderer. + * + * Returns: (transfer none) (nullable): a #GdkDrawingContext + */ +GdkDrawingContext * +gsk_renderer_get_drawing_context (GskRenderer *renderer) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); + + return priv->drawing_context; } /** @@ -947,26 +838,6 @@ gsk_renderer_get_display (GskRenderer *renderer) return priv->display; } -/** - * gsk_renderer_get_root_node: - * @renderer: a #GskRenderer - * - * Retrieves the root node of the scene graph. - * - * Returns: (transfer none) (nullable): a #GskRenderNode - * - * Since: 3.22 - */ -GskRenderNode * -gsk_renderer_get_root_node (GskRenderer *renderer) -{ - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); - - return priv->root_node; -} - /*< private > * gsk_renderer_is_realized: * @renderer: a #GskRenderer @@ -987,51 +858,6 @@ gsk_renderer_is_realized (GskRenderer *renderer) return priv->is_realized; } -/** - * gsk_renderer_set_window: - * @renderer: a #GskRenderer - * @window: (nullable): a #GdkWindow - * - * Sets the #GdkWindow used to create the target rendering surface. - * - * See also: gsk_renderer_set_surface() - * - * Since: 3.22 - */ -void -gsk_renderer_set_window (GskRenderer *renderer, - GdkWindow *window) -{ - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - g_return_if_fail (GSK_IS_RENDERER (renderer)); - g_return_if_fail (window == NULL || GDK_IS_WINDOW (window)); - g_return_if_fail (!priv->is_realized); - - if (g_set_object (&priv->window, window)) - g_object_notify_by_pspec (G_OBJECT (renderer), gsk_renderer_properties[PROP_WINDOW]); -} - -/** - * gsk_renderer_get_window: - * @renderer: a #GskRenderer - * - * Retrieves the #GdkWindow set with gsk_renderer_set_window(). - * - * Returns: (transfer none) (nullable): a #GdkWindow - * - * Since: 3.22 - */ -GdkWindow * -gsk_renderer_get_window (GskRenderer *renderer) -{ - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); - - return priv->window; -} - /** * gsk_renderer_realize: * @renderer: a #GskRenderer @@ -1051,12 +877,6 @@ gsk_renderer_realize (GskRenderer *renderer) if (priv->is_realized) return TRUE; - if (priv->window == NULL && priv->surface == NULL) - { - g_critical ("No rendering surface has been set."); - return FALSE; - } - priv->is_realized = GSK_RENDERER_GET_CLASS (renderer)->realize (renderer); return priv->is_realized; @@ -1085,156 +905,41 @@ gsk_renderer_unrealize (GskRenderer *renderer) priv->is_realized = FALSE; } -/*< private > - * gsk_renderer_maybe_resize_viewport: - * @renderer: a #GskRenderer - * - * Optionally resize the viewport of @renderer. - * - * This function should be called by gsk_renderer_render(). - * - * This function may call @GskRendererClass.resize_viewport(). - */ -void -gsk_renderer_maybe_resize_viewport (GskRenderer *renderer) -{ - GskRendererClass *renderer_class = GSK_RENDERER_GET_CLASS (renderer); - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - if (priv->needs_viewport_resize) - { - renderer_class->resize_viewport (renderer, &priv->viewport); - priv->needs_viewport_resize = FALSE; - - GSK_NOTE (RENDERER, g_print ("Viewport size: %g x %g\n", - priv->viewport.size.width, - priv->viewport.size.height)); - - /* If the target surface has been created from a window, we need - * to clear it, so that it gets recreated with the right size - */ - if (priv->window != NULL && priv->surface != NULL) - g_clear_pointer (&priv->surface, cairo_surface_destroy); - } -} - -/*< private > - * gsk_renderer_maybe_update: - * @renderer: a #GskRenderer - * - * Optionally recomputes the modelview-projection matrix used by - * the @renderer. - * - * This function should be called by gsk_renderer_render(). - * - * This function may call @GskRendererClass.update(). - */ -void -gsk_renderer_maybe_update (GskRenderer *renderer) -{ - GskRendererClass *renderer_class = GSK_RENDERER_GET_CLASS (renderer); - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - if (priv->needs_modelview_update || priv->needs_projection_update) - { - renderer_class->update (renderer, &priv->modelview, &priv->projection); - priv->needs_modelview_update = FALSE; - priv->needs_projection_update = FALSE; - } -} - -void -gsk_renderer_clear_tree (GskRenderer *renderer, - GskRenderNode *old_root) -{ - GSK_RENDERER_GET_CLASS (renderer)->clear_tree (renderer, old_root); -} - -/*< private > - * gsk_renderer_maybe_validate_tree: - * @renderer: a #GskRenderer - * - * Optionally validates the #GskRenderNode scene graph, and uses it - * to generate more efficient intermediate representations depending - * on the type of @renderer. - * - * This function should be called by gsk_renderer_render(). - * - * This function may call @GskRendererClas.validate_tree(). - */ -void -gsk_renderer_maybe_validate_tree (GskRenderer *renderer) -{ - GskRendererClass *renderer_class = GSK_RENDERER_GET_CLASS (renderer); - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - if (priv->root_node == NULL) - return; - - /* Ensure that the render nodes are valid; this will change the - * needs_tree_validation flag on the renderer, if needed - */ - gsk_render_node_validate (priv->root_node); - - if (priv->needs_tree_validation) - { - /* Ensure that the Renderer can update itself */ - renderer_class->validate_tree (renderer, priv->root_node); - priv->needs_tree_validation = FALSE; - } -} - -/*< private > - * gsk_renderer_maybe_clear: - * @renderer: a #GskRenderer - * - * Optionally calls @GskRendererClass.clear(), depending on the value - * of #GskRenderer:auto-clear. - * - * This function should be called by gsk_renderer_render(). - */ -void -gsk_renderer_maybe_clear (GskRenderer *renderer) -{ - GskRendererClass *renderer_class = GSK_RENDERER_GET_CLASS (renderer); - GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); - - if (priv->auto_clear) - renderer_class->clear (renderer); -} - /** * gsk_renderer_render: - * @renderer: a#GskRenderer + * @renderer: a #GskRenderer + * @root: a #GskRenderNode + * @context: a #GdkDrawingContext * - * Renders the scene graph associated to @renderer, using the - * given target surface. + * Renders the scene graph, described by a tree of #GskRenderNode instances, + * using the given #GdkDrawingContext. + * + * The @renderer will acquire a reference on the #GskRenderNode tree while + * the rendering is in progress, and will make the tree immutable. * * Since: 3.22 */ void -gsk_renderer_render (GskRenderer *renderer) +gsk_renderer_render (GskRenderer *renderer, + GskRenderNode *root, + GdkDrawingContext *context) { GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); g_return_if_fail (GSK_IS_RENDERER (renderer)); g_return_if_fail (priv->is_realized); - g_return_if_fail (priv->root_node != NULL); + g_return_if_fail (GSK_IS_RENDER_NODE (root)); + g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context)); - /* We need to update the viewport and the modelview, to allow renderers - * to update their clip region and/or frustum; this allows them to cull - * render nodes in the tree validation phase - */ - gsk_renderer_maybe_resize_viewport (renderer); + g_set_object (&priv->root_node, root); + g_set_object (&priv->drawing_context, context); - gsk_renderer_maybe_update (renderer); + gsk_render_node_make_immutable (root); - gsk_renderer_maybe_validate_tree (renderer); + GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root, context); - /* Clear the output surface */ - gsk_renderer_maybe_clear (renderer); - - GSK_RENDERER_GET_CLASS (renderer)->render (renderer); + g_clear_object (&priv->root_node); + g_clear_object (&priv->drawing_context); } /** @@ -1345,7 +1050,7 @@ gsk_renderer_get_use_alpha (GskRenderer *renderer) * * Creates an appropriate #GskRenderer instance for the given @display. * - * Returns: (transfer full): a #GskRenderer + * Returns: (transfer full) (nullable): a #GskRenderer * * Since: 3.22 */ @@ -1364,10 +1069,7 @@ gsk_renderer_get_for_display (GdkDisplay *display) } if (use_software[0] != '0') - { - renderer_type = GSK_TYPE_CAIRO_RENDERER; - goto out; - } + return NULL; #ifdef GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (display)) @@ -1377,9 +1079,9 @@ gsk_renderer_get_for_display (GdkDisplay *display) #ifdef GDK_WINDOWING_WAYLAND if (GDK_IS_WAYLAND_DISPLAY (display)) renderer_type = GSK_TYPE_GL_RENDERER; - else #endif - renderer_type = GSK_TYPE_CAIRO_RENDERER; + else + return NULL; GSK_NOTE (RENDERER, g_print ("Creating renderer of type '%s' for display '%s'\n", g_type_name (renderer_type), @@ -1387,6 +1089,5 @@ gsk_renderer_get_for_display (GdkDisplay *display) g_assert (renderer_type != G_TYPE_INVALID); -out: return g_object_new (renderer_type, "display", display, NULL); } diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h index a18ab9b19a..ec1d3aacc2 100644 --- a/gsk/gskrenderer.h +++ b/gsk/gskrenderer.h @@ -69,44 +69,37 @@ void gsk_renderer_get_scaling_filters (GskRenderer GskScalingFilter *min_filter, GskScalingFilter *mag_filter); GDK_AVAILABLE_IN_3_22 +void gsk_renderer_set_scale_factor (GskRenderer *renderer, + int scale_factor); +GDK_AVAILABLE_IN_3_22 +int gsk_renderer_get_scale_factor (GskRenderer *renderer); +GDK_AVAILABLE_IN_3_22 void gsk_renderer_set_auto_clear (GskRenderer *renderer, gboolean clear); GDK_AVAILABLE_IN_3_22 gboolean gsk_renderer_get_auto_clear (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 -void gsk_renderer_set_root_node (GskRenderer *renderer, - GskRenderNode *root); +void gsk_renderer_set_use_alpha (GskRenderer *renderer, + gboolean use_alpha); GDK_AVAILABLE_IN_3_22 -GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer); -GDK_AVAILABLE_IN_3_22 -void gsk_renderer_set_surface (GskRenderer *renderer, - cairo_surface_t *surface); -GDK_AVAILABLE_IN_3_22 -cairo_surface_t * gsk_renderer_get_surface (GskRenderer *renderer); +gboolean gsk_renderer_get_use_alpha (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 void gsk_renderer_set_window (GskRenderer *renderer, GdkWindow *window); GDK_AVAILABLE_IN_3_22 GdkWindow * gsk_renderer_get_window (GskRenderer *renderer); -GDK_AVAILABLE_IN_3_22 -void gsk_renderer_set_draw_context (GskRenderer *renderer, - cairo_t *cr); -GDK_AVAILABLE_IN_3_22 -cairo_t * gsk_renderer_get_draw_context (GskRenderer *renderer); + GDK_AVAILABLE_IN_3_22 GdkDisplay * gsk_renderer_get_display (GskRenderer *renderer); -GDK_AVAILABLE_IN_3_22 -void gsk_renderer_set_use_alpha (GskRenderer *renderer, - gboolean use_alpha); -GDK_AVAILABLE_IN_3_22 -gboolean gsk_renderer_get_use_alpha (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 gboolean gsk_renderer_realize (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 void gsk_renderer_unrealize (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 -void gsk_renderer_render (GskRenderer *renderer); +void gsk_renderer_render (GskRenderer *renderer, + GskRenderNode *root, + GdkDrawingContext *context); G_END_DECLS diff --git a/gsk/gskrendererprivate.h b/gsk/gskrendererprivate.h index 2237c86ed1..81037193d4 100644 --- a/gsk/gskrendererprivate.h +++ b/gsk/gskrendererprivate.h @@ -39,28 +39,15 @@ struct _GskRendererClass gboolean (* realize) (GskRenderer *renderer); void (* unrealize) (GskRenderer *renderer); - void (* resize_viewport) (GskRenderer *renderer, - const graphene_rect_t *viewport); - void (* update) (GskRenderer *renderer, - const graphene_matrix_t *modelview, - const graphene_matrix_t *projection); - void (* validate_tree) (GskRenderer *renderer, - GskRenderNode *root); - void (* clear_tree) (GskRenderer *renderer, - GskRenderNode *old_root); - void (* clear) (GskRenderer *renderer); - void (* render) (GskRenderer *renderer); + void (* render) (GskRenderer *renderer, + GskRenderNode *root, + GdkDrawingContext *context); }; gboolean gsk_renderer_is_realized (GskRenderer *renderer); -void gsk_renderer_clear_tree (GskRenderer *renderer, - GskRenderNode *old_root); - -void gsk_renderer_maybe_resize_viewport (GskRenderer *renderer); -void gsk_renderer_maybe_update (GskRenderer *renderer); -void gsk_renderer_maybe_validate_tree (GskRenderer *renderer); -void gsk_renderer_maybe_clear (GskRenderer *renderer); +GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer); +GdkDrawingContext * gsk_renderer_get_drawing_context (GskRenderer *renderer); G_END_DECLS diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 092b96a2e3..95feb24147 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -41,8 +41,6 @@ gsk_render_node_dispose (GObject *gobject) GskRenderNode *self = GSK_RENDER_NODE (gobject); GskRenderNodeIter iter; - gsk_render_node_set_invalidate_func (self, NULL, NULL, NULL); - gsk_render_node_iter_init (&iter, self); while (gsk_render_node_iter_next (&iter, NULL)) gsk_render_node_iter_remove (&iter); @@ -50,19 +48,12 @@ gsk_render_node_dispose (GObject *gobject) G_OBJECT_CLASS (gsk_render_node_parent_class)->dispose (gobject); } -static void -gsk_render_node_real_resize (GskRenderNode *node) -{ -} - static void gsk_render_node_class_init (GskRenderNodeClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->dispose = gsk_render_node_dispose; - - klass->resize = gsk_render_node_real_resize; } static void @@ -74,6 +65,8 @@ gsk_render_node_init (GskRenderNode *self) graphene_matrix_init_identity (&self->child_transform); self->opacity = 1.0; + + self->is_mutable = TRUE; } /** @@ -204,6 +197,13 @@ gsk_render_node_insert_child_internal (GskRenderNode *node, return; } + if (!node->is_mutable) + { + g_critical ("The render node of type '%s' is immutable.", + G_OBJECT_TYPE_NAME (node)); + return; + } + insert_func (node, child, insert_func_data); g_object_ref (child); @@ -216,21 +216,6 @@ gsk_render_node_insert_child_internal (GskRenderNode *node, node->age += 1; node->needs_world_matrix_update = TRUE; - /* Transfer invalidated children to the current top-level */ - if (child->invalidated_descendants != NULL) - { - if (node->parent == NULL) - node->invalidated_descendants = child->invalidated_descendants; - else - { - GskRenderNode *tmp = gsk_render_node_get_toplevel (node); - - tmp->invalidated_descendants = child->invalidated_descendants; - } - - child->invalidated_descendants = NULL; - } - if (child->prev_sibling == NULL) node->first_child = child; if (child->next_sibling == NULL) @@ -296,6 +281,62 @@ insert_child_at_pos (GskRenderNode *node, } } +/** + * gsk_render_node_append_child: + * @node: a #GskRenderNode + * @child: a #GskRenderNode + * + * Appends @child to the list of children of @node. + * + * This function acquires a reference on @child. + * + * Returns: (transfer none): the #GskRenderNode + * + * Since: 3.22 + */ +GskRenderNode * +gsk_render_node_append_child (GskRenderNode *node, + GskRenderNode *child) +{ + g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); + g_return_val_if_fail (node->is_mutable, node); + + gsk_render_node_insert_child_internal (node, child, + insert_child_at_pos, + GINT_TO_POINTER (node->n_children)); + + return node; +} + +/** + * gsk_render_node_prepend_child: + * @node: a #GskRenderNode + * @child: a #GskRenderNode + * + * Prepends @child to the list of children of @node. + * + * This function acquires a reference on @child. + * + * Returns: (transfer none): the #GskRenderNode + * + * Since: 3.22 + */ +GskRenderNode * +gsk_render_node_prepend_child (GskRenderNode *node, + GskRenderNode *child) +{ + g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); + g_return_val_if_fail (node->is_mutable, node); + + gsk_render_node_insert_child_internal (node, child, + insert_child_at_pos, + GINT_TO_POINTER (0)); + + return node; +} + /** * gsk_render_node_insert_child_at_pos: * @node: a #GskRenderNode @@ -322,6 +363,7 @@ gsk_render_node_insert_child_at_pos (GskRenderNode *node, { g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); + g_return_val_if_fail (node->is_mutable, node); gsk_render_node_insert_child_internal (node, child, insert_child_at_pos, @@ -382,6 +424,7 @@ gsk_render_node_insert_child_before (GskRenderNode *node, g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); g_return_val_if_fail (sibling == NULL || GSK_IS_RENDER_NODE (sibling), node); + g_return_val_if_fail (node->is_mutable, node); gsk_render_node_insert_child_internal (node, child, insert_child_before, sibling); @@ -440,6 +483,7 @@ gsk_render_node_insert_child_after (GskRenderNode *node, g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); g_return_val_if_fail (sibling == NULL || GSK_IS_RENDER_NODE (sibling), node); + g_return_val_if_fail (node->is_mutable, node); if (sibling != NULL) g_return_val_if_fail (sibling->parent == node, node); @@ -500,6 +544,8 @@ gsk_render_node_replace_child (GskRenderNode *node, g_return_val_if_fail (new_child->parent == NULL, node); g_return_val_if_fail (old_child->parent == node, node); + g_return_val_if_fail (node->is_mutable, node); + clos.prev_sibling = old_child->prev_sibling; clos.next_sibling = old_child->next_sibling; gsk_render_node_remove_child (node, old_child); @@ -529,6 +575,7 @@ gsk_render_node_remove_child (GskRenderNode *node, g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); g_return_val_if_fail (GSK_IS_RENDER_NODE (child), node); + g_return_val_if_fail (node->is_mutable, node); if (child->parent != node) { @@ -582,6 +629,7 @@ gsk_render_node_remove_all_children (GskRenderNode *node) GskRenderNodeIter iter; g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); + g_return_val_if_fail (node->is_mutable, node); if (node->n_children == 0) return node; @@ -631,13 +679,12 @@ gsk_render_node_set_bounds (GskRenderNode *node, const graphene_rect_t *bounds) { g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); if (bounds == NULL) graphene_rect_init_from_rect (&node->bounds, graphene_rect_zero ()); else graphene_rect_init_from_rect (&node->bounds, bounds); - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_BOUNDS); } /** @@ -673,6 +720,7 @@ gsk_render_node_set_transform (GskRenderNode *node, const graphene_matrix_t *transform) { g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); if (transform == NULL) graphene_matrix_init_identity (&node->transform); @@ -680,7 +728,6 @@ gsk_render_node_set_transform (GskRenderNode *node, graphene_matrix_init_from_matrix (&node->transform, transform); node->transform_set = !graphene_matrix_is_identity (&node->transform); - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM); } /** @@ -697,10 +744,8 @@ void gsk_render_node_set_child_transform (GskRenderNode *node, const graphene_matrix_t *transform) { - GskRenderNodeIter iter; - GskRenderNode *child; - g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); if (transform == NULL) graphene_matrix_init_identity (&node->child_transform); @@ -708,11 +753,6 @@ gsk_render_node_set_child_transform (GskRenderNode *node, graphene_matrix_init_from_matrix (&node->child_transform, transform); node->child_transform_set = !graphene_matrix_is_identity (&node->child_transform); - - /* We need to invalidate the world matrix for our children */ - gsk_render_node_iter_init (&iter, node); - while (gsk_render_node_iter_next (&iter, &child)) - gsk_render_node_queue_invalidate (child, GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM); } /** @@ -730,10 +770,9 @@ gsk_render_node_set_opacity (GskRenderNode *node, double opacity) { g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); node->opacity = CLAMP (opacity, 0.0, 1.0); - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY); } /** @@ -770,10 +809,9 @@ gsk_render_node_set_hidden (GskRenderNode *node, gboolean hidden) { g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); node->hidden = !!hidden; - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_VISIBILITY); } /** @@ -813,10 +851,9 @@ gsk_render_node_set_opaque (GskRenderNode *node, gboolean opaque) { g_return_if_fail (GSK_IS_RENDER_NODE (node)); + g_return_if_fail (node->is_mutable); node->opaque = !!opaque; - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY); } /** @@ -865,31 +902,6 @@ gsk_render_node_contains (GskRenderNode *node, return FALSE; } -/** - * gsk_render_node_set_surface: - * @node: a #GskRenderNode - * @surface: (nullable): a Cairo surface - * - * Sets the contents of the #GskRenderNode. - * - * The @node will acquire a reference on the given @surface. - * - * Since: 3.22 - */ -void -gsk_render_node_set_surface (GskRenderNode *node, - cairo_surface_t *surface) -{ - g_return_if_fail (GSK_IS_RENDER_NODE (node)); - - g_clear_pointer (&node->surface, cairo_surface_destroy); - - if (surface != NULL) - node->surface = cairo_surface_reference (surface); - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_SURFACE); -} - /*< private > * gsk_render_node_get_toplevel: * @node: a #GskRenderNode @@ -1014,168 +1026,6 @@ gsk_render_node_get_world_matrix (GskRenderNode *node, *mv = node->world_matrix; } -void -gsk_render_node_set_invalidate_func (GskRenderNode *node, - GskRenderNodeInvalidateFunc invalidate_func, - gpointer func_data, - GDestroyNotify destroy_func_data) -{ - if (node->parent != NULL) - { - g_critical ("Render node of type '%s' is not a root node. Only root " - "nodes can have an invalidation function.", - G_OBJECT_TYPE_NAME (node)); - return; - } - - if (node->invalidate_func != NULL) - { - if (node->destroy_func_data != NULL) - node->destroy_func_data (node->func_data); - } - - node->invalidate_func = invalidate_func; - node->func_data = func_data; - node->destroy_func_data = destroy_func_data; -} - -GskRenderNodeChanges -gsk_render_node_get_current_state (GskRenderNode *node) -{ - GskRenderNodeChanges res = 0; - - if (node->needs_resize) - res |= GSK_RENDER_NODE_CHANGES_UPDATE_BOUNDS; - if (node->needs_world_matrix_update) - res |= GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM; - if (node->needs_content_update) - res |= GSK_RENDER_NODE_CHANGES_UPDATE_SURFACE; - if (node->needs_opacity_update) - res |= GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY; - if (node->needs_visibility_update) - res |= GSK_RENDER_NODE_CHANGES_UPDATE_VISIBILITY; - - return res; -} - -GskRenderNodeChanges -gsk_render_node_get_last_state (GskRenderNode *node) -{ - return node->last_state_change; -} - -void -gsk_render_node_queue_invalidate (GskRenderNode *node, - GskRenderNodeChanges changes) -{ - GskRenderNodeChanges cur_invalidated_bits = 0; - GskRenderNode *root; - int i; - - cur_invalidated_bits = gsk_render_node_get_current_state (node); - if ((cur_invalidated_bits & changes) != 0) - return; - - node->needs_resize = (changes & GSK_RENDER_NODE_CHANGES_UPDATE_BOUNDS) != 0; - node->needs_world_matrix_update = (changes & GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM) != 0; - node->needs_content_update = (changes & GSK_RENDER_NODE_CHANGES_UPDATE_SURFACE) != 0; - node->needs_opacity_update = (changes & GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY) != 0; - node->needs_visibility_update = (changes & GSK_RENDER_NODE_CHANGES_UPDATE_VISIBILITY) != 0; - - if (node->parent == NULL) - { - GSK_NOTE (RENDER_NODE, g_print ("Invalid node [%p] is top-level\n", node)); - return; - } - - root = gsk_render_node_get_toplevel (node); - - if (root->invalidated_descendants == NULL) - root->invalidated_descendants = g_ptr_array_new (); - - for (i = 0; i < root->invalidated_descendants->len; i++) - { - if (node == g_ptr_array_index (root->invalidated_descendants, i)) - { - GSK_NOTE (RENDER_NODE, g_print ("Node [%p] already invalidated; skipping...\n", node)); - return; - } - } - - GSK_NOTE (RENDER_NODE, g_print ("Adding node [%p] to list of invalid descendants of [%p]\n", node, root)); - g_ptr_array_add (root->invalidated_descendants, node); -} - -void -gsk_render_node_validate (GskRenderNode *node) -{ - GPtrArray *invalidated_descendants; - gboolean call_invalidate_func; - int i; - - node->last_state_change = gsk_render_node_get_current_state (node); - - /* We call the invalidation function if our state changed, or if - * the descendants state has changed - */ - call_invalidate_func = node->last_state_change != 0 || - node->invalidated_descendants != NULL; - - gsk_render_node_maybe_resize (node); - gsk_render_node_update_world_matrix (node, FALSE); - node->needs_content_update = FALSE; - node->needs_visibility_update = FALSE; - node->needs_opacity_update = FALSE; - - /* Steal the array of invalidated descendants, so that changes caused by - * the validation will not cause recursions - */ - invalidated_descendants = node->invalidated_descendants; - node->invalidated_descendants = NULL; - - if (invalidated_descendants != NULL) - { - for (i = 0; i < invalidated_descendants->len; i++) - { - GskRenderNode *child = g_ptr_array_index (invalidated_descendants, i); - - child->last_state_change = 0; - - GSK_NOTE (RENDER_NODE, g_print ("Validating descendant node [%p] (resize:%s, transform:%s)\n", - child, - child->needs_resize ? "yes" : "no", - child->needs_world_matrix_update ? "yes" : "no")); - - child->last_state_change = gsk_render_node_get_current_state (child); - - gsk_render_node_maybe_resize (child); - gsk_render_node_update_world_matrix (child, FALSE); - - child->needs_content_update = FALSE; - child->needs_visibility_update = FALSE; - child->needs_opacity_update = FALSE; - } - } - - g_clear_pointer (&invalidated_descendants, g_ptr_array_unref); - - if (call_invalidate_func && node->invalidate_func != NULL) - node->invalidate_func (node, node->func_data); -} - -void -gsk_render_node_maybe_resize (GskRenderNode *node) -{ - g_return_if_fail (GSK_IS_RENDER_NODE (node)); - - if (!node->needs_resize) - return; - - GSK_RENDER_NODE_GET_CLASS (node)->resize (node); - - node->needs_resize = FALSE; -} - /** * gsk_render_node_set_name: * @node: a #GskRenderNode @@ -1197,23 +1047,12 @@ gsk_render_node_set_name (GskRenderNode *node, node->name = g_strdup (name); } -static cairo_user_data_key_t render_node_context_key; - -static void -surface_invalidate (void *data) -{ - GskRenderNode *node = data; - - gsk_render_node_queue_invalidate (node, GSK_RENDER_NODE_CHANGES_UPDATE_SURFACE); -} - /** * gsk_render_node_get_draw_context: * @node: a #GskRenderNode * * Creates a Cairo context for drawing using the surface associated - * to the render node. If no surface has been attached to the render - * node, a new surface will be created as a side effect. + * to the render node. * * Returns: (transfer full): a Cairo context used for drawing; use * cairo_destroy() when done drawing @@ -1226,6 +1065,7 @@ gsk_render_node_get_draw_context (GskRenderNode *node) cairo_t *res; g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); + g_return_val_if_fail (node->is_mutable, NULL); if (node->surface == NULL) node->surface = cairo_image_surface_create (node->opaque ? CAIRO_FORMAT_RGB24 @@ -1240,7 +1080,21 @@ gsk_render_node_get_draw_context (GskRenderNode *node) node->bounds.size.width, node->bounds.size.height); cairo_clip (res); - cairo_set_user_data (res, &render_node_context_key, node, surface_invalidate); - return res; } + +void +gsk_render_node_make_immutable (GskRenderNode *node) +{ + GskRenderNodeIter iter; + GskRenderNode *child; + + if (!node->is_mutable) + return; + + node->is_mutable = FALSE; + + gsk_render_node_iter_init (&iter, node); + while (gsk_render_node_iter_next (&iter, &child)) + gsk_render_node_make_immutable (child); +} diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index f729c274f0..18e56f728b 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -52,6 +52,12 @@ GskRenderNode * gsk_render_node_get_next_sibling (GskRenderNode * GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_render_node_get_previous_sibling (GskRenderNode *node); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_render_node_append_child (GskRenderNode *node, + GskRenderNode *child); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_render_node_prepend_child (GskRenderNode *node, + GskRenderNode *child); GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_render_node_insert_child_at_pos (GskRenderNode *node, GskRenderNode *child, @@ -103,9 +109,6 @@ void gsk_render_node_set_opaque (GskRenderNode * GDK_AVAILABLE_IN_3_22 gboolean gsk_render_node_is_opaque (GskRenderNode *node); GDK_AVAILABLE_IN_3_22 -void gsk_render_node_set_surface (GskRenderNode *node, - cairo_surface_t *surface); -GDK_AVAILABLE_IN_3_22 cairo_t * gsk_render_node_get_draw_context (GskRenderNode *node); GDK_AVAILABLE_IN_3_22 diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 72373d8e68..9e9188fe8b 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -10,18 +10,6 @@ G_BEGIN_DECLS #define GSK_IS_RENDER_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RENDER_NODE)) #define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass)) -typedef enum { - GSK_RENDER_NODE_CHANGES_UPDATE_BOUNDS = 1 << 0, - GSK_RENDER_NODE_CHANGES_UPDATE_TRANSFORM = 1 << 1, - GSK_RENDER_NODE_CHANGES_UPDATE_SURFACE = 1 << 2, - GSK_RENDER_NODE_CHANGES_UPDATE_OPACITY = 1 << 3, - GSK_RENDER_NODE_CHANGES_UPDATE_VISIBILITY = 1 << 4, - GSK_RENDER_NODE_CHANEGS_UPDATE_HIERARCHY = 1 << 5 -} GskRenderNodeChanges; - -typedef void (* GskRenderNodeInvalidateFunc) (GskRenderNode *node, - gpointer data); - struct _GskRenderNode { GObject parent_instance; @@ -59,35 +47,22 @@ struct _GskRenderNode /* Transformations applied to the children of the node */ graphene_matrix_t child_transform; - /* Invalidation function for root node */ - GskRenderNodeInvalidateFunc invalidate_func; - gpointer func_data; - GDestroyNotify destroy_func_data; - - /* Descendants that need to be validated; only for root node */ - GPtrArray *invalidated_descendants; - - GskRenderNodeChanges last_state_change; - /* Bit fields; leave at the end */ + gboolean is_mutable : 1; gboolean hidden : 1; gboolean opaque : 1; gboolean transform_set : 1; gboolean child_transform_set : 1; - gboolean needs_resize : 1; gboolean needs_world_matrix_update : 1; - gboolean needs_content_update : 1; - gboolean needs_opacity_update : 1; - gboolean needs_visibility_update : 1; }; struct _GskRenderNodeClass { GObjectClass parent_class; - - void (* resize) (GskRenderNode *node); }; +void gsk_render_node_make_immutable (GskRenderNode *node); + void gsk_render_node_get_bounds (GskRenderNode *node, graphene_rect_t *frame); void gsk_render_node_get_transform (GskRenderNode *node, @@ -104,21 +79,6 @@ void gsk_render_node_update_world_matrix (GskRenderNode *node, void gsk_render_node_get_world_matrix (GskRenderNode *node, graphene_matrix_t *mv); -void gsk_render_node_queue_invalidate (GskRenderNode *node, - GskRenderNodeChanges changes); - -void gsk_render_node_set_invalidate_func (GskRenderNode *root, - GskRenderNodeInvalidateFunc validate_func, - gpointer data, - GDestroyNotify notify); - -void gsk_render_node_validate (GskRenderNode *node); - -void gsk_render_node_maybe_resize (GskRenderNode *node); - -GskRenderNodeChanges gsk_render_node_get_current_state (GskRenderNode *node); -GskRenderNodeChanges gsk_render_node_get_last_state (GskRenderNode *node); - G_END_DECLS #endif /* __GSK_RENDER_NODE_PRIVATE_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 651af12b34..b10615e826 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -163,7 +163,6 @@ noinst_PROGRAMS = $(TEST_PROGS) \ testpopup \ testpopupat \ testgaction \ - testgskrenderer \ $(NULL) if USE_X11 @@ -281,7 +280,6 @@ testtitlebar_DEPENDENCIES = $(TEST_DEPS) testwindowsize_DEPENDENCIES = $(TEST_DEPS) listmodel_DEPENDENCIES = $(TEST_DEPS) foreigndrawing_DEPENDENCIES = $(TEST_DEPS) -testgskrenderer_DEPENDENCIES = $(TEST_DEPS) animated_resizing_SOURCES = \ animated-resizing.c \ @@ -490,8 +488,6 @@ listmodel_SOURCES = listmodel.c foreigndrawing_SOURCES = foreigndrawing.c -testgskrenderer_SOURCES = testgskrenderer.c - EXTRA_DIST += \ gradient1.png \ testgtk.1 \ diff --git a/tests/testgskrenderer.c b/tests/testgskrenderer.c deleted file mode 100644 index a7a9eeb051..0000000000 --- a/tests/testgskrenderer.c +++ /dev/null @@ -1,229 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include - -#define BOX_SIZE 50.f -#define PADDING 10.f -#define ROOT_SIZE BOX_SIZE * 2 + PADDING * 2 - -static void -create_color_surface (cairo_t *cr, GdkRGBA *color, int w, int h) -{ - cairo_set_source_rgba (cr, color->red, color->green, color->blue, color->alpha); - cairo_rectangle (cr, 0, 0, w, h); - cairo_fill (cr); -} - -static GskRenderer * -get_renderer (GtkWidget *widget) -{ - GskRenderer *res; - - res = g_object_get_data (G_OBJECT (widget), "-gsk-renderer"); - if (res == NULL) - { - res = gsk_renderer_get_for_display (gtk_widget_get_display (widget)); - - g_object_set_data_full (G_OBJECT (widget), "-gsk-renderer", - res, - (GDestroyNotify) g_object_unref); - } - - return res; -} - -static void -create_scene (GskRenderer *renderer) -{ - GskRenderNode *root, *node; - graphene_matrix_t ctm; - cairo_t *cr; - - root = gsk_render_node_new (); - gsk_render_node_set_name (root, "Root node"); - gsk_render_node_set_bounds (root, &(graphene_rect_t) { - .origin.x = 0.f, - .origin.y = 0.f, - .size.width = ROOT_SIZE, - .size.height = ROOT_SIZE - }); - cr = gsk_render_node_get_draw_context (root); - create_color_surface (cr, &(GdkRGBA) { .red = 1, .green = 0, .blue = 0, .alpha = 1 }, ROOT_SIZE, ROOT_SIZE); - cairo_destroy (cr); - gsk_renderer_set_root_node (renderer, root); - g_object_set_data (G_OBJECT (renderer), "-gsk-renderer-root-node", root); - - g_object_unref (root); - - node = gsk_render_node_new (); - gsk_render_node_set_name (node, "Green node"); - gsk_render_node_set_bounds (node, &(graphene_rect_t) { - .origin.x = 0.f, - .origin.y = 0.f, - .size.width = BOX_SIZE, - .size.height = BOX_SIZE - }); - cr = gsk_render_node_get_draw_context (node); - create_color_surface (cr, &(GdkRGBA) { .red = 0, .green = 1, .blue = 0, .alpha = 1 }, BOX_SIZE, BOX_SIZE); - cairo_destroy (cr); - graphene_matrix_init_translate (&ctm, &(graphene_point3d_t) { .x = -0.5, .y = -0.5, .z = 0.f }); - gsk_render_node_set_transform (node, &ctm); - gsk_render_node_insert_child_at_pos (root, node, 0); - g_object_unref (node); - - node = gsk_render_node_new (); - gsk_render_node_set_name (node, "Blue node"); - gsk_render_node_set_bounds (node, &(graphene_rect_t) { - .origin.x = 0.f, - .origin.y = 0.f, - .size.width = BOX_SIZE, - .size.height = BOX_SIZE - }); - cr = gsk_render_node_get_draw_context (node); - create_color_surface (cr, &(GdkRGBA) { .red = 0, .green = 0, .blue = 1, .alpha = 1 }, BOX_SIZE, BOX_SIZE); - cairo_destroy (cr); - graphene_matrix_init_translate (&ctm, &(graphene_point3d_t) { .x = 0.5, .y = 0.5, .z = 0.f }); - gsk_render_node_set_transform (node, &ctm); - gsk_render_node_insert_child_at_pos (root, node, 1); - g_object_unref (node); -} - -static void -realize (GtkWidget *widget) -{ - GskRenderer *renderer = get_renderer (widget); - - gsk_renderer_set_window (renderer, gtk_widget_get_window (widget)); - gsk_renderer_set_use_alpha (renderer, TRUE); - gsk_renderer_realize (renderer); - - create_scene (renderer); -} - -static void -unrealize (GtkWidget *widget) -{ - g_object_set_data (G_OBJECT (widget), "-gsk-renderer", NULL); -} - -static void -size_allocate (GtkWidget *widget, GtkAllocation *allocation) -{ - GskRenderer *renderer = get_renderer (widget); - GskRenderNode *root; - graphene_matrix_t ctm; - - gsk_renderer_set_viewport (renderer, &(graphene_rect_t) { - .origin.x = 0, - .origin.y = 0, - .size.width = allocation->width, - .size.height = allocation->height - }); - - graphene_matrix_init_translate (&ctm, &(graphene_point3d_t) { - allocation->x, - allocation->y, - 0.f - }); - gsk_renderer_set_modelview (renderer, &ctm); - - root = g_object_get_data (G_OBJECT (renderer), "-gsk-renderer-root-node"); - if (root == NULL) - { - create_scene (renderer); - root = g_object_get_data (G_OBJECT (renderer), "-gsk-renderer-root-node"); - } - - graphene_matrix_init_translate (&ctm, &(graphene_point3d_t) { - .x = 0, - .y = 0, - .z = 0 - }); - gsk_render_node_set_transform (root, &ctm); -} - -static gboolean -draw (GtkWidget *widget, cairo_t *cr) -{ - GskRenderer *renderer = get_renderer (widget); - - gsk_renderer_set_draw_context (renderer, cr); - gsk_renderer_render (renderer); - - return TRUE; -} - -static gboolean -fade_out (GtkWidget *widget, - GdkFrameClock *frame_clock, - gpointer data) -{ - static gint64 first_frame_time; - static gboolean flip = FALSE; - gint64 now = gdk_frame_clock_get_frame_time (frame_clock); - - if (first_frame_time == 0) - { - first_frame_time = now; - - return G_SOURCE_CONTINUE; - } - - double start = first_frame_time; - double end = first_frame_time + (double) 1000000; - double progress = (now - first_frame_time) / (end - start); - - if (flip) - progress = 1 - progress; - - if (progress < 0 || progress >= 1) - { - first_frame_time = now; - flip = !flip; - return G_SOURCE_CONTINUE; - } - - GskRenderer *renderer = get_renderer (widget); - GskRenderNode *root = gsk_renderer_get_root_node (renderer); - - gsk_render_node_set_opacity (root, 1.0 - progress); - - gtk_widget_queue_draw (widget); - - return G_SOURCE_CONTINUE; -} - - -int -main (int argc, char *argv[]) -{ - GtkWidget *window, *area; - - gtk_init (NULL, NULL); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size (GTK_WINDOW (window), 400, 400); - gtk_window_set_title (GTK_WINDOW (window), "GSK Renderer"); - g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); - - area = gtk_drawing_area_new (); - gtk_widget_set_hexpand (area, TRUE); - gtk_widget_set_vexpand (area, TRUE); - gtk_widget_set_has_window (GTK_WIDGET (area), FALSE); - gtk_widget_set_app_paintable (GTK_WIDGET (area), TRUE); - gtk_container_add (GTK_CONTAINER (window), area); - - g_signal_connect (area, "realize", G_CALLBACK (realize), NULL); - g_signal_connect (area, "unrealize", G_CALLBACK (unrealize), NULL); - g_signal_connect (area, "size-allocate", G_CALLBACK (size_allocate), NULL); - g_signal_connect (area, "draw", G_CALLBACK (draw), NULL); - - gtk_widget_add_tick_callback (area, fade_out, NULL, NULL); - - gtk_widget_show_all (window); - - gtk_main (); -}