summaryrefslogtreecommitdiff
path: root/gsk/gl/gskgldriver.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-03-21 23:26:55 -0400
committerMatthias Clasen <mclasen@redhat.com>2023-03-22 00:15:32 -0400
commit9dcc1943b3356431aa39d2db149bb5bf25c17b48 (patch)
tree8ac55ad9092de118c92a7408b85f02877c393bbf /gsk/gl/gskgldriver.c
parentc3ee8d2699bf8d053dec84584fb941ab6462b27c (diff)
downloadgtk+-9dcc1943b3356431aa39d2db149bb5bf25c17b48.tar.gz
gsk: Improve slice handling
Upload slices in chunks, instead of copying enormous amounts of memory.
Diffstat (limited to 'gsk/gl/gskgldriver.c')
-rw-r--r--gsk/gl/gskgldriver.c236
1 files changed, 208 insertions, 28 deletions
diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c
index 4b8aa14e45..f0b03ebcc8 100644
--- a/gsk/gl/gskgldriver.c
+++ b/gsk/gl/gskgldriver.c
@@ -1197,6 +1197,10 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
int x = 0, y = 0;
GdkMemoryTexture *memtex;
int extra_pixels;
+ GdkMemoryTexture *memtex1 = NULL;
+ GdkMemoryTexture *memtex2 = NULL;
+ GdkMemoryTexture *memtex3 = NULL;
+ GdkMemoryTexture *memtex4 = NULL;
g_assert (GSK_IS_GL_DRIVER (self));
g_assert (GDK_IS_TEXTURE (texture));
@@ -1233,50 +1237,112 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
if (ensure_mipmap)
{
- guchar *data, *data2;
- int w, h;
+ guchar *data1, *data2, *data3, *data4;
+ guchar *top_row, *bot_row, *left_row, *right_row;
+ GdkTexture *tmp;
+ int w;
GBytes *bytes;
/* We need some extra pixels around our tiles, in order for
* GL to properly determine the right level of detail to use.
* This number should probably depend on the scale, but for
* now we just hardcode it.
+ *
+ * We create some auxiliary textures to hold the extra pixels:
+ *
+ * +---------------------+
+ * | memtex1 |
+ * *---+-------------+---+
+ * | | | |
+ * memtex2| memtex |memtex3
+ * | | | |
+ * *---+-------------+---+
+ * | memtex4 | |
+ * +---------------------+
*/
+
extra_pixels = 15;
- /* FIXME a shame we have to copy the data here.
- * It would be nicer if we could scatter-gather
- * textures from smaller pieces.
- */
+ top_row = g_malloc (4 * tex_width);
+ tmp = gdk_memory_texture_new_subtexture (memtex, 0, 0, tex_width, 1);
+ gdk_texture_download (tmp, top_row, 4 * tex_width);
+ g_object_unref (tmp);
+
+ bot_row = g_malloc (4 * tex_width);
+ tmp = gdk_memory_texture_new_subtexture (memtex, 0, tex_height - 1, tex_width, 1);
+ gdk_texture_download (tmp, bot_row, 4 * tex_width);
+ g_object_unref (tmp);
- data = g_malloc (4 * tex_width * tex_height);
- gdk_texture_download (GDK_TEXTURE (memtex), data, 4 * tex_width);
+ left_row = g_malloc (4 * tex_height);
+ tmp = gdk_memory_texture_new_subtexture (memtex, 0, 0, 1, tex_height);
+ gdk_texture_download (tmp, left_row, 4);
+ g_object_unref (tmp);
+
+ right_row = g_malloc (4 * tex_height);
+ tmp = gdk_memory_texture_new_subtexture (memtex, tex_width - 1, 0, 1, tex_height);
+ gdk_texture_download (tmp, right_row, 4);
+ g_object_unref (tmp);
w = tex_width + 2 * extra_pixels;
- h = tex_height + 2 * extra_pixels;
- data2 = g_malloc (4 * w * h);
+ data1 = g_malloc (4 * w * extra_pixels);
+ data2 = g_malloc (4 * extra_pixels * tex_height);
+ data3 = g_malloc (4 * extra_pixels * tex_height);
+ data4 = g_malloc (4 * w * extra_pixels);
for (int i = 0; i < w; i++)
{
int ii = CLAMP (i, extra_pixels, (tex_width - 1) + extra_pixels) - extra_pixels;
- for (int j = 0; j < h; j++)
+ for (int j = 0; j < extra_pixels; j++)
{
- int jj = CLAMP (j, extra_pixels, (tex_height - 1) + extra_pixels) - extra_pixels;
+ data1[(j * w + i) * 4] = top_row[ii * 4];
+ data1[(j * w + i) * 4 + 1] = top_row[ii * 4 + 1];
+ data1[(j * w + i) * 4 + 2] = top_row[ii * 4 + 2];
+ data1[(j * w + i) * 4 + 3] = top_row[ii * 4 + 3];
+
+ data4[(j * w + i) * 4] = bot_row[ii * 4];
+ data4[(j * w + i) * 4 + 1] = bot_row[ii * 4 + 1];
+ data4[(j * w + i) * 4 + 2] = bot_row[ii * 4 + 2];
+ data4[(j * w + i) * 4 + 3] = bot_row[ii * 4 + 3];
+ }
+ }
- data2[(j * w + i) * 4] = data[(jj * tex_width + ii) * 4];
- data2[(j * w + i) * 4 + 1] = data[(jj * tex_width + ii) * 4 + 1];
- data2[(j * w + i) * 4 + 2] = data[(jj * tex_width + ii) * 4 + 2];
- data2[(j * w + i) * 4 + 3] = data[(jj * tex_width + ii) * 4 + 3];
+ for (int i = 0; i < extra_pixels; i++)
+ {
+ for (int j = 0; j < tex_height; j++)
+ {
+ data2[(j * extra_pixels + i) * 4] = left_row[j * 4];
+ data2[(j * extra_pixels + i) * 4 + 1] = left_row[j * 4 + 1];
+ data2[(j * extra_pixels + i) * 4 + 2] = left_row[j * 4 + 2];
+ data2[(j * extra_pixels + i) * 4 + 3] = left_row[j * 4 + 3];
+
+ data3[(j * extra_pixels + i) * 4] = right_row[j * 4];
+ data3[(j * extra_pixels + i) * 4 + 1] = right_row[j * 4 + 1];
+ data3[(j * extra_pixels + i) * 4 + 2] = right_row[j * 4 + 2];
+ data3[(j * extra_pixels + i) * 4 + 3] = right_row[j * 4 + 3];
}
}
- g_free (data);
- bytes = g_bytes_new_take (data2, 4 * w * h);
+ g_free (top_row);
+ g_free (bot_row);
+ g_free (left_row);
+ g_free (right_row);
+
+ bytes = g_bytes_new_take (data1, 4 * w * extra_pixels);
+ memtex1 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (w, extra_pixels, GDK_MEMORY_DEFAULT, bytes, 4 * w));
+ g_bytes_unref (bytes);
+
+ bytes = g_bytes_new_take (data2, 4 * extra_pixels * tex_height);
+ memtex2 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (extra_pixels, tex_height, GDK_MEMORY_DEFAULT, bytes, 4 * extra_pixels));
+ g_bytes_unref (bytes);
- g_object_unref (memtex);
- memtex = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (w, h, GDK_MEMORY_DEFAULT, bytes, 4 * w));
+ bytes = g_bytes_new_take (data3, 4 * extra_pixels * tex_height);
+ memtex3 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (extra_pixels, tex_height, GDK_MEMORY_DEFAULT, bytes, 4 * extra_pixels));
+ g_bytes_unref (bytes);
+
+ bytes = g_bytes_new_take (data4, 4 * w * extra_pixels);
+ memtex4 = GDK_MEMORY_TEXTURE (gdk_memory_texture_new (w, extra_pixels, GDK_MEMORY_DEFAULT, bytes, 4 * w));
g_bytes_unref (bytes);
}
else
@@ -1292,20 +1358,130 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
{
int slice_height = row + 1 < rows ? tex_height / rows : tex_height - y;
int slice_index = (col * rows) + row;
- GdkTexture *subtex;
guint texture_id;
- subtex = gdk_memory_texture_new_subtexture (memtex,
- x, y,
- slice_width + 2 * extra_pixels,
- slice_height + 2 * extra_pixels);
-
- texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex);
- g_object_unref (subtex);
if (ensure_mipmap)
{
+ GskGLTextureChunk chunks[5];
+ unsigned int n_chunks = 0;
+
+ if (row == 0)
+ {
+ chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex1,
+ x, 0,
+ slice_width + 2 * extra_pixels, extra_pixels);
+ chunks[n_chunks].x = 0;
+ chunks[n_chunks].y = 0;
+ n_chunks++;
+ }
+
+ if (row == rows - 1)
+ {
+ chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex4,
+ x, 0,
+ slice_width + 2 * extra_pixels, extra_pixels);
+ chunks[n_chunks].x = 0;
+ chunks[n_chunks].y = slice_height + extra_pixels;
+ n_chunks++;
+ }
+
+ if (col == 0)
+ {
+ int yy = y - extra_pixels;
+ int hh = slice_height + 2 * extra_pixels;
+ int y0 = 0;
+
+ if (row == 0)
+ {
+ yy = 0;
+ y0 = extra_pixels;
+ hh -= extra_pixels;
+ }
+ if (row == rows - 1)
+ {
+ hh -= extra_pixels;
+ }
+
+ chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex2,
+ 0, yy, extra_pixels, hh);
+ chunks[n_chunks].x = 0;
+ chunks[n_chunks].y = y0;
+ n_chunks++;
+ }
+
+ if (col == cols - 1)
+ {
+ int yy = y - extra_pixels;
+ int hh = slice_height + 2 * extra_pixels;
+ int y0 = 0;
+
+ if (row == 0)
+ {
+ yy = 0;
+ y0 = extra_pixels;
+ hh -= extra_pixels;
+ }
+ if (row == rows - 1)
+ {
+ hh -= extra_pixels;
+ }
+
+ chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex3,
+ 0, yy, extra_pixels, hh);
+ chunks[n_chunks].x = slice_width + extra_pixels;
+ chunks[n_chunks].y = y0;
+ n_chunks++;
+ }
+
+ {
+ int xx = x - extra_pixels;
+ int yy = y - extra_pixels;
+ int ww = slice_width + 2 * extra_pixels;
+ int hh = slice_height + 2 * extra_pixels;
+ int x0 = 0;
+ int y0 = 0;
+ if (col == 0)
+ {
+ xx = 0;
+ ww -= extra_pixels;
+ x0 = extra_pixels;
+ }
+ if (col == cols - 1)
+ {
+ ww -= extra_pixels;
+ }
+ if (row == 0)
+ {
+ yy = 0;
+ hh -= extra_pixels;
+ y0 = extra_pixels;
+ }
+ if (row == rows - 1)
+ {
+ hh -= extra_pixels;
+ }
+
+ chunks[n_chunks].texture = gdk_memory_texture_new_subtexture (memtex, xx, yy, ww, hh);
+ chunks[n_chunks].x = x0;
+ chunks[n_chunks].y = y0;
+ n_chunks++;
+ }
+
+ texture_id = gsk_gl_command_queue_upload_texture_chunks (self->command_queue, n_chunks, chunks);
+
glBindTexture (GL_TEXTURE_2D, texture_id);
glGenerateMipmap (GL_TEXTURE_2D);
+
+ for (unsigned int i = 0; i < n_chunks; i++)
+ g_object_unref (chunks[i].texture);
+ }
+ else
+ {
+ GdkTexture *subtex;
+
+ subtex = gdk_memory_texture_new_subtexture (memtex, x, y, slice_width, slice_height);
+ texture_id = gsk_gl_command_queue_upload_texture (self->command_queue, subtex);
+ g_object_unref (subtex);
}
slices[slice_index].rect.x = x;
@@ -1325,6 +1501,10 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
}
g_object_unref (memtex);
+ g_clear_object (&memtex1);
+ g_clear_object (&memtex2);
+ g_clear_object (&memtex3);
+ g_clear_object (&memtex4);
/* Allocate one Texture for the entire thing. */
t = gsk_gl_texture_new (0,