Merge branch 'new-frag-attribs'
[mesa.git] / src / gallium / drivers / i915simple / i915_prim_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 * \file
30 * Build post-transformation, post-clipping vertex buffers and element
31 * lists by hooking into the end of the primitive pipeline and
32 * manipulating the vertex_id field in the vertex headers.
33 *
34 * XXX: work in progress
35 *
36 * \author José Fonseca <jrfonseca@tungstengraphics.com>
37 * \author Keith Whitwell <keith@tungstengraphics.com>
38 */
39
40
41 #include "draw/draw_context.h"
42 #include "draw/draw_vbuf.h"
43 #include "util/u_debug.h"
44 #include "pipe/p_inlines.h"
45 #include "pipe/internal/p_winsys_screen.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
48
49 #include "i915_context.h"
50 #include "i915_reg.h"
51 #include "i915_winsys.h"
52 #include "i915_batch.h"
53 #include "i915_state.h"
54
55
56 /**
57 * Primitive renderer for i915.
58 */
59 struct i915_vbuf_render {
60 struct vbuf_render base;
61
62 struct i915_context *i915;
63
64 /** Vertex size in bytes */
65 size_t vertex_size;
66
67 /** Software primitive */
68 unsigned prim;
69
70 /** Hardware primitive */
71 unsigned hwprim;
72
73 /** Genereate a vertex list */
74 unsigned fallback;
75
76 /* Stuff for the vbo */
77 struct pipe_buffer *vbo;
78 size_t vbo_size;
79 size_t vbo_offset;
80 void *vbo_ptr;
81 size_t vbo_alloc_size;
82 size_t vbo_max_used;
83 };
84
85
86 /**
87 * Basically a cast wrapper.
88 */
89 static INLINE struct i915_vbuf_render *
90 i915_vbuf_render( struct vbuf_render *render )
91 {
92 assert(render);
93 return (struct i915_vbuf_render *)render;
94 }
95
96
97 static const struct vertex_info *
98 i915_vbuf_render_get_vertex_info( struct vbuf_render *render )
99 {
100 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
101 struct i915_context *i915 = i915_render->i915;
102
103 if (i915->dirty) {
104 /* make sure we have up to date vertex layout */
105 i915_update_derived( i915 );
106 }
107
108 return &i915->current.vertex_info;
109 }
110
111
112 static boolean
113 i915_vbuf_render_allocate_vertices( struct vbuf_render *render,
114 ushort vertex_size,
115 ushort nr_vertices )
116 {
117 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
118 struct i915_context *i915 = i915_render->i915;
119 struct pipe_screen *screen = i915->pipe.screen;
120 size_t size = (size_t)vertex_size * (size_t)nr_vertices;
121
122 /* FIXME: handle failure */
123 assert(!i915->vbo);
124
125 if (i915_render->vbo_size > size + i915_render->vbo_offset && !i915->vbo_flushed) {
126 } else {
127 i915->vbo_flushed = 0;
128 if (i915_render->vbo)
129 pipe_buffer_reference(&i915_render->vbo, NULL);
130 }
131
132 if (!i915_render->vbo) {
133 i915_render->vbo_size = MAX2(size, i915_render->vbo_alloc_size);
134 i915_render->vbo_offset = 0;
135 i915_render->vbo = pipe_buffer_create(screen,
136 64,
137 I915_BUFFER_USAGE_LIT_VERTEX,
138 i915_render->vbo_size);
139
140 }
141
142 i915_render->vertex_size = vertex_size;
143 i915->vbo = i915_render->vbo;
144 i915->vbo_offset = i915_render->vbo_offset;
145 i915->dirty |= I915_NEW_VBO;
146
147 if (!i915_render->vbo)
148 return FALSE;
149 return TRUE;
150 }
151
152
153 static void *
154 i915_vbuf_render_map_vertices( struct vbuf_render *render )
155 {
156 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
157 struct i915_context *i915 = i915_render->i915;
158 struct pipe_screen *screen = i915->pipe.screen;
159
160 if (i915->vbo_flushed)
161 debug_printf("%s bad vbo flush occured stalling on hw\n");
162
163 i915_render->vbo_ptr = pipe_buffer_map(screen,
164 i915_render->vbo,
165 PIPE_BUFFER_USAGE_CPU_WRITE);
166
167 return (unsigned char *)i915_render->vbo_ptr + i915->vbo_offset;
168 }
169
170 static void
171 i915_vbuf_render_unmap_vertices( struct vbuf_render *render,
172 ushort min_index,
173 ushort max_index )
174 {
175 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
176 struct i915_context *i915 = i915_render->i915;
177 struct pipe_screen *screen = i915->pipe.screen;
178
179 i915_render->vbo_max_used = MAX2(i915_render->vbo_max_used, i915_render->vertex_size * (max_index + 1));
180 pipe_buffer_unmap(screen, i915_render->vbo);
181 }
182
183 static boolean
184 i915_vbuf_render_set_primitive( struct vbuf_render *render,
185 unsigned prim )
186 {
187 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
188 i915_render->prim = prim;
189
190 switch(prim) {
191 case PIPE_PRIM_POINTS:
192 i915_render->hwprim = PRIM3D_POINTLIST;
193 i915_render->fallback = 0;
194 return TRUE;
195 case PIPE_PRIM_LINES:
196 i915_render->hwprim = PRIM3D_LINELIST;
197 i915_render->fallback = 0;
198 return TRUE;
199 case PIPE_PRIM_LINE_LOOP:
200 i915_render->hwprim = PRIM3D_LINELIST;
201 i915_render->fallback = PIPE_PRIM_LINE_LOOP;
202 return TRUE;
203 case PIPE_PRIM_LINE_STRIP:
204 i915_render->hwprim = PRIM3D_LINESTRIP;
205 i915_render->fallback = 0;
206 return TRUE;
207 case PIPE_PRIM_TRIANGLES:
208 i915_render->hwprim = PRIM3D_TRILIST;
209 i915_render->fallback = 0;
210 return TRUE;
211 case PIPE_PRIM_TRIANGLE_STRIP:
212 i915_render->hwprim = PRIM3D_TRISTRIP;
213 i915_render->fallback = 0;
214 return TRUE;
215 case PIPE_PRIM_TRIANGLE_FAN:
216 i915_render->hwprim = PRIM3D_TRIFAN;
217 i915_render->fallback = 0;
218 return TRUE;
219 case PIPE_PRIM_QUADS:
220 i915_render->hwprim = PRIM3D_TRILIST;
221 i915_render->fallback = PIPE_PRIM_QUADS;
222 return TRUE;
223 case PIPE_PRIM_QUAD_STRIP:
224 i915_render->hwprim = PRIM3D_TRILIST;
225 i915_render->fallback = PIPE_PRIM_QUAD_STRIP;
226 return TRUE;
227 case PIPE_PRIM_POLYGON:
228 i915_render->hwprim = PRIM3D_POLY;
229 i915_render->fallback = 0;
230 return TRUE;
231 default:
232 /* FIXME: Actually, can handle a lot more just fine... */
233 return FALSE;
234 }
235 }
236
237
238
239 /**
240 * Used for fallbacks in draw_arrays
241 */
242 static void
243 draw_arrays_generate_indices( struct vbuf_render *render,
244 unsigned start, uint nr,
245 unsigned type )
246 {
247 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
248 struct i915_context *i915 = i915_render->i915;
249 unsigned i;
250 unsigned end = start + nr;
251 switch(type) {
252 case 0:
253 for (i = start; i+1 < end; i += 2)
254 OUT_BATCH( (i+0) | (i+1) << 16 );
255 if (i < end)
256 OUT_BATCH( i );
257 break;
258 case PIPE_PRIM_LINE_LOOP:
259 if (nr >= 2) {
260 for (i = start + 1; i < end; i++)
261 OUT_BATCH( (i-0) | (i+0) << 16 );
262 OUT_BATCH( (i-0) | ( start) << 16 );
263 }
264 break;
265 case PIPE_PRIM_QUADS:
266 for (i = start; i + 3 < end; i += 4) {
267 OUT_BATCH( (i+0) | (i+1) << 16 );
268 OUT_BATCH( (i+3) | (i+1) << 16 );
269 OUT_BATCH( (i+2) | (i+3) << 16 );
270 }
271 break;
272 case PIPE_PRIM_QUAD_STRIP:
273 for (i = start; i + 3 < end; i += 2) {
274 OUT_BATCH( (i+0) | (i+1) << 16 );
275 OUT_BATCH( (i+3) | (i+2) << 16 );
276 OUT_BATCH( (i+0) | (i+3) << 16 );
277 }
278 break;
279 default:
280 assert(0);
281 }
282 }
283
284 static unsigned
285 draw_arrays_calc_nr_indices( uint nr, unsigned type )
286 {
287 switch (type) {
288 case 0:
289 return nr;
290 case PIPE_PRIM_LINE_LOOP:
291 if (nr >= 2)
292 return nr * 2;
293 else
294 return 0;
295 case PIPE_PRIM_QUADS:
296 return (nr / 4) * 6;
297 case PIPE_PRIM_QUAD_STRIP:
298 return ((nr - 2) / 2) * 6;
299 default:
300 assert(0);
301 return 0;
302 }
303 }
304
305 static void
306 draw_arrays_fallback( struct vbuf_render *render,
307 unsigned start,
308 uint nr )
309 {
310 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
311 struct i915_context *i915 = i915_render->i915;
312 unsigned nr_indices;
313
314 if (i915->dirty)
315 i915_update_derived( i915 );
316
317 if (i915->hardware_dirty)
318 i915_emit_hardware_state( i915 );
319
320 nr_indices = draw_arrays_calc_nr_indices( nr, i915_render->fallback );
321 if (!nr_indices)
322 return;
323
324 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
325 FLUSH_BATCH(NULL);
326
327 /* Make sure state is re-emitted after a flush:
328 */
329 i915_update_derived( i915 );
330 i915_emit_hardware_state( i915 );
331 i915->vbo_flushed = 1;
332
333 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
334 assert(0);
335 goto out;
336 }
337 }
338 OUT_BATCH( _3DPRIMITIVE |
339 PRIM_INDIRECT |
340 i915_render->hwprim |
341 PRIM_INDIRECT_ELTS |
342 nr_indices );
343
344 draw_arrays_generate_indices( render, start, nr, i915_render->fallback );
345
346 out:
347 return;
348 }
349
350 static void
351 i915_vbuf_render_draw_arrays( struct vbuf_render *render,
352 unsigned start,
353 uint nr )
354 {
355 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
356
357 if (i915_render->fallback) {
358 draw_arrays_fallback( render, start, nr );
359 return;
360 }
361
362 /* JB: TODO submit direct cmds */
363 draw_arrays_fallback( render, start, nr );
364 }
365
366 /**
367 * Used for normal and fallback emitting of indices
368 * If type is zero normal operation assumed.
369 */
370 static void
371 draw_generate_indices( struct vbuf_render *render,
372 const ushort *indices,
373 uint nr_indices,
374 unsigned type )
375 {
376 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
377 struct i915_context *i915 = i915_render->i915;
378 unsigned i;
379
380 switch(type) {
381 case 0:
382 for (i = 0; i + 1 < nr_indices; i += 2) {
383 OUT_BATCH( indices[i] | indices[i+1] << 16 );
384 }
385 if (i < nr_indices) {
386 OUT_BATCH( indices[i] );
387 }
388 break;
389 case PIPE_PRIM_LINE_LOOP:
390 if (nr_indices >= 2) {
391 for (i = 1; i < nr_indices; i++)
392 OUT_BATCH( indices[i-1] | indices[i] << 16 );
393 OUT_BATCH( indices[i-1] | indices[0] << 16 );
394 }
395 break;
396 case PIPE_PRIM_QUADS:
397 for (i = 0; i + 3 < nr_indices; i += 4) {
398 OUT_BATCH( indices[i+0] | indices[i+1] << 16 );
399 OUT_BATCH( indices[i+3] | indices[i+1] << 16 );
400 OUT_BATCH( indices[i+2] | indices[i+3] << 16 );
401 }
402 break;
403 case PIPE_PRIM_QUAD_STRIP:
404 for (i = 0; i + 3 < nr_indices; i += 2) {
405 OUT_BATCH( indices[i+0] | indices[i+1] << 16 );
406 OUT_BATCH( indices[i+3] | indices[i+2] << 16 );
407 OUT_BATCH( indices[i+0] | indices[i+3] << 16 );
408 }
409 break;
410 default:
411 assert(0);
412 break;
413 }
414 }
415
416 static unsigned
417 draw_calc_nr_indices( uint nr_indices, unsigned type )
418 {
419 switch (type) {
420 case 0:
421 return nr_indices;
422 case PIPE_PRIM_LINE_LOOP:
423 if (nr_indices >= 2)
424 return nr_indices * 2;
425 else
426 return 0;
427 case PIPE_PRIM_QUADS:
428 return (nr_indices / 4) * 6;
429 case PIPE_PRIM_QUAD_STRIP:
430 return ((nr_indices - 2) / 2) * 6;
431 default:
432 assert(0);
433 return 0;
434 }
435 }
436
437 static void
438 i915_vbuf_render_draw( struct vbuf_render *render,
439 const ushort *indices,
440 uint nr_indices)
441 {
442 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
443 struct i915_context *i915 = i915_render->i915;
444 unsigned save_nr_indices;
445
446 save_nr_indices = nr_indices;
447
448 nr_indices = draw_calc_nr_indices( nr_indices, i915_render->fallback );
449 if (!nr_indices)
450 return;
451
452 if (i915->dirty)
453 i915_update_derived( i915 );
454
455 if (i915->hardware_dirty)
456 i915_emit_hardware_state( i915 );
457
458 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
459 FLUSH_BATCH(NULL);
460
461 /* Make sure state is re-emitted after a flush:
462 */
463 i915_update_derived( i915 );
464 i915_emit_hardware_state( i915 );
465 i915->vbo_flushed = 1;
466
467 if (!BEGIN_BATCH( 1 + (nr_indices + 1)/2, 1 )) {
468 assert(0);
469 goto out;
470 }
471 }
472
473 OUT_BATCH( _3DPRIMITIVE |
474 PRIM_INDIRECT |
475 i915_render->hwprim |
476 PRIM_INDIRECT_ELTS |
477 nr_indices );
478 draw_generate_indices( render,
479 indices,
480 save_nr_indices,
481 i915_render->fallback );
482
483 out:
484 return;
485 }
486
487
488 static void
489 i915_vbuf_render_release_vertices( struct vbuf_render *render )
490 {
491 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
492 struct i915_context *i915 = i915_render->i915;
493
494 assert(i915->vbo);
495
496 i915_render->vbo_offset += i915_render->vbo_max_used;
497 i915_render->vbo_max_used = 0;
498 i915->vbo = NULL;
499 i915->dirty |= I915_NEW_VBO;
500 }
501
502
503 static void
504 i915_vbuf_render_destroy( struct vbuf_render *render )
505 {
506 struct i915_vbuf_render *i915_render = i915_vbuf_render(render);
507 FREE(i915_render);
508 }
509
510
511 /**
512 * Create a new primitive render.
513 */
514 static struct vbuf_render *
515 i915_vbuf_render_create( struct i915_context *i915 )
516 {
517 struct i915_vbuf_render *i915_render = CALLOC_STRUCT(i915_vbuf_render);
518 struct pipe_screen *screen = i915->pipe.screen;
519
520 i915_render->i915 = i915;
521
522 i915_render->base.max_vertex_buffer_bytes = 128*1024;
523
524 /* NOTE: it must be such that state and vertices indices fit in a single
525 * batch buffer.
526 */
527 i915_render->base.max_indices = 16*1024;
528
529 i915_render->base.get_vertex_info = i915_vbuf_render_get_vertex_info;
530 i915_render->base.allocate_vertices = i915_vbuf_render_allocate_vertices;
531 i915_render->base.map_vertices = i915_vbuf_render_map_vertices;
532 i915_render->base.unmap_vertices = i915_vbuf_render_unmap_vertices;
533 i915_render->base.set_primitive = i915_vbuf_render_set_primitive;
534 i915_render->base.draw = i915_vbuf_render_draw;
535 i915_render->base.draw_arrays = i915_vbuf_render_draw_arrays;
536 i915_render->base.release_vertices = i915_vbuf_render_release_vertices;
537 i915_render->base.destroy = i915_vbuf_render_destroy;
538
539 i915_render->vbo_alloc_size = 128 * 4096;
540 i915_render->vbo_size = i915_render->vbo_alloc_size;
541 i915_render->vbo_offset = 0;
542 i915_render->vbo = pipe_buffer_create(screen,
543 64,
544 I915_BUFFER_USAGE_LIT_VERTEX,
545 i915_render->vbo_size);
546 i915_render->vbo_ptr = pipe_buffer_map(screen,
547 i915_render->vbo,
548 PIPE_BUFFER_USAGE_CPU_WRITE);
549 pipe_buffer_unmap(screen, i915_render->vbo);
550
551 return &i915_render->base;
552 }
553
554
555 /**
556 * Create a new primitive vbuf/render stage.
557 */
558 struct draw_stage *i915_draw_vbuf_stage( struct i915_context *i915 )
559 {
560 struct vbuf_render *render;
561 struct draw_stage *stage;
562
563 render = i915_vbuf_render_create(i915);
564 if(!render)
565 return NULL;
566
567 stage = draw_vbuf_stage( i915->draw, render );
568 if(!stage) {
569 render->destroy(render);
570 return NULL;
571 }
572 /** TODO JB: this shouldn't be here */
573 draw_set_render(i915->draw, render);
574
575 return stage;
576 }