1 /**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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, sub license, 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 portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /* Authors: Keith Whitwell <[email protected]>
29 */
30
31 #include "util/u_math.h"
32 #include "util/u_memory.h"
33
34 #include "pipe/p_shader_tokens.h"
35 #include "draw_vs.h"
36 #include "draw_fs.h"
37 #include "draw_pipe.h"
38
39
40 /** subclass of draw_stage */
41 struct flat_stage
42 {
43 struct draw_stage stage;
44
45 unsigned num_flat_attribs;
46 unsigned flat_attribs[PIPE_MAX_SHADER_OUTPUTS]; /* flatshaded attribs */
47 };
48
49
50 static inline struct flat_stage *
flat_stage(struct draw_stage * stage)51 flat_stage(struct draw_stage *stage)
52 {
53 return (struct flat_stage *) stage;
54 }
55
56
57 /** Copy all the constant attributes from 'src' vertex to 'dst' vertex */
58 static inline void
copy_flats(struct draw_stage * stage,struct vertex_header * dst,const struct vertex_header * src)59 copy_flats(struct draw_stage *stage,
60 struct vertex_header *dst,
61 const struct vertex_header *src)
62 {
63 const struct flat_stage *flat = flat_stage(stage);
64 for (unsigned i = 0; i < flat->num_flat_attribs; i++) {
65 const unsigned attr = flat->flat_attribs[i];
66 COPY_4FV(dst->data[attr], src->data[attr]);
67 }
68 }
69
70
71 /** Copy all the color attributes from src vertex to dst0 & dst1 vertices */
72 static inline void
copy_flats2(struct draw_stage * stage,struct vertex_header * dst0,struct vertex_header * dst1,const struct vertex_header * src)73 copy_flats2(struct draw_stage *stage,
74 struct vertex_header *dst0,
75 struct vertex_header *dst1,
76 const struct vertex_header *src)
77 {
78 const struct flat_stage *flat = flat_stage(stage);
79 for (unsigned i = 0; i < flat->num_flat_attribs; i++) {
80 const unsigned attr = flat->flat_attribs[i];
81 COPY_4FV(dst0->data[attr], src->data[attr]);
82 COPY_4FV(dst1->data[attr], src->data[attr]);
83 }
84 }
85
86
87 /**
88 * Flatshade tri. Not required for clipping which handles this on its own,
89 * but required for unfilled tris and other primitive-changing stages
90 * (like widelines). If no such stages are active, handled by hardware.
91 */
92 static void
flatshade_tri_0(struct draw_stage * stage,struct prim_header * header)93 flatshade_tri_0(struct draw_stage *stage,
94 struct prim_header *header)
95 {
96 struct prim_header tmp;
97
98 tmp.det = header->det;
99 tmp.flags = header->flags;
100 tmp.pad = header->pad;
101 tmp.v[0] = header->v[0];
102 tmp.v[1] = dup_vert(stage, header->v[1], 0);
103 tmp.v[2] = dup_vert(stage, header->v[2], 1);
104
105 copy_flats2(stage, tmp.v[1], tmp.v[2], tmp.v[0]);
106
107 stage->next->tri(stage->next, &tmp);
108 }
109
110
111 static void
flatshade_tri_2(struct draw_stage * stage,struct prim_header * header)112 flatshade_tri_2(struct draw_stage *stage,
113 struct prim_header *header)
114 {
115 struct prim_header tmp;
116
117 tmp.det = header->det;
118 tmp.flags = header->flags;
119 tmp.pad = header->pad;
120 tmp.v[0] = dup_vert(stage, header->v[0], 0);
121 tmp.v[1] = dup_vert(stage, header->v[1], 1);
122 tmp.v[2] = header->v[2];
123
124 copy_flats2(stage, tmp.v[0], tmp.v[1], tmp.v[2]);
125
126 stage->next->tri(stage->next, &tmp);
127 }
128
129
130 /**
131 * Flatshade line.
132 */
133 static void
flatshade_line_0(struct draw_stage * stage,struct prim_header * header)134 flatshade_line_0(struct draw_stage *stage,
135 struct prim_header *header)
136 {
137 struct prim_header tmp;
138
139 tmp.det = header->det;
140 tmp.flags = header->flags;
141 tmp.pad = header->pad;
142 tmp.v[0] = header->v[0];
143 tmp.v[1] = dup_vert(stage, header->v[1], 0);
144
145 copy_flats(stage, tmp.v[1], tmp.v[0]);
146
147 stage->next->line(stage->next, &tmp);
148 }
149
150
151 static void
flatshade_line_1(struct draw_stage * stage,struct prim_header * header)152 flatshade_line_1(struct draw_stage *stage,
153 struct prim_header *header)
154 {
155 struct prim_header tmp;
156
157 tmp.det = header->det;
158 tmp.flags = header->flags;
159 tmp.pad = header->pad;
160 tmp.v[0] = dup_vert(stage, header->v[0], 0);
161 tmp.v[1] = header->v[1];
162
163 copy_flats(stage, tmp.v[0], tmp.v[1]);
164
165 stage->next->line(stage->next, &tmp);
166 }
167
168
169 static int
find_interp(const struct draw_fragment_shader * fs,int * indexed_interp,enum tgsi_semantic semantic_name,unsigned semantic_index)170 find_interp(const struct draw_fragment_shader *fs, int *indexed_interp,
171 enum tgsi_semantic semantic_name, unsigned semantic_index)
172 {
173 int interp;
174 /* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
175 * from the array we've filled before. */
176 if ((semantic_name == TGSI_SEMANTIC_COLOR ||
177 semantic_name == TGSI_SEMANTIC_BCOLOR) &&
178 semantic_index < 2) {
179 interp = indexed_interp[semantic_index];
180 } else {
181 /* Otherwise, search in the FS inputs, with a decent default
182 * if we don't find it.
183 */
184 interp = TGSI_INTERPOLATE_PERSPECTIVE;
185 if (fs) {
186 for (unsigned j = 0; j < fs->info.num_inputs; j++) {
187 if (semantic_name == fs->info.input_semantic_name[j] &&
188 semantic_index == fs->info.input_semantic_index[j]) {
189 interp = fs->info.input_interpolate[j];
190 break;
191 }
192 }
193 }
194 }
195 return interp;
196 }
197
198
199 static void
flatshade_init_state(struct draw_stage * stage)200 flatshade_init_state(struct draw_stage *stage)
201 {
202 struct flat_stage *flat = flat_stage(stage);
203 const struct draw_context *draw = stage->draw;
204 const struct draw_fragment_shader *fs = draw->fs.fragment_shader;
205 const struct tgsi_shader_info *info = draw_get_shader_info(draw);
206 unsigned i, j;
207
208 /* Find which vertex shader outputs need constant interpolation, make a list */
209
210 /* XXX: this code is a near exact copy of the one in clip_init_state.
211 * The latter also cares about perspective though.
212 */
213
214 /* First pick up the interpolation mode for
215 * gl_Color/gl_SecondaryColor, with the correct default.
216 */
217 int indexed_interp[2];
218 indexed_interp[0] = indexed_interp[1] = draw->rasterizer->flatshade ?
219 TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
220
221 if (fs) {
222 for (i = 0; i < fs->info.num_inputs; i++) {
223 if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&
224 fs->info.input_semantic_index[i] < 2) {
225 if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
226 indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
227 }
228 }
229 }
230
231 /* Then resolve the interpolation mode for every output attribute.
232 *
233 * Given how the rest of the code, the most efficient way is to
234 * have a vector of flat-mode attributes.
235 */
236 flat->num_flat_attribs = 0;
237 for (i = 0; i < info->num_outputs; i++) {
238 /* Find the interpolation mode for a specific attribute */
239 int interp = find_interp(fs, indexed_interp,
240 info->output_semantic_name[i],
241 info->output_semantic_index[i]);
242 /* If it's flat, add it to the flat vector. */
243
244 if (interp == TGSI_INTERPOLATE_CONSTANT ||
245 (interp == TGSI_INTERPOLATE_COLOR && draw->rasterizer->flatshade)) {
246 flat->flat_attribs[flat->num_flat_attribs] = i;
247 flat->num_flat_attribs++;
248 }
249 }
250 /* Search the extra vertex attributes */
251 for (j = 0; j < draw->extra_shader_outputs.num; j++) {
252 /* Find the interpolation mode for a specific attribute */
253 int interp = find_interp(fs, indexed_interp,
254 draw->extra_shader_outputs.semantic_name[j],
255 draw->extra_shader_outputs.semantic_index[j]);
256 /* If it's flat, add it to the flat vector. */
257 if (interp == TGSI_INTERPOLATE_CONSTANT) {
258 flat->flat_attribs[flat->num_flat_attribs] = i + j;
259 flat->num_flat_attribs++;
260 }
261 }
262
263 /* Choose flatshade routine according to provoking vertex:
264 */
265 if (draw->rasterizer->flatshade_first) {
266 stage->line = flatshade_line_0;
267 stage->tri = flatshade_tri_0;
268 } else {
269 stage->line = flatshade_line_1;
270 stage->tri = flatshade_tri_2;
271 }
272 }
273
274
275 static void
flatshade_first_tri(struct draw_stage * stage,struct prim_header * header)276 flatshade_first_tri(struct draw_stage *stage,
277 struct prim_header *header)
278 {
279 flatshade_init_state(stage);
280 stage->tri(stage, header);
281 }
282
283
284 static void
flatshade_first_line(struct draw_stage * stage,struct prim_header * header)285 flatshade_first_line(struct draw_stage *stage,
286 struct prim_header *header)
287 {
288 flatshade_init_state(stage);
289 stage->line(stage, header);
290 }
291
292
293 static void
flatshade_flush(struct draw_stage * stage,unsigned flags)294 flatshade_flush(struct draw_stage *stage,
295 unsigned flags)
296 {
297 stage->tri = flatshade_first_tri;
298 stage->line = flatshade_first_line;
299 stage->next->flush(stage->next, flags);
300 }
301
302
303 static void
flatshade_reset_stipple_counter(struct draw_stage * stage)304 flatshade_reset_stipple_counter(struct draw_stage *stage)
305 {
306 stage->next->reset_stipple_counter(stage->next);
307 }
308
309
310 static void
flatshade_destroy(struct draw_stage * stage)311 flatshade_destroy(struct draw_stage *stage)
312 {
313 draw_free_temp_verts(stage);
314 FREE(stage);
315 }
316
317
318 /**
319 * Create flatshading drawing stage.
320 */
321 struct draw_stage *
draw_flatshade_stage(struct draw_context * draw)322 draw_flatshade_stage(struct draw_context *draw)
323 {
324 struct flat_stage *flatshade = CALLOC_STRUCT(flat_stage);
325 if (!flatshade)
326 goto fail;
327
328 flatshade->stage.draw = draw;
329 flatshade->stage.name = "flatshade";
330 flatshade->stage.next = NULL;
331 flatshade->stage.point = draw_pipe_passthrough_point;
332 flatshade->stage.line = flatshade_first_line;
333 flatshade->stage.tri = flatshade_first_tri;
334 flatshade->stage.flush = flatshade_flush;
335 flatshade->stage.reset_stipple_counter = flatshade_reset_stipple_counter;
336 flatshade->stage.destroy = flatshade_destroy;
337
338 if (!draw_alloc_temp_verts(&flatshade->stage, 2))
339 goto fail;
340
341 return &flatshade->stage;
342
343 fail:
344 if (flatshade)
345 flatshade->stage.destroy(&flatshade->stage);
346
347 return NULL;
348 }
349
350
351