From c3ee8d2699bf8d053dec84584fb941ab6462b27c Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 21 Mar 2023 22:55:03 -0400 Subject: gsk: Add more flexible texture upload Add a command queue function to create a GL texture by uploading several GdkTextures at given positions. This lets us 'piece together' textures. --- gsk/gl/gskglcommandqueue.c | 121 ++++++++++++++++++++++++++------------ gsk/gl/gskglcommandqueueprivate.h | 12 ++++ 2 files changed, 97 insertions(+), 36 deletions(-) (limited to 'gsk/gl') diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index c0cee895d4..436b8afcad 100644 --- a/gsk/gl/gskglcommandqueue.c +++ b/gsk/gl/gskglcommandqueue.c @@ -1412,9 +1412,41 @@ gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self) return fbo_id; } +static GdkMemoryFormat +memory_format_gl_format (GdkMemoryFormat data_format, + gboolean use_es, + guint *gl_internalformat, + guint *gl_format, + guint *gl_type) +{ + if (!gdk_memory_format_gl_format (data_format, + use_es, + gl_internalformat, + gl_format, + gl_type)) + { + if (gdk_memory_format_prefers_high_depth (data_format)) + data_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; + else + data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + if (!gdk_memory_format_gl_format (data_format, + use_es, + gl_internalformat, + gl_format, + gl_type)) + { + g_assert_not_reached (); + } + } + + return data_format; +} + static void -gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self, - GdkTexture *texture) +gsk_gl_command_queue_do_upload_texture_chunk (GskGLCommandQueue *self, + GdkTexture *texture, + int x, + int y) { GdkGLContext *context; const guchar *data; @@ -1435,25 +1467,11 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self, width = gdk_texture_get_width (texture); height = gdk_texture_get_height (texture); - if (!gdk_memory_format_gl_format (data_format, - use_es, - &gl_internalformat, - &gl_format, - &gl_type)) - { - if (gdk_memory_format_prefers_high_depth (data_format)) - data_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; - else - data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; - if (!gdk_memory_format_gl_format (data_format, - use_es, - &gl_internalformat, - &gl_format, - &gl_type)) - { - g_assert_not_reached (); - } - } + data_format = memory_format_gl_format (data_format, + use_es, + &gl_internalformat, + &gl_format, + &gl_type); gdk_texture_downloader_init (&downloader, texture); gdk_texture_downloader_set_format (&downloader, data_format); @@ -1469,43 +1487,53 @@ gsk_gl_command_queue_do_upload_texture (GskGLCommandQueue *self, */ if (stride == width * bpp) { - glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data); + glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); } else if (stride % bpp == 0 && (gdk_gl_context_check_version (context, 0, 0, 3, 0) || gdk_gl_context_has_unpack_subimage (context))) { glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp); - glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data); + glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, width, height, gl_format, gl_type, data); glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); } else { - int i; - glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL); - for (i = 0; i < height; i++) - glTexSubImage2D (GL_TEXTURE_2D, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride)); + for (int i = 0; i < height; i++) + glTexSubImage2D (GL_TEXTURE_2D, 0, x, y + i, width, 1, gl_format, gl_type, data + (i * stride)); } + glPixelStorei (GL_UNPACK_ALIGNMENT, 4); g_bytes_unref (bytes); } int -gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, - GdkTexture *texture) +gsk_gl_command_queue_upload_texture_chunks (GskGLCommandQueue *self, + unsigned int n_chunks, + GskGLTextureChunk *chunks) { G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME; - cairo_surface_t *surface = NULL; int width, height; + GdkMemoryFormat data_format; + GLenum gl_internalformat; + GLenum gl_format; + GLenum gl_type; + gboolean use_es; int texture_id; g_assert (GSK_IS_GL_COMMAND_QUEUE (self)); - g_assert (!GDK_IS_GL_TEXTURE (texture)); - width = gdk_texture_get_width (texture); - height = gdk_texture_get_height (texture); + width = height = 0; + for (unsigned int i = 0; i < n_chunks; i++) + { + GskGLTextureChunk *c = &chunks[i]; + + width = MAX (width, c->x + gdk_texture_get_width (c->texture)); + height = MAX (height, c->y + gdk_texture_get_height (c->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. " @@ -1514,6 +1542,7 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, width = MIN (width, self->max_texture_size); height = MIN (height, self->max_texture_size); } + texture_id = gsk_gl_command_queue_create_texture (self, width, height, GL_RGBA8); if (texture_id == -1) return texture_id; @@ -1524,15 +1553,28 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, glActiveTexture (GL_TEXTURE0); glBindTexture (GL_TEXTURE_2D, texture_id); - gsk_gl_command_queue_do_upload_texture (self, texture); + /* Initialize the texture */ + use_es = gdk_gl_context_get_use_es (gdk_gl_context_get_current ()); + data_format = gdk_texture_get_format (chunks[0].texture); + memory_format_gl_format (data_format, + use_es, + &gl_internalformat, + &gl_format, + &gl_type); + + glTexImage2D (GL_TEXTURE_2D, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL); + + for (unsigned int i = 0; i < n_chunks; i++) + { + GskGLTextureChunk *c = &chunks[i]; + gsk_gl_command_queue_do_upload_texture_chunk (self, c->texture, c->x, c->y); + } /* Restore previous texture state if any */ if (self->attachments->textures[0].id > 0) glBindTexture (self->attachments->textures[0].target, self->attachments->textures[0].id); - g_clear_pointer (&surface, cairo_surface_destroy); - if (gdk_profiler_is_running ()) gdk_profiler_add_markf (start_time, GDK_PROFILER_CURRENT_TIME-start_time, "Upload Texture", @@ -1541,6 +1583,13 @@ gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, return texture_id; } +int +gsk_gl_command_queue_upload_texture (GskGLCommandQueue *self, + GdkTexture *texture) +{ + return gsk_gl_command_queue_upload_texture_chunks (self, 1, &(GskGLTextureChunk){ texture, 0, 0}); +} + void gsk_gl_command_queue_set_profiler (GskGLCommandQueue *self, GskProfiler *profiler) diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h index 388745ea6f..cab15afbaa 100644 --- a/gsk/gl/gskglcommandqueueprivate.h +++ b/gsk/gl/gskglcommandqueueprivate.h @@ -298,6 +298,18 @@ int gsk_gl_command_queue_create_texture (GskGLCommandQueue int width, int height, int format); + + +typedef struct { + GdkTexture *texture; + int x; + int y; +} GskGLTextureChunk; + +int gsk_gl_command_queue_upload_texture_chunks(GskGLCommandQueue *self, + unsigned int n_chunks, + GskGLTextureChunk *chunks); + guint gsk_gl_command_queue_create_framebuffer (GskGLCommandQueue *self); gboolean gsk_gl_command_queue_create_render_target (GskGLCommandQueue *self, int width, -- cgit v1.2.1