edb2aa73e162e95e082c17f3a0e1fc2775e8e1ad
[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 "util/u_memory.h"
34 #include "draw/draw_context.h"
35 #include "draw/draw_private.h"
36 #include "draw/draw_pt.h"
37
38
39 #define CACHE_MAX 256
40 #define FETCH_MAX 256
41 #define DRAW_MAX (16*1024)
42
43 struct vcache_frontend {
44 struct draw_pt_front_end base;
45 struct draw_context *draw;
46
47 unsigned in[CACHE_MAX];
48 ushort out[CACHE_MAX];
49
50 ushort draw_elts[DRAW_MAX];
51 unsigned fetch_elts[FETCH_MAX];
52
53 unsigned draw_count;
54 unsigned fetch_count;
55 unsigned fetch_max;
56
57 struct draw_pt_middle_end *middle;
58
59 unsigned input_prim;
60 unsigned output_prim;
61
62 unsigned middle_prim;
63 unsigned opt;
64 };
65
66 static INLINE void
67 vcache_flush( struct vcache_frontend *vcache )
68 {
69 if (vcache->middle_prim != vcache->output_prim) {
70 vcache->middle_prim = vcache->output_prim;
71 vcache->middle->prepare( vcache->middle,
72 vcache->middle_prim,
73 vcache->opt,
74 &vcache->fetch_max );
75 }
76
77 if (vcache->draw_count) {
78 vcache->middle->run( vcache->middle,
79 vcache->fetch_elts,
80 vcache->fetch_count,
81 vcache->draw_elts,
82 vcache->draw_count );
83 }
84
85 memset(vcache->in, ~0, sizeof(vcache->in));
86 vcache->fetch_count = 0;
87 vcache->draw_count = 0;
88 }
89
90 static INLINE void
91 vcache_check_flush( struct vcache_frontend *vcache )
92 {
93 if ( vcache->draw_count + 6 >= DRAW_MAX ||
94 vcache->fetch_count + 4 >= FETCH_MAX )
95 {
96 vcache_flush( vcache );
97 }
98 }
99
100
101 static INLINE void
102 vcache_elt( struct vcache_frontend *vcache,
103 unsigned felt,
104 ushort flags )
105 {
106 unsigned idx = felt % CACHE_MAX;
107
108 if (vcache->in[idx] != felt) {
109 assert(vcache->fetch_count < FETCH_MAX);
110
111 vcache->in[idx] = felt;
112 vcache->out[idx] = (ushort)vcache->fetch_count;
113 vcache->fetch_elts[vcache->fetch_count++] = felt;
114 }
115
116 vcache->draw_elts[vcache->draw_count++] = vcache->out[idx] | flags;
117 }
118
119
120
121 static INLINE void
122 vcache_triangle( struct vcache_frontend *vcache,
123 unsigned i0,
124 unsigned i1,
125 unsigned i2 )
126 {
127 vcache_elt(vcache, i0, 0);
128 vcache_elt(vcache, i1, 0);
129 vcache_elt(vcache, i2, 0);
130 vcache_check_flush(vcache);
131 }
132
133
134 static INLINE void
135 vcache_triangle_flags( struct vcache_frontend *vcache,
136 ushort flags,
137 unsigned i0,
138 unsigned i1,
139 unsigned i2 )
140 {
141 vcache_elt(vcache, i0, flags);
142 vcache_elt(vcache, i1, 0);
143 vcache_elt(vcache, i2, 0);
144 vcache_check_flush(vcache);
145 }
146
147 static INLINE void
148 vcache_line( struct vcache_frontend *vcache,
149 unsigned i0,
150 unsigned i1 )
151 {
152 vcache_elt(vcache, i0, 0);
153 vcache_elt(vcache, i1, 0);
154 vcache_check_flush(vcache);
155 }
156
157
158 static INLINE void
159 vcache_line_flags( struct vcache_frontend *vcache,
160 ushort flags,
161 unsigned i0,
162 unsigned i1 )
163 {
164 vcache_elt(vcache, i0, flags);
165 vcache_elt(vcache, i1, 0);
166 vcache_check_flush(vcache);
167 }
168
169
170 static INLINE void
171 vcache_point( struct vcache_frontend *vcache,
172 unsigned i0 )
173 {
174 vcache_elt(vcache, i0, 0);
175 vcache_check_flush(vcache);
176 }
177
178 static INLINE void
179 vcache_quad( struct vcache_frontend *vcache,
180 unsigned i0,
181 unsigned i1,
182 unsigned i2,
183 unsigned i3 )
184 {
185 vcache_triangle( vcache, i0, i1, i3 );
186 vcache_triangle( vcache, i1, i2, i3 );
187 }
188
189 static INLINE void
190 vcache_ef_quad( struct vcache_frontend *vcache,
191 unsigned i0,
192 unsigned i1,
193 unsigned i2,
194 unsigned i3 )
195 {
196 if (vcache->draw->rasterizer->flatshade_first) {
197 vcache_triangle_flags( vcache,
198 ( DRAW_PIPE_RESET_STIPPLE |
199 DRAW_PIPE_EDGE_FLAG_0 |
200 DRAW_PIPE_EDGE_FLAG_1 ),
201 i0, i1, i2 );
202
203 vcache_triangle_flags( vcache,
204 ( DRAW_PIPE_EDGE_FLAG_2 |
205 DRAW_PIPE_EDGE_FLAG_1 ),
206 i0, i2, i3 );
207 }
208 else {
209 vcache_triangle_flags( vcache,
210 ( DRAW_PIPE_RESET_STIPPLE |
211 DRAW_PIPE_EDGE_FLAG_0 |
212 DRAW_PIPE_EDGE_FLAG_2 ),
213 i0, i1, i3 );
214
215 vcache_triangle_flags( vcache,
216 ( DRAW_PIPE_EDGE_FLAG_0 |
217 DRAW_PIPE_EDGE_FLAG_1 ),
218 i1, i2, i3 );
219 }
220 }
221
222 /* At least for now, we're back to using a template include file for
223 * this. The two paths aren't too different though - it may be
224 * possible to reunify them.
225 */
226 #define TRIANGLE(vc,flags,i0,i1,i2) vcache_triangle_flags(vc,flags,i0,i1,i2)
227 #define QUAD(vc,i0,i1,i2,i3) vcache_ef_quad(vc,i0,i1,i2,i3)
228 #define LINE(vc,flags,i0,i1) vcache_line_flags(vc,flags,i0,i1)
229 #define POINT(vc,i0) vcache_point(vc,i0)
230 #define FUNC vcache_run_extras
231 #include "draw_pt_vcache_tmp.h"
232
233 #define TRIANGLE(vc,flags,i0,i1,i2) vcache_triangle(vc,i0,i1,i2)
234 #define QUAD(vc,i0,i1,i2,i3) vcache_quad(vc,i0,i1,i2,i3)
235 #define LINE(vc,flags,i0,i1) vcache_line(vc,i0,i1)
236 #define POINT(vc,i0) vcache_point(vc,i0)
237 #define FUNC vcache_run
238 #include "draw_pt_vcache_tmp.h"
239
240 static INLINE void
241 rebase_uint_elts( const unsigned *src,
242 unsigned count,
243 int delta,
244 ushort *dest )
245 {
246 unsigned i;
247
248 for (i = 0; i < count; i++)
249 dest[i] = (ushort)(src[i] + delta);
250 }
251
252 static INLINE void
253 rebase_ushort_elts( const ushort *src,
254 unsigned count,
255 int delta,
256 ushort *dest )
257 {
258 unsigned i;
259
260 for (i = 0; i < count; i++)
261 dest[i] = (ushort)(src[i] + delta);
262 }
263
264 static INLINE void
265 rebase_ubyte_elts( const ubyte *src,
266 unsigned count,
267 int delta,
268 ushort *dest )
269 {
270 unsigned i;
271
272 for (i = 0; i < count; i++)
273 dest[i] = (ushort)(src[i] + delta);
274 }
275
276
277
278 static INLINE void
279 translate_uint_elts( const unsigned *src,
280 unsigned count,
281 ushort *dest )
282 {
283 unsigned i;
284
285 for (i = 0; i < count; i++)
286 dest[i] = (ushort)(src[i]);
287 }
288
289 static INLINE void
290 translate_ushort_elts( const ushort *src,
291 unsigned count,
292 ushort *dest )
293 {
294 unsigned i;
295
296 for (i = 0; i < count; i++)
297 dest[i] = (ushort)(src[i]);
298 }
299
300 static INLINE void
301 translate_ubyte_elts( const ubyte *src,
302 unsigned count,
303 ushort *dest )
304 {
305 unsigned i;
306
307 for (i = 0; i < count; i++)
308 dest[i] = (ushort)(src[i]);
309 }
310
311
312
313
314 #if 0
315 static INLINE enum pipe_format
316 format_from_get_elt( pt_elt_func get_elt )
317 {
318 switch (draw->pt.user.eltSize) {
319 case 1: return PIPE_FORMAT_R8_UNORM;
320 case 2: return PIPE_FORMAT_R16_UNORM;
321 case 4: return PIPE_FORMAT_R32_UNORM;
322 default: return PIPE_FORMAT_NONE;
323 }
324 }
325 #endif
326
327 static INLINE void
328 vcache_check_run( struct draw_pt_front_end *frontend,
329 pt_elt_func get_elt,
330 const void *elts,
331 unsigned draw_count )
332 {
333 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
334 struct draw_context *draw = vcache->draw;
335 unsigned min_index = draw->pt.user.min_index;
336 unsigned max_index = draw->pt.user.max_index;
337 unsigned index_size = draw->pt.user.eltSize;
338 unsigned fetch_count = max_index + 1 - min_index;
339 const ushort *transformed_elts;
340 ushort *storage = NULL;
341 boolean ok = FALSE;
342
343
344 if (0) debug_printf("fetch_count %d fetch_max %d draw_count %d\n", fetch_count,
345 vcache->fetch_max,
346 draw_count);
347
348 if (max_index == 0xffffffff ||
349 fetch_count > draw_count) {
350 if (0) debug_printf("fail\n");
351 goto fail;
352 }
353
354 if (vcache->middle_prim != vcache->input_prim) {
355 vcache->middle_prim = vcache->input_prim;
356 vcache->middle->prepare( vcache->middle,
357 vcache->middle_prim,
358 vcache->opt,
359 &vcache->fetch_max );
360 }
361
362
363 if (min_index == 0 &&
364 index_size == 2)
365 {
366 transformed_elts = (const ushort *)elts;
367 }
368 else
369 {
370 storage = MALLOC( draw_count * sizeof(ushort) );
371 if (!storage)
372 goto fail;
373
374 if (min_index == 0) {
375 switch(index_size) {
376 case 1:
377 translate_ubyte_elts( (const ubyte *)elts,
378 draw_count,
379 storage );
380 break;
381
382 case 2:
383 translate_ushort_elts( (const ushort *)elts,
384 draw_count,
385 storage );
386 break;
387
388 case 4:
389 translate_uint_elts( (const uint *)elts,
390 draw_count,
391 storage );
392 break;
393
394 default:
395 assert(0);
396 return;
397 }
398 }
399 else {
400 switch(index_size) {
401 case 1:
402 rebase_ubyte_elts( (const ubyte *)elts,
403 draw_count,
404 0 - (int)min_index,
405 storage );
406 break;
407
408 case 2:
409 rebase_ushort_elts( (const ushort *)elts,
410 draw_count,
411 0 - (int)min_index,
412 storage );
413 break;
414
415 case 4:
416 rebase_uint_elts( (const uint *)elts,
417 draw_count,
418 0 - (int)min_index,
419 storage );
420 break;
421
422 default:
423 assert(0);
424 return;
425 }
426 }
427 transformed_elts = storage;
428 }
429
430 if (fetch_count < UNDEFINED_VERTEX_ID)
431 ok = vcache->middle->run_linear_elts( vcache->middle,
432 min_index, /* start */
433 fetch_count,
434 transformed_elts,
435 draw_count );
436
437 FREE(storage);
438
439 if (ok)
440 return;
441
442 debug_printf("failed to execute atomic draw elts for %d/%d, splitting up\n",
443 fetch_count, draw_count);
444
445 fail:
446 vcache_run( frontend, get_elt, elts, draw_count );
447 }
448
449
450
451
452 static void
453 vcache_prepare( struct draw_pt_front_end *frontend,
454 unsigned prim,
455 struct draw_pt_middle_end *middle,
456 unsigned opt )
457 {
458 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
459
460 if (opt & PT_PIPELINE)
461 {
462 vcache->base.run = vcache_run_extras;
463 }
464 else
465 {
466 vcache->base.run = vcache_check_run;
467 }
468
469 vcache->input_prim = prim;
470 vcache->output_prim = draw_pt_reduced_prim(prim);
471
472 vcache->middle = middle;
473 vcache->opt = opt;
474
475 /* Have to run prepare here, but try and guess a good prim for
476 * doing so:
477 */
478 vcache->middle_prim = (opt & PT_PIPELINE) ? vcache->output_prim : vcache->input_prim;
479 middle->prepare( middle, vcache->middle_prim, opt, &vcache->fetch_max );
480 }
481
482
483
484
485 static void
486 vcache_finish( struct draw_pt_front_end *frontend )
487 {
488 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
489 vcache->middle->finish( vcache->middle );
490 vcache->middle = NULL;
491 }
492
493 static void
494 vcache_destroy( struct draw_pt_front_end *frontend )
495 {
496 FREE(frontend);
497 }
498
499
500 struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw )
501 {
502 struct vcache_frontend *vcache = CALLOC_STRUCT( vcache_frontend );
503 if (vcache == NULL)
504 return NULL;
505
506 vcache->base.prepare = vcache_prepare;
507 vcache->base.run = NULL;
508 vcache->base.finish = vcache_finish;
509 vcache->base.destroy = vcache_destroy;
510 vcache->draw = draw;
511
512 memset(vcache->in, ~0, sizeof(vcache->in));
513
514 return &vcache->base;
515 }