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