v2 : - Fix format issue thank to Brian Paul comments. - UBOs are now sent to program correctly. --- src/glsl/linker.cpp | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 191 insertions(+), 1 deletions(-)
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index ba81c59..7d85d4e 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -65,6 +65,7 @@ */ #include "main/core.h" +#include "main/hash.h" #include "glsl_symbol_table.h" #include "ir.h" #include "program.h" @@ -784,6 +785,61 @@ get_main_function_signature(gl_shader *sh) return NULL; } +/** + * TODO : write the function + * This function should check consistency between 2 UBO having same name + * from different shaders : + * - Same layout + * - Same variables (name and type) in same order + * - Same matrix layout (ie row/column major) + */ +static bool validate_separate_ubo(const ubo& first, const ubo& second) +{ + return true; +} + +/** + * At intrastage, when several shaders of same type are merged in a single one, + * this function generates UBOs of the newly created shader from them and + * performs necessary check. + */ +static void merge_intrastage_ubo ( gl_shader_program* prog, struct gl_shader& merged_shader, + struct gl_shader **shader_list, unsigned num_shaders) +{ + hash_table *ht = hash_table_ctor(0, hash_table_string_hash, + hash_table_string_compare); + merged_shader.UBOCount = 0; + unsigned& index = merged_shader.UBOCount; + if(!merged_shader.UniformBufferObjects) + merged_shader.UniformBufferObjects = (struct ubo*) malloc(MAX_UBO_IN_SHADER * sizeof(struct ubo)); + for (unsigned shad_id=0; shad_id < num_shaders; shad_id++) + { + for(unsigned ubo_id=0; ubo_id < shader_list[shad_id]->UBOCount; ubo_id++) + { + ubo* current_ubo = &(shader_list[shad_id]->UniformBufferObjects[ubo_id]); + ubo* sh = (ubo*) hash_table_find(ht,current_ubo->Name); + if(!sh) + { + ubo& tmp = merged_shader.UniformBufferObjects[index]; + tmp = *current_ubo; + tmp.Name = strdup(current_ubo->Name); + tmp.StorageLayout = (UBOVariableInfo*) malloc(tmp.NumberOfVariables * sizeof(UBOVariableInfo)); + for (unsigned i = 0; i < current_ubo->NumberOfVariables; i++) { + tmp.StorageLayout[i] = current_ubo->StorageLayout[i]; + tmp.StorageLayout[i].Name = strdup(current_ubo->StorageLayout[i].Name); + } + hash_table_insert(ht,current_ubo,current_ubo->Name); + index++; + } + else + { + if(!validate_separate_ubo(*current_ubo,*sh)) + linker_error(prog,"Uniform Buffer Object '%s definition mismatch",sh->Name); + } + } + } + hash_table_dtor(ht); +} /** * Combine a group of shaders for a single stage to generate a linked shader @@ -955,6 +1011,8 @@ link_intrastage_shaders(void *mem_ctx, v.run(linked->ir); } + merge_intrastage_ubo(prog,*linked,shader_list,num_shaders); + return linked; } @@ -1134,7 +1192,7 @@ assign_uniform_locations(struct gl_shader_program *prog) foreach_list(node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); - if ((var == NULL) || (var->mode != ir_var_uniform)) + if ((var == NULL) || (var->mode != ir_var_uniform) || var->UBO) continue; if (strncmp(var->name, "gl_", 3) == 0) { @@ -1176,12 +1234,142 @@ assign_uniform_locations(struct gl_shader_program *prog) free(node); } + /* UBO : mirror the setup to the variable and set program scope UBO variable */ + prog->IndexedUniformsInUBO = (struct UBOVariableInfo**) malloc(MAX_UBO_IN_SHADER * MAX_VARIABLES_IN_UBO * sizeof(struct UBOVariableInfo*)); + idx = 0; + + for(unsigned i = 0; i < prog->UBOCount; i++) { + const ubo* current_ubo = prog->UniformBufferObject[i]; + if(!current_ubo) + continue; + for (unsigned j = 0;j < current_ubo->NumberOfVariables; j++) { + + for (unsigned k = 0; k < MESA_SHADER_TYPES; k++) { + + gl_shader* shader = prog->_LinkedShaders[k]; + if(shader==NULL) + continue; + ir_variable* var = shader->symbols->get_variable(current_ubo->StorageLayout[j].Name); + if(var==NULL) + continue; + var->UBO = &(current_ubo->StorageLayout[j]); + var->location = 0; + + } + prog->IndexedUniformsInUBO[idx] = &(current_ubo->StorageLayout[j]); + current_ubo->StorageLayout[j].UBO = prog->UniformBufferObject[i]; + idx++; + } + } + prog->UBOVariableCount = idx; + hash_table_dtor(ht); prog->Uniforms = ul; } + +/** + * This function sets offset of UBO elements according to + * standard packing rule from GL_ARB_Uniform_Buffer_Object spec. + * TODO : compute stride + */ +static void set_standard_uniform_block_layout(ubo* prog_ubo,GLenum shaderType) +{ + exec_list uniforms; + unsigned total_uniforms = 0; + hash_table *ht = hash_table_ctor(32, hash_table_string_hash, + hash_table_string_compare); + void *mem_ctx = ralloc_context(NULL); + + unsigned next_position = 0; + + for(unsigned i=0;i<prog_ubo->NumberOfVariables;i++) { + UBOVariableInfo& var = prog_ubo->StorageLayout[i]; + + add_uniform(mem_ctx, &uniforms, ht, var.Name, var.Type, + shaderType, + &next_position, &total_uniforms); + } + + ralloc_free(mem_ctx); + + unsigned idx = 0; + uniform_node *next; + for (uniform_node *node = (uniform_node *) uniforms.head + ; node->link.next != NULL + ; node = next) { + next = (uniform_node *) node->link.next; + + node->link.remove(); + switch(shaderType) { + case GL_VERTEX_SHADER: + prog_ubo->StorageLayout[idx].Offset = node->u->VertPos; + break; + case GL_FRAGMENT_SHADER: + prog_ubo->StorageLayout[idx].Offset = node->u->FragPos; + break; + case GL_GEOMETRY_SHADER: + prog_ubo->StorageLayout[idx].Offset = node->u->GeomPos; + break; + default: + break; + } + idx++; + + free(node->u); + free(node); + } + + hash_table_dtor(ht); +} + +/** + * At interstage this function extract UBOs from shaders to populate programs UBOs + * It also performs checks coherency between UBOs with same name. + */ +static void merge_interstage_ubo(gl_shader_program* prog) +{ + hash_table *ht = hash_table_ctor(0, hash_table_string_hash, + hash_table_string_compare); + prog->UBOCount = 0; + + unsigned index = 0; + for (unsigned k = 0; k < MESA_SHADER_TYPES; k++) { + gl_shader* shader = prog->_LinkedShaders[k]; + if(shader==NULL) + continue; + + for(unsigned ubo_idx = 0; ubo_idx < shader->UBOCount; ubo_idx++) { + + ubo* current_ubo = &(shader->UniformBufferObjects[ubo_idx]); + ubo* ubo_model = (ubo*) hash_table_find(ht,current_ubo->Name); + if(!ubo_model) { + // Maps pointer + prog->UniformBufferObject[index] = current_ubo; + current_ubo->BoundBuffer = -1; + current_ubo->Index = index; + + // Set variables info in current_ubo + // Todo : implementation dependant packing rules + set_standard_uniform_block_layout(current_ubo,shader->Type); + index++; + + prog->UBOCount = index; + hash_table_insert(ht,current_ubo,current_ubo->Name); + } + else { + if(!validate_separate_ubo(*current_ubo,*ubo_model)) + linker_error(prog,"Uniform Buffer Object '%s definition mismatch",ubo_model->Name); + } + } + } + + hash_table_dtor(ht); +} + + /** * Find a contiguous set of available bits in a bitmask. * @@ -1730,6 +1918,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) update_array_sizes(prog); + merge_interstage_ubo(prog); + assign_uniform_locations(prog); /* FINISHME: The value of the max_attribute_index parameter is -- 1.7.6.4 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev