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