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.
This commit is contained in:
Benjamin Otte 2018-03-12 17:17:30 +01:00
parent e5813b3ae7
commit 13d943f763
4 changed files with 69 additions and 16 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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,