diff options
author | Benjamin Otte <otte.benjamin@googlemail.com> | 2023-04-28 15:58:10 +0000 |
---|---|---|
committer | Benjamin Otte <otte.benjamin@googlemail.com> | 2023-04-28 15:58:10 +0000 |
commit | 76777cdd1801b450a0ba5fb6d8147045d888c866 (patch) | |
tree | fd198c14e9ecf01f8f4ed0124065ffefea331438 /gsk | |
parent | bdec7782b4d30da8482f9d1f6a330e3fd1af2e8d (diff) | |
parent | 92a9f8cd7edb029a18f0897c173adba7c6213a18 (diff) | |
download | gtk+-76777cdd1801b450a0ba5fb6d8147045d888c866.tar.gz |
Merge branch 'wip/otte/texturebuilder' into 'main'
Add GdkGLTextureBuilder
See merge request GNOME/gtk!5862
Diffstat (limited to 'gsk')
-rw-r--r-- | gsk/gl/gskglcommandqueue.c | 13 | ||||
-rw-r--r-- | gsk/gl/gskglcommandqueueprivate.h | 41 | ||||
-rw-r--r-- | gsk/gl/gskgldriver.c | 42 | ||||
-rw-r--r-- | gsk/gl/gskglprogramprivate.h | 16 | ||||
-rw-r--r-- | gsk/gl/gskglrenderjob.c | 42 |
5 files changed, 126 insertions, 28 deletions
diff --git a/gsk/gl/gskglcommandqueue.c b/gsk/gl/gskglcommandqueue.c index d286c001ba..774b957785 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/gskgldriver.c b/gsk/gl/gskgldriver.c index 672f44a5ee..d0af5e76da 100644 --- a/gsk/gl/gskgldriver.c +++ b/gsk/gl/gskgldriver.c @@ -1126,14 +1126,20 @@ write_atlas_to_png (GskGLDriver *driver, GskGLTextureAtlas *atlas, const char *filename) { + GdkGLTextureBuilder *builder; GdkTexture *texture; - texture = gdk_gl_texture_new (gsk_gl_driver_get_context (driver), - atlas->texture_id, - atlas->width, atlas->height, - NULL, NULL); + builder = gdk_gl_texture_builder_new (); + gdk_gl_texture_builder_set_context (builder, gsk_gl_driver_get_context (driver)); + gdk_gl_texture_builder_set_id (builder, atlas->texture_id); + gdk_gl_texture_builder_set_width (builder, atlas->width); + gdk_gl_texture_builder_set_height (builder, atlas->height); + + texture = gdk_gl_texture_builder_build (builder, NULL, NULL); gdk_texture_save_to_png (texture, filename); + g_object_unref (texture); + g_object_unref (builder); } void @@ -1557,6 +1563,7 @@ typedef struct _GskGLTextureState { GdkGLContext *context; GLuint texture_id; + GLsync sync; } GskGLTextureState; static void @@ -1569,6 +1576,8 @@ create_texture_from_texture_destroy (gpointer data) gdk_gl_context_make_current (state->context); glDeleteTextures (1, &state->texture_id); + if (state->sync) + glDeleteSync (state->sync); g_clear_object (&state->context); g_free (state); } @@ -1578,8 +1587,9 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self, guint texture_id) { GskGLTextureState *state; + GdkGLTextureBuilder *builder; GskGLTexture *texture; - int width, height; + GdkTexture *result; g_return_val_if_fail (GSK_IS_GL_DRIVER (self), NULL); g_return_val_if_fail (self->command_queue != NULL, NULL); @@ -1594,19 +1604,25 @@ gsk_gl_driver_create_gdk_texture (GskGLDriver *self, state = g_new0 (GskGLTextureState, 1); state->texture_id = texture_id; state->context = g_object_ref (self->command_queue->context); + if (gdk_gl_context_has_sync (self->command_queue->context)) + state->sync = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0); g_hash_table_steal (self->textures, GUINT_TO_POINTER (texture_id)); - width = texture->width; - height = texture->height; + builder = gdk_gl_texture_builder_new (); + gdk_gl_texture_builder_set_context (builder, self->command_queue->context); + gdk_gl_texture_builder_set_id (builder, texture_id); + gdk_gl_texture_builder_set_width (builder, texture->width); + gdk_gl_texture_builder_set_height (builder, texture->height); + gdk_gl_texture_builder_set_sync (builder, state->sync); + + result = gdk_gl_texture_builder_build (builder, + create_texture_from_texture_destroy, + state); texture->texture_id = 0; gsk_gl_texture_free (texture); + g_object_unref (builder); - return gdk_gl_texture_new (self->command_queue->context, - texture_id, - width, - height, - create_texture_from_texture_destroy, - state); + return result; } 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, |