#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"
#define MAX_GLSL_TEXTURE_OFFSET 4
+#ifndef NDEBUG
+#include "util/u_atomic.h"
+#include "util/simple_mtx.h"
+#include <fstream>
+#include <ios>
+
+/* 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)
enum glsl_interp_mode interp;
enum glsl_base_type base_type;
ubyte usage_mask; /* GLSL-style usage-mask, i.e. single bit per double */
+ bool invariant;
};
static struct inout_decl *
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;
bool has_tex_txf_lz;
bool precise;
bool need_uarl;
+ bool tg4_component_in_swizzle;
variable_storage *find_variable_storage(ir_variable *var);
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 *);
void visit_membar_intrinsic(ir_call *);
void visit_shared_intrinsic(ir_call *);
void visit_image_intrinsic(ir_call *);
- void visit_generic_intrinsic(ir_call *, unsigned op);
+ void visit_generic_intrinsic(ir_call *, enum tgsi_opcode op);
st_src_reg result;
/** List of glsl_to_tgsi_instruction */
exec_list instructions;
- glsl_to_tgsi_instruction *emit_asm(ir_instruction *ir, unsigned op,
+ glsl_to_tgsi_instruction *emit_asm(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst = undef_dst,
st_src_reg src0 = undef_src,
st_src_reg src1 = undef_src,
st_src_reg src2 = undef_src,
st_src_reg src3 = undef_src);
- glsl_to_tgsi_instruction *emit_asm(ir_instruction *ir, unsigned op,
+ glsl_to_tgsi_instruction *emit_asm(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst, st_dst_reg dst1,
st_src_reg src0 = undef_src,
st_src_reg src1 = undef_src,
st_src_reg src2 = undef_src,
st_src_reg src3 = undef_src);
- unsigned get_opcode(unsigned op,
- st_dst_reg dst,
- st_src_reg src0, st_src_reg src1);
+ enum tgsi_opcode get_opcode(enum tgsi_opcode op,
+ st_dst_reg dst,
+ st_src_reg src0, st_src_reg src1);
/**
* Emit the correct dot-product instruction for the type of arguments
st_src_reg src1,
unsigned elements);
- void emit_scalar(ir_instruction *ir, unsigned op,
+ void emit_scalar(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst, st_src_reg src0);
- void emit_scalar(ir_instruction *ir, unsigned op,
+ void emit_scalar(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst, st_src_reg src0, st_src_reg src1);
void emit_arl(ir_instruction *ir, st_dst_reg dst, st_src_reg src0);
st_src_reg *indirect,
unsigned *location);
st_src_reg canonicalize_gather_offset(st_src_reg offset);
+ bool handle_bound_deref(ir_dereference *ir);
bool try_emit_mad(ir_expression *ir,
int mul_operand);
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);
st_dst_reg *l, st_src_reg *r,
st_src_reg *cond, bool cond_swap);
+ void print_stats();
+
void *mem_ctx;
};
glsl_to_tgsi_instruction *
-glsl_to_tgsi_visitor::emit_asm(ir_instruction *ir, unsigned op,
+glsl_to_tgsi_visitor::emit_asm(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst, st_dst_reg dst1,
st_src_reg src0, st_src_reg src1,
st_src_reg src2, st_src_reg src3)
}
glsl_to_tgsi_instruction *
-glsl_to_tgsi_visitor::emit_asm(ir_instruction *ir, unsigned op,
+glsl_to_tgsi_visitor::emit_asm(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst,
st_src_reg src0, st_src_reg src1,
st_src_reg src2, st_src_reg src3)
* Determines whether to use an integer, unsigned integer, or float opcode
* based on the operands and input opcode, then emits the result.
*/
-unsigned
-glsl_to_tgsi_visitor::get_opcode(unsigned op,
+enum tgsi_opcode
+glsl_to_tgsi_visitor::get_opcode(enum tgsi_opcode op,
st_dst_reg dst,
st_src_reg src0, st_src_reg src1)
{
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);
st_dst_reg dst, st_src_reg src0, st_src_reg src1,
unsigned elements)
{
- static const unsigned dot_opcodes[] = {
+ static const enum tgsi_opcode dot_opcodes[] = {
TGSI_OPCODE_DP2, TGSI_OPCODE_DP3, TGSI_OPCODE_DP4
};
* to produce dest channels.
*/
void
-glsl_to_tgsi_visitor::emit_scalar(ir_instruction *ir, unsigned op,
+glsl_to_tgsi_visitor::emit_scalar(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst,
st_src_reg orig_src0, st_src_reg orig_src1)
{
}
void
-glsl_to_tgsi_visitor::emit_scalar(ir_instruction *ir, unsigned op,
+glsl_to_tgsi_visitor::emit_scalar(ir_instruction *ir, enum tgsi_opcode op,
st_dst_reg dst, st_src_reg src0)
{
st_src_reg undef = undef_src;
glsl_to_tgsi_visitor::emit_arl(ir_instruction *ir,
st_dst_reg dst, st_src_reg src0)
{
- int op = TGSI_OPCODE_ARL;
+ enum tgsi_opcode op = TGSI_OPCODE_ARL;
if (src0.type == GLSL_TYPE_INT || src0.type == GLSL_TYPE_UINT) {
if (!this->need_uarl && src0.is_legal_tgsi_address_operand())
* emit_asm() might have actually split the op into pieces, e.g. for
* double stores. We have to go back and fix up all the generated ops.
*/
- unsigned op = inst->op;
+ enum tgsi_opcode op = inst->op;
do {
inst->resource = *buf;
if (access)
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;
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);
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();
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;
case ir_binop_lshift:
case ir_binop_rshift:
if (native_integers) {
- unsigned opcode = ir->operation == ir_binop_lshift ? TGSI_OPCODE_SHL
- : TGSI_OPCODE_ISHR;
+ enum tgsi_opcode opcode = ir->operation == ir_binop_lshift
+ ? TGSI_OPCODE_SHL : TGSI_OPCODE_ISHR;
st_src_reg count;
if (glsl_base_type_is_64bit(op[0].type)) {
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) {
} 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;
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);
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:
/* This operation is not supported, or should have already been handled.
*/
assert(!"Invalid ir opcode in glsl_to_tgsi_visitor::visit()");
{
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
void
glsl_to_tgsi_visitor::visit(ir_dereference_variable *ir)
{
- variable_storage *entry = find_variable_storage(ir->var);
+ variable_storage *entry;
ir_variable *var = ir->var;
bool remove_array;
+ if (handle_bound_deref(ir->as_dereference()))
+ return;
+
+ entry = find_variable_storage(ir->var);
+
if (!entry) {
switch (var->data.mode) {
case ir_var_uniform:
unsigned num_components;
num_outputs++;
+ decl->invariant = var->data.invariant;
+
if (type_without_array->is_64bit())
component = component / 2;
if (type_without_array->vector_elements)
}
}
+
+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)
{
bool is_2D = false;
ir_variable *var = ir->variable_referenced();
- /* We only need the logic provided by st_glsl_storage_type_size()
+ if (handle_bound_deref(ir->as_dereference()))
+ return;
+
+ /* 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));
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;
}
}
ir_variable *var = ir->record->variable_referenced();
int offset = 0;
+ if (handle_bound_deref(ir->as_dereference()))
+ return;
+
ir->record->accept(this);
assert(ir->field_idx >= 0);
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. */
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);
GLdouble stack_vals[4] = { 0 };
gl_constant_value *values = (gl_constant_value *) stack_vals;
GLenum gl_type = GL_NONE;
- unsigned int i;
+ unsigned int i, elements;
static int in_array = 0;
gl_register_file file = in_array ? PROGRAM_CONSTANT : PROGRAM_IMMEDIATE;
* 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);
return;
}
+ elements = ir->type->vector_elements;
switch (ir->type->base_type) {
case GLSL_TYPE_FLOAT:
gl_type = GL_FLOAT;
values[i].u = ir->value.b[i] ? ctx->Const.UniformBooleanTrue : 0;
}
break;
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_IMAGE:
+ gl_type = GL_UNSIGNED_INT;
+ elements = 2;
+ values[0].u = ir->value.u64[0] & 0xffffffff;
+ values[1].u = ir->value.u64[0] >> 32;
+ break;
default:
- assert(!"Non-float/uint/int/bool constant");
+ assert(!"Non-float/uint/int/bool/sampler/image constant");
}
this->result = st_src_reg(file, -1, ir->type);
this->result.index = add_constant(file,
values,
- ir->type->vector_elements,
+ elements,
gl_type,
&this->result.swizzle);
}
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) {
val->accept(this);
st_src_reg data = this->result, data2 = undef_src;
- unsigned opcode;
+ enum tgsi_opcode opcode;
switch (ir->callee->intrinsic_id) {
case ir_intrinsic_atomic_counter_add:
opcode = TGSI_OPCODE_ATOMUADD;
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) {
val->accept(this);
st_src_reg data = this->result, data2 = undef_src;
- unsigned opcode;
+ enum tgsi_opcode opcode;
switch (ir->callee->intrinsic_id) {
case ir_intrinsic_ssbo_atomic_add:
opcode = TGSI_OPCODE_ATOMUADD;
val->accept(this);
st_src_reg data = this->result, data2 = undef_src;
- unsigned opcode;
+ enum tgsi_opcode opcode;
switch (ir->callee->intrinsic_id) {
case ir_intrinsic_shared_atomic_add:
opcode = TGSI_OPCODE_ATOMUADD;
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) {
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;
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;
}
*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;
}
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);
assert(param->is_tail_sentinel());
- unsigned opcode;
+ enum tgsi_opcode opcode;
switch (ir->callee->intrinsic_id) {
case ir_intrinsic_image_load:
opcode = TGSI_OPCODE_LOAD;
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;
}
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;
}
void
-glsl_to_tgsi_visitor::visit_generic_intrinsic(ir_call *ir, unsigned op)
+glsl_to_tgsi_visitor::visit_generic_intrinsic(ir_call *ir, enum tgsi_opcode op)
{
ir->return_deref->accept(this);
st_dst_reg dst = st_dst_reg(this->result);
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;
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:
case ir_intrinsic_generic_atomic_max:
case ir_intrinsic_generic_atomic_exchange:
case ir_intrinsic_generic_atomic_comp_swap:
+ case ir_intrinsic_begin_invocation_interlock:
+ case ir_intrinsic_end_invocation_interlock:
unreachable("Invalid intrinsic");
}
}
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;
}
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;
st_src_reg
glsl_to_tgsi_visitor::canonicalize_gather_offset(st_src_reg offset)
{
- if (offset.reladdr || offset.reladdr2) {
+ if (offset.reladdr || offset.reladdr2 ||
+ offset.has_index2 ||
+ offset.file == PROGRAM_UNIFORM ||
+ offset.file == PROGRAM_CONSTANT ||
+ offset.file == PROGRAM_STATE_VAR) {
st_src_reg tmp = get_temp(glsl_type::ivec2_type);
st_dst_reg tmp_dst = st_dst_reg(tmp);
tmp_dst.writemask = WRITEMASK_XY;
return offset;
}
+
+bool
+glsl_to_tgsi_visitor::handle_bound_deref(ir_dereference *ir)
+{
+ ir_variable *var = ir->variable_referenced();
+
+ if (!var || var->data.mode != ir_var_uniform || var->data.bindless ||
+ !(ir->type->is_image() || ir->type->is_sampler()))
+ return false;
+
+ /* Convert from bound sampler/image to bindless handle. */
+ bool is_image = ir->type->is_image();
+ st_src_reg resource(is_image ? PROGRAM_IMAGE : PROGRAM_SAMPLER, 0, GLSL_TYPE_UINT);
+ uint16_t index = 0;
+ unsigned array_size = 1, base = 0;
+ st_src_reg reladdr;
+ get_deref_offsets(ir, &array_size, &base, &index, &reladdr, true);
+
+ resource.index = index;
+ if (reladdr.file != PROGRAM_UNDEFINED) {
+ resource.reladdr = ralloc(mem_ctx, st_src_reg);
+ *resource.reladdr = reladdr;
+ emit_arl(ir, sampler_reladdr, reladdr);
+ }
+
+ this->result = get_temp(glsl_type::uvec2_type);
+ st_dst_reg dst(this->result);
+ dst.writemask = WRITEMASK_XY;
+
+ glsl_to_tgsi_instruction *inst = emit_asm(
+ ir, is_image ? TGSI_OPCODE_IMG2HND : TGSI_OPCODE_SAMP2HND, dst);
+
+ inst->tex_target = ir->type->sampler_index();
+ inst->resource = resource;
+ inst->sampler_array_size = array_size;
+ inst->sampler_base = base;
+
+ return true;
+}
void
glsl_to_tgsi_visitor::visit(ir_texture *ir)
st_src_reg levels_src, reladdr;
st_dst_reg result_dst, coord_dst, cube_sc_dst;
glsl_to_tgsi_instruction *inst = NULL;
- unsigned opcode = TGSI_OPCODE_NOP;
+ 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) {
}
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 {
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;
}
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 &&
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);
}
}
+void
+glsl_to_tgsi_visitor::visit(ir_demote *ir)
+{
+ emit_asm(ir, TGSI_OPCODE_DEMOTE);
+}
+
void
glsl_to_tgsi_visitor::visit(ir_if *ir)
{
- unsigned if_opcode;
+ enum tgsi_opcode if_opcode;
glsl_to_tgsi_instruction *if_inst;
ir->condition->accept(this);
ctx = NULL;
prog = NULL;
precise = 0;
+ need_uarl = false;
+ tg4_component_in_swizzle = false;
shader_program = NULL;
shader = NULL;
options = NULL;
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;
}
}
}
}
}
+template <typename st_reg>
+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 <typename st_reg>
+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.
*
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
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 -------------------------- */
/**
const ubyte *inputMapping;
const ubyte *outputMapping;
- unsigned procType; /**< PIPE_SHADER_VERTEX/FRAGMENT */
+ 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.
*/
case TGSI_OPCODE_TXL2:
case TGSI_OPCODE_TG4:
case TGSI_OPCODE_LODQ:
+ 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);
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++;
}
}
+/* 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
* 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 */
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 */
extern "C" enum pipe_error
st_translate_program(
struct gl_context *ctx,
- uint procType,
+ enum pipe_shader_type procType,
struct ureg_program *ureg,
glsl_to_tgsi_visitor *program,
const struct gl_program *proginfo,
(gl_texture_index) (NUM_TEXTURE_TARGETS - 1));
ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, image_format,
(enum pipe_format) (PIPE_FORMAT_COUNT - 1));
- ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, op, TGSI_OPCODE_LAST - 1);
+ ASSERT_BITFIELD_SIZE(glsl_to_tgsi_instruction, op,
+ (enum tgsi_opcode) (TGSI_OPCODE_LAST - 1));
t = CALLOC_STRUCT(st_translate);
if (!t) {
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;
(enum tgsi_semantic) outputSemanticName[slot],
outputSemanticIndex[slot],
decl->gs_out_streams,
- slot, tgsi_usage_mask, decl->array_id, decl->size);
-
+ slot, tgsi_usage_mask, decl->array_id, decl->size, decl->invariant);
+ dst.Invariant = decl->invariant;
for (unsigned j = 0; j < decl->size; ++j) {
if (t->outputs[slot + j].File != TGSI_FILE_OUTPUT) {
/* The ArrayID is set up in dst_register */
t->outputs[slot + j] = dst;
t->outputs[slot + j].ArrayID = 0;
t->outputs[slot + j].Index += j;
+ t->outputs[slot + j].Invariant = decl->invariant;
}
}
}
/* Declare misc input registers
*/
{
- GLbitfield sysInputs = proginfo->info.system_values_read;
+ GLbitfield64 sysInputs = proginfo->info.system_values_read;
for (i = 0; sysInputs; i++) {
- if (sysInputs & (1 << i)) {
- enum tgsi_semantic semName = _mesa_sysval_to_semantic(i);
+ if (sysInputs & (1ull << i)) {
+ enum tgsi_semantic semName = tgsi_get_sysval_semantic(i);
t->systemValues[i] = ureg_DECL_system_value(ureg, semName, 0);
emit_wpos(st_context(ctx), t, proginfo, ureg,
program->wpos_transform_const);
- sysInputs &= ~(1 << i);
+ if (procType == PIPE_SHADER_FRAGMENT &&
+ semName == TGSI_SEMANTIC_SAMPLEPOS)
+ emit_samplepos_adjustment(t, program->wpos_transform_const);
+
+ sysInputs &= ~(1ull << i);
}
}
}
t->num_constants = proginfo->Parameters->NumParameters;
for (i = 0; i < proginfo->Parameters->NumParameters; i++) {
+ unsigned pvo = proginfo->Parameters->ParameterValueOffset[i];
+
switch (proginfo->Parameters->Parameters[i].Type) {
case PROGRAM_STATE_VAR:
case PROGRAM_UNIFORM:
t->constants[i] = ureg_DECL_constant(ureg, i);
else
t->constants[i] = emit_immediate(t,
- proginfo->Parameters->ParameterValues[i],
+ proginfo->Parameters->ParameterValues + pvo,
proginfo->Parameters->Parameters[i].DataType,
4);
break;
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 {
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);
}
}
t->images[i] = ureg_DECL_image(ureg, i,
program->image_targets[i],
program->image_formats[i],
- true, false);
+ program->image_wr[i],
+ false);
}
}
}
}
break;
+ default:
+ ; /* nothing - silence compiler warning */
}
out:
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 =
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. */
}
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. */
/* 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 & (1 << 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
};
* 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;
}
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);
-
- 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 {
} while (progress);
}
- validate_ir_tree(ir);
- }
-
- build_program_resource_list(ctx, prog);
-
- if (use_nir)
- return st_link_nir(ctx, prog);
+ /* Do this again to lower ir_binop_vector_extract introduced
+ * by optimization passes.
+ */
+ do_vec_index_to_cond_assign(ir);
- for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
- struct gl_linked_shader *shader = prog->_LinkedShaders[i];
- if (shader == NULL)
- continue;
+ validate_ir_tree(ir);
struct gl_program *linked_prog =
get_mesa_program_tgsi(ctx, prog, shader);
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" */