Merge branch 'mesa_7_7_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 >= DRAW_PIPE_MAX_VERTICES ||
350 fetch_count >= UNDEFINED_VERTEX_ID ||
351 fetch_count > draw_count) {
352 if (0) debug_printf("fail\n");
353 goto fail;
354 }
355
356 if (vcache->middle_prim != vcache->input_prim) {
357 vcache->middle_prim = vcache->input_prim;
358 vcache->middle->prepare( vcache->middle,
359 vcache->middle_prim,
360 vcache->opt,
361 &vcache->fetch_max );
362 }
363
364
365 if (min_index == 0 &&
366 index_size == 2)
367 {
368 transformed_elts = (const ushort *)elts;
369 }
370 else
371 {
372 storage = MALLOC( draw_count * sizeof(ushort) );
373 if (!storage)
374 goto fail;
375
376 if (min_index == 0) {
377 switch(index_size) {
378 case 1:
379 translate_ubyte_elts( (const ubyte *)elts,
380 draw_count,
381 storage );
382 break;
383
384 case 2:
385 translate_ushort_elts( (const ushort *)elts,
386 draw_count,
387 storage );
388 break;
389
390 case 4:
391 translate_uint_elts( (const uint *)elts,
392 draw_count,
393 storage );
394 break;
395
396 default:
397 assert(0);
398 FREE(storage);
399 return;
400 }
401 }
402 else {
403 switch(index_size) {
404 case 1:
405 rebase_ubyte_elts( (const ubyte *)elts,
406 draw_count,
407 0 - (int)min_index,
408 storage );
409 break;
410
411 case 2:
412 rebase_ushort_elts( (const ushort *)elts,
413 draw_count,
414 0 - (int)min_index,
415 storage );
416 break;
417
418 case 4:
419 rebase_uint_elts( (const uint *)elts,
420 draw_count,
421 0 - (int)min_index,
422 storage );
423 break;
424
425 default:
426 assert(0);
427 FREE(storage);
428 return;
429 }
430 }
431 transformed_elts = storage;
432 }
433
434 if (fetch_count < UNDEFINED_VERTEX_ID)
435 ok = vcache->middle->run_linear_elts( vcache->middle,
436 min_index, /* start */
437 fetch_count,
438 transformed_elts,
439 draw_count );
440
441 FREE(storage);
442
443 if (ok)
444 return;
445
446 debug_printf("failed to execute atomic draw elts for %d/%d, splitting up\n",
447 fetch_count, draw_count);
448
449 fail:
450 vcache_run( frontend, get_elt, elts, draw_count );
451 }
452
453
454
455
456 static void
457 vcache_prepare( struct draw_pt_front_end *frontend,
458 unsigned prim,
459 struct draw_pt_middle_end *middle,
460 unsigned opt )
461 {
462 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
463
464 if (opt & PT_PIPELINE)
465 {
466 vcache->base.run = vcache_run_extras;
467 }
468 else
469 {
470 vcache->base.run = vcache_check_run;
471 }
472
473 vcache->input_prim = prim;
474 vcache->output_prim = u_reduced_prim(prim);
475
476 vcache->middle = middle;
477 vcache->opt = opt;
478
479 /* Have to run prepare here, but try and guess a good prim for
480 * doing so:
481 */
482 vcache->middle_prim = (opt & PT_PIPELINE) ? vcache->output_prim : vcache->input_prim;
483 middle->prepare( middle, vcache->middle_prim, opt, &vcache->fetch_max );
484 }
485
486
487
488
489 static void
490 vcache_finish( struct draw_pt_front_end *frontend )
491 {
492 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
493 vcache->middle->finish( vcache->middle );
494 vcache->middle = NULL;
495 }
496
497 static void
498 vcache_destroy( struct draw_pt_front_end *frontend )
499 {
500 FREE(frontend);
501 }
502
503
504 struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw )
505 {
506 struct vcache_frontend *vcache = CALLOC_STRUCT( vcache_frontend );
507 if (vcache == NULL)
508 return NULL;
509
510 vcache->base.prepare = vcache_prepare;
511 vcache->base.run = NULL;
512 vcache->base.finish = vcache_finish;
513 vcache->base.destroy = vcache_destroy;
514 vcache->draw = draw;
515
516 memset(vcache->in, ~0, sizeof(vcache->in));
517
518 return &vcache->base;
519 }