Merge remote branch 'main/master' into radeon-rewrite
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_pass0.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
6 Permission is hereby granted, free of charge, to any person obtaining
7 a copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sublicense, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial
16 portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **********************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 */
31
32
33 #include "brw_context.h"
34 #include "brw_wm.h"
35 #include "shader/prog_parameter.h"
36
37
38
39 /***********************************************************************
40 */
41
42 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
43 {
44 assert(c->nr_refs < BRW_WM_MAX_REF);
45 return &c->refs[c->nr_refs++];
46 }
47
48 static struct brw_wm_value *get_value( struct brw_wm_compile *c)
49 {
50 assert(c->nr_refs < BRW_WM_MAX_VREG);
51 return &c->vreg[c->nr_vreg++];
52 }
53
54 /** return pointer to a newly allocated instruction */
55 static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
56 {
57 assert(c->nr_insns < BRW_WM_MAX_INSN);
58 return &c->instruction[c->nr_insns++];
59 }
60
61 /***********************************************************************
62 */
63
64 /** Init the "undef" register */
65 static void pass0_init_undef( struct brw_wm_compile *c)
66 {
67 struct brw_wm_ref *ref = &c->undef_ref;
68 ref->value = &c->undef_value;
69 ref->hw_reg = brw_vec8_grf(0, 0);
70 ref->insn = 0;
71 ref->prevuse = NULL;
72 }
73
74 /** Set a FP register to a value */
75 static void pass0_set_fpreg_value( struct brw_wm_compile *c,
76 GLuint file,
77 GLuint idx,
78 GLuint component,
79 struct brw_wm_value *value )
80 {
81 struct brw_wm_ref *ref = get_ref(c);
82 ref->value = value;
83 ref->hw_reg = brw_vec8_grf(0, 0);
84 ref->insn = 0;
85 ref->prevuse = NULL;
86 c->pass0_fp_reg[file][idx][component] = ref;
87 }
88
89 /** Set a FP register to a ref */
90 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
91 GLuint file,
92 GLuint idx,
93 GLuint component,
94 const struct brw_wm_ref *src_ref )
95 {
96 c->pass0_fp_reg[file][idx][component] = src_ref;
97 }
98
99 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
100 const GLfloat *param_ptr )
101 {
102 GLuint i = c->prog_data.nr_params++;
103
104 if (i >= BRW_WM_MAX_PARAM) {
105 _mesa_printf("%s: out of params\n", __FUNCTION__);
106 c->prog_data.error = 1;
107 return NULL;
108 }
109 else {
110 struct brw_wm_ref *ref = get_ref(c);
111
112 c->prog_data.param[i] = param_ptr;
113 c->nr_creg = (i+16)/16;
114
115 /* Push the offsets into hw_reg. These will be added to the
116 * real register numbers once one is allocated in pass2.
117 */
118 ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
119 ref->value = &c->creg[i/16];
120 ref->insn = 0;
121 ref->prevuse = NULL;
122
123 return ref;
124 }
125 }
126
127
128 /** Return a ref to a constant/literal value */
129 static const struct brw_wm_ref *get_const_ref( struct brw_wm_compile *c,
130 const GLfloat *constval )
131 {
132 GLuint i;
133
134 /* Search for an existing const value matching the request:
135 */
136 for (i = 0; i < c->nr_constrefs; i++) {
137 if (c->constref[i].constval == *constval)
138 return c->constref[i].ref;
139 }
140
141 /* Else try to add a new one:
142 */
143 if (c->nr_constrefs < BRW_WM_MAX_CONST) {
144 GLuint i = c->nr_constrefs++;
145
146 /* A constant is a special type of parameter:
147 */
148 c->constref[i].constval = *constval;
149 c->constref[i].ref = get_param_ref(c, constval);
150
151 return c->constref[i].ref;
152 }
153 else {
154 _mesa_printf("%s: out of constrefs\n", __FUNCTION__);
155 c->prog_data.error = 1;
156 return NULL;
157 }
158 }
159
160
161 /* Lookup our internal registers
162 */
163 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
164 GLuint file,
165 GLuint idx,
166 GLuint component )
167 {
168 const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
169
170 if (!ref) {
171 switch (file) {
172 case PROGRAM_INPUT:
173 case PROGRAM_PAYLOAD:
174 case PROGRAM_TEMPORARY:
175 case PROGRAM_OUTPUT:
176 case PROGRAM_VARYING:
177 break;
178
179 case PROGRAM_LOCAL_PARAM:
180 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
181 break;
182
183 case PROGRAM_ENV_PARAM:
184 ref = get_param_ref(c, &c->env_param[idx][component]);
185 break;
186
187 case PROGRAM_STATE_VAR:
188 case PROGRAM_UNIFORM:
189 case PROGRAM_CONSTANT:
190 case PROGRAM_NAMED_PARAM: {
191 struct gl_program_parameter_list *plist = c->fp->program.Base.Parameters;
192
193 /* There's something really hokey about parameters parsed in
194 * arb programs - they all end up in here, whether they be
195 * state values, parameters or constants. This duplicates the
196 * structure above & also seems to subvert the limits set for
197 * each type of constant/param.
198 */
199 switch (plist->Parameters[idx].Type) {
200 case PROGRAM_NAMED_PARAM:
201 case PROGRAM_CONSTANT:
202 /* These are invarient:
203 */
204 ref = get_const_ref(c, &plist->ParameterValues[idx][component]);
205 break;
206
207 case PROGRAM_STATE_VAR:
208 case PROGRAM_UNIFORM:
209 /* These may change from run to run:
210 */
211 ref = get_param_ref(c, &plist->ParameterValues[idx][component] );
212 break;
213
214 default:
215 assert(0);
216 break;
217 }
218 break;
219 }
220
221 default:
222 assert(0);
223 break;
224 }
225
226 c->pass0_fp_reg[file][idx][component] = ref;
227 }
228
229 if (!ref)
230 ref = &c->undef_ref;
231
232 return ref;
233 }
234
235
236
237 /***********************************************************************
238 * Straight translation to internal instruction format
239 */
240
241 static void pass0_set_dst( struct brw_wm_compile *c,
242 struct brw_wm_instruction *out,
243 const struct prog_instruction *inst,
244 GLuint writemask )
245 {
246 const struct prog_dst_register *dst = &inst->DstReg;
247 GLuint i;
248
249 for (i = 0; i < 4; i++) {
250 if (writemask & (1<<i)) {
251 out->dst[i] = get_value(c);
252 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[i]);
253 }
254 }
255
256 out->writemask = writemask;
257 }
258
259
260 static void pass0_set_dst_scalar( struct brw_wm_compile *c,
261 struct brw_wm_instruction *out,
262 const struct prog_instruction *inst,
263 GLuint writemask )
264 {
265 if (writemask) {
266 const struct prog_dst_register *dst = &inst->DstReg;
267 GLuint i;
268
269 /* Compute only the first (X) value:
270 */
271 out->writemask = WRITEMASK_X;
272 out->dst[0] = get_value(c);
273
274 /* Update our tracking register file for all the components in
275 * writemask:
276 */
277 for (i = 0; i < 4; i++) {
278 if (writemask & (1<<i)) {
279 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[0]);
280 }
281 }
282 }
283 else
284 out->writemask = 0;
285 }
286
287
288 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
289 struct prog_src_register src,
290 GLuint i )
291 {
292 GLuint component = GET_SWZ(src.Swizzle,i);
293 const struct brw_wm_ref *src_ref;
294 static const GLfloat const_zero = 0.0;
295 static const GLfloat const_one = 1.0;
296
297 if (component == SWIZZLE_ZERO)
298 src_ref = get_const_ref(c, &const_zero);
299 else if (component == SWIZZLE_ONE)
300 src_ref = get_const_ref(c, &const_one);
301 else
302 src_ref = pass0_get_reg(c, src.File, src.Index, component);
303
304 return src_ref;
305 }
306
307
308 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
309 struct prog_src_register src,
310 GLuint i,
311 struct brw_wm_instruction *insn)
312 {
313 const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
314 struct brw_wm_ref *newref = get_ref(c);
315
316 newref->value = ref->value;
317 newref->hw_reg = ref->hw_reg;
318
319 if (insn) {
320 newref->insn = insn - c->instruction;
321 newref->prevuse = newref->value->lastuse;
322 newref->value->lastuse = newref;
323 }
324
325 if (src.NegateBase & (1<<i))
326 newref->hw_reg.negate ^= 1;
327
328 if (src.Abs) {
329 newref->hw_reg.negate = 0;
330 newref->hw_reg.abs = 1;
331 }
332
333 return newref;
334 }
335
336
337 static void
338 translate_insn(struct brw_wm_compile *c,
339 const struct prog_instruction *inst)
340 {
341 struct brw_wm_instruction *out = get_instruction(c);
342 GLuint writemask = inst->DstReg.WriteMask;
343 GLuint nr_args = brw_wm_nr_args(inst->Opcode);
344 GLuint i, j;
345
346 /* Copy some data out of the instruction
347 */
348 out->opcode = inst->Opcode;
349 out->saturate = (inst->SaturateMode != SATURATE_OFF);
350 out->tex_unit = inst->TexSrcUnit;
351 out->tex_idx = inst->TexSrcTarget;
352 out->tex_shadow = inst->TexShadow;
353 out->eot = inst->Aux & 1;
354 out->target = inst->Aux >> 1;
355
356 /* Args:
357 */
358 for (i = 0; i < nr_args; i++) {
359 for (j = 0; j < 4; j++) {
360 out->src[i][j] = get_new_ref(c, inst->SrcReg[i], j, out);
361 }
362 }
363
364 /* Dst:
365 */
366 if (brw_wm_is_scalar_result(out->opcode))
367 pass0_set_dst_scalar(c, out, inst, writemask);
368 else
369 pass0_set_dst(c, out, inst, writemask);
370 }
371
372
373
374 /***********************************************************************
375 * Optimize moves and swizzles away:
376 */
377 static void pass0_precalc_mov( struct brw_wm_compile *c,
378 const struct prog_instruction *inst )
379 {
380 const struct prog_dst_register *dst = &inst->DstReg;
381 GLuint writemask = inst->DstReg.WriteMask;
382 struct brw_wm_ref *refs[4];
383 GLuint i;
384
385 /* Get the effect of a MOV by manipulating our register table:
386 * First get all refs, then assign refs. This ensures that "in-place"
387 * swizzles such as:
388 * MOV t, t.xxyx
389 * are handled correctly. Previously, these two steps were done in
390 * one loop and the above case was incorrectly handled.
391 */
392 for (i = 0; i < 4; i++) {
393 refs[i] = get_new_ref(c, inst->SrcReg[0], i, NULL);
394 }
395 for (i = 0; i < 4; i++) {
396 if (writemask & (1 << i)) {
397 pass0_set_fpreg_ref( c, dst->File, dst->Index, i, refs[i]);
398 }
399 }
400 }
401
402
403 /* Initialize payload "registers".
404 */
405 static void pass0_init_payload( struct brw_wm_compile *c )
406 {
407 GLuint i;
408
409 for (i = 0; i < 4; i++) {
410 GLuint j = i >= c->key.nr_depth_regs ? 0 : i;
411 pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i,
412 &c->payload.depth[j] );
413 }
414
415 #if 0
416 /* This seems to be an alternative to the INTERP_WPOS stuff I do
417 * elsewhere:
418 */
419 if (c->key.source_depth_reg)
420 pass0_set_fpreg_value(c, PROGRAM_INPUT, FRAG_ATTRIB_WPOS, 2,
421 &c->payload.depth[c->key.source_depth_reg/2]);
422 #endif
423
424 for (i = 0; i < FRAG_ATTRIB_MAX; i++)
425 pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, i, 0,
426 &c->payload.input_interp[i] );
427 }
428
429
430 /***********************************************************************
431 * PASS 0
432 *
433 * Work forwards to give each calculated value a unique number. Where
434 * an instruction produces duplicate values (eg DP3), all are given
435 * the same number.
436 *
437 * Translate away swizzling and eliminate non-saturating moves.
438 */
439 void brw_wm_pass0( struct brw_wm_compile *c )
440 {
441 GLuint insn;
442
443 c->nr_vreg = 0;
444 c->nr_insns = 0;
445
446 pass0_init_undef(c);
447 pass0_init_payload(c);
448
449 for (insn = 0; insn < c->nr_fp_insns; insn++) {
450 const struct prog_instruction *inst = &c->prog_instructions[insn];
451
452 /* Optimize away moves, otherwise emit translated instruction:
453 */
454 switch (inst->Opcode) {
455 case OPCODE_MOV:
456 case OPCODE_SWZ:
457 if (!inst->SaturateMode) {
458 pass0_precalc_mov(c, inst);
459 }
460 else {
461 translate_insn(c, inst);
462 }
463 break;
464 default:
465 translate_insn(c, inst);
466 break;
467 }
468 }
469
470 if (INTEL_DEBUG & DEBUG_WM) {
471 brw_wm_print_program(c, "pass0");
472 }
473 }