--- src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 375 +++++++++++++++++++--------- 1 files changed, 262 insertions(+), 113 deletions(-)
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index 2825180..ab93a65 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -526,6 +526,205 @@ variable_store::optimise_access(void) reindex_rvalue(); } +/** + * This visitor will retrieve offset and expression of indirect addressing + * from any ir_dereference* + */ +class glsl_to_tgsi_dereference_to_address : public ir_visitor { +public: + ir_constant *possible_constant; + unsigned offset; + struct { + unsigned stride; + unsigned max_index; + ir_rvalue *expr; + } indirect_address_expression[8]; + unsigned indirect_address_expression_count; + variable_store &store; + glsl_to_tgsi_dereference_to_address(variable_store&); + void* mem_ctx; + variable_storage *entry; + + void visit(class ir_dereference_variable *); + void visit(class ir_dereference_array *); + void visit(class ir_dereference_record *); + void visit(class ir_constant *); + + void visit(ir_variable *); + void visit(ir_function_signature *); + void visit(ir_function *); + void visit(ir_expression *); + void visit(ir_texture *); + void visit(ir_swizzle *); + void visit(ir_assignment *); + void visit(ir_call *); + void visit(ir_discard *); + void visit(ir_if *); + void visit(ir_loop *); + void visit(ir_loop_jump *); + void visit(ir_return *); +}; + +glsl_to_tgsi_dereference_to_address::glsl_to_tgsi_dereference_to_address(variable_store &s):possible_constant(NULL), indirect_address_expression_count(0), store(s), entry(NULL) +{ + +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_variable *ir) +{ + entry = store.find_variable_storage(ir->var); + ir_variable *var = ir->var; + + if (!entry) { + switch (var->mode) { + case ir_var_uniform: + entry = store.push(var, PROGRAM_UNIFORM, var->location); + break; + case ir_var_in: + case ir_var_inout: + /* The linker assigns locations for varyings and attributes, + * including deprecated builtins (like gl_Color), user-assign + * generic attributes (glBindVertexLocation), and + * user-defined varyings. + * + * FINISHME: We would hit this path for function arguments. Fix! + */ + assert(var->location != -1); + entry = store.push(var, PROGRAM_INPUT, var->location); + break; + case ir_var_out: + entry = store.push(var, PROGRAM_OUTPUT, var->location); + break; + case ir_var_system_value: + entry = store.push(var, PROGRAM_SYSTEM_VALUE, var->location); + break; + case ir_var_auto: + case ir_var_temporary: + entry = store.push(var); + break; + } + } + + if (!entry) { + printf("Failed to make storage for %s\n", var->name); + exit(1); + } + + offset = 0; +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_constant *ir) +{ + possible_constant = ir; + offset = 0; + return; +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_record *ir) +{ + unsigned int i; + const glsl_type *struct_type = ir->record->type; + ir->record->accept(this); + + for (i = 0; i < struct_type->length; i++) { + if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0) + break; + offset += type_size(struct_type->fields.structure[i].type); + } + return; +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_array *ir) +{ + ir_constant *index; + int element_size = type_size(ir->type); + ir->array->accept(this); + + index = ir->array_index->constant_expression_value(); + + if (index) { + offset += index->value.i[0] * element_size; + } else { + indirect_address_expression[indirect_address_expression_count].expr = ir->array_index; + indirect_address_expression[indirect_address_expression_count].stride = element_size; + if (ir->array->type->is_array()) { + indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->length; + } + else if (ir->array->type->is_matrix()) { + indirect_address_expression[indirect_address_expression_count].max_index = ir->array->type->components(); + } + + indirect_address_expression_count++; + } + return; +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_function *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_if *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_variable *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_discard *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_function_signature *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_expression *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_call *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_texture *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_loop *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_return *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_loop_jump *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_assignment *) +{ + assert(0); +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_swizzle *) +{ + assert(0); +} + + class glsl_to_tgsi_visitor : public ir_visitor { public: glsl_to_tgsi_visitor(); @@ -584,6 +783,8 @@ public: virtual void visit(ir_if *); /*@}*/ + void handle_dereference(ir_dereference *); + st_src_reg result; /** List of variable_storage */ @@ -2084,145 +2285,93 @@ glsl_to_tgsi_visitor::visit(ir_swizzle *ir) } void -glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir) +glsl_to_tgsi_visitor::handle_dereference(ir_dereference *ir) { - variable_storage *entry = find_variable_storage(ir->var); - ir_variable *var = ir->var; + glsl_to_tgsi_dereference_to_address secondary_visitor(store); + secondary_visitor.mem_ctx = mem_ctx; + ir->accept(&secondary_visitor); - if (!entry) { - switch (var->mode) { - case ir_var_uniform: - entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM, - var->location); - this->variables.push_tail(entry); - break; - case ir_var_in: - case ir_var_inout: - /* The linker assigns locations for varyings and attributes, - * including deprecated builtins (like gl_Color), user-assign - * generic attributes (glBindVertexLocation), and - * user-defined varyings. - * - * FINISHME: We would hit this path for function arguments. Fix! - */ - assert(var->location != -1); - entry = new(mem_ctx) variable_storage(var, - PROGRAM_INPUT, - var->location); - break; - case ir_var_out: - assert(var->location != -1); - entry = new(mem_ctx) variable_storage(var, - PROGRAM_OUTPUT, - var->location); - break; - case ir_var_system_value: - entry = new(mem_ctx) variable_storage(var, - PROGRAM_SYSTEM_VALUE, - var->location); - break; - case ir_var_auto: - case ir_var_temporary: - entry = new(mem_ctx) variable_storage(var, PROGRAM_TEMPORARY, - this->next_temp); - this->variables.push_tail(entry); - - next_temp += type_size(var->type); - break; - } + st_src_reg result; + if (secondary_visitor.possible_constant) { + secondary_visitor.possible_constant->accept(this); + result = this->result; - if (!entry) { - printf("Failed to make storage for %s\n", var->name); - exit(1); - } + } + else { + variable_storage *entry = secondary_visitor.entry; + result = st_src_reg(entry->file, entry->index, ir->type); } - this->result = st_src_reg(entry->file, entry->index, var->type); - if (!native_integers) - this->result.type = GLSL_TYPE_FLOAT; -} - -void -glsl_to_tgsi_visitor::visit(ir_dereference_array *ir) -{ - ir_constant *index; - st_src_reg src; - int element_size = type_size(ir->type); - - index = ir->array_index->constant_expression_value(); - - ir->array->accept(this); - src = this->result; - - if (index) { - src.index += index->value.i[0] * element_size; - } else { - /* Variable index array dereference. It eats the "vec4" of the - * base of the array and an index that offsets the TGSI register - * index. - */ - ir->array_index->accept(this); + result.index += secondary_visitor.offset; + if (secondary_visitor.indirect_address_expression_count > 0) { st_src_reg index_reg; - if (element_size == 1) { - index_reg = this->result; - } else { - index_reg = get_temp(native_integers ? - glsl_type::int_type : glsl_type::float_type); - - emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg), - this->result, st_src_reg_for_type(index_reg.type, element_size)); + if(secondary_visitor.entry) + secondary_visitor.entry->is_reladdressed = true; + else { + /* This is an ugly hack that should be properly handled when variable_store will also store immediates*/ + store.retrieve_anonymous_temp(result.index)->is_reladdressed = true; } - /* If there was already a relative address register involved, add the - * new and the old together to get the new offset. - */ - if (src.reladdr != NULL) { - st_src_reg accum_reg = get_temp(native_integers ? - glsl_type::int_type : glsl_type::float_type); + for (unsigned i = 0; i < secondary_visitor.indirect_address_expression_count; i++) { + secondary_visitor.indirect_address_expression[i].expr->accept(this); + unsigned element_size = secondary_visitor.indirect_address_expression[i].stride; - emit(ir, TGSI_OPCODE_ADD, st_dst_reg(accum_reg), - index_reg, *src.reladdr); + if (i == 0) { + if (element_size == 1) { + index_reg = this->result; + } else { + index_reg = store.get_temp(native_integers ? + glsl_type::int_type : glsl_type::float_type); - index_reg = accum_reg; + emit(ir, TGSI_OPCODE_MUL, st_dst_reg(index_reg), + this->result, st_src_reg_for_type(index_reg.type, element_size)); + } + } + else { + if (element_size == 1) { + emit(ir, TGSI_OPCODE_ADD, st_dst_reg(index_reg), + index_reg, this->result); + } + else { + emit(ir, TGSI_OPCODE_UMAD, st_dst_reg(index_reg), + this->result, st_src_reg_for_type(index_reg.type, element_size), index_reg); + } + } } - src.reladdr = ralloc(mem_ctx, st_src_reg); - memcpy(src.reladdr, &index_reg, sizeof(index_reg)); + result.reladdr = ralloc(mem_ctx, st_src_reg); + *(result.reladdr) = st_src_reg(index_reg); } + this->result = result; /* If the type is smaller than a vec4, replicate the last channel out. */ if (ir->type->is_scalar() || ir->type->is_vector()) - src.swizzle = swizzle_for_size(ir->type->vector_elements); + this->result.swizzle = swizzle_for_size(ir->type->vector_elements); else - src.swizzle = SWIZZLE_NOOP; + this->result.swizzle = SWIZZLE_NOOP; - this->result = src; + if (!native_integers) + this->result.type = GLSL_TYPE_FLOAT; } void -glsl_to_tgsi_visitor::visit(ir_dereference_record *ir) +glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir) { - unsigned int i; - const glsl_type *struct_type = ir->record->type; - int offset = 0; - - ir->record->accept(this); - - for (i = 0; i < struct_type->length; i++) { - if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0) - break; - offset += type_size(struct_type->fields.structure[i].type); - } + handle_dereference(ir); +} - /* If the type is smaller than a vec4, replicate the last channel out. */ - if (ir->type->is_scalar() || ir->type->is_vector()) - this->result.swizzle = swizzle_for_size(ir->type->vector_elements); - else - this->result.swizzle = SWIZZLE_NOOP; +void +glsl_to_tgsi_visitor::visit(ir_dereference_array *ir) +{ + handle_dereference(ir); +} - this->result.index += offset; +void +glsl_to_tgsi_visitor::visit(ir_dereference_record *ir) +{ + handle_dereference(ir); } /** -- 1.7.7 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev