[Bf-blender-cvs] [bb9b8b13e58] blender2.8: Gawain: Lookup uniforms and attributes from buckets

Sergey Sharybin noreply at git.blender.org
Thu Oct 5 14:17:09 CEST 2017


Commit: bb9b8b13e582bc5bc961159e1e9c6d8d03cbff4c
Author: Sergey Sharybin
Date:   Wed Oct 4 17:36:52 2017 +0500
Branches: blender2.8
https://developer.blender.org/rBbb9b8b13e582bc5bc961159e1e9c6d8d03cbff4c

Gawain: Lookup uniforms and attributes from buckets

This way we reduce number of loops from look-over-all-inputs to
loop-over-collision, which is expected to be much less CPU ticks.

There is still possible optimization: use memory pool of some sort
to manage memory needed for hash entries, but that will only speedup
shader interface construction / deconstruction time.

There are also some trickery happening to speed up process even more
in the case there is no hash collisions detected when constructing
shader interface.

===================================================================

M	intern/gawain/gawain/gwn_shader_interface.h
M	intern/gawain/src/gwn_shader_interface.c

===================================================================

diff --git a/intern/gawain/gawain/gwn_shader_interface.h b/intern/gawain/gawain/gwn_shader_interface.h
index cb3aeb84239..a1d4d82e080 100644
--- a/intern/gawain/gawain/gwn_shader_interface.h
+++ b/intern/gawain/gawain/gwn_shader_interface.h
@@ -39,9 +39,18 @@ typedef struct Gwn_ShaderInput {
 	GLint location;
 } Gwn_ShaderInput;
 
+typedef struct Gwn_ShaderInput_Entry {
+	struct Gwn_ShaderInput_Entry* next;
+	Gwn_ShaderInput* shader_input;
+} Gwn_ShaderInput_Entry;
+
+#define GWN_NUM_SHADERINTERFACE_BUCKETS 1009
+
 typedef struct Gwn_ShaderInterface {
 	uint16_t uniform_ct;
 	uint16_t attrib_ct;
+	Gwn_ShaderInput_Entry* uniform_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS];
+	Gwn_ShaderInput_Entry* attrib_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS];
 	Gwn_ShaderInput inputs[0]; // dynamic size, uniforms followed by attribs
 } Gwn_ShaderInterface;
 
diff --git a/intern/gawain/src/gwn_shader_interface.c b/intern/gawain/src/gwn_shader_interface.c
index 697eb586e7b..076d0b71e15 100644
--- a/intern/gawain/src/gwn_shader_interface.c
+++ b/intern/gawain/src/gwn_shader_interface.c
@@ -67,6 +67,75 @@ GWN_INLINE void set_input_name(Gwn_ShaderInput* input, const char* name)
 	input->name_hash = hash_string(name);
 	}
 
