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 */
guint bpp;
/* The height and width of our cairo surface */
/* The height and width the framebuffer was created with */
guint height;
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 */
guint n_columns;
guint n_rows;
@ -113,17 +117,12 @@ mks_cairo_framebuffer_snapshot (GdkPaintable *paintable,
double height)
{
MksCairoFramebuffer *self = MKS_CAIRO_FRAMEBUFFER (paintable);
static GdkRGBA black = {0,0,0,1};
gtk_snapshot_save (snapshot);
gtk_snapshot_scale (snapshot,
width / (double)self->width,
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++)
{
guint row_pos = row * self->n_columns;
@ -199,8 +198,6 @@ static void
mks_cairo_framebuffer_constructed (GObject *object)
{
MksCairoFramebuffer *self = (MksCairoFramebuffer *)object;
guint real_width;
guint real_height;
G_OBJECT_CLASS (mks_cairo_framebuffer_parent_class)->constructed (object);
@ -228,37 +225,37 @@ mks_cairo_framebuffer_constructed (GObject *object)
return;
}
real_width = self->width;
real_height = self->height;
self->real_width = self->width;
self->real_height = self->height;
realign (&real_width, TILE_WIDTH);
realign (&real_height, TILE_HEIGHT);
realign (&self->real_width, TILE_WIDTH);
realign (&self->real_height, TILE_HEIGHT);
g_assert (real_width % TILE_WIDTH == 0);
g_assert (real_height % TILE_HEIGHT == 0);
g_assert (self->real_width % TILE_WIDTH == 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)
{
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;
}
self->stride = cairo_format_stride_for_width (self->format, real_width);
self->bpp = self->stride / real_width;
self->stride = cairo_format_stride_for_width (self->format, self->real_width);
self->bpp = self->stride / self->real_width;
/* Currently only 4bbp are supported */
g_assert (self->bpp == 4);
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,
cairo_surface_reference (self->surface));
self->n_columns = real_width / TILE_WIDTH;
self->n_rows = real_height / TILE_HEIGHT;
self->n_columns = self->real_width / TILE_WIDTH;
self->n_rows = self->real_height / TILE_HEIGHT;
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);
@ -381,10 +378,11 @@ mks_cairo_framebuffer_new (cairo_format_t format,
}
static void
invalidate_on_destroy (gpointer data)
flush_and_invalidate_on_destroy (gpointer data)
{
g_autoptr(MksCairoFramebuffer) self = data;
cairo_surface_flush (self->surface);
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 (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);
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++)
{
guint row_pos = row * self->n_rows;
guint row_pos = row * self->n_columns;
for (guint col = col1; col <= col2; col++)
{
@ -423,13 +424,14 @@ mks_cairo_framebuffer_update (MksCairoFramebuffer *self,
}
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_set_user_data (cr,
&invalidate_key,
g_object_ref (self),
invalidate_on_destroy);
flush_and_invalidate_on_destroy);
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
mks_paintable_set_framebuffer (MksPaintable *self,
MksCairoFramebuffer *framebuffer)
@ -193,12 +213,12 @@ mks_paintable_set_framebuffer (MksPaintable *self,
self->framebuffer = g_object_ref (framebuffer);
g_signal_connect_object (self->framebuffer,
"invalidate-size",
G_CALLBACK (gdk_paintable_invalidate_size),
G_CALLBACK (mks_paintable_invalidate_size_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (self->framebuffer,
"invalidate-contents",
G_CALLBACK (gdk_paintable_invalidate_contents),
G_CALLBACK (mks_paintable_invalidate_contents_cb),
self,
G_CONNECT_SWAPPED);
self->mode = MODE_FRAMEBUFFER;
@ -267,6 +287,8 @@ mks_paintable_listener_update (MksPaintable *self,
guint8 *data;
cairo_format_t format;
gsize data_len;
static int counter;
char name[32];
g_assert (MKS_IS_PAINTABLE (self));
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);
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);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_surface (cr, source, 0, 0);
cairo_rectangle (cr, x, y, width, height);
cairo_paint (cr);
cairo_rectangle (cr, 0, 0, width, height);
cairo_fill (cr);
cairo_destroy (cr);
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);
cr = mks_cairo_framebuffer_update (self->framebuffer, 0, 0, width, height);
cairo_set_source_surface (cr, source, 0, 0);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
cairo_rectangle (cr, 0, 0, width, height);
cairo_paint (cr);
cairo_destroy (cr);