[Bf-blender-cvs] [d7d32ad4521] blender2.8: Gawain: Simplify / optimize the shader interface.

Clément Foucault noreply at git.blender.org
Fri Oct 6 01:57:13 CEST 2017


Commit: d7d32ad45217736c677edd22906d980d03aeb175
Author: Clément Foucault
Date:   Thu Oct 5 18:26:50 2017 +0200
Branches: blender2.8
https://developer.blender.org/rBd7d32ad45217736c677edd22906d980d03aeb175

Gawain: Simplify / optimize the shader interface.

This changes quite a few things:
- Drops the allocation of inputs as a chunk.
- Merge the linked list system into the Gwn_ShaderInput.
- Put name buffer into another memory block, easily resizable.
- Use offset instead of char* to direct to input name.
- Add only requested uniforms dynamicaly to the Shader Interface.

This drops some minor optimisation and use a bit more memory for small shaders (which are fixed count).
But this saves a lot of memory when using UBOs because the names and the Gwn_ShaderInput were alloc'ed for every UBO variable.
This also reduce the Shader Interface initial generation.
The lookup time is left unchanged.

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

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 4c3d44cadbd..1411bd24e7c 100644
--- a/intern/gawain/gawain/gwn_shader_interface.h
+++ b/intern/gawain/gawain/gwn_shader_interface.h
@@ -33,28 +33,24 @@ typedef enum {
 } Gwn_UniformBuiltin;
 
 typedef struct Gwn_ShaderInput {
-	const char* name;
+	struct Gwn_ShaderInput* next;
+	uint32_t name_offset;
 	unsigned name_hash;
-	GLenum gl_type;
 	Gwn_UniformBuiltin builtin_type; // only for uniform inputs
-	GLint size;
+	GLenum gl_type; // only for attrib inputs
+	GLint size; // only for attrib inputs
 	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];
+	GLint program;
+	uint32_t name_buffer_offset;
+	Gwn_ShaderInput* attrib_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS];
+	Gwn_ShaderInput* uniform_buckets[GWN_NUM_SHADERINTERFACE_BUCKETS];
 	Gwn_ShaderInput* builtin_uniforms[GWN_NUM_UNIFORMS];
-	Gwn_ShaderInput inputs[0]; // dynamic size, uniforms followed by attribs
+	char* name_buffer;
 } Gwn_ShaderInterface;
 
 Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program_id);
diff --git a/intern/gawain/src/gwn_shader_interface.c b/intern/gawain/src/gwn_shader_interface.c
index 5305dae9a9a..292e2148c8f 100644
--- a/intern/gawain/src/gwn_shader_interface.c
+++ b/intern/gawain/src/gwn_shader_interface.c
@@ -14,7 +14,6 @@
 #include <stddef.h>
 #include <string.h>
 
-#define SUPPORT_LEGACY_GLSL 1
 #define DEBUG_SHADER_INTERFACE 0
 
 #if DEBUG_SHADER_INTERFACE
@@ -62,29 +61,29 @@ GWN_INLINE unsigned hash_string(const char *str)
 	return i;
 	}
 
-GWN_INLINE void set_input_name(Gwn_ShaderInput* input, const char* name)
+GWN_INLINE void set_input_name(Gwn_ShaderInterface* shaderface, Gwn_ShaderInput* input,
+                               const char* name, uint32_t name_len)
 	{
-	input->name = name;
+	input->name_offset = shaderface->name_buffer_offset;
 	input->name_hash = hash_string(name);
+	shaderface->name_buffer_offset += name_len + 1; // include NULL terminator
 	}
 
 GWN_INLINE void shader_input_to_bucket(Gwn_ShaderInput* input,
-                                       Gwn_ShaderInput_Entry* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
+                                       Gwn_ShaderInput* 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;
+	input->next = buckets[bucket_index];
+	buckets[bucket_index] = input;
 	}
 
-GWN_INLINE Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput_Entry* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS],
-                                           const char *name)
+GWN_INLINE const Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS],
+                                           const char *name_buffer, 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)
+	const Gwn_ShaderInput* input = buckets[bucket_index];
+	if (input == NULL)
 		{
 			// Requested uniform is not found at all.
 			return NULL;
@@ -92,168 +91,121 @@ GWN_INLINE Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput_Entry* const buckets[
 	// 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 (input->next == NULL)
 		{
-			if (name_hash == entry->shader_input->name_hash)
+			if (name_hash == input->name_hash)
 				{
 #if TRUST_NO_ONE
-				assert(match(entry->shader_input->name, name));
+				assert(match(name_buffer + input->name_offset, name));
 #endif
-				return entry->shader_input;
+				return input;
 				}
 			return NULL;
 		}
 	// Work through possible collisions.
-	while (entry != NULL)
+	const Gwn_ShaderInput* next = input;
+	while (next != 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)
+		input = next;
+		next = input->next;
+
+		if (input->name_hash != name_hash)
 			{
-				continue;
+			continue;
 			}
-		if (match(uniform->name, name))
+		if (match(name_buffer + input->name_offset, name))
 			{
-			return uniform;
+			return input;
 			}
 		}
 	return NULL; // not found
 	}
 
