summaryrefslogtreecommitdiff
path: root/src/mesa/pipe/i915simple/i915_fpc_translate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/pipe/i915simple/i915_fpc_translate.c')
-rw-r--r--src/mesa/pipe/i915simple/i915_fpc_translate.c297
1 files changed, 226 insertions, 71 deletions
diff --git a/src/mesa/pipe/i915simple/i915_fpc_translate.c b/src/mesa/pipe/i915simple/i915_fpc_translate.c
index db6b92ad7f..cf6a142075 100644
--- a/src/mesa/pipe/i915simple/i915_fpc_translate.c
+++ b/src/mesa/pipe/i915simple/i915_fpc_translate.c
@@ -32,6 +32,34 @@
#include "pipe/tgsi/core/tgsi_token.h"
#include "pipe/tgsi/core/tgsi_parse.h"
+/**
+ * Simple pass-through fragment shader to use when we don't have
+ * a real shader (or it fails to compile for some reason).
+ */
+static unsigned passthrough[] =
+{
+ _3DSTATE_PIXEL_SHADER_PROGRAM | ((2*3)-1),
+
+ /* declare input color:
+ */
+ (D0_DCL |
+ (REG_TYPE_T << D0_TYPE_SHIFT) |
+ (T_DIFFUSE << D0_NR_SHIFT) |
+ D0_CHANNEL_ALL),
+ 0,
+ 0,
+
+ /* move to output color:
+ */
+ (A0_MOV |
+ (REG_TYPE_OC << A0_DEST_TYPE_SHIFT) |
+ A0_DEST_CHANNEL_ALL |
+ (REG_TYPE_T << A0_SRC0_TYPE_SHIFT) |
+ (T_DIFFUSE << A0_SRC0_NR_SHIFT)),
+ 0x01230000, /* .xyzw */
+ 0
+};
+
/* 1, -1/3!, 1/5!, -1/7! */
static const float sin_constants[4] = { 1.0,
@@ -48,6 +76,30 @@ static const float cos_constants[4] = { 1.0,
};
+
+static void
+i915_use_passthrough_shader(struct i915_context *i915)
+{
+ fprintf(stderr, "**** Using i915 pass-through fragment shader\n");
+
+ i915->current.program = (uint *) malloc(sizeof(passthrough));
+ memcpy(i915->current.program, passthrough, sizeof(passthrough));
+ i915->current.program_len = Elements(passthrough);
+
+ i915->current.constants = NULL;
+ i915->current.num_constants = 0;
+}
+
+
+void
+i915_program_error(struct i915_fp_compile *p, const char *msg)
+{
+ fprintf(stderr, "i915_program_error: %s\n", msg);
+ p->error = 1;
+}
+
+
+
/**
* Construct a ureg for the given source register. Will emit
* constants, apply swizzling and negation as needed.
@@ -59,7 +111,7 @@ src_vector(struct i915_fp_compile *p,
const uint index = source->SrcRegister.Index;
uint src;
- switch (source->SrcRegisterInd.File) {
+ switch (source->SrcRegister.File) {
case TGSI_FILE_TEMPORARY:
if (source->SrcRegister.Index >= I915_MAX_TEMPORARY) {
i915_program_error(p, "Exceeded max temporary reg");
@@ -79,7 +131,7 @@ src_vector(struct i915_fp_compile *p,
*/
switch (index) {
case FRAG_ATTRIB_WPOS:
- src = i915_emit_decl(p, REG_TYPE_T, p->fp->wpos_tex, D0_CHANNEL_ALL);
+ src = i915_emit_decl(p, REG_TYPE_T, p->wpos_tex, D0_CHANNEL_ALL);
break;
case FRAG_ATTRIB_COL0:
src = i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL);
@@ -111,27 +163,9 @@ src_vector(struct i915_fp_compile *p,
}
break;
- /* Various parameters and env values. All emitted to
- * hardware as program constants.
- */
-#if 0
- case PROGRAM_LOCAL_PARAM:
- src = i915_emit_param4fv(p, program->Base.LocalParams[index]);
- break;
- case PROGRAM_ENV_PARAM:
- src = i915_emit_param4fv(p, p->env_param[index]);
- break;
- case PROGRAM_CONSTANT:
- case PROGRAM_STATE_VAR:
- case PROGRAM_NAMED_PARAM:
- src = i915_emit_param4fv(
- p, program->Base.Parameters->ParameterValues[index]);
- break;
-#else
case TGSI_FILE_CONSTANT:
src = UREG(REG_TYPE_CONST, index);
break;
-#endif
default:
i915_program_error(p, "Bad source->File");
@@ -151,26 +185,14 @@ src_vector(struct i915_fp_compile *p,
assert(!source->SrcRegisterExtSwz.NegateW);
assert(!source->SrcRegisterExtMod.Absolute);
assert(!source->SrcRegisterExtMod.Negate);
-#if 0
- if (source->SrcRegister.Negate)
- negate all
-
- if (extended source swiz per component)
- src = negate(src,
- source->SrcRegisterExtSwz.NegateX,
- source->SrcRegisterExtSwz.NegateY,
- source->SrcRegisterExtSwz.NegateZ,
- source->SrcRegisterExtSwz.NegateW);
- if (mod.abs)
- absolute value
-
- if (mod.negate)
- another negate;
-#endif
+
return src;
}
+/**
+ * Construct a ureg for a destination register.
+ */
static uint
get_result_vector(struct i915_fp_compile *p,
const struct tgsi_full_dst_register *dest)
@@ -178,9 +200,9 @@ get_result_vector(struct i915_fp_compile *p,
switch (dest->DstRegister.File) {
case TGSI_FILE_OUTPUT:
switch (dest->DstRegister.Index) {
- case FRAG_RESULT_COLR:
+ case 1: /*COLOR*/ /*FRAG_RESULT_COLR:*/
return UREG(REG_TYPE_OC, 0);
- case FRAG_RESULT_DEPR:
+ case 0: /*DEPTH*/ /*FRAG_RESULT_DEPR:*/
return UREG(REG_TYPE_OD, 0);
default:
i915_program_error(p, "Bad inst->DstReg.Index");
@@ -296,12 +318,15 @@ emit_simple_arith(struct i915_fp_compile *p,
}
-#define EMIT_1ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 1)
-#define EMIT_2ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 2)
-#define EMIT_3ARG_ARITH( OP ) emit_simple_arith(p, inst, OP, 3)
-
-
-
+/*
+ * Translate TGSI instruction to i915 instruction.
+ *
+ * Possible concerns:
+ *
+ * SIN, COS -- could use another taylor step?
+ * LIT -- results seem a little different to sw mesa
+ * LOG -- different to mesa on negative numbers, but this is conformant.
+ */
static void
i915_translate_instruction(struct i915_fp_compile *p,
const struct tgsi_full_instruction *inst)
@@ -321,7 +346,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_ADD:
- EMIT_2ARG_ARITH(A0_ADD);
+ emit_simple_arith(p, inst, A0_ADD, 2);
break;
case TGSI_OPCODE_CMP:
@@ -385,11 +410,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_DP3:
- EMIT_2ARG_ARITH(A0_DP3);
+ emit_simple_arith(p, inst, A0_DP3, 2);
break;
case TGSI_OPCODE_DP4:
- EMIT_2ARG_ARITH(A0_DP4);
+ emit_simple_arith(p, inst, A0_DP4, 2);
break;
case TGSI_OPCODE_DPH:
@@ -431,11 +456,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_FLR:
- EMIT_1ARG_ARITH(A0_FLR);
+ emit_simple_arith(p, inst, A0_FLR, 1);
break;
case TGSI_OPCODE_FRC:
- EMIT_1ARG_ARITH(A0_FRC);
+ emit_simple_arith(p, inst, A0_FRC, 1);
break;
case TGSI_OPCODE_KIL:
@@ -512,11 +537,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_MAD:
- EMIT_3ARG_ARITH(A0_MAD);
+ emit_simple_arith(p, inst, A0_MAD, 3);
break;
case TGSI_OPCODE_MAX:
- EMIT_2ARG_ARITH(A0_MAX);
+ emit_simple_arith(p, inst, A0_MAX, 2);
break;
case TGSI_OPCODE_MIN:
@@ -539,11 +564,11 @@ i915_translate_instruction(struct i915_fp_compile *p,
case TGSI_OPCODE_MOV:
/* aka TGSI_OPCODE_SWZ */
- EMIT_1ARG_ARITH(A0_MOV);
+ emit_simple_arith(p, inst, A0_MOV, 1);
break;
case TGSI_OPCODE_MUL:
- EMIT_2ARG_ARITH(A0_MUL);
+ emit_simple_arith(p, inst, A0_MUL, 2);
break;
case TGSI_OPCODE_POW:
@@ -652,7 +677,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_SGE:
- EMIT_2ARG_ARITH(A0_SGE);
+ emit_simple_arith(p, inst, A0_SGE, 2);
break;
case TGSI_OPCODE_SIN:
@@ -706,7 +731,7 @@ i915_translate_instruction(struct i915_fp_compile *p,
break;
case TGSI_OPCODE_SLT:
- EMIT_2ARG_ARITH(A0_SLT);
+ emit_simple_arith(p, inst, A0_SLT, 2);
break;
case TGSI_OPCODE_SUB:
@@ -769,20 +794,12 @@ i915_translate_instruction(struct i915_fp_compile *p,
/**
* Translate TGSI fragment shader into i915 hardware instructions.
- *
- * Possible concerns:
- *
- * SIN, COS -- could use another taylor step?
- * LIT -- results seem a little different to sw mesa
- * LOG -- different to mesa on negative numbers, but this is conformant.
- *
- * Parse failures -- Mesa doesn't currently give a good indication
- * internally whether a particular program string parsed or not. This
- * can lead to confusion -- hopefully we cope with it ok now.
+ * \param p the translation state
+ * \param tokens the TGSI token array
*/
-void
-i915_translate_program(struct i915_fp_compile *p,
- const struct tgsi_token *tokens)
+static void
+i915_translate_instructions(struct i915_fp_compile *p,
+ const struct tgsi_token *tokens)
{
struct tgsi_parse_context parse;
@@ -794,10 +811,11 @@ i915_translate_program(struct i915_fp_compile *p,
switch( parse.FullToken.Token.Type ) {
case TGSI_TOKEN_TYPE_DECLARATION:
- assert(0);
+ /* XXX no-op? */
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
+ /* XXX no-op? */
assert(0);
break;
@@ -815,13 +833,139 @@ i915_translate_program(struct i915_fp_compile *p,
}
+static struct i915_fp_compile *
+i915_init_compile(struct i915_context *i915,
+ struct pipe_shader_state *fs)
+{
+ struct i915_fp_compile *p = CALLOC_STRUCT(i915_fp_compile);
+
+ p->shader = &i915->fs;
+
+ /* a bit of a hack, need to improve constant buffer infrastructure */
+ if (i915->fs.constants)
+ p->constants = i915->fs.constants;
+ else
+ p->constants = &i915->temp_constants;
+
+ p->nr_tex_indirect = 1; /* correct? */
+ p->nr_tex_insn = 0;
+ p->nr_alu_insn = 0;
+ p->nr_decl_insn = 0;
+
+ memset(p->constant_flags, 0, sizeof(p->constant_flags));
+
+ p->csr = p->program;
+ p->decl = p->declarations;
+ p->decl_s = 0;
+ p->decl_t = 0;
+ p->temp_flag = 0xffff000;
+ p->utemp_flag = ~0x7;
+
+ p->wpos_tex = -1;
+
+ /* initialize the first program word */
+ *(p->decl++) = _3DSTATE_PIXEL_SHADER_PROGRAM;
+
+ return p;
+}
+
+/* Copy compile results to the fragment program struct and destroy the
+ * compilation context.
+ */
+static void
+i915_fini_compile(struct i915_context *i915, struct i915_fp_compile *p)
+{
+ uint program_size = p->csr - p->program;
+ uint decl_size = p->decl - p->declarations;
+
+ if (p->nr_tex_indirect > I915_MAX_TEX_INDIRECT)
+ i915_program_error(p, "Exceeded max nr indirect texture lookups");
+
+ if (p->nr_tex_insn > I915_MAX_TEX_INSN)
+ i915_program_error(p, "Exceeded max TEX instructions");
+
+ if (p->nr_alu_insn > I915_MAX_ALU_INSN)
+ i915_program_error(p, "Exceeded max ALU instructions");
+
+ if (p->nr_decl_insn > I915_MAX_DECL_INSN)
+ i915_program_error(p, "Exceeded max DECL instructions");
+
+ if (p->error) {
+ p->NumNativeInstructions = 0;
+ p->NumNativeAluInstructions = 0;
+ p->NumNativeTexInstructions = 0;
+ p->NumNativeTexIndirections = 0;
+
+ i915_use_passthrough_shader(i915);
+ }
+ else {
+ p->NumNativeInstructions = (p->nr_alu_insn +
+ p->nr_tex_insn +
+ p->nr_decl_insn);
+ p->NumNativeAluInstructions = p->nr_alu_insn;
+ p->NumNativeTexInstructions = p->nr_tex_insn;
+ p->NumNativeTexIndirections = p->nr_tex_indirect;
+
+ /* patch in the program length */
+ p->declarations[0] |= program_size + decl_size - 2;
+
+ /* Copy compilation results to fragment program struct:
+ */
+ i915->current.program
+ = (uint *) malloc((program_size + decl_size) * sizeof(uint));
+ i915->current.program_len = program_size + decl_size;
+
+ memcpy(i915->current.program,
+ p->declarations,
+ decl_size * sizeof(uint));
+ memcpy(i915->current.program + decl_size,
+ p->program,
+ program_size * sizeof(uint));
-/* Rather than trying to intercept and jiggle depth writes during
+ i915->current.constants = (uint *) p->constants->constant;
+ i915->current.num_constants = p->constants->nr_constants;
+ }
+
+ /* Release the compilation struct:
+ */
+ free(p);
+}
+
+
+/**
+ * Find an unused texture coordinate slot to use for fragment WPOS.
+ * Update p->fp->wpos_tex with the result (-1 if no used texcoord slot is found).
+ */
+static void
+i915_find_wpos_space(struct i915_fp_compile *p)
+{
+ const uint inputs = p->shader->inputs_read;
+ uint i;
+
+ p->wpos_tex = -1;
+
+ if (inputs & FRAG_BIT_WPOS) {
+ for (i = 0; i < I915_TEX_UNITS; i++) {
+ if ((inputs & (FRAG_BIT_TEX0 << i)) == 0) {
+ p->wpos_tex = i;
+ return;
+ }
+ }
+
+ i915_program_error(p, "No free texcoord for wpos value");
+ }
+}
+
+
+
+
+/**
+ * Rather than trying to intercept and jiggle depth writes during
* emit, just move the value into its correct position at the end of
* the program:
*/
-void
+static void
i915_fixup_depth_write(struct i915_fp_compile *p)
{
if (p->shader->outputs_written & (1<<FRAG_RESULT_DEPR)) {
@@ -835,5 +979,16 @@ i915_fixup_depth_write(struct i915_fp_compile *p)
}
+void
+i915_translate_fragment_program( struct i915_context *i915 )
+{
+ struct i915_fp_compile *p = i915_init_compile(i915, &i915->fs);
+ const struct tgsi_token *tokens = i915->fs.tokens;
+ i915_find_wpos_space(p);
+ i915_translate_instructions(p, tokens);
+ i915_fixup_depth_write(p);
+
+ i915_fini_compile(i915, p);
+}