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