summaryrefslogtreecommitdiff
path: root/src/mesa
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-07-13 09:05:28 -0700
committerEric Anholt <eric@anholt.net>2010-07-13 09:52:20 -0700
commitf8a2b65bc9bf3dfb4a4aa6fe1c0ea65f78a01922 (patch)
tree46f2fcaa3ea0bf21c704bebc5e6d03d22e1456d9 /src/mesa
parent4e6a3e0d2d148747002ab9e9c1dffe63e912c688 (diff)
ir_to_mesa: Add support for array dereferences on the LHS of assignments.
The big change is to delay address reg setup until the instruction that needs the deref. It was hard to use the deref chain support for the LHS because it does the copy of the dereffed value to a temporary (to avoid problems when two src regs are array derefs), so we wouldn't haev a pointer to actual storage in the end. Fixes glsl-vs-arrays on swrast.
Diffstat (limited to 'src/mesa')
-rw-r--r--src/mesa/shader/ir_to_mesa.cpp96
1 files changed, 67 insertions, 29 deletions
diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp
index 110fc100db..f4a8ceb09e 100644
--- a/src/mesa/shader/ir_to_mesa.cpp
+++ b/src/mesa/shader/ir_to_mesa.cpp
@@ -61,7 +61,8 @@ typedef struct ir_to_mesa_src_reg {
int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */
int negate; /**< NEGATE_XYZW mask from mesa */
- bool reladdr; /**< Register index should be offset by address reg. */
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
} ir_to_mesa_src_reg;
typedef struct ir_to_mesa_dst_reg {
@@ -69,6 +70,8 @@ typedef struct ir_to_mesa_dst_reg {
int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
GLuint cond_mask:4;
+ /** Register index should be offset by the integer in this reg. */
+ ir_to_mesa_src_reg *reladdr;
} ir_to_mesa_dst_reg;
extern ir_to_mesa_src_reg ir_to_mesa_undef;
@@ -111,6 +114,8 @@ public:
temp_entry *find_variable_storage(ir_variable *var);
ir_to_mesa_src_reg get_temp(const glsl_type *type);
+ void reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr);
struct ir_to_mesa_src_reg src_reg_for_float(float val);
@@ -191,15 +196,15 @@ public:
};
ir_to_mesa_src_reg ir_to_mesa_undef = {
- PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, false,
+ PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, NEGATE_NONE, NULL,
};
ir_to_mesa_dst_reg ir_to_mesa_undef_dst = {
- PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR
+ PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
};
ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
- PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR
+ PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
};
static int swizzle_for_size(int size)
@@ -223,6 +228,28 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
ir_to_mesa_src_reg src2)
{
ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction();
+ int num_reladdr = 0;
+
+ /* If we have to do relative addressing, we want to load the ARL
+ * reg directly for one of the regs, and preload the other reladdr
+ * sources into temps.
+ */
+ num_reladdr += dst.reladdr != NULL;
+ num_reladdr += src0.reladdr != NULL;
+ num_reladdr += src1.reladdr != NULL;
+ num_reladdr += src2.reladdr != NULL;
+
+ reladdr_to_temp(ir, &src2, &num_reladdr);
+ reladdr_to_temp(ir, &src1, &num_reladdr);
+ reladdr_to_temp(ir, &src0, &num_reladdr);
+
+ if (dst.reladdr) {
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
+ *dst.reladdr);
+
+ num_reladdr--;
+ }
+ assert(num_reladdr == 0);
inst->op = op;
inst->dst_reg = dst;
@@ -285,6 +312,7 @@ ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
dst_reg.index = reg.index;
dst_reg.writemask = WRITEMASK_XYZW;
dst_reg.cond_mask = COND_TR;
+ dst_reg.reladdr = reg.reladdr;
return dst_reg;
}
@@ -298,7 +326,7 @@ ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
src_reg.index = reg.index;
src_reg.swizzle = SWIZZLE_XYZW;
src_reg.negate = 0;
- src_reg.reladdr = 0;
+ src_reg.reladdr = reg.reladdr;
return src_reg;
}
@@ -378,7 +406,7 @@ ir_to_mesa_visitor::src_reg_for_float(float val)
src_reg.file = PROGRAM_CONSTANT;
src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
&val, 1, &src_reg.swizzle);
- src_reg.reladdr = GL_FALSE;
+ src_reg.reladdr = NULL;
src_reg.negate = 0;
return src_reg;
@@ -435,7 +463,7 @@ ir_to_mesa_visitor::get_temp(const glsl_type *type)
src_reg.file = PROGRAM_TEMPORARY;
src_reg.index = next_temp;
- src_reg.reladdr = false;
+ src_reg.reladdr = NULL;
next_temp += type_size(type);
for (i = 0; i < type->vector_elements; i++)
@@ -558,6 +586,26 @@ ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
}
void
+ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir,
+ ir_to_mesa_src_reg *reg, int *num_reladdr)
+{
+ if (!reg->reladdr)
+ return;
+
+ ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg, *reg->reladdr);
+
+ if (*num_reladdr != 1) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type);
+
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp), *reg);
+ *reg = temp;
+ }
+
+ (*num_reladdr)--;
+}
+
+void
ir_to_mesa_visitor::visit(ir_expression *ir)
{
unsigned int operand;
@@ -1045,7 +1093,7 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
src_reg.index = entry->index;
/* If the type is smaller than a vec4, replicate the last channel out. */
src_reg.swizzle = swizzle_for_size(ir->var->type->vector_elements);
- src_reg.reladdr = false;
+ src_reg.reladdr = NULL;
src_reg.negate = 0;
this->result = src_reg;
@@ -1077,7 +1125,7 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir)
src_reg.negate = 0;
if (index) {
- src_reg.reladdr = GL_FALSE;
+ src_reg.reladdr = NULL;
} else {
ir_to_mesa_src_reg index_reg = get_temp(glsl_type::float_type);
@@ -1086,9 +1134,8 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir)
ir_to_mesa_dst_reg_from_src(index_reg),
this->result, src_reg_for_float(element_size));
- src_reg.reladdr = true;
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
- index_reg);
+ src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
+ memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
}
this->result = src_reg;
@@ -1126,17 +1173,10 @@ ir_to_mesa_visitor::visit(ir_dereference_array *ir)
this->result, src_reg_for_float(element_size));
}
- /* FINISHME: This doesn't work when we're trying to do the LHS
- * of an assignment.
- */
- src_reg.reladdr = true;
- ir_to_mesa_emit_op1(ir, OPCODE_ARL, ir_to_mesa_address_reg,
- index_reg);
-
- this->result = get_temp(ir->type);
- ir_to_mesa_emit_op1(ir, OPCODE_MOV,
- ir_to_mesa_dst_reg_from_src(this->result),
- src_reg);
+ src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
+ memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
+
+ this->result = src_reg;
}
}
@@ -1183,9 +1223,6 @@ get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v)
/* This should have been handled by ir_vec_index_to_cond_assign */
if (deref_array) {
assert(!deref_array->array->type->is_vector());
-
- /* We don't handle relative addressing on the LHS yet. */
- assert(deref_array->array_index->constant_expression_value() != NULL);
}
/* Use the rvalue deref handler for the most part. We'll ignore
@@ -1313,7 +1350,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
values,
ir->type->vector_elements,
&src_reg.swizzle);
- src_reg.reladdr = false;
+ src_reg.reladdr = NULL;
src_reg.negate = 0;
ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
@@ -1350,7 +1387,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir)
src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
values, ir->type->vector_elements,
&src_reg.swizzle);
- src_reg.reladdr = false;
+ src_reg.reladdr = NULL;
src_reg.negate = 0;
this->result = src_reg;
@@ -1578,7 +1615,7 @@ mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg)
assert(reg.index < (1 << INST_INDEX_BITS) - 1);
mesa_reg.Index = reg.index;
mesa_reg.Swizzle = reg.swizzle;
- mesa_reg.RelAddr = reg.reladdr;
+ mesa_reg.RelAddr = reg.reladdr != NULL;
mesa_reg.Negate = reg.negate;
mesa_reg.Abs = 0;
@@ -1813,6 +1850,7 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader)
mesa_inst->DstReg.Index = inst->dst_reg.index;
mesa_inst->DstReg.CondMask = inst->dst_reg.cond_mask;
mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
+ mesa_inst->DstReg.RelAddr = inst->dst_reg.reladdr != NULL;
mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);