From: Dave Airlie <airl...@redhat.com> The state tracker never handled this properly, and it finally annoyed me for the second time so I decided to fix it properly.
This is inspired by the NIR sampler lowering code and I only realised NIR seems to do its deref ordering different to GLSL at the last minute, once I got that things got much easier. it fixes a bunch of tests in tests/spec/arb_gpu_shader5/execution/sampler_array_indexing/ It's rfc because I need to piglit it, and because I really am not sure if all of the code is required. Signed-off-by: Dave Airlie <airl...@redhat.com> --- src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 154 ++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 16 deletions(-) diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index b8182de..ddd0664 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -257,6 +257,7 @@ public: GLboolean cond_update; bool saturate; st_src_reg sampler; /**< sampler register */ + int sampler_base; int sampler_array_size; /**< 1-based size of sampler array, 1 if not array */ int tex_target; /**< One of TEXTURE_*_INDEX */ glsl_base_type tex_type; @@ -502,6 +503,18 @@ public: void emit_arl(ir_instruction *ir, st_dst_reg dst, st_src_reg src0); + void get_sampler_nonconst_offsets(ir_texture *ir, + unsigned *sampler_array_size, + unsigned *sampler_base, + unsigned *sampler_index, + st_src_reg *sampler_reg); + void calc_sampler_offsets(ir_texture *ir, + ir_dereference *tail, + unsigned *array_elements, + unsigned *sampler_index, + st_src_reg *indirect, + unsigned *location); + bool try_emit_mad(ir_expression *ir, int mul_operand); bool try_emit_mad_for_and_not(ir_expression *ir, @@ -3436,18 +3449,130 @@ glsl_to_tgsi_visitor::visit(ir_call *ir) this->result = entry->return_reg; } +static unsigned +glsl_get_length(const struct glsl_type *type) +{ + return type->is_matrix() ? type->matrix_columns : type->length; +} + +void +glsl_to_tgsi_visitor::calc_sampler_offsets(ir_texture *ir, + ir_dereference *tail, + unsigned *array_elements, + unsigned *sampler_index, + st_src_reg *indirect, + unsigned *location) +{ + switch (tail->ir_type) { + case ir_type_dereference_record: { + ir_dereference_record *deref_record = tail->as_dereference_record(); + const glsl_type *struct_type = deref_record->record->type; + int tmp = 0; + unsigned i; + + calc_sampler_offsets(ir, deref_record->record->as_dereference(), array_elements, sampler_index, indirect, location); + + for (i = 0; i < struct_type->length; i++) { + if (strcmp(struct_type->fields.structure[i].name, deref_record->field) == 0) + break; + } + if (i < struct_type->length) + tmp = struct_type->record_location_offset(i); + + *location += tmp; + break; + } + + case ir_type_dereference_array: { + ir_dereference_array *deref_arr = tail->as_dereference_array(); + ir_constant *index = deref_arr->array_index->constant_expression_value(); + bool next_is_record = (deref_arr->array->ir_type == ir_type_dereference_record); + + if (deref_arr->array->ir_type == ir_type_dereference_variable && ir->sampler == tail) { + ir_dereference_variable *deref_var = deref_arr->array->as_dereference_variable(); + *location += deref_var->var->data.location; + } + + if (index && deref_arr->array->ir_type == ir_type_dereference_variable) + *sampler_index += index->value.u[0] * *array_elements; + + if (!index || next_is_record) { + st_src_reg temp_reg; + st_dst_reg temp_dst; + + temp_reg = get_temp(glsl_type::uint_type); + temp_dst = st_dst_reg(temp_reg); + temp_dst.writemask = 1; + + if (!index) { + deref_arr->array_index->accept(this); + emit_asm(NULL, TGSI_OPCODE_MUL, temp_dst, this->result, st_src_reg_for_int(*array_elements)); + } else { + emit_asm(NULL, TGSI_OPCODE_MOV, temp_dst, st_src_reg_for_int(index->value.u[0])); + } + if (indirect->file == PROGRAM_UNDEFINED) + *indirect = temp_reg; + else { + temp_dst = st_dst_reg(*indirect); + temp_dst.writemask = 1; + emit_asm(NULL, TGSI_OPCODE_ADD, temp_dst, *indirect, temp_reg); + } + } + + *array_elements *= glsl_get_length(deref_arr->array->type); + + calc_sampler_offsets(ir, deref_arr->array->as_dereference(), array_elements, sampler_index, indirect, location); + break; + } + case ir_type_dereference_variable: { + if (ir->sampler == tail) { + ir_dereference_variable *deref_var = tail->as_dereference_variable(); + *location = deref_var->var->data.location; + } + break; + } + default: + break; + } +} + +void +glsl_to_tgsi_visitor::get_sampler_nonconst_offsets(ir_texture *ir, + unsigned *sampler_array_size, + unsigned *sampler_base, + unsigned *sampler_index, + st_src_reg *sampler_reg) +{ + unsigned location = 0; + GLuint shader = _mesa_program_enum_to_shader_stage(this->prog->Target); + st_src_reg indirect; + unsigned array_elements = 1; + + memset(&indirect, 0, sizeof(indirect)); + indirect.file = PROGRAM_UNDEFINED; + + calc_sampler_offsets(ir, ir->sampler, &array_elements, sampler_index, &indirect, &location); + + if (indirect.file != PROGRAM_UNDEFINED) { + sampler_reg->reladdr = ralloc(mem_ctx, st_src_reg); + *sampler_reg->reladdr = indirect; + } + *sampler_array_size = array_elements; + *sampler_base = this->shader_program->UniformStorage[location].opaque[shader].index; + *sampler_index += *sampler_base; +} + void glsl_to_tgsi_visitor::visit(ir_texture *ir) { st_src_reg result_src, coord, cube_sc, lod_info, projector, dx, dy; st_src_reg offset[MAX_GLSL_TEXTURE_OFFSET], sample_index, component; - st_src_reg levels_src; + st_src_reg levels_src, sampler_reg; st_dst_reg result_dst, coord_dst, cube_sc_dst; glsl_to_tgsi_instruction *inst = NULL; unsigned opcode = TGSI_OPCODE_NOP; const glsl_type *sampler_type = ir->sampler->type; - ir_rvalue *sampler_index = - _mesa_get_sampler_array_nonconst_index(ir->sampler); + unsigned sampler_array_size = 1, sampler_index = 0, sampler_base = 0; bool is_cube_array = false; unsigned i; @@ -3669,10 +3794,10 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) coord_dst.writemask = WRITEMASK_XYZW; } - if (sampler_index) { - sampler_index->accept(this); - emit_arl(ir, sampler_reladdr, this->result); - } + get_sampler_nonconst_offsets(ir, &sampler_array_size, &sampler_base, + &sampler_index, &sampler_reg); + if (sampler_reg.reladdr) + emit_arl(ir, sampler_reladdr, *sampler_reg.reladdr); if (opcode == TGSI_OPCODE_TXD) inst = emit_asm(ir, opcode, result_dst, coord, dx, dy); @@ -3705,16 +3830,13 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) if (ir->shadow_comparitor) inst->tex_shadow = GL_TRUE; - inst->sampler.index = _mesa_get_sampler_uniform_value(ir->sampler, - this->shader_program, - this->prog); - if (sampler_index) { + inst->sampler.index = sampler_index; + inst->sampler_array_size = sampler_array_size; + inst->sampler_base = sampler_base; + + if (sampler_reg.reladdr) { inst->sampler.reladdr = ralloc(mem_ctx, st_src_reg); memcpy(inst->sampler.reladdr, &sampler_reladdr, sizeof(sampler_reladdr)); - inst->sampler_array_size = - ir->sampler->as_dereference_array()->array->type->array_size(); - } else { - inst->sampler_array_size = 1; } if (ir->offset) { @@ -3915,7 +4037,7 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog) foreach_in_list(glsl_to_tgsi_instruction, inst, &v->instructions) { if (inst->info->is_tex) { for (int i = 0; i < inst->sampler_array_size; i++) { - unsigned idx = inst->sampler.index + i; + unsigned idx = inst->sampler_base + i; v->samplers_used |= 1 << idx; debug_assert(idx < (int)ARRAY_SIZE(v->sampler_types)); -- 2.5.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev