summaryrefslogtreecommitdiff
path: root/gsk
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-01-28 15:20:26 -0500
committerBenjamin Otte <otte@redhat.com>2023-04-27 06:57:02 +0200
commit8292b846d58a09295e4e30c25c4e19c3ea4be8e1 (patch)
treef88bf88215d5eedcafb49180f0802c7319a2b0ce /gsk
parent6efaa79e3c1b9b17a99f93de2e8a76705f3409ff (diff)
downloadgtk+-8292b846d58a09295e4e30c25c4e19c3ea4be8e1.tar.gz
gsk: Synchronize when using textures
Pass the GLsync object from texture into our command queue, and when executing the queue, wait on the sync object the first time we use its associated texture.
Diffstat (limited to 'gsk')
-rw-r--r--gsk/gl/gskglcommandqueue.c13
-rw-r--r--gsk/gl/gskglcommandqueueprivate.h41
-rw-r--r--gsk/gl/gskglprogramprivate.h16
-rw-r--r--gsk/gl/gskglrenderjob.c42
4 files changed, 97 insertions, 15 deletions
diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c
index d5aa01a5f8..cf8acc5da2 100644
--- a/gsk/gl/gskglcommandqueue.c
+++ b/gsk/gl/gskglcommandqueue.c
@@ -427,6 +427,7 @@ gsk_gl_command_queue_dispose (GObject *object)
gsk_gl_command_batches_clear (&self->batches);
gsk_gl_command_binds_clear (&self->batch_binds);
gsk_gl_command_uniforms_clear (&self->batch_uniforms);
+ gsk_gl_syncs_clear (&self->syncs);
gsk_gl_buffer_destroy (&self->vertices);
@@ -449,6 +450,7 @@ gsk_gl_command_queue_init (GskGLCommandQueue *self)
gsk_gl_command_batches_init (&self->batches, 128);
gsk_gl_command_binds_init (&self->batch_binds, 1024);
gsk_gl_command_uniforms_init (&self->batch_uniforms, 2048);
+ gsk_gl_syncs_init (&self->syncs, 10);
gsk_gl_buffer_init (&self->vertices, GL_ARRAY_BUFFER, sizeof (GskGLDrawVertex));
}
@@ -1159,17 +1161,25 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
if G_UNLIKELY (batch->draw.bind_count > 0)
{
const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset];
-
for (guint i = 0; i < batch->draw.bind_count; i++)
{
if (textures[bind->texture] != bind->id)
{
+ GskGLSync *s;
+
if (active != bind->texture)
{
active = bind->texture;
glActiveTexture (GL_TEXTURE0 + bind->texture);
}
+ s = gsk_gl_syncs_get_sync (&self->syncs, bind->id);
+ if (s && s->sync)
+ {
+ glWaitSync ((GLsync) s->sync, 0, GL_TIMEOUT_IGNORED);
+ s->sync = NULL;
+ }
+
glBindTexture (GL_TEXTURE_2D, bind->id);
textures[bind->texture] = bind->id;
if (!self->has_samplers)
@@ -1315,6 +1325,7 @@ gsk_gl_command_queue_end_frame (GskGLCommandQueue *self)
self->batches.len = 0;
self->batch_binds.len = 0;
self->batch_uniforms.len = 0;
+ self->syncs.len = 0;
self->n_uploads = 0;
self->tail_batch_index = -1;
self->in_frame = FALSE;
diff --git a/gsk/gl/gskglcommandqueueprivate.h b/gsk/gl/gskglcommandqueueprivate.h
index fd72f68aff..df3afb1eea 100644
--- a/gsk/gl/gskglcommandqueueprivate.h
+++ b/gsk/gl/gskglcommandqueueprivate.h
@@ -168,9 +168,15 @@ typedef union _GskGLCommandBatch
G_STATIC_ASSERT (sizeof (GskGLCommandBatch) == 32);
+typedef struct _GskGLSync {
+ guint id;
+ gpointer sync;
+} GskGLSync;
+
DEFINE_INLINE_ARRAY (GskGLCommandBatches, gsk_gl_command_batches, GskGLCommandBatch)
DEFINE_INLINE_ARRAY (GskGLCommandBinds, gsk_gl_command_binds, GskGLCommandBind)
DEFINE_INLINE_ARRAY (GskGLCommandUniforms, gsk_gl_command_uniforms, GskGLCommandUniform)
+DEFINE_INLINE_ARRAY (GskGLSyncs, gsk_gl_syncs, GskGLSync)
struct _GskGLCommandQueue
{
@@ -233,6 +239,10 @@ struct _GskGLCommandQueue
*/
GLuint samplers[GSK_GL_N_FILTERS * GSK_GL_N_FILTERS];
+ /* Array of sync objects to wait on.
+ */
+ GskGLSyncs syncs;
+
/* Discovered max texture size when loading the command queue so that we
* can either scale down or slice textures to fit within this size. Assumed
* to be both height and width.
@@ -371,5 +381,36 @@ gsk_gl_command_queue_bind_framebuffer (GskGLCommandQueue *self,
return ret;
}
+static inline GskGLSync *
+gsk_gl_syncs_get_sync (GskGLSyncs *syncs,
+ guint id)
+{
+ for (unsigned int i = 0; i < syncs->len; i++)
+ {
+ GskGLSync *sync = &syncs->items[i];
+ if (sync->id == id)
+ return sync;
+ }
+ return NULL;
+}
+
+static inline void
+gsk_gl_syncs_add_sync (GskGLSyncs *syncs,
+ guint id,
+ gpointer sync)
+{
+ GskGLSync *s;
+
+ s = gsk_gl_syncs_get_sync (syncs, id);
+ if (s)
+ g_assert (s->sync == sync);
+ else
+ {
+ s = gsk_gl_syncs_append (syncs);
+ s->id = id;
+ s->sync = sync;
+ }
+}
+
G_END_DECLS
diff --git a/gsk/gl/gskglprogramprivate.h b/gsk/gl/gskglprogramprivate.h
index 50c191eb4b..6bfbe48f02 100644
--- a/gsk/gl/gskglprogramprivate.h
+++ b/gsk/gl/gskglprogramprivate.h
@@ -286,6 +286,22 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
}
static inline void
+gsk_gl_program_set_uniform_texture_with_sync (GskGLProgram *self,
+ guint key,
+ guint stamp,
+ GLenum texture_target,
+ GLenum texture_slot,
+ guint texture_id,
+ GLint min_filter,
+ GLint max_filter,
+ gpointer sync)
+{
+ gsk_gl_program_set_uniform_texture_with_filter (self, key, stamp, texture_target, texture_slot, texture_id,
+ min_filter, max_filter);
+ gsk_gl_syncs_add_sync (&self->driver->command_queue->syncs, texture_id, sync);
+}
+
+static inline void
gsk_gl_program_set_uniform_matrix (GskGLProgram *self,
guint key,
guint stamp,
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c
index 1eb82e80da..051619528c 100644
--- a/gsk/gl/gskglrenderjob.c
+++ b/gsk/gl/gskglrenderjob.c
@@ -191,6 +191,7 @@ typedef struct _GskGLRenderOffscreen
/* Return location for texture ID */
guint texture_id;
+ gpointer sync;
/* Whether to force creating a new texture, even if the
* input already is a texture
@@ -3570,6 +3571,9 @@ gsk_gl_render_job_upload_texture (GskGLRenderJob *job,
offscreen->texture_id = gsk_gl_driver_load_texture (job->driver, texture, ensure_mipmap);
init_full_texture_region (offscreen);
offscreen->has_mipmap = ensure_mipmap;
+
+ if (gl_texture && offscreen->texture_id == gdk_gl_texture_get_id (gl_texture))
+ offscreen->sync = gdk_gl_texture_get_sync (gl_texture);
}
}
@@ -3597,13 +3601,15 @@ gsk_gl_render_job_visit_texture (GskGLRenderJob *job,
g_assert (offscreen.was_offscreen == FALSE);
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
- gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
- UNIFORM_SHARED_SOURCE, 0,
- GL_TEXTURE_2D,
- GL_TEXTURE0,
- offscreen.texture_id,
- offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
- GL_LINEAR);
+
+ gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
+ UNIFORM_SHARED_SOURCE, 0,
+ GL_TEXTURE_2D,
+ GL_TEXTURE0,
+ offscreen.texture_id,
+ offscreen.has_mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR,
+ GL_LINEAR,
+ offscreen.sync);
gsk_gl_render_job_draw_offscreen (job, bounds, &offscreen);
gsk_gl_render_job_end_draw (job);
}
@@ -3733,21 +3739,29 @@ gsk_gl_render_job_visit_texture_scale_node (GskGLRenderJob *job,
if G_LIKELY (texture->width <= max_texture_size &&
texture->height <= max_texture_size)
{
+ gpointer sync;
+
texture_id = gsk_gl_driver_load_texture (job->driver, texture, filter == GSK_SCALING_FILTER_TRILINEAR);
+ if (GDK_IS_GL_TEXTURE (texture) && texture_id == gdk_gl_texture_get_id (GDK_GL_TEXTURE (texture)))
+ sync = gdk_gl_texture_get_sync (GDK_GL_TEXTURE (texture));
+ else
+ sync = NULL;
+
u0 = (clip_rect.origin.x - bounds->origin.x) / bounds->size.width;
v0 = (clip_rect.origin.y - bounds->origin.y) / bounds->size.height;
u1 = (clip_rect.origin.x + clip_rect.size.width - bounds->origin.x) / bounds->size.width;
v1 = (clip_rect.origin.y + clip_rect.size.height - bounds->origin.y) / bounds->size.height;
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
- gsk_gl_program_set_uniform_texture_with_filter (job->current_program,
- UNIFORM_SHARED_SOURCE, 0,
- GL_TEXTURE_2D,
- GL_TEXTURE0,
- texture_id,
- min_filter,
- mag_filter);
+ gsk_gl_program_set_uniform_texture_with_sync (job->current_program,
+ UNIFORM_SHARED_SOURCE, 0,
+ GL_TEXTURE_2D,
+ GL_TEXTURE0,
+ texture_id,
+ min_filter,
+ mag_filter,
+ sync);
gsk_gl_render_job_draw_coords (job,
0, 0, clip_rect.size.width, clip_rect.size.height,
u0, v0, u1, v1,