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 llvmpipe 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 "lp_setup_context.h"
40 #include "draw/draw_vbuf.h"
41 #include "draw/draw_vertex.h"
42 #include "util/u_memory.h"
43 
44 
45 #define LP_MAX_VBUF_INDEXES 1024
46 #define LP_MAX_VBUF_SIZE    4096
47 
48 
49 
50 /** cast wrapper */
51 static struct lp_setup_context *
lp_setup_context(struct vbuf_render * vbr)52 lp_setup_context(struct vbuf_render *vbr)
53 {
54    return (struct lp_setup_context *) vbr;
55 }
56 
57 
58 
59 static const struct vertex_info *
lp_setup_get_vertex_info(struct vbuf_render * vbr)60 lp_setup_get_vertex_info(struct vbuf_render *vbr)
61 {
62    struct lp_setup_context *setup = lp_setup_context(vbr);
63 
64    /* Vertex size/info depends on the latest state.
65     * The draw module may have issued additional state-change commands.
66     */
67    lp_setup_update_state(setup, FALSE);
68 
69    return setup->vertex_info;
70 }
71 
72 
73 static boolean
lp_setup_allocate_vertices(struct vbuf_render * vbr,ushort vertex_size,ushort nr_vertices)74 lp_setup_allocate_vertices(struct vbuf_render *vbr,
75                           ushort vertex_size, ushort nr_vertices)
76 {
77    struct lp_setup_context *setup = lp_setup_context(vbr);
78    unsigned size = vertex_size * nr_vertices;
79 
80    if (setup->vertex_buffer_size < size) {
81       align_free(setup->vertex_buffer);
82       setup->vertex_buffer = align_malloc(size, 16);
83       setup->vertex_buffer_size = size;
84    }
85 
86    setup->vertex_size = vertex_size;
87    setup->nr_vertices = nr_vertices;
88 
89    return setup->vertex_buffer != NULL;
90 }
91 
92 static void
lp_setup_release_vertices(struct vbuf_render * vbr)93 lp_setup_release_vertices(struct vbuf_render *vbr)
94 {
95    /* keep the old allocation for next time */
96 }
97 
98 static void *
lp_setup_map_vertices(struct vbuf_render * vbr)99 lp_setup_map_vertices(struct vbuf_render *vbr)
100 {
101    struct lp_setup_context *setup = lp_setup_context(vbr);
102    return setup->vertex_buffer;
103 }
104 
105 static void
lp_setup_unmap_vertices(struct vbuf_render * vbr,ushort min_index,ushort max_index)106 lp_setup_unmap_vertices(struct vbuf_render *vbr,
107                        ushort min_index,
108                        ushort max_index )
109 {
110    struct lp_setup_context *setup = lp_setup_context(vbr);
111    assert( setup->vertex_buffer_size >= (max_index+1) * setup->vertex_size );
112    /* do nothing */
113 }
114 
115 
116 static void
lp_setup_set_primitive(struct vbuf_render * vbr,unsigned prim)117 lp_setup_set_primitive(struct vbuf_render *vbr, unsigned prim)
118 {
119    lp_setup_context(vbr)->prim = prim;
120 }
121 
122 typedef const float (*const_float4_ptr)[4];
123 
get_vert(const void * vertex_buffer,int index,int stride)124 static INLINE const_float4_ptr get_vert( const void *vertex_buffer,
125                                          int index,
126                                          int stride )
127 {
128    return (const_float4_ptr)((char *)vertex_buffer + index * stride);
129 }
130 
131 /**
132  * draw elements / indexed primitives
133  */
134 static void
lp_setup_draw_elements(struct vbuf_render * vbr,const ushort * indices,uint nr)135 lp_setup_draw_elements(struct vbuf_render *vbr, const ushort *indices, uint nr)
136 {
137    struct lp_setup_context *setup = lp_setup_context(vbr);
138    const unsigned stride = setup->vertex_info->size * sizeof(float);
139    const void *vertex_buffer = setup->vertex_buffer;
140    const boolean flatshade_first = setup->flatshade_first;
141    unsigned i;
142 
143    assert(setup->setup.variant);
144 
145    if (!lp_setup_update_state(setup, TRUE))
146       return;
147 
148    switch (setup->prim) {
149    case PIPE_PRIM_POINTS:
150       for (i = 0; i < nr; i++) {
151          setup->point( setup,
152                        get_vert(vertex_buffer, indices[i-0], stride) );
153       }
154       break;
155 
156    case PIPE_PRIM_LINES:
157       for (i = 1; i < nr; i += 2) {
158          setup->line( setup,
159                       get_vert(vertex_buffer, indices[i-1], stride),
160                       get_vert(vertex_buffer, indices[i-0], stride) );
161       }
162       break;
163 
164    case PIPE_PRIM_LINE_STRIP:
165       for (i = 1; i < nr; i ++) {
166          setup->line( setup,
167                       get_vert(vertex_buffer, indices[i-1], stride),
168                       get_vert(vertex_buffer, indices[i-0], stride) );
169       }
170       break;
171 
172    case PIPE_PRIM_LINE_LOOP:
173       for (i = 1; i < nr; i ++) {
174          setup->line( setup,
175                       get_vert(vertex_buffer, indices[i-1], stride),
176                       get_vert(vertex_buffer, indices[i-0], stride) );
177       }
178       if (nr) {
179          setup->line( setup,
180                       get_vert(vertex_buffer, indices[nr-1], stride),
181                       get_vert(vertex_buffer, indices[0], stride) );
182       }
183       break;
184 
185    case PIPE_PRIM_TRIANGLES:
186       for (i = 2; i < nr; i += 3) {
187          setup->triangle( setup,
188                           get_vert(vertex_buffer, indices[i-2], stride),
189                           get_vert(vertex_buffer, indices[i-1], stride),
190                           get_vert(vertex_buffer, indices[i-0], stride) );
191       }
192       break;
193 
194    case PIPE_PRIM_TRIANGLE_STRIP:
195       if (flatshade_first) {
196          for (i = 2; i < nr; i += 1) {
197             /* emit first triangle vertex as first triangle vertex */
198             setup->triangle( setup,
199                              get_vert(vertex_buffer, indices[i-2], stride),
200                              get_vert(vertex_buffer, indices[i+(i&1)-1], stride),
201                              get_vert(vertex_buffer, indices[i-(i&1)], stride) );
202 
203          }
204       }
205       else {
206          for (i = 2; i < nr; i += 1) {
207             /* emit last triangle vertex as last triangle vertex */
208             setup->triangle( setup,
209                              get_vert(vertex_buffer, indices[i+(i&1)-2], stride),
210                              get_vert(vertex_buffer, indices[i-(i&1)-1], stride),
211                              get_vert(vertex_buffer, indices[i-0], stride) );
212          }
213       }
214       break;
215 
216    case PIPE_PRIM_TRIANGLE_FAN:
217       if (flatshade_first) {
218          for (i = 2; i < nr; i += 1) {
219             /* emit first non-spoke vertex as first vertex */
220             setup->triangle( setup,
221                              get_vert(vertex_buffer, indices[i-1], stride),
222                              get_vert(vertex_buffer, indices[i-0], stride),
223                              get_vert(vertex_buffer, indices[0], stride) );
224          }
225       }
226       else {
227          for (i = 2; i < nr; i += 1) {
228             /* emit last non-spoke vertex as last vertex */
229             setup->triangle( setup,
230                              get_vert(vertex_buffer, indices[0], stride),
231                              get_vert(vertex_buffer, indices[i-1], stride),
232                              get_vert(vertex_buffer, indices[i-0], stride) );
233          }
234       }
235       break;
236 
237    case PIPE_PRIM_QUADS:
238       /* GL quads don't follow provoking vertex convention */
239       if (flatshade_first) {
240          /* emit last quad vertex as first triangle vertex */
241          for (i = 3; i < nr; i += 4) {
242             setup->triangle( setup,
243                              get_vert(vertex_buffer, indices[i-0], stride),
244                              get_vert(vertex_buffer, indices[i-3], stride),
245                              get_vert(vertex_buffer, indices[i-2], stride) );
246 
247             setup->triangle( setup,
248                              get_vert(vertex_buffer, indices[i-0], stride),
249                              get_vert(vertex_buffer, indices[i-2], stride),
250                              get_vert(vertex_buffer, indices[i-1], stride) );
251          }
252       }
253       else {
254          /* emit last quad vertex as last triangle vertex */
255          for (i = 3; i < nr; i += 4) {
256             setup->triangle( setup,
257                           get_vert(vertex_buffer, indices[i-3], stride),
258                           get_vert(vertex_buffer, indices[i-2], stride),
259                           get_vert(vertex_buffer, indices[i-0], stride) );
260 
261             setup->triangle( setup,
262                              get_vert(vertex_buffer, indices[i-2], stride),
263                              get_vert(vertex_buffer, indices[i-1], stride),
264                              get_vert(vertex_buffer, indices[i-0], stride) );
265          }
266       }
267       break;
268 
269    case PIPE_PRIM_QUAD_STRIP:
270       /* GL quad strips don't follow provoking vertex convention */
271       if (flatshade_first) {
272          /* emit last quad vertex as first triangle vertex */
273          for (i = 3; i < nr; i += 2) {
274             setup->triangle( setup,
275                              get_vert(vertex_buffer, indices[i-0], stride),
276                              get_vert(vertex_buffer, indices[i-3], stride),
277                              get_vert(vertex_buffer, indices[i-2], stride) );
278             setup->triangle( setup,
279                              get_vert(vertex_buffer, indices[i-0], stride),
280                              get_vert(vertex_buffer, indices[i-1], stride),
281                              get_vert(vertex_buffer, indices[i-3], stride) );
282          }
283       }
284       else {
285          /* emit last quad vertex as last triangle vertex */
286          for (i = 3; i < nr; i += 2) {
287             setup->triangle( setup,
288                              get_vert(vertex_buffer, indices[i-3], stride),
289                              get_vert(vertex_buffer, indices[i-2], stride),
290                              get_vert(vertex_buffer, indices[i-0], stride) );
291             setup->triangle( setup,
292                              get_vert(vertex_buffer, indices[i-1], stride),
293                              get_vert(vertex_buffer, indices[i-3], stride),
294                              get_vert(vertex_buffer, indices[i-0], stride) );
295          }
296       }
297       break;
298 
299    case PIPE_PRIM_POLYGON:
300       /* Almost same as tri fan but the _first_ vertex specifies the flat
301        * shading color.
302        */
303       if (flatshade_first) {
304          /* emit first polygon  vertex as first triangle vertex */
305          for (i = 2; i < nr; i += 1) {
306             setup->triangle( setup,
307                              get_vert(vertex_buffer, indices[0], stride),
308                              get_vert(vertex_buffer, indices[i-1], stride),
309                              get_vert(vertex_buffer, indices[i-0], stride) );
310          }
311       }
312       else {
313          /* emit first polygon  vertex as last triangle vertex */
314          for (i = 2; i < nr; i += 1) {
315             setup->triangle( setup,
316                              get_vert(vertex_buffer, indices[i-1], stride),
317                              get_vert(vertex_buffer, indices[i-0], stride),
318                              get_vert(vertex_buffer, indices[0], stride) );
319          }
320       }
321       break;
322 
323    default:
324       assert(0);
325    }
326 }
327 
328 
329 /**
330  * This function is hit when the draw module is working in pass-through mode.
331  * It's up to us to convert the vertex array into point/line/tri prims.
332  */
333 static void
lp_setup_draw_arrays(struct vbuf_render * vbr,uint start,uint nr)334 lp_setup_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
335 {
336    struct lp_setup_context *setup = lp_setup_context(vbr);
337    const unsigned stride = setup->vertex_info->size * sizeof(float);
338    const void *vertex_buffer =
339       (void *) get_vert(setup->vertex_buffer, start, stride);
340    const boolean flatshade_first = setup->flatshade_first;
341    unsigned i;
342 
343    if (!lp_setup_update_state(setup, TRUE))
344       return;
345 
346    switch (setup->prim) {
347    case PIPE_PRIM_POINTS:
348       for (i = 0; i < nr; i++) {
349          setup->point( setup,
350                        get_vert(vertex_buffer, i-0, stride) );
351       }
352       break;
353 
354    case PIPE_PRIM_LINES:
355       for (i = 1; i < nr; i += 2) {
356          setup->line( setup,
357                       get_vert(vertex_buffer, i-1, stride),
358                       get_vert(vertex_buffer, i-0, stride) );
359       }
360       break;
361 
362    case PIPE_PRIM_LINE_STRIP:
363       for (i = 1; i < nr; i ++) {
364          setup->line( setup,
365                       get_vert(vertex_buffer, i-1, stride),
366                       get_vert(vertex_buffer, i-0, stride) );
367       }
368       break;
369 
370    case PIPE_PRIM_LINE_LOOP:
371       for (i = 1; i < nr; i ++) {
372          setup->line( setup,
373                       get_vert(vertex_buffer, i-1, stride),
374                       get_vert(vertex_buffer, i-0, stride) );
375       }
376       if (nr) {
377          setup->line( setup,
378                       get_vert(vertex_buffer, nr-1, stride),
379                       get_vert(vertex_buffer, 0, stride) );
380       }
381       break;
382 
383    case PIPE_PRIM_TRIANGLES:
384       for (i = 2; i < nr; i += 3) {
385          setup->triangle( setup,
386                           get_vert(vertex_buffer, i-2, stride),
387                           get_vert(vertex_buffer, i-1, stride),
388                           get_vert(vertex_buffer, i-0, stride) );
389       }
390       break;
391 
392    case PIPE_PRIM_TRIANGLE_STRIP:
393       if (flatshade_first) {
394          for (i = 2; i < nr; i++) {
395             /* emit first triangle vertex as first triangle vertex */
396             setup->triangle( setup,
397                              get_vert(vertex_buffer, i-2, stride),
398                              get_vert(vertex_buffer, i+(i&1)-1, stride),
399                              get_vert(vertex_buffer, i-(i&1), stride) );
400          }
401       }
402       else {
403          for (i = 2; i < nr; i++) {
404             /* emit last triangle vertex as last triangle vertex */
405             setup->triangle( setup,
406                              get_vert(vertex_buffer, i+(i&1)-2, stride),
407                              get_vert(vertex_buffer, i-(i&1)-1, stride),
408                              get_vert(vertex_buffer, i-0, stride) );
409          }
410       }
411       break;
412 
413    case PIPE_PRIM_TRIANGLE_FAN:
414       if (flatshade_first) {
415          for (i = 2; i < nr; i += 1) {
416             /* emit first non-spoke vertex as first vertex */
417             setup->triangle( setup,
418                              get_vert(vertex_buffer, i-1, stride),
419                              get_vert(vertex_buffer, i-0, stride),
420                              get_vert(vertex_buffer, 0, stride)  );
421          }
422       }
423       else {
424          for (i = 2; i < nr; i += 1) {
425             /* emit last non-spoke vertex as last vertex */
426             setup->triangle( setup,
427                              get_vert(vertex_buffer, 0, stride),
428                              get_vert(vertex_buffer, i-1, stride),
429                              get_vert(vertex_buffer, i-0, stride) );
430          }
431       }
432       break;
433 
434    case PIPE_PRIM_QUADS:
435       /* GL quads don't follow provoking vertex convention */
436       if (flatshade_first) {
437          /* emit last quad vertex as first triangle vertex */
438          for (i = 3; i < nr; i += 4) {
439             setup->triangle( setup,
440                              get_vert(vertex_buffer, i-0, stride),
441                              get_vert(vertex_buffer, i-3, stride),
442                              get_vert(vertex_buffer, i-2, stride) );
443             setup->triangle( setup,
444                              get_vert(vertex_buffer, i-0, stride),
445                              get_vert(vertex_buffer, i-2, stride),
446                              get_vert(vertex_buffer, i-1, stride) );
447          }
448       }
449       else {
450          /* emit last quad vertex as last triangle vertex */
451          for (i = 3; i < nr; i += 4) {
452             setup->triangle( setup,
453                              get_vert(vertex_buffer, i-3, stride),
454                              get_vert(vertex_buffer, i-2, stride),
455                              get_vert(vertex_buffer, i-0, stride) );
456             setup->triangle( setup,
457                              get_vert(vertex_buffer, i-2, stride),
458                              get_vert(vertex_buffer, i-1, stride),
459                              get_vert(vertex_buffer, i-0, stride) );
460          }
461       }
462       break;
463 
464    case PIPE_PRIM_QUAD_STRIP:
465       /* GL quad strips don't follow provoking vertex convention */
466       if (flatshade_first) {
467          /* emit last quad vertex as first triangle vertex */
468          for (i = 3; i < nr; i += 2) {
469             setup->triangle( setup,
470                              get_vert(vertex_buffer, i-0, stride),
471                              get_vert(vertex_buffer, i-3, stride),
472                              get_vert(vertex_buffer, i-2, stride) );
473             setup->triangle( setup,
474                              get_vert(vertex_buffer, i-0, stride),
475                              get_vert(vertex_buffer, i-1, stride),
476                              get_vert(vertex_buffer, i-3, stride) );
477          }
478       }
479       else {
480          /* emit last quad vertex as last triangle vertex */
481          for (i = 3; i < nr; i += 2) {
482             setup->triangle( setup,
483                              get_vert(vertex_buffer, i-3, stride),
484                              get_vert(vertex_buffer, i-2, stride),
485                              get_vert(vertex_buffer, i-0, stride) );
486             setup->triangle( setup,
487                              get_vert(vertex_buffer, i-1, stride),
488                              get_vert(vertex_buffer, i-3, stride),
489                              get_vert(vertex_buffer, i-0, stride) );
490          }
491       }
492       break;
493 
494    case PIPE_PRIM_POLYGON:
495       /* Almost same as tri fan but the _first_ vertex specifies the flat
496        * shading color.
497        */
498       if (flatshade_first) {
499          /* emit first polygon  vertex as first triangle vertex */
500          for (i = 2; i < nr; i += 1) {
501             setup->triangle( setup,
502                              get_vert(vertex_buffer, 0, stride),
503                              get_vert(vertex_buffer, i-1, stride),
504                              get_vert(vertex_buffer, i-0, stride) );
505          }
506       }
507       else {
508          /* emit first polygon  vertex as last triangle vertex */
509          for (i = 2; i < nr; i += 1) {
510             setup->triangle( setup,
511                              get_vert(vertex_buffer, i-1, stride),
512                              get_vert(vertex_buffer, i-0, stride),
513                              get_vert(vertex_buffer, 0, stride) );
514          }
515       }
516       break;
517 
518    default:
519       assert(0);
520    }
521 }
522 
523 
524 
525 static void
lp_setup_vbuf_destroy(struct vbuf_render * vbr)526 lp_setup_vbuf_destroy(struct vbuf_render *vbr)
527 {
528    struct lp_setup_context *setup = lp_setup_context(vbr);
529    if (setup->vertex_buffer) {
530       align_free(setup->vertex_buffer);
531       setup->vertex_buffer = NULL;
532    }
533    lp_setup_destroy(setup);
534 }
535 
536 
537 /**
538  * Create the post-transform vertex handler for the given context.
539  */
540 void
lp_setup_init_vbuf(struct lp_setup_context * setup)541 lp_setup_init_vbuf(struct lp_setup_context *setup)
542 {
543    setup->base.max_indices = LP_MAX_VBUF_INDEXES;
544    setup->base.max_vertex_buffer_bytes = LP_MAX_VBUF_SIZE;
545 
546    setup->base.get_vertex_info = lp_setup_get_vertex_info;
547    setup->base.allocate_vertices = lp_setup_allocate_vertices;
548    setup->base.map_vertices = lp_setup_map_vertices;
549    setup->base.unmap_vertices = lp_setup_unmap_vertices;
550    setup->base.set_primitive = lp_setup_set_primitive;
551    setup->base.draw_elements = lp_setup_draw_elements;
552    setup->base.draw_arrays = lp_setup_draw_arrays;
553    setup->base.release_vertices = lp_setup_release_vertices;
554    setup->base.destroy = lp_setup_vbuf_destroy;
555 }
556