v2: fix glsl-fs-uniform-array-4 piglit test v3: fix glsl-array-bound-02 piglit crash --- src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 466 ++++++++++++++++++---------- 1 files changed, 307 insertions(+), 159 deletions(-)
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index 59ecb52..2bfa622 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -293,6 +293,46 @@ public: void push(class variable_storage *); }; +/** + * 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; + ir_rvalue *expr; + } indirect_address_expression[8]; + unsigned indirect_address_expression_count; + variable_store &store; + int &next_temp; + glsl_to_tgsi_dereference_to_address(variable_store&,int&); + void* mem_ctx; + gl_register_file file; + + 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 *); +}; + + class glsl_to_tgsi_visitor : public ir_visitor { public: glsl_to_tgsi_visitor(); @@ -354,6 +394,8 @@ public: virtual void visit(ir_if *); /*@}*/ + void handle_dereference(ir_dereference *); + st_src_reg result; /** List of variable_storage */ @@ -491,6 +533,215 @@ num_inst_src_regs(unsigned opcode) return info->is_tex ? info->num_src - 1 : info->num_src; } +static int +type_size(const struct glsl_type *type) +{ + unsigned int i; + int size; + + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + if (type->is_matrix()) { + return type->matrix_columns; + } else { + /* Regardless of size of vector, it gets a vec4. This is bad + * packing for things like floats, but otherwise arrays become a + * mess. Hopefully a later pass over the code can pack scalars + * down if appropriate. + */ + return 1; + } + case GLSL_TYPE_ARRAY: + assert(type->length > 0); + return type_size(type->fields.array) * type->length; + case GLSL_TYPE_STRUCT: + size = 0; + for (i = 0; i < type->length; i++) { + size += type_size(type->fields.structure[i].type); + } + return size; + case GLSL_TYPE_SAMPLER: + /* Samplers take up one slot in UNIFORMS[], but they're baked in + * at link time. + */ + return 1; + default: + assert(0); + return 0; + } +} + +glsl_to_tgsi_dereference_to_address::glsl_to_tgsi_dereference_to_address(variable_store &s, int &t):possible_constant(0),indirect_address_expression_count(0),store(s),next_temp(t) +{ + +} + +void glsl_to_tgsi_dereference_to_address::visit(ir_dereference_variable *ir) +{ + variable_storage *entry = store.find_variable_storage(ir->var); + ir_variable *var = ir->var; + + if (!entry) { + switch (var->mode) { + case ir_var_uniform: + entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM, + var->location); + store.push(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); + store.push(entry); + + next_temp += type_size(var->type); + break; + } + + if (!entry) { + printf("Failed to make storage for %s\n", var->name); + exit(1); + } + } + offset = entry->index; + file = entry->file; + return; +} + +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; + 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); +} + glsl_to_tgsi_instruction * glsl_to_tgsi_visitor::emit(ir_instruction *ir, unsigned op, st_dst_reg dst, @@ -931,46 +1182,7 @@ glsl_to_tgsi_visitor::st_src_reg_for_type(int type, int val) return st_src_reg_for_float(val); } -static int -type_size(const struct glsl_type *type) -{ - unsigned int i; - int size; - switch (type->base_type) { - case GLSL_TYPE_UINT: - case GLSL_TYPE_INT: - case GLSL_TYPE_FLOAT: - case GLSL_TYPE_BOOL: - if (type->is_matrix()) { - return type->matrix_columns; - } else { - /* Regardless of size of vector, it gets a vec4. This is bad - * packing for things like floats, but otherwise arrays become a - * mess. Hopefully a later pass over the code can pack scalars - * down if appropriate. - */ - return 1; - } - case GLSL_TYPE_ARRAY: - assert(type->length > 0); - return type_size(type->fields.array) * type->length; - case GLSL_TYPE_STRUCT: - size = 0; - for (i = 0; i < type->length; i++) { - size += type_size(type->fields.structure[i].type); - } - return size; - case GLSL_TYPE_SAMPLER: - /* Samplers take up one slot in UNIFORMS[], but they're baked in - * at link time. - */ - return 1; - default: - assert(0); - return 0; - } -} /** * In the initial pass of codegen, we assign temporary numbers to @@ -1902,145 +2114,81 @@ 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 = store.find_variable_storage(ir->var); - ir_variable *var = ir->var; - - if (!entry) { - switch (var->mode) { - case ir_var_uniform: - entry = new(mem_ctx) variable_storage(var, PROGRAM_UNIFORM, - var->location); - store.push(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); - store.push(entry); - - next_temp += type_size(var->type); - break; - } + glsl_to_tgsi_dereference_to_address secondary_visitor(store,next_temp); + secondary_visitor.mem_ctx = mem_ctx; + ir->accept(&secondary_visitor); - if (!entry) { - printf("Failed to make storage for %s\n", var->name); - exit(1); - } + st_src_reg result; + if (secondary_visitor.possible_constant) { + secondary_visitor.possible_constant->accept(this); + result = this->result; + result.index += secondary_visitor.offset; + } + else { + result = st_src_reg(secondary_visitor.file,secondary_visitor.offset,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); - - 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 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); + if (secondary_visitor.indirect_address_expression_count > 0) { + 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; + st_src_reg index_reg; - 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 = 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); + } + } + result.reladdr = ralloc(mem_ctx, st_src_reg); + memcpy(result.reladdr, &index_reg, sizeof(index_reg)); } - - src.reladdr = ralloc(mem_ctx, st_src_reg); - memcpy(src.reladdr, &index_reg, sizeof(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