diff options
Diffstat (limited to 'src/mesa/program')
-rw-r--r-- | src/mesa/program/arbprogparse.c | 21 | ||||
-rw-r--r-- | src/mesa/program/ir_to_mesa.cpp | 850 | ||||
-rw-r--r-- | src/mesa/program/prog_optimize.c | 106 | ||||
-rw-r--r-- | src/mesa/program/prog_statevars.c | 34 | ||||
-rw-r--r-- | src/mesa/program/prog_statevars.h | 1 | ||||
-rw-r--r-- | src/mesa/program/program.c | 5 | ||||
-rw-r--r-- | src/mesa/program/program_parse.y | 29 | ||||
-rw-r--r-- | src/mesa/program/program_parse_extra.c | 10 | ||||
-rw-r--r-- | src/mesa/program/program_parser.h | 1 | ||||
-rw-r--r-- | src/mesa/program/programopt.c | 36 | ||||
-rw-r--r-- | src/mesa/program/programopt.h | 4 |
11 files changed, 608 insertions, 489 deletions
diff --git a/src/mesa/program/arbprogparse.c b/src/mesa/program/arbprogparse.c index ca63e72c085..dffc8abf735 100644 --- a/src/mesa/program/arbprogparse.c +++ b/src/mesa/program/arbprogparse.c @@ -116,20 +116,11 @@ _mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target, program->Base.SamplersUsed |= (1 << i); } program->Base.ShadowSamplers = prog.ShadowSamplers; - switch (state.option.Fog) { - case OPTION_FOG_EXP: program->FogOption = GL_EXP; break; - case OPTION_FOG_EXP2: program->FogOption = GL_EXP2; break; - case OPTION_FOG_LINEAR: program->FogOption = GL_LINEAR; break; - default: program->FogOption = GL_NONE; break; - } program->OriginUpperLeft = state.option.OriginUpperLeft; program->PixelCenterInteger = state.option.PixelCenterInteger; program->UsesKill = state.fragment.UsesKill; - if (program->FogOption) - program->Base.InputsRead |= FRAG_BIT_FOGC; - if (program->Base.Instructions) free(program->Base.Instructions); program->Base.Instructions = prog.Instructions; @@ -143,9 +134,15 @@ _mesa_parse_arb_fragment_program(struct gl_context* ctx, GLenum target, * there's no hardware that wants to do fog in a discrete stage separate * from the fragment shader. */ - if (program->FogOption != GL_NONE) { - _mesa_append_fog_code(ctx, program); - program->FogOption = GL_NONE; + if (state.option.Fog != OPTION_NONE) { + static const GLenum fog_modes[4] = { + GL_NONE, GL_EXP, GL_EXP2, GL_LINEAR + }; + + /* XXX: we should somehow recompile this to remove clamping if disabled + * On the ATI driver, this is unclampled if fragment clamping is disabled + */ + _mesa_append_fog_code(ctx, program, fog_modes[state.option.Fog], GL_TRUE); } #if DEBUG_FP diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 17e0f9953f9..3c9b9733832 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -56,16 +56,20 @@ extern "C" { #include "program/sampler.h" } +class src_reg; +class dst_reg; + static int swizzle_for_size(int size); /** * This struct is a corresponding struct to Mesa prog_src_register, with * wider fields. */ -typedef struct ir_to_mesa_src_reg { - ir_to_mesa_src_reg(int file, int index, const glsl_type *type) +class src_reg { +public: + src_reg(gl_register_file file, int index, const glsl_type *type) { - this->file = (gl_register_file) file; + this->file = file; this->index = index; if (type && (type->is_scalar() || type->is_vector() || type->is_matrix())) this->swizzle = swizzle_for_size(type->vector_elements); @@ -75,7 +79,7 @@ typedef struct ir_to_mesa_src_reg { this->reladdr = NULL; } - ir_to_mesa_src_reg() + src_reg() { this->file = PROGRAM_UNDEFINED; this->index = 0; @@ -84,24 +88,63 @@ typedef struct ir_to_mesa_src_reg { this->reladdr = NULL; } + explicit src_reg(dst_reg reg); + gl_register_file file; /**< PROGRAM_* from Mesa */ int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */ GLuint swizzle; /**< SWIZZLE_XYZWONEZERO swizzles from Mesa. */ int negate; /**< NEGATE_XYZW mask from mesa */ /** Register index should be offset by the integer in this reg. */ - ir_to_mesa_src_reg *reladdr; -} ir_to_mesa_src_reg; + src_reg *reladdr; +}; + +class dst_reg { +public: + dst_reg(gl_register_file file, int writemask) + { + this->file = file; + this->index = 0; + this->writemask = writemask; + this->cond_mask = COND_TR; + this->reladdr = NULL; + } -typedef struct ir_to_mesa_dst_reg { - int file; /**< PROGRAM_* from Mesa */ + dst_reg() + { + this->file = PROGRAM_UNDEFINED; + this->index = 0; + this->writemask = 0; + this->cond_mask = COND_TR; + this->reladdr = NULL; + } + + explicit dst_reg(src_reg reg); + + gl_register_file 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; + src_reg *reladdr; +}; -extern ir_to_mesa_src_reg ir_to_mesa_undef; +src_reg::src_reg(dst_reg reg) +{ + this->file = reg.file; + this->index = reg.index; + this->swizzle = SWIZZLE_XYZW; + this->negate = 0; + this->reladdr = NULL; +} + +dst_reg::dst_reg(src_reg reg) +{ + this->file = reg.file; + this->index = reg.index; + this->writemask = WRITEMASK_XYZW; + this->cond_mask = COND_TR; + this->reladdr = reg.reladdr; +} class ir_to_mesa_instruction : public exec_node { public: @@ -118,8 +161,8 @@ public: } enum prog_opcode op; - ir_to_mesa_dst_reg dst_reg; - ir_to_mesa_src_reg src_reg[3]; + dst_reg dst; + src_reg src[3]; /** Pointer to the ir source this tree came from for debugging */ ir_instruction *ir; GLboolean cond_update; @@ -174,7 +217,7 @@ public: int inst; /** Storage for the return value. */ - ir_to_mesa_src_reg return_reg; + src_reg return_reg; }; class ir_to_mesa_visitor : public ir_visitor { @@ -195,11 +238,10 @@ public: 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); + src_reg get_temp(const glsl_type *type); + void reladdr_to_temp(ir_instruction *ir, src_reg *reg, int *num_reladdr); - struct ir_to_mesa_src_reg src_reg_for_float(float val); + src_reg src_reg_for_float(float val); /** * \name Visit methods @@ -228,7 +270,7 @@ public: virtual void visit(ir_if *); /*@}*/ - struct ir_to_mesa_src_reg result; + src_reg result; /** List of variable_storage */ exec_list variables; @@ -240,52 +282,35 @@ public: /** 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 *emit(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_src_reg src0); + ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0); - ir_to_mesa_instruction *ir_to_mesa_emit_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); + ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0, src_reg src1); - ir_to_mesa_instruction *ir_to_mesa_emit_op3(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, - ir_to_mesa_src_reg src2); + ir_to_mesa_instruction *emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, + src_reg src0, src_reg src1, src_reg src2); /** * Emit the correct dot-product instruction for the type of arguments - * - * \sa ir_to_mesa_emit_op2 */ - void ir_to_mesa_emit_dp(ir_instruction *ir, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1, - unsigned elements); - - void 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); - - 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); + void emit_dp(ir_instruction *ir, + dst_reg dst, + src_reg src0, + src_reg src1, + unsigned elements); + + void emit_scalar(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0); + + void emit_scalar(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0, src_reg src1); void emit_scs(ir_instruction *ir, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - const ir_to_mesa_src_reg &src); + dst_reg dst, const src_reg &src); GLboolean try_emit_mad(ir_expression *ir, int mul_operand); @@ -300,15 +325,11 @@ public: void *mem_ctx; }; -ir_to_mesa_src_reg ir_to_mesa_undef = ir_to_mesa_src_reg(PROGRAM_UNDEFINED, 0, NULL); +src_reg undef_src = src_reg(PROGRAM_UNDEFINED, 0, NULL); -ir_to_mesa_dst_reg ir_to_mesa_undef_dst = { - PROGRAM_UNDEFINED, 0, SWIZZLE_NOOP, COND_TR, NULL, -}; +dst_reg undef_dst = dst_reg(PROGRAM_UNDEFINED, SWIZZLE_NOOP); -ir_to_mesa_dst_reg ir_to_mesa_address_reg = { - PROGRAM_ADDRESS, 0, WRITEMASK_X, COND_TR, NULL -}; +dst_reg address_reg = dst_reg(PROGRAM_ADDRESS, WRITEMASK_X); static void fail_link(struct gl_shader_program *prog, const char *fmt, ...) PRINTFLIKE(2, 3); @@ -339,12 +360,9 @@ swizzle_for_size(int size) } ir_to_mesa_instruction * -ir_to_mesa_visitor::ir_to_mesa_emit_op3(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, - ir_to_mesa_src_reg src2) +ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, + src_reg src0, src_reg src1, src_reg src2) { ir_to_mesa_instruction *inst = new(mem_ctx) ir_to_mesa_instruction(); int num_reladdr = 0; @@ -363,18 +381,16 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir, 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); - + emit(ir, OPCODE_ARL, address_reg, *dst.reladdr); num_reladdr--; } assert(num_reladdr == 0); inst->op = op; - inst->dst_reg = dst; - inst->src_reg[0] = src0; - inst->src_reg[1] = src1; - inst->src_reg[2] = src2; + inst->dst = dst; + inst->src[0] = src0; + inst->src[1] = src1; + inst->src[2] = src2; inst->ir = ir; inst->function = NULL; @@ -386,69 +402,36 @@ ir_to_mesa_visitor::ir_to_mesa_emit_op3(ir_instruction *ir, ir_to_mesa_instruction * -ir_to_mesa_visitor::ir_to_mesa_emit_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) +ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0, src_reg src1) { - return ir_to_mesa_emit_op3(ir, op, dst, src0, src1, ir_to_mesa_undef); + return emit(ir, op, dst, src0, src1, undef_src); } ir_to_mesa_instruction * -ir_to_mesa_visitor::ir_to_mesa_emit_op1(ir_instruction *ir, - enum prog_opcode op, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0) +ir_to_mesa_visitor::emit(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0) { assert(dst.writemask != 0); - return ir_to_mesa_emit_op3(ir, op, dst, - src0, ir_to_mesa_undef, ir_to_mesa_undef); + return emit(ir, op, dst, src0, undef_src, undef_src); } ir_to_mesa_instruction * -ir_to_mesa_visitor::ir_to_mesa_emit_op0(ir_instruction *ir, - enum prog_opcode op) +ir_to_mesa_visitor::emit(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); + return emit(ir, op, undef_dst, undef_src, undef_src, undef_src); } void -ir_to_mesa_visitor::ir_to_mesa_emit_dp(ir_instruction *ir, - ir_to_mesa_dst_reg dst, - ir_to_mesa_src_reg src0, - ir_to_mesa_src_reg src1, - unsigned elements) +ir_to_mesa_visitor::emit_dp(ir_instruction *ir, + dst_reg dst, src_reg src0, src_reg src1, + unsigned elements) { static const gl_inst_opcode dot_opcodes[] = { OPCODE_DP2, OPCODE_DP3, OPCODE_DP4 }; - ir_to_mesa_emit_op3(ir, dot_opcodes[elements - 2], - dst, src0, src1, ir_to_mesa_undef); -} - -inline ir_to_mesa_dst_reg -ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg) -{ - ir_to_mesa_dst_reg dst_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) -{ - return ir_to_mesa_src_reg(reg.file, reg.index, NULL); + emit(ir, dot_opcodes[elements - 2], dst, src0, src1); } /** @@ -460,11 +443,9 @@ ir_to_mesa_src_reg_from_dst(ir_to_mesa_dst_reg reg) * to produce dest channels. */ void -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 orig_src0, - ir_to_mesa_src_reg orig_src1) +ir_to_mesa_visitor::emit_scalar(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, + src_reg orig_src0, src_reg orig_src1) { int i, j; int done_mask = ~dst.writemask; @@ -476,8 +457,8 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir, for (i = 0; i < 4; i++) { GLuint this_mask = (1 << i); ir_to_mesa_instruction *inst; - ir_to_mesa_src_reg src0 = orig_src0; - ir_to_mesa_src_reg src1 = orig_src1; + src_reg src0 = orig_src0; + src_reg src1 = orig_src1; if (done_mask & this_mask) continue; @@ -500,26 +481,21 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op2(ir_instruction *ir, src1.swizzle = MAKE_SWIZZLE4(src1_swiz, src1_swiz, src1_swiz, src1_swiz); - inst = ir_to_mesa_emit_op2(ir, op, - dst, - src0, - src1); - inst->dst_reg.writemask = this_mask; + inst = emit(ir, op, dst, src0, src1); + inst->dst.writemask = this_mask; done_mask |= this_mask; } } 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_visitor::emit_scalar(ir_instruction *ir, enum prog_opcode op, + dst_reg dst, src_reg src0) { - ir_to_mesa_src_reg undef = ir_to_mesa_undef; + src_reg undef = undef_src; undef.swizzle = SWIZZLE_XXXX; - ir_to_mesa_emit_scalar_op2(ir, op, dst, src0, undef); + emit_scalar(ir, op, dst, src0, undef); } /** @@ -538,20 +514,20 @@ ir_to_mesa_visitor::ir_to_mesa_emit_scalar_op1(ir_instruction *ir, */ void ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op, - ir_to_mesa_dst_reg dst, - const ir_to_mesa_src_reg &src) + dst_reg dst, + const src_reg &src) { /* Vertex programs cannot use the SCS opcode. */ if (this->prog->Target == GL_VERTEX_PROGRAM_ARB) { - ir_to_mesa_emit_scalar_op1(ir, op, dst, src); + emit_scalar(ir, op, dst, src); return; } const unsigned component = (op == OPCODE_SIN) ? 0 : 1; const unsigned scs_mask = (1U << component); int done_mask = ~dst.writemask; - ir_to_mesa_src_reg tmp; + src_reg tmp; assert(op == OPCODE_SIN || op == OPCODE_COS); @@ -564,7 +540,7 @@ ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op, for (unsigned i = 0; i < 4; i++) { unsigned this_mask = (1U << i); - ir_to_mesa_src_reg src0 = src; + src_reg src0 = src; if ((done_mask & this_mask) != 0) continue; @@ -592,41 +568,40 @@ ir_to_mesa_visitor::emit_scs(ir_instruction *ir, enum prog_opcode op, if (this_mask != scs_mask) { ir_to_mesa_instruction *inst; - ir_to_mesa_dst_reg tmp_dst = ir_to_mesa_dst_reg_from_src(tmp); + dst_reg tmp_dst = dst_reg(tmp); /* Emit the SCS instruction. */ - inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, tmp_dst, src0); - inst->dst_reg.writemask = scs_mask; + inst = emit(ir, OPCODE_SCS, tmp_dst, src0); + inst->dst.writemask = scs_mask; /* Move the result of the SCS instruction to the desired location in * the destination. */ tmp.swizzle = MAKE_SWIZZLE4(component, component, component, component); - inst = ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, tmp); - inst->dst_reg.writemask = this_mask; + inst = emit(ir, OPCODE_SCS, dst, tmp); + inst->dst.writemask = this_mask; } else { /* Emit the SCS instruction to write directly to the destination. */ - ir_to_mesa_instruction *inst = - ir_to_mesa_emit_op1(ir, OPCODE_SCS, dst, src0); - inst->dst_reg.writemask = scs_mask; + ir_to_mesa_instruction *inst = emit(ir, OPCODE_SCS, dst, src0); + inst->dst.writemask = scs_mask; } done_mask |= this_mask; } } -struct ir_to_mesa_src_reg +struct src_reg ir_to_mesa_visitor::src_reg_for_float(float val) { - ir_to_mesa_src_reg src_reg(PROGRAM_CONSTANT, -1, NULL); + src_reg src(PROGRAM_CONSTANT, -1, NULL); - src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters, - &val, 1, &src_reg.swizzle); + src.index = _mesa_add_unnamed_constant(this->prog->Parameters, + &val, 1, &src.swizzle); - return src_reg; + return src; } static int @@ -676,31 +651,31 @@ type_size(const struct glsl_type *type) * storage). Actual register allocation for the Mesa VM occurs in a * pass over the Mesa IR later. */ -ir_to_mesa_src_reg +src_reg ir_to_mesa_visitor::get_temp(const glsl_type *type) { - ir_to_mesa_src_reg src_reg; + src_reg src; int swizzle[4]; int i; - src_reg.file = PROGRAM_TEMPORARY; - src_reg.index = next_temp; - src_reg.reladdr = NULL; + src.file = PROGRAM_TEMPORARY; + src.index = next_temp; + src.reladdr = NULL; next_temp += type_size(type); if (type->is_array() || type->is_record()) { - src_reg.swizzle = SWIZZLE_NOOP; + src.swizzle = SWIZZLE_NOOP; } else { 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.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], + swizzle[2], swizzle[3]); } - src_reg.negate = 0; + src.negate = 0; - return src_reg; + return src; } variable_storage * @@ -754,27 +729,8 @@ ir_to_mesa_visitor::visit(ir_variable *ir) if (ir->mode == ir_var_uniform && strncmp(ir->name, "gl_", 3) == 0) { unsigned int i; - const struct gl_builtin_uniform_desc *statevar; - - for (i = 0; _mesa_builtin_uniform_desc[i].name; i++) { - if (strcmp(ir->name, _mesa_builtin_uniform_desc[i].name) == 0) - break; - } - - if (!_mesa_builtin_uniform_desc[i].name) { - fail_link(this->shader_program, - "Failed to find builtin uniform `%s'\n", ir->name); - return; - } - - statevar = &_mesa_builtin_uniform_desc[i]; - - int array_count; - if (ir->type->is_array()) { - array_count = ir->type->length; - } else { - array_count = 1; - } + const ir_state_slot *const slots = ir->state_slots; + assert(ir->state_slots != NULL); /* Check if this statevar's setup in the STATE file exactly * matches how we'll want to reference it as a @@ -782,63 +738,57 @@ ir_to_mesa_visitor::visit(ir_variable *ir) * temporary storage and hope that it'll get copy-propagated * out. */ - for (i = 0; i < statevar->num_elements; i++) { - if (statevar->elements[i].swizzle != SWIZZLE_XYZW) { + for (i = 0; i < ir->num_state_slots; i++) { + if (slots[i].swizzle != SWIZZLE_XYZW) { break; } } struct variable_storage *storage; - ir_to_mesa_dst_reg dst; - if (i == statevar->num_elements) { + dst_reg dst; + if (i == ir->num_state_slots) { /* We'll set the index later. */ storage = new(mem_ctx) variable_storage(ir, PROGRAM_STATE_VAR, -1); this->variables.push_tail(storage); - dst = ir_to_mesa_undef_dst; + dst = undef_dst; } else { + /* The variable_storage constructor allocates slots based on the size + * of the type. However, this had better match the number of state + * elements that we're going to copy into the new temporary. + */ + assert((int) ir->num_state_slots == type_size(ir->type)); + storage = new(mem_ctx) variable_storage(ir, PROGRAM_TEMPORARY, this->next_temp); this->variables.push_tail(storage); this->next_temp += type_size(ir->type); - dst = ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg(PROGRAM_TEMPORARY, - storage->index, - NULL)); + dst = dst_reg(src_reg(PROGRAM_TEMPORARY, storage->index, NULL)); } - for (int a = 0; a < array_count; a++) { - for (unsigned int i = 0; i < statevar->num_elements; i++) { - struct gl_builtin_uniform_element *element = &statevar->elements[i]; - int tokens[STATE_LENGTH]; - - memcpy(tokens, element->tokens, sizeof(element->tokens)); - if (ir->type->is_array()) { - tokens[1] = a; - } - - int index = _mesa_add_state_reference(this->prog->Parameters, - (gl_state_index *)tokens); + for (unsigned int i = 0; i < ir->num_state_slots; i++) { + int index = _mesa_add_state_reference(this->prog->Parameters, + (gl_state_index *)slots[i].tokens); - if (storage->file == PROGRAM_STATE_VAR) { - if (storage->index == -1) { - storage->index = index; - } else { - assert(index == - (int)(storage->index + a * statevar->num_elements + i)); - } + if (storage->file == PROGRAM_STATE_VAR) { + if (storage->index == -1) { + storage->index = index; } else { - ir_to_mesa_src_reg src(PROGRAM_STATE_VAR, index, NULL); - src.swizzle = element->swizzle; - ir_to_mesa_emit_op1(ir, OPCODE_MOV, dst, src); - /* even a float takes up a whole vec4 reg in a struct/array. */ - dst.index++; + assert(index == storage->index + (int)i); } + } else { + src_reg src(PROGRAM_STATE_VAR, index, NULL); + src.swizzle = slots[i].swizzle; + emit(ir, OPCODE_MOV, dst, src); + /* even a float takes up a whole vec4 reg in a struct/array. */ + dst.index++; } } + if (storage->file == PROGRAM_TEMPORARY && - dst.index != storage->index + type_size(ir->type)) { + dst.index != storage->index + (int) ir->num_state_slots) { fail_link(this->shader_program, "failed to load builtin uniform `%s' (%d/%d regs loaded)\n", ir->name, dst.index - storage->index, @@ -864,7 +814,7 @@ ir_to_mesa_visitor::visit(ir_loop *ir) delete a; } - ir_to_mesa_emit_op0(NULL, OPCODE_BGNLOOP); + emit(NULL, OPCODE_BGNLOOP); if (ir->to) { ir_expression *e = @@ -897,7 +847,7 @@ ir_to_mesa_visitor::visit(ir_loop *ir) delete e; } - ir_to_mesa_emit_op0(NULL, OPCODE_ENDLOOP); + emit(NULL, OPCODE_ENDLOOP); } void @@ -905,10 +855,10 @@ ir_to_mesa_visitor::visit(ir_loop_jump *ir) { switch (ir->mode) { case ir_loop_jump::jump_break: - ir_to_mesa_emit_op0(NULL, OPCODE_BRK); + emit(NULL, OPCODE_BRK); break; case ir_loop_jump::jump_continue: - ir_to_mesa_emit_op0(NULL, OPCODE_CONT); + emit(NULL, OPCODE_CONT); break; } } @@ -947,7 +897,7 @@ 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; + src_reg a, b, c; ir_expression *expr = ir->operands[mul_operand]->as_expression(); if (!expr || expr->operation != ir_binop_mul) @@ -961,8 +911,7 @@ ir_to_mesa_visitor::try_emit_mad(ir_expression *ir, int mul_operand) 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); + emit(ir, OPCODE_MAD, dst_reg(this->result), a, b, c); return true; } @@ -981,13 +930,11 @@ ir_to_mesa_visitor::try_emit_sat(ir_expression *ir) return false; sat_src->accept(this); - ir_to_mesa_src_reg src = this->result; + src_reg src = this->result; this->result = get_temp(ir->type); ir_to_mesa_instruction *inst; - inst = ir_to_mesa_emit_op1(ir, OPCODE_MOV, - ir_to_mesa_dst_reg_from_src(this->result), - src); + inst = emit(ir, OPCODE_MOV, dst_reg(this->result), src); inst->saturate = true; return true; @@ -995,18 +942,17 @@ ir_to_mesa_visitor::try_emit_sat(ir_expression *ir) void ir_to_mesa_visitor::reladdr_to_temp(ir_instruction *ir, - ir_to_mesa_src_reg *reg, int *num_reladdr) + 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); + emit(ir, OPCODE_ARL, address_reg, *reg->reladdr); if (*num_reladdr != 1) { - ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); + 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); + emit(ir, OPCODE_MOV, dst_reg(temp), *reg); *reg = temp; } @@ -1102,7 +1048,7 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir) exit(1); } - ir_to_mesa_src_reg src; + src_reg src; src = this->result; src.swizzle = MAKE_SWIZZLE4(components[0], @@ -1117,8 +1063,8 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir) /* Storage for our result. Ideally for an assignment we'd be using the * actual storage for the result here, instead. */ - const ir_to_mesa_src_reg result_src = get_temp(ir->type); - ir_to_mesa_dst_reg result_dst = ir_to_mesa_dst_reg_from_src(result_src); + const src_reg result_src = get_temp(ir->type); + dst_reg result_dst = dst_reg(result_src); /* Limit writes to the channels that will be used by result_src later. * This does limit this temp's use as a temporary for multi-instruction @@ -1126,7 +1072,7 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir) */ result_dst.writemask = (1 << ir->type->vector_elements) - 1; - ir_to_mesa_emit_op1(ir, OPCODE_SWZ, result_dst, src); + emit(ir, OPCODE_SWZ, result_dst, src); this->result = result_src; } @@ -1134,9 +1080,9 @@ void ir_to_mesa_visitor::visit(ir_expression *ir) { unsigned int operand; - struct ir_to_mesa_src_reg op[Elements(ir->operands)]; - struct ir_to_mesa_src_reg result_src; - struct ir_to_mesa_dst_reg result_dst; + src_reg op[Elements(ir->operands)]; + src_reg result_src; + dst_reg result_dst; /* Quick peephole: Emit OPCODE_MAD(a, b, c) instead of ADD(MUL(a, b), c) */ @@ -1184,7 +1130,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) */ result_src = get_temp(ir->type); /* convenience for the emit functions below. */ - result_dst = ir_to_mesa_dst_reg_from_src(result_src); + result_dst = dst_reg(result_src); /* Limit writes to the channels that will be used by result_src later. * This does limit this temp's use as a temporary for multi-instruction * sequences. @@ -1193,38 +1139,37 @@ ir_to_mesa_visitor::visit(ir_expression *ir) switch (ir->operation) { case ir_unop_logic_not: - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, - op[0], src_reg_for_float(0.0)); + emit(ir, OPCODE_SEQ, result_dst, op[0], src_reg_for_float(0.0)); break; case ir_unop_neg: 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]); + emit(ir, OPCODE_ABS, result_dst, op[0]); break; case ir_unop_sign: - ir_to_mesa_emit_op1(ir, OPCODE_SSG, result_dst, op[0]); + emit(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]); + emit_scalar(ir, OPCODE_RCP, result_dst, op[0]); break; case ir_unop_exp2: - ir_to_mesa_emit_scalar_op1(ir, OPCODE_EX2, result_dst, op[0]); + emit_scalar(ir, OPCODE_EX2, result_dst, op[0]); break; case ir_unop_exp: case ir_unop_log: assert(!"not reached: should be handled by ir_explog_to_explog2"); break; case ir_unop_log2: - ir_to_mesa_emit_scalar_op1(ir, OPCODE_LG2, result_dst, op[0]); + emit_scalar(ir, OPCODE_LG2, result_dst, op[0]); break; case ir_unop_sin: - ir_to_mesa_emit_scalar_op1(ir, OPCODE_SIN, result_dst, op[0]); + emit_scalar(ir, OPCODE_SIN, result_dst, op[0]); break; case ir_unop_cos: - ir_to_mesa_emit_scalar_op1(ir, OPCODE_COS, result_dst, op[0]); + emit_scalar(ir, OPCODE_COS, result_dst, op[0]); break; case ir_unop_sin_reduced: emit_scs(ir, OPCODE_SIN, result_dst, op[0]); @@ -1234,10 +1179,10 @@ ir_to_mesa_visitor::visit(ir_expression *ir) break; case ir_unop_dFdx: - ir_to_mesa_emit_op1(ir, OPCODE_DDX, result_dst, op[0]); + emit(ir, OPCODE_DDX, result_dst, op[0]); break; case ir_unop_dFdy: - ir_to_mesa_emit_op1(ir, OPCODE_DDY, result_dst, op[0]); + emit(ir, OPCODE_DDY, result_dst, op[0]); break; case ir_unop_noise: { @@ -1246,19 +1191,19 @@ ir_to_mesa_visitor::visit(ir_expression *ir) + (ir->operands[0]->type->vector_elements) - 1); assert((opcode >= OPCODE_NOISE1) && (opcode <= OPCODE_NOISE4)); - ir_to_mesa_emit_op1(ir, opcode, result_dst, op[0]); + emit(ir, opcode, result_dst, op[0]); break; } case ir_binop_add: - ir_to_mesa_emit_op2(ir, OPCODE_ADD, result_dst, op[0], op[1]); + emit(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]); + emit(ir, OPCODE_SUB, result_dst, op[0], op[1]); break; case ir_binop_mul: - ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, op[0], op[1]); + emit(ir, OPCODE_MUL, result_dst, op[0], op[1]); break; case ir_binop_div: assert(!"not reached: should be handled by ir_div_to_mul_rcp"); @@ -1267,100 +1212,88 @@ ir_to_mesa_visitor::visit(ir_expression *ir) break; case ir_binop_less: - ir_to_mesa_emit_op2(ir, OPCODE_SLT, result_dst, op[0], op[1]); + emit(ir, OPCODE_SLT, result_dst, op[0], op[1]); break; case ir_binop_greater: - ir_to_mesa_emit_op2(ir, OPCODE_SGT, result_dst, op[0], op[1]); + emit(ir, OPCODE_SGT, result_dst, op[0], op[1]); break; case ir_binop_lequal: - ir_to_mesa_emit_op2(ir, OPCODE_SLE, result_dst, op[0], op[1]); + emit(ir, OPCODE_SLE, result_dst, op[0], op[1]); break; case ir_binop_gequal: - ir_to_mesa_emit_op2(ir, OPCODE_SGE, result_dst, op[0], op[1]); + emit(ir, OPCODE_SGE, result_dst, op[0], op[1]); break; case ir_binop_equal: - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]); + emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]); break; case ir_binop_nequal: - ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); + emit(ir, OPCODE_SNE, result_dst, op[0], op[1]); break; case ir_binop_all_equal: /* "==" operator producing a scalar boolean. */ if (ir->operands[0]->type->is_vector() || ir->operands[1]->type->is_vector()) { - ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); - ir_to_mesa_emit_op2(ir, OPCODE_SNE, - ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]); - ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements); - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, - result_dst, result_src, src_reg_for_float(0.0)); + src_reg temp = get_temp(glsl_type::vec4_type); + emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]); + emit_dp(ir, result_dst, temp, temp, vector_elements); + emit(ir, OPCODE_SEQ, result_dst, result_src, src_reg_for_float(0.0)); } else { - ir_to_mesa_emit_op2(ir, OPCODE_SEQ, result_dst, op[0], op[1]); + emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]); } break; case ir_binop_any_nequal: /* "!=" operator producing a scalar boolean. */ if (ir->operands[0]->type->is_vector() || ir->operands[1]->type->is_vector()) { - ir_to_mesa_src_reg temp = get_temp(glsl_type::vec4_type); - ir_to_mesa_emit_op2(ir, OPCODE_SNE, - ir_to_mesa_dst_reg_from_src(temp), op[0], op[1]); - ir_to_mesa_emit_dp(ir, result_dst, temp, temp, vector_elements); - ir_to_mesa_emit_op2(ir, OPCODE_SNE, - result_dst, result_src, src_reg_for_float(0.0)); + src_reg temp = get_temp(glsl_type::vec4_type); + emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]); + emit_dp(ir, result_dst, temp, temp, vector_elements); + emit(ir, OPCODE_SNE, result_dst, result_src, src_reg_for_float(0.0)); } else { - ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); + emit(ir, OPCODE_SNE, result_dst, op[0], op[1]); } break; case ir_unop_any: assert(ir->operands[0]->type->is_vector()); - ir_to_mesa_emit_dp(ir, result_dst, op[0], op[0], - ir->operands[0]->type->vector_elements); - ir_to_mesa_emit_op2(ir, OPCODE_SNE, - result_dst, result_src, src_reg_for_float(0.0)); + emit_dp(ir, result_dst, op[0], op[0], + ir->operands[0]->type->vector_elements); + emit(ir, OPCODE_SNE, result_dst, result_src, src_reg_for_float(0.0)); break; case ir_binop_logic_xor: - ir_to_mesa_emit_op2(ir, OPCODE_SNE, result_dst, op[0], op[1]); + emit(ir, OPCODE_SNE, result_dst, op[0], op[1]); break; case ir_binop_logic_or: /* This could be a saturated add and skip the SNE. */ - ir_to_mesa_emit_op2(ir, OPCODE_ADD, - result_dst, - op[0], op[1]); - - ir_to_mesa_emit_op2(ir, OPCODE_SNE, - result_dst, - result_src, src_reg_for_float(0.0)); + emit(ir, OPCODE_ADD, result_dst, op[0], op[1]); + emit(ir, OPCODE_SNE, result_dst, result_src, src_reg_for_float(0.0)); break; case ir_binop_logic_and: /* the bool args are stored as float 0.0 or 1.0, so "mul" gives us "and". */ - ir_to_mesa_emit_op2(ir, OPCODE_MUL, - result_dst, - op[0], op[1]); + emit(ir, OPCODE_MUL, result_dst, op[0], op[1]); break; case ir_binop_dot: assert(ir->operands[0]->type->is_vector()); assert(ir->operands[0]->type == ir->operands[1]->type); - ir_to_mesa_emit_dp(ir, result_dst, op[0], op[1], - ir->operands[0]->type->vector_elements); + emit_dp(ir, result_dst, op[0], op[1], + ir->operands[0]->type->vector_elements); break; case ir_unop_sqrt: /* sqrt(x) = x * rsq(x). */ - ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); - ir_to_mesa_emit_op2(ir, OPCODE_MUL, result_dst, result_src, op[0]); + emit_scalar(ir, OPCODE_RSQ, result_dst, op[0]); + emit(ir, OPCODE_MUL, result_dst, result_src, op[0]); /* For incoming channels <= 0, set the result to 0. */ op[0].negate = ~op[0].negate; - ir_to_mesa_emit_op3(ir, OPCODE_CMP, result_dst, + emit(ir, OPCODE_CMP, result_dst, op[0], result_src, src_reg_for_float(0.0)); break; case ir_unop_rsq: - ir_to_mesa_emit_scalar_op1(ir, OPCODE_RSQ, result_dst, op[0]); + emit_scalar(ir, OPCODE_RSQ, result_dst, op[0]); break; case ir_unop_i2f: case ir_unop_b2f: @@ -1369,36 +1302,36 @@ ir_to_mesa_visitor::visit(ir_expression *ir) result_src = op[0]; break; case ir_unop_f2i: - ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); + emit(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, + emit(ir, OPCODE_SNE, result_dst, op[0], src_reg_for_float(0.0)); break; case ir_unop_trunc: - ir_to_mesa_emit_op1(ir, OPCODE_TRUNC, result_dst, op[0]); + emit(ir, OPCODE_TRUNC, result_dst, op[0]); break; case ir_unop_ceil: op[0].negate = ~op[0].negate; - ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); + emit(ir, OPCODE_FLR, result_dst, op[0]); result_src.negate = ~result_src.negate; break; case ir_unop_floor: - ir_to_mesa_emit_op1(ir, OPCODE_FLR, result_dst, op[0]); + emit(ir, OPCODE_FLR, result_dst, op[0]); break; case ir_unop_fract: - ir_to_mesa_emit_op1(ir, OPCODE_FRC, result_dst, op[0]); + emit(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]); + emit(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]); + emit(ir, OPCODE_MAX, result_dst, op[0], op[1]); break; case ir_binop_pow: - ir_to_mesa_emit_scalar_op2(ir, OPCODE_POW, result_dst, op[0], op[1]); + emit_scalar(ir, OPCODE_POW, result_dst, op[0], op[1]); break; case ir_unop_bit_not: @@ -1426,7 +1359,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) void ir_to_mesa_visitor::visit(ir_swizzle *ir) { - ir_to_mesa_src_reg src_reg; + src_reg src; int i; int swizzle[4]; @@ -1436,23 +1369,23 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) */ ir->val->accept(this); - src_reg = this->result; - assert(src_reg.file != PROGRAM_UNDEFINED); + src = this->result; + assert(src.file != PROGRAM_UNDEFINED); for (i = 0; i < 4; i++) { if (i < ir->type->vector_elements) { switch (i) { case 0: - swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.x); + swizzle[i] = GET_SWZ(src.swizzle, ir->mask.x); break; case 1: - swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.y); + swizzle[i] = GET_SWZ(src.swizzle, ir->mask.y); break; case 2: - swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.z); + swizzle[i] = GET_SWZ(src.swizzle, ir->mask.z); break; case 3: - swizzle[i] = GET_SWZ(src_reg.swizzle, ir->mask.w); + swizzle[i] = GET_SWZ(src.swizzle, ir->mask.w); break; } } else { @@ -1463,12 +1396,9 @@ ir_to_mesa_visitor::visit(ir_swizzle *ir) } } - src_reg.swizzle = MAKE_SWIZZLE4(swizzle[0], - swizzle[1], - swizzle[2], - swizzle[3]); + src.swizzle = MAKE_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]); - this->result = src_reg; + this->result = src; } void @@ -1533,54 +1463,53 @@ ir_to_mesa_visitor::visit(ir_dereference_variable *ir) } } - this->result = ir_to_mesa_src_reg(entry->file, entry->index, var->type); + this->result = src_reg(entry->file, entry->index, var->type); } void ir_to_mesa_visitor::visit(ir_dereference_array *ir) { ir_constant *index; - ir_to_mesa_src_reg src_reg; + src_reg src; int element_size = type_size(ir->type); index = ir->array_index->constant_expression_value(); ir->array->accept(this); - src_reg = this->result; + src = this->result; if (index) { - src_reg.index += index->value.i[0] * element_size; + src.index += index->value.i[0] * element_size; } else { - ir_to_mesa_src_reg array_base = this->result; + 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; + 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)); + emit(ir, OPCODE_MUL, dst_reg(index_reg), + this->result, src_reg_for_float(element_size)); } - src_reg.reladdr = ralloc(mem_ctx, ir_to_mesa_src_reg); - memcpy(src_reg.reladdr, &index_reg, sizeof(index_reg)); + src.reladdr = ralloc(mem_ctx, src_reg); + memcpy(src.reladdr, &index_reg, sizeof(index_reg)); } /* If the type is smaller than a vec4, replicate the last channel out. */ if (ir->type->is_scalar() || ir->type->is_vector()) - src_reg.swizzle = swizzle_for_size(ir->type->vector_elements); + src.swizzle = swizzle_for_size(ir->type->vector_elements); else - src_reg.swizzle = SWIZZLE_NOOP; + src.swizzle = SWIZZLE_NOOP; - this->result = src_reg; + this->result = src; } void @@ -1612,7 +1541,7 @@ ir_to_mesa_visitor::visit(ir_dereference_record *ir) * instead of potentially using a temporary like we might with the * ir_dereference handler. */ -static struct ir_to_mesa_dst_reg +static dst_reg get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v) { /* The LHS must be a dereference. If the LHS is a variable indexed array @@ -1629,7 +1558,7 @@ get_assignment_lhs(ir_dereference *ir, ir_to_mesa_visitor *v) * swizzles in it and write swizzles using writemask, though. */ ir->accept(v); - return ir_to_mesa_dst_reg_from_src(v->result); + return dst_reg(v->result); } /** @@ -1722,8 +1651,8 @@ ir_to_mesa_visitor::process_move_condition(ir_rvalue *ir) void ir_to_mesa_visitor::visit(ir_assignment *ir) { - struct ir_to_mesa_dst_reg l; - struct ir_to_mesa_src_reg r; + dst_reg l; + src_reg r; int i; ir->rhs->accept(this); @@ -1779,15 +1708,13 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) if (ir->condition) { const bool switch_order = this->process_move_condition(ir->condition); - ir_to_mesa_src_reg condition = this->result; + src_reg condition = this->result; for (i = 0; i < type_size(ir->lhs->type); i++) { if (switch_order) { - ir_to_mesa_emit_op3(ir, OPCODE_CMP, l, - condition, ir_to_mesa_src_reg_from_dst(l), r); + emit(ir, OPCODE_CMP, l, condition, src_reg(l), r); } else { - ir_to_mesa_emit_op3(ir, OPCODE_CMP, l, - condition, r, ir_to_mesa_src_reg_from_dst(l)); + emit(ir, OPCODE_CMP, l, condition, r, src_reg(l)); } l.index++; @@ -1795,7 +1722,7 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) } } else { for (i = 0; i < type_size(ir->lhs->type); i++) { - ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + emit(ir, OPCODE_MOV, l, r); l.index++; r.index++; } @@ -1806,7 +1733,7 @@ ir_to_mesa_visitor::visit(ir_assignment *ir) void ir_to_mesa_visitor::visit(ir_constant *ir) { - ir_to_mesa_src_reg src_reg; + src_reg src; GLfloat stack_vals[4] = { 0 }; GLfloat *values = stack_vals; unsigned int i; @@ -1818,8 +1745,8 @@ ir_to_mesa_visitor::visit(ir_constant *ir) */ if (ir->type->base_type == GLSL_TYPE_STRUCT) { - ir_to_mesa_src_reg temp_base = get_temp(ir->type); - ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base); + src_reg temp_base = get_temp(ir->type); + dst_reg temp = dst_reg(temp_base); foreach_iter(exec_list_iterator, iter, ir->components) { ir_constant *field_value = (ir_constant *)iter.get(); @@ -1828,12 +1755,12 @@ ir_to_mesa_visitor::visit(ir_constant *ir) assert(size > 0); field_value->accept(this); - src_reg = this->result; + src = this->result; for (i = 0; i < (unsigned int)size; i++) { - ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg); + emit(ir, OPCODE_MOV, temp, src); - src_reg.index++; + src.index++; temp.index++; } } @@ -1842,19 +1769,19 @@ ir_to_mesa_visitor::visit(ir_constant *ir) } if (ir->type->is_array()) { - ir_to_mesa_src_reg temp_base = get_temp(ir->type); - ir_to_mesa_dst_reg temp = ir_to_mesa_dst_reg_from_src(temp_base); + src_reg temp_base = get_temp(ir->type); + dst_reg temp = dst_reg(temp_base); int size = type_size(ir->type->fields.array); assert(size > 0); for (i = 0; i < ir->type->length; i++) { ir->array_elements[i]->accept(this); - src_reg = this->result; + src = this->result; for (int j = 0; j < size; j++) { - ir_to_mesa_emit_op1(ir, OPCODE_MOV, temp, src_reg); + emit(ir, OPCODE_MOV, temp, src); - src_reg.index++; + src.index++; temp.index++; } } @@ -1863,19 +1790,19 @@ ir_to_mesa_visitor::visit(ir_constant *ir) } if (ir->type->is_matrix()) { - ir_to_mesa_src_reg mat = get_temp(ir->type); - ir_to_mesa_dst_reg mat_column = ir_to_mesa_dst_reg_from_src(mat); + src_reg mat = get_temp(ir->type); + dst_reg mat_column = dst_reg(mat); for (i = 0; i < ir->type->matrix_columns; i++) { assert(ir->type->base_type == GLSL_TYPE_FLOAT); values = &ir->value.f[i * ir->type->vector_elements]; - src_reg = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, NULL); - src_reg.index = _mesa_add_unnamed_constant(this->prog->Parameters, + src = src_reg(PROGRAM_CONSTANT, -1, NULL); + src.index = _mesa_add_unnamed_constant(this->prog->Parameters, values, ir->type->vector_elements, - &src_reg.swizzle); - ir_to_mesa_emit_op1(ir, OPCODE_MOV, mat_column, src_reg); + &src.swizzle); + emit(ir, OPCODE_MOV, mat_column, src); mat_column.index++; } @@ -1884,7 +1811,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) return; } - src_reg.file = PROGRAM_CONSTANT; + src.file = PROGRAM_CONSTANT; switch (ir->type->base_type) { case GLSL_TYPE_FLOAT: values = &ir->value.f[0]; @@ -1908,7 +1835,7 @@ ir_to_mesa_visitor::visit(ir_constant *ir) assert(!"Non-float/uint/int/bool constant"); } - this->result = ir_to_mesa_src_reg(PROGRAM_CONSTANT, -1, ir->type); + this->result = src_reg(PROGRAM_CONSTANT, -1, ir->type); this->result.index = _mesa_add_unnamed_constant(this->prog->Parameters, values, ir->type->vector_elements, @@ -1950,7 +1877,7 @@ ir_to_mesa_visitor::get_function_signature(ir_function_signature *sig) if (!sig->return_type->is_void()) { entry->return_reg = get_temp(sig->return_type); } else { - entry->return_reg = ir_to_mesa_undef; + entry->return_reg = undef_src; } this->function_signatures.push_tail(entry); @@ -1977,9 +1904,9 @@ ir_to_mesa_visitor::visit(ir_call *ir) assert(storage); param_rval->accept(this); - ir_to_mesa_src_reg r = this->result; + src_reg r = this->result; - ir_to_mesa_dst_reg l; + dst_reg l; l.file = storage->file; l.index = storage->index; l.reladdr = NULL; @@ -1987,7 +1914,7 @@ ir_to_mesa_visitor::visit(ir_call *ir) l.cond_mask = COND_TR; for (i = 0; i < type_size(param->type); i++) { - ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + emit(ir, OPCODE_MOV, l, r); l.index++; r.index++; } @@ -1998,8 +1925,7 @@ ir_to_mesa_visitor::visit(ir_call *ir) 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 = emit(ir, OPCODE_CAL); call_inst->function = entry; /* Process out parameters. */ @@ -2013,7 +1939,7 @@ ir_to_mesa_visitor::visit(ir_call *ir) variable_storage *storage = find_variable_storage(param); assert(storage); - ir_to_mesa_src_reg r; + src_reg r; r.file = storage->file; r.index = storage->index; r.reladdr = NULL; @@ -2021,10 +1947,10 @@ ir_to_mesa_visitor::visit(ir_call *ir) r.negate = 0; param_rval->accept(this); - ir_to_mesa_dst_reg l = ir_to_mesa_dst_reg_from_src(this->result); + dst_reg l = dst_reg(this->result); for (i = 0; i < type_size(param->type); i++) { - ir_to_mesa_emit_op1(ir, OPCODE_MOV, l, r); + emit(ir, OPCODE_MOV, l, r); l.index++; r.index++; } @@ -2041,8 +1967,8 @@ ir_to_mesa_visitor::visit(ir_call *ir) void ir_to_mesa_visitor::visit(ir_texture *ir) { - ir_to_mesa_src_reg result_src, coord, lod_info, projector; - ir_to_mesa_dst_reg result_dst, coord_dst; + src_reg result_src, coord, lod_info, projector; + dst_reg result_dst, coord_dst; ir_to_mesa_instruction *inst = NULL; prog_opcode opcode = OPCODE_NOP; @@ -2054,9 +1980,8 @@ ir_to_mesa_visitor::visit(ir_texture *ir) * 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); + coord_dst = dst_reg(coord); + emit(ir, OPCODE_MOV, coord_dst, this->result); if (ir->projector) { ir->projector->accept(this); @@ -2067,7 +1992,7 @@ ir_to_mesa_visitor::visit(ir_texture *ir) * 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); + result_dst = dst_reg(result_src); switch (ir->op) { case ir_tex: @@ -2093,11 +2018,11 @@ ir_to_mesa_visitor::visit(ir_texture *ir) 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); + emit(ir, OPCODE_MOV, coord_dst, projector); coord_dst.writemask = WRITEMASK_XYZW; opcode = OPCODE_TXP; } else { - ir_to_mesa_src_reg coord_w = coord; + src_reg coord_w = coord; coord_w.swizzle = SWIZZLE_WWWW; /* For the other TEX opcodes there's no projective version @@ -2105,34 +2030,58 @@ ir_to_mesa_visitor::visit(ir_texture *ir) * projective divide now. */ coord_dst.writemask = WRITEMASK_W; - ir_to_mesa_emit_op1(ir, OPCODE_RCP, coord_dst, projector); + emit(ir, OPCODE_RCP, coord_dst, projector); + + /* In the case where we have to project the coordinates "by hand," + * the shadow comparitor value must also be projected. + */ + src_reg tmp_src = coord; + if (ir->shadow_comparitor) { + /* Slot the shadow value in as the second to last component of the + * coord. + */ + ir->shadow_comparitor->accept(this); + + tmp_src = get_temp(glsl_type::vec4_type); + dst_reg tmp_dst = dst_reg(tmp_src); + + tmp_dst.writemask = WRITEMASK_Z; + emit(ir, OPCODE_MOV, tmp_dst, this->result); + + tmp_dst.writemask = WRITEMASK_XY; + emit(ir, OPCODE_MOV, tmp_dst, coord); + } coord_dst.writemask = WRITEMASK_XYZ; - ir_to_mesa_emit_op2(ir, OPCODE_MUL, coord_dst, coord, coord_w); + emit(ir, OPCODE_MUL, coord_dst, tmp_src, coord_w); coord_dst.writemask = WRITEMASK_XYZW; coord.swizzle = SWIZZLE_XYZW; } } - if (ir->shadow_comparitor) { + /* If projection is done and the opcode is not OPCODE_TXP, then the shadow + * comparitor was put in the correct place (and projected) by the code, + * above, that handles by-hand projection. + */ + if (ir->shadow_comparitor && (!ir->projector || opcode == OPCODE_TXP)) { /* 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); + emit(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); + emit(ir, OPCODE_MOV, coord_dst, lod_info); coord_dst.writemask = WRITEMASK_XYZW; } - inst = ir_to_mesa_emit_op1(ir, opcode, result_dst, coord); + inst = emit(ir, opcode, result_dst, coord); if (ir->shadow_comparitor) inst->tex_shadow = GL_TRUE; @@ -2175,24 +2124,24 @@ void ir_to_mesa_visitor::visit(ir_return *ir) { if (ir->get_value()) { - ir_to_mesa_dst_reg l; + dst_reg l; int i; assert(current_function); ir->get_value()->accept(this); - ir_to_mesa_src_reg r = this->result; + src_reg r = this->result; - l = ir_to_mesa_dst_reg_from_src(current_function->return_reg); + l = dst_reg(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); + emit(ir, OPCODE_MOV, l, r); l.index++; r.index++; } } - ir_to_mesa_emit_op0(ir, OPCODE_RET); + emit(ir, OPCODE_RET); } void @@ -2203,9 +2152,9 @@ ir_to_mesa_visitor::visit(ir_discard *ir) if (ir->condition) { ir->condition->accept(this); this->result.negate = ~this->result.negate; - ir_to_mesa_emit_op1(ir, OPCODE_KIL, ir_to_mesa_undef_dst, this->result); + emit(ir, OPCODE_KIL, undef_dst, this->result); } else { - ir_to_mesa_emit_op0(ir, OPCODE_KIL_NV); + emit(ir, OPCODE_KIL_NV); } fp->UsesKill = GL_TRUE; @@ -2230,19 +2179,15 @@ ir_to_mesa_visitor::visit(ir_if *ir) * 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); + src_reg temp = get_temp(glsl_type::bool_type); + cond_inst = emit(ir->condition, OPCODE_MOV, dst_reg(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; + if_inst = emit(ir->condition, OPCODE_IF); + if_inst->dst.cond_mask = COND_NE; } else { - if_inst = ir_to_mesa_emit_op1(ir->condition, - OPCODE_IF, ir_to_mesa_undef_dst, - this->result); + if_inst = emit(ir->condition, OPCODE_IF, undef_dst, this->result); } this->instructions.push_tail(if_inst); @@ -2250,12 +2195,11 @@ ir_to_mesa_visitor::visit(ir_if *ir) visit_exec_list(&ir->then_instructions, this); if (!ir->else_instructions.is_empty()) { - else_inst = ir_to_mesa_emit_op0(ir->condition, OPCODE_ELSE); + else_inst = emit(ir->condition, OPCODE_ELSE); visit_exec_list(&ir->else_instructions, this); } - if_inst = ir_to_mesa_emit_op1(ir->condition, OPCODE_ENDIF, - ir_to_mesa_undef_dst, ir_to_mesa_undef); + if_inst = emit(ir->condition, OPCODE_ENDIF); } ir_to_mesa_visitor::ir_to_mesa_visitor() @@ -2273,7 +2217,7 @@ ir_to_mesa_visitor::~ir_to_mesa_visitor() } static struct prog_src_register -mesa_src_reg_from_ir_src_reg(ir_to_mesa_src_reg reg) +mesa_src_reg_from_ir_src_reg(src_reg reg) { struct prog_src_register mesa_reg; @@ -2730,17 +2674,17 @@ ir_to_mesa_visitor::copy_propagate(void) foreach_iter(exec_list_iterator, iter, this->instructions) { ir_to_mesa_instruction *inst = (ir_to_mesa_instruction *)iter.get(); - assert(inst->dst_reg.file != PROGRAM_TEMPORARY - || inst->dst_reg.index < this->next_temp); + assert(inst->dst.file != PROGRAM_TEMPORARY + || inst->dst.index < this->next_temp); /* First, do any copy propagation possible into the src regs. */ for (int r = 0; r < 3; r++) { ir_to_mesa_instruction *first = NULL; bool good = true; - int acp_base = inst->src_reg[r].index * 4; + int acp_base = inst->src[r].index * 4; - if (inst->src_reg[r].file != PROGRAM_TEMPORARY || - inst->src_reg[r].reladdr) + if (inst->src[r].file != PROGRAM_TEMPORARY || + inst->src[r].reladdr) continue; /* See if we can find entries in the ACP consisting of MOVs @@ -2748,7 +2692,7 @@ ir_to_mesa_visitor::copy_propagate(void) * of this src register reference. */ for (int i = 0; i < 4; i++) { - int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i); + int src_chan = GET_SWZ(inst->src[r].swizzle, i); ir_to_mesa_instruction *copy_chan = acp[acp_base + src_chan]; if (!copy_chan) { @@ -2761,8 +2705,8 @@ ir_to_mesa_visitor::copy_propagate(void) if (!first) { first = copy_chan; } else { - if (first->src_reg[0].file != copy_chan->src_reg[0].file || - first->src_reg[0].index != copy_chan->src_reg[0].index) { + if (first->src[0].file != copy_chan->src[0].file || + first->src[0].index != copy_chan->src[0].index) { good = false; break; } @@ -2773,17 +2717,17 @@ ir_to_mesa_visitor::copy_propagate(void) /* We've now validated that we can copy-propagate to * replace this src register reference. Do it. */ - inst->src_reg[r].file = first->src_reg[0].file; - inst->src_reg[r].index = first->src_reg[0].index; + inst->src[r].file = first->src[0].file; + inst->src[r].index = first->src[0].index; int swizzle = 0; for (int i = 0; i < 4; i++) { - int src_chan = GET_SWZ(inst->src_reg[r].swizzle, i); + int src_chan = GET_SWZ(inst->src[r].swizzle, i); ir_to_mesa_instruction *copy_inst = acp[acp_base + src_chan]; - swizzle |= (GET_SWZ(copy_inst->src_reg[0].swizzle, src_chan) << + swizzle |= (GET_SWZ(copy_inst->src[0].swizzle, src_chan) << (3 * i)); } - inst->src_reg[r].swizzle = swizzle; + inst->src[r].swizzle = swizzle; } } @@ -2820,13 +2764,13 @@ ir_to_mesa_visitor::copy_propagate(void) /* Continuing the block, clear any written channels from * the ACP. */ - if (inst->dst_reg.file == PROGRAM_TEMPORARY && inst->dst_reg.reladdr) { + if (inst->dst.file == PROGRAM_TEMPORARY && inst->dst.reladdr) { /* Any temporary might be written, so no copy propagation * across this instruction. */ memset(acp, 0, sizeof(*acp) * this->next_temp * 4); - } else if (inst->dst_reg.file == PROGRAM_OUTPUT && - inst->dst_reg.reladdr) { + } else if (inst->dst.file == PROGRAM_OUTPUT && + inst->dst.reladdr) { /* Any output might be written, so no copy propagation * from outputs across this instruction. */ @@ -2835,17 +2779,17 @@ ir_to_mesa_visitor::copy_propagate(void) if (!acp[4 * r + c]) continue; - if (acp[4 * r + c]->src_reg[0].file == PROGRAM_OUTPUT) + if (acp[4 * r + c]->src[0].file == PROGRAM_OUTPUT) acp[4 * r + c] = NULL; } } - } else if (inst->dst_reg.file == PROGRAM_TEMPORARY || - inst->dst_reg.file == PROGRAM_OUTPUT) { + } else if (inst->dst.file == PROGRAM_TEMPORARY || + inst->dst.file == PROGRAM_OUTPUT) { /* Clear where it's used as dst. */ - if (inst->dst_reg.file == PROGRAM_TEMPORARY) { + if (inst->dst.file == PROGRAM_TEMPORARY) { for (int c = 0; c < 4; c++) { - if (inst->dst_reg.writemask & (1 << c)) { - acp[4 * inst->dst_reg.index + c] = NULL; + if (inst->dst.writemask & (1 << c)) { + acp[4 * inst->dst.index + c] = NULL; } } } @@ -2856,11 +2800,11 @@ ir_to_mesa_visitor::copy_propagate(void) if (!acp[4 * r + c]) continue; - int src_chan = GET_SWZ(acp[4 * r + c]->src_reg[0].swizzle, c); + int src_chan = GET_SWZ(acp[4 * r + c]->src[0].swizzle, c); - if (acp[4 * r + c]->src_reg[0].file == inst->dst_reg.file && - acp[4 * r + c]->src_reg[0].index == inst->dst_reg.index && - inst->dst_reg.writemask & (1 << src_chan)) + if (acp[4 * r + c]->src[0].file == inst->dst.file && + acp[4 * r + c]->src[0].index == inst->dst.index && + inst->dst.writemask & (1 << src_chan)) { acp[4 * r + c] = NULL; } @@ -2872,15 +2816,15 @@ ir_to_mesa_visitor::copy_propagate(void) /* If this is a copy, add it to the ACP. */ if (inst->op == OPCODE_MOV && - inst->dst_reg.file == PROGRAM_TEMPORARY && - !inst->dst_reg.reladdr && + inst->dst.file == PROGRAM_TEMPORARY && + !inst->dst.reladdr && !inst->saturate && - !inst->src_reg[0].reladdr && - !inst->src_reg[0].negate) { + !inst->src[0].reladdr && + !inst->src[0].negate) { for (int i = 0; i < 4; i++) { - if (inst->dst_reg.writemask & (1 << i)) { - acp[4 * inst->dst_reg.index + i] = inst; - acp_level[4 * inst->dst_reg.index + i] = level; + if (inst->dst.writemask & (1 << i)) { + acp[4 * inst->dst.index + i] = inst; + acp_level[4 * inst->dst.index + i] = level; } } } @@ -2945,7 +2889,7 @@ get_mesa_program(struct gl_context *ctx, /* Emit Mesa IR for main(). */ visit_exec_list(shader->ir, &v); - v.ir_to_mesa_emit_op0(NULL, OPCODE_END); + v.emit(NULL, OPCODE_END); /* Now emit bodies for any functions that were used. */ do { @@ -2957,7 +2901,7 @@ get_mesa_program(struct gl_context *ctx, if (!entry->bgn_inst) { v.current_function = entry; - entry->bgn_inst = v.ir_to_mesa_emit_op0(NULL, OPCODE_BGNSUB); + entry->bgn_inst = v.emit(NULL, OPCODE_BGNSUB); entry->bgn_inst->function = entry; visit_exec_list(&entry->sig->body, &v); @@ -2965,10 +2909,10 @@ get_mesa_program(struct gl_context *ctx, ir_to_mesa_instruction *last; last = (ir_to_mesa_instruction *)v.instructions.get_tail(); if (last->op != OPCODE_RET) - v.ir_to_mesa_emit_op0(NULL, OPCODE_RET); + v.emit(NULL, OPCODE_RET); ir_to_mesa_instruction *end; - end = v.ir_to_mesa_emit_op0(NULL, OPCODE_ENDSUB); + end = v.emit(NULL, OPCODE_ENDSUB); end->function = entry; progress = GL_TRUE; @@ -3002,14 +2946,14 @@ get_mesa_program(struct gl_context *ctx, mesa_inst->CondUpdate = inst->cond_update; if (inst->saturate) mesa_inst->SaturateMode = SATURATE_ZERO_ONE; - mesa_inst->DstReg.File = inst->dst_reg.file; - 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]); + mesa_inst->DstReg.File = inst->dst.file; + mesa_inst->DstReg.Index = inst->dst.index; + mesa_inst->DstReg.CondMask = inst->dst.cond_mask; + mesa_inst->DstReg.WriteMask = inst->dst.writemask; + mesa_inst->DstReg.RelAddr = inst->dst.reladdr != NULL; + mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src[0]); + mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src[1]); + mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src[2]); mesa_inst->TexSrcUnit = inst->sampler; mesa_inst->TexSrcTarget = inst->tex_target; mesa_inst->TexShadow = inst->tex_shadow; diff --git a/src/mesa/program/prog_optimize.c b/src/mesa/program/prog_optimize.c index 96971f2eda4..11debc485eb 100644 --- a/src/mesa/program/prog_optimize.c +++ b/src/mesa/program/prog_optimize.c @@ -74,6 +74,17 @@ get_src_arg_mask(const struct prog_instruction *inst, case OPCODE_MAD: case OPCODE_MUL: case OPCODE_SUB: + case OPCODE_CMP: + case OPCODE_FLR: + case OPCODE_FRC: + case OPCODE_LRP: + case OPCODE_SEQ: + case OPCODE_SGE: + case OPCODE_SGT: + case OPCODE_SLE: + case OPCODE_SLT: + case OPCODE_SNE: + case OPCODE_SSG: channel_mask = inst->DstReg.WriteMask & dst_mask; break; case OPCODE_RCP: @@ -937,24 +948,35 @@ update_interval(GLint intBegin[], GLint intEnd[], GLuint index, GLuint ic) { int i; + GLuint begin = ic; + GLuint end = ic; /* If the register is used in a loop, extend its lifetime through the end * of the outermost loop that doesn't contain its definition. */ for (i = 0; i < loopStackDepth; i++) { if (intBegin[index] < loopStack[i].Start) { - ic = loopStack[i].End; + end = loopStack[i].End; break; } } + /* Variables that are live at the end of a loop will also be live at the + * beginning, so an instruction inside of a loop should have its live + * interval begin at the start of the outermost loop. + */ + if (loopStackDepth > 0 && ic > loopStack[0].Start && ic < loopStack[0].End) { + begin = loopStack[0].Start; + } + ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); if (intBegin[index] == -1) { ASSERT(intEnd[index] == -1); - intBegin[index] = intEnd[index] = ic; + intBegin[index] = begin; + intEnd[index] = end; } else { - intEnd[index] = ic; + intEnd[index] = end; } } @@ -1224,6 +1246,83 @@ print_it(struct gl_context *ctx, struct gl_program *program, const char *txt) { } #endif +/** + * This pass replaces CMP T0, T1 T2 T0 with MOV T0, T2 when the CMP + * instruction is the first instruction to write to register T0. The are + * several lowering passes done in GLSL IR (e.g. branches and + * relative addressing) that create a large number of conditional assignments + * that ir_to_mesa converts to CMP instructions like the one mentioned above. + * + * Here is why this conversion is safe: + * CMP T0, T1 T2 T0 can be expanded to: + * if (T1 < 0.0) + * MOV T0, T2; + * else + * MOV T0, T0; + * + * If (T1 < 0.0) evaluates to true then our replacement MOV T0, T2 is the same + * as the original program. If (T1 < 0.0) evaluates to false, executing + * MOV T0, T0 will store a garbage value in T0 since T0 is uninitialized. + * Therefore, it doesn't matter that we are replacing MOV T0, T0 with MOV T0, T2 + * because any instruction that was going to read from T0 after this was going + * to read a garbage value anyway. + */ +static void +_mesa_simplify_cmp(struct gl_program * program) +{ + GLuint tempWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; + GLuint outputWrites[MAX_PROGRAM_OUTPUTS]; + GLuint i; + + if (dbg) { + printf("Optimize: Begin reads without writes\n"); + _mesa_print_program(program); + } + + for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) { + tempWrites[i] = 0; + } + + for (i = 0; i < MAX_PROGRAM_OUTPUTS; i++) { + outputWrites[i] = 0; + } + + for (i = 0; i < program->NumInstructions; i++) { + struct prog_instruction *inst = program->Instructions + i; + GLuint prevWriteMask; + + /* Give up if we encounter relative addressing or flow control. */ + if (_mesa_is_flow_control_opcode(inst->Opcode) || inst->DstReg.RelAddr) { + return; + } + + if (inst->DstReg.File == PROGRAM_OUTPUT) { + assert(inst->DstReg.Index < MAX_PROGRAM_OUTPUTS); + prevWriteMask = outputWrites[inst->DstReg.Index]; + outputWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask; + } else if (inst->DstReg.File == PROGRAM_TEMPORARY) { + assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS); + prevWriteMask = tempWrites[inst->DstReg.Index]; + tempWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask; + } + + /* For a CMP to be considered a conditional write, the destination + * register and source register two must be the same. */ + if (inst->Opcode == OPCODE_CMP + && !(inst->DstReg.WriteMask & prevWriteMask) + && inst->SrcReg[2].File == inst->DstReg.File + && inst->SrcReg[2].Index == inst->DstReg.Index + && inst->DstReg.WriteMask == get_src_arg_mask(inst, 2, NO_MASK)) { + + inst->Opcode = OPCODE_MOV; + inst->SrcReg[0] = inst->SrcReg[1]; + } + } + if (dbg) { + printf("Optimize: End reads without writes\n"); + _mesa_print_program(program); + } +} /** * Apply optimizations to the given program to eliminate unnecessary @@ -1234,6 +1333,7 @@ _mesa_optimize_program(struct gl_context *ctx, struct gl_program *program) { GLboolean any_change; + _mesa_simplify_cmp(program); /* Stop when no modifications were output */ do { any_change = GL_FALSE; diff --git a/src/mesa/program/prog_statevars.c b/src/mesa/program/prog_statevars.c index c310acb01d4..1fd26f44d56 100644 --- a/src/mesa/program/prog_statevars.c +++ b/src/mesa/program/prog_statevars.c @@ -237,11 +237,17 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], { /* state[1] is the texture unit */ const GLuint unit = (GLuint) state[1]; - COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); + if(ctx->Color._ClampFragmentColor) + COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); + else + COPY_4V(value, ctx->Texture.Unit[unit].EnvColorUnclamped); } return; case STATE_FOG_COLOR: - COPY_4V(value, ctx->Fog.Color); + if(ctx->Color._ClampFragmentColor) + COPY_4V(value, ctx->Fog.Color); + else + COPY_4V(value, ctx->Fog.ColorUnclamped); return; case STATE_FOG_PARAMS: value[0] = ctx->Fog.Density; @@ -399,6 +405,22 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], } return; + case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED: + { + const GLuint idx = (GLuint) state[2]; + if(ctx->Light._ClampVertexColor && + (idx == VERT_ATTRIB_COLOR0 || + idx == VERT_ATTRIB_COLOR1)) { + value[0] = CLAMP(ctx->Current.Attrib[idx][0], 0.0f, 1.0f); + value[1] = CLAMP(ctx->Current.Attrib[idx][1], 0.0f, 1.0f); + value[2] = CLAMP(ctx->Current.Attrib[idx][2], 0.0f, 1.0f); + value[3] = CLAMP(ctx->Current.Attrib[idx][3], 0.0f, 1.0f); + } + else + COPY_4V(value, ctx->Current.Attrib[idx]); + } + return; + case STATE_NORMAL_SCALE: ASSIGN_4V(value, ctx->_ModelViewInvScale, @@ -560,7 +582,7 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], value[0] = value[1] = value[2] = - value[3] = texObj->CompareFailValue; + value[3] = texObj->Sampler.CompareFailValue; } } return; @@ -649,10 +671,12 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) return _NEW_LIGHT; case STATE_TEXGEN: - case STATE_TEXENV_COLOR: return _NEW_TEXTURE; + case STATE_TEXENV_COLOR: + return _NEW_TEXTURE | _NEW_BUFFERS | _NEW_FRAG_CLAMP; case STATE_FOG_COLOR: + return _NEW_FOG | _NEW_BUFFERS | _NEW_FRAG_CLAMP; case STATE_FOG_PARAMS: return _NEW_FOG; @@ -688,6 +712,8 @@ _mesa_program_state_flags(const gl_state_index state[STATE_LENGTH]) switch (state[1]) { case STATE_CURRENT_ATTRIB: return _NEW_CURRENT_ATTRIB; + case STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED: + return _NEW_CURRENT_ATTRIB | _NEW_LIGHT | _NEW_BUFFERS; case STATE_NORMAL_SCALE: return _NEW_MODELVIEW; diff --git a/src/mesa/program/prog_statevars.h b/src/mesa/program/prog_statevars.h index f2407af9c87..9fe8d81b3dd 100644 --- a/src/mesa/program/prog_statevars.h +++ b/src/mesa/program/prog_statevars.h @@ -106,6 +106,7 @@ typedef enum gl_state_index_ { STATE_INTERNAL, /* Mesa additions */ STATE_CURRENT_ATTRIB, /* ctx->Current vertex attrib value */ + STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED, /* ctx->Current vertex attrib value after passthrough vertex processing */ STATE_NORMAL_SCALE, STATE_TEXRECT_SCALE, STATE_FOG_PARAMS_OPTIMIZED, /* for faster fog calc */ diff --git a/src/mesa/program/program.c b/src/mesa/program/program.c index 79034ab26f2..78efca9f122 100644 --- a/src/mesa/program/program.c +++ b/src/mesa/program/program.c @@ -75,10 +75,10 @@ _mesa_init_program(struct gl_context *ctx) ASSERT(ctx->Const.FragmentProgram.MaxAddressOffset <= (1 << INST_INDEX_BITS)); /* If this fails, increase prog_instruction::TexSrcUnit size */ - ASSERT(MAX_TEXTURE_UNITS < (1 << 5)); + ASSERT(MAX_TEXTURE_UNITS <= (1 << 5)); /* If this fails, increase prog_instruction::TexSrcTarget size */ - ASSERT(NUM_TEXTURE_TARGETS < (1 << 3)); + ASSERT(NUM_TEXTURE_TARGETS <= (1 << 3)); ctx->Program.ErrorPos = -1; ctx->Program.ErrorString = _mesa_strdup(""); @@ -557,7 +557,6 @@ _mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog) const struct gl_fragment_program *fp = (const struct gl_fragment_program *) prog; struct gl_fragment_program *fpc = (struct gl_fragment_program *) clone; - fpc->FogOption = fp->FogOption; fpc->UsesKill = fp->UsesKill; fpc->OriginUpperLeft = fp->OriginUpperLeft; fpc->PixelCenterInteger = fp->PixelCenterInteger; diff --git a/src/mesa/program/program_parse.y b/src/mesa/program/program_parse.y index 19aa8ccdb53..b35bc5a7cae 100644 --- a/src/mesa/program/program_parse.y +++ b/src/mesa/program/program_parse.y @@ -2064,6 +2064,34 @@ optResultFaceType: ? VERT_RESULT_COL0 : FRAG_RESULT_COLOR; } + | '[' INTEGER ']' + { + if (state->mode == ARB_vertex) { + yyerror(& @1, state, "invalid program result name"); + YYERROR; + } else { + if (!state->option.DrawBuffers) { + /* From the ARB_draw_buffers spec (same text exists + * for ATI_draw_buffers): + * + * If this option is not specified, a fragment + * program that attempts to bind + * "result.color[n]" will fail to load, and only + * "result.color" will be allowed. + */ + yyerror(& @1, state, + "result.color[] used without " + "`OPTION ARB_draw_buffers' or " + "`OPTION ATI_draw_buffers'"); + YYERROR; + } else if ($2 >= state->MaxDrawBuffers) { + yyerror(& @1, state, + "result.color[] exceeds MAX_DRAW_BUFFERS_ARB"); + YYERROR; + } + $$ = FRAG_RESULT_DATA0 + $2; + } + } | FRONT { if (state->mode == ARB_vertex) { @@ -2681,6 +2709,7 @@ _mesa_parse_arb_program(struct gl_context *ctx, GLenum target, const GLubyte *st state->MaxClipPlanes = ctx->Const.MaxClipPlanes; state->MaxLights = ctx->Const.MaxLights; state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices; + state->MaxDrawBuffers = ctx->Const.MaxDrawBuffers; state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB) ? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM; diff --git a/src/mesa/program/program_parse_extra.c b/src/mesa/program/program_parse_extra.c index ae98b782b70..4d928483e16 100644 --- a/src/mesa/program/program_parse_extra.c +++ b/src/mesa/program/program_parse_extra.c @@ -229,6 +229,16 @@ _mesa_ARBfp_parse_option(struct asm_parser_state *state, const char *option) } } } + } else if (strncmp(option, "ATI_", 4) == 0) { + option += 4; + + if (strcmp(option, "draw_buffers") == 0) { + /* Don't need to check extension availability because all Mesa-based + * drivers support GL_ATI_draw_buffers. + */ + state->option.DrawBuffers = 1; + return 1; + } } else if (strncmp(option, "NV_fragment_program", 19) == 0) { option += 19; diff --git a/src/mesa/program/program_parser.h b/src/mesa/program/program_parser.h index d689eef7958..8e5aaee95e5 100644 --- a/src/mesa/program/program_parser.h +++ b/src/mesa/program/program_parser.h @@ -173,6 +173,7 @@ struct asm_parser_state { unsigned MaxClipPlanes; unsigned MaxLights; unsigned MaxProgramMatrices; + unsigned MaxDrawBuffers; /*@}*/ /** diff --git a/src/mesa/program/programopt.c b/src/mesa/program/programopt.c index f92881f8337..a239da2c609 100644 --- a/src/mesa/program/programopt.c +++ b/src/mesa/program/programopt.c @@ -230,15 +230,25 @@ _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog) /** - * Append extra instructions onto the given fragment program to implement - * the fog mode specified by fprog->FogOption. - * The fragment.fogcoord input is used to compute the fog blend factor. + * Append instructions to implement fog * - * XXX with a little work, this function could be adapted to add fog code + * The \c fragment.fogcoord input is used to compute the fog blend factor. + * + * \param ctx The GL context + * \param fprog Fragment program that fog instructions will be appended to. + * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR. + * \param saturate True if writes to color outputs should be clamped to [0, 1] + * + * \note + * This function sets \c FRAG_BIT_FOGC in \c fprog->Base.InputsRead. + * + * \todo With a little work, this function could be adapted to add fog code * to vertex programs too. */ void -_mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) +_mesa_append_fog_code(struct gl_context *ctx, + struct gl_fragment_program *fprog, GLenum fog_mode, + GLboolean saturate) { static const gl_state_index fogPStateOpt[STATE_LENGTH] = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 }; @@ -251,9 +261,9 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) GLint fogPRefOpt, fogColorRef; /* state references */ GLuint colorTemp, fogFactorTemp; /* temporary registerss */ - if (fprog->FogOption == GL_NONE) { + if (fog_mode == GL_NONE) { _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program" - " with FogOption == GL_NONE"); + " with fog_mode == GL_NONE"); return; } @@ -290,7 +300,7 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) /* change the instruction to write to colorTemp w/ clamping */ inst->DstReg.File = PROGRAM_TEMPORARY; inst->DstReg.Index = colorTemp; - inst->SaturateMode = SATURATE_ZERO_ONE; + inst->SaturateMode = saturate; /* don't break (may be several writes to result.color) */ } inst++; @@ -300,7 +310,8 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) _mesa_init_instructions(inst, 5); /* emit instructions to compute fog blending factor */ - if (fprog->FogOption == GL_LINEAR) { + /* this is always clamped to [0, 1] regardless of fragment clamping */ + if (fog_mode == GL_LINEAR) { /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */ inst->Opcode = OPCODE_MAD; inst->DstReg.File = PROGRAM_TEMPORARY; @@ -319,7 +330,7 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) inst++; } else { - ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2); + ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2); /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */ /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */ /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */ @@ -330,12 +341,12 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) inst->SrcReg[0].File = PROGRAM_STATE_VAR; inst->SrcReg[0].Index = fogPRefOpt; inst->SrcReg[0].Swizzle - = (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; + = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW; inst->SrcReg[1].File = PROGRAM_INPUT; inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC; inst->SrcReg[1].Swizzle = SWIZZLE_XXXX; inst++; - if (fprog->FogOption == GL_EXP2) { + if (fog_mode == GL_EXP2) { /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */ inst->Opcode = OPCODE_MUL; inst->DstReg.File = PROGRAM_TEMPORARY; @@ -396,7 +407,6 @@ _mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog) fprog->Base.Instructions = newInst; fprog->Base.NumInstructions = inst - newInst; fprog->Base.InputsRead |= FRAG_BIT_FOGC; - /* XXX do this? fprog->FogOption = GL_NONE; */ } diff --git a/src/mesa/program/programopt.h b/src/mesa/program/programopt.h index ef6f1bd0794..b9205823c29 100644 --- a/src/mesa/program/programopt.h +++ b/src/mesa/program/programopt.h @@ -32,7 +32,9 @@ extern void _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog); extern void -_mesa_append_fog_code(struct gl_context *ctx, struct gl_fragment_program *fprog); +_mesa_append_fog_code(struct gl_context *ctx, + struct gl_fragment_program *fprog, GLenum fog_mode, + GLboolean saturate); extern void _mesa_count_texture_indirections(struct gl_program *prog); |