X-Git-Url: https://git.libre-soc.org/?p=mesa.git;a=blobdiff_plain;f=src%2Fmesa%2Fstate_tracker%2Fst_glsl_to_tgsi.cpp;h=3dc685e71f7ff617a190b5875223c39e52975280;hp=aec53309172c563d6d405b6a2030718054ae0620;hb=9ed33383a5b1399315cd62f119234ee2332ee76f;hpb=f903bce8a649296f9d8a67a740942b2a80303c50 diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index aec53309172..3dc685e71f7 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -49,12 +49,9 @@ #include "tgsi/tgsi_info.h" #include "util/u_math.h" #include "util/u_memory.h" -#include "st_glsl_types.h" #include "st_program.h" #include "st_mesa_to_tgsi.h" #include "st_format.h" -#include "st_nir.h" -#include "st_shader_cache.h" #include "st_glsl_to_tgsi_temprename.h" #include "util/hash_table.h" @@ -66,6 +63,49 @@ #define MAX_GLSL_TEXTURE_OFFSET 4 +#ifndef NDEBUG +#include "util/u_atomic.h" +#include "util/simple_mtx.h" +#include +#include + +/* Prepare to make it possible to specify log file */ +static std::ofstream stats_log; + +/* Helper function to check whether we want to write some statistics + * of the shader conversion. + */ + +static simple_mtx_t print_stats_mutex = _SIMPLE_MTX_INITIALIZER_NP; + +static inline bool print_stats_enabled () +{ + static int stats_enabled = 0; + + if (!stats_enabled) { + simple_mtx_lock(&print_stats_mutex); + if (!stats_enabled) { + const char *stats_filename = getenv("GLSL_TO_TGSI_PRINT_STATS"); + if (stats_filename) { + bool write_header = std::ifstream(stats_filename).fail(); + stats_log.open(stats_filename, std::ios_base::out | std::ios_base::app); + stats_enabled = stats_log.good() ? 1 : -1; + if (write_header) + stats_log << "arrays,temps,temps in arrays,total,instructions\n"; + } else { + stats_enabled = -1; + } + } + simple_mtx_unlock(&print_stats_mutex); + } + return stats_enabled > 0; +} +#define PRINT_STATS(X) if (print_stats_enabled()) do { X; } while (false); +#else +#define PRINT_STATS(X) +#endif + + static unsigned is_precise(const ir_variable *ir) { if (!ir) @@ -194,6 +234,7 @@ public: int images_used; enum tgsi_texture_type image_targets[PIPE_MAX_SHADER_IMAGES]; enum pipe_format image_formats[PIPE_MAX_SHADER_IMAGES]; + bool image_wr[PIPE_MAX_SHADER_IMAGES]; bool indirect_addr_consts; int wpos_transform_const; @@ -204,6 +245,7 @@ public: bool has_tex_txf_lz; bool precise; bool need_uarl; + bool tg4_component_in_swizzle; variable_storage *find_variable_storage(ir_variable *var); @@ -242,6 +284,7 @@ public: virtual void visit(ir_call *); virtual void visit(ir_return *); virtual void visit(ir_discard *); + virtual void visit(ir_demote *); virtual void visit(ir_texture *); virtual void visit(ir_if *); virtual void visit(ir_emit_vertex *); @@ -249,7 +292,7 @@ public: virtual void visit(ir_barrier *); /*@}*/ - void visit_expression(ir_expression *, st_src_reg *) ATTRIBUTE_NOINLINE; + void ATTRIBUTE_NOINLINE visit_expression(ir_expression *, st_src_reg *); void visit_atomic_counter_intrinsic(ir_call *); void visit_ssbo_intrinsic(ir_call *); @@ -339,6 +382,7 @@ public: void copy_propagate(void); int eliminate_dead_code(void); + void split_arrays(void); void merge_two_dsts(void); void merge_registers(void); void renumber_registers(void); @@ -347,6 +391,8 @@ public: st_dst_reg *l, st_src_reg *r, st_src_reg *cond, bool cond_swap); + void print_stats(); + void *mem_ctx; }; @@ -734,6 +780,7 @@ glsl_to_tgsi_visitor::get_opcode(enum tgsi_opcode op, case7(ISHR, LAST, ISHR, USHR, LAST, I64SHR, U64SHR); case7(ATOMIMAX,LAST, ATOMIMAX,ATOMUMAX,LAST, LAST, LAST); case7(ATOMIMIN,LAST, ATOMIMIN,ATOMUMIN,LAST, LAST, LAST); + case7(ATOMUADD,ATOMFADD,ATOMUADD,ATOMUADD,LAST, LAST, LAST); casecomp(SEQ, FSEQ, USEQ, USEQ, DSEQ, U64SEQ, U64SEQ); casecomp(SNE, FSNE, USNE, USNE, DSNE, U64SNE, U64SNE); @@ -1018,7 +1065,7 @@ type_has_array_or_matrix(const glsl_type *type) if (type->is_array() || type->is_matrix()) return true; - if (type->is_record()) { + if (type->is_struct()) { for (unsigned i = 0; i < type->length; i++) { if (type_has_array_or_matrix(type->fields.structure[i].type)) { return true; @@ -1064,7 +1111,7 @@ glsl_to_tgsi_visitor::get_temp(const glsl_type *type) next_temp += type_size(type); } - if (type->is_array() || type->is_record()) { + if (type->is_array() || type->is_struct()) { src.swizzle = SWIZZLE_NOOP; } else { src.swizzle = swizzle_for_size(type->vector_elements); @@ -1088,11 +1135,6 @@ glsl_to_tgsi_visitor::find_variable_storage(ir_variable *var) void glsl_to_tgsi_visitor::visit(ir_variable *ir) { - if (strcmp(ir->name, "gl_FragCoord") == 0) { - this->prog->OriginUpperLeft = ir->data.origin_upper_left; - this->prog->PixelCenterInteger = ir->data.pixel_center_integer; - } - if (ir->data.mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) { unsigned int i; const ir_state_slot *const slots = ir->get_state_slots(); @@ -1227,6 +1269,10 @@ glsl_to_tgsi_visitor::try_emit_mad(ir_expression *ir, int mul_operand) st_src_reg a, b, c; st_dst_reg result_dst; + // there is no TGSI opcode for this + if (ir->type->is_integer_64()) + return false; + ir_expression *expr = ir->operands[mul_operand]->as_expression(); if (!expr || expr->operation != ir_binop_mul) return false; @@ -1526,17 +1572,6 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) emit_asm(ir, TGSI_OPCODE_DFRACEXP, undef_dst, result_dst, op[0]); break; - case ir_unop_noise: { - /* At some point, a motivated person could add a better - * implementation of noise. Currently not even the nvidia - * binary drivers do anything more than this. In any case, the - * place to do this is in the GL state tracker, not the poor - * driver. - */ - emit_asm(ir, TGSI_OPCODE_MOV, result_dst, st_src_reg_for_float(0.5)); - break; - } - case ir_binop_add: emit_asm(ir, TGSI_OPCODE_ADD, result_dst, op[0], op[1]); break; @@ -1903,11 +1938,13 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) emit_asm(ir, TGSI_OPCODE_NOT, result_dst, op[0]); break; } + /* fallthrough */ case ir_unop_u2f: if (native_integers) { emit_asm(ir, TGSI_OPCODE_U2F, result_dst, op[0]); break; } + /* fallthrough */ case ir_binop_lshift: case ir_binop_rshift: if (native_integers) { @@ -1929,16 +1966,19 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) emit_asm(ir, opcode, result_dst, op[0], count); break; } + /* fallthrough */ case ir_binop_bit_and: if (native_integers) { emit_asm(ir, TGSI_OPCODE_AND, result_dst, op[0], op[1]); break; } + /* fallthrough */ case ir_binop_bit_xor: if (native_integers) { emit_asm(ir, TGSI_OPCODE_XOR, result_dst, op[0], op[1]); break; } + /* fallthrough */ case ir_binop_bit_or: if (native_integers) { emit_asm(ir, TGSI_OPCODE_OR, result_dst, op[0], op[1]); @@ -2037,7 +2077,7 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) emit_asm(ir, TGSI_OPCODE_USHR, st_dst_reg(index_reg), offset, st_src_reg_for_int(4)); cbuf.reladdr = ralloc(mem_ctx, st_src_reg); - memcpy(cbuf.reladdr, &index_reg, sizeof(index_reg)); + *cbuf.reladdr = index_reg; } if (const_uniform_block) { @@ -2046,7 +2086,7 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) } else { /* Relative/variable constant buffer */ cbuf.reladdr2 = ralloc(mem_ctx, st_src_reg); - memcpy(cbuf.reladdr2, &op[0], sizeof(st_src_reg)); + *cbuf.reladdr2 = op[0]; } cbuf.has_index2 = true; @@ -2191,11 +2231,9 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) case ir_unop_get_buffer_size: { ir_constant *const_offset = ir->operands[0]->as_constant(); - int buf_base = ctx->st->has_hw_atomics - ? 0 : ctx->Const.Program[shader->Stage].MaxAtomicBuffers; st_src_reg buffer( PROGRAM_BUFFER, - buf_base + (const_offset ? const_offset->value.u[0] : 0), + const_offset ? const_offset->value.u[0] : 0, GLSL_TYPE_UINT); if (!const_offset) { buffer.reladdr = ralloc(mem_ctx, st_src_reg); @@ -2342,6 +2380,24 @@ glsl_to_tgsi_visitor::visit_expression(ir_expression* ir, st_src_reg *op) case ir_binop_carry: case ir_binop_borrow: case ir_unop_ssbo_unsized_array_length: + case ir_unop_atan: + case ir_binop_atan2: + case ir_unop_clz: + case ir_binop_add_sat: + case ir_binop_sub_sat: + case ir_binop_abs_sub: + case ir_binop_avg: + case ir_binop_avg_round: + case ir_binop_mul_32x16: + case ir_unop_f162f: + case ir_unop_f2f16: + case ir_unop_f2fmp: + case ir_unop_f162b: + case ir_unop_b2f16: + case ir_unop_i2i: + case ir_unop_i2imp: + case ir_unop_u2u: + case ir_unop_u2ump: /* This operation is not supported, or should have already been handled. */ assert(!"Invalid ir opcode in glsl_to_tgsi_visitor::visit()"); @@ -2357,7 +2413,7 @@ glsl_to_tgsi_visitor::visit(ir_swizzle *ir) { st_src_reg src; int i; - int swizzle[4]; + int swizzle[4] = {0}; /* Note that this is only swizzles in expressions, not those on the left * hand side of an assignment, which do write masking. See ir_assignment @@ -2670,6 +2726,42 @@ shrink_array_declarations(struct inout_decl *decls, unsigned count, } } + +static void +mark_array_io(struct inout_decl *decls, unsigned count, + GLbitfield64* usage_mask, + GLbitfield64 double_usage_mask, + GLbitfield* patch_usage_mask) +{ + unsigned i; + int j; + + /* Fix array declarations by removing unused array elements at both ends + * of the arrays. For example, mat4[3] where only mat[1] is used. + */ + for (i = 0; i < count; i++) { + struct inout_decl *decl = &decls[i]; + if (!decl->array_id) + continue; + + /* When not all entries of an array are accessed, we mark them as used + * here anyway, to ensure that the input/output mapping logic doesn't get + * confused. + * + * TODO This happens when an array isn't used via indirect access, which + * some game ports do (at least eON-based). There is an optimization + * opportunity here by replacing the array declaration with non-array + * declarations of those slots that are actually used. + */ + for (j = 0; j < (int)decl->size; ++j) { + if (decl->mesa_index >= VARYING_SLOT_PATCH0) + *patch_usage_mask |= BITFIELD64_BIT(decl->mesa_index - VARYING_SLOT_PATCH0 + j); + else + *usage_mask |= BITFIELD64_BIT(decl->mesa_index + j); + } + } +} + void glsl_to_tgsi_visitor::visit(ir_dereference_array *ir) { @@ -2681,12 +2773,12 @@ glsl_to_tgsi_visitor::visit(ir_dereference_array *ir) if (handle_bound_deref(ir->as_dereference())) return; - /* We only need the logic provided by st_glsl_storage_type_size() + /* We only need the logic provided by count_vec4_slots() * for arrays of structs. Indirect sampler and image indexing is handled * elsewhere. */ - int element_size = ir->type->without_array()->is_record() ? - st_glsl_storage_type_size(ir->type, var->data.bindless) : + int element_size = ir->type->without_array()->is_struct() ? + ir->type->count_vec4_slots(false, var->data.bindless) : type_size(ir->type); index = ir->array_index->constant_expression_value(ralloc_parent(ir)); @@ -2757,12 +2849,12 @@ glsl_to_tgsi_visitor::visit(ir_dereference_array *ir) if (is_2D) { src.reladdr2 = ralloc(mem_ctx, st_src_reg); - memcpy(src.reladdr2, &index_reg, sizeof(index_reg)); + *src.reladdr2 = index_reg; src.index2D = 0; src.has_index2 = true; } else { src.reladdr = ralloc(mem_ctx, st_src_reg); - memcpy(src.reladdr, &index_reg, sizeof(index_reg)); + *src.reladdr = index_reg; } } @@ -2791,7 +2883,7 @@ glsl_to_tgsi_visitor::visit(ir_dereference_record *ir) if (i == (unsigned) ir->field_idx) break; const glsl_type *member_type = struct_type->fields.structure[i].type; - offset += st_glsl_storage_type_size(member_type, var->data.bindless); + offset += member_type->count_vec4_slots(false, var->data.bindless); } /* If the type is smaller than a vec4, replicate the last channel out. */ @@ -2940,7 +3032,7 @@ glsl_to_tgsi_visitor::emit_block_mov(ir_assignment *ir, const struct glsl_type * st_dst_reg *l, st_src_reg *r, st_src_reg *cond, bool cond_swap) { - if (type->is_record()) { + if (type->is_struct()) { for (unsigned int i = 0; i < type->length; i++) { emit_block_mov(ir, type->fields.structure[i].type, l, r, cond, cond_swap); @@ -3128,7 +3220,7 @@ glsl_to_tgsi_visitor::visit(ir_constant *ir) * aggregate constant and move each constant value into it. If we * get lucky, copy propagation will eliminate the extra moves. */ - if (ir->type->is_record()) { + if (ir->type->is_struct()) { st_src_reg temp_base = get_temp(ir->type); st_dst_reg temp = st_dst_reg(temp_base); @@ -3365,7 +3457,9 @@ glsl_to_tgsi_visitor::visit_atomic_counter_intrinsic(ir_call *ir) resource = buffer; } else { - st_src_reg buffer(PROGRAM_BUFFER, location->data.binding, + st_src_reg buffer(PROGRAM_BUFFER, + prog->info.num_ssbos + + location->data.binding, GLSL_TYPE_ATOMIC_UINT); if (offset.file != PROGRAM_UNDEFINED) { @@ -3453,11 +3547,9 @@ glsl_to_tgsi_visitor::visit_ssbo_intrinsic(ir_call *ir) ir_rvalue *offset = ((ir_instruction *)param)->as_rvalue(); ir_constant *const_block = block->as_constant(); - int buf_base = st_context(ctx)->has_hw_atomics - ? 0 : ctx->Const.Program[shader->Stage].MaxAtomicBuffers; st_src_reg buffer( PROGRAM_BUFFER, - buf_base + (const_block ? const_block->value.u[0] : 0), + const_block ? const_block->value.u[0] : 0, GLSL_TYPE_UINT); if (!const_block) { @@ -3678,7 +3770,8 @@ glsl_to_tgsi_visitor::visit_shared_intrinsic(ir_call *ir) static void get_image_qualifiers(ir_dereference *ir, const glsl_type **type, bool *memory_coherent, bool *memory_volatile, - bool *memory_restrict, unsigned *image_format) + bool *memory_restrict, bool *memory_read_only, + enum pipe_format *image_format) { switch (ir->ir_type) { @@ -3694,6 +3787,8 @@ get_image_qualifiers(ir_dereference *ir, const glsl_type **type, struct_type->fields.structure[fild_idx].memory_volatile; *memory_restrict = struct_type->fields.structure[fild_idx].memory_restrict; + *memory_read_only = + struct_type->fields.structure[fild_idx].memory_read_only; *image_format = struct_type->fields.structure[fild_idx].image_format; break; @@ -3703,7 +3798,7 @@ get_image_qualifiers(ir_dereference *ir, const glsl_type **type, ir_dereference_array *deref_arr = ir->as_dereference_array(); get_image_qualifiers((ir_dereference *)deref_arr->array, type, memory_coherent, memory_volatile, memory_restrict, - image_format); + memory_read_only, image_format); break; } @@ -3714,6 +3809,7 @@ get_image_qualifiers(ir_dereference *ir, const glsl_type **type, *memory_coherent = var->data.memory_coherent; *memory_volatile = var->data.memory_volatile; *memory_restrict = var->data.memory_restrict; + *memory_read_only = var->data.memory_read_only; *image_format = var->data.image_format; break; } @@ -3731,12 +3827,13 @@ glsl_to_tgsi_visitor::visit_image_intrinsic(ir_call *ir) ir_dereference *img = (ir_dereference *)param; const ir_variable *imgvar = img->variable_referenced(); unsigned sampler_array_size = 1, sampler_base = 0; - bool memory_coherent = false, memory_volatile = false, memory_restrict = false; - unsigned image_format = 0; + bool memory_coherent = false, memory_volatile = false, + memory_restrict = false, memory_read_only = false; + enum pipe_format image_format = PIPE_FORMAT_NONE; const glsl_type *type = NULL; get_image_qualifiers(img, &type, &memory_coherent, &memory_volatile, - &memory_restrict, &image_format); + &memory_restrict, &memory_read_only, &image_format); st_src_reg reladdr; st_src_reg image(PROGRAM_IMAGE, 0, GLSL_TYPE_UINT); @@ -3852,6 +3949,21 @@ glsl_to_tgsi_visitor::visit_image_intrinsic(ir_call *ir) case ir_intrinsic_image_atomic_comp_swap: opcode = TGSI_OPCODE_ATOMCAS; break; + case ir_intrinsic_image_atomic_inc_wrap: { + /* There's a bit of disagreement between GLSL and the hardware. The + * hardware wants to wrap after the given wrap value, while GLSL + * wants to wrap at the value. Subtract 1 to make up the difference. + */ + st_src_reg wrap = get_temp(glsl_type::uint_type); + emit_asm(ir, TGSI_OPCODE_ADD, st_dst_reg(wrap), + arg1, st_src_reg_for_int(-1)); + arg1 = wrap; + opcode = TGSI_OPCODE_ATOMINC_WRAP; + break; + } + case ir_intrinsic_image_atomic_dec_wrap: + opcode = TGSI_OPCODE_ATOMDEC_WRAP; + break; default: assert(!"Unexpected intrinsic"); return; @@ -3873,8 +3985,8 @@ glsl_to_tgsi_visitor::visit_image_intrinsic(ir_call *ir) } inst->tex_target = type->sampler_index(); - inst->image_format = st_mesa_format_to_pipe_format(st_context(ctx), - _mesa_get_shader_image_format(image_format)); + inst->image_format = image_format; + inst->read_only = memory_read_only; if (memory_coherent) inst->buffer_access |= TGSI_MEMORY_COHERENT; @@ -3976,6 +4088,8 @@ glsl_to_tgsi_visitor::visit(ir_call *ir) case ir_intrinsic_image_atomic_comp_swap: case ir_intrinsic_image_size: case ir_intrinsic_image_samples: + case ir_intrinsic_image_atomic_inc_wrap: + case ir_intrinsic_image_atomic_dec_wrap: visit_image_intrinsic(ir); return; @@ -4002,6 +4116,10 @@ glsl_to_tgsi_visitor::visit(ir_call *ir) visit_generic_intrinsic(ir, TGSI_OPCODE_READ_INVOC); return; + case ir_intrinsic_helper_invocation: + visit_generic_intrinsic(ir, TGSI_OPCODE_READ_HELPER); + return; + case ir_intrinsic_invalid: case ir_intrinsic_generic_load: case ir_intrinsic_generic_store: @@ -4035,7 +4153,7 @@ glsl_to_tgsi_visitor::calc_deref_offsets(ir_dereference *tail, calc_deref_offsets(deref_record->record->as_dereference(), array_elements, index, indirect, location); assert(field_index >= 0); - *location += struct_type->record_location_offset(field_index); + *location += struct_type->struct_location_offset(field_index); break; } @@ -4092,8 +4210,7 @@ glsl_to_tgsi_visitor::get_deref_offsets(ir_dereference *ir, unsigned location = 0; ir_variable *var = ir->variable_referenced(); - memset(reladdr, 0, sizeof(*reladdr)); - reladdr->file = PROGRAM_UNDEFINED; + reladdr->reset(); *base = 0; *array_size = 1; @@ -4186,14 +4303,13 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) enum tgsi_opcode opcode = TGSI_OPCODE_NOP; const glsl_type *sampler_type = ir->sampler->type; unsigned sampler_array_size = 1, sampler_base = 0; - bool is_cube_array = false, is_cube_shadow = false; + bool is_cube_array = false; ir_variable *var = ir->sampler->variable_referenced(); unsigned i; /* if we are a cube array sampler or a cube shadow */ if (sampler_type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE) { is_cube_array = sampler_type->sampler_array; - is_cube_shadow = sampler_type->sampler_shadow; } if (ir->coordinate) { @@ -4231,7 +4347,8 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) } break; case ir_txb: - if (is_cube_array || is_cube_shadow) { + if (is_cube_array || + (sampler_type->sampler_shadow && sampler_type->coordinate_components() >= 3)) { opcode = TGSI_OPCODE_TXB2; } else { @@ -4248,7 +4365,7 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) if (this->has_tex_txf_lz && ir->lod_info.lod->is_zero()) { opcode = TGSI_OPCODE_TEX_LZ; } else { - opcode = is_cube_array ? TGSI_OPCODE_TXL2 : TGSI_OPCODE_TXL; + opcode = (is_cube_array || (sampler_type->sampler_shadow && sampler_type->coordinate_components() >= 3)) ? TGSI_OPCODE_TXL2 : TGSI_OPCODE_TXL; ir->lod_info.lod->accept(this); lod_info = this->result; } @@ -4386,11 +4503,21 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) ir->shadow_comparator->accept(this); if (is_cube_array) { - cube_sc = get_temp(glsl_type::float_type); - cube_sc_dst = st_dst_reg(cube_sc); - cube_sc_dst.writemask = WRITEMASK_X; + if (lod_info.file != PROGRAM_UNDEFINED) { + // If we have both a cube array *and* a bias/lod, stick the + // comparator into the .Y of the second argument. + st_src_reg tmp = get_temp(glsl_type::vec2_type); + cube_sc_dst = st_dst_reg(tmp); + cube_sc_dst.writemask = WRITEMASK_X; + emit_asm(ir, TGSI_OPCODE_MOV, cube_sc_dst, lod_info); + lod_info = tmp; + cube_sc_dst.writemask = WRITEMASK_Y; + } else { + cube_sc = get_temp(glsl_type::float_type); + cube_sc_dst = st_dst_reg(cube_sc); + cube_sc_dst.writemask = WRITEMASK_X; + } emit_asm(ir, TGSI_OPCODE_MOV, cube_sc_dst, this->result); - cube_sc_dst.writemask = WRITEMASK_X; } else { if ((sampler_type->sampler_dimensionality == GLSL_SAMPLER_DIM_2D && @@ -4457,7 +4584,20 @@ glsl_to_tgsi_visitor::visit(ir_texture *ir) if (is_cube_array && ir->shadow_comparator) { inst = emit_asm(ir, opcode, result_dst, coord, cube_sc); } else { - inst = emit_asm(ir, opcode, result_dst, coord, component); + if (this->tg4_component_in_swizzle) { + inst = emit_asm(ir, opcode, result_dst, coord); + int idx = 0; + foreach_in_list(immediate_storage, entry, &this->immediates) { + if (component.index == idx) { + gl_constant_value value = entry->values[component.swizzle]; + inst->gather_component = value.i; + break; + } + idx++; + } + } else { + inst = emit_asm(ir, opcode, result_dst, coord, component); + } } } else inst = emit_asm(ir, opcode, result_dst, coord); @@ -4523,6 +4663,12 @@ glsl_to_tgsi_visitor::visit(ir_discard *ir) } } +void +glsl_to_tgsi_visitor::visit(ir_demote *ir) +{ + emit_asm(ir, TGSI_OPCODE_DEMOTE); +} + void glsl_to_tgsi_visitor::visit(ir_if *ir) { @@ -4602,6 +4748,8 @@ glsl_to_tgsi_visitor::glsl_to_tgsi_visitor() ctx = NULL; prog = NULL; precise = 0; + need_uarl = false; + tg4_component_in_swizzle = false; shader_program = NULL; shader = NULL; options = NULL; @@ -4675,6 +4823,7 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog) v->image_targets[idx] = st_translate_texture_target(inst->tex_target, false); v->image_formats[idx] = inst->image_format; + v->image_wr[idx] = !inst->read_only; } } } @@ -5430,6 +5579,107 @@ glsl_to_tgsi_visitor::merge_two_dsts(void) } } +template +void test_indirect_access(const st_reg& reg, bool *has_indirect_access) +{ + if (reg.file == PROGRAM_ARRAY) { + if (reg.reladdr || reg.reladdr2 || reg.has_index2) { + has_indirect_access[reg.array_id] = true; + if (reg.reladdr) + test_indirect_access(*reg.reladdr, has_indirect_access); + if (reg.reladdr2) + test_indirect_access(*reg.reladdr2, has_indirect_access); + } + } +} + +template +void remap_array(st_reg& reg, const int *array_remap_info, + const bool *has_indirect_access) +{ + if (reg.file == PROGRAM_ARRAY) { + if (!has_indirect_access[reg.array_id]) { + reg.file = PROGRAM_TEMPORARY; + reg.index = reg.index + array_remap_info[reg.array_id]; + reg.array_id = 0; + } else { + reg.array_id = array_remap_info[reg.array_id]; + } + + if (reg.reladdr) + remap_array(*reg.reladdr, array_remap_info, has_indirect_access); + + if (reg.reladdr2) + remap_array(*reg.reladdr2, array_remap_info, has_indirect_access); + } +} + +/* One-dimensional arrays whose elements are only accessed directly are + * replaced by an according set of temporary registers that then can become + * subject to further optimization steps like copy propagation and + * register merging. + */ +void +glsl_to_tgsi_visitor::split_arrays(void) +{ + if (!next_array) + return; + + bool *has_indirect_access = rzalloc_array(mem_ctx, bool, next_array + 1); + + foreach_in_list(glsl_to_tgsi_instruction, inst, &this->instructions) { + for (unsigned j = 0; j < num_inst_src_regs(inst); j++) + test_indirect_access(inst->src[j], has_indirect_access); + + for (unsigned j = 0; j < inst->tex_offset_num_offset; j++) + test_indirect_access(inst->tex_offsets[j], has_indirect_access); + + for (unsigned j = 0; j < num_inst_dst_regs(inst); j++) + test_indirect_access(inst->dst[j], has_indirect_access); + + test_indirect_access(inst->resource, has_indirect_access); + } + + unsigned array_offset = 0; + unsigned n_remaining_arrays = 0; + + /* Double use: For arrays that get split this value will contain + * the base index of the temporary registers this array is replaced + * with. For arrays that remain it contains the new array ID. + */ + int *array_remap_info = rzalloc_array(has_indirect_access, int, + next_array + 1); + + for (unsigned i = 1; i <= next_array; ++i) { + if (!has_indirect_access[i]) { + array_remap_info[i] = this->next_temp + array_offset; + array_offset += array_sizes[i - 1]; + } else { + array_sizes[n_remaining_arrays] = array_sizes[i-1]; + array_remap_info[i] = ++n_remaining_arrays; + } + } + + if (next_array != n_remaining_arrays) { + foreach_in_list(glsl_to_tgsi_instruction, inst, &this->instructions) { + for (unsigned j = 0; j < num_inst_src_regs(inst); j++) + remap_array(inst->src[j], array_remap_info, has_indirect_access); + + for (unsigned j = 0; j < inst->tex_offset_num_offset; j++) + remap_array(inst->tex_offsets[j], array_remap_info, has_indirect_access); + + for (unsigned j = 0; j < num_inst_dst_regs(inst); j++) { + remap_array(inst->dst[j], array_remap_info, has_indirect_access); + } + remap_array(inst->resource, array_remap_info, has_indirect_access); + } + } + + ralloc_free(has_indirect_access); + this->next_temp += array_offset; + next_array = n_remaining_arrays; +} + /* Merges temporary registers together where possible to reduce the number of * registers needed to run a program. * @@ -5438,19 +5688,35 @@ glsl_to_tgsi_visitor::merge_two_dsts(void) void glsl_to_tgsi_visitor::merge_registers(void) { - struct lifetime *lifetimes = - rzalloc_array(mem_ctx, struct lifetime, this->next_temp); + class array_live_range *arr_live_ranges = NULL; + + struct register_live_range *reg_live_ranges = + rzalloc_array(mem_ctx, struct register_live_range, this->next_temp); + + if (this->next_array > 0) { + arr_live_ranges = new array_live_range[this->next_array]; + for (unsigned i = 0; i < this->next_array; ++i) + arr_live_ranges[i] = array_live_range(i+1, this->array_sizes[i]); + } - if (get_temp_registers_required_lifetimes(mem_ctx, &this->instructions, - this->next_temp, lifetimes)) { + + if (get_temp_registers_required_live_ranges(reg_live_ranges, &this->instructions, + this->next_temp, reg_live_ranges, + this->next_array, arr_live_ranges)) { struct rename_reg_pair *renames = - rzalloc_array(mem_ctx, struct rename_reg_pair, this->next_temp); - get_temp_registers_remapping(mem_ctx, this->next_temp, lifetimes, renames); + rzalloc_array(reg_live_ranges, struct rename_reg_pair, this->next_temp); + get_temp_registers_remapping(reg_live_ranges, this->next_temp, + reg_live_ranges, renames); rename_temp_registers(renames); - ralloc_free(renames); + + this->next_array = merge_arrays(this->next_array, this->array_sizes, + &this->instructions, arr_live_ranges); } - ralloc_free(lifetimes); + if (arr_live_ranges) + delete[] arr_live_ranges; + + ralloc_free(reg_live_ranges); } /* Reassign indices to temporary registers by reusing unused indices created @@ -5483,6 +5749,27 @@ glsl_to_tgsi_visitor::renumber_registers(void) ralloc_free(first_writes); } +#ifndef NDEBUG +void glsl_to_tgsi_visitor::print_stats() +{ + int narray_registers = 0; + for (unsigned i = 0; i < this->next_array; ++i) + narray_registers += this->array_sizes[i]; + + int ninstructions = 0; + foreach_in_list(glsl_to_tgsi_instruction, inst, &instructions) { + ++ninstructions; + } + + simple_mtx_lock(&print_stats_mutex); + stats_log << next_array << ", " + << next_temp << ", " + << narray_registers << ", " + << next_temp + narray_registers << ", " + << ninstructions << "\n"; + simple_mtx_unlock(&print_stats_mutex); +} +#endif /* ------------------------- TGSI conversion stuff -------------------------- */ /** @@ -5520,93 +5807,9 @@ struct st_translate { enum pipe_shader_type procType; /**< PIPE_SHADER_VERTEX/FRAGMENT */ bool need_uarl; + bool tg4_component_in_swizzle; }; -/** Map Mesa's SYSTEM_VALUE_x to TGSI_SEMANTIC_x */ -enum tgsi_semantic -_mesa_sysval_to_semantic(unsigned sysval) -{ - switch (sysval) { - /* Vertex shader */ - case SYSTEM_VALUE_VERTEX_ID: - return TGSI_SEMANTIC_VERTEXID; - case SYSTEM_VALUE_INSTANCE_ID: - return TGSI_SEMANTIC_INSTANCEID; - case SYSTEM_VALUE_VERTEX_ID_ZERO_BASE: - return TGSI_SEMANTIC_VERTEXID_NOBASE; - case SYSTEM_VALUE_BASE_VERTEX: - return TGSI_SEMANTIC_BASEVERTEX; - case SYSTEM_VALUE_BASE_INSTANCE: - return TGSI_SEMANTIC_BASEINSTANCE; - case SYSTEM_VALUE_DRAW_ID: - return TGSI_SEMANTIC_DRAWID; - - /* Geometry shader */ - case SYSTEM_VALUE_INVOCATION_ID: - return TGSI_SEMANTIC_INVOCATIONID; - - /* Fragment shader */ - case SYSTEM_VALUE_FRAG_COORD: - return TGSI_SEMANTIC_POSITION; - case SYSTEM_VALUE_FRONT_FACE: - return TGSI_SEMANTIC_FACE; - case SYSTEM_VALUE_SAMPLE_ID: - return TGSI_SEMANTIC_SAMPLEID; - case SYSTEM_VALUE_SAMPLE_POS: - return TGSI_SEMANTIC_SAMPLEPOS; - case SYSTEM_VALUE_SAMPLE_MASK_IN: - return TGSI_SEMANTIC_SAMPLEMASK; - case SYSTEM_VALUE_HELPER_INVOCATION: - return TGSI_SEMANTIC_HELPER_INVOCATION; - - /* Tessellation shader */ - case SYSTEM_VALUE_TESS_COORD: - return TGSI_SEMANTIC_TESSCOORD; - case SYSTEM_VALUE_VERTICES_IN: - return TGSI_SEMANTIC_VERTICESIN; - case SYSTEM_VALUE_PRIMITIVE_ID: - return TGSI_SEMANTIC_PRIMID; - case SYSTEM_VALUE_TESS_LEVEL_OUTER: - return TGSI_SEMANTIC_TESSOUTER; - case SYSTEM_VALUE_TESS_LEVEL_INNER: - return TGSI_SEMANTIC_TESSINNER; - - /* Compute shader */ - case SYSTEM_VALUE_LOCAL_INVOCATION_ID: - return TGSI_SEMANTIC_THREAD_ID; - case SYSTEM_VALUE_WORK_GROUP_ID: - return TGSI_SEMANTIC_BLOCK_ID; - case SYSTEM_VALUE_NUM_WORK_GROUPS: - return TGSI_SEMANTIC_GRID_SIZE; - case SYSTEM_VALUE_LOCAL_GROUP_SIZE: - return TGSI_SEMANTIC_BLOCK_SIZE; - - /* ARB_shader_ballot */ - case SYSTEM_VALUE_SUBGROUP_SIZE: - return TGSI_SEMANTIC_SUBGROUP_SIZE; - case SYSTEM_VALUE_SUBGROUP_INVOCATION: - return TGSI_SEMANTIC_SUBGROUP_INVOCATION; - case SYSTEM_VALUE_SUBGROUP_EQ_MASK: - return TGSI_SEMANTIC_SUBGROUP_EQ_MASK; - case SYSTEM_VALUE_SUBGROUP_GE_MASK: - return TGSI_SEMANTIC_SUBGROUP_GE_MASK; - case SYSTEM_VALUE_SUBGROUP_GT_MASK: - return TGSI_SEMANTIC_SUBGROUP_GT_MASK; - case SYSTEM_VALUE_SUBGROUP_LE_MASK: - return TGSI_SEMANTIC_SUBGROUP_LE_MASK; - case SYSTEM_VALUE_SUBGROUP_LT_MASK: - return TGSI_SEMANTIC_SUBGROUP_LT_MASK; - - /* Unhandled */ - case SYSTEM_VALUE_LOCAL_INVOCATION_INDEX: - case SYSTEM_VALUE_GLOBAL_INVOCATION_ID: - case SYSTEM_VALUE_VERTEX_CNT: - default: - assert(!"Unexpected SYSTEM_VALUE_ enum"); - return TGSI_SEMANTIC_COUNT; - } -} - /** * Map a glsl_to_tgsi constant/immediate to a TGSI immediate. */ @@ -5971,6 +6174,8 @@ compile_tgsi_instruction(struct st_translate *t, case TGSI_OPCODE_SAMP2HND: if (inst->resource.file == PROGRAM_SAMPLER) { src[num_src] = t->samplers[inst->resource.index]; + if (t->tg4_component_in_swizzle && inst->op == TGSI_OPCODE_TG4) + src[num_src].SwizzleX = inst->gather_component; } else { /* Bindless samplers. */ src[num_src] = translate_src(t, &inst->resource); @@ -6007,7 +6212,10 @@ compile_tgsi_instruction(struct st_translate *t, case TGSI_OPCODE_ATOMUMAX: case TGSI_OPCODE_ATOMIMIN: case TGSI_OPCODE_ATOMIMAX: + case TGSI_OPCODE_ATOMFADD: case TGSI_OPCODE_IMG2HND: + case TGSI_OPCODE_ATOMINC_WRAP: + case TGSI_OPCODE_ATOMDEC_WRAP: for (i = num_src - 1; i >= 0; i--) src[i + 1] = src[i]; num_src++; @@ -6072,6 +6280,34 @@ compile_tgsi_instruction(struct st_translate *t, } } +/* Invert SamplePos.y when rendering to the default framebuffer. */ +static void +emit_samplepos_adjustment(struct st_translate *t, int wpos_y_transform) +{ + struct ureg_program *ureg = t->ureg; + + assert(wpos_y_transform >= 0); + struct ureg_src trans_const = ureg_DECL_constant(ureg, wpos_y_transform); + struct ureg_src samplepos_sysval = t->systemValues[SYSTEM_VALUE_SAMPLE_POS]; + struct ureg_dst samplepos_flipped = ureg_DECL_temporary(ureg); + struct ureg_dst is_fbo = ureg_DECL_temporary(ureg); + + ureg_ADD(ureg, ureg_writemask(samplepos_flipped, TGSI_WRITEMASK_Y), + ureg_imm1f(ureg, 1), ureg_negate(samplepos_sysval)); + + /* If trans.x == 1, use samplepos.y, else use 1 - samplepos.y. */ + ureg_FSEQ(ureg, ureg_writemask(is_fbo, TGSI_WRITEMASK_Y), + ureg_scalar(trans_const, TGSI_SWIZZLE_X), ureg_imm1f(ureg, 1)); + ureg_UCMP(ureg, ureg_writemask(samplepos_flipped, TGSI_WRITEMASK_Y), + ureg_src(is_fbo), samplepos_sysval, ureg_src(samplepos_flipped)); + ureg_MOV(ureg, ureg_writemask(samplepos_flipped, TGSI_WRITEMASK_X), + samplepos_sysval); + + /* Use the result in place of the system value. */ + t->systemValues[SYSTEM_VALUE_SAMPLE_POS] = ureg_src(samplepos_flipped); +} + + /** * Emit the TGSI instructions for inverting and adjusting WPOS. * This code is unavoidable because it also depends on whether @@ -6195,7 +6431,7 @@ emit_wpos(struct st_context *st, * u,i -> l,h: (99.0 + 0.5) * -1 + 100 = 0.5 * u,h -> l,i: (99.5 + 0.5) * -1 + 100 = 0 */ - if (program->OriginUpperLeft) { + if (program->info.fs.origin_upper_left) { /* Fragment shader wants origin in upper-left */ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_ORIGIN_UPPER_LEFT)) { /* the driver supports upper-left origin */ @@ -6222,7 +6458,7 @@ emit_wpos(struct st_context *st, assert(0); } - if (program->PixelCenterInteger) { + if (program->info.fs.pixel_center_integer) { /* Fragment shader wants pixel center integer */ if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER)) { /* the driver supports pixel center integer */ @@ -6284,17 +6520,6 @@ emit_face_var(struct gl_context *ctx, struct st_translate *t) t->inputs[t->inputMapping[VARYING_SLOT_FACE]] = ureg_src(face_temp); } -static void -emit_compute_block_size(const struct gl_program *prog, - struct ureg_program *ureg) { - ureg_property(ureg, TGSI_PROPERTY_CS_FIXED_BLOCK_WIDTH, - prog->info.cs.local_size[0]); - ureg_property(ureg, TGSI_PROPERTY_CS_FIXED_BLOCK_HEIGHT, - prog->info.cs.local_size[1]); - ureg_property(ureg, TGSI_PROPERTY_CS_FIXED_BLOCK_DEPTH, - prog->info.cs.local_size[2]); -} - struct sort_inout_decls { bool operator()(const struct inout_decl &a, const struct inout_decl &b) const { return mapping[a.mesa_index] < mapping[b.mesa_index]; @@ -6318,26 +6543,6 @@ sort_inout_decls_by_slot(struct inout_decl *decls, std::sort(decls, decls + count, sorter); } -static enum tgsi_interpolate_mode -st_translate_interp(enum glsl_interp_mode glsl_qual, GLuint varying) -{ - switch (glsl_qual) { - case INTERP_MODE_NONE: - if (varying == VARYING_SLOT_COL0 || varying == VARYING_SLOT_COL1) - return TGSI_INTERPOLATE_COLOR; - return TGSI_INTERPOLATE_PERSPECTIVE; - case INTERP_MODE_SMOOTH: - return TGSI_INTERPOLATE_PERSPECTIVE; - case INTERP_MODE_FLAT: - return TGSI_INTERPOLATE_CONSTANT; - case INTERP_MODE_NOPERSPECTIVE: - return TGSI_INTERPOLATE_LINEAR; - default: - assert(0 && "unexpected interp mode in st_translate_interp()"); - return TGSI_INTERPOLATE_PERSPECTIVE; - } -} - /** * Translate intermediate IR (glsl_to_tgsi_instruction) to TGSI format. * \param program the program to translate @@ -6386,7 +6591,9 @@ st_translate_program( assert(numOutputs <= ARRAY_SIZE(t->outputs)); ASSERT_BITFIELD_SIZE(st_src_reg, type, GLSL_TYPE_ERROR); + ASSERT_BITFIELD_SIZE(st_src_reg, file, PROGRAM_FILE_MAX); ASSERT_BITFIELD_SIZE(st_dst_reg, type, GLSL_TYPE_ERROR); + ASSERT_BITFIELD_SIZE(st_dst_reg, file, PROGRAM_FILE_MAX); ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, tex_type, GLSL_TYPE_ERROR); ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, image_format, PIPE_FORMAT_COUNT); ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, tex_target, @@ -6404,6 +6611,7 @@ st_translate_program( t->procType = procType; t->need_uarl = !screen->get_param(screen, PIPE_CAP_TGSI_ANY_REG_AS_ADDRESS); + t->tg4_component_in_swizzle = screen->get_param(screen, PIPE_CAP_TGSI_TG4_COMPONENT_IN_SWIZZLE); t->inputMapping = inputMapping; t->outputMapping = outputMapping; t->ureg = ureg; @@ -6443,7 +6651,9 @@ st_translate_program( assert(interpMode); interp_mode = interpMode[slot] != TGSI_INTERPOLATE_COUNT ? (enum tgsi_interpolate_mode) interpMode[slot] : - st_translate_interp(decl->interp, inputSlotToAttr[slot]); + tgsi_get_interp_mode(decl->interp, + inputSlotToAttr[slot] == VARYING_SLOT_COL0 || + inputSlotToAttr[slot] == VARYING_SLOT_COL1); interp_location = (enum tgsi_interpolate_loc) decl->interp_loc; } @@ -6525,14 +6735,6 @@ st_translate_program( } if (procType == PIPE_SHADER_FRAGMENT) { - if (program->shader->Program->info.fs.early_fragment_tests || - program->shader->Program->info.fs.post_depth_coverage) { - ureg_property(ureg, TGSI_PROPERTY_FS_EARLY_DEPTH_STENCIL, 1); - - if (program->shader->Program->info.fs.post_depth_coverage) - ureg_property(ureg, TGSI_PROPERTY_FS_POST_DEPTH_COVERAGE, 1); - } - if (proginfo->info.inputs_read & VARYING_BIT_POS) { /* Must do this after setting up t->inputs. */ emit_wpos(st_context(ctx), t, proginfo, ureg, @@ -6576,6 +6778,12 @@ st_translate_program( goto out; } } + + if (program->shader->Program->sh.fs.BlendSupport) + ureg_property(ureg, + TGSI_PROPERTY_FS_BLEND_EQUATION_ADVANCED, + program->shader->Program->sh.fs.BlendSupport); + } else if (procType == PIPE_SHADER_VERTEX) { for (i = 0; i < numOutputs; i++) { @@ -6589,10 +6797,6 @@ st_translate_program( } } - if (procType == PIPE_SHADER_COMPUTE) { - emit_compute_block_size(proginfo, ureg); - } - /* Declare address register. */ if (program->num_address_regs > 0) { @@ -6608,7 +6812,7 @@ st_translate_program( for (i = 0; sysInputs; i++) { if (sysInputs & (1ull << i)) { - enum tgsi_semantic semName = _mesa_sysval_to_semantic(i); + enum tgsi_semantic semName = tgsi_get_sysval_semantic(i); t->systemValues[i] = ureg_DECL_system_value(ureg, semName, 0); @@ -6639,6 +6843,10 @@ st_translate_program( emit_wpos(st_context(ctx), t, proginfo, ureg, program->wpos_transform_const); + if (procType == PIPE_SHADER_FRAGMENT && + semName == TGSI_SEMANTIC_SAMPLEPOS) + emit_samplepos_adjustment(t, program->wpos_transform_const); + sysInputs &= ~(1ull << i); } } @@ -6738,8 +6946,10 @@ st_translate_program( if (!st_context(ctx)->has_hw_atomics) { for (i = 0; i < prog->info.num_abos; i++) { - unsigned index = prog->sh.AtomicBuffers[i]->Binding; - assert(index < frag_const->MaxAtomicBuffers); + unsigned index = (prog->info.num_ssbos + + prog->sh.AtomicBuffers[i]->Binding); + assert(prog->sh.AtomicBuffers[i]->Binding < + frag_const->MaxAtomicBuffers); t->buffers[index] = ureg_DECL_buffer(ureg, index, true); } } else { @@ -6754,11 +6964,7 @@ st_translate_program( assert(prog->info.num_ssbos <= frag_const->MaxShaderStorageBlocks); for (i = 0; i < prog->info.num_ssbos; i++) { - unsigned index = i; - if (!st_context(ctx)->has_hw_atomics) - index += frag_const->MaxAtomicBuffers; - - t->buffers[index] = ureg_DECL_buffer(ureg, index, false); + t->buffers[i] = ureg_DECL_buffer(ureg, i, false); } } @@ -6770,7 +6976,8 @@ st_translate_program( t->images[i] = ureg_DECL_image(ureg, i, program->image_targets[i], program->image_formats[i], - true, false); + program->image_wr[i], + false); } } @@ -6779,25 +6986,6 @@ st_translate_program( foreach_in_list(glsl_to_tgsi_instruction, inst, &program->instructions) compile_tgsi_instruction(t, inst); - /* Set the next shader stage hint for VS and TES. */ - switch (procType) { - case PIPE_SHADER_VERTEX: - case PIPE_SHADER_TESS_EVAL: - if (program->shader_program->SeparateShader) - break; - - for (i = program->shader->Stage+1; i <= MESA_SHADER_FRAGMENT; i++) { - if (program->shader_program->_LinkedShaders[i]) { - ureg_set_next_shader_processor( - ureg, pipe_shader_type_from_mesa((gl_shader_stage)i)); - break; - } - } - break; - default: - ; /* nothing - silence compiler warning */ - } - out: if (t) { free(t->arrays); @@ -6852,6 +7040,7 @@ get_mesa_program_tgsi(struct gl_context *ctx, PIPE_CAP_TGSI_TEX_TXF_LZ); v->need_uarl = !pscreen->get_param(pscreen, PIPE_CAP_TGSI_ANY_REG_AS_ADDRESS); + v->tg4_component_in_swizzle = pscreen->get_param(pscreen, PIPE_CAP_TGSI_TG4_COMPONENT_IN_SWIZZLE); v->variables = _mesa_hash_table_create(v->mem_ctx, _mesa_hash_pointer, _mesa_key_pointer_equal); skip_merge_registers = @@ -6906,8 +7095,17 @@ get_mesa_program_tgsi(struct gl_context *ctx, while (v->eliminate_dead_code()); v->merge_two_dsts(); - if (!skip_merge_registers) + + if (!skip_merge_registers) { + v->split_arrays(); + v->copy_propagate(); + while (v->eliminate_dead_code()); + v->merge_registers(); + v->copy_propagate(); + while (v->eliminate_dead_code()); + } + v->renumber_registers(); /* Write the END instruction. */ @@ -6923,14 +7121,28 @@ get_mesa_program_tgsi(struct gl_context *ctx, } do_set_program_inouts(shader->ir, prog, shader->Stage); + _mesa_copy_linked_program_data(shader_program, shader); - shrink_array_declarations(v->inputs, v->num_inputs, - &prog->info.inputs_read, - prog->info.vs.double_inputs_read, - &prog->info.patch_inputs_read); - shrink_array_declarations(v->outputs, v->num_outputs, - &prog->info.outputs_written, 0ULL, - &prog->info.patch_outputs_written); + + if (pscreen->get_param(pscreen, PIPE_CAP_TGSI_SKIP_SHRINK_IO_ARRAYS)) { + mark_array_io(v->inputs, v->num_inputs, + &prog->info.inputs_read, + prog->DualSlotInputs, + &prog->info.patch_inputs_read); + + mark_array_io(v->outputs, v->num_outputs, + &prog->info.outputs_written, 0ULL, + &prog->info.patch_outputs_written); + } else { + shrink_array_declarations(v->inputs, v->num_inputs, + &prog->info.inputs_read, + prog->DualSlotInputs, + &prog->info.patch_inputs_read); + shrink_array_declarations(v->outputs, v->num_outputs, + &prog->info.outputs_written, 0ULL, + &prog->info.patch_outputs_written); + } + count_resources(v, prog); /* The GLSL IR won't be needed anymore. */ @@ -6940,7 +7152,8 @@ get_mesa_program_tgsi(struct gl_context *ctx, /* This must be done before the uniform storage is associated. */ if (shader->Stage == MESA_SHADER_FRAGMENT && (prog->info.inputs_read & VARYING_BIT_POS || - prog->info.system_values_read & (1ull << SYSTEM_VALUE_FRAG_COORD))) { + prog->info.system_values_read & (1ull << SYSTEM_VALUE_FRAG_COORD) || + prog->info.system_values_read & (1ull << SYSTEM_VALUE_SAMPLE_POS))) { static const gl_state_index16 wposTransformState[STATE_LENGTH] = { STATE_INTERNAL, STATE_FB_WPOS_Y_TRANSFORM }; @@ -6959,41 +7172,16 @@ get_mesa_program_tgsi(struct gl_context *ctx, * prog->ParameterValues to get reallocated (e.g., anything that adds a * program constant) has to happen before creating this linkage. */ - _mesa_associate_uniform_storage(ctx, shader_program, prog, true); + _mesa_associate_uniform_storage(ctx, shader_program, prog); if (!shader_program->data->LinkStatus) { free_glsl_to_tgsi_visitor(v); _mesa_reference_program(ctx, &shader->Program, NULL); return NULL; } - struct st_vertex_program *stvp; - struct st_fragment_program *stfp; - struct st_common_program *stp; - struct st_compute_program *stcp; + st_program(prog)->glsl_to_tgsi = v; - switch (shader->Stage) { - case MESA_SHADER_VERTEX: - stvp = (struct st_vertex_program *)prog; - stvp->glsl_to_tgsi = v; - break; - case MESA_SHADER_FRAGMENT: - stfp = (struct st_fragment_program *)prog; - stfp->glsl_to_tgsi = v; - break; - case MESA_SHADER_TESS_CTRL: - case MESA_SHADER_TESS_EVAL: - case MESA_SHADER_GEOMETRY: - stp = st_common_program(prog); - stp->glsl_to_tgsi = v; - break; - case MESA_SHADER_COMPUTE: - stcp = (struct st_compute_program *)prog; - stcp->glsl_to_tgsi = v; - break; - default: - assert(!"should not be reached"); - return NULL; - } + PRINT_STATS(v->print_stats()); return prog; } @@ -7048,130 +7236,29 @@ has_unsupported_control_flow(exec_list *ir, return visitor.unsupported; } -extern "C" { - /** * Link a shader. - * Called via ctx->Driver.LinkShader() * This actually involves converting GLSL IR into an intermediate TGSI-like IR * with code lowering and other optimizations. */ GLboolean -st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) +st_link_tgsi(struct gl_context *ctx, struct gl_shader_program *prog) { struct pipe_screen *pscreen = ctx->st->pipe->screen; - enum pipe_shader_ir preferred_ir = (enum pipe_shader_ir) - pscreen->get_shader_param(pscreen, PIPE_SHADER_VERTEX, - PIPE_SHADER_CAP_PREFERRED_IR); - bool use_nir = preferred_ir == PIPE_SHADER_IR_NIR; - - /* Return early if we are loading the shader from on-disk cache */ - if (st_load_ir_from_disk_cache(ctx, prog, use_nir)) { - return GL_TRUE; - } - - assert(prog->data->LinkStatus); - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (prog->_LinkedShaders[i] == NULL) + struct gl_linked_shader *shader = prog->_LinkedShaders[i]; + if (shader == NULL) continue; - struct gl_linked_shader *shader = prog->_LinkedShaders[i]; exec_list *ir = shader->ir; gl_shader_stage stage = shader->Stage; + enum pipe_shader_type ptarget = pipe_shader_type_from_mesa(stage); const struct gl_shader_compiler_options *options = &ctx->Const.ShaderCompilerOptions[stage]; - enum pipe_shader_type ptarget = pipe_shader_type_from_mesa(stage); - bool have_dround = pscreen->get_shader_param(pscreen, ptarget, - PIPE_SHADER_CAP_TGSI_DROUND_SUPPORTED); - bool have_dfrexp = pscreen->get_shader_param(pscreen, ptarget, - PIPE_SHADER_CAP_TGSI_DFRACEXP_DLDEXP_SUPPORTED); - bool have_ldexp = pscreen->get_shader_param(pscreen, ptarget, - PIPE_SHADER_CAP_TGSI_LDEXP_SUPPORTED); + unsigned if_threshold = pscreen->get_shader_param(pscreen, ptarget, PIPE_SHADER_CAP_LOWER_IF_THRESHOLD); - - /* If there are forms of indirect addressing that the driver - * cannot handle, perform the lowering pass. - */ - if (options->EmitNoIndirectInput || options->EmitNoIndirectOutput || - options->EmitNoIndirectTemp || options->EmitNoIndirectUniform) { - lower_variable_index_to_cond_assign(stage, ir, - options->EmitNoIndirectInput, - options->EmitNoIndirectOutput, - options->EmitNoIndirectTemp, - options->EmitNoIndirectUniform); - } - - if (!pscreen->get_param(pscreen, PIPE_CAP_INT64_DIVMOD)) - lower_64bit_integer_instructions(ir, DIV64 | MOD64); - - if (ctx->Extensions.ARB_shading_language_packing) { - unsigned lower_inst = LOWER_PACK_SNORM_2x16 | - LOWER_UNPACK_SNORM_2x16 | - LOWER_PACK_UNORM_2x16 | - LOWER_UNPACK_UNORM_2x16 | - LOWER_PACK_SNORM_4x8 | - LOWER_UNPACK_SNORM_4x8 | - LOWER_UNPACK_UNORM_4x8 | - LOWER_PACK_UNORM_4x8; - - if (ctx->Extensions.ARB_gpu_shader5) - lower_inst |= LOWER_PACK_USE_BFI | - LOWER_PACK_USE_BFE; - if (!ctx->st->has_half_float_packing) - lower_inst |= LOWER_PACK_HALF_2x16 | - LOWER_UNPACK_HALF_2x16; - - lower_packing_builtins(ir, lower_inst); - } - - if (!pscreen->get_param(pscreen, PIPE_CAP_TEXTURE_GATHER_OFFSETS)) - lower_offset_arrays(ir); - do_mat_op_to_vec(ir); - - if (stage == MESA_SHADER_FRAGMENT) - lower_blend_equation_advanced( - shader, ctx->Extensions.KHR_blend_equation_advanced_coherent); - - lower_instructions(ir, - MOD_TO_FLOOR | - FDIV_TO_MUL_RCP | - EXP_TO_EXP2 | - LOG_TO_LOG2 | - (have_ldexp ? 0 : LDEXP_TO_ARITH) | - (have_dfrexp ? 0 : DFREXP_DLDEXP_TO_ARITH) | - CARRY_TO_ARITH | - BORROW_TO_ARITH | - (have_dround ? 0 : DOPS_TO_DFRAC) | - (options->EmitNoPow ? POW_TO_EXP2 : 0) | - (!ctx->Const.NativeIntegers ? INT_DIV_TO_MUL_RCP : 0) | - (options->EmitNoSat ? SAT_TO_CLAMP : 0) | - (ctx->Const.ForceGLSLAbsSqrt ? SQRT_TO_ABS_SQRT : 0) | - /* Assume that if ARB_gpu_shader5 is not supported - * then all of the extended integer functions need - * lowering. It may be necessary to add some caps - * for individual instructions. - */ - (!ctx->Extensions.ARB_gpu_shader5 - ? BIT_COUNT_TO_MATH | - EXTRACT_TO_SHIFTS | - INSERT_TO_SHIFTS | - REVERSE_TO_SHIFTS | - FIND_LSB_TO_FLOAT_CAST | - FIND_MSB_TO_FLOAT_CAST | - IMUL_HIGH_TO_MUL - : 0)); - - do_vec_index_to_cond_assign(ir); - lower_vector_insert(ir, true); - lower_quadop_vector(ir, false); - lower_noise(ir); - if (options->MaxIfDepth == 0) { - lower_discard(ir); - } - if (ctx->Const.GLSLOptimizeConservatively) { /* Do it once and repeat only if there's unsupported control flow. */ do { @@ -7197,23 +7284,20 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) do_vec_index_to_cond_assign(ir); validate_ir_tree(ir); - } - - build_program_resource_list(ctx, prog); - - if (use_nir) - return st_link_nir(ctx, prog); - - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - struct gl_linked_shader *shader = prog->_LinkedShaders[i]; - if (shader == NULL) - continue; struct gl_program *linked_prog = get_mesa_program_tgsi(ctx, prog, shader); st_set_prog_affected_state_flags(linked_prog); if (linked_prog) { + /* This is really conservative: */ + linked_prog->info.writes_memory = + linked_prog->info.num_ssbos || + linked_prog->info.num_images || + ctx->Extensions.ARB_bindless_texture || + (linked_prog->sh.LinkedTransformFeedback && + linked_prog->sh.LinkedTransformFeedback->NumVarying); + if (!ctx->Driver.ProgramStringNotify(ctx, _mesa_shader_stage_to_program(i), linked_prog)) { @@ -7225,41 +7309,3 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) return GL_TRUE; } - -void -st_translate_stream_output_info(glsl_to_tgsi_visitor *glsl_to_tgsi, - const ubyte outputMapping[], - struct pipe_stream_output_info *so) -{ - if (!glsl_to_tgsi->shader_program->last_vert_prog) - return; - - struct gl_transform_feedback_info *info = - glsl_to_tgsi->shader_program->last_vert_prog->sh.LinkedTransformFeedback; - st_translate_stream_output_info2(info, outputMapping, so); -} - -void -st_translate_stream_output_info2(struct gl_transform_feedback_info *info, - const ubyte outputMapping[], - struct pipe_stream_output_info *so) -{ - unsigned i; - - for (i = 0; i < info->NumOutputs; i++) { - so->output[i].register_index = - outputMapping[info->Outputs[i].OutputRegister]; - so->output[i].start_component = info->Outputs[i].ComponentOffset; - so->output[i].num_components = info->Outputs[i].NumComponents; - so->output[i].output_buffer = info->Outputs[i].OutputBuffer; - so->output[i].dst_offset = info->Outputs[i].DstOffset; - so->output[i].stream = info->Outputs[i].StreamId; - } - - for (i = 0; i < PIPE_MAX_SO_BUFFERS; i++) { - so->stride[i] = info->Buffers[i].Stride; - } - so->num_outputs = info->NumOutputs; -} - -} /* extern "C" */