lib: tweak cairo drawing a bit and fix invalidation

This commit is contained in:
Christian Hergert 2023-02-14 11:59:04 -08:00
parent 6beaf8b925
commit 441b7355ef
2 changed files with 57 additions and 29 deletions

View File

@ -66,10 +66,14 @@ struct _MksCairoFramebuffer
/* Number of bytes per-pixel */ /* Number of bytes per-pixel */
guint bpp; guint bpp;
/* The height and width of our cairo surface */ /* The height and width the framebuffer was created with */
guint height; guint height;
guint width; guint width;
/* The real width and height when tiling is taken into account */
guint real_height;
guint real_width;
/* The number of tiles horizontally and vertically */ /* The number of tiles horizontally and vertically */
guint n_columns; guint n_columns;
guint n_rows; guint n_rows;
@ -113,17 +117,12 @@ mks_cairo_framebuffer_snapshot (GdkPaintable *paintable,
double height) double height)
{ {
MksCairoFramebuffer *self = MKS_CAIRO_FRAMEBUFFER (paintable); MksCairoFramebuffer *self = MKS_CAIRO_FRAMEBUFFER (paintable);
static GdkRGBA black = {0,0,0,1};
gtk_snapshot_save (snapshot); gtk_snapshot_save (snapshot);
gtk_snapshot_scale (snapshot, gtk_snapshot_scale (snapshot,
width / (double)self->width, width / (double)self->width,
height / (double)self->height); height / (double)self->height);
gtk_snapshot_append_color (snapshot,
&black,
&GRAPHENE_RECT_INIT (0, 0, self->width, self->height));
for (guint row = 0; row < self->n_rows; row++) for (guint row = 0; row < self->n_rows; row++)
{ {
guint row_pos = row * self->n_columns; guint row_pos = row * self->n_columns;
@ -199,8 +198,6 @@ static void
mks_cairo_framebuffer_constructed (GObject *object) mks_cairo_framebuffer_constructed (GObject *object)
{ {
MksCairoFramebuffer *self = (MksCairoFramebuffer *)object; MksCairoFramebuffer *self = (MksCairoFramebuffer *)object;
guint real_width;
guint real_height;
G_OBJECT_CLASS (mks_cairo_framebuffer_parent_class)->constructed (object); G_OBJECT_CLASS (mks_cairo_framebuffer_parent_class)->constructed (object);
@ -228,37 +225,37 @@ mks_cairo_framebuffer_constructed (GObject *object)
return; return;
} }
real_width = self->width; self->real_width = self->width;
real_height = self->height; self->real_height = self->height;
realign (&real_width, TILE_WIDTH); realign (&self->real_width, TILE_WIDTH);
realign (&real_height, TILE_HEIGHT); realign (&self->real_height, TILE_HEIGHT);
g_assert (real_width % TILE_WIDTH == 0); g_assert (self->real_width % TILE_WIDTH == 0);
g_assert (real_height % TILE_HEIGHT == 0); g_assert (self->real_height % TILE_HEIGHT == 0);
self->surface = cairo_image_surface_create (self->format, real_width, real_height); self->surface = cairo_image_surface_create (self->format, self->real_width, self->real_height);
if (self->surface == NULL) if (self->surface == NULL)
{ {
g_warning ("Cairo surface creation failed: format=0x%x width=%u height=%u", g_warning ("Cairo surface creation failed: format=0x%x width=%u height=%u",
self->format, real_width, real_height); self->format, self->real_width, self->real_height);
return; return;
} }
self->stride = cairo_format_stride_for_width (self->format, real_width); self->stride = cairo_format_stride_for_width (self->format, self->real_width);
self->bpp = self->stride / real_width; self->bpp = self->stride / self->real_width;
/* Currently only 4bbp are supported */ /* Currently only 4bbp are supported */
g_assert (self->bpp == 4); g_assert (self->bpp == 4);
self->content = g_bytes_new_with_free_func (cairo_image_surface_get_data (self->surface), self->content = g_bytes_new_with_free_func (cairo_image_surface_get_data (self->surface),
self->stride * real_height, self->stride * self->real_height,
(GDestroyNotify) cairo_surface_destroy, (GDestroyNotify) cairo_surface_destroy,
cairo_surface_reference (self->surface)); cairo_surface_reference (self->surface));
self->n_columns = real_width / TILE_WIDTH; self->n_columns = self->real_width / TILE_WIDTH;
self->n_rows = real_height / TILE_HEIGHT; self->n_rows = self->real_height / TILE_HEIGHT;
self->tiles = g_ptr_array_new_full (self->n_columns * self->n_rows, texture_clear); self->tiles = g_ptr_array_new_full (self->n_columns * self->n_rows, texture_clear);
g_ptr_array_set_size (self->tiles, self->n_columns * self->n_rows); g_ptr_array_set_size (self->tiles, self->n_columns * self->n_rows);
@ -381,10 +378,11 @@ mks_cairo_framebuffer_new (cairo_format_t format,
} }
static void static void
invalidate_on_destroy (gpointer data) flush_and_invalidate_on_destroy (gpointer data)
{ {
g_autoptr(MksCairoFramebuffer) self = data; g_autoptr(MksCairoFramebuffer) self = data;
cairo_surface_flush (self->surface);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self)); gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
} }
@ -402,6 +400,9 @@ mks_cairo_framebuffer_update (MksCairoFramebuffer *self,
g_return_val_if_fail (MKS_IS_CAIRO_FRAMEBUFFER (self), NULL); g_return_val_if_fail (MKS_IS_CAIRO_FRAMEBUFFER (self), NULL);
g_return_val_if_fail (self->surface != NULL, NULL); g_return_val_if_fail (self->surface != NULL, NULL);
g_assert (self->n_columns > 0);
g_assert (self->n_rows > 0);
col1 = MIN (x / TILE_WIDTH, self->n_columns-1); col1 = MIN (x / TILE_WIDTH, self->n_columns-1);
col2 = MIN ((x + width) / TILE_WIDTH, self->n_columns-1); col2 = MIN ((x + width) / TILE_WIDTH, self->n_columns-1);
@ -410,7 +411,7 @@ mks_cairo_framebuffer_update (MksCairoFramebuffer *self,
for (guint row = row1; row <= row2; row++) for (guint row = row1; row <= row2; row++)
{ {
guint row_pos = row * self->n_rows; guint row_pos = row * self->n_columns;
for (guint col = col1; col <= col2; col++) for (guint col = col1; col <= col2; col++)
{ {
@ -423,13 +424,14 @@ mks_cairo_framebuffer_update (MksCairoFramebuffer *self,
} }
cr = cairo_create (self->surface); cr = cairo_create (self->surface);
cairo_rectangle (cr, x, y, width, height); cairo_translate (cr, x, y);
cairo_rectangle (cr, 0, 0, width, height);
cairo_clip (cr); cairo_clip (cr);
cairo_set_user_data (cr, cairo_set_user_data (cr,
&invalidate_key, &invalidate_key,
g_object_ref (self), g_object_ref (self),
invalidate_on_destroy); flush_and_invalidate_on_destroy);
return cr; return cr;
} }

View File

@ -159,6 +159,26 @@ mks_paintable_init (MksPaintable *self)
{ {
} }
static void
mks_paintable_invalidate_contents_cb (MksPaintable *self,
GdkPaintable *paintable)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (GDK_IS_PAINTABLE (paintable));
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
static void
mks_paintable_invalidate_size_cb (MksPaintable *self,
GdkPaintable *paintable)
{
g_assert (MKS_IS_PAINTABLE (self));
g_assert (GDK_IS_PAINTABLE (paintable));
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
}
static void static void
mks_paintable_set_framebuffer (MksPaintable *self, mks_paintable_set_framebuffer (MksPaintable *self,
MksCairoFramebuffer *framebuffer) MksCairoFramebuffer *framebuffer)
@ -193,12 +213,12 @@ mks_paintable_set_framebuffer (MksPaintable *self,
self->framebuffer = g_object_ref (framebuffer); self->framebuffer = g_object_ref (framebuffer);
g_signal_connect_object (self->framebuffer, g_signal_connect_object (self->framebuffer,
"invalidate-size", "invalidate-size",
G_CALLBACK (gdk_paintable_invalidate_size), G_CALLBACK (mks_paintable_invalidate_size_cb),
self, self,
G_CONNECT_SWAPPED); G_CONNECT_SWAPPED);
g_signal_connect_object (self->framebuffer, g_signal_connect_object (self->framebuffer,
"invalidate-contents", "invalidate-contents",
G_CALLBACK (gdk_paintable_invalidate_contents), G_CALLBACK (mks_paintable_invalidate_contents_cb),
self, self,
G_CONNECT_SWAPPED); G_CONNECT_SWAPPED);
self->mode = MODE_FRAMEBUFFER; self->mode = MODE_FRAMEBUFFER;
@ -267,6 +287,8 @@ mks_paintable_listener_update (MksPaintable *self,
guint8 *data; guint8 *data;
cairo_format_t format; cairo_format_t format;
gsize data_len; gsize data_len;
static int counter;
char name[32];
g_assert (MKS_IS_PAINTABLE (self)); g_assert (MKS_IS_PAINTABLE (self));
g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation)); g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
@ -319,10 +341,13 @@ mks_paintable_listener_update (MksPaintable *self,
} }
source = cairo_image_surface_create_for_data (data, format, width, height, stride); source = cairo_image_surface_create_for_data (data, format, width, height, stride);
g_snprintf (name, sizeof name, "update-%u.png", counter++ % 10);
cairo_surface_write_to_png (source, name);
cr = mks_cairo_framebuffer_update (self->framebuffer, x, y, width, height); cr = mks_cairo_framebuffer_update (self->framebuffer, x, y, width, height);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, source, 0, 0); cairo_set_source_surface (cr, source, 0, 0);
cairo_rectangle (cr, x, y, width, height); cairo_rectangle (cr, 0, 0, width, height);
cairo_paint (cr); cairo_fill (cr);
cairo_destroy (cr); cairo_destroy (cr);
cairo_surface_destroy (source); cairo_surface_destroy (source);
@ -385,6 +410,7 @@ mks_paintable_listener_scanout (MksPaintable *self,
source = cairo_image_surface_create_for_data (data, format, width, height, stride); source = cairo_image_surface_create_for_data (data, format, width, height, stride);
cr = mks_cairo_framebuffer_update (self->framebuffer, 0, 0, width, height); cr = mks_cairo_framebuffer_update (self->framebuffer, 0, 0, width, height);
cairo_set_source_surface (cr, source, 0, 0); cairo_set_source_surface (cr, source, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle (cr, 0, 0, width, height); cairo_rectangle (cr, 0, 0, width, height);
cairo_paint (cr); cairo_paint (cr);
cairo_destroy (cr); cairo_destroy (cr);