Merge branch 'master' of git+ssh://brianp@git.freedesktop.org/git/mesa/mesa
[mesa.git] / src / mesa / drivers / dri / nouveau / nv40_fragprog.c
1 #include "nouveau_shader.h"
2 #include "nv40_shader.h"
3
4 /* branching ops */
5 unsigned int NVFP_TX_BOP_COUNT = 5;
6 struct _op_xlat NVFP_TX_BOP[64];
7
8
9 /*****************************************************************************
10 * Assembly routines
11 * - These extend the NV30 routines, which are almost identical. NV40
12 * just has branching hacked into the instruction set.
13 */
14 static int
15 NV40FPSupportsResultScale(nvsFunc *shader, nvsScale scale)
16 {
17 switch (scale) {
18 case NVS_SCALE_1X:
19 case NVS_SCALE_2X:
20 case NVS_SCALE_4X:
21 case NVS_SCALE_8X:
22 case NVS_SCALE_INV_2X:
23 case NVS_SCALE_INV_4X:
24 case NVS_SCALE_INV_8X:
25 return 1;
26 default:
27 return 0;
28 }
29 }
30
31 static void
32 NV40FPSetResultScale(nvsFunc *shader, nvsScale scale)
33 {
34 shader->inst[2] &= ~NV40_FP_OP_DST_SCALE_MASK;
35 shader->inst[2] |= ((unsigned int)scale << NV40_FP_OP_DST_SCALE_SHIFT);
36 }
37
38 static void
39 NV40FPSetBranchTarget(nvsFunc *shader, int addr)
40 {
41 shader->inst[2] &= ~NV40_FP_OP_IADDR_MASK;
42 shader->inst[2] |= (addr << NV40_FP_OP_IADDR_SHIFT);
43 }
44
45 static void
46 NV40FPSetBranchElse(nvsFunc *shader, int addr)
47 {
48 shader->inst[2] &= ~NV40_FP_OP_ELSE_ID_MASK;
49 shader->inst[2] |= (addr << NV40_FP_OP_ELSE_ID_SHIFT);
50 }
51
52 static void
53 NV40FPSetBranchEnd(nvsFunc *shader, int addr)
54 {
55 shader->inst[3] &= ~NV40_FP_OP_END_ID_MASK;
56 shader->inst[3] |= (addr << NV40_FP_OP_END_ID_SHIFT);
57 }
58
59 static void
60 NV40FPSetLoopParams(nvsFunc *shader, int count, int initial, int increment)
61 {
62 shader->inst[2] &= ~(NV40_FP_OP_LOOP_COUNT_MASK |
63 NV40_FP_OP_LOOP_INDEX_MASK |
64 NV40_FP_OP_LOOP_INCR_MASK);
65 shader->inst[2] |= ((count << NV40_FP_OP_LOOP_COUNT_SHIFT) |
66 (initial << NV40_FP_OP_LOOP_INDEX_SHIFT) |
67 (increment << NV40_FP_OP_LOOP_INCR_SHIFT));
68 }
69
70 /*****************************************************************************
71 * Disassembly routines
72 */
73 static struct _op_xlat *
74 NV40FPGetOPTXRec(nvsFunc * shader, int merged)
75 {
76 struct _op_xlat *opr;
77 int op;
78
79 op = shader->GetOpcodeHW(shader, 0);
80 if (shader->inst[2] & NV40_FP_OP_OPCODE_IS_BRANCH) {
81 opr = NVFP_TX_BOP;
82 op &= ~NV40_FP_OP_OPCODE_IS_BRANCH;
83 if (op > NVFP_TX_BOP_COUNT)
84 return NULL;
85 }
86 else {
87 opr = NVFP_TX_AOP;
88 if (op > NVFP_TX_AOP_COUNT)
89 return NULL;
90 }
91
92 if (opr[op].SOP == NVS_OP_UNKNOWN)
93 return NULL;
94 return &opr[op];
95 }
96
97 static int
98 NV40FPGetSourceID(nvsFunc * shader, int merged, int pos)
99 {
100 switch (shader->GetSourceFile(shader, merged, pos)) {
101 case NVS_FILE_ATTRIB:
102 switch ((shader->inst[0] & NV40_FP_OP_INPUT_SRC_MASK)
103 >> NV40_FP_OP_INPUT_SRC_SHIFT) {
104 case NV40_FP_OP_INPUT_SRC_POSITION: return NVS_FR_POSITION;
105 case NV40_FP_OP_INPUT_SRC_COL0 : return NVS_FR_COL0;
106 case NV40_FP_OP_INPUT_SRC_COL1 : return NVS_FR_COL1;
107 case NV40_FP_OP_INPUT_SRC_FOGC : return NVS_FR_FOGCOORD;
108 case NV40_FP_OP_INPUT_SRC_TC(0) : return NVS_FR_TEXCOORD0;
109 case NV40_FP_OP_INPUT_SRC_TC(1) : return NVS_FR_TEXCOORD1;
110 case NV40_FP_OP_INPUT_SRC_TC(2) : return NVS_FR_TEXCOORD2;
111 case NV40_FP_OP_INPUT_SRC_TC(3) : return NVS_FR_TEXCOORD3;
112 case NV40_FP_OP_INPUT_SRC_TC(4) : return NVS_FR_TEXCOORD4;
113 case NV40_FP_OP_INPUT_SRC_TC(5) : return NVS_FR_TEXCOORD5;
114 case NV40_FP_OP_INPUT_SRC_TC(6) : return NVS_FR_TEXCOORD6;
115 case NV40_FP_OP_INPUT_SRC_TC(7) : return NVS_FR_TEXCOORD7;
116 case NV40_FP_OP_INPUT_SRC_FACING : return NVS_FR_FACING;
117 default:
118 return -1;
119 }
120 break;
121 case NVS_FILE_TEMP:
122 {
123 unsigned int src;
124
125 src = shader->GetSourceHW(shader, merged, pos);
126 return ((src & NV40_FP_REG_SRC_MASK) >> NV40_FP_REG_SRC_SHIFT);
127 }
128 case NVS_FILE_CONST: /* inlined into fragprog */
129 default:
130 return -1;
131 }
132 }
133
134 static int
135 NV40FPGetBranch(nvsFunc * shader)
136 {
137 return ((shader->inst[2] & NV40_FP_OP_IADDR_MASK)
138 >> NV40_FP_OP_IADDR_SHIFT);;
139 }
140
141 static int
142 NV40FPGetBranchElse(nvsFunc * shader)
143 {
144 return ((shader->inst[2] & NV40_FP_OP_ELSE_ID_MASK)
145 >> NV40_FP_OP_ELSE_ID_SHIFT);
146 }
147
148 static int
149 NV40FPGetBranchEnd(nvsFunc * shader)
150 {
151 return ((shader->inst[3] & NV40_FP_OP_END_ID_MASK)
152 >> NV40_FP_OP_END_ID_SHIFT);
153 }
154
155 static int
156 NV40FPGetLoopCount(nvsFunc * shader)
157 {
158 return ((shader->inst[2] & NV40_FP_OP_LOOP_COUNT_MASK)
159 >> NV40_FP_OP_LOOP_COUNT_SHIFT);
160 }
161
162 static int
163 NV40FPGetLoopInitial(nvsFunc * shader)
164 {
165 return ((shader->inst[2] & NV40_FP_OP_LOOP_INDEX_MASK)
166 >> NV40_FP_OP_LOOP_INDEX_SHIFT);
167 }
168
169 static int
170 NV40FPGetLoopIncrement(nvsFunc * shader)
171 {
172 return ((shader->inst[2] & NV40_FP_OP_LOOP_INCR_MASK)
173 >> NV40_FP_OP_LOOP_INCR_SHIFT);
174 }
175
176 void
177 NV40FPInitShaderFuncs(nvsFunc * shader)
178 {
179 /* Inherit NV30 FP code, it's mostly the same */
180 NV30FPInitShaderFuncs(shader);
181
182 /* Kill off opcodes seen on NV30, but not seen on NV40 - need to find
183 * out if these actually work or not.
184 *
185 * update: either LIT/RSQ don't work on nv40, or I generate bad code for
186 * them. haven't tested the others yet
187 */
188 MOD_OPCODE(NVFP_TX_AOP, 0x1B, NVS_OP_UNKNOWN, -1, -1, -1); /* NV30 RSQ */
189 MOD_OPCODE(NVFP_TX_AOP, 0x1E, NVS_OP_UNKNOWN, -1, -1, -1); /* NV30 LIT */
190 MOD_OPCODE(NVFP_TX_AOP, 0x1F, NVS_OP_UNKNOWN, -1, -1, -1); /* NV30 LRP */
191 MOD_OPCODE(NVFP_TX_AOP, 0x26, NVS_OP_UNKNOWN, -1, -1, -1); /* NV30 POW */
192 MOD_OPCODE(NVFP_TX_AOP, 0x36, NVS_OP_UNKNOWN, -1, -1, -1); /* NV30 RFL */
193
194 /* Extra opcodes supported on NV40 */
195 MOD_OPCODE(NVFP_TX_AOP, NV40_FP_OP_OPCODE_DIV , NVS_OP_DIV , 0, 1, -1);
196 MOD_OPCODE(NVFP_TX_AOP, NV40_FP_OP_OPCODE_DP2A , NVS_OP_DP2A, 0, 1, 2);
197 MOD_OPCODE(NVFP_TX_AOP, NV40_FP_OP_OPCODE_TXL , NVS_OP_TXL , 0, -1, -1);
198
199 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_BRK , NVS_OP_BRK , -1, -1, -1);
200 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_CAL , NVS_OP_CAL , -1, -1, -1);
201 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_IF , NVS_OP_IF , -1, -1, -1);
202 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_LOOP, NVS_OP_LOOP, -1, -1, -1);
203 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_REP , NVS_OP_REP , -1, -1, -1);
204 MOD_OPCODE(NVFP_TX_BOP, NV40_FP_OP_BRA_OPCODE_RET , NVS_OP_RET , -1, -1, -1);
205
206 shader->SupportsResultScale = NV40FPSupportsResultScale;
207 shader->SetResultScale = NV40FPSetResultScale;
208
209 /* fragment.facing */
210 shader->GetSourceID = NV40FPGetSourceID;
211
212 /* branching */
213 shader->GetOPTXRec = NV40FPGetOPTXRec;
214 shader->GetBranch = NV40FPGetBranch;
215 shader->GetBranchElse = NV40FPGetBranchElse;
216 shader->GetBranchEnd = NV40FPGetBranchEnd;
217 shader->GetLoopCount = NV40FPGetLoopCount;
218 shader->GetLoopInitial = NV40FPGetLoopInitial;
219 shader->GetLoopIncrement = NV40FPGetLoopIncrement;
220 shader->SetBranchTarget = NV40FPSetBranchTarget;
221 shader->SetBranchElse = NV40FPSetBranchElse;
222 shader->SetBranchEnd = NV40FPSetBranchEnd;
223 shader->SetLoopParams = NV40FPSetLoopParams;
224 }