static GLuint get_dest( struct i915_fragment_program *p, int unit ) { if (p->ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) return i915_get_temp( p ); else if (unit != p->last_tex_stage) return i915_get_temp( p ); else return UREG(REG_TYPE_OC, 0); }
static GLuint emit_combine_source( struct i915_fragment_program *p, GLuint mask, GLuint unit, GLenum source, GLenum operand ) { GLuint arg, src; src = get_source(p, source, unit); switch (operand) { case GL_ONE_MINUS_SRC_COLOR: /* Get unused tmp, * Emit tmp = 1.0 + arg.-x-y-z-w */ arg = i915_get_temp( p ); return i915_emit_arith( p, A0_ADD, arg, mask, 0, swizzle(src, ONE, ONE, ONE, ONE ), negate(src, 1,1,1,1), 0); case GL_SRC_ALPHA: if (mask == A0_DEST_CHANNEL_W) return src; else return swizzle( src, W, W, W, W ); case GL_ONE_MINUS_SRC_ALPHA: /* Get unused tmp, * Emit tmp = 1.0 + arg.-w-w-w-w */ arg = i915_get_temp( p ); return i915_emit_arith( p, A0_ADD, arg, mask, 0, swizzle(src, ONE, ONE, ONE, ONE ), negate( swizzle(src,W,W,W,W), 1,1,1,1), 0); case GL_SRC_COLOR: default: return src; } }
static GLuint get_source( struct i915_fragment_program *p, GLenum src, GLuint unit ) { switch (src) { case GL_TEXTURE: if (p->src_texture == UREG_BAD) { /* TODO: Use D0_CHANNEL_XY where possible. */ GLuint dim = translate_tex_src_bit( p, p->ctx->Texture.Unit[unit]._ReallyEnabled); GLuint sampler = i915_emit_decl(p, REG_TYPE_S, unit, dim); GLuint texcoord = i915_emit_decl(p, REG_TYPE_T, unit, D0_CHANNEL_ALL); GLuint tmp = i915_get_temp( p ); GLuint op = T0_TEXLD; if (p->VB->TexCoordPtr[unit]->size == 4) op = T0_TEXLDP; p->src_texture = i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, sampler, texcoord, op ); } return p->src_texture; /* Crossbar: */ case GL_TEXTURE0: case GL_TEXTURE1: case GL_TEXTURE2: case GL_TEXTURE3: case GL_TEXTURE4: case GL_TEXTURE5: case GL_TEXTURE6: case GL_TEXTURE7: { return UREG_BAD; } case GL_CONSTANT: return i915_emit_const4fv( p, p->ctx->Texture.Unit[unit].EnvColor ); case GL_PRIMARY_COLOR: return i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL); case GL_PREVIOUS: default: i915_emit_decl(p, GET_UREG_TYPE(p->src_previous), GET_UREG_NR(p->src_previous), D0_CHANNEL_ALL); return p->src_previous; } }
/** * Emit a texture load or texkill instruction. * \param dest the dest i915 register * \param destmask the dest register writemask * \param sampler the i915 sampler register * \param coord the i915 source texcoord operand * \param opcode the instruction opcode */ uint i915_emit_texld( struct i915_fp_compile *p, uint dest, uint destmask, uint sampler, uint coord, uint opcode, uint num_coord ) { const uint k = UREG(GET_UREG_TYPE(coord), GET_UREG_NR(coord)); int temp = -1; uint ignore = 0; /* Eliminate the useless texture coordinates. Otherwise we end up generating * a swizzle for no reason below. */ switch(num_coord) { case 0: /* Ignore x */ ignore |= (0xf << UREG_CHANNEL_X_SHIFT); case 1: /* Ignore y */ ignore |= (0xf << UREG_CHANNEL_Y_SHIFT); case 2: /* Ignore z */ ignore |= (0xf << UREG_CHANNEL_Z_SHIFT); case 3: /* Ignore w */ ignore |= (0xf << UREG_CHANNEL_W_SHIFT); } if ( (coord &~ignore ) != (k & ~ignore) ) { /* texcoord is swizzled or negated. Need to allocate a new temporary * register (a utemp / unpreserved temp) won't do. */ uint tempReg; temp = i915_get_temp(p); /* get temp reg index */ tempReg = UREG(REG_TYPE_R, temp); /* make i915 register */ i915_emit_arith( p, A0_MOV, tempReg, A0_DEST_CHANNEL_ALL, /* dest reg, writemask */ 0, /* saturate */ coord, 0, 0 ); /* src0, src1, src2 */ /* new src texcoord is tempReg */ coord = tempReg; } /* Don't worry about saturate as we only support */ if (destmask != A0_DEST_CHANNEL_ALL) { /* if not writing to XYZW... */ uint tmp = i915_get_utemp(p); i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, sampler, coord, opcode, num_coord ); i915_emit_arith( p, A0_MOV, dest, destmask, 0, tmp, 0, 0 ); /* XXX release utemp here? */ } else { assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); assert(dest == UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest))); /* Output register being oC or oD defines a phase boundary */ if (GET_UREG_TYPE(dest) == REG_TYPE_OC || GET_UREG_TYPE(dest) == REG_TYPE_OD) p->nr_tex_indirect++; /* Reading from an r# register whose contents depend on output of the * current phase defines a phase boundary. */ if (GET_UREG_TYPE(coord) == REG_TYPE_R && p->register_phases[GET_UREG_NR(coord)] == p->nr_tex_indirect) p->nr_tex_indirect++; if (p->csr< p->program + I915_PROGRAM_SIZE) { *(p->csr++) = (opcode | T0_DEST( dest ) | T0_SAMPLER( sampler )); *(p->csr++) = T1_ADDRESS_REG( coord ); *(p->csr++) = T2_MBZ; } else i915_program_error(p, "Out of instructions"); if (GET_UREG_TYPE(dest) == REG_TYPE_R) p->register_phases[GET_UREG_NR(dest)] = p->nr_tex_indirect; p->nr_tex_insn++; } if (temp >= 0) i915_release_temp(p, temp); return dest; }
static GLuint emit_combine( struct i915_fragment_program *p, GLuint dest, GLuint mask, GLuint saturate, GLuint unit, GLenum mode, const GLenum *source, const GLenum *operand) { int tmp, src[3], nr = nr_args(mode); int i; for (i = 0; i < nr; i++) src[i] = emit_combine_source( p, mask, unit, source[i], operand[i] ); switch (mode) { case GL_REPLACE: if (mask == A0_DEST_CHANNEL_ALL && !saturate) return src[0]; else return i915_emit_arith( p, A0_MOV, dest, mask, saturate, src[0], 0, 0 ); case GL_MODULATE: return i915_emit_arith( p, A0_MUL, dest, mask, saturate, src[0], src[1], 0 ); case GL_ADD: return i915_emit_arith( p, A0_ADD, dest, mask, saturate, src[0], src[1], 0 ); case GL_ADD_SIGNED: /* tmp = arg0 + arg1 * result = tmp + -.5 */ tmp = i915_emit_const1f(p, .5); tmp = negate(swizzle(tmp,X,X,X,X),1,1,1,1); i915_emit_arith( p, A0_ADD, dest, mask, 0, src[0], src[1], 0 ); i915_emit_arith( p, A0_ADD, dest, mask, saturate, dest, tmp, 0 ); return dest; case GL_INTERPOLATE: /* TWO INSTRUCTIONS */ /* Arg0 * (Arg2) + Arg1 * (1-Arg2) * * Arg0*Arg2 + Arg1 - Arg1Arg2 * * tmp = Arg0*Arg2 + Arg1, * result = (-Arg1)Arg2 + tmp */ tmp = i915_get_temp( p ); i915_emit_arith( p, A0_MAD, tmp, mask, 0, src[0], src[2], src[1] ); i915_emit_arith( p, A0_MAD, dest, mask, saturate, negate(src[1], 1,1,1,1), src[2], tmp ); return dest; case GL_SUBTRACT: /* negate src[1] */ return i915_emit_arith( p, A0_ADD, dest, mask, saturate, src[0], negate(src[1],1,1,1,1), 0 ); case GL_DOT3_RGBA: case GL_DOT3_RGBA_EXT: case GL_DOT3_RGB_EXT: case GL_DOT3_RGB: { GLuint tmp0 = i915_get_temp( p ); GLuint tmp1 = i915_get_temp( p ); GLuint neg1 = negate(swizzle(i915_emit_const1f(p, 1),X,X,X,X), 1,1,1,1); GLuint two = swizzle(i915_emit_const1f(p, 2),X,X,X,X); i915_emit_arith( p, A0_MAD, tmp0, A0_DEST_CHANNEL_ALL, 0, two, src[0], neg1); if (src[0] == src[1]) tmp1 = tmp0; else i915_emit_arith( p, A0_MAD, tmp1, A0_DEST_CHANNEL_ALL, 0, two, src[1], neg1); i915_emit_arith( p, A0_DP3, dest, mask, saturate, tmp0, tmp1, 0); return dest; } default: return src[0]; } }