1 /* Originally written by Ben Skeggs for the nv50 driver*/
2 
3 #ifndef U_SPLIT_PRIM_H
4 #define U_SPLIT_PRIM_H
5 
6 #include "pipe/p_defines.h"
7 #include "pipe/p_compiler.h"
8 
9 #include "util/u_debug.h"
10 
11 struct util_split_prim {
12    void *priv;
13    void (*emit)(void *priv, unsigned start, unsigned count);
14    void (*edge)(void *priv, boolean enabled);
15 
16    unsigned mode;
17    unsigned start;
18    unsigned p_start;
19    unsigned p_end;
20 
21    uint repeat_first:1;
22    uint close_first:1;
23    uint edgeflag_off:1;
24 };
25 
26 static INLINE void
util_split_prim_init(struct util_split_prim * s,unsigned mode,unsigned start,unsigned count)27 util_split_prim_init(struct util_split_prim *s,
28                   unsigned mode, unsigned start, unsigned count)
29 {
30    if (mode == PIPE_PRIM_LINE_LOOP) {
31       s->mode = PIPE_PRIM_LINE_STRIP;
32       s->close_first = 1;
33    } else {
34       s->mode = mode;
35       s->close_first = 0;
36    }
37    s->start = start;
38    s->p_start = start;
39    s->p_end = start + count;
40    s->edgeflag_off = 0;
41    s->repeat_first = 0;
42 }
43 
44 static INLINE boolean
util_split_prim_next(struct util_split_prim * s,unsigned max_verts)45 util_split_prim_next(struct util_split_prim *s, unsigned max_verts)
46 {
47    int repeat = 0;
48 
49    if (s->repeat_first) {
50       s->emit(s->priv, s->start, 1);
51       max_verts--;
52       if (s->edgeflag_off) {
53          s->edge(s->priv, TRUE);
54          s->edgeflag_off = FALSE;
55       }
56    }
57 
58    if ((s->p_end - s->p_start) + s->close_first <= max_verts) {
59       s->emit(s->priv, s->p_start, s->p_end - s->p_start);
60       if (s->close_first)
61          s->emit(s->priv, s->start, 1);
62       return TRUE;
63    }
64 
65    switch (s->mode) {
66    case PIPE_PRIM_LINES:
67       max_verts &= ~1;
68       break;
69    case PIPE_PRIM_LINE_STRIP:
70       repeat = 1;
71       break;
72    case PIPE_PRIM_POLYGON:
73       max_verts--;
74       s->emit(s->priv, s->p_start, max_verts);
75       s->edge(s->priv, FALSE);
76       s->emit(s->priv, s->p_start + max_verts, 1);
77       s->p_start += max_verts;
78       s->repeat_first = TRUE;
79       s->edgeflag_off = TRUE;
80       return FALSE;
81    case PIPE_PRIM_TRIANGLES:
82       max_verts = max_verts - (max_verts % 3);
83       break;
84    case PIPE_PRIM_TRIANGLE_STRIP:
85       /* to ensure winding stays correct, always split
86        * on an even number of generated triangles
87        */
88       max_verts = max_verts & ~1;
89       repeat = 2;
90       break;
91    case PIPE_PRIM_TRIANGLE_FAN:
92       s->repeat_first = TRUE;
93       repeat = 1;
94       break;
95    case PIPE_PRIM_QUADS:
96       max_verts &= ~3;
97       break;
98    case PIPE_PRIM_QUAD_STRIP:
99       max_verts &= ~1;
100       repeat = 2;
101       break;
102    case PIPE_PRIM_POINTS:
103       break;
104    default:
105       /* TODO: implement adjacency primitives */
106       assert(0);
107    }
108 
109    s->emit (s->priv, s->p_start, max_verts);
110    s->p_start += (max_verts - repeat);
111    return FALSE;
112 }
113 
114 #endif /* U_SPLIT_PRIM_H */
115