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 
get_ref(struct brw_wm_compile * c)42 static 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 
get_value(struct brw_wm_compile * c)49 static 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 */
get_instruction(struct brw_wm_compile * c)57 static 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 */
pass0_init_undef(struct brw_wm_compile * c)68 static 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 */
pass0_set_fpreg_value(struct brw_wm_compile * c,GLuint file,GLuint idx,GLuint component,struct brw_wm_value * value)78 static 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 */
pass0_set_fpreg_ref(struct brw_wm_compile * c,GLuint file,GLuint idx,GLuint component,const struct brw_wm_ref * src_ref)93 static 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 
get_param_ref(struct brw_wm_compile * c,const GLfloat * param_ptr)102 static 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 */
get_const_ref(struct brw_wm_compile * c,const GLfloat * constval)132 static 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  */
pass0_get_reg(struct brw_wm_compile * c,GLuint file,GLuint idx,GLuint component)166 static 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 
pass0_set_dst(struct brw_wm_compile * c,struct brw_wm_instruction * out,const struct prog_instruction * inst,GLuint writemask)244 static 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 
get_fp_src_reg_ref(struct brw_wm_compile * c,struct prog_src_register src,GLuint i)263 static 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 
get_new_ref(struct brw_wm_compile * c,struct prog_src_register src,GLuint i,struct brw_wm_instruction * insn)283 static 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 
312 static void
translate_insn(struct brw_wm_compile * c,const struct prog_instruction * inst)313 translate_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  */
pass0_precalc_mov(struct brw_wm_compile * c,const struct prog_instruction * inst)349 static 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  */
pass0_init_payload(struct brw_wm_compile * c)377 static 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  */
brw_wm_pass0(struct brw_wm_compile * c)411 void 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