From 89d81ab16c05818b290ed735c1343d3abde449bf Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 25 Jan 2011 10:41:20 -0800 Subject: [PATCH] glsl: Calcluate Mesa state slots in front-end instead of back-end This should be the last bit of infrastructure changes before generating GLSL IR for assembly shaders. This commit leaves some odd code formatting in ir_to_mesa and brw_fs. This was done to minimize whitespace changes / reindentation in some loops. The following commit will restore formatting sanity. Reviewed-by: Eric Anholt Reviewed-by: Chad Versace --- src/glsl/ir.h | 26 +++++++++++++++++ src/glsl/ir_clone.cpp | 12 ++++++++ src/glsl/ir_variable.cpp | 46 +++++++++++++++++++++++++++-- src/glsl/linker.cpp | 13 +++++++++ src/mesa/drivers/dri/i965/brw_fs.cpp | 37 ++++-------------------- src/mesa/program/ir_to_mesa.cpp | 56 +++++++++++------------------------- 6 files changed, 117 insertions(+), 73 deletions(-) diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 39d4ebc..a419843 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -253,6 +253,16 @@ enum ir_depth_layout { const char* depth_layout_string(ir_depth_layout layout); +/** + * Description of built-in state associated with a uniform + * + * \sa ir_variable::state_slots + */ +struct ir_state_slot { + int tokens[5]; + int swizzle; +}; + class ir_variable : public ir_instruction { public: ir_variable(const struct glsl_type *, const char *, ir_variable_mode); @@ -386,6 +396,22 @@ public: int location; /** + * Built-in state that backs this uniform + * + * Once set at variable creation, \c state_slots must remain invariant. + * This is because, ideally, this array would be shared by all clones of + * this variable in the IR tree. In other words, we'd really like for it + * to be a fly-weight. + * + * If the variable is not a uniform, \c num_state_slots will be zero and + * \c state_slots will be \c NULL. + */ + /*@{*/ + unsigned num_state_slots; /**< Number of state slots used */ + ir_state_slot *state_slots; /**< State descriptors. */ + /*@}*/ + + /** * Emit a warning if this variable is accessed. */ const char *warn_extension; diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index 2c0574d..069bb85 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -53,6 +53,18 @@ ir_variable::clone(void *mem_ctx, struct hash_table *ht) const var->origin_upper_left = this->origin_upper_left; var->pixel_center_integer = this->pixel_center_integer; var->explicit_location = this->explicit_location; + + var->num_state_slots = this->num_state_slots; + if (this->state_slots) { + /* FINISHME: This really wants to use something like talloc_reference, but + * FINISHME: ralloc doesn't have any similar function. + */ + var->state_slots = ralloc_array(var, ir_state_slot, + this->num_state_slots); + memcpy(var->state_slots, this->state_slots, + sizeof(this->state_slots[0]) * var->num_state_slots); + } + if (this->explicit_location) var->location = this->location; diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp index c271525..f357717 100644 --- a/src/glsl/ir_variable.cpp +++ b/src/glsl/ir_variable.cpp @@ -327,7 +327,43 @@ static ir_variable * add_uniform(exec_list *instructions, glsl_symbol_table *symtab, const char *name, const glsl_type *type) { - return add_variable(instructions, symtab, name, type, ir_var_uniform, -1); + ir_variable *const uni = + add_variable(instructions, symtab, name, type, ir_var_uniform, -1); + + unsigned i; + for (i = 0; _mesa_builtin_uniform_desc[i].name != NULL; i++) { + if (strcmp(_mesa_builtin_uniform_desc[i].name, name) == 0) { + break; + } + } + + assert(_mesa_builtin_uniform_desc[i].name != NULL); + const struct gl_builtin_uniform_desc* const statevar = + &_mesa_builtin_uniform_desc[i]; + + const unsigned array_count = type->is_array() ? type->length : 1; + uni->num_state_slots = array_count * statevar->num_elements; + + ir_state_slot *slots = + ralloc_array(uni, ir_state_slot, uni->num_state_slots); + + uni->state_slots = slots; + + for (unsigned a = 0; a < array_count; a++) { + for (unsigned j = 0; j < statevar->num_elements; j++) { + struct gl_builtin_uniform_element *element = &statevar->elements[j]; + + memcpy(slots->tokens, element->tokens, sizeof(element->tokens)); + if (type->is_array()) { + slots->tokens[1] = a; + } + + slots->swizzle = element->swizzle; + slots++; + } + } + + return uni; } static void @@ -341,8 +377,12 @@ add_builtin_variable(exec_list *instructions, glsl_symbol_table *symtab, assert(type != NULL); - add_variable(instructions, symtab, proto->name, type, proto->mode, - proto->slot); + if (proto->mode == ir_var_uniform) { + add_uniform(instructions, symtab, proto->name, type); + } else { + add_variable(instructions, symtab, proto->name, type, proto->mode, + proto->slot); + } } static void diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 7db5c5e..1749235 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -994,6 +994,19 @@ update_array_sizes(struct gl_shader_program *prog) } if (size + 1 != var->type->fields.array->length) { + /* If this is a built-in uniform (i.e., it's backed by some + * fixed-function state), adjust the number of state slots to + * match the new array size. The number of slots per array entry + * is not known. It seems saft to assume that the total number of + * slots is an integer multiple of the number of array elements. + * Determine the number of slots per array element by dividing by + * the old (total) size. + */ + if (var->num_state_slots > 0) { + var->num_state_slots = (size + 1) + * (var->num_state_slots / var->type->length); + } + var->type = glsl_type::get_array_instance(var->type->fields.array, size + 1); /* FINISHME: We should update the types of array diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index bdf0523..cf05fb4 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -399,41 +399,16 @@ fs_visitor::setup_uniform_values(int loc, const glsl_type *type) void fs_visitor::setup_builtin_uniform_values(ir_variable *ir) { - const struct gl_builtin_uniform_desc *statevar = NULL; - - for (unsigned int i = 0; _mesa_builtin_uniform_desc[i].name; i++) { - statevar = &_mesa_builtin_uniform_desc[i]; - if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0) - break; - } - - if (!statevar->name) { - fail("Failed to find builtin uniform `%s'\n", ir->name); - return; - } - - int array_count; - if (ir->type->is_array()) { - array_count = ir->type->length; - } else { - array_count = 1; - } - - for (int a = 0; a < array_count; a++) { - for (unsigned int i = 0; i < statevar->num_elements; i++) { - struct gl_builtin_uniform_element *element = &statevar->elements[i]; - int tokens[STATE_LENGTH]; - - memcpy(tokens, element->tokens, sizeof(element->tokens)); - if (ir->type->is_array()) { - tokens[1] = a; - } + const ir_state_slot *const slots = ir->state_slots; + assert(ir->state_slots != NULL); + { + for (unsigned int i = 0; i < ir->num_state_slots; i++) { /* This state reference has already been setup by ir_to_mesa, * but we'll get the same index back here. */ int index = _mesa_add_state_reference(this->fp->Base.Parameters, - (gl_state_index *)tokens); + (gl_state_index *)slots[i].tokens); /* Add each of the unique swizzles of the element as a * parameter. This'll end up matching the expected layout of @@ -441,7 +416,7 @@ fs_visitor::setup_builtin_uniform_values(ir_variable *ir) */ int last_swiz = -1; for (unsigned int j = 0; j < 4; j++) { - int swiz = GET_SWZ(element->swizzle, j); + int swiz = GET_SWZ(slots[i].swizzle, j); if (swiz == last_swiz) break; last_swiz = swiz; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 17e0f99..4cca2b7 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -754,27 +754,8 @@ ir_to_mesa_visitor::visit(ir_variable *ir) if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) { unsigned int i; - const struct gl_builtin_uniform_desc *statevar; - - for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) { - if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0) - break; - } - - if (!_mesa_builtin_uniform_desc[i].name) { - fail_link(this->shader_program, - "Failed to find builtin uniform `%s'\n", ir->name); - return; - } - - statevar = &_mesa_builtin_uniform_desc[i]; - - int array_count; - if (ir->type->is_array()) { - array_count = ir->type->length; - } else { - array_count = 1; - } + const ir_state_slot *const slots = ir->state_slots; + assert(ir->state_slots != NULL); /* Check if this statevar's setup in the STATE file exactly * matches how we'll want to reference it as a @@ -782,21 +763,27 @@ ir_to_mesa_visitor::visit(ir_variable *ir) * temporary storage and hope that it'll get copy-propagated * out. */ - for (i = 0; i < statevar->num_elements; i++) { - if (statevar->elements[i].swizzle != SWIZZLE_XYZW) { + for (i = 0; i < ir->num_state_slots; i++) { + if (slots[i].swizzle != SWIZZLE_XYZW) { break; } } struct variable_storage *storage; ir_to_mesa_dst_reg dst; - if (i == statevar->num_elements) { + if (i == ir->num_state_slots) { /* We'll set the index later. */ storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1); this->variables.push_tail(storage); dst = ir_to_mesa_undef_dst; } else { + /* The variable_storage constructor allocates slots based on the size + * of the type. However, this had better match the number of state + * elements that we're going to copy into the new temporary. + */ + assert(ir->num_state_slots == type_size(ir->type)); + storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY, this->next_temp); this->variables.push_tail(storage); @@ -808,29 +795,20 @@ ir_to_mesa_visitor::visit(ir_variable *ir) } - for (int a = 0; a < array_count; a++) { - for (unsigned int i = 0; i < statevar->num_elements; i++) { - struct gl_builtin_uniform_element *element = &statevar->elements[i]; - int tokens[STATE_LENGTH]; - - memcpy(tokens, element->tokens, sizeof(element->tokens)); - if (ir->type->is_array()) { - tokens[1] = a; - } - + { + for (unsigned int i = 0; i < ir->num_state_slots; i++) { int index = _mesa_add_state_reference(this->prog->Parameters, - (gl_state_index *)tokens); + (gl_state_index *)slots[i].tokens); if (storage->file == PROGRAM_STATE_VAR) { if (storage->index == -1) { storage->index = index; } else { - assert(index == - (int)(storage->index + a * statevar->num_elements + i)); + assert(index == storage->index + (int)i); } } else { ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL); - src.swizzle = element->swizzle; + src.swizzle = slots[i].swizzle; ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src); /* even a float takes up a whole vec4 reg in a struct/array. */ dst.index++; @@ -838,7 +816,7 @@ ir_to_mesa_visitor::visit(ir_variable *ir) } } if (storage->file == PROGRAM_TEMPORARY && - dst.index != storage->index + type_size(ir->type)) { + dst.index != storage->index + ir->num_state_slots) { fail_link(this->shader_program, "failed to load builtin uniform `%s' (%d/%d regs loaded)\n", ir->name, dst.index - storage->index, -- 2.7.4