textures and paintables

With GTK4, we’ve been trying to find better solution for image data. In GTK3 the objects we used for this were pixbufs and Cairo surfaces. But they don’t fit the bill anymore, so now we have GdkTexture and GdkPaintable.

GdkTexture

GdkTexture is the replacement for GdkPixbuf. Why is it better?
For a start, it is a lot simpler. The API looks like this:

int gdk_texture_get_width (GdkTexture *texture);
int gdk_texture_get_height (GdkTexture *texture);

void gdk_texture_download (GdkTexture *texture,
                           guchar     *data,
                           gsize       stride);

So it is a 2D pixel array and if you want to, you can download the pixels. It is also guaranteed immutable, so the pixels will never change. Lots of constructors exist to create textures from files, resources, data or pixbufs.

But the biggest difference between textures and pixbufs is that they don’t expose the memory that they use to store the pixels. In fact, before gdk_texture_download() is called, that data doesn’t even need to exist.
And this is used in the GL texture. The GtkGLArea widget for example uses this method to pass data around. GStreamer is expected to pass video in the form of GL textures, too.

GdkPaintable

But sometimes, you have something more complex than an immutable bunch of pixels. For example you could have an animated GIF or a scalable SVG. That’s where GdkPaintable comes in.
In abstract terms, GdkPaintable is an interface for objects that know how to render themselves at any size. Inspired by CSS images, they can optionally provide intrinsic sizing information that GTK widgets can use to place them.
So the core of the GdkPaintable interface are the function make the paintable render itself and the 3 functions that provide sizing information:

void gdk_paintable_snapshot (GdkPaintable *paintable,
                             GdkSnapshot  *snapshot,
                             double        width,
                             double        height);

int gdk_paintable_get_intrinsic_width (GdkPaintable *paintable);
int gdk_paintable_get_intrinsic_height (GdkPaintable *paintable);
double gdk_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable);

On top of that, the paintable can emit the “invalidate-contents” and “invalidate-size” signals when its contents or size changes.

To make this more concrete, let’s take a scalable SVG as an example: The paintable implementation would return no intrinsic size (the return value 0 for those sizing function achieves that) and whenever it is drawn, it would draw itself pixel-exact at the given size.
Or take the example of the animated GIF: It would provide its pixel size as its intrinsic size and draw the current frame of the animation scaled to the given size. And whenever the next frame of the animation should be displayed, it would emit the “invalidate-size” signal.
And last but not least, GdkTexture implements this interface.

We’re currently in the process of changing all the code that in GTK3 accepted GdkPixbuf to now accept GdkPaintable. The GtkImage widget of course has been changed already, as have the drag’n’drop icons or GtkAboutDialog. Experimental patches exist to let applications provide paintables to the GTK CSS engine.

And if you now put all this information together about GStreamer potentially providing textures backed by GL images and creating paintables that do animations that can then be uploaded to CSS, you can maybe see where this is going

Author: Benjamin Otte

In conference bios, I write this about me: Since his entry into the Free Software world in 2002 Benjamin Otte has continually tried to make computers more fun. His success stories include the Swfdec Flash player, co-maintaining GStreamer, working on GVfs and a high ranking on Ohloh. During the days he spends his time working on all things multimedia at Red Hat.

5 thoughts on “textures and paintables”

  1. What about the GIcon abstraction? Are those two objects inheriting GIcon to be able to hash/serialize them?

Comments are closed.

Leave a Reply

Your email address will not be published. Required fields are marked *