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 
36 
get_tracked_mask(struct brw_wm_compile * c,struct brw_wm_instruction * inst)37 static GLuint get_tracked_mask(struct brw_wm_compile *c,
38 			       struct brw_wm_instruction *inst)
39 {
40    GLuint i;
41    for (i = 0; i < 4; i++) {
42       if (inst->writemask & (1<<i)) {
43 	 if (!inst->dst[i]->contributes_to_output) {
44 	    inst->writemask &= ~(1<<i);
45 	    inst->dst[i] = 0;
46 	 }
47       }
48    }
49 
50    return inst->writemask;
51 }
52 
53 /* Remove a reference from a value's usage chain.
54  */
unlink_ref(struct brw_wm_ref * ref)55 static void unlink_ref(struct brw_wm_ref *ref)
56 {
57    struct brw_wm_value *value = ref->value;
58 
59    if (ref == value->lastuse) {
60       value->lastuse = ref->prevuse;
61    }
62    else {
63       struct brw_wm_ref *i = value->lastuse;
64       while (i->prevuse != ref) i = i->prevuse;
65       i->prevuse = ref->prevuse;
66    }
67 }
68 
track_arg(struct brw_wm_compile * c,struct brw_wm_instruction * inst,GLuint arg,GLuint readmask)69 static void track_arg(struct brw_wm_compile *c,
70 		      struct brw_wm_instruction *inst,
71 		      GLuint arg,
72 		      GLuint readmask)
73 {
74    GLuint i;
75 
76    for (i = 0; i < 4; i++) {
77       struct brw_wm_ref *ref = inst->src[arg][i];
78       if (ref) {
79 	 if (readmask & (1<<i)) {
80 	    ref->value->contributes_to_output = 1;
81          }
82 	 else {
83 	    unlink_ref(ref);
84 	    inst->src[arg][i] = NULL;
85 	 }
86       }
87    }
88 }
89 
get_texcoord_mask(GLuint tex_idx)90 static GLuint get_texcoord_mask( GLuint tex_idx )
91 {
92    switch (tex_idx) {
93    case TEXTURE_1D_INDEX:
94       return WRITEMASK_X;
95    case TEXTURE_2D_INDEX:
96    case TEXTURE_1D_ARRAY_INDEX:
97    case TEXTURE_EXTERNAL_INDEX:
98       return WRITEMASK_XY;
99    case TEXTURE_3D_INDEX:
100    case TEXTURE_2D_ARRAY_INDEX:
101       return WRITEMASK_XYZ;
102    case TEXTURE_CUBE_INDEX:
103       return WRITEMASK_XYZ;
104    case TEXTURE_RECT_INDEX:
105       return WRITEMASK_XY;
106    default: return 0;
107    }
108 }
109 
110 
111 /* Step two: Basically this is dead code elimination.
112  *
113  * Iterate backwards over instructions, noting which values
114  * contribute to the final result.  Adjust writemasks to only
115  * calculate these values.
116  */
brw_wm_pass1(struct brw_wm_compile * c)117 void brw_wm_pass1( struct brw_wm_compile *c )
118 {
119    GLint insn;
120 
121    for (insn = c->nr_insns-1; insn >= 0; insn--) {
122       struct brw_wm_instruction *inst = &c->instruction[insn];
123       GLuint writemask;
124       GLuint read0, read1, read2;
125 
126       if (inst->opcode == OPCODE_KIL) {
127 	 track_arg(c, inst, 0, WRITEMASK_XYZW); /* All args contribute to final */
128 	 continue;
129       }
130 
131       if (inst->opcode == WM_FB_WRITE) {
132 	 track_arg(c, inst, 0, WRITEMASK_XYZW);
133 	 track_arg(c, inst, 1, WRITEMASK_XYZW);
134 	 if (c->source_depth_to_render_target && c->computes_depth)
135 	    track_arg(c, inst, 2, WRITEMASK_Z);
136 	 else
137 	    track_arg(c, inst, 2, 0);
138 	 continue;
139       }
140 
141       /* Lookup all the registers which were written by this
142        * instruction and get a mask of those that contribute to the output:
143        */
144       writemask = get_tracked_mask(c, inst);
145       if (!writemask) {
146 	 GLuint arg;
147 	 for (arg = 0; arg < 3; arg++)
148 	    track_arg(c, inst, arg, 0);
149 	 continue;
150       }
151 
152       read0 = 0;
153       read1 = 0;
154       read2 = 0;
155 
156       /* Mark all inputs which contribute to the marked outputs:
157        */
158       switch (inst->opcode) {
159       case OPCODE_ABS:
160       case OPCODE_FLR:
161       case OPCODE_FRC:
162       case OPCODE_MOV:
163       case OPCODE_SSG:
164       case OPCODE_SWZ:
165       case OPCODE_TRUNC:
166 	 read0 = writemask;
167 	 break;
168 
169       case OPCODE_SUB:
170       case OPCODE_SLT:
171       case OPCODE_SLE:
172       case OPCODE_SGE:
173       case OPCODE_SGT:
174       case OPCODE_SEQ:
175       case OPCODE_SNE:
176       case OPCODE_ADD:
177       case OPCODE_MAX:
178       case OPCODE_MIN:
179       case OPCODE_MUL:
180 	 read0 = writemask;
181 	 read1 = writemask;
182 	 break;
183 
184       case OPCODE_DDX:
185       case OPCODE_DDY:
186 	 read0 = writemask;
187 	 break;
188 
189       case OPCODE_MAD:
190       case OPCODE_CMP:
191       case OPCODE_LRP:
192 	 read0 = writemask;
193 	 read1 = writemask;
194 	 read2 = writemask;
195 	 break;
196 
197       case OPCODE_XPD:
198 	 if (writemask & WRITEMASK_X) read0 |= WRITEMASK_YZ;
199 	 if (writemask & WRITEMASK_Y) read0 |= WRITEMASK_XZ;
200 	 if (writemask & WRITEMASK_Z) read0 |= WRITEMASK_XY;
201 	 read1 = read0;
202 	 break;
203 
204       case OPCODE_COS:
205       case OPCODE_EX2:
206       case OPCODE_LG2:
207       case OPCODE_RCP:
208       case OPCODE_RSQ:
209       case OPCODE_SIN:
210       case OPCODE_SCS:
211       case WM_CINTERP:
212       case WM_PIXELXY:
213 	 read0 = WRITEMASK_X;
214 	 break;
215 
216       case OPCODE_POW:
217 	 read0 = WRITEMASK_X;
218 	 read1 = WRITEMASK_X;
219 	 break;
220 
221       case OPCODE_TEX:
222       case OPCODE_TXP:
223 	 read0 = get_texcoord_mask(inst->tex_idx);
224 
225          if (inst->tex_shadow)
226 	    read0 |= WRITEMASK_Z;
227 	 break;
228 
229       case OPCODE_TXB:
230 	 /* Shadow ignored for txb.
231 	  */
232 	 read0 = get_texcoord_mask(inst->tex_idx) | WRITEMASK_W;
233 	 break;
234 
235       case WM_WPOSXY:
236 	 read0 = writemask & WRITEMASK_XY;
237 	 break;
238 
239       case WM_DELTAXY:
240 	 read0 = writemask & WRITEMASK_XY;
241 	 read1 = WRITEMASK_X;
242 	 break;
243 
244       case WM_PIXELW:
245 	 read0 = WRITEMASK_X;
246 	 read1 = WRITEMASK_XY;
247 	 break;
248 
249       case WM_LINTERP:
250 	 read0 = WRITEMASK_X;
251 	 read1 = WRITEMASK_XY;
252 	 break;
253 
254       case WM_PINTERP:
255 	 read0 = WRITEMASK_X; /* interpolant */
256 	 read1 = WRITEMASK_XY; /* deltas */
257 	 read2 = WRITEMASK_W; /* pixel w */
258 	 break;
259 
260       case OPCODE_DP2:
261 	 read0 = WRITEMASK_XY;
262 	 read1 = WRITEMASK_XY;
263 	 break;
264 
265       case OPCODE_DP3:
266 	 read0 = WRITEMASK_XYZ;
267 	 read1 = WRITEMASK_XYZ;
268 	 break;
269 
270       case OPCODE_DPH:
271 	 read0 = WRITEMASK_XYZ;
272 	 read1 = WRITEMASK_XYZW;
273 	 break;
274 
275       case OPCODE_DP4:
276 	 read0 = WRITEMASK_XYZW;
277 	 read1 = WRITEMASK_XYZW;
278 	 break;
279 
280       case OPCODE_LIT:
281 	 read0 = WRITEMASK_XYW;
282 	 break;
283 
284       case OPCODE_DST:
285       case WM_FRONTFACING:
286       default:
287 	 break;
288       }
289 
290       track_arg(c, inst, 0, read0);
291       track_arg(c, inst, 1, read1);
292       track_arg(c, inst, 2, read2);
293    }
294 
295    if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
296       brw_wm_print_program(c, "pass1");
297    }
298 }
299