[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