gl: Refactor texture uploading

Don't pass texture + rect, but instead have
  gdk_memory_texture_new_subtexture()
and use it to generate subtextures and pass them.

This has the advantage of downloading the a too large texture only once
instead of N times.
This commit is contained in:
Benjamin Otte 2021-10-13 00:07:08 +02:00
parent 52e88ed4c8
commit ddc4a40c33
5 changed files with 54 additions and 21 deletions

View File

@ -166,6 +166,39 @@ gdk_memory_texture_new (int width,
return GDK_TEXTURE (self);
}
GdkTexture *
gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
int x,
int y,
int width,
int height)
{
GdkTexture *texture, *result;
gsize bpp, offset, size;
GBytes *bytes;
g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE (source), NULL);
g_return_val_if_fail (x < 0 || x >= GDK_TEXTURE (source)->width, NULL);
g_return_val_if_fail (y < 0 || y >= GDK_TEXTURE (source)->height, NULL);
g_return_val_if_fail (width <= 0 || x + width > GDK_TEXTURE (source)->width, NULL);
g_return_val_if_fail (height <= 0 || y + height > GDK_TEXTURE (source)->height, NULL);
texture = GDK_TEXTURE (source);
bpp = gdk_memory_format_bytes_per_pixel (texture->format);
offset = y * source->stride + x * bpp;
size = source->stride * (height - 1) + x * bpp;
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
result = gdk_memory_texture_new (texture->width,
texture->height,
texture->format,
bytes,
source->stride);
g_bytes_unref (bytes);
return result;
}
GdkMemoryTexture *
gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format)

View File

@ -31,6 +31,11 @@ G_BEGIN_DECLS
GdkMemoryTexture * gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format);
GdkTexture * gdk_memory_texture_new_subtexture (GdkMemoryTexture *texture,
int x,
int y,
int width,
int height);
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);

View File

@ -1422,10 +1422,6 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self,
int
gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture,
guint x_offset,
guint y_offset,
guint width,
guint height,
int min_filter,
int mag_filter)
{
@ -1434,16 +1430,17 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkMemoryFormat data_format;
const guchar *data;
gsize data_stride;
gsize bpp;
int width, height;
int texture_id;
g_assert (GSK_IS_GL_COMMAND_QUEUE (self));
g_assert (!GDK_IS_GL_TEXTURE (texture));
g_assert (x_offset + width <= gdk_texture_get_width (texture));
g_assert (y_offset + height <= gdk_texture_get_height (texture));
g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
g_assert (mag_filter == GL_LINEAR || min_filter == GL_NEAREST);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
if (width > self->max_texture_size || height > self->max_texture_size)
{
g_warning ("Attempt to create texture of size %ux%u but max size is %d. "
@ -1476,14 +1473,12 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
self->n_uploads++;
bpp = gdk_memory_format_bytes_per_pixel (data_format);
/* Switch to texture0 as 2D. We'll restore it later. */
glActiveTexture (GL_TEXTURE0);
glBindTexture (GL_TEXTURE_2D, texture_id);
gsk_gl_command_queue_do_upload_texture (self,
data + x_offset * bpp + y_offset * data_stride,
data,
width, height, data_stride,
data_format);

View File

@ -281,10 +281,6 @@ void gsk_gl_command_queue_execute (GskGLCommandQueue
const cairo_region_t *scissor);
int gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self,
GdkTexture *texture,
guint x_offset,
guint y_offset,
guint width,
guint height,
int min_filter,
int mag_filter);
int gsk_gl_command_queue_create_texture (GskGLCommandQueue *self,

View File

@ -798,10 +798,6 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
height = gdk_texture_get_height (texture);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
GDK_TEXTURE (downloaded_texture),
0,
0,
width,
height,
min_filter,
mag_filter);
@ -1230,6 +1226,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
int tex_width;
int tex_height;
int x = 0, y = 0;
GdkMemoryTexture *memtex;
g_assert (GSK_IS_GL_DRIVER (self));
g_assert (GDK_IS_TEXTURE (texture));
@ -1253,6 +1250,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
n_slices = cols * rows;
slices = g_new0 (GskGLTextureSlice, n_slices);
memtex = gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture));
for (guint col = 0; col < cols; col ++)
{
@ -1262,13 +1261,16 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
{
int slice_height = MIN (max_texture_size, texture->height - y);
int slice_index = (col * rows) + row;
GdkTexture *subtex;
guint texture_id;
subtex = gdk_memory_texture_new_subtexture (memtex,
x, y,
slice_width, slice_height);
texture_id = gsk_gl_command_queue_upload_texture (self->command_queue,
texture,
x, y,
slice_width, slice_height,
subtex,
GL_NEAREST, GL_NEAREST);
g_object_unref (subtex);
slices[slice_index].rect.x = x;
slices[slice_index].rect.y = y;
@ -1283,6 +1285,8 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
x += slice_width;
}
g_object_unref (memtex);
/* Allocate one Texture for the entire thing. */
t = gsk_gl_texture_new (0,
tex_width, tex_height,