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