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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to