Merge branch 'upstream-gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_vcache.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 */
32
33 #include "pipe/p_util.h"
34 #include "draw/draw_context.h"
35 #include "draw/draw_private.h"
36 //#include "draw/draw_vbuf.h"
37 //#include "draw/draw_vertex.h"
38 #include "draw/draw_pt.h"
39
40
41 #define CACHE_MAX 32
42 #define FETCH_MAX 128
43 #define DRAW_MAX (16*1024)
44
45 struct vcache_frontend {
46 struct draw_pt_front_end base;
47 struct draw_context *draw;
48
49 unsigned in[CACHE_MAX];
50 ushort out[CACHE_MAX];
51
52 ushort draw_elts[DRAW_MAX];
53 unsigned fetch_elts[FETCH_MAX];
54
55 unsigned draw_count;
56 unsigned fetch_count;
57
58 struct draw_pt_middle_end *middle;
59
60 unsigned input_prim;
61 unsigned output_prim;
62 };
63
64 static void vcache_flush( struct vcache_frontend *vcache )
65 {
66 vcache->draw->vcache_flushing = TRUE;
67 if (vcache->draw_count) {
68 vcache->middle->run( vcache->middle,
69 vcache->fetch_elts,
70 vcache->fetch_count,
71 vcache->draw_elts,
72 vcache->draw_count );
73 }
74
75 memset(vcache->in, ~0, sizeof(vcache->in));
76 vcache->fetch_count = 0;
77 vcache->draw_count = 0;
78 vcache->draw->vcache_flushing = FALSE;
79 }
80
81 static void vcache_check_flush( struct vcache_frontend *vcache )
82 {
83 if ( vcache->draw_count + 6 >= DRAW_MAX ||
84 vcache->fetch_count + 4 >= FETCH_MAX )
85 {
86 vcache_flush( vcache );
87 }
88 }
89
90
91 static void vcache_elt( struct vcache_frontend *vcache,
92 unsigned felt )
93 {
94 unsigned idx = felt % CACHE_MAX;
95
96 if (vcache->in[idx] != felt) {
97 assert(vcache->fetch_count < FETCH_MAX);
98
99 vcache->in[idx] = felt;
100 vcache->out[idx] = (ushort)vcache->fetch_count;
101 vcache->fetch_elts[vcache->fetch_count++] = felt;
102 }
103
104 vcache->draw_elts[vcache->draw_count++] = vcache->out[idx];
105 }
106
107 static unsigned add_edgeflag( struct vcache_frontend *vcache,
108 unsigned idx,
109 unsigned mask )
110 {
111 if (0 && mask && draw_pt_get_edgeflag(vcache->draw, idx))
112 return idx | DRAW_PT_EDGEFLAG;
113 else
114 return idx;
115 }
116
117
118 static unsigned add_reset_stipple( unsigned idx,
119 unsigned reset )
120 {
121 if (0 && reset)
122 return idx | DRAW_PT_RESET_STIPPLE;
123 else
124 return idx;
125 }
126
127
128 static void vcache_triangle( struct vcache_frontend *vcache,
129 unsigned i0,
130 unsigned i1,
131 unsigned i2 )
132 {
133 vcache_elt(vcache, i0 /* | DRAW_PT_EDGEFLAG | DRAW_PT_RESET_STIPPLE */ );
134 vcache_elt(vcache, i1 /* | DRAW_PT_EDGEFLAG */);
135 vcache_elt(vcache, i2 /* | DRAW_PT_EDGEFLAG */);
136 vcache_check_flush(vcache);
137 }
138
139
140 static void vcache_ef_triangle( struct vcache_frontend *vcache,
141 boolean reset_stipple,
142 unsigned ef_mask,
143 unsigned i0,
144 unsigned i1,
145 unsigned i2 )
146 {
147 /*
148 i0 = add_edgeflag( vcache, i0, (ef_mask >> 0) & 1 );
149 i1 = add_edgeflag( vcache, i1, (ef_mask >> 1) & 1 );
150 i2 = add_edgeflag( vcache, i2, (ef_mask >> 2) & 1 );
151 i0 = add_reset_stipple( i0, reset_stipple );
152 */
153
154 vcache_elt(vcache, i0);
155 vcache_elt(vcache, i1);
156 vcache_elt(vcache, i2);
157 vcache_check_flush(vcache);
158
159 if (0) debug_printf("emit tri ef: %d %d %d\n",
160 !!(i0 & DRAW_PT_EDGEFLAG),
161 !!(i1 & DRAW_PT_EDGEFLAG),
162 !!(i2 & DRAW_PT_EDGEFLAG));
163
164 }
165
166
167 static void vcache_line( struct vcache_frontend *vcache,
168 boolean reset_stipple,
169 unsigned i0,
170 unsigned i1 )
171 {
172 i0 = add_reset_stipple( i0, reset_stipple );
173
174 vcache_elt(vcache, i0);
175 vcache_elt(vcache, i1);
176 vcache_check_flush(vcache);
177 }
178
179
180 static void vcache_point( struct vcache_frontend *vcache,
181 unsigned i0 )
182 {
183 vcache_elt(vcache, i0);
184 vcache_check_flush(vcache);
185 }
186
187 static void vcache_quad( struct vcache_frontend *vcache,
188 unsigned i0,
189 unsigned i1,
190 unsigned i2,
191 unsigned i3 )
192 {
193 vcache_triangle( vcache, i0, i1, i3 );
194 vcache_triangle( vcache, i1, i2, i3 );
195 }
196
197 static void vcache_ef_quad( struct vcache_frontend *vcache,
198 unsigned i0,
199 unsigned i1,
200 unsigned i2,
201 unsigned i3 )
202 {
203 const unsigned omitEdge2 = ~(1 << 1);
204 const unsigned omitEdge3 = ~(1 << 2);
205 vcache_ef_triangle( vcache, 1, omitEdge2, i0, i1, i3 );
206 vcache_ef_triangle( vcache, 0, omitEdge3, i1, i2, i3 );
207 }
208
209
210
211
212 static void vcache_run( struct draw_pt_front_end *frontend,
213 pt_elt_func get_elt,
214 const void *elts,
215 unsigned count )
216 {
217 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
218 struct draw_context *draw = vcache->draw;
219
220 boolean unfilled = (draw->rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL ||
221 draw->rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL);
222
223 boolean flatfirst = (draw->rasterizer->flatshade &&
224 draw->rasterizer->flatshade_first);
225 unsigned i;
226
227 // debug_printf("%s (%d) %d/%d\n", __FUNCTION__, draw->prim, start, count );
228
229 switch (vcache->input_prim) {
230 case PIPE_PRIM_POINTS:
231 for (i = 0; i < count; i ++) {
232 vcache_point( vcache,
233 get_elt(elts, i + 0) );
234 }
235 break;
236
237 case PIPE_PRIM_LINES:
238 for (i = 0; i+1 < count; i += 2) {
239 vcache_line( vcache,
240 TRUE,
241 get_elt(elts, i + 0),
242 get_elt(elts, i + 1));
243 }
244 break;
245
246 case PIPE_PRIM_LINE_LOOP:
247 if (count >= 2) {
248 for (i = 1; i < count; i++) {
249 vcache_line( vcache,
250 i == 1, /* XXX: only if vb not split */
251 get_elt(elts, i - 1),
252 get_elt(elts, i ));
253 }
254
255 vcache_line( vcache,
256 0,
257 get_elt(elts, count - 1),
258 get_elt(elts, 0 ));
259 }
260 break;
261
262 case PIPE_PRIM_LINE_STRIP:
263 for (i = 1; i < count; i++) {
264 vcache_line( vcache,
265 i == 1,
266 get_elt(elts, i - 1),
267 get_elt(elts, i ));
268 }
269 break;
270
271 case PIPE_PRIM_TRIANGLES:
272 if (unfilled) {
273 for (i = 0; i+2 < count; i += 3) {
274 vcache_ef_triangle( vcache,
275 1,
276 ~0,
277 get_elt(elts, i + 0),
278 get_elt(elts, i + 1),
279 get_elt(elts, i + 2 ));
280 }
281 }
282 else {
283 for (i = 0; i+2 < count; i += 3) {
284 vcache_triangle( vcache,
285 get_elt(elts, i + 0),
286 get_elt(elts, i + 1),
287 get_elt(elts, i + 2 ));
288 }
289 }
290 break;
291
292 case PIPE_PRIM_TRIANGLE_STRIP:
293 if (flatfirst) {
294 for (i = 0; i+2 < count; i++) {
295 if (i & 1) {
296 vcache_triangle( vcache,
297 get_elt(elts, i + 0),
298 get_elt(elts, i + 2),
299 get_elt(elts, i + 1 ));
300 }
301 else {
302 vcache_triangle( vcache,
303 get_elt(elts, i + 0),
304 get_elt(elts, i + 1),
305 get_elt(elts, i + 2 ));
306 }
307 }
308 }
309 else {
310 for (i = 0; i+2 < count; i++) {
311 if (i & 1) {
312 vcache_triangle( vcache,
313 get_elt(elts, i + 1),
314 get_elt(elts, i + 0),
315 get_elt(elts, i + 2 ));
316 }
317 else {
318 vcache_triangle( vcache,
319 get_elt(elts, i + 0),
320 get_elt(elts, i + 1),
321 get_elt(elts, i + 2 ));
322 }
323 }
324 }
325 break;
326
327 case PIPE_PRIM_TRIANGLE_FAN:
328 if (count >= 3) {
329 if (flatfirst) {
330 for (i = 0; i+2 < count; i++) {
331 vcache_triangle( vcache,
332 get_elt(elts, i + 1),
333 get_elt(elts, i + 2),
334 get_elt(elts, 0 ));
335 }
336 }
337 else {
338 for (i = 0; i+2 < count; i++) {
339 vcache_triangle( vcache,
340 get_elt(elts, 0),
341 get_elt(elts, i + 1),
342 get_elt(elts, i + 2 ));
343 }
344 }
345 }
346 break;
347
348
349 case PIPE_PRIM_QUADS:
350 if (unfilled) {
351 for (i = 0; i+3 < count; i += 4) {
352 vcache_ef_quad( vcache,
353 get_elt(elts, i + 0),
354 get_elt(elts, i + 1),
355 get_elt(elts, i + 2),
356 get_elt(elts, i + 3));
357 }
358 }
359 else {
360 for (i = 0; i+3 < count; i += 4) {
361 vcache_quad( vcache,
362 get_elt(elts, i + 0),
363 get_elt(elts, i + 1),
364 get_elt(elts, i + 2),
365 get_elt(elts, i + 3));
366 }
367 }
368 break;
369
370 case PIPE_PRIM_QUAD_STRIP:
371 if (unfilled) {
372 for (i = 0; i+3 < count; i += 2) {
373 vcache_ef_quad( vcache,
374 get_elt(elts, i + 2),
375 get_elt(elts, i + 0),
376 get_elt(elts, i + 1),
377 get_elt(elts, i + 3));
378 }
379 }
380 else {
381 for (i = 0; i+3 < count; i += 2) {
382 vcache_quad( vcache,
383 get_elt(elts, i + 2),
384 get_elt(elts, i + 0),
385 get_elt(elts, i + 1),
386 get_elt(elts, i + 3));
387 }
388 }
389 break;
390
391 case PIPE_PRIM_POLYGON:
392 if (unfilled) {
393 /* These bitflags look a little odd because we submit the
394 * vertices as (1,2,0) to satisfy flatshade requirements.
395 */
396 const unsigned edge_first = (1<<2);
397 const unsigned edge_middle = (1<<0);
398 const unsigned edge_last = (1<<1);
399
400 for (i = 0; i+2 < count; i++) {
401 unsigned ef_mask = edge_middle;
402
403 if (i == 0)
404 ef_mask |= edge_first;
405
406 if (i + 3 == count)
407 ef_mask |= edge_last;
408
409 vcache_ef_triangle( vcache,
410 i == 0,
411 ef_mask,
412 get_elt(elts, i + 1),
413 get_elt(elts, i + 2),
414 get_elt(elts, 0));
415 }
416 }
417 else {
418 for (i = 0; i+2 < count; i++) {
419 vcache_triangle( vcache,
420 get_elt(elts, i + 1),
421 get_elt(elts, i + 2),
422 get_elt(elts, 0));
423 }
424 }
425 break;
426
427 default:
428 assert(0);
429 break;
430 }
431
432 vcache_flush( vcache );
433 }
434
435
436
437 static unsigned reduced_prim[PIPE_PRIM_POLYGON + 1] = {
438 PIPE_PRIM_POINTS,
439 PIPE_PRIM_LINES,
440 PIPE_PRIM_LINES,
441 PIPE_PRIM_LINES,
442 PIPE_PRIM_TRIANGLES,
443 PIPE_PRIM_TRIANGLES,
444 PIPE_PRIM_TRIANGLES,
445 PIPE_PRIM_TRIANGLES,
446 PIPE_PRIM_TRIANGLES,
447 PIPE_PRIM_TRIANGLES
448 };
449
450
451
452 static void vcache_prepare( struct draw_pt_front_end *frontend,
453 unsigned prim,
454 struct draw_pt_middle_end *middle,
455 unsigned opt )
456 {
457 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
458
459 /*
460 if (vcache->draw->rasterizer->flatshade_first)
461 vcache->base.run = vcache_run_pv0;
462 else
463 vcache->base.run = vcache_run_pv2;
464 */
465
466 vcache->base.run = vcache_run;
467 vcache->input_prim = prim;
468 vcache->output_prim = reduced_prim[prim];
469
470 vcache->middle = middle;
471 middle->prepare( middle, vcache->output_prim, opt );
472 }
473
474
475
476
477 static void vcache_finish( struct draw_pt_front_end *frontend )
478 {
479 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
480 vcache->middle->finish( vcache->middle );
481 vcache->middle = NULL;
482 }
483
484 static void vcache_destroy( struct draw_pt_front_end *frontend )
485 {
486 FREE(frontend);
487 }
488
489
490 struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw )
491 {
492 struct vcache_frontend *vcache = CALLOC_STRUCT( vcache_frontend );
493 if (vcache == NULL)
494 return NULL;
495
496 vcache->base.prepare = vcache_prepare;
497 vcache->base.run = NULL;
498 vcache->base.finish = vcache_finish;
499 vcache->base.destroy = vcache_destroy;
500 vcache->draw = draw;
501
502 memset(vcache->in, ~0, sizeof(vcache->in));
503
504 return &vcache->base;
505 }