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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -285,6 +285,22 @@ gsk_gl_program_set_uniform_texture (GskGLProgram *self,
|
||||
GL_LINEAR);
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user