llvmpipe: use opcodes instead of function pointers in bins
[mesa.git] / src / gallium / drivers / llvmpipe / lp_setup_vbuf.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 * Interface between 'draw' module's output and the llvmpipe rasterizer/setup
30 * code. When the 'draw' module has finished filling a vertex buffer, the
31 * draw_arrays() functions below will be called. Loop over the vertices and
32 * call the point/line/tri setup functions.
33 *
34 * Authors
35 * Brian Paul
36 */
37
38
39 #include "lp_setup_context.h"
40 #include "draw/draw_vbuf.h"
41 #include "draw/draw_vertex.h"
42 #include "util/u_memory.h"
43
44
45 #define LP_MAX_VBUF_INDEXES 1024
46 #define LP_MAX_VBUF_SIZE 4096
47
48
49
50 /** cast wrapper */
51 static struct lp_setup_context *
52 lp_setup_context(struct vbuf_render *vbr)
53 {
54 return (struct lp_setup_context *) vbr;
55 }
56
57
58
59 static const struct vertex_info *
60 lp_setup_get_vertex_info(struct vbuf_render *vbr)
61 {
62 struct lp_setup_context *setup = lp_setup_context(vbr);
63
64 /* Vertex size/info depends on the latest state.
65 * The draw module may have issued additional state-change commands.
66 */
67 lp_setup_update_state(setup, FALSE);
68
69 return setup->vertex_info;
70 }
71
72
73 static boolean
74 lp_setup_allocate_vertices(struct vbuf_render *vbr,
75 ushort vertex_size, ushort nr_vertices)
76 {
77 struct lp_setup_context *setup = lp_setup_context(vbr);
78 unsigned size = vertex_size * nr_vertices;
79
80 if (setup->vertex_buffer_size < size) {
81 align_free(setup->vertex_buffer);
82 setup->vertex_buffer = align_malloc(size, 16);
83 setup->vertex_buffer_size = size;
84 }
85
86 setup->vertex_size = vertex_size;
87 setup->nr_vertices = nr_vertices;
88
89 return setup->vertex_buffer != NULL;
90 }
91
92 static void
93 lp_setup_release_vertices(struct vbuf_render *vbr)
94 {
95 /* keep the old allocation for next time */
96 }
97
98 static void *
99 lp_setup_map_vertices(struct vbuf_render *vbr)
100 {
101 struct lp_setup_context *setup = lp_setup_context(vbr);
102 return setup->vertex_buffer;
103 }
104
105 static void
106 lp_setup_unmap_vertices(struct vbuf_render *vbr,
107 ushort min_index,
108 ushort max_index )
109 {
110 struct lp_setup_context *setup = lp_setup_context(vbr);
111 assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
112 /* do nothing */
113 }
114
115
116 static boolean
117 lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
118 {
119 lp_setup_context(vbr)->prim = prim;
120 return TRUE;
121 }
122
123 typedef const float (*const_float4_ptr)[4];
124
125 static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
126 int index,
127 int stride )
128 {
129 return (const_float4_ptr)((char *)vertex_buffer + index * stride);
130 }
131
132 /**
133 * draw elements / indexed primitives
134 */
135 static void
136 lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
137 {
138 struct lp_setup_context *setup = lp_setup_context(vbr);
139 const unsigned stride = setup->vertex_info->size * sizeof(float);
140 const void *vertex_buffer = setup->vertex_buffer;
141 const boolean flatshade_first = setup->flatshade_first;
142 unsigned i;
143
144 lp_setup_update_state(setup, TRUE);
145
146 switch (setup->prim) {
147 case PIPE_PRIM_POINTS:
148 for (i = 0; i < nr; i++) {
149 setup->point( setup,
150 get_vert(vertex_buffer, indices[i-0], stride) );
151 }
152 break;
153
154 case PIPE_PRIM_LINES:
155 for (i = 1; i < nr; i += 2) {
156 setup->line( setup,
157 get_vert(vertex_buffer, indices[i-1], stride),
158 get_vert(vertex_buffer, indices[i-0], stride) );
159 }
160 break;
161
162 case PIPE_PRIM_LINE_STRIP:
163 for (i = 1; i < nr; i ++) {
164 setup->line( setup,
165 get_vert(vertex_buffer, indices[i-1], stride),
166 get_vert(vertex_buffer, indices[i-0], stride) );
167 }
168 break;
169
170 case PIPE_PRIM_LINE_LOOP:
171 for (i = 1; i < nr; i ++) {
172 setup->line( setup,
173 get_vert(vertex_buffer, indices[i-1], stride),
174 get_vert(vertex_buffer, indices[i-0], stride) );
175 }
176 if (nr) {
177 setup->line( setup,
178 get_vert(vertex_buffer, indices[nr-1], stride),
179 get_vert(vertex_buffer, indices[0], stride) );
180 }
181 break;
182
183 case PIPE_PRIM_TRIANGLES:
184 for (i = 2; i < nr; i += 3) {
185 setup->triangle( setup,
186 get_vert(vertex_buffer, indices[i-2], stride),
187 get_vert(vertex_buffer, indices[i-1], stride),
188 get_vert(vertex_buffer, indices[i-0], stride) );
189 }
190 break;
191
192 case PIPE_PRIM_TRIANGLE_STRIP:
193 if (flatshade_first) {
194 for (i = 2; i < nr; i += 1) {
195 /* emit first triangle vertex as first triangle vertex */
196 setup->triangle( setup,
197 get_vert(vertex_buffer, indices[i-2], stride),
198 get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
199 get_vert(vertex_buffer, indices[i-(i&1)], stride) );
200
201 }
202 }
203 else {
204 for (i = 2; i < nr; i += 1) {
205 /* emit last triangle vertex as last triangle vertex */
206 setup->triangle( setup,
207 get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
208 get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
209 get_vert(vertex_buffer, indices[i-0], stride) );
210 }
211 }
212 break;
213
214 case PIPE_PRIM_TRIANGLE_FAN:
215 if (flatshade_first) {
216 for (i = 2; i < nr; i += 1) {
217 /* emit first non-spoke vertex as first vertex */
218 setup->triangle( setup,
219 get_vert(vertex_buffer, indices[i-1], stride),
220 get_vert(vertex_buffer, indices[i-0], stride),
221 get_vert(vertex_buffer, indices[0], stride) );
222 }
223 }
224 else {
225 for (i = 2; i < nr; i += 1) {
226 /* emit last non-spoke vertex as last vertex */
227 setup->triangle( setup,
228 get_vert(vertex_buffer, indices[0], stride),
229 get_vert(vertex_buffer, indices[i-1], stride),
230 get_vert(vertex_buffer, indices[i-0], stride) );
231 }
232 }
233 break;
234
235 case PIPE_PRIM_QUADS:
236 /* GL quads don't follow provoking vertex convention */
237 if (flatshade_first) {
238 /* emit last quad vertex as first triangle vertex */
239 for (i = 3; i < nr; i += 4) {
240 setup->triangle( setup,
241 get_vert(vertex_buffer, indices[i-0], stride),
242 get_vert(vertex_buffer, indices[i-3], stride),
243 get_vert(vertex_buffer, indices[i-2], stride) );
244
245 setup->triangle( setup,
246 get_vert(vertex_buffer, indices[i-0], stride),
247 get_vert(vertex_buffer, indices[i-2], stride),
248 get_vert(vertex_buffer, indices[i-1], stride) );
249 }
250 }
251 else {
252 /* emit last quad vertex as last triangle vertex */
253 for (i = 3; i < nr; i += 4) {
254 setup->triangle( setup,
255 get_vert(vertex_buffer, indices[i-3], stride),
256 get_vert(vertex_buffer, indices[i-2], stride),
257 get_vert(vertex_buffer, indices[i-0], stride) );
258
259 setup->triangle( setup,
260 get_vert(vertex_buffer, indices[i-2], stride),
261 get_vert(vertex_buffer, indices[i-1], stride),
262 get_vert(vertex_buffer, indices[i-0], stride) );
263 }
264 }
265 break;
266
267 case PIPE_PRIM_QUAD_STRIP:
268 /* GL quad strips don't follow provoking vertex convention */
269 if (flatshade_first) {
270 /* emit last quad vertex as first triangle vertex */
271 for (i = 3; i < nr; i += 2) {
272 setup->triangle( setup,
273 get_vert(vertex_buffer, indices[i-0], stride),
274 get_vert(vertex_buffer, indices[i-3], stride),
275 get_vert(vertex_buffer, indices[i-2], stride) );
276 setup->triangle( setup,
277 get_vert(vertex_buffer, indices[i-0], stride),
278 get_vert(vertex_buffer, indices[i-1], stride),
279 get_vert(vertex_buffer, indices[i-3], stride) );
280 }
281 }
282 else {
283 /* emit last quad vertex as last triangle vertex */
284 for (i = 3; i < nr; i += 2) {
285 setup->triangle( setup,
286 get_vert(vertex_buffer, indices[i-3], stride),
287 get_vert(vertex_buffer, indices[i-2], stride),
288 get_vert(vertex_buffer, indices[i-0], stride) );
289 setup->triangle( setup,
290 get_vert(vertex_buffer, indices[i-1], stride),
291 get_vert(vertex_buffer, indices[i-3], stride),
292 get_vert(vertex_buffer, indices[i-0], stride) );
293 }
294 }
295 break;
296
297 case PIPE_PRIM_POLYGON:
298 /* Almost same as tri fan but the _first_ vertex specifies the flat
299 * shading color.
300 */
301 if (flatshade_first) {
302 /* emit first polygon vertex as first triangle vertex */
303 for (i = 2; i < nr; i += 1) {
304 setup->triangle( setup,
305 get_vert(vertex_buffer, indices[0], stride),
306 get_vert(vertex_buffer, indices[i-1], stride),
307 get_vert(vertex_buffer, indices[i-0], stride) );
308 }
309 }
310 else {
311 /* emit first polygon vertex as last triangle vertex */
312 for (i = 2; i < nr; i += 1) {
313 setup->triangle( setup,
314 get_vert(vertex_buffer, indices[i-1], stride),
315 get_vert(vertex_buffer, indices[i-0], stride),
316 get_vert(vertex_buffer, indices[0], stride) );
317 }
318 }
319 break;
320
321 default:
322 assert(0);
323 }
324 }
325
326
327 /**
328 * This function is hit when the draw module is working in pass-through mode.
329 * It's up to us to convert the vertex array into point/line/tri prims.
330 */
331 static void
332 lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
333 {
334 struct lp_setup_context *setup = lp_setup_context(vbr);
335 const unsigned stride = setup->vertex_info->size * sizeof(float);
336 const void *vertex_buffer =
337 (void *) get_vert(setup->vertex_buffer, start, stride);
338 const boolean flatshade_first = setup->flatshade_first;
339 unsigned i;
340
341 lp_setup_update_state(setup, TRUE);
342
343 switch (setup->prim) {
344 case PIPE_PRIM_POINTS:
345 for (i = 0; i < nr; i++) {
346 setup->point( setup,
347 get_vert(vertex_buffer, i-0, stride) );
348 }
349 break;
350
351 case PIPE_PRIM_LINES:
352 for (i = 1; i < nr; i += 2) {
353 setup->line( setup,
354 get_vert(vertex_buffer, i-1, stride),
355 get_vert(vertex_buffer, i-0, stride) );
356 }
357 break;
358
359 case PIPE_PRIM_LINE_STRIP:
360 for (i = 1; i < nr; i ++) {
361 setup->line( setup,
362 get_vert(vertex_buffer, i-1, stride),
363 get_vert(vertex_buffer, i-0, stride) );
364 }
365 break;
366
367 case PIPE_PRIM_LINE_LOOP:
368 for (i = 1; i < nr; i ++) {
369 setup->line( setup,
370 get_vert(vertex_buffer, i-1, stride),
371 get_vert(vertex_buffer, i-0, stride) );
372 }
373 if (nr) {
374 setup->line( setup,
375 get_vert(vertex_buffer, nr-1, stride),
376 get_vert(vertex_buffer, 0, stride) );
377 }
378 break;
379
380 case PIPE_PRIM_TRIANGLES:
381 for (i = 2; i < nr; i += 3) {
382 setup->triangle( setup,
383 get_vert(vertex_buffer, i-2, stride),
384 get_vert(vertex_buffer, i-1, stride),
385 get_vert(vertex_buffer, i-0, stride) );
386 }
387 break;
388
389 case PIPE_PRIM_TRIANGLE_STRIP:
390 if (flatshade_first) {
391 for (i = 2; i < nr; i++) {
392 /* emit first triangle vertex as first triangle vertex */
393 setup->triangle( setup,
394 get_vert(vertex_buffer, i-2, stride),
395 get_vert(vertex_buffer, i+(i&1)-1, stride),
396 get_vert(vertex_buffer, i-(i&1), stride) );
397 }
398 }
399 else {
400 for (i = 2; i < nr; i++) {
401 /* emit last triangle vertex as last triangle vertex */
402 setup->triangle( setup,
403 get_vert(vertex_buffer, i+(i&1)-2, stride),
404 get_vert(vertex_buffer, i-(i&1)-1, stride),
405 get_vert(vertex_buffer, i-0, stride) );
406 }
407 }
408 break;
409
410 case PIPE_PRIM_TRIANGLE_FAN:
411 if (flatshade_first) {
412 for (i = 2; i < nr; i += 1) {
413 /* emit first non-spoke vertex as first vertex */
414 setup->triangle( setup,
415 get_vert(vertex_buffer, i-1, stride),
416 get_vert(vertex_buffer, i-0, stride),
417 get_vert(vertex_buffer, 0, stride) );
418 }
419 }
420 else {
421 for (i = 2; i < nr; i += 1) {
422 /* emit last non-spoke vertex as last vertex */
423 setup->triangle( setup,
424 get_vert(vertex_buffer, 0, stride),
425 get_vert(vertex_buffer, i-1, stride),
426 get_vert(vertex_buffer, i-0, stride) );
427 }
428 }
429 break;
430
431 case PIPE_PRIM_QUADS:
432 /* GL quads don't follow provoking vertex convention */
433 if (flatshade_first) {
434 /* emit last quad vertex as first triangle vertex */
435 for (i = 3; i < nr; i += 4) {
436 setup->triangle( setup,
437 get_vert(vertex_buffer, i-0, stride),
438 get_vert(vertex_buffer, i-3, stride),
439 get_vert(vertex_buffer, i-2, stride) );
440 setup->triangle( setup,
441 get_vert(vertex_buffer, i-0, stride),
442 get_vert(vertex_buffer, i-2, stride),
443 get_vert(vertex_buffer, i-1, stride) );
444 }
445 }
446 else {
447 /* emit last quad vertex as last triangle vertex */
448 for (i = 3; i < nr; i += 4) {
449 setup->triangle( setup,
450 get_vert(vertex_buffer, i-3, stride),
451 get_vert(vertex_buffer, i-2, stride),
452 get_vert(vertex_buffer, i-0, stride) );
453 setup->triangle( setup,
454 get_vert(vertex_buffer, i-2, stride),
455 get_vert(vertex_buffer, i-1, stride),
456 get_vert(vertex_buffer, i-0, stride) );
457 }
458 }
459 break;
460
461 case PIPE_PRIM_QUAD_STRIP:
462 /* GL quad strips don't follow provoking vertex convention */
463 if (flatshade_first) {
464 /* emit last quad vertex as first triangle vertex */
465 for (i = 3; i < nr; i += 2) {
466 setup->triangle( setup,
467 get_vert(vertex_buffer, i-0, stride),
468 get_vert(vertex_buffer, i-3, stride),
469 get_vert(vertex_buffer, i-2, stride) );
470 setup->triangle( setup,
471 get_vert(vertex_buffer, i-0, stride),
472 get_vert(vertex_buffer, i-1, stride),
473 get_vert(vertex_buffer, i-3, stride) );
474 }
475 }
476 else {
477 /* emit last quad vertex as last triangle vertex */
478 for (i = 3; i < nr; i += 2) {
479 setup->triangle( setup,
480 get_vert(vertex_buffer, i-3, stride),
481 get_vert(vertex_buffer, i-2, stride),
482 get_vert(vertex_buffer, i-0, stride) );
483 setup->triangle( setup,
484 get_vert(vertex_buffer, i-1, stride),
485 get_vert(vertex_buffer, i-3, stride),
486 get_vert(vertex_buffer, i-0, stride) );
487 }
488 }
489 break;
490
491 case PIPE_PRIM_POLYGON:
492 /* Almost same as tri fan but the _first_ vertex specifies the flat
493 * shading color.
494 */
495 if (flatshade_first) {
496 /* emit first polygon vertex as first triangle vertex */
497 for (i = 2; i < nr; i += 1) {
498 setup->triangle( setup,
499 get_vert(vertex_buffer, 0, stride),
500 get_vert(vertex_buffer, i-1, stride),
501 get_vert(vertex_buffer, i-0, stride) );
502 }
503 }
504 else {
505 /* emit first polygon vertex as last triangle vertex */
506 for (i = 2; i < nr; i += 1) {
507 setup->triangle( setup,
508 get_vert(vertex_buffer, i-1, stride),
509 get_vert(vertex_buffer, i-0, stride),
510 get_vert(vertex_buffer, 0, stride) );
511 }
512 }
513 break;
514
515 default:
516 assert(0);
517 }
518 }
519
520
521
522 static void
523 lp_setup_vbuf_destroy(struct vbuf_render *vbr)
524 {
525 struct lp_setup_context *setup = lp_setup_context(vbr);
526 if (setup->vertex_buffer) {
527 align_free(setup->vertex_buffer);
528 setup->vertex_buffer = NULL;
529 }
530 lp_setup_destroy(setup);
531 }
532
533
534 /**
535 * Create the post-transform vertex handler for the given context.
536 */
537 void
538 lp_setup_init_vbuf(struct lp_setup_context *setup)
539 {
540 setup->base.max_indices = LP_MAX_VBUF_INDEXES;
541 setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
542
543 setup->base.get_vertex_info = lp_setup_get_vertex_info;
544 setup->base.allocate_vertices = lp_setup_allocate_vertices;
545 setup->base.map_vertices = lp_setup_map_vertices;
546 setup->base.unmap_vertices = lp_setup_unmap_vertices;
547 setup->base.set_primitive = lp_setup_set_primitive;
548 setup->base.draw_elements = lp_setup_draw_elements;
549 setup->base.draw_arrays = lp_setup_draw_arrays;
550 setup->base.release_vertices = lp_setup_release_vertices;
551 setup->base.destroy = lp_setup_vbuf_destroy;
552 }