Merge branch 'ext-provoking-vertex'
[profile/ivi/mesa.git] / src / gallium / drivers / softpipe / sp_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  * Interface between 'draw' module's output and the softpipe 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 "sp_context.h"
40 #include "sp_state.h"
41 #include "sp_prim_vbuf.h"
42 #include "sp_prim_setup.h"
43 #include "sp_setup.h"
44 #include "draw/draw_context.h"
45 #include "draw/draw_vbuf.h"
46 #include "util/u_memory.h"
47
48
49 #define SP_MAX_VBUF_INDEXES 1024
50 #define SP_MAX_VBUF_SIZE    4096
51
52 typedef const float (*cptrf4)[4];
53
54 /**
55  * Subclass of vbuf_render.
56  */
57 struct softpipe_vbuf_render
58 {
59    struct vbuf_render base;
60    struct softpipe_context *softpipe;
61    uint prim;
62    uint vertex_size;
63    uint nr_vertices;
64    uint vertex_buffer_size;
65    void *vertex_buffer;
66 };
67
68
69 /** cast wrapper */
70 static struct softpipe_vbuf_render *
71 softpipe_vbuf_render(struct vbuf_render *vbr)
72 {
73    return (struct softpipe_vbuf_render *) vbr;
74 }
75
76
77 static const struct vertex_info *
78 sp_vbuf_get_vertex_info(struct vbuf_render *vbr)
79 {
80    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
81    return softpipe_get_vbuf_vertex_info(cvbr->softpipe);
82 }
83
84
85 static boolean
86 sp_vbuf_allocate_vertices(struct vbuf_render *vbr,
87                           ushort vertex_size, ushort nr_vertices)
88 {
89    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
90    unsigned size = vertex_size * nr_vertices;
91
92    if (cvbr->vertex_buffer_size < size) {
93       align_free(cvbr->vertex_buffer);
94       cvbr->vertex_buffer = align_malloc(size, 16);
95       cvbr->vertex_buffer_size = size;
96    }
97
98    cvbr->vertex_size = vertex_size;
99    cvbr->nr_vertices = nr_vertices;
100    
101    return cvbr->vertex_buffer != NULL;
102 }
103
104 static void
105 sp_vbuf_release_vertices(struct vbuf_render *vbr)
106 {
107 #if 0
108    {
109       struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
110       const struct vertex_info *info = 
111          softpipe_get_vbuf_vertex_info(cvbr->softpipe);
112       const float *vtx = (const float *) cvbr->vertex_buffer;
113       uint i, j;
114       debug_printf("%s (vtx_size = %u,  vtx_used = %u)\n",
115              __FUNCTION__, cvbr->vertex_size, cvbr->nr_vertices);
116       for (i = 0; i < cvbr->nr_vertices; i++) {
117          for (j = 0; j < info->num_attribs; j++) {
118             uint k;
119             switch (info->attrib[j].emit) {
120             case EMIT_4F:  k = 4;   break;
121             case EMIT_3F:  k = 3;   break;
122             case EMIT_2F:  k = 2;   break;
123             case EMIT_1F:  k = 1;   break;
124             default: assert(0);
125             }
126             debug_printf("Vert %u attr %u: ", i, j);
127             while (k-- > 0) {
128                debug_printf("%g ", vtx[0]);
129                vtx++;
130             }
131             debug_printf("\n");
132          }
133       }
134    }
135 #endif
136
137    /* keep the old allocation for next time */
138 }
139
140 static void *
141 sp_vbuf_map_vertices(struct vbuf_render *vbr)
142 {
143    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
144    return cvbr->vertex_buffer;
145 }
146
147 static void 
148 sp_vbuf_unmap_vertices(struct vbuf_render *vbr, 
149                        ushort min_index,
150                        ushort max_index )
151 {
152    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
153    assert( cvbr->vertex_buffer_size >= (max_index+1) * cvbr->vertex_size );
154    /* do nothing */
155 }
156
157
158 static boolean
159 sp_vbuf_set_primitive(struct vbuf_render *vbr, unsigned prim)
160 {
161    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
162
163    /* XXX: break this dependency - make setup_context live under
164     * softpipe, rename the old "setup" draw stage to something else.
165     */
166    struct setup_context *setup_ctx = sp_draw_setup_context(cvbr->softpipe->setup);
167    
168    setup_prepare( setup_ctx );
169
170    cvbr->prim = prim;
171    return TRUE;
172
173 }
174
175
176 static INLINE cptrf4 get_vert( const void *vertex_buffer,
177                                int index,
178                                int stride )
179 {
180    return (cptrf4)((char *)vertex_buffer + index * stride);
181 }
182
183
184 /**
185  * draw elements / indexed primitives
186  */
187 static void
188 sp_vbuf_draw(struct vbuf_render *vbr, const ushort *indices, uint nr)
189 {
190    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
191    struct softpipe_context *softpipe = cvbr->softpipe;
192    const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float);
193    const void *vertex_buffer = cvbr->vertex_buffer;
194    unsigned i;
195
196    /* XXX: break this dependency - make setup_context live under
197     * softpipe, rename the old "setup" draw stage to something else.
198     */
199    struct draw_stage *setup = softpipe->setup;
200    struct setup_context *setup_ctx = sp_draw_setup_context(setup);
201
202    switch (cvbr->prim) {
203    case PIPE_PRIM_POINTS:
204       for (i = 0; i < nr; i++) {
205          setup_point( setup_ctx,
206                       get_vert(vertex_buffer, indices[i-0], stride) );
207       }
208       break;
209
210    case PIPE_PRIM_LINES:
211       for (i = 1; i < nr; i += 2) {
212          setup_line( setup_ctx,
213                      get_vert(vertex_buffer, indices[i-1], stride),
214                      get_vert(vertex_buffer, indices[i-0], stride) );
215       }
216       break;
217
218    case PIPE_PRIM_LINE_STRIP:
219       for (i = 1; i < nr; i ++) {
220          setup_line( setup_ctx,
221                      get_vert(vertex_buffer, indices[i-1], stride),
222                      get_vert(vertex_buffer, indices[i-0], stride) );
223       }
224       break;
225
226    case PIPE_PRIM_LINE_LOOP:
227       for (i = 1; i < nr; i ++) {
228          setup_line( setup_ctx,
229                      get_vert(vertex_buffer, indices[i-1], stride),
230                      get_vert(vertex_buffer, indices[i-0], stride) );
231       }
232       if (nr) {
233          setup_line( setup_ctx,
234                      get_vert(vertex_buffer, indices[nr-1], stride),
235                      get_vert(vertex_buffer, indices[0], stride) );
236       }
237       break;
238
239    case PIPE_PRIM_TRIANGLES:
240       for (i = 2; i < nr; i += 3) {
241          if (softpipe->rasterizer->flatshade_first) {
242             setup_tri( setup_ctx,
243                        get_vert(vertex_buffer, indices[i-1], stride),
244                        get_vert(vertex_buffer, indices[i-0], stride),
245                        get_vert(vertex_buffer, indices[i-2], stride) );
246          }
247          else {
248             setup_tri( setup_ctx,
249                        get_vert(vertex_buffer, indices[i-2], stride),
250                        get_vert(vertex_buffer, indices[i-1], stride),
251                        get_vert(vertex_buffer, indices[i-0], stride) );
252          }
253       }
254       break;
255
256    case PIPE_PRIM_TRIANGLE_STRIP:
257       for (i = 2; i < nr; i += 1) {
258          if (softpipe->rasterizer->flatshade_first) {
259             setup_tri( setup_ctx,
260                        get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
261                        get_vert(vertex_buffer, indices[i-(i&1)], stride),
262                        get_vert(vertex_buffer, indices[i-2], stride) );
263          }
264          else {
265             setup_tri( setup_ctx,
266                        get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
267                        get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
268                        get_vert(vertex_buffer, indices[i-0], stride) );
269          }
270       }
271       break;
272
273    case PIPE_PRIM_TRIANGLE_FAN:
274       for (i = 2; i < nr; i += 1) {
275          if (softpipe->rasterizer->flatshade_first) {
276             setup_tri( setup_ctx,
277                        get_vert(vertex_buffer, indices[i-0], stride),
278                        get_vert(vertex_buffer, indices[0], stride),
279                        get_vert(vertex_buffer, indices[i-1], stride) );
280          }
281          else {
282             setup_tri( setup_ctx,
283                        get_vert(vertex_buffer, indices[0], stride),
284                        get_vert(vertex_buffer, indices[i-1], stride),
285                        get_vert(vertex_buffer, indices[i-0], stride) );
286          }
287       }
288       break;
289
290    case PIPE_PRIM_QUADS:
291       for (i = 3; i < nr; i += 4) {
292          if (softpipe->rasterizer->flatshade_first) {
293             setup_tri( setup_ctx,
294                        get_vert(vertex_buffer, indices[i-2], stride),
295                        get_vert(vertex_buffer, indices[i-1], stride),
296                        get_vert(vertex_buffer, indices[i-3], stride) );
297             setup_tri( setup_ctx,
298                        get_vert(vertex_buffer, indices[i-1], stride),
299                        get_vert(vertex_buffer, indices[i-0], stride),
300                        get_vert(vertex_buffer, indices[i-3], stride) );
301          }
302          else {
303             setup_tri( setup_ctx,
304                        get_vert(vertex_buffer, indices[i-3], stride),
305                        get_vert(vertex_buffer, indices[i-2], stride),
306                        get_vert(vertex_buffer, indices[i-0], stride) );
307
308             setup_tri( setup_ctx,
309                        get_vert(vertex_buffer, indices[i-2], stride),
310                        get_vert(vertex_buffer, indices[i-1], stride),
311                        get_vert(vertex_buffer, indices[i-0], stride) );
312          }
313       }
314       break;
315
316    case PIPE_PRIM_QUAD_STRIP:
317       for (i = 3; i < nr; i += 2) {
318          if (softpipe->rasterizer->flatshade_first) {
319             setup_tri( setup_ctx,
320                        get_vert(vertex_buffer, indices[i-0], stride),
321                        get_vert(vertex_buffer, indices[i-1], stride),
322                        get_vert(vertex_buffer, indices[i-3], stride));
323             setup_tri( setup_ctx,
324                        get_vert(vertex_buffer, indices[i-2], stride),
325                        get_vert(vertex_buffer, indices[i-0], stride),
326                        get_vert(vertex_buffer, indices[i-3], stride) );
327          }
328          else {
329             setup_tri( setup_ctx,
330                        get_vert(vertex_buffer, indices[i-3], stride),
331                        get_vert(vertex_buffer, indices[i-2], stride),
332                        get_vert(vertex_buffer, indices[i-0], stride) );
333             setup_tri( setup_ctx,
334                        get_vert(vertex_buffer, indices[i-1], stride),
335                        get_vert(vertex_buffer, indices[i-3], stride),
336                        get_vert(vertex_buffer, indices[i-0], stride) );
337          }
338       }
339       break;
340
341    case PIPE_PRIM_POLYGON:
342       /* Almost same as tri fan but the _first_ vertex specifies the flat
343        * shading color.  Note that the first polygon vertex is passed as
344        * the last triangle vertex here.
345        * flatshade_first state makes no difference.
346        */
347       for (i = 2; i < nr; i += 1) {
348          setup_tri( setup_ctx,
349                     get_vert(vertex_buffer, indices[i-0], stride),
350                     get_vert(vertex_buffer, indices[i-1], stride),
351                     get_vert(vertex_buffer, indices[0], stride) );
352       }
353       break;
354
355    default:
356       assert(0);
357    }
358
359    /* XXX: why are we calling this???  If we had to call something, it
360     * would be a function in sp_setup.c:
361     */
362    sp_draw_flush( setup );
363 }
364
365
366 /**
367  * This function is hit when the draw module is working in pass-through mode.
368  * It's up to us to convert the vertex array into point/line/tri prims.
369  */
370 static void
371 sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
372 {
373    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
374    struct softpipe_context *softpipe = cvbr->softpipe;
375    const unsigned stride = softpipe->vertex_info_vbuf.size * sizeof(float);
376    const void *vertex_buffer =
377       (void *) get_vert(cvbr->vertex_buffer, start, stride);
378    unsigned i;
379
380    /* XXX: break this dependency - make setup_context live under
381     * softpipe, rename the old "setup" draw stage to something else.
382     */
383    struct draw_stage *setup = softpipe->setup;
384    struct setup_context *setup_ctx = sp_draw_setup_context(setup);
385
386    switch (cvbr->prim) {
387    case PIPE_PRIM_POINTS:
388       for (i = 0; i < nr; i++) {
389          setup_point( setup_ctx,
390                       get_vert(vertex_buffer, i-0, stride) );
391       }
392       break;
393
394    case PIPE_PRIM_LINES:
395       for (i = 1; i < nr; i += 2) {
396          setup_line( setup_ctx,
397                      get_vert(vertex_buffer, i-1, stride),
398                      get_vert(vertex_buffer, i-0, stride) );
399       }
400       break;
401
402    case PIPE_PRIM_LINE_STRIP:
403       for (i = 1; i < nr; i ++) {
404          setup_line( setup_ctx,
405                      get_vert(vertex_buffer, i-1, stride),
406                      get_vert(vertex_buffer, i-0, stride) );
407       }
408       break;
409
410    case PIPE_PRIM_LINE_LOOP:
411       for (i = 1; i < nr; i ++) {
412          setup_line( setup_ctx,
413                      get_vert(vertex_buffer, i-1, stride),
414                      get_vert(vertex_buffer, i-0, stride) );
415       }
416       if (nr) {
417          setup_line( setup_ctx,
418                      get_vert(vertex_buffer, nr-1, stride),
419                      get_vert(vertex_buffer, 0, stride) );
420       }
421       break;
422
423    case PIPE_PRIM_TRIANGLES:
424       for (i = 2; i < nr; i += 3) {
425          if (softpipe->rasterizer->flatshade_first) {
426             setup_tri( setup_ctx,
427                        get_vert(vertex_buffer, i-1, stride),
428                        get_vert(vertex_buffer, i-0, stride),
429                        get_vert(vertex_buffer, i-2, stride) );
430          }
431          else {
432             setup_tri( setup_ctx,
433                        get_vert(vertex_buffer, i-2, stride),
434                        get_vert(vertex_buffer, i-1, stride),
435                        get_vert(vertex_buffer, i-0, stride) );
436          }
437       }
438       break;
439
440    case PIPE_PRIM_TRIANGLE_STRIP:
441       for (i = 2; i < nr; i++) {
442          if (softpipe->rasterizer->flatshade_first) {
443             setup_tri( setup_ctx,
444                        get_vert(vertex_buffer, i+(i&1)-1, stride),
445                        get_vert(vertex_buffer, i-(i&1), stride),
446                        get_vert(vertex_buffer, i-2, stride) );
447          }
448          else {
449             setup_tri( setup_ctx,
450                        get_vert(vertex_buffer, i+(i&1)-2, stride),
451                        get_vert(vertex_buffer, i-(i&1)-1, stride),
452                        get_vert(vertex_buffer, i-0, stride) );
453          }
454       }
455       break;
456
457    case PIPE_PRIM_TRIANGLE_FAN:
458       for (i = 2; i < nr; i += 1) {
459          if (softpipe->rasterizer->flatshade_first) {
460             setup_tri( setup_ctx,
461                        get_vert(vertex_buffer, i-0, stride),
462                        get_vert(vertex_buffer, 0, stride),
463                        get_vert(vertex_buffer, i-1, stride) );
464          }
465          else {
466             setup_tri( setup_ctx,
467                        get_vert(vertex_buffer, 0, stride),
468                        get_vert(vertex_buffer, i-1, stride),
469                        get_vert(vertex_buffer, i-0, stride) );
470          }
471       }
472       break;
473
474    case PIPE_PRIM_QUADS:
475       for (i = 3; i < nr; i += 4) {
476          if (softpipe->rasterizer->flatshade_first) {
477             setup_tri( setup_ctx,
478                        get_vert(vertex_buffer, i-2, stride),
479                        get_vert(vertex_buffer, i-1, stride),
480                        get_vert(vertex_buffer, i-3, stride) );
481             setup_tri( setup_ctx,
482                        get_vert(vertex_buffer, i-1, stride),
483                        get_vert(vertex_buffer, i-0, stride),
484                        get_vert(vertex_buffer, i-3, stride) );
485          }
486          else {
487             setup_tri( setup_ctx,
488                        get_vert(vertex_buffer, i-3, stride),
489                        get_vert(vertex_buffer, i-2, stride),
490                        get_vert(vertex_buffer, i-0, stride) );
491             setup_tri( setup_ctx,
492                        get_vert(vertex_buffer, i-2, stride),
493                        get_vert(vertex_buffer, i-1, stride),
494                        get_vert(vertex_buffer, i-0, stride) );
495          }
496       }
497       break;
498
499    case PIPE_PRIM_QUAD_STRIP:
500       for (i = 3; i < nr; i += 2) {
501          if (softpipe->rasterizer->flatshade_first) {
502             setup_tri( setup_ctx,
503                        get_vert(vertex_buffer, i-0, stride),
504                        get_vert(vertex_buffer, i-1, stride),
505                        get_vert(vertex_buffer, i-3, stride) );
506             setup_tri( setup_ctx,
507                        get_vert(vertex_buffer, i-2, stride),
508                        get_vert(vertex_buffer, i-0, stride),
509                        get_vert(vertex_buffer, i-3, stride) );
510          }
511          else {
512             setup_tri( setup_ctx,
513                        get_vert(vertex_buffer, i-3, stride),
514                        get_vert(vertex_buffer, i-2, stride),
515                        get_vert(vertex_buffer, i-0, stride) );
516             setup_tri( setup_ctx,
517                        get_vert(vertex_buffer, i-1, stride),
518                        get_vert(vertex_buffer, i-3, stride),
519                        get_vert(vertex_buffer, i-0, stride) );
520          }
521       }
522       break;
523
524    case PIPE_PRIM_POLYGON:
525       /* Almost same as tri fan but the _first_ vertex specifies the flat
526        * shading color.  Note that the first polygon vertex is passed as
527        * the last triangle vertex here.
528        * flatshade_first state makes no difference.
529        */
530       for (i = 2; i < nr; i += 1) {
531          setup_tri( setup_ctx,
532                     get_vert(vertex_buffer, i-1, stride),
533                     get_vert(vertex_buffer, i-0, stride),
534                     get_vert(vertex_buffer, 0, stride) );
535       }
536       break;
537
538    default:
539       assert(0);
540    }
541 }
542
543
544
545 static void
546 sp_vbuf_destroy(struct vbuf_render *vbr)
547 {
548    struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
549    cvbr->softpipe->vbuf_render = NULL;
550    FREE(cvbr);
551 }
552
553
554 /**
555  * Initialize the post-transform vertex buffer information for the given
556  * context.
557  */
558 void
559 sp_init_vbuf(struct softpipe_context *sp)
560 {
561    assert(sp->draw);
562
563    sp->vbuf_render = CALLOC_STRUCT(softpipe_vbuf_render);
564
565    sp->vbuf_render->base.max_indices = SP_MAX_VBUF_INDEXES;
566    sp->vbuf_render->base.max_vertex_buffer_bytes = SP_MAX_VBUF_SIZE;
567
568    sp->vbuf_render->base.get_vertex_info = sp_vbuf_get_vertex_info;
569    sp->vbuf_render->base.allocate_vertices = sp_vbuf_allocate_vertices;
570    sp->vbuf_render->base.map_vertices = sp_vbuf_map_vertices;
571    sp->vbuf_render->base.unmap_vertices = sp_vbuf_unmap_vertices;
572    sp->vbuf_render->base.set_primitive = sp_vbuf_set_primitive;
573    sp->vbuf_render->base.draw = sp_vbuf_draw;
574    sp->vbuf_render->base.draw_arrays = sp_vbuf_draw_arrays;
575    sp->vbuf_render->base.release_vertices = sp_vbuf_release_vertices;
576    sp->vbuf_render->base.destroy = sp_vbuf_destroy;
577
578    sp->vbuf_render->softpipe = sp;
579
580    sp->vbuf = draw_vbuf_stage(sp->draw, &sp->vbuf_render->base);
581
582    draw_set_rasterize_stage(sp->draw, sp->vbuf);
583
584    draw_set_render(sp->draw, &sp->vbuf_render->base);
585 }