-GWN_INLINE void buckets_free(Gwn_ShaderInput_Entry* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
+GWN_INLINE void buckets_free(Gwn_ShaderInput* 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 *input = buckets[bucket_index];
+		while (input != NULL)
 			{
-			Gwn_ShaderInput_Entry *entry_next = entry->next;
-			free(entry);
-			entry = entry_next;
+			Gwn_ShaderInput *input_next = input->next;
+			free(input);
+			input = input_next;
 			}
 		}
 	}
 
 // keep these in sync with Gwn_UniformBuiltin order
-#define FIRST_MAT4_UNIFORM GWN_UNIFORM_MODELVIEW
-#define LAST_MAT4_UNIFORM GWN_UNIFORM_PROJECTION_INV
+#define FIRST_UNIFORM GWN_UNIFORM_MODELVIEW
+#define LAST_UNIFORM GWN_UNIFORM_COLOR
 
 static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name)
 	{
 	// TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types
 
-	// detect built-in uniforms (gl_type and name must match)
-	// if a match is found, use BuiltinUniform_name so name buffer space can be reclaimed
-	switch (input->gl_type)
+	// detect built-in uniforms (name must match)
+	for (Gwn_UniformBuiltin u = FIRST_UNIFORM; u <= LAST_UNIFORM; ++u)
 		{
-		case GL_FLOAT_MAT4:
-			for (Gwn_UniformBuiltin u = FIRST_MAT4_UNIFORM; u <= LAST_MAT4_UNIFORM; ++u)
-				{
-				const char* builtin_name = BuiltinUniform_name(u);
-				if (match(name, builtin_name))
-					{
-					set_input_name(input, builtin_name);
-					input->builtin_type = u;
-					return true;
-					}
-				}
-			break;
-		case GL_FLOAT_MAT3:
+		const char* builtin_name = BuiltinUniform_name(u);
+		if (match(name, builtin_name))
 			{
-			const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_NORMAL);
-			if (match(name, builtin_name))
-				{
-				set_input_name(input, builtin_name);
-				input->builtin_type = GWN_UNIFORM_NORMAL;
-				return true;
-				}
+			input->builtin_type = u;
+			return true;
 			}
-			break;
-		case GL_FLOAT_VEC4:
-			{
-			const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_COLOR);
-			if (match(name, builtin_name))
-				{
-				set_input_name(input, builtin_name);
-				input->builtin_type = GWN_UNIFORM_COLOR;
-				return true;
-				}
-			}
-			break;
-		default:
-			;
-		} 
+		}
 
 	input->builtin_type = GWN_UNIFORM_CUSTOM;
 	return false;
 	}
 
-Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program)
+static const Gwn_ShaderInput* add_uniform(Gwn_ShaderInterface* shaderface, const char* name)
 	{
-#if DEBUG_SHADER_INTERFACE
-	printf("%s {\n", __func__); // enter function
-#endif
+		Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput));
 
-	GLint uniform_ct, attrib_ct;
-	glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_ct);
-	glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attrib_ct);
-	const GLint input_ct = uniform_ct + attrib_ct;
+		input->location = glGetUniformLocation(shaderface->program, name);
 
-	GLint max_uniform_name_len, max_attrib_name_len;
-	glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
-	glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len);
-	const uint32_t name_buffer_len = uniform_ct * max_uniform_name_len + attrib_ct * max_attrib_name_len;
+		unsigned name_len = strlen(name);
+		shaderface->name_buffer = realloc(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); // include NULL terminator
+		char* name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset;
+		strcpy(name_buffer, name);
 
-	// allocate enough space for input counts, details for each input, and a buffer for name strings
-	Gwn_ShaderInterface* shaderface = calloc(1, offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput) + name_buffer_len);
-	shaderface->uniform_ct = uniform_ct;
-	shaderface->attrib_ct = attrib_ct;
+		set_input_name(shaderface, input, name, name_len);
+		setup_builtin_uniform(input, name);
 
-	char* name_buffer = (char*)shaderface + offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput);
-	uint32_t name_buffer_offset = 0;
-
-	for (uint32_t i = 0; i < uniform_ct; ++i)
-		{
-		Gwn_ShaderInput* input = shaderface->inputs + i;
-		GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
-		char* name = name_buffer + name_buffer_offset;
-		GLsizei name_len = 0;
-
-		glGetActiveUniform(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
-
-		input->location = glGetUniformLocation(program, name);
-
-#if SUPPORT_LEGACY_GLSL
-		if (input->location != -1)
+		shader_input_to_bucket(input, shaderface->uniform_buckets);
+		if (input->builtin_type != GWN_UNIFORM_NONE &&
+		    input->builtin_type != GWN_UNIFORM_CUSTOM)
 			{
-#elif TRUST_NO_ONE
-			assert(input->location != -1);
-#endif
-
-			if (setup_builtin_uniform(input, name))
-				; // reclaim space from name buffer (don't advance offset)
-			else
-				{
-				set_input_name(input, name);
-				name_buffer_offset += name_len + 1; // include NULL termi

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list