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 "program/prog_parameter.h"
36
37
38
39/***********************************************************************
40 */
41
42static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
43{
44   assert(c->nr_refs < BRW_WM_MAX_REF);
45   memset(&c->refs[c->nr_refs], 0, sizeof(*c->refs));
46   return &c->refs[c->nr_refs++];
47}
48
49static struct brw_wm_value *get_value( struct brw_wm_compile *c)
50{
51   assert(c->nr_refs < BRW_WM_MAX_VREG);
52   memset(&c->vreg[c->nr_vreg], 0, sizeof(*c->vreg));
53   return &c->vreg[c->nr_vreg++];
54}
55
56/** return pointer to a newly allocated instruction */
57static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
58{
59   assert(c->nr_insns < BRW_WM_MAX_INSN);
60   memset(&c->instruction[c->nr_insns], 0, sizeof(*c->instruction));
61   return &c->instruction[c->nr_insns++];
62}
63
64/***********************************************************************
65 */
66
67/** Init the "undef" register */
68static void pass0_init_undef( struct brw_wm_compile *c)
69{
70   struct brw_wm_ref *ref = &c->undef_ref;
71   ref->value = &c->undef_value;
72   ref->hw_reg = brw_vec8_grf(0, 0);
73   ref->insn = 0;
74   ref->prevuse = NULL;
75}
76
77/** Set a FP register to a value */
78static void pass0_set_fpreg_value( struct brw_wm_compile *c,
79				   GLuint file,
80				   GLuint idx,
81				   GLuint component,
82				   struct brw_wm_value *value )
83{
84   struct brw_wm_ref *ref = get_ref(c);
85   ref->value = value;
86   ref->hw_reg = brw_vec8_grf(0, 0);
87   ref->insn = 0;
88   ref->prevuse = NULL;
89   c->pass0_fp_reg[file][idx][component] = ref;
90}
91
92/** Set a FP register to a ref */
93static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
94				 GLuint file,
95				 GLuint idx,
96				 GLuint component,
97				 const struct brw_wm_ref *src_ref )
98{
99   c->pass0_fp_reg[file][idx][component] = src_ref;
100}
101
102static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
103					       const GLfloat *param_ptr )
104{
105   GLuint i = c->prog_data.nr_params++;
106
107   if (i >= BRW_WM_MAX_PARAM) {
108      printf("%s: out of params\n", __FUNCTION__);
109      c->prog_data.error = 1;
110      return NULL;
111   }
112   else {
113      struct brw_wm_ref *ref = get_ref(c);
114
115      c->prog_data.param[i] = param_ptr;
116      c->nr_creg = (i+16)/16;
117
118      /* Push the offsets into hw_reg.  These will be added to the
119       * real register numbers once one is allocated in pass2.
120       */
121      ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
122      ref->value = &c->creg[i/16];
123      ref->insn = 0;
124      ref->prevuse = NULL;
125
126      return ref;
127   }
128}
129
130
131/** Return a ref to a constant/literal value */
132static const struct brw_wm_ref *get_const_ref( struct brw_wm_compile *c,
133					       const GLfloat *constval )
134{
135   GLuint i;
136
137   /* Search for an existing const value matching the request:
138    */
139   for (i = 0; i < c->nr_constrefs; i++) {
140      if (c->constref[i].constval == *constval)
141	 return c->constref[i].ref;
142   }
143
144   /* Else try to add a new one:
145    */
146   if (c->nr_constrefs < BRW_WM_MAX_CONST) {
147      GLuint i = c->nr_constrefs++;
148
149      /* A constant is a special type of parameter:
150       */
151      c->constref[i].constval = *constval;
152      c->constref[i].ref = get_param_ref(c, constval);
153
154      return c->constref[i].ref;
155   }
156   else {
157      printf("%s: out of constrefs\n", __FUNCTION__);
158      c->prog_data.error = 1;
159      return NULL;
160   }
161}
162
163
164/* Lookup our internal registers
165 */
166static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
167					       GLuint file,
168					       GLuint idx,
169					       GLuint component )
170{
171   const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
172
173   if (!ref) {
174      switch (file) {
175      case PROGRAM_INPUT:
176      case PROGRAM_PAYLOAD:
177      case PROGRAM_TEMPORARY:
178      case PROGRAM_OUTPUT:
179      case PROGRAM_VARYING:
180	 break;
181
182      case PROGRAM_LOCAL_PARAM:
183	 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
184	 break;
185
186      case PROGRAM_ENV_PARAM:
187	 ref = get_param_ref(c, &c->env_param[idx][component]);
188	 break;
189
190      case PROGRAM_STATE_VAR:
191      case PROGRAM_UNIFORM:
192      case PROGRAM_CONSTANT:
193      case PROGRAM_NAMED_PARAM: {
194	 struct gl_program_parameter_list *plist = c->fp->program.Base.Parameters;
195
196	 /* There's something really hokey about parameters parsed in
197	  * arb programs - they all end up in here, whether they be
198	  * state values, parameters or constants.  This duplicates the
199	  * structure above & also seems to subvert the limits set for
200	  * each type of constant/param.
201	  */
202	 switch (plist->Parameters[idx].Type) {
203	 case PROGRAM_NAMED_PARAM:
204	 case PROGRAM_CONSTANT:
205	    /* These are invariant:
206	     */
207	    ref = get_const_ref(c, &plist->ParameterValues[idx][component].f);
208	    break;
209
210	 case PROGRAM_STATE_VAR:
211	 case PROGRAM_UNIFORM:
212	    /* These may change from run to run:
213	     */
214	    ref = get_param_ref(c, &plist->ParameterValues[idx][component].f );
215	    break;
216
217	 default:
218	    assert(0);
219	    break;
220	 }
221	 break;
222      }
223
224      default:
225	 assert(0);
226	 break;
227      }
228
229      c->pass0_fp_reg[file][idx][component] = ref;
230   }
231
232   if (!ref)
233      ref = &c->undef_ref;
234
235   return ref;
236}
237
238
239
240/***********************************************************************
241 * Straight translation to internal instruction format
242 */
243
244static void pass0_set_dst( struct brw_wm_compile *c,
245			   struct brw_wm_instruction *out,
246			   const struct prog_instruction *inst,
247			   GLuint writemask )
248{
249   const struct prog_dst_register *dst = &inst->DstReg;
250   GLuint i;
251
252   for (i = 0; i < 4; i++) {
253      if (writemask & (1<<i)) {
254	 out->dst[i] = get_value(c);
255	 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[i]);
256      }
257   }
258
259   out->writemask = writemask;
260}
261
262
263static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
264						    struct prog_src_register src,
265						    GLuint i )
266{
267   GLuint component = GET_SWZ(src.Swizzle,i);
268   const struct brw_wm_ref *src_ref;
269   static const GLfloat const_zero = 0.0;
270   static const GLfloat const_one = 1.0;
271
272   if (component == SWIZZLE_ZERO)
273      src_ref = get_const_ref(c, &const_zero);
274   else if (component == SWIZZLE_ONE)
275      src_ref = get_const_ref(c, &const_one);
276   else
277      src_ref = pass0_get_reg(c, src.File, src.Index, component);
278
279   return src_ref;
280}
281
282
283static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
284				       struct prog_src_register src,
285				       GLuint i,
286				       struct brw_wm_instruction *insn)
287{
288   const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
289   struct brw_wm_ref *newref = get_ref(c);
290
291   newref->value = ref->value;
292   newref->hw_reg = ref->hw_reg;
293
294   if (insn) {
295      newref->insn = insn - c->instruction;
296      newref->prevuse = newref->value->lastuse;
297      newref->value->lastuse = newref;
298   }
299
300   if (src.Negate & (1 << i))
301      newref->hw_reg.negate ^= 1;
302
303   if (src.Abs) {
304      newref->hw_reg.negate = 0;
305      newref->hw_reg.abs = 1;
306   }
307
308   return newref;
309}
310
311
312static void
313translate_insn(struct brw_wm_compile *c,
314               const struct prog_instruction *inst)
315{
316   struct brw_wm_instruction *out = get_instruction(c);
317   GLuint writemask = inst->DstReg.WriteMask;
318   GLuint nr_args = brw_wm_nr_args(inst->Opcode);
319   GLuint i, j;
320
321   /* Copy some data out of the instruction
322    */
323   out->opcode = inst->Opcode;
324   out->saturate = (inst->SaturateMode != SATURATE_OFF);
325   out->tex_unit = inst->TexSrcUnit;
326   out->tex_idx = inst->TexSrcTarget;
327   out->tex_shadow = inst->TexShadow;
328   out->eot = inst->Aux & INST_AUX_EOT;
329   out->target = INST_AUX_GET_TARGET(inst->Aux);
330
331   /* Args:
332    */
333   for (i = 0; i < nr_args; i++) {
334      for (j = 0; j < 4; j++) {
335	 out->src[i][j] = get_new_ref(c, inst->SrcReg[i], j, out);
336      }
337   }
338
339   /* Dst:
340    */
341   pass0_set_dst(c, out, inst, writemask);
342}
343
344
345
346/***********************************************************************
347 * Optimize moves and swizzles away:
348 */
349static void pass0_precalc_mov( struct brw_wm_compile *c,
350			       const struct prog_instruction *inst )
351{
352   const struct prog_dst_register *dst = &inst->DstReg;
353   GLuint writemask = inst->DstReg.WriteMask;
354   struct brw_wm_ref *refs[4];
355   GLuint i;
356
357   /* Get the effect of a MOV by manipulating our register table:
358    * First get all refs, then assign refs.  This ensures that "in-place"
359    * swizzles such as:
360    *   MOV t, t.xxyx
361    * are handled correctly.  Previously, these two steps were done in
362    * one loop and the above case was incorrectly handled.
363    */
364   for (i = 0; i < 4; i++) {
365      refs[i] = get_new_ref(c, inst->SrcReg[0], i, NULL);
366   }
367   for (i = 0; i < 4; i++) {
368      if (writemask & (1 << i)) {
369         pass0_set_fpreg_ref( c, dst->File, dst->Index, i, refs[i]);
370      }
371   }
372}
373
374
375/* Initialize payload "registers".
376 */
377static void pass0_init_payload( struct brw_wm_compile *c )
378{
379   GLuint i;
380
381   for (i = 0; i < 4; i++) {
382      GLuint j = i >= (c->nr_payload_regs + 1) / 2 ? 0 : i;
383      pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i,
384			     &c->payload.depth[j] );
385   }
386
387#if 0
388   /* This seems to be an alternative to the INTERP_WPOS stuff I do
389    * elsewhere:
390    */
391   if (c->key.source_depth_reg)
392      pass0_set_fpreg_value(c, PROGRAM_INPUT, FRAG_ATTRIB_WPOS, 2,
393			    &c->payload.depth[c->key.source_depth_reg/2]);
394#endif
395
396   for (i = 0; i < FRAG_ATTRIB_MAX; i++)
397      pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, i, 0,
398			     &c->payload.input_interp[i] );
399}
400
401
402/***********************************************************************
403 * PASS 0
404 *
405 * Work forwards to give each calculated value a unique number.  Where
406 * an instruction produces duplicate values (eg DP3), all are given
407 * the same number.
408 *
409 * Translate away swizzling and eliminate non-saturating moves.
410 */
411void brw_wm_pass0( struct brw_wm_compile *c )
412{
413   GLuint insn;
414
415   c->nr_vreg = 0;
416   c->nr_insns = 0;
417
418   pass0_init_undef(c);
419   pass0_init_payload(c);
420
421   for (insn = 0; insn < c->nr_fp_insns; insn++) {
422      const struct prog_instruction *inst = &c->prog_instructions[insn];
423
424      /* Optimize away moves, otherwise emit translated instruction:
425       */
426      switch (inst->Opcode) {
427      case OPCODE_MOV:
428      case OPCODE_SWZ:
429	 if (!inst->SaturateMode) {
430	    pass0_precalc_mov(c, inst);
431	 }
432	 else {
433	    translate_insn(c, inst);
434	 }
435	 break;
436      default:
437	 translate_insn(c, inst);
438	 break;
439      }
440   }
441
442   if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
443      brw_wm_print_program(c, "pass0");
444   }
445}
446