Merge commit 'origin/gallium-master-merge'
[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 vcache_triangle_flags( vcache,
197 ( DRAW_PIPE_RESET_STIPPLE |
198 DRAW_PIPE_EDGE_FLAG_0 |
199 DRAW_PIPE_EDGE_FLAG_2 ),
200 i0, i1, i3 );
201
202 vcache_triangle_flags( vcache,
203 ( DRAW_PIPE_EDGE_FLAG_0 |
204 DRAW_PIPE_EDGE_FLAG_1 ),
205 i1, i2, i3 );
206 }
207
208 /* At least for now, we're back to using a template include file for
209 * this. The two paths aren't too different though - it may be
210 * possible to reunify them.
211 */
212 #define TRIANGLE(vc,flags,i0,i1,i2) vcache_triangle_flags(vc,flags,i0,i1,i2)
213 #define QUAD(vc,i0,i1,i2,i3) vcache_ef_quad(vc,i0,i1,i2,i3)
214 #define LINE(vc,flags,i0,i1) vcache_line_flags(vc,flags,i0,i1)
215 #define POINT(vc,i0) vcache_point(vc,i0)
216 #define FUNC vcache_run_extras
217 #include "draw_pt_vcache_tmp.h"
218
219 #define TRIANGLE(vc,flags,i0,i1,i2) vcache_triangle(vc,i0,i1,i2)
220 #define QUAD(vc,i0,i1,i2,i3) vcache_quad(vc,i0,i1,i2,i3)
221 #define LINE(vc,flags,i0,i1) vcache_line(vc,i0,i1)
222 #define POINT(vc,i0) vcache_point(vc,i0)
223 #define FUNC vcache_run
224 #include "draw_pt_vcache_tmp.h"
225
226 static INLINE void
227 rebase_uint_elts( const unsigned *src,
228 unsigned count,
229 int delta,
230 ushort *dest )
231 {
232 unsigned i;
233
234 for (i = 0; i < count; i++)
235 dest[i] = (ushort)(src[i] + delta);
236 }
237
238 static INLINE void
239 rebase_ushort_elts( const ushort *src,
240 unsigned count,
241 int delta,
242 ushort *dest )
243 {
244 unsigned i;
245
246 for (i = 0; i < count; i++)
247 dest[i] = (ushort)(src[i] + delta);
248 }
249
250 static INLINE void
251 rebase_ubyte_elts( const ubyte *src,
252 unsigned count,
253 int delta,
254 ushort *dest )
255 {
256 unsigned i;
257
258 for (i = 0; i < count; i++)
259 dest[i] = (ushort)(src[i] + delta);
260 }
261
262
263
264 static INLINE void
265 translate_uint_elts( const unsigned *src,
266 unsigned count,
267 ushort *dest )
268 {
269 unsigned i;
270
271 for (i = 0; i < count; i++)
272 dest[i] = (ushort)(src[i]);
273 }
274
275 static INLINE void
276 translate_ushort_elts( const ushort *src,
277 unsigned count,
278 ushort *dest )
279 {
280 unsigned i;
281
282 for (i = 0; i < count; i++)
283 dest[i] = (ushort)(src[i]);
284 }
285
286 static INLINE void
287 translate_ubyte_elts( const ubyte *src,
288 unsigned count,
289 ushort *dest )
290 {
291 unsigned i;
292
293 for (i = 0; i < count; i++)
294 dest[i] = (ushort)(src[i]);
295 }
296
297
298
299
300 #if 0
301 static INLINE enum pipe_format
302 format_from_get_elt( pt_elt_func get_elt )
303 {
304 switch (draw->pt.user.eltSize) {
305 case 1: return PIPE_FORMAT_R8_UNORM;
306 case 2: return PIPE_FORMAT_R16_UNORM;
307 case 4: return PIPE_FORMAT_R32_UNORM;
308 default: return PIPE_FORMAT_NONE;
309 }
310 }
311 #endif
312
313 static INLINE void
314 vcache_check_run( struct draw_pt_front_end *frontend,
315 pt_elt_func get_elt,
316 const void *elts,
317 unsigned draw_count )
318 {
319 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
320 struct draw_context *draw = vcache->draw;
321 unsigned min_index = draw->pt.user.min_index;
322 unsigned max_index = draw->pt.user.max_index;
323 unsigned index_size = draw->pt.user.eltSize;
324 unsigned fetch_count = max_index + 1 - min_index;
325 const ushort *transformed_elts;
326 ushort *storage = NULL;
327 boolean ok = FALSE;
328
329
330 if (0) debug_printf("fetch_count %d fetch_max %d draw_count %d\n", fetch_count,
331 vcache->fetch_max,
332 draw_count);
333
334 if (max_index == 0xffffffff ||
335 fetch_count > draw_count) {
336 if (0) debug_printf("fail\n");
337 goto fail;
338 }
339
340 if (vcache->middle_prim != vcache->input_prim) {
341 vcache->middle_prim = vcache->input_prim;
342 vcache->middle->prepare( vcache->middle,
343 vcache->middle_prim,
344 vcache->opt,
345 &vcache->fetch_max );
346 }
347
348
349 if (min_index == 0 &&
350 index_size == 2)
351 {
352 transformed_elts = (const ushort *)elts;
353 }
354 else
355 {
356 storage = MALLOC( draw_count * sizeof(ushort) );
357 if (!storage)
358 goto fail;
359
360 if (min_index == 0) {
361 switch(index_size) {
362 case 1:
363 translate_ubyte_elts( (const ubyte *)elts,
364 draw_count,
365 storage );
366 break;
367
368 case 2:
369 translate_ushort_elts( (const ushort *)elts,
370 draw_count,
371 storage );
372 break;
373
374 case 4:
375 translate_uint_elts( (const uint *)elts,
376 draw_count,
377 storage );
378 break;
379
380 default:
381 assert(0);
382 return;
383 }
384 }
385 else {
386 switch(index_size) {
387 case 1:
388 rebase_ubyte_elts( (const ubyte *)elts,
389 draw_count,
390 0 - (int)min_index,
391 storage );
392 break;
393
394 case 2:
395 rebase_ushort_elts( (const ushort *)elts,
396 draw_count,
397 0 - (int)min_index,
398 storage );
399 break;
400
401 case 4:
402 rebase_uint_elts( (const uint *)elts,
403 draw_count,
404 0 - (int)min_index,
405 storage );
406 break;
407
408 default:
409 assert(0);
410 return;
411 }
412 }
413 transformed_elts = storage;
414 }
415
416 if (fetch_count < UNDEFINED_VERTEX_ID)
417 ok = vcache->middle->run_linear_elts( vcache->middle,
418 min_index, /* start */
419 fetch_count,
420 transformed_elts,
421 draw_count );
422
423 FREE(storage);
424
425 if (ok)
426 return;
427
428 debug_printf("failed to execute atomic draw elts for %d/%d, splitting up\n",
429 fetch_count, draw_count);
430
431 fail:
432 vcache_run( frontend, get_elt, elts, draw_count );
433 }
434
435
436
437
438 static void
439 vcache_prepare( struct draw_pt_front_end *frontend,
440 unsigned prim,
441 struct draw_pt_middle_end *middle,
442 unsigned opt )
443 {
444 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
445
446 if (opt & PT_PIPELINE)
447 {
448 vcache->base.run = vcache_run_extras;
449 }
450 else
451 {
452 vcache->base.run = vcache_check_run;
453 }
454
455 vcache->input_prim = prim;
456 vcache->output_prim = draw_pt_reduced_prim(prim);
457
458 vcache->middle = middle;
459 vcache->opt = opt;
460
461 /* Have to run prepare here, but try and guess a good prim for
462 * doing so:
463 */
464 vcache->middle_prim = (opt & PT_PIPELINE) ? vcache->output_prim : vcache->input_prim;
465 middle->prepare( middle, vcache->middle_prim, opt, &vcache->fetch_max );
466 }
467
468
469
470
471 static void
472 vcache_finish( struct draw_pt_front_end *frontend )
473 {
474 struct vcache_frontend *vcache = (struct vcache_frontend *)frontend;
475 vcache->middle->finish( vcache->middle );
476 vcache->middle = NULL;
477 }
478
479 static void
480 vcache_destroy( struct draw_pt_front_end *frontend )
481 {
482 FREE(frontend);
483 }
484
485
486 struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw )
487 {
488 struct vcache_frontend *vcache = CALLOC_STRUCT( vcache_frontend );
489 if (vcache == NULL)
490 return NULL;
491
492 vcache->base.prepare = vcache_prepare;
493 vcache->base.run = NULL;
494 vcache->base.finish = vcache_finish;
495 vcache->base.destroy = vcache_destroy;
496 vcache->draw = draw;
497
498 memset(vcache->in, ~0, sizeof(vcache->in));
499
500 return &vcache->base;
501 }