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