diff options
author | Alexander Larsson <alexl@redhat.com> | 2019-03-29 09:09:54 +0100 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2019-03-29 14:30:13 +0100 |
commit | f1ba94843e81dcfab39b61fa23d8818d4790352f (patch) | |
tree | 98606308d1f005128c4a5403a44c6a46ef5a6e9d /gsk/broadway | |
parent | f932d35c9507a15ad89cbf2680531ed0c11a9b77 (diff) | |
download | gtk+-f1ba94843e81dcfab39b61fa23d8818d4790352f.tar.gz |
broadway: Move gsk files to a subdirectory
Diffstat (limited to 'gsk/broadway')
-rw-r--r-- | gsk/broadway/gskbroadwayrenderer.c | 830 | ||||
-rw-r--r-- | gsk/broadway/gskbroadwayrendererprivate.h | 24 |
2 files changed, 854 insertions, 0 deletions
diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c new file mode 100644 index 0000000000..dd30633aed --- /dev/null +++ b/gsk/broadway/gskbroadwayrenderer.c @@ -0,0 +1,830 @@ +#include "config.h" + +#include "gskbroadwayrendererprivate.h" +#include "broadway/gdkprivate-broadway.h" + +#include "gskdebugprivate.h" +#include "gsktransformprivate.h" +#include "gskrendererprivate.h" +#include "gskrendernodeprivate.h" +#include "gdk/gdktextureprivate.h" + +struct _GskBroadwayRenderer +{ + GskRenderer parent_instance; + GdkBroadwayDrawContext *draw_context; + guint32 next_node_id; + + /* Set during rendering */ + GArray *nodes; /* Owned by draw_contex */ + GPtrArray *node_textures; /* Owned by draw_contex */ + GHashTable *node_lookup; + + /* Kept from last frame */ + GHashTable *last_node_lookup; + GskRenderNode *last_root; /* Owning refs to the things in last_node_lookup */ +}; + +struct _GskBroadwayRendererClass +{ + GskRendererClass parent_class; +}; + +G_DEFINE_TYPE (GskBroadwayRenderer, gsk_broadway_renderer, GSK_TYPE_RENDERER) + +static gboolean +gsk_broadway_renderer_realize (GskRenderer *renderer, + GdkSurface *surface, + GError **error) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + + if (!GDK_IS_BROADWAY_SURFACE (surface)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Broadway renderer only works for broadway surfaces"); + return FALSE; + } + + self->draw_context = gdk_broadway_draw_context_context (surface); + + return TRUE; +} + +static void +gsk_broadway_renderer_unrealize (GskRenderer *renderer) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + g_clear_object (&self->draw_context); +} + +static GdkTexture * +gsk_broadway_renderer_render_texture (GskRenderer *renderer, + GskRenderNode *root, + const graphene_rect_t *viewport) +{ + GdkTexture *texture; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height)); + cr = cairo_create (surface); + + cairo_translate (cr, - viewport->origin.x, - viewport->origin.y); + + gsk_render_node_draw (root, cr); + + cairo_destroy (cr); + + texture = gdk_texture_new_for_surface (surface); + cairo_surface_destroy (surface); + + return texture; +} + +/* uint32 is sent in native endianness, and then converted to little endian in broadwayd when sending to browser */ +static void +add_uint32 (GArray *nodes, guint32 v) +{ + g_array_append_val (nodes, v); +} + +static void +add_float (GArray *nodes, float f) +{ + union { + float f; + guint32 i; + } u; + + u.f = f; + g_array_append_val (nodes, u.i); +} + +static guint32 +rgba_to_uint32 (const GdkRGBA *rgba) +{ + return + ((guint32)(0.5 + CLAMP (rgba->alpha, 0., 1.) * 255.) << 24) | + ((guint32)(0.5 + CLAMP (rgba->red, 0., 1.) * 255.) << 16) | + ((guint32)(0.5 + CLAMP (rgba->green, 0., 1.) * 255.) << 8) | + ((guint32)(0.5 + CLAMP (rgba->blue, 0., 1.) * 255.) << 0); +} + + +static void +add_rgba (GArray *nodes, const GdkRGBA *rgba) +{ + guint32 c = rgba_to_uint32 (rgba); + g_array_append_val (nodes, c); +} + +static void +add_xy (GArray *nodes, float x, float y, float offset_x, float offset_y) +{ + add_float (nodes, x - offset_x); + add_float (nodes, y - offset_y); +} + +static void +add_point (GArray *nodes, const graphene_point_t *point, float offset_x, float offset_y) +{ + add_xy (nodes, point->x, point->y, offset_x, offset_y); +} + +static void +add_size (GArray *nodes, const graphene_size_t *size) +{ + add_float (nodes, size->width); + add_float (nodes, size->height); +} + +static void +add_rect (GArray *nodes, const graphene_rect_t *rect, float offset_x, float offset_y) +{ + add_point (nodes, &rect->origin, offset_x, offset_y); + add_size (nodes, &rect->size); +} + +static void +add_rounded_rect (GArray *nodes, const GskRoundedRect *rrect, float offset_x, float offset_y) +{ + int i; + add_rect (nodes, &rrect->bounds, offset_x, offset_y); + for (i = 0; i < 4; i++) + add_size (nodes, &rrect->corner[i]); +} + +static void +add_matrix (GArray *nodes, graphene_matrix_t *matrix) +{ + float matrix_floats[16]; + int i; + + graphene_matrix_to_float (matrix, matrix_floats); + for (i = 0; i < 16; i++) + add_float (nodes, matrix_floats[i]); +} + +static void +add_color_stop (GArray *nodes, const GskColorStop *stop) +{ + add_float (nodes, stop->offset); + add_rgba (nodes, &stop->color); +} + +static void +add_string (GArray *nodes, const char *str) +{ + guint32 len = strlen(str); + guint32 v, c; + + add_uint32 (nodes, len); + + v = 0; + c = 0; + while (*str != 0) + { + v |= (*str++) << 8*c++; + if (c == 4) + { + add_uint32 (nodes, v); + v = 0; + c = 0; + } + } + + if (c != 0) + add_uint32 (nodes, v); +} + +static void +collect_reused_child_nodes (GskRenderer *renderer, + GskRenderNode *node); + +static void +collect_reused_node (GskRenderer *renderer, + GskRenderNode *node) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + guint32 old_id; + + if (self->last_node_lookup && + (old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0) + { + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id)); + collect_reused_child_nodes (renderer, node); + } +} + + +static void +collect_reused_child_nodes (GskRenderer *renderer, + GskRenderNode *node) +{ + guint i; + + switch (gsk_render_node_get_node_type (node)) + { + case GSK_NOT_A_RENDER_NODE: + g_assert_not_reached (); + return; + + /* Leaf nodes */ + + case GSK_TEXTURE_NODE: + case GSK_CAIRO_NODE: + case GSK_COLOR_NODE: + case GSK_BORDER_NODE: + case GSK_OUTSET_SHADOW_NODE: + case GSK_INSET_SHADOW_NODE: + case GSK_LINEAR_GRADIENT_NODE: + + /* Fallbacks (=> leaf for now */ + case GSK_COLOR_MATRIX_NODE: + case GSK_TEXT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + case GSK_REPEAT_NODE: + case GSK_BLEND_NODE: + case GSK_CROSS_FADE_NODE: + case GSK_BLUR_NODE: + + default: + + break; + + /* Bin nodes */ + + case GSK_SHADOW_NODE: + collect_reused_node (renderer, + gsk_shadow_node_get_child (node)); + break; + + case GSK_OPACITY_NODE: + collect_reused_node (renderer, + gsk_opacity_node_get_child (node)); + break; + + case GSK_ROUNDED_CLIP_NODE: + collect_reused_node (renderer, + gsk_rounded_clip_node_get_child (node)); + break; + + case GSK_CLIP_NODE: + collect_reused_node (renderer, + gsk_clip_node_get_child (node)); + break; + + case GSK_TRANSFORM_NODE: + collect_reused_node (renderer, + gsk_transform_node_get_child (node)); + break; + + case GSK_DEBUG_NODE: + collect_reused_node (renderer, + gsk_debug_node_get_child (node)); + break; + + /* Generic nodes */ + + case GSK_CONTAINER_NODE: + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + collect_reused_node (renderer, + gsk_container_node_get_child (node, i)); + break; + + break; /* Fallback */ + } +} + +static gboolean +add_new_node (GskRenderer *renderer, + GskRenderNode *node, + BroadwayNodeType type) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + guint32 id, old_id; + + if (self->last_node_lookup && + (old_id = GPOINTER_TO_INT (g_hash_table_lookup (self->last_node_lookup, node))) != 0) + { + add_uint32 (self->nodes, BROADWAY_NODE_REUSE); + add_uint32 (self->nodes, old_id); + + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(old_id)); + collect_reused_child_nodes (renderer, node); + + return FALSE; + } + + id = ++self->next_node_id; + g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id)); + + add_uint32 (self->nodes, type); + add_uint32 (self->nodes, id); + + return TRUE; +} + +typedef struct ColorizedTexture { + GdkTexture *texture; + graphene_matrix_t color_matrix; + graphene_vec4_t color_offset; +} ColorizedTexture; + +static void +colorized_texture_free (ColorizedTexture *colorized) +{ + g_object_unref (colorized->texture); + g_free (colorized); +} + +static ColorizedTexture * +colorized_texture_new (GdkTexture *texture, + const graphene_matrix_t *color_matrix, + const graphene_vec4_t *color_offset) +{ + ColorizedTexture *colorized = g_new0 (ColorizedTexture, 1); + colorized->texture = g_object_ref (texture); + colorized->color_matrix = *color_matrix; + colorized->color_offset = *color_offset; + return colorized; +} + +static void +colorized_texture_free_list (GList *list) +{ + g_list_free_full (list, (GDestroyNotify)colorized_texture_free); +} + + +static gboolean +matrix_equal (const graphene_matrix_t *a, + const graphene_matrix_t *b) +{ + for (int i = 0; i < 4; i ++) + { + graphene_vec4_t ra, rb; + graphene_matrix_get_row (a, i, &ra); + graphene_matrix_get_row (b, i, &rb); + if (!graphene_vec4_equal (&ra, &rb)) + return FALSE; + } + return TRUE; +} + +static GdkTexture * +get_colorized_texture (GdkTexture *texture, + const graphene_matrix_t *color_matrix, + const graphene_vec4_t *color_offset) +{ + cairo_surface_t *surface = gdk_texture_download_surface (texture); + cairo_surface_t *image_surface; + graphene_vec4_t pixel; + guint32* pixel_data; + guchar *data; + gsize x, y, width, height, stride; + float alpha; + GdkTexture *colorized_texture; + GList *colorized_list, *l; + ColorizedTexture *colorized; + + colorized_list = g_object_get_data (G_OBJECT (texture), "broadway-colorized"); + + for (l = colorized_list; l != NULL; l = l->next) + { + colorized = l->data; + + if (graphene_vec4_equal (&colorized->color_offset, color_offset) && + matrix_equal (&colorized->color_matrix, color_matrix)) + return g_object_ref (colorized->texture); + } + + image_surface = cairo_surface_map_to_image (surface, NULL); + data = cairo_image_surface_get_data (image_surface); + width = cairo_image_surface_get_width (image_surface); + height = cairo_image_surface_get_height (image_surface); + stride = cairo_image_surface_get_stride (image_surface); + + for (y = 0; y < height; y++) + { + pixel_data = (guint32 *) data; + for (x = 0; x < width; x++) + { + alpha = ((pixel_data[x] >> 24) & 0xFF) / 255.0; + + if (alpha == 0) + { + graphene_vec4_init (&pixel, 0.0, 0.0, 0.0, 0.0); + } + else + { + graphene_vec4_init (&pixel, + ((pixel_data[x] >> 16) & 0xFF) / (255.0 * alpha), + ((pixel_data[x] >> 8) & 0xFF) / (255.0 * alpha), + ( pixel_data[x] & 0xFF) / (255.0 * alpha), + alpha); + graphene_matrix_transform_vec4 (color_matrix, &pixel, &pixel); + } + + graphene_vec4_add (&pixel, color_offset, &pixel); + + alpha = graphene_vec4_get_w (&pixel); + if (alpha > 0.0) + { + alpha = MIN (alpha, 1.0); + pixel_data[x] = (((guint32) (alpha * 255)) << 24) | + (((guint32) (CLAMP (graphene_vec4_get_x (&pixel), 0, 1) * alpha * 255)) << 16) | + (((guint32) (CLAMP (graphene_vec4_get_y (&pixel), 0, 1) * alpha * 255)) << 8) | + ((guint32) (CLAMP (graphene_vec4_get_z (&pixel), 0, 1) * alpha * 255)); + } + else + { + pixel_data[x] = 0; + } + } + data += stride; + } + + cairo_surface_mark_dirty (image_surface); + cairo_surface_unmap_image (surface, image_surface); + + colorized_texture = gdk_texture_new_for_surface (surface); + + colorized = colorized_texture_new (colorized_texture, color_matrix, color_offset); + if (colorized_list) + colorized_list = g_list_append (colorized_list, colorized); + else + { + colorized_list = g_list_append (NULL, colorized); + g_object_set_data_full (G_OBJECT (texture), "broadway-colorized", + colorized_list, (GDestroyNotify)colorized_texture_free_list); + } + + return colorized_texture; +} + + +/* Note: This tracks the offset so that we can convert + the absolute coordinates of the GskRenderNodes to + parent-relative which is what the dom uses, and + which is good for re-using subtrees. */ +static void +gsk_broadway_renderer_add_node (GskRenderer *renderer, + GskRenderNode *node, + float offset_x, + float offset_y) +{ + GdkDisplay *display = gdk_surface_get_display (gsk_renderer_get_surface (renderer)); + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + GArray *nodes = self->nodes; + + switch (gsk_render_node_get_node_type (node)) + { + case GSK_NOT_A_RENDER_NODE: + g_assert_not_reached (); + return; + + /* Leaf nodes */ + + case GSK_TEXTURE_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + GdkTexture *texture = gsk_texture_node_get_texture (node); + guint32 texture_id; + + /* No need to add to self->node_textures here, the node will keep it alive until end of frame. */ + + texture_id = gdk_broadway_display_ensure_texture (display, texture); + + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_uint32 (nodes, texture_id); + } + return; + + case GSK_CAIRO_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + cairo_surface_t *surface = (cairo_surface_t *)gsk_cairo_node_peek_surface (node); + cairo_surface_t *image_surface = NULL; + GdkTexture *texture; + guint32 texture_id; + + if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) + image_surface = cairo_surface_reference (surface); + else + { + cairo_t *cr; + image_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ceilf (node->bounds.size.width), + ceilf (node->bounds.size.height)); + cr = cairo_create (image_surface); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_rectangle (cr, 0, 0, node->bounds.size.width, node->bounds.size.height); + cairo_fill (cr); + cairo_destroy (cr); + } + + texture = gdk_texture_new_for_surface (image_surface); + g_ptr_array_add (self->node_textures, g_object_ref (texture)); /* Transfers ownership to node_textures */ + texture_id = gdk_broadway_display_ensure_texture (display, texture); + + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_uint32 (nodes, texture_id); + + cairo_surface_destroy (image_surface); + } + return; + + case GSK_COLOR_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_COLOR)) + { + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_rgba (nodes, gsk_color_node_peek_color (node)); + } + return; + + case GSK_BORDER_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_BORDER)) + { + int i; + add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y); + for (i = 0; i < 4; i++) + add_float (nodes, gsk_border_node_peek_widths (node)[i]); + for (i = 0; i < 4; i++) + add_rgba (nodes, &gsk_border_node_peek_colors (node)[i]); + } + return; + + case GSK_OUTSET_SHADOW_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW)) + { + add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y); + add_rgba (nodes, gsk_outset_shadow_node_peek_color (node)); + add_float (nodes, gsk_outset_shadow_node_get_dx (node)); + add_float (nodes, gsk_outset_shadow_node_get_dy (node)); + add_float (nodes, gsk_outset_shadow_node_get_spread (node)); + add_float (nodes, gsk_outset_shadow_node_get_blur_radius (node)); + } + return; + + case GSK_INSET_SHADOW_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW)) + { + add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y); + add_rgba (nodes, gsk_inset_shadow_node_peek_color (node)); + add_float (nodes, gsk_inset_shadow_node_get_dx (node)); + add_float (nodes, gsk_inset_shadow_node_get_dy (node)); + add_float (nodes, gsk_inset_shadow_node_get_spread (node)); + add_float (nodes, gsk_inset_shadow_node_get_blur_radius (node)); + } + return; + + case GSK_LINEAR_GRADIENT_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT)) + { + guint i, n; + + add_rect (nodes, &node->bounds, offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_start (node), offset_x, offset_y); + add_point (nodes, gsk_linear_gradient_node_peek_end (node), offset_x, offset_y); + n = gsk_linear_gradient_node_get_n_color_stops (node); + add_uint32 (nodes, n); + for (i = 0; i < n; i++) + add_color_stop (nodes, &gsk_linear_gradient_node_peek_color_stops (node)[i]); + } + return; + + /* Bin nodes */ + + case GSK_SHADOW_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW)) + { + gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node); + + add_uint32 (nodes, n_shadows); + for (i = 0; i < n_shadows; i++) + { + const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); + add_rgba (nodes, &shadow->color); + add_float (nodes, shadow->dx); + add_float (nodes, shadow->dy); + add_float (nodes, shadow->radius); + } + gsk_broadway_renderer_add_node (renderer, + gsk_shadow_node_get_child (node), + offset_x, offset_y); + } + return; + + case GSK_OPACITY_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY)) + { + add_float (nodes, gsk_opacity_node_get_opacity (node)); + gsk_broadway_renderer_add_node (renderer, + gsk_opacity_node_get_child (node), + offset_x, offset_y); + } + return; + + case GSK_ROUNDED_CLIP_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP)) + { + const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node); + + add_rounded_rect (nodes, rclip, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, + gsk_rounded_clip_node_get_child (node), + rclip->bounds.origin.x, + rclip->bounds.origin.y); + } + return; + + case GSK_CLIP_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_CLIP)) + { + const graphene_rect_t *clip = gsk_clip_node_peek_clip (node); + + add_rect (nodes, clip, offset_x, offset_y); + gsk_broadway_renderer_add_node (renderer, + gsk_clip_node_get_child (node), + clip->origin.x, + clip->origin.y); + } + return; + + case GSK_TRANSFORM_NODE: + { + GskTransform *transform = gsk_transform_node_get_transform (node); + GskTransformCategory category = gsk_transform_get_category (transform); + + if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM)) { + if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE) + { + float dx, dy; + gsk_transform_to_translate (transform, &dx, &dy); + + add_uint32 (nodes, 0); // Translate + add_xy (nodes, dx, dy, 0, 0); + gsk_broadway_renderer_add_node (renderer, + gsk_transform_node_get_child (node), + 0, 0); + } + else + { + graphene_matrix_t matrix; + + gsk_transform_to_matrix (transform, &matrix); + add_uint32 (nodes, 1); // General transform + add_matrix (nodes, &matrix); + gsk_broadway_renderer_add_node (renderer, + gsk_transform_node_get_child (node), + 0, 0); + } + } + } + return; + + case GSK_DEBUG_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG)) + { + const char *message = gsk_debug_node_get_message (node); + add_string (nodes, message); + gsk_broadway_renderer_add_node (renderer, + gsk_debug_node_get_child (node), offset_x, offset_y); + } + return; + + /* Generic nodes */ + + case GSK_CONTAINER_NODE: + if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER)) + { + guint i; + + add_uint32 (nodes, gsk_container_node_get_n_children (node)); + for (i = 0; i < gsk_container_node_get_n_children (node); i++) + gsk_broadway_renderer_add_node (renderer, + gsk_container_node_get_child (node, i), offset_x, offset_y); + } + return; + + case GSK_COLOR_MATRIX_NODE: + { + GskRenderNode *child = gsk_color_matrix_node_get_child (node); + if (gsk_render_node_get_node_type (child) == GSK_TEXTURE_NODE) + { + const graphene_matrix_t *color_matrix = gsk_color_matrix_node_peek_color_matrix (node); + const graphene_vec4_t *color_offset = gsk_color_matrix_node_peek_color_offset (node); + GdkTexture *texture = gsk_texture_node_get_texture (child); + GdkTexture *colorized_texture = get_colorized_texture (texture, color_matrix, color_offset); + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + guint32 texture_id = gdk_broadway_display_ensure_texture (display, colorized_texture); + add_rect (nodes, &child->bounds, offset_x, offset_y); + add_uint32 (nodes, texture_id); + } + + return; + } + } + break; + + + case GSK_TEXT_NODE: + case GSK_REPEATING_LINEAR_GRADIENT_NODE: + case GSK_REPEAT_NODE: + case GSK_BLEND_NODE: + case GSK_CROSS_FADE_NODE: + case GSK_BLUR_NODE: + default: + break; /* Fallback */ + } + + if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE)) + { + GdkTexture *texture; + cairo_surface_t *surface; + cairo_t *cr; + guint32 texture_id; + int x = floorf (node->bounds.origin.x); + int y = floorf (node->bounds.origin.y); + int width = ceil (node->bounds.origin.x + node->bounds.size.width) - x; + int height = ceil (node->bounds.origin.y + node->bounds.size.height) - y; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surface); + cairo_translate (cr, -x, -y); + gsk_render_node_draw (node, cr); + cairo_destroy (cr); + + texture = gdk_texture_new_for_surface (surface); + g_ptr_array_add (self->node_textures, texture); /* Transfers ownership to node_textures */ + + texture_id = gdk_broadway_display_ensure_texture (display, texture); + add_float (nodes, x - offset_x); + add_float (nodes, y - offset_y); + add_float (nodes, gdk_texture_get_width (texture)); + add_float (nodes, gdk_texture_get_height (texture)); + add_uint32 (nodes, texture_id); + } +} + +static void +gsk_broadway_renderer_render (GskRenderer *renderer, + GskRenderNode *root, + const cairo_region_t *update_area) +{ + GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer); + + self->node_lookup = g_hash_table_new (g_direct_hash, g_direct_equal); + + gdk_draw_context_begin_frame (GDK_DRAW_CONTEXT (self->draw_context), update_area); + + /* These are owned by the draw context between begin and end, but + cache them here for easier access during the render */ + self->nodes = self->draw_context->nodes; + self->node_textures = self->draw_context->node_textures; + + gsk_broadway_renderer_add_node (renderer, root, 0, 0); + + self->nodes = NULL; + self->node_textures = NULL; + + gdk_draw_context_end_frame (GDK_DRAW_CONTEXT (self->draw_context)); + + if (self->last_node_lookup) + g_hash_table_unref (self->last_node_lookup); + self->last_node_lookup = self->node_lookup; + self->node_lookup = NULL; + + if (self->last_root) + gsk_render_node_unref (self->last_root); + self->last_root = gsk_render_node_ref (root); + + if (self->next_node_id > G_MAXUINT32 / 2) + { + /* We're "near" a wrap of the ids, lets avoid reusing any of + * these nodes next frame, then we can reset the id counter + * without risk of any old nodes sticking around and conflicting. */ + + g_hash_table_remove_all (self->last_node_lookup); + self->next_node_id = 0; + } +} + +static void +gsk_broadway_renderer_class_init (GskBroadwayRendererClass *klass) +{ + GskRendererClass *renderer_class = GSK_RENDERER_CLASS (klass); + + renderer_class->realize = gsk_broadway_renderer_realize; + renderer_class->unrealize = gsk_broadway_renderer_unrealize; + renderer_class->render = gsk_broadway_renderer_render; + renderer_class->render_texture = gsk_broadway_renderer_render_texture; +} + +static void +gsk_broadway_renderer_init (GskBroadwayRenderer *self) +{ +} diff --git a/gsk/broadway/gskbroadwayrendererprivate.h b/gsk/broadway/gskbroadwayrendererprivate.h new file mode 100644 index 0000000000..acc69f7117 --- /dev/null +++ b/gsk/broadway/gskbroadwayrendererprivate.h @@ -0,0 +1,24 @@ +#ifndef __GSK_BROADWAY_RENDERER_PRIVATE_H__ +#define __GSK_BROADWAY_RENDERER_PRIVATE_H__ + +#include "broadway/gdkbroadway.h" +#include <gsk/gskrenderer.h> + +G_BEGIN_DECLS + +#define GSK_TYPE_BROADWAY_RENDERER (gsk_broadway_renderer_get_type ()) + +#define GSK_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRenderer)) +#define GSK_IS_BROADWAY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_BROADWAY_RENDERER)) +#define GSK_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass)) +#define GSK_IS_BROADWAY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_BROADWAY_RENDERER)) +#define GSK_BROADWAY_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_BROADWAY_RENDERER, GskBroadwayRendererClass)) + +typedef struct _GskBroadwayRenderer GskBroadwayRenderer; +typedef struct _GskBroadwayRendererClass GskBroadwayRendererClass; + +GType gsk_broadway_renderer_get_type (void) G_GNUC_CONST; + +G_END_DECLS + +#endif /* __GSK_BROADWAY_RENDERER_PRIVATE_H__ */ |