From 13d943f76353367724d5f6e9d9f5174d73f09a2e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 12 Mar 2018 17:17:30 +0100 Subject: [PATCH] texture: Change download vfunc A problem with textures is that they can become too big for GPU memory, which would require tiling. But for tiling we only need to download the pixels needed by the tile. Similarly, there might be interest to not upload full textures if a renderer knows it only needs a small part. Both of these methods require the ability to specify an area of the texture to be downloaded. So change the download vfunc to include this parameter now before we add even more textures later. A private gdk_texture_download_area() function has also been added, but nobody is using it yet. --- gdk/gdkgltexture.c | 14 ++++++++------ gdk/gdkmemorytexture.c | 38 +++++++++++++++++++++++++++++++++----- gdk/gdktexture.c | 28 +++++++++++++++++++++++----- gdk/gdktextureprivate.h | 5 +++++ 4 files changed, 69 insertions(+), 16 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index e2f51c12d6..6a0185626a 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -68,9 +68,10 @@ gdk_gl_texture_dispose (GObject *object) } static void -gdk_gl_texture_download (GdkTexture *texture, - guchar *data, - gsize stride) +gdk_gl_texture_download (GdkTexture *texture, + const GdkRectangle *area, + guchar *data, + gsize stride) { GdkGLTexture *self = GDK_GL_TEXTURE (texture); cairo_surface_t *surface; @@ -78,7 +79,7 @@ gdk_gl_texture_download (GdkTexture *texture, surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, - texture->width, texture->height, + area->width, area->height, stride); cr = cairo_create (surface); @@ -93,8 +94,9 @@ gdk_gl_texture_download (GdkTexture *texture, GdkWindow *window; window = gdk_gl_context_get_window (self->context); - gdk_cairo_draw_from_gl (cr, window, self->id, GL_TEXTURE, 1, 0, 0, - texture->width, texture->height); + gdk_cairo_draw_from_gl (cr, window, self->id, GL_TEXTURE, 1, + area->x, area->y, + area->width, area->height); } cairo_destroy (cr); diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index f44dff2139..7a84e3962f 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -38,6 +38,30 @@ struct _GdkMemoryTextureClass G_DEFINE_TYPE (GdkMemoryTexture, gdk_memory_texture, GDK_TYPE_TEXTURE) +static gsize +gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) +{ + switch (format) + { + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_B8G8R8A8: + case GDK_MEMORY_A8R8G8B8: + case GDK_MEMORY_R8G8B8A8: + case GDK_MEMORY_A8B8G8R8: + return 4; + + case GDK_MEMORY_R8G8B8: + case GDK_MEMORY_B8G8R8: + return 3; + + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + return 4; + } +} + static void gdk_memory_texture_dispose (GObject *object) { @@ -49,17 +73,21 @@ gdk_memory_texture_dispose (GObject *object) } static void -gdk_memory_texture_download (GdkTexture *texture, - guchar *data, - gsize stride) +gdk_memory_texture_download (GdkTexture *texture, + const GdkRectangle *area, + guchar *data, + gsize stride) { GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); gdk_memory_convert (data, stride, GDK_MEMORY_CAIRO_FORMAT_ARGB32, - g_bytes_get_data (self->bytes, NULL), self->stride, + (guchar *) g_bytes_get_data (self->bytes, NULL) + + area->x * gdk_memory_format_bytes_per_pixel (self->format) + + area->y * self->stride, + self->stride, self->format, - texture->width, texture->height); + area->width, area->height); } static void diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index 616b0cbb8b..6e42f0a952 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -77,9 +77,10 @@ G_DEFINE_ABSTRACT_TYPE (GdkTexture, gdk_texture, G_TYPE_OBJECT) g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj)) static void -gdk_texture_real_download (GdkTexture *self, - guchar *data, - gsize stride) +gdk_texture_real_download (GdkTexture *self, + const GdkRectangle *area, + guchar *data, + gsize stride) { GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download); } @@ -431,7 +432,21 @@ gdk_texture_download_surface (GdkTexture *texture) return GDK_TEXTURE_GET_CLASS (texture)->download_surface (texture); } -/** +void +gdk_texture_download_area (GdkTexture *texture, + const GdkRectangle *area, + guchar *data, + gsize stride) +{ + g_assert (area->x >= 0); + g_assert (area->y >= 0); + g_assert (area->x + area->width <= texture->width); + g_assert (area->y + area->height <= texture->height); + + return GDK_TEXTURE_GET_CLASS (texture)->download (texture, area, data, stride); +} + +/* * gdk_texture_download: * @texture: a #GdkTexture * @data: (array): pointer to enough memory to be filled with the @@ -466,7 +481,10 @@ gdk_texture_download (GdkTexture *texture, g_return_if_fail (data != NULL); g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4); - return GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride); + gdk_texture_download_area (texture, + &(GdkRectangle) { 0, 0, texture->width, texture->height }, + data, + stride); } gboolean diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index f9e5fbe908..07cb5436a3 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -25,6 +25,7 @@ struct _GdkTextureClass { GObjectClass parent_class; void (* download) (GdkTexture *texture, + const GdkRectangle *area, guchar *data, gsize stride); cairo_surface_t * (* download_surface) (GdkTexture *texture); @@ -35,6 +36,10 @@ gpointer gdk_texture_new (const GdkTextureClass int height); GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface); cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture); +void gdk_texture_download_area (GdkTexture *texture, + const GdkRectangle *area, + guchar *data, + gsize stride); gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key,