extern "C" {
#include "main/mtypes.h"
#include "shader/prog_instruction.h"
+#include "shader/prog_optimize.h"
#include "shader/prog_print.h"
#include "shader/program.h"
#include "shader/prog_uniform.h"
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 {
int file; /**< PROGRAM_* from Mesa */
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;
ir_to_mesa_src_reg src_reg[3];
/** Pointer to the ir source this tree came from for debugging */
ir_instruction *ir;
+ GLboolean cond_update;
+ int sampler; /**< sampler index */
+ int tex_target; /**< One of TEXTURE_*_INDEX */
+ GLboolean tex_shadow;
+
+ class function_entry *function; /* Set on OPCODE_CAL or OPCODE_BGNSUB */
};
-class temp_entry : public exec_node {
+class variable_storage : public exec_node {
public:
- temp_entry(ir_variable *var, int file, int index)
+ variable_storage(ir_variable *var, int file, int index)
: file(file), index(index), var(var)
{
/* empty */
ir_variable *var; /* variable that maps to this, if any */
};
+class function_entry : public exec_node {
+public:
+ ir_function_signature *sig;
+
+ /**
+ * identifier of this function signature used by the program.
+ *
+ * At the point that Mesa instructions for function calls are
+ * generated, we don't know the address of the first instruction of
+ * the function body. So we make the BranchTarget that is called a
+ * small integer and rewrite them during set_branchtargets().
+ */
+ int sig_id;
+
+ /**
+ * Pointer to first instruction of the function body.
+ *
+ * Set during function body emits after main() is processed.
+ */
+ ir_to_mesa_instruction *bgn_inst;
+
+ /**
+ * Index of the first instruction of the function body in actual
+ * Mesa IR.
+ *
+ * Set after convertion from ir_to_mesa_instruction to prog_instruction.
+ */
+ int inst;
+
+ /** Storage for the return value. */
+ ir_to_mesa_src_reg return_reg;
+};
+
class ir_to_mesa_visitor : public ir_visitor {
public:
ir_to_mesa_visitor();
+ function_entry *current_function;
+
GLcontext *ctx;
struct gl_program *prog;
int next_temp;
- temp_entry *find_variable_storage(ir_variable *var);
+ variable_storage *find_variable_storage(ir_variable *var);
+
+ function_entry *get_function_signature(ir_function_signature *sig);
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);
virtual void visit(ir_constant *);
virtual void visit(ir_call *);
virtual void visit(ir_return *);
+ virtual void visit(ir_discard *);
virtual void visit(ir_texture *);
virtual void visit(ir_if *);
/*@}*/
struct ir_to_mesa_src_reg result;
- /** List of temp_entry */
- exec_list variable_storage;
+ /** List of variable_storage */
+ exec_list variables;
+
+ /** List of function_entry */
+ exec_list function_signatures;
+ int next_signature_id;
/** List of ir_to_mesa_instruction */
exec_list instructions;
+ ir_to_mesa_instruction *ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op);
+
ir_to_mesa_instruction *ir_to_mesa_emit_op1(ir_instruction *ir,
enum prog_opcode op,
ir_to_mesa_dst_reg dst,
ir_to_mesa_dst_reg dst,
ir_to_mesa_src_reg src0);
+ void ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0,
+ ir_to_mesa_src_reg src1);
+
+ GLboolean try_emit_mad(ir_expression *ir,
+ int mul_operand);
+
+ int *sampler_map;
+ int sampler_map_size;
+
+ void map_sampler(int location, int sampler);
+ int get_sampler_number(int location);
+
void *mem_ctx;
};
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
+ PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL,
};
ir_to_mesa_dst_reg ir_to_mesa_address_reg = {
- PROGRAM_ADDRESS, 0, WRITEMASK_X
+ PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL
};
static int swizzle_for_size(int size)
return size_swizzles[size - 1];
}
-/* This list should match up with builtin_variables.h */
-static const struct {
- const char *name;
- int file;
- int index;
-} builtin_var_to_mesa_reg[] = {
- /* core_vs */
- {"gl_Position", PROGRAM_OUTPUT, VERT_RESULT_HPOS},
- {"gl_PointSize", PROGRAM_OUTPUT, VERT_RESULT_PSIZ},
-
- /* core_fs */
- {"gl_FragCoord", PROGRAM_INPUT, FRAG_ATTRIB_WPOS},
- {"gl_FrontFacing", PROGRAM_INPUT, FRAG_ATTRIB_FACE},
- {"gl_FragColor", PROGRAM_OUTPUT, FRAG_ATTRIB_COL0},
- {"gl_FragDepth", PROGRAM_UNDEFINED, FRAG_ATTRIB_WPOS}, /* FINISHME: WPOS.z */
-
- /* 110_deprecated_fs */
- {"gl_Color", PROGRAM_INPUT, FRAG_ATTRIB_COL0},
- {"gl_SecondaryColor", PROGRAM_INPUT, FRAG_ATTRIB_COL1},
- {"gl_FogFragCoord", PROGRAM_INPUT, FRAG_ATTRIB_FOGC},
- {"gl_TexCoord", PROGRAM_INPUT, FRAG_ATTRIB_TEX0}, /* array */
-
- /* 110_deprecated_vs */
- {"gl_Vertex", PROGRAM_INPUT, VERT_ATTRIB_POS},
- {"gl_Normal", PROGRAM_INPUT, VERT_ATTRIB_NORMAL},
- {"gl_Color", PROGRAM_INPUT, VERT_ATTRIB_COLOR0},
- {"gl_SecondaryColor", PROGRAM_INPUT, VERT_ATTRIB_COLOR1},
- {"gl_MultiTexCoord0", PROGRAM_INPUT, VERT_ATTRIB_TEX0},
- {"gl_MultiTexCoord1", PROGRAM_INPUT, VERT_ATTRIB_TEX1},
- {"gl_MultiTexCoord2", PROGRAM_INPUT, VERT_ATTRIB_TEX2},
- {"gl_MultiTexCoord3", PROGRAM_INPUT, VERT_ATTRIB_TEX3},
- {"gl_MultiTexCoord4", PROGRAM_INPUT, VERT_ATTRIB_TEX4},
- {"gl_MultiTexCoord5", PROGRAM_INPUT, VERT_ATTRIB_TEX5},
- {"gl_MultiTexCoord6", PROGRAM_INPUT, VERT_ATTRIB_TEX6},
- {"gl_MultiTexCoord7", PROGRAM_INPUT, VERT_ATTRIB_TEX7},
- {"gl_TexCoord", PROGRAM_OUTPUT, VERT_RESULT_TEX0}, /* array */
- {"gl_FogCoord", PROGRAM_INPUT, VERT_RESULT_FOGC},
- /*{"gl_ClipVertex", PROGRAM_OUTPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
- {"gl_FrontColor", PROGRAM_OUTPUT, VERT_RESULT_COL0},
- {"gl_BackColor", PROGRAM_OUTPUT, VERT_RESULT_BFC0},
- {"gl_FrontSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_COL1},
- {"gl_BackSecondaryColor", PROGRAM_OUTPUT, VERT_RESULT_BFC1},
- {"gl_FogFragCoord", PROGRAM_OUTPUT, VERT_RESULT_FOGC},
-
- /* 130_vs */
- /*{"gl_VertexID", PROGRAM_INPUT, VERT_ATTRIB_FOGC},*/ /* FINISHME */
-
- {"gl_FragData", PROGRAM_OUTPUT, FRAG_RESULT_DATA0}, /* array */
-};
-
ir_to_mesa_instruction *
ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir,
enum prog_opcode op,
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;
inst->src_reg[2] = src2;
inst->ir = ir;
+ inst->function = NULL;
+
this->instructions.push_tail(inst);
return inst;
src0, ir_to_mesa_undef, ir_to_mesa_undef);
}
+ir_to_mesa_instruction *
+ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir,
+ enum prog_opcode op)
+{
+ return ir_to_mesa_emit_op3(ir, op, ir_to_mesa_undef_dst,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef,
+ ir_to_mesa_undef);
+}
+
+void
+ir_to_mesa_visitor::map_sampler(int location, int sampler)
+{
+ if (this->sampler_map_size <= location) {
+ this->sampler_map = talloc_realloc(this->mem_ctx, this->sampler_map,
+ int, location + 1);
+ this->sampler_map_size = location + 1;
+ }
+
+ this->sampler_map[location] = sampler;
+}
+
+int
+ir_to_mesa_visitor::get_sampler_number(int location)
+{
+ assert(location < this->sampler_map_size);
+ return this->sampler_map[location];
+}
+
inline ir_to_mesa_dst_reg
ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
{
dst_reg.file = reg.file;
dst_reg.index = reg.index;
dst_reg.writemask = WRITEMASK_XYZW;
+ dst_reg.cond_mask = COND_TR;
+ dst_reg.reladdr = reg.reladdr;
return dst_reg;
}
+inline ir_to_mesa_src_reg
+ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg)
+{
+ ir_to_mesa_src_reg src_reg;
+
+ src_reg.file = reg.file;
+ src_reg.index = reg.index;
+ src_reg.swizzle = SWIZZLE_XYZW;
+ src_reg.negate = 0;
+ src_reg.reladdr = reg.reladdr;
+
+ return src_reg;
+}
+
/**
* Emits Mesa scalar opcodes to produce unique answers across channels.
*
* to produce dest channels.
*/
void
-ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir,
enum prog_opcode op,
ir_to_mesa_dst_reg dst,
- ir_to_mesa_src_reg src0)
+ ir_to_mesa_src_reg orig_src0,
+ ir_to_mesa_src_reg orig_src1)
{
int i, j;
int done_mask = ~dst.writemask;
for (i = 0; i < 4; i++) {
GLuint this_mask = (1 << i);
ir_to_mesa_instruction *inst;
- ir_to_mesa_src_reg src = src0;
+ ir_to_mesa_src_reg src0 = orig_src0;
+ ir_to_mesa_src_reg src1 = orig_src1;
if (done_mask & this_mask)
continue;
- GLuint src_swiz = GET_SWZ(src.swizzle, i);
+ GLuint src0_swiz = GET_SWZ(src0.swizzle, i);
+ GLuint src1_swiz = GET_SWZ(src1.swizzle, i);
for (j = i + 1; j < 4; j++) {
- if (!(done_mask & (1 << j)) && GET_SWZ(src.swizzle, j) == src_swiz) {
+ if (!(done_mask & (1 << j)) &&
+ GET_SWZ(src0.swizzle, j) == src0_swiz &&
+ GET_SWZ(src1.swizzle, j) == src1_swiz) {
this_mask |= (1 << j);
}
}
- src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz,
- src_swiz, src_swiz);
+ src0.swizzle = MAKE_SWIZZLE4(src0_swiz, src0_swiz,
+ src0_swiz, src0_swiz);
+ src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz,
+ src1_swiz, src1_swiz);
- inst = ir_to_mesa_emit_op1(ir, op,
+ inst = ir_to_mesa_emit_op2(ir, op,
dst,
- src);
+ src0,
+ src1);
inst->dst_reg.writemask = this_mask;
done_mask |= this_mask;
}
}
-struct ir_to_mesa_src_reg
-ir_to_mesa_visitor::src_reg_for_float(float val)
+void
+ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir,
+ enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
{
- ir_to_mesa_src_reg src_reg;
+ ir_to_mesa_src_reg undef = ir_to_mesa_undef;
- src_reg.file = PROGRAM_CONSTANT;
- src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
- &val, 1, &src_reg.swizzle);
+ undef.swizzle = SWIZZLE_XXXX;
- return src_reg;
+ ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef);
}
-/**
- * In the initial pass of codegen, we assign temporary numbers to
- * intermediate results. (not SSA -- variable assignments will reuse
- * storage). Actual register allocation for the Mesa VM occurs in a
- * pass over the Mesa IR later.
- */
-ir_to_mesa_src_reg
-ir_to_mesa_visitor::get_temp(const glsl_type *type)
+struct ir_to_mesa_src_reg
+ir_to_mesa_visitor::src_reg_for_float(float val)
{
ir_to_mesa_src_reg src_reg;
- int swizzle[4];
- int i;
-
- assert(!type->is_array());
- src_reg.file = PROGRAM_TEMPORARY;
- src_reg.index = type->matrix_columns;
- src_reg.reladdr = false;
-
- for (i = 0; i < type->vector_elements; i++)
- swizzle[i] = i;
- for (; i < 4; i++)
- swizzle[i] = type->vector_elements - 1;
- src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
- swizzle[2], swizzle[3]);
+ src_reg.file = PROGRAM_CONSTANT;
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ &val, 1, &src_reg.swizzle);
+ src_reg.reladdr = NULL;
+ src_reg.negate = 0;
return src_reg;
}
case GLSL_TYPE_FLOAT:
case GLSL_TYPE_BOOL:
if (type->is_matrix()) {
- return 4; /* FINISHME: Not all matrices are 4x4. */
+ return type->matrix_columns;
} else {
/* Regardless of size of vector, it gets a vec4. This is bad
* packing for things like floats, but otherwise arrays become a
}
}
-temp_entry *
+/**
+ * In the initial pass of codegen, we assign temporary numbers to
+ * intermediate results. (not SSA -- variable assignments will reuse
+ * storage). Actual register allocation for the Mesa VM occurs in a
+ * pass over the Mesa IR later.
+ */
+ir_to_mesa_src_reg
+ir_to_mesa_visitor::get_temp(const glsl_type *type)
+{
+ ir_to_mesa_src_reg src_reg;
+ int swizzle[4];
+ int i;
+
+ assert(!type->is_array());
+
+ src_reg.file = PROGRAM_TEMPORARY;
+ src_reg.index = next_temp;
+ src_reg.reladdr = NULL;
+ next_temp += type_size(type);
+
+ for (i = 0; i < type->vector_elements; i++)
+ swizzle[i] = i;
+ for (; i < 4; i++)
+ swizzle[i] = type->vector_elements - 1;
+ src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1],
+ swizzle[2], swizzle[3]);
+ src_reg.negate = 0;
+
+ return src_reg;
+}
+
+variable_storage *
ir_to_mesa_visitor::find_variable_storage(ir_variable *var)
{
- temp_entry *entry;
+ variable_storage *entry;
- foreach_iter(exec_list_iterator, iter, this->variable_storage) {
- entry = (temp_entry *)iter.get();
+ foreach_iter(exec_list_iterator, iter, this->variables) {
+ entry = (variable_storage *)iter.get();
if (entry->var == var)
return entry;
assert(!ir->increment);
assert(!ir->counter);
- ir_to_mesa_emit_op1(NULL, OPCODE_BGNLOOP,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
-
+ ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP);
visit_exec_list(&ir->body_instructions, this);
-
- ir_to_mesa_emit_op1(NULL, OPCODE_ENDLOOP,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP);
}
void
{
switch (ir->mode) {
case ir_loop_jump::jump_break:
- ir_to_mesa_emit_op1(NULL, OPCODE_BRK,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ ir_to_mesa_emit_op0(NULL, OPCODE_BRK);
break;
case ir_loop_jump::jump_continue:
- ir_to_mesa_emit_op1(NULL, OPCODE_CONT,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ ir_to_mesa_emit_op0(NULL, OPCODE_CONT);
break;
}
}
}
}
+GLboolean
+ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
+{
+ int nonmul_operand = 1 - mul_operand;
+ ir_to_mesa_src_reg a, b, c;
+
+ ir_expression *expr = ir->operands[mul_operand]->as_expression();
+ if (!expr || expr->operation != ir_binop_mul)
+ return false;
+
+ expr->operands[0]->accept(this);
+ a = this->result;
+ expr->operands[1]->accept(this);
+ b = this->result;
+ ir->operands[nonmul_operand]->accept(this);
+ c = this->result;
+
+ this->result = get_temp(ir->type);
+ ir_to_mesa_emit_op3(ir, OPCODE_MAD,
+ ir_to_mesa_dst_reg_from_src(this->result), a, b, c);
+
+ return true;
+}
+
+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)
{
const glsl_type *vec3_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 3, 1);
const glsl_type *vec2_type = glsl_type::get_instance(GLSL_TYPE_FLOAT, 2, 1);
+ /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c)
+ */
+ if (ir->operation == ir_binop_add) {
+ if (try_emit_mad(ir, 1))
+ return;
+ if (try_emit_mad(ir, 0))
+ return;
+ }
+
for (operand = 0; operand < ir->get_num_operands(); operand++) {
this->result.file = PROGRAM_UNDEFINED;
ir->operands[operand]->accept(this);
}
op[operand] = this->result;
- /* Only expression implemented for matrices yet */
- assert(!ir->operands[operand]->type->is_matrix() ||
- ir->operation == ir_binop_mul);
+ /* Matrix expression operands should have been broken down to vector
+ * operations already.
+ */
+ assert(!ir->operands[operand]->type->is_matrix());
}
this->result.file = PROGRAM_UNDEFINED;
op[0].negate = ~op[0].negate;
result_src = op[0];
break;
+ case ir_unop_abs:
+ ir_to_mesa_emit_op1(ir, OPCODE_ABS, result_dst, op[0]);
+ break;
+ case ir_unop_sign:
+ ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]);
+ break;
+ case ir_unop_rcp:
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[0]);
+ break;
+
case ir_unop_exp:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_EXP, result_dst, op[0]);
+ ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst,
+ src_reg_for_float(M_E), op[0]);
break;
case ir_unop_exp2:
ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]);
case ir_unop_cos:
ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]);
break;
+
+ case ir_unop_dFdx:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]);
+ break;
+ case ir_unop_dFdy:
+ ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]);
+ break;
+
case ir_binop_add:
ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]);
break;
case ir_binop_sub:
ir_to_mesa_emit_op2(ir, OPCODE_SUB, result_dst, op[0], op[1]);
break;
+
case ir_binop_mul:
- if (ir->operands[0]->type->is_matrix() &&
- !ir->operands[1]->type->is_matrix()) {
- if (ir->operands[0]->type->is_scalar()) {
- ir_to_mesa_dst_reg dst_column = result_dst;
- ir_to_mesa_src_reg src_column = op[0];
- for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- dst_column, src_column, op[1]);
- dst_column.index++;
- src_column.index++;
- }
- } else {
- ir_to_mesa_dst_reg dst_chan = result_dst;
- ir_to_mesa_src_reg src_column = op[0];
- ir_to_mesa_src_reg src_chan = op[1];
- for (int i = 0; i < ir->operands[0]->type->matrix_columns; i++) {
- dst_chan.writemask = (1 << i);
- src_chan.swizzle = MAKE_SWIZZLE4(i, i, i, i);
- ir_to_mesa_emit_op2(ir, OPCODE_MUL,
- dst_chan, src_column, src_chan);
- src_column.index++;
- }
- }
- } else {
- assert(!ir->operands[0]->type->is_matrix());
- assert(!ir->operands[1]->type->is_matrix());
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
- }
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]);
break;
case ir_binop_div:
- ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, op[1]);
- ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], result_src);
+ assert(!"not reached: should be handled by ir_div_to_mul_rcp");
+ case ir_binop_mod:
+ assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
break;
case ir_binop_less:
op[0], op[1]);
}
break;
+
+ case ir_binop_cross:
+ ir_to_mesa_emit_op2(ir, OPCODE_XPD, result_dst, op[0], op[1]);
+ break;
+
case ir_unop_sqrt:
ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
- ir_to_mesa_emit_op1(ir, OPCODE_RCP, result_dst, result_src);
+ ir_to_mesa_emit_scalar_op1(ir, OPCODE_RCP, result_dst, result_src);
+ /* For incoming channels < 0, set the result to 0. */
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst,
+ op[0], src_reg_for_float(0.0), result_src);
break;
case ir_unop_rsq:
ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]);
break;
case ir_unop_i2f:
+ case ir_unop_b2f:
+ case ir_unop_b2i:
/* Mesa IR lacks types, ints are stored as truncated floats. */
result_src = op[0];
break;
ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]);
break;
case ir_unop_f2b:
+ case ir_unop_i2b:
ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst,
result_src, src_reg_for_float(0.0));
break;
case ir_unop_floor:
ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]);
break;
+ case ir_unop_fract:
+ ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]);
+ break;
+
case ir_binop_min:
ir_to_mesa_emit_op2(ir, OPCODE_MIN, result_dst, op[0], op[1]);
break;
case ir_binop_max:
ir_to_mesa_emit_op2(ir, OPCODE_MAX, result_dst, op[0], op[1]);
break;
- default:
- ir_print_visitor v;
- printf("Failed to get tree for expression:\n");
- ir->accept(&v);
- exit(1);
+ case ir_binop_pow:
+ ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]);
+ break;
+
+ case ir_unop_bit_not:
+ case ir_unop_u2f:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ assert(!"GLSL 1.30 features unsupported");
break;
}
if (i < ir->type->vector_elements) {
switch (i) {
case 0:
- swizzle[i] = ir->mask.x;
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x);
break;
case 1:
- swizzle[i] = ir->mask.y;
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y);
break;
case 2:
- swizzle[i] = ir->mask.z;
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z);
break;
case 3:
- swizzle[i] = ir->mask.w;
+ swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w);
break;
}
} else {
/* If the type is smaller than a vec4, replicate the last
* channel out.
*/
- swizzle[i] = ir->type->vector_elements - 1;
+ swizzle[i] = swizzle[ir->type->vector_elements - 1];
}
}
this->result = src_reg;
}
-static temp_entry *
-get_builtin_matrix_ref(void *mem_ctx, struct gl_program *prog, ir_variable *var)
+static int
+add_matrix_ref(struct gl_program *prog, int *tokens)
+{
+ int base_pos = -1;
+ int i;
+
+ /* Add a ref for each column. It looks like the reason we do
+ * it this way is that _mesa_add_state_reference doesn't work
+ * for things that aren't vec4s, so the tokens[2]/tokens[3]
+ * range has to be equal.
+ */
+ for (i = 0; i < 4; i++) {
+ tokens[2] = i;
+ tokens[3] = i;
+ int pos = _mesa_add_state_reference(prog->Parameters,
+ (gl_state_index *)tokens);
+ if (base_pos == -1)
+ base_pos = pos;
+ else
+ assert(base_pos + i == pos);
+ }
+
+ return base_pos;
+}
+
+static variable_storage *
+get_builtin_matrix_ref(void *mem_ctx, struct gl_program *prog, ir_variable *var,
+ ir_rvalue *array_index)
{
/*
* NOTE: The ARB_vertex_program extension specified that matrices get
};
unsigned int i;
- temp_entry *entry;
+ variable_storage *entry;
/* C++ gets angry when we try to use an int as a gl_state_index, so we use
* ints for gl_state_index. Make sure they're compatible.
for (i = 0; i < Elements(matrices); i++) {
if (strcmp(var->name, matrices[i].name) == 0) {
- int j;
- int last_pos = -1, base_pos = -1;
int tokens[STATE_LENGTH];
+ int base_pos = -1;
tokens[0] = matrices[i].matrix;
- tokens[1] = 0; /* array index! */
tokens[4] = matrices[i].modifier;
-
- /* Add a ref for each column. It looks like the reason we do
- * it this way is that _mesa_add_state_reference doesn't work
- * for things that aren't vec4s, so the tokens[2]/tokens[3]
- * range has to be equal.
- */
- for (j = 0; j < 4; j++) {
- tokens[2] = j;
- tokens[3] = j;
- int pos = _mesa_add_state_reference(prog->Parameters,
- (gl_state_index *)tokens);
- assert(last_pos == -1 || last_pos == base_pos + j);
- if (base_pos == -1)
- base_pos = pos;
+ if (matrices[i].matrix == STATE_TEXTURE_MATRIX) {
+ ir_constant *index = array_index->constant_expression_value();
+ if (index) {
+ tokens[1] = index->value.i[0];
+ base_pos = add_matrix_ref(prog, tokens);
+ } else {
+ for (i = 0; i < var->type->length; i++) {
+ tokens[1] = i;
+ int pos = add_matrix_ref(prog, tokens);
+ if (base_pos == -1)
+ base_pos = pos;
+ else
+ assert(base_pos + (int)i * 4 == pos);
+ }
+ }
+ } else {
+ tokens[1] = 0; /* unused array index */
+ base_pos = add_matrix_ref(prog, tokens);
}
+ tokens[4] = matrices[i].modifier;
- entry = new(mem_ctx) temp_entry(var,
- PROGRAM_STATE_VAR,
- base_pos);
+ entry = new(mem_ctx) variable_storage(var,
+ PROGRAM_STATE_VAR,
+ base_pos);
return entry;
}
ir_to_mesa_visitor::visit(ir_dereference_variable *ir)
{
ir_to_mesa_src_reg src_reg;
- temp_entry *entry = find_variable_storage(ir->var);
- unsigned int i, loc;
- bool var_in;
+ variable_storage *entry = find_variable_storage(ir->var);
+ unsigned int loc;
if (!entry) {
switch (ir->var->mode) {
case ir_var_uniform:
- entry = get_builtin_matrix_ref(this->mem_ctx, this->prog, ir->var);
+ entry = get_builtin_matrix_ref(this->mem_ctx, this->prog, ir->var,
+ NULL);
if (entry)
break;
/* FINISHME: Fix up uniform name for arrays and things */
+ if (ir->var->type->base_type == GLSL_TYPE_SAMPLER) {
+ /* FINISHME: we whack the location of the var here, which
+ * is probably not expected. But we need to communicate
+ * mesa's sampler number to the tex instruction.
+ */
+ int sampler = _mesa_add_sampler(this->prog->Parameters,
+ ir->var->name,
+ ir->var->type->gl_type);
+ map_sampler(ir->var->location, sampler);
+
+ entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_SAMPLER,
+ sampler);
+ this->variables.push_tail(entry);
+ break;
+ }
+
assert(ir->var->type->gl_type != 0 &&
ir->var->type->gl_type != GL_INVALID_ENUM);
loc = _mesa_add_uniform(this->prog->Parameters,
type_size(ir->var->type) * 4,
ir->var->type->gl_type,
NULL);
+
/* Always mark the uniform used at this point. If it isn't
* used, dead code elimination should have nuked the decl already.
*/
this->prog->Parameters->Parameters[loc].Used = GL_TRUE;
- entry = new(mem_ctx) temp_entry(ir->var, PROGRAM_UNIFORM, loc);
- this->variable_storage.push_tail(entry);
+ entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_UNIFORM, loc);
+ this->variables.push_tail(entry);
break;
case ir_var_in:
case ir_var_out:
case ir_var_inout:
- var_in = (ir->var->mode == ir_var_in ||
- ir->var->mode == ir_var_inout);
-
- for (i = 0; i < ARRAY_SIZE(builtin_var_to_mesa_reg); i++) {
- bool in = builtin_var_to_mesa_reg[i].file == PROGRAM_INPUT;
-
- if (strcmp(ir->var->name, builtin_var_to_mesa_reg[i].name) == 0 &&
- !(var_in ^ in))
- break;
- }
- if (i == ARRAY_SIZE(builtin_var_to_mesa_reg)) {
- printf("Failed to find builtin for %s variable %s\n",
- var_in ? "in" : "out",
- ir->var->name);
- abort();
+ /* The linker assigns locations for varyings and attributes,
+ * including deprecated builtins (like gl_Color), user-assign
+ * generic attributes (glBindVertexLocation), and
+ * user-defined varyings.
+ *
+ * FINISHME: We would hit this path for function arguments. Fix!
+ */
+ assert(ir->var->location != -1);
+ if (ir->var->mode == ir_var_in ||
+ ir->var->mode == ir_var_inout) {
+ entry = new(mem_ctx) variable_storage(ir->var,
+ PROGRAM_INPUT,
+ ir->var->location);
+
+ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB &&
+ ir->var->location >= VERT_ATTRIB_GENERIC0) {
+ _mesa_add_attribute(prog->Attributes,
+ ir->var->name,
+ type_size(ir->var->type) * 4,
+ ir->var->type->gl_type,
+ ir->var->location - VERT_ATTRIB_GENERIC0);
+ }
+ } else {
+ entry = new(mem_ctx) variable_storage(ir->var,
+ PROGRAM_OUTPUT,
+ ir->var->location);
}
- entry = new(mem_ctx) temp_entry(ir->var,
- builtin_var_to_mesa_reg[i].file,
- builtin_var_to_mesa_reg[i].index);
+
break;
case ir_var_auto:
- entry = new(mem_ctx) temp_entry(ir->var, PROGRAM_TEMPORARY,
- this->next_temp);
- this->variable_storage.push_tail(entry);
+ case ir_var_temporary:
+ entry = new(mem_ctx) variable_storage(ir->var, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(entry);
next_temp += type_size(ir->var->type);
break;
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;
{
ir_constant *index;
ir_to_mesa_src_reg src_reg;
+ ir_dereference_variable *deref_var = ir->array->as_dereference_variable();
+ int element_size = type_size(ir->type);
index = ir->array_index->constant_expression_value();
- /* By the time we make it to this stage, matrices should be broken down
- * to vectors.
- */
- assert(!ir->type->is_matrix());
+ if (deref_var && strncmp(deref_var->var->name,
+ "gl_TextureMatrix",
+ strlen("gl_TextureMatrix")) == 0) {
+ ir_to_mesa_src_reg src_reg;
+ struct variable_storage *entry;
- ir->array->accept(this);
- src_reg = this->result;
+ entry = get_builtin_matrix_ref(this->mem_ctx, this->prog, deref_var->var,
+ ir->array_index);
+ assert(entry);
- if (src_reg.file == PROGRAM_INPUT ||
- src_reg.file == PROGRAM_OUTPUT) {
- assert(index); /* FINISHME: Handle variable indexing of builtins. */
+ src_reg.file = entry->file;
+ src_reg.index = entry->index;
+ src_reg.swizzle = swizzle_for_size(ir->type->vector_elements);
+ src_reg.negate = 0;
- src_reg.index += index->value.i[0];
- } else {
if (index) {
- src_reg.index += index->value.i[0];
+ src_reg.reladdr = NULL;
} else {
- ir_to_mesa_src_reg array_base = this->result;
- /* Variable index array dereference. It eats the "vec4" of the
- * base of the array and an index that offsets the Mesa register
- * index.
- */
+ ir_to_mesa_src_reg index_reg = get_temp(glsl_type::float_type);
+
ir->array_index->accept(this);
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ ir_to_mesa_dst_reg_from_src(index_reg),
+ 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,
- this->result);
-
- 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;
+ return;
+ }
+
+ ir->array->accept(this);
+ src_reg = this->result;
+
+ if (index) {
+ src_reg.index += index->value.i[0] * element_size;
+ } else {
+ ir_to_mesa_src_reg array_base = this->result;
+ /* Variable index array dereference. It eats the "vec4" of the
+ * base of the array and an index that offsets the Mesa register
+ * index.
+ */
+ ir->array_index->accept(this);
+
+ ir_to_mesa_src_reg index_reg;
+
+ if (element_size == 1) {
+ index_reg = this->result;
+ } else {
+ index_reg = get_temp(glsl_type::float_type);
+
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL,
+ ir_to_mesa_dst_reg_from_src(index_reg),
+ this->result, src_reg_for_float(element_size));
+ }
+
+ src_reg.reladdr = talloc(mem_ctx, ir_to_mesa_src_reg);
+ memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg));
}
/* If the type is smaller than a vec4, replicate the last channel out. */
* those, then go use ir_dereference to handle the rest.
*/
static struct ir_to_mesa_dst_reg
-get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v)
+get_assignment_lhs(ir_instruction *ir, ir_to_mesa_visitor *v,
+ ir_to_mesa_src_reg *r)
{
struct ir_to_mesa_dst_reg dst_reg;
- ir_dereference *deref;
ir_swizzle *swiz;
+ ir_dereference_array *deref_array = ir->as_dereference_array();
+ /* This should have been handled by ir_vec_index_to_cond_assign */
+ if (deref_array) {
+ assert(!deref_array->array->type->is_vector());
+ }
+
/* Use the rvalue deref handler for the most part. We'll ignore
* swizzles in it and write swizzles using writemask, though.
*/
ir->accept(v);
dst_reg = ir_to_mesa_dst_reg_from_src(v->result);
- if ((deref = ir->as_dereference())) {
- ir_dereference_array *deref_array = ir->as_dereference_array();
- assert(!deref_array || deref_array->array->type->is_array());
+ if ((swiz = ir->as_swizzle())) {
+ int swizzles[4] = {
+ swiz->mask.x,
+ swiz->mask.y,
+ swiz->mask.z,
+ swiz->mask.w
+ };
+ int new_r_swizzle[4];
+ int orig_r_swizzle = r->swizzle;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ new_r_swizzle[i] = GET_SWZ(orig_r_swizzle, 0);
+ }
- ir->accept(v);
- } else if ((swiz = ir->as_swizzle())) {
dst_reg.writemask = 0;
- if (swiz->mask.num_components >= 1)
- dst_reg.writemask |= (1 << swiz->mask.x);
- if (swiz->mask.num_components >= 2)
- dst_reg.writemask |= (1 << swiz->mask.y);
- if (swiz->mask.num_components >= 3)
- dst_reg.writemask |= (1 << swiz->mask.z);
- if (swiz->mask.num_components >= 4)
- dst_reg.writemask |= (1 << swiz->mask.w);
+ for (i = 0; i < 4; i++) {
+ if (i < swiz->mask.num_components) {
+ dst_reg.writemask |= 1 << swizzles[i];
+ new_r_swizzle[swizzles[i]] = GET_SWZ(orig_r_swizzle, i);
+ }
+ }
+
+ r->swizzle = MAKE_SWIZZLE4(new_r_swizzle[0],
+ new_r_swizzle[1],
+ new_r_swizzle[2],
+ new_r_swizzle[3]);
}
return dst_reg;
{
struct ir_to_mesa_dst_reg l;
struct ir_to_mesa_src_reg r;
+ int i;
- assert(!ir->lhs->type->is_matrix());
assert(!ir->lhs->type->is_array());
assert(ir->lhs->type->base_type != GLSL_TYPE_STRUCT);
- l = get_assignment_lhs(ir->lhs, this);
-
ir->rhs->accept(this);
r = this->result;
+
+ l = get_assignment_lhs(ir->lhs, this, &r);
+
assert(l.file != PROGRAM_UNDEFINED);
assert(r.file != PROGRAM_UNDEFINED);
if (ir->condition) {
- ir_constant *condition_constant;
-
- condition_constant = ir->condition->constant_expression_value();
-
- assert(condition_constant && condition_constant->value.b[0]);
+ ir_to_mesa_src_reg condition;
+
+ ir->condition->accept(this);
+ condition = this->result;
+
+ /* We use the OPCODE_CMP (a < 0 ? b : c) for conditional moves,
+ * and the condition we produced is 0.0 or 1.0. By flipping the
+ * sign, we can choose which value OPCODE_CMP produces without
+ * an extra computing the condition.
+ */
+ condition.negate = ~condition.negate;
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ ir_to_mesa_emit_op3(ir, OPCODE_CMP, l,
+ condition, r, ir_to_mesa_src_reg_from_dst(l));
+ l.index++;
+ r.index++;
+ }
+ } else {
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
}
-
- ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
}
GLfloat *values = stack_vals;
unsigned int i;
- if (ir->type->is_matrix() || ir->type->is_array()) {
- assert(!"FINISHME: array/matrix constants");
+ if (ir->type->is_array()) {
+ ir->print();
+ printf("\n");
+ assert(!"FINISHME: array constants");
+ }
+
+ if (ir->type->is_matrix()) {
+ /* Unfortunately, 4 floats is all we can get into
+ * _mesa_add_unnamed_constant. So, make a temp to store the
+ * matrix and move each constant value into it. If we get
+ * lucky, copy propagation will eliminate the extra moves.
+ */
+ ir_to_mesa_src_reg mat = get_temp(glsl_type::vec4_type);
+ ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat);
+
+ for (i = 0; i < ir->type->matrix_columns; i++) {
+ src_reg.file = PROGRAM_CONSTANT;
+
+ assert(ir->type->base_type == GLSL_TYPE_FLOAT);
+ values = &ir->value.f[i * ir->type->vector_elements];
+
+ src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters,
+ values,
+ ir->type->vector_elements,
+ &src_reg.swizzle);
+ src_reg.reladdr = NULL;
+ src_reg.negate = 0;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg);
+
+ mat_column.index++;
+ }
+
+ this->result = mat;
}
src_reg.file = PROGRAM_CONSTANT;
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;
}
+function_entry *
+ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig)
+{
+ function_entry *entry;
+
+ foreach_iter(exec_list_iterator, iter, this->function_signatures) {
+ entry = (function_entry *)iter.get();
+
+ if (entry->sig == sig)
+ return entry;
+ }
+
+ entry = talloc(mem_ctx, function_entry);
+ entry->sig = sig;
+ entry->sig_id = this->next_signature_id++;
+ entry->bgn_inst = NULL;
+
+ /* Allocate storage for all the parameters. */
+ foreach_iter(exec_list_iterator, iter, sig->parameters) {
+ ir_variable *param = (ir_variable *)iter.get();
+ variable_storage *storage;
+
+ storage = find_variable_storage(param);
+ assert(!storage);
+
+ storage = new(mem_ctx) variable_storage(param, PROGRAM_TEMPORARY,
+ this->next_temp);
+ this->variables.push_tail(storage);
+
+ this->next_temp += type_size(param->type);
+ break;
+ }
+
+ if (sig->return_type) {
+ entry->return_reg = get_temp(sig->return_type);
+ } else {
+ entry->return_reg = ir_to_mesa_undef;
+ }
+
+ this->function_signatures.push_tail(entry);
+ return entry;
+}
void
ir_to_mesa_visitor::visit(ir_call *ir)
{
- printf("Can't support call to %s\n", ir->callee_name());
- exit(1);
+ ir_to_mesa_instruction *call_inst;
+ ir_function_signature *sig = ir->get_callee();
+ function_entry *entry = get_function_signature(sig);
+ int i;
+
+ /* Process in parameters. */
+ exec_list_iterator sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_in ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ param_rval->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ ir_to_mesa_dst_reg l;
+ l.file = storage->file;
+ l.index = storage->index;
+ l.reladdr = NULL;
+ l.writemask = WRITEMASK_XYZW;
+ l.cond_mask = COND_TR;
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Emit call instruction */
+ call_inst = ir_to_mesa_emit_op1(ir, OPCODE_CAL,
+ ir_to_mesa_undef_dst, ir_to_mesa_undef);
+ call_inst->function = entry;
+
+ /* Process out parameters. */
+ sig_iter = sig->parameters.iterator();
+ foreach_iter(exec_list_iterator, iter, *ir) {
+ ir_rvalue *param_rval = (ir_rvalue *)iter.get();
+ ir_variable *param = (ir_variable *)sig_iter.get();
+
+ if (param->mode == ir_var_out ||
+ param->mode == ir_var_inout) {
+ variable_storage *storage = find_variable_storage(param);
+ assert(storage);
+
+ ir_to_mesa_src_reg r;
+ r.file = storage->file;
+ r.index = storage->index;
+ r.reladdr = NULL;
+ r.swizzle = SWIZZLE_NOOP;
+ r.negate = 0;
+
+ param_rval->accept(this);
+ ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result);
+
+ for (i = 0; i < type_size(param->type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ sig_iter.next();
+ }
+ assert(!sig_iter.has_next());
+
+ /* Process return value. */
+ this->result = entry->return_reg;
}
void
ir_to_mesa_visitor::visit(ir_texture *ir)
{
- assert(0);
+ ir_to_mesa_src_reg result_src, coord, lod_info = { 0 }, projector;
+ ir_to_mesa_dst_reg result_dst, coord_dst;
+ ir_to_mesa_instruction *inst = NULL;
+ prog_opcode opcode = OPCODE_NOP;
ir->coordinate->accept(this);
+
+ /* Put our coords in a temp. We'll need to modify them for shadow,
+ * projection, or LOD, so the only case we'd use it as is is if
+ * we're doing plain old texturing. Mesa IR optimization should
+ * handle cleaning up our mess in that case.
+ */
+ coord = get_temp(glsl_type::vec4_type);
+ coord_dst = ir_to_mesa_dst_reg_from_src(coord);
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst,
+ this->result);
+
+ if (ir->projector) {
+ ir->projector->accept(this);
+ projector = this->result;
+ }
+
+ /* Storage for our result. Ideally for an assignment we'd be using
+ * the actual storage for the result here, instead.
+ */
+ result_src = get_temp(glsl_type::vec4_type);
+ result_dst = ir_to_mesa_dst_reg_from_src(result_src);
+
+ switch (ir->op) {
+ case ir_tex:
+ opcode = OPCODE_TEX;
+ break;
+ case ir_txb:
+ opcode = OPCODE_TXB;
+ ir->lod_info.bias->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txl:
+ opcode = OPCODE_TXL;
+ ir->lod_info.lod->accept(this);
+ lod_info = this->result;
+ break;
+ case ir_txd:
+ case ir_txf:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+
+ if (ir->projector) {
+ if (opcode == OPCODE_TEX) {
+ /* Slot the projector in as the last component of the coord. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, projector);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ opcode = OPCODE_TXP;
+ } else {
+ ir_to_mesa_src_reg coord_w = coord;
+ coord_w.swizzle = SWIZZLE_WWWW;
+
+ /* For the other TEX opcodes there's no projective version
+ * since the last slot is taken up by lod info. Do the
+ * projective divide now.
+ */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector);
+
+ coord_dst.writemask = WRITEMASK_XYZ;
+ ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w);
+
+ coord_dst.writemask = WRITEMASK_XYZW;
+ coord.swizzle = SWIZZLE_XYZW;
+ }
+ }
+
+ if (ir->shadow_comparitor) {
+ /* Slot the shadow value in as the second to last component of the
+ * coord.
+ */
+ ir->shadow_comparitor->accept(this);
+ coord_dst.writemask = WRITEMASK_Z;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, this->result);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ if (opcode == OPCODE_TXL || opcode == OPCODE_TXB) {
+ /* Mesa IR stores lod or lod bias in the last channel of the coords. */
+ coord_dst.writemask = WRITEMASK_W;
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, coord_dst, lod_info);
+ coord_dst.writemask = WRITEMASK_XYZW;
+ }
+
+ inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord);
+
+ if (ir->shadow_comparitor)
+ inst->tex_shadow = GL_TRUE;
+
+ ir_dereference_variable *sampler = ir->sampler->as_dereference_variable();
+ assert(sampler); /* FINISHME: sampler arrays */
+ /* generate the mapping, remove when we generate storage at
+ * declaration time
+ */
+ sampler->accept(this);
+
+ inst->sampler = get_sampler_number(sampler->var->location);
+
+ switch (sampler->type->sampler_dimensionality) {
+ case GLSL_SAMPLER_DIM_1D:
+ inst->tex_target = TEXTURE_1D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_2D:
+ inst->tex_target = TEXTURE_2D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_3D:
+ inst->tex_target = TEXTURE_3D_INDEX;
+ break;
+ case GLSL_SAMPLER_DIM_CUBE:
+ inst->tex_target = TEXTURE_CUBE_INDEX;
+ break;
+ default:
+ assert(!"FINISHME: other texture targets");
+ }
+
+ this->result = result_src;
}
void
ir_to_mesa_visitor::visit(ir_return *ir)
{
- assert(0);
+ assert(current_function);
+
+ if (ir->get_value()) {
+ ir_to_mesa_dst_reg l;
+ int i;
- ir->get_value()->accept(this);
+ ir->get_value()->accept(this);
+ ir_to_mesa_src_reg r = this->result;
+
+ l = ir_to_mesa_dst_reg_from_src(current_function->return_reg);
+
+ for (i = 0; i < type_size(current_function->sig->return_type); i++) {
+ ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r);
+ l.index++;
+ r.index++;
+ }
+ }
+
+ ir_to_mesa_emit_op0(ir, OPCODE_RET);
}
+void
+ir_to_mesa_visitor::visit(ir_discard *ir)
+{
+ assert(ir->condition == NULL); /* FINISHME */
+
+ ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV);
+}
void
ir_to_mesa_visitor::visit(ir_if *ir)
{
- ir_to_mesa_instruction *if_inst, *else_inst = NULL;
+ ir_to_mesa_instruction *cond_inst, *if_inst, *else_inst = NULL;
+ ir_to_mesa_instruction *prev_inst;
+
+ prev_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
ir->condition->accept(this);
assert(this->result.file != PROGRAM_UNDEFINED);
- if_inst = ir_to_mesa_emit_op1(ir->condition,
- OPCODE_IF, ir_to_mesa_undef_dst,
- this->result);
+ if (ctx->Shader.EmitCondCodes) {
+ cond_inst = (ir_to_mesa_instruction *)this->instructions.get_tail();
+
+ /* See if we actually generated any instruction for generating
+ * the condition. If not, then cook up a move to a temp so we
+ * have something to set cond_update on.
+ */
+ if (cond_inst == prev_inst) {
+ ir_to_mesa_src_reg temp = get_temp(glsl_type::bool_type);
+ cond_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_MOV,
+ ir_to_mesa_dst_reg_from_src(temp),
+ result);
+ }
+ cond_inst->cond_update = GL_TRUE;
+
+ if_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_IF);
+ if_inst->dst_reg.cond_mask = COND_NE;
+ } else {
+ if_inst = ir_to_mesa_emit_op1(ir->condition,
+ OPCODE_IF, ir_to_mesa_undef_dst,
+ this->result);
+ }
this->instructions.push_tail(if_inst);
visit_exec_list(&ir->then_instructions, this);
if (!ir->else_instructions.is_empty()) {
- else_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ELSE,
- ir_to_mesa_undef_dst,
- ir_to_mesa_undef);
- visit_exec_list(&ir->then_instructions, this);
+ else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE);
+ visit_exec_list(&ir->else_instructions, this);
}
if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF,
{
result.file = PROGRAM_UNDEFINED;
next_temp = 1;
+ next_signature_id = 1;
+ sampler_map = NULL;
+ sampler_map_size = 0;
+ current_function = NULL;
}
static struct prog_src_register
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;
return mesa_reg;
}
static void
-set_branchtargets(struct prog_instruction *mesa_instructions,
+set_branchtargets(ir_to_mesa_visitor *v,
+ struct prog_instruction *mesa_instructions,
int num_instructions)
{
- int if_count = 0, loop_count;
+ int if_count = 0, loop_count = 0;
int *if_stack, *loop_stack;
int if_stack_pos = 0, loop_stack_pos = 0;
int i, j;
/* The loop ends point at each other. */
mesa_instructions[i].BranchTarget = loop_stack[loop_stack_pos];
mesa_instructions[loop_stack[loop_stack_pos]].BranchTarget = i;
+ break;
+ case OPCODE_CAL:
+ foreach_iter(exec_list_iterator, iter, v->function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (entry->sig_id == mesa_instructions[i].BranchTarget) {
+ mesa_instructions[i].BranchTarget = entry->inst;
+ break;
+ }
+ }
+ break;
default:
break;
}
}
}
+static void
+mark_input(struct gl_program *prog,
+ int index,
+ GLboolean reladdr)
+{
+ prog->InputsRead |= BITFIELD64_BIT(index);
+ int i;
+
+ if (reladdr) {
+ if (index >= FRAG_ATTRIB_TEX0 && index <= FRAG_ATTRIB_TEX7) {
+ for (i = 0; i < 8; i++) {
+ prog->InputsRead |= BITFIELD64_BIT(FRAG_ATTRIB_TEX0 + i);
+ }
+ } else {
+ assert(!"FINISHME: Mark InputsRead for varying arrays");
+ }
+ }
+}
+
+static void
+mark_output(struct gl_program *prog,
+ int index,
+ GLboolean reladdr)
+{
+ prog->OutputsWritten |= BITFIELD64_BIT(index);
+ int i;
+
+ if (reladdr) {
+ if (index >= VERT_RESULT_TEX0 && index <= VERT_RESULT_TEX7) {
+ for (i = 0; i < 8; i++) {
+ prog->OutputsWritten |= BITFIELD64_BIT(FRAG_ATTRIB_TEX0 + i);
+ }
+ } else {
+ assert(!"FINISHME: Mark OutputsWritten for varying arrays");
+ }
+ }
+}
+
static void
count_resources(struct gl_program *prog)
{
+ unsigned int i;
+
prog->InputsRead = 0;
prog->OutputsWritten = 0;
- unsigned int i;
+ prog->SamplersUsed = 0;
for (i = 0; i < prog->NumInstructions; i++) {
struct prog_instruction *inst = &prog->Instructions[i];
switch (inst->DstReg.File) {
case PROGRAM_OUTPUT:
- prog->OutputsWritten |= BITFIELD64_BIT(inst->DstReg.Index);
+ mark_output(prog, inst->DstReg.Index, inst->DstReg.RelAddr);
break;
case PROGRAM_INPUT:
- prog->InputsRead |= BITFIELD64_BIT(inst->DstReg.Index);
+ mark_input(prog, inst->DstReg.Index, inst->DstReg.RelAddr);
break;
default:
break;
for (reg = 0; reg < _mesa_num_inst_src_regs(inst->Opcode); reg++) {
switch (inst->SrcReg[reg].File) {
case PROGRAM_OUTPUT:
- prog->OutputsWritten |= BITFIELD64_BIT(inst->SrcReg[reg].Index);
+ mark_output(prog, inst->SrcReg[reg].Index,
+ inst->SrcReg[reg].RelAddr);
break;
case PROGRAM_INPUT:
- prog->InputsRead |= BITFIELD64_BIT(inst->SrcReg[reg].Index);
+ mark_input(prog, inst->SrcReg[reg].Index, inst->SrcReg[reg].RelAddr);
break;
default:
break;
}
}
+
+ /* Instead of just using the uniform's value to map to a
+ * sampler, Mesa first allocates a separate number for the
+ * sampler (_mesa_add_sampler), then we reindex it down to a
+ * small integer (sampler_map[], SamplersUsed), then that gets
+ * mapped to the uniform's value, and we get an actual sampler.
+ */
+ if (_mesa_is_tex_instruction(inst->Opcode)) {
+ prog->SamplerTargets[inst->TexSrcUnit] =
+ (gl_texture_index)inst->TexSrcTarget;
+ prog->SamplersUsed |= 1 << inst->TexSrcUnit;
+ if (inst->TexShadow) {
+ prog->ShadowSamplers |= 1 << inst->TexSrcUnit;
+ }
+ }
}
+
+ _mesa_update_shader_textures_used(prog);
}
/* Each stage has some uniforms in its Parameters list. The Uniforms
}
struct gl_program *
-get_mesa_program(GLcontext *ctx, void *mem_ctx, struct glsl_shader *shader)
+get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program,
+ struct gl_shader *shader)
{
+ void *mem_ctx = shader_program;
ir_to_mesa_visitor v;
struct prog_instruction *mesa_instructions, *mesa_inst;
ir_instruction **mesa_instruction_annotation;
int i;
- exec_list *instructions = &shader->ir;
struct gl_program *prog;
GLenum target;
+ GLboolean progress;
switch (shader->Type) {
case GL_VERTEX_SHADER: target = GL_VERTEX_PROGRAM_ARB; break;
default: assert(!"should not be reached"); break;
}
+ validate_ir_tree(shader->ir);
+
prog = ctx->Driver.NewProgram(ctx, target, 1);
if (!prog)
return NULL;
v.prog = prog;
v.mem_ctx = talloc_new(NULL);
- visit_exec_list(instructions, &v);
- v.ir_to_mesa_emit_op1(NULL, OPCODE_END,
- ir_to_mesa_undef_dst, ir_to_mesa_undef);
+
+ /* Emit Mesa IR for main(). */
+ visit_exec_list(shader->ir, &v);
+ v.ir_to_mesa_emit_op0(NULL, OPCODE_END);
+
+ /* Now emit bodies for any functions that were used. */
+ do {
+ progress = GL_FALSE;
+
+ foreach_iter(exec_list_iterator, iter, v.function_signatures) {
+ function_entry *entry = (function_entry *)iter.get();
+
+ if (!entry->bgn_inst) {
+ v.current_function = entry;
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB);
+ entry->bgn_inst->function = entry;
+
+ visit_exec_list(&entry->sig->body, &v);
+
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_RET);
+ entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB);
+ progress = GL_TRUE;
+ }
+ }
+ } while (progress);
prog->NumTemporaries = v.next_temp;
ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get();
mesa_inst->Opcode = inst->op;
+ mesa_inst->CondUpdate = inst->cond_update;
mesa_inst->DstReg.File = inst->dst_reg.file;
mesa_inst->DstReg.Index = inst->dst_reg.index;
- mesa_inst->DstReg.CondMask = COND_TR;
+ 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]);
+ mesa_inst->TexSrcUnit = inst->sampler;
+ mesa_inst->TexSrcTarget = inst->tex_target;
+ mesa_inst->TexShadow = inst->tex_shadow;
mesa_instruction_annotation[i] = inst->ir;
+ if (ctx->Shader.EmitNoIfs && mesa_inst->Opcode == OPCODE_IF) {
+ shader_program->InfoLog =
+ talloc_asprintf_append(shader_program->InfoLog,
+ "Couldn't flatten if statement\n");
+ shader_program->LinkStatus = false;
+ }
+
+ if (mesa_inst->Opcode == OPCODE_BGNSUB)
+ inst->function->inst = i;
+ else if (mesa_inst->Opcode == OPCODE_CAL)
+ mesa_inst->BranchTarget = inst->function->sig_id; /* rewritten later */
+
mesa_inst++;
i++;
}
- set_branchtargets(mesa_instructions, num_instructions);
+ set_branchtargets(&v, mesa_instructions, num_instructions);
if (0) {
print_program(mesa_instructions, mesa_instruction_annotation,
num_instructions);
prog->Instructions = mesa_instructions;
prog->NumInstructions = num_instructions;
- _mesa_reference_program(ctx, &shader->mesa_shader->Program, prog);
+ _mesa_reference_program(ctx, &shader->Program, prog);
+
+ if ((ctx->Shader.Flags & GLSL_NO_OPT) == 0) {
+ _mesa_optimize_program(ctx, prog);
+ }
return prog;
}
-/* Takes a Mesa gl shader structure and compiles it, returning our Mesa-like
- * structure with the IR and such attached.
- */
-static struct glsl_shader *
-_mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh)
+extern "C" {
+
+void
+_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader)
{
- struct glsl_shader *shader = talloc_zero(mem_ctx, struct glsl_shader);
- struct _mesa_glsl_parse_state *state;
+ struct _mesa_glsl_parse_state *state =
+ new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
- shader->Type = sh->Type;
- shader->Name = sh->Name;
- shader->RefCount = 1;
- shader->Source = sh->Source;
- shader->SourceLen = strlen(sh->Source);
- shader->mesa_shader = sh;
+ const char *source = shader->Source;
+ state->error = preprocess(state, &source, &state->info_log,
+ &ctx->Extensions);
- state = talloc_zero(shader, struct _mesa_glsl_parse_state);
- switch (shader->Type) {
- case GL_VERTEX_SHADER: state->target = vertex_shader; break;
- case GL_FRAGMENT_SHADER: state->target = fragment_shader; break;
- case GL_GEOMETRY_SHADER: state->target = geometry_shader; break;
+ if (!state->error) {
+ _mesa_glsl_lexer_ctor(state, source);
+ _mesa_glsl_parse(state);
+ _mesa_glsl_lexer_dtor(state);
}
- state->scanner = NULL;
- state->translation_unit.make_empty();
- state->symbols = new(mem_ctx) glsl_symbol_table;
- state->info_log = talloc_strdup(shader, "");
- state->error = false;
- state->temp_index = 0;
- state->loop_or_switch_nesting = NULL;
- state->ARB_texture_rectangle_enable = true;
+ shader->ir = new(shader) exec_list;
+ if (!state->error && !state->translation_unit.is_empty())
+ _mesa_ast_to_hir(shader->ir, state);
- _mesa_glsl_lexer_ctor(state, shader->Source);
- _mesa_glsl_parse(state);
- _mesa_glsl_lexer_dtor(state);
+ if (!state->error && !shader->ir->is_empty()) {
+ validate_ir_tree(shader->ir);
- shader->ir.make_empty();
- if (!state->error && !state->translation_unit.is_empty())
- _mesa_ast_to_hir(&shader->ir, state);
+ /* Lowering */
+ do_mat_op_to_vec(shader->ir);
+ do_mod_to_fract(shader->ir);
+ do_div_to_mul_rcp(shader->ir);
- /* Optimization passes */
- if (!state->error && !shader->ir.is_empty()) {
+ /* Optimization passes */
bool progress;
do {
progress = false;
- progress = do_function_inlining(&shader->ir) || progress;
- progress = do_if_simplification(&shader->ir) || progress;
- progress = do_copy_propagation(&shader->ir) || progress;
- progress = do_dead_code_local(&shader->ir) || progress;
- progress = do_dead_code_unlinked(state, &shader->ir) || progress;
- progress = do_constant_variable_unlinked(&shader->ir) || progress;
- progress = do_constant_folding(&shader->ir) || progress;
- progress = do_vec_index_to_swizzle(&shader->ir) || progress;
- progress = do_swizzle_swizzle(&shader->ir) || progress;
+ progress = do_function_inlining(shader->ir) || progress;
+ progress = do_if_simplification(shader->ir) || progress;
+ progress = do_copy_propagation(shader->ir) || progress;
+ progress = do_dead_code_local(shader->ir) || progress;
+ progress = do_dead_code_unlinked(state, shader->ir) || progress;
+ progress = do_constant_variable_unlinked(shader->ir) || progress;
+ progress = do_constant_folding(shader->ir) || progress;
+ progress = do_if_return(shader->ir) || progress;
+ if (ctx->Shader.EmitNoIfs)
+ progress = do_if_to_cond_assign(shader->ir) || progress;
+
+ progress = do_vec_index_to_swizzle(shader->ir) || progress;
+ /* Do this one after the previous to let the easier pass handle
+ * constant vector indexing.
+ */
+ progress = do_vec_index_to_cond_assign(shader->ir) || progress;
+
+ progress = do_swizzle_swizzle(shader->ir) || progress;
} while (progress);
+
+ validate_ir_tree(shader->ir);
}
shader->symbols = state->symbols;
shader->CompileStatus = !state->error;
shader->InfoLog = state->info_log;
+ shader->Version = state->language_version;
+ memcpy(shader->builtins_to_link, state->builtins_to_link,
+ sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
+ shader->num_builtins_to_link = state->num_builtins_to_link;
- talloc_free(state);
-
- return shader;
-}
-
-extern "C" {
-
-void
-_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *sh)
-{
- struct glsl_shader *shader;
- TALLOC_CTX *mem_ctx = talloc_new(NULL);
-
- shader = _mesa_get_glsl_shader(ctx, mem_ctx, sh);
+ /* Retain any live IR, but trash the rest. */
+ reparent_ir(shader->ir, shader);
- sh->CompileStatus = shader->CompileStatus;
- sh->InfoLog = strdup(shader->InfoLog);
- talloc_free(mem_ctx);
+ talloc_free(state);
}
void
_mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
{
- struct glsl_program *whole_program;
unsigned int i;
_mesa_clear_shader_program_data(ctx, prog);
- whole_program = talloc_zero(NULL, struct glsl_program);
- whole_program->LinkStatus = GL_TRUE;
- whole_program->NumShaders = prog->NumShaders;
- whole_program->Shaders = talloc_array(whole_program, struct glsl_shader *,
- prog->NumShaders);
+ prog->LinkStatus = GL_TRUE;
for (i = 0; i < prog->NumShaders; i++) {
- whole_program->Shaders[i] = _mesa_get_glsl_shader(ctx, whole_program,
- prog->Shaders[i]);
- if (!whole_program->Shaders[i]->CompileStatus) {
- whole_program->InfoLog =
- talloc_asprintf_append(whole_program->InfoLog,
+ if (!prog->Shaders[i]->CompileStatus) {
+ prog->InfoLog =
+ talloc_asprintf_append(prog->InfoLog,
"linking with uncompiled shader");
- whole_program->LinkStatus = GL_FALSE;
+ prog->LinkStatus = GL_FALSE;
}
}
- prog->Uniforms = _mesa_new_uniform_list();
prog->Varying = _mesa_new_parameter_list();
_mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL);
_mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL);
- if (whole_program->LinkStatus)
- link_shaders(whole_program);
+ if (prog->LinkStatus) {
+ link_shaders(prog);
- prog->LinkStatus = whole_program->LinkStatus;
+ /* We don't use the linker's uniforms list, and cook up our own at
+ * generate time.
+ */
+ free(prog->Uniforms);
+ prog->Uniforms = _mesa_new_uniform_list();
+ }
- /* FINISHME: This should use the linker-generated code */
if (prog->LinkStatus) {
- for (i = 0; i < prog->NumShaders; i++) {
+ for (i = 0; i < prog->_NumLinkedShaders; i++) {
struct gl_program *linked_prog;
- linked_prog = get_mesa_program(ctx, whole_program,
- whole_program->Shaders[i]);
+ linked_prog = get_mesa_program(ctx, prog,
+ prog->_LinkedShaders[i]);
count_resources(linked_prog);
link_uniforms_to_shared_uniform_list(prog->Uniforms, linked_prog);
- switch (whole_program->Shaders[i]->Type) {
+ switch (prog->_LinkedShaders[i]->Type) {
case GL_VERTEX_SHADER:
_mesa_reference_vertprog(ctx, &prog->VertexProgram,
(struct gl_vertex_program *)linked_prog);
+ ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB,
+ linked_prog);
break;
case GL_FRAGMENT_SHADER:
_mesa_reference_fragprog(ctx, &prog->FragmentProgram,
(struct gl_fragment_program *)linked_prog);
+ ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB,
+ linked_prog);
break;
}
}
}
-
- talloc_free(whole_program);
}
} /* extern "C" */