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