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