mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 14:10:30 +00:00
ngl: add front cache to reduce uniform changes
Since we make full snapshots when recording uniform state of batches, we need to perform some deduplication to avoid so many repeated uniform calls. This uses a closed hashtable to determine if we are likely changing the value to something new. This does not currently compare values, it instead only compares that we are going to point at a new offset into the uniform buffer. We could go further if we compare upon updating values (we did that early on in the prototype) so that offsets are less likely to be changed.
This commit is contained in:
parent
7f292d34bd
commit
0b7d8e19c3
@ -731,98 +731,6 @@ gsk_ngl_command_queue_delete_program (GskNglCommandQueue *self,
|
||||
glDeleteProgram (program);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_uniform (gconstpointer dataptr,
|
||||
GskNglUniformInfo info,
|
||||
guint location)
|
||||
{
|
||||
g_assert (dataptr != NULL);
|
||||
g_assert (info.format > 0);
|
||||
g_assert (location < GL_MAX_UNIFORM_LOCATIONS);
|
||||
|
||||
switch (info.format)
|
||||
{
|
||||
case GSK_NGL_UNIFORM_FORMAT_1F:
|
||||
glUniform1fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2F:
|
||||
glUniform2fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3F:
|
||||
glUniform3fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4F:
|
||||
glUniform4fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1FV:
|
||||
glUniform1fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2FV:
|
||||
glUniform2fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3FV:
|
||||
glUniform3fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4FV:
|
||||
glUniform4fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1I:
|
||||
case GSK_NGL_UNIFORM_FORMAT_TEXTURE:
|
||||
glUniform1iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2I:
|
||||
glUniform2iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3I:
|
||||
glUniform3iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4I:
|
||||
glUniform4iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1UI:
|
||||
glUniform1uiv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_MATRIX: {
|
||||
float mat[16];
|
||||
graphene_matrix_to_float (dataptr, mat);
|
||||
glUniformMatrix4fv (location, 1, GL_FALSE, mat);
|
||||
#if 0
|
||||
/* TODO: If Graphene can give us a peek here on platforms
|
||||
* where the format is float[16] (most/all x86_64?) then
|
||||
* We can avoid the SIMD operation to convert the format.
|
||||
*/
|
||||
G_STATIC_ASSERT (sizeof (graphene_matrix_t) == 16*4);
|
||||
glUniformMatrix4fv (location, 1, GL_FALSE, dataptr);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_COLOR:
|
||||
glUniform4fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_ROUNDED_RECT:
|
||||
glUniform4fv (location, 3, dataptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_viewport (guint *current_width,
|
||||
guint *current_height,
|
||||
@ -1187,8 +1095,7 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self,
|
||||
const GskNglCommandUniform *u = &self->batch_uniforms.items[batch->draw.uniform_offset];
|
||||
|
||||
for (guint i = 0; i < batch->draw.uniform_count; i++, u++)
|
||||
apply_uniform (gsk_ngl_uniform_state_get_uniform_data (self->uniforms, u->info.offset),
|
||||
u->info, u->location);
|
||||
gsk_ngl_uniform_state_apply (self->uniforms, program, u->location, u->info);
|
||||
|
||||
n_uniforms += batch->draw.uniform_count;
|
||||
}
|
||||
|
@ -65,6 +65,8 @@ gsk_ngl_uniform_state_new (void)
|
||||
state->values_pos = 0;
|
||||
state->values_buf = g_malloc (4096);
|
||||
|
||||
memset (state->apply_hash, 0, sizeof state->apply_hash);
|
||||
|
||||
return g_steal_pointer (&state);
|
||||
}
|
||||
|
||||
@ -221,6 +223,8 @@ gsk_ngl_uniform_state_end_frame (GskNglUniformState *state)
|
||||
state->values_pos = allocator;
|
||||
|
||||
g_assert (allocator <= state->values_len);
|
||||
|
||||
memset (state->apply_hash, 0, sizeof state->apply_hash);
|
||||
}
|
||||
|
||||
gsize
|
||||
|
@ -83,6 +83,7 @@ typedef struct _GskNglUniformState
|
||||
guint8 *values_buf;
|
||||
guint values_pos;
|
||||
guint values_len;
|
||||
GskNglUniformInfo apply_hash[512];
|
||||
} GskNglUniformState;
|
||||
|
||||
/**
|
||||
@ -680,6 +681,137 @@ gsk_ngl_uniform_state_set4fv (GskNglUniformState *state,
|
||||
}
|
||||
}
|
||||
|
||||
static inline guint
|
||||
gsk_ngl_uniform_state_fmix (guint program,
|
||||
guint location)
|
||||
{
|
||||
guint h = (program << 16) | location;
|
||||
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
* gsk_ngl_uniform_state_apply:
|
||||
* @state: the uniform state
|
||||
* @program: the program id
|
||||
* @location: the location of the uniform
|
||||
* @offset: the offset of the data within the buffer
|
||||
* @info: the uniform info
|
||||
*
|
||||
* This function can be used to apply state that was previously recorded
|
||||
* by the #GskNglUniformState.
|
||||
*
|
||||
* It is specifically useful from the GskNglCommandQueue to execute uniform
|
||||
* changes but only when they have changed from the current value.
|
||||
*/
|
||||
static inline void
|
||||
gsk_ngl_uniform_state_apply (GskNglUniformState *state,
|
||||
guint program,
|
||||
guint location,
|
||||
GskNglUniformInfo info)
|
||||
{
|
||||
guint index = gsk_ngl_uniform_state_fmix (program, location) % G_N_ELEMENTS (state->apply_hash);
|
||||
gconstpointer dataptr = GSK_NGL_UNIFORM_VALUE (state->values_buf, info.offset);
|
||||
|
||||
/* aligned, can treat as unsigned */
|
||||
if (*(guint *)&info == *(guint *)&state->apply_hash[index])
|
||||
return;
|
||||
|
||||
state->apply_hash[index] = info;
|
||||
|
||||
/* TODO: We could do additional comparisons here to make sure we are
|
||||
* changing state.
|
||||
*/
|
||||
|
||||
switch (info.format)
|
||||
{
|
||||
case GSK_NGL_UNIFORM_FORMAT_1F:
|
||||
glUniform1fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2F:
|
||||
glUniform2fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3F:
|
||||
glUniform3fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4F:
|
||||
glUniform4fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1FV:
|
||||
glUniform1fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2FV:
|
||||
glUniform2fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3FV:
|
||||
glUniform3fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4FV:
|
||||
glUniform4fv (location, info.array_count, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1I:
|
||||
case GSK_NGL_UNIFORM_FORMAT_TEXTURE:
|
||||
glUniform1iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_2I:
|
||||
glUniform2iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_3I:
|
||||
glUniform3iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_4I:
|
||||
glUniform4iv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_1UI:
|
||||
glUniform1uiv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_MATRIX: {
|
||||
float mat[16];
|
||||
graphene_matrix_to_float (dataptr, mat);
|
||||
glUniformMatrix4fv (location, 1, GL_FALSE, mat);
|
||||
#if 0
|
||||
/* TODO: If Graphene can give us a peek here on platforms
|
||||
* where the format is float[16] (most/all x86_64?) then
|
||||
* We can avoid the SIMD operation to convert the format.
|
||||
*/
|
||||
G_STATIC_ASSERT (sizeof (graphene_matrix_t) == 16*4);
|
||||
glUniformMatrix4fv (location, 1, GL_FALSE, dataptr);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_COLOR:
|
||||
glUniform4fv (location, 1, dataptr);
|
||||
break;
|
||||
|
||||
case GSK_NGL_UNIFORM_FORMAT_ROUNDED_RECT:
|
||||
glUniform4fv (location, 3, dataptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GSK_NGL_UNIFORM_STATE_PRIVATE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user