diff options
author | Matthias Clasen <mclasen@redhat.com> | 2023-03-21 23:26:55 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2023-03-22 00:15:32 -0400 |
commit | 9dcc1943b3356431aa39d2db149bb5bf25c17b48 (patch) | |
tree | 8ac55ad9092de118c92a7408b85f02877c393bbf /gsk/gl/gskgldriver.c | |
parent | c3ee8d2699bf8d053dec84584fb941ab6462b27c (diff) | |
download | gtk+-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.c | 236 |
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, |