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