summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Hergert <chergert@redhat.com>2021-03-12 10:16:52 -0800
committerChristian Hergert <chergert@redhat.com>2021-03-12 11:22:59 -0800
commit0b7d8e19c3b4cffe450c0e9a31ea4e0d8419b65b (patch)
tree572b5066d63c0501b2b6400a3fa3712dab458075
parent7f292d34bd1841df1ea214037d0549b256f315da (diff)
downloadgtk+-0b7d8e19c3b4cffe450c0e9a31ea4e0d8419b65b.tar.gz
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.
-rw-r--r--gsk/ngl/gsknglcommandqueue.c95
-rw-r--r--gsk/ngl/gskngluniformstate.c4
-rw-r--r--gsk/ngl/gskngluniformstateprivate.h132
3 files changed, 137 insertions, 94 deletions
diff --git a/gsk/ngl/gsknglcommandqueue.c b/gsk/ngl/gsknglcommandqueue.c
index 9426c199b1..f0aaf1806f 100644
--- a/gsk/ngl/gsknglcommandqueue.c
+++ b/gsk/ngl/gsknglcommandqueue.c
@@ -732,98 +732,6 @@ gsk_ngl_command_queue_delete_program (GskNglCommandQueue *self,
}
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,
guint width,
@@ -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;
}
diff --git a/gsk/ngl/gskngluniformstate.c b/gsk/ngl/gskngluniformstate.c
index 9b896e7d1a..c6fc9b5b67 100644
--- a/gsk/ngl/gskngluniformstate.c
+++ b/gsk/ngl/gskngluniformstate.c
@@ -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
diff --git a/gsk/ngl/gskngluniformstateprivate.h b/gsk/ngl/gskngluniformstateprivate.h
index 1385f93dac..6185087a68 100644
--- a/gsk/ngl/gskngluniformstateprivate.h
+++ b/gsk/ngl/gskngluniformstateprivate.h
@@ -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 */