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 "main/macros.h"
34 #include "brw_context.h"
35 #include "brw_vs.h"
36 
37 /* Component is active if it may diverge from [0,0,0,1].  Undef values
38  * are promoted to [0,0,0,1] for the purposes of this analysis.
39  */
40 struct tracker {
41    bool twoside;
42    GLubyte active[PROGRAM_OUTPUT+1][MAX_PROGRAM_TEMPS];
43    GLbitfield size_masks[4];  /**< one bit per fragment program input attrib */
44 };
45 
46 
set_active_component(struct tracker * t,GLuint file,GLuint index,GLubyte active)47 static void set_active_component( struct tracker *t,
48 				  GLuint file,
49 				  GLuint index,
50 				  GLubyte active )
51 {
52    switch (file) {
53    case PROGRAM_TEMPORARY:
54    case PROGRAM_INPUT:
55    case PROGRAM_OUTPUT:
56       assert(file < PROGRAM_OUTPUT + 1);
57       assert(index < Elements(t->active[0]));
58       t->active[file][index] |= active;
59       break;
60    default:
61       break;
62    }
63 }
64 
set_active(struct tracker * t,struct prog_dst_register dst,GLuint active)65 static void set_active( struct tracker *t,
66 			struct prog_dst_register dst,
67 			GLuint active )
68 {
69    set_active_component( t, dst.File, dst.Index, active & dst.WriteMask );
70 }
71 
72 
get_active_component(struct tracker * t,GLuint file,GLuint index,GLuint component,GLubyte swz)73 static GLubyte get_active_component( struct tracker *t,
74 				     GLuint file,
75 				     GLuint index,
76 				     GLuint component,
77 				     GLubyte swz )
78 {
79    switch (swz) {
80    case SWIZZLE_ZERO:
81       return component < 3 ? 0 : (1<<component);
82    case SWIZZLE_ONE:
83       return component == 3 ? 0 : (1<<component);
84    default:
85       switch (file) {
86       case PROGRAM_TEMPORARY:
87       case PROGRAM_INPUT:
88       case PROGRAM_OUTPUT:
89 	 return t->active[file][index] & (1<<component);
90       default:
91 	 return 1 << component;
92       }
93    }
94 }
95 
96 
get_active(struct tracker * t,struct prog_src_register src)97 static GLubyte get_active( struct tracker *t,
98 			   struct prog_src_register src )
99 {
100    GLuint i;
101    GLubyte active = src.Negate; /* NOTE! */
102 
103    if (src.RelAddr)
104       return 0xf;
105 
106    for (i = 0; i < 4; i++)
107       active |= get_active_component(t, src.File, src.Index, i,
108 				     GET_SWZ(src.Swizzle, i));
109 
110    return active;
111 }
112 
113 /**
114  * Return the size (1,2,3 or 4) of the output/result for VERT_RESULT_idx.
115  */
get_output_size(struct tracker * t,GLuint idx)116 static GLubyte get_output_size( struct tracker *t,
117 				GLuint idx )
118 {
119    GLubyte active;
120    assert(idx < VERT_RESULT_MAX);
121    active = t->active[PROGRAM_OUTPUT][idx];
122    if (active & (1<<3)) return 4;
123    if (active & (1<<2)) return 3;
124    if (active & (1<<1)) return 2;
125    if (active & (1<<0)) return 1;
126    return 0;
127 }
128 
129 /* Note the potential copying that occurs in the setup program:
130  */
calc_sizes(struct tracker * t)131 static void calc_sizes( struct tracker *t )
132 {
133    GLint vertRes;
134 
135    if (t->twoside) {
136       t->active[PROGRAM_OUTPUT][VERT_RESULT_COL0] |=
137 	 t->active[PROGRAM_OUTPUT][VERT_RESULT_BFC0];
138 
139       t->active[PROGRAM_OUTPUT][VERT_RESULT_COL1] |=
140 	 t->active[PROGRAM_OUTPUT][VERT_RESULT_BFC1];
141    }
142 
143    /* Examine vertex program output sizes to set the size_masks[] info
144     * which describes the fragment program input sizes.
145     */
146    for (vertRes = 0; vertRes < VERT_RESULT_MAX; vertRes++) {
147 
148       /* map vertex program output index to fragment program input index */
149       GLint fragAttrib = _mesa_vert_result_to_frag_attrib(vertRes);
150       if (fragAttrib < 0)
151          continue;
152 
153       switch (get_output_size(t, vertRes)) {
154       case 4: t->size_masks[4-1] |= 1 << fragAttrib;
155       case 3: t->size_masks[3-1] |= 1 << fragAttrib;
156       case 2: t->size_masks[2-1] |= 1 << fragAttrib;
157       case 1: t->size_masks[1-1] |= 1 << fragAttrib;
158 	 break;
159       }
160    }
161 }
162 
163 static GLubyte szflag[4+1] = {
164    0,
165    0x1,
166    0x3,
167    0x7,
168    0xf
169 };
170 
171 /* Pull a size out of the packed array:
172  */
get_input_size(struct brw_context * brw,GLuint attr)173 static GLuint get_input_size(struct brw_context *brw,
174 			     GLuint attr)
175 {
176    GLuint sizes_dword = brw->vb.info.sizes[attr/16];
177    GLuint sizes_bits = (sizes_dword>>((attr%16)*2)) & 0x3;
178    return sizes_bits + 1;
179 /*    return brw->vb.inputs[attr].glarray->Size; */
180 }
181 
182 /* Calculate sizes of vertex program outputs.  Size is the largest
183  * component index which might vary from [0,0,0,1]
184  */
calc_wm_input_sizes(struct brw_context * brw)185 static void calc_wm_input_sizes( struct brw_context *brw )
186 {
187    struct gl_context *ctx = &brw->intel.ctx;
188    /* BRW_NEW_VERTEX_PROGRAM */
189    const struct brw_vertex_program *vp =
190       brw_vertex_program_const(brw->vertex_program);
191    /* BRW_NEW_INPUT_DIMENSIONS */
192    struct tracker t;
193    GLuint insn;
194    GLuint i;
195 
196    /* Mesa IR is not generated for GLSL vertex shaders.  If there's no Mesa
197     * IR, the code below cannot determine which output components are
198     * written.  So, skip it and assume everything is written.  This
199     * circumvents some optimizations in the fragment shader, but it guarantees
200     * that correct code is generated.
201     */
202    if (vp->program.Base.NumInstructions == 0) {
203       brw->wm.input_size_masks[0] = ~0;
204       brw->wm.input_size_masks[1] = ~0;
205       brw->wm.input_size_masks[2] = ~0;
206       brw->wm.input_size_masks[3] = ~0;
207       return;
208    }
209 
210 
211    memset(&t, 0, sizeof(t));
212 
213    /* _NEW_LIGHT | _NEW_PROGRAM */
214    if (ctx->VertexProgram._TwoSideEnabled)
215       t.twoside = 1;
216 
217    for (i = 0; i < VERT_ATTRIB_MAX; i++)
218       if (vp->program.Base.InputsRead & BITFIELD64_BIT(i))
219 	 set_active_component(&t, PROGRAM_INPUT, i,
220 			      szflag[get_input_size(brw, i)]);
221 
222    for (insn = 0; insn < vp->program.Base.NumInstructions; insn++) {
223       struct prog_instruction *inst = &vp->program.Base.Instructions[insn];
224 
225       switch (inst->Opcode) {
226       case OPCODE_ARL:
227 	 break;
228 
229       case OPCODE_MOV:
230 	 set_active(&t, inst->DstReg, get_active(&t, inst->SrcReg[0]));
231 	 break;
232 
233       default:
234 	 set_active(&t, inst->DstReg, 0xf);
235 	 break;
236       }
237    }
238 
239    calc_sizes(&t);
240 
241    if (memcmp(brw->wm.input_size_masks, t.size_masks, sizeof(t.size_masks)) != 0) {
242       memcpy(brw->wm.input_size_masks, t.size_masks, sizeof(t.size_masks));
243       brw->state.dirty.brw |= BRW_NEW_WM_INPUT_DIMENSIONS;
244    }
245 }
246 
247 const struct brw_tracked_state brw_wm_input_sizes = {
248    .dirty = {
249       .mesa  = _NEW_LIGHT | _NEW_PROGRAM,
250       .brw   = BRW_NEW_VERTEX_PROGRAM | BRW_NEW_INPUT_DIMENSIONS,
251       .cache = 0
252    },
253    .emit = calc_wm_input_sizes
254 };
255 
256