+GWN_INLINE void shader_input_to_bucket(Gwn_ShaderInput* input,
+                                       Gwn_ShaderInput_Entry* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
+	{
+	Gwn_ShaderInput_Entry* entry = malloc(sizeof(Gwn_ShaderInput_Entry));
+	const unsigned bucket_index = input->name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS;
+	entry->next = buckets[bucket_index];
+	entry->shader_input = input;
+	buckets[bucket_index] = entry;
+	}
+
+GWN_INLINE Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput_Entry* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS],
+                                           const char *name)
+	{
+	const unsigned name_hash = hash_string(name);
+	const unsigned bucket_index = name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS;
+	const Gwn_ShaderInput_Entry* entry = buckets[bucket_index];
+	if (entry == NULL)
+		{
+			// Requested uniform is not found at all.
+			return NULL;
+		}
+	// Optimization bit: if there is no hash collision detected when constructing shader interface
+	// it means we can only request the single possible uniform. Surely, it's possible we request
+	// uniform which causes hash collision, but that will be detected in debug builds.
+	if (entry->next == NULL)
+		{
+			if (name_hash == entry->shader_input->name_hash)
+				{
+#if TRUST_NO_ONE
+				assert(match(entry->shader_input->name, name));
+#endif
+				return entry->shader_input;
+				}
+			return NULL;
+		}
+	// Work through possible collisions.
+	while (entry != NULL)
+		{
+		Gwn_ShaderInput* uniform = entry->shader_input;
+		entry = entry->next;
+#if SUPPORT_LEGACY_GLSL
+		if (uniform->name == NULL) continue;
+#endif
+		if (uniform->name_hash != name_hash)
+			{
+				continue;
+			}
+		if (match(uniform->name, name))
+			{
+			return uniform;
+			}
+		}
+	return NULL; // not found
+	}
+
+GWN_INLINE void buckets_free(Gwn_ShaderInput_Entry* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
+	{
+	for (unsigned bucket_index = 0; bucket_index < GWN_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index)
+		{
+		Gwn_ShaderInput_Entry *entry = buckets[bucket_index];
+		while (entry != NULL)
+			{
+			Gwn_ShaderInput_Entry *entry_next = entry->next;
+			free(entry);
+			entry = entry_next;
+			}
+		}
+	}
+
 // keep these in sync with Gwn_UniformBuiltin order
 #define FIRST_MAT4_UNIFORM GWN_UNIFORM_MODELVIEW
 #define LAST_MAT4_UNIFORM GWN_UNIFORM_PROJECTION_INV
@@ -240,35 +309,33 @@ Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program)
 			}
 		}
 
+	for (uint32_t i = 0; i < shaderface->uniform_ct; ++i)
+		{
+			Gwn_ShaderInput* input = &shaderface->inputs[i];
+			shader_input_to_bucket(input, shaderface->uniform_buckets);
+		}
+	for (uint32_t i = 0; i < shaderface->attrib_ct; ++i)
+		{
+			Gwn_ShaderInput* input = &shaderface->inputs[i + shaderface->uniform_ct];
+			shader_input_to_bucket(input, shaderface->attrib_buckets);
+		}
+
 	return shaderface;
 	}
 
 void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface)
 	{
-	// allocated as one chunk, so discard is simple
+	// Free memory used by buckets and has entries.
+	buckets_free(shaderface->uniform_buckets);
+	buckets_free(shaderface->attrib_buckets);
+	// Free memory used by shader interface by its self.
 	free(shaderface);
 	}
 
 const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name)
 	{
-	const unsigned name_hash = hash_string(name);
-	for (uint32_t i = 0; i < shaderface->uniform_ct; ++i)
-		{
-		const Gwn_ShaderInput* uniform = shaderface->inputs + i;
-
-#if SUPPORT_LEGACY_GLSL
-		if (uniform->name == NULL) continue;
-#endif
-
-		if (uniform->name_hash != name_hash) continue;
-
-		if (match(uniform->name, name))
-			return uniform;
-
-		// TODO: warn if we find a matching builtin, since these can be looked up much quicker --v
-		}
-
-	return NULL; // not found
+	// TODO: Warn if we find a matching builtin, since these can be looked up much quicker.
+	return buckets_lookup(shaderface->uniform_buckets, name);
 	}
 
 const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin)
@@ -291,21 +358,5 @@ const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInter
 
 const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name)
 	{
-	// attribs are stored after uniforms
-	const uint32_t input_ct = shaderface->uniform_ct + shaderface->attrib_ct;
-	const unsigned name_hash = hash_string(name);
-	for (uint32_t i = shaderface->uniform_ct; i < input_ct; ++i)
-		{
-		const Gwn_ShaderInput* attrib = shaderface->inputs + i;
-
-#if SUPPORT_LEGACY_GLSL
-		if (attrib->name == NULL) continue;
-#endif
-
-		if (attrib->name_hash != name_hash) continue;
-
-		if (match(attrib->name, name))
-			return attrib;
-		}
-	return NULL; // not found
+	return buckets_lookup(shaderface->attrib_buckets, name);
 	}



More information about the Bf-blender-cvs mailing list