summaryrefslogtreecommitdiff
path: root/gsk/gl
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-03-21 22:55:03 -0400
committerMatthias Clasen <mclasen@redhat.com>2023-03-22 00:15:04 -0400
commitc3ee8d2699bf8d053dec84584fb941ab6462b27c (patch)
treec46471d3468e9b4f93c7f853481946bf6f648332 /gsk/gl
parent24720307bb0d609af6bf29fd4b1161a45d2d17fd (diff)
downloadgtk+-c3ee8d2699bf8d053dec84584fb941ab6462b27c.tar.gz
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.
Diffstat (limited to 'gsk/gl')
-rw-r--r--gsk/gl/gskglcommandqueue.c121
-rw-r--r--gsk/gl/gskglcommandqueueprivate.h12
2 files changed, 97 insertions, 36 deletions
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,