Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / drivers / nouveau / nouveau_util.h
1 #ifndef __NOUVEAU_UTIL_H__
2 #define __NOUVEAU_UTIL_H__
3
4 /* Determine how many vertices can be pushed into the command stream.
5  * Where the remaining space isn't large enough to represent all verices,
6  * split the buffer at primitive boundaries.
7  *
8  * Returns a count of vertices that can be rendered, and an index to
9  * restart drawing at after a flush.
10  */
11 static INLINE unsigned
12 nouveau_vbuf_split(unsigned remaining, unsigned overhead, unsigned vpp,
13                    unsigned mode, unsigned start, unsigned count,
14                    unsigned *restart)
15 {
16         int max, adj = 0;
17
18         max  = remaining - overhead;
19         if (max < 0)
20                 return 0;
21
22         max *= vpp;
23         if (max >= count)
24                 return count;
25
26         switch (mode) {
27         case PIPE_PRIM_POINTS:
28                 break;
29         case PIPE_PRIM_LINES:
30                 max = max & 1;
31                 break;
32         case PIPE_PRIM_TRIANGLES:
33                 max = max - (max % 3);
34                 break;
35         case PIPE_PRIM_QUADS:
36                 max = max & ~3;
37                 break;
38         case PIPE_PRIM_LINE_LOOP:
39         case PIPE_PRIM_LINE_STRIP:
40                 if (max < 2)
41                         max = 0;
42                 adj = 1;
43                 break;
44         case PIPE_PRIM_POLYGON:
45         case PIPE_PRIM_TRIANGLE_STRIP:
46         case PIPE_PRIM_TRIANGLE_FAN:
47                 if (max < 3)
48                         max = 0;
49                 adj = 2;
50                 break;
51         case PIPE_PRIM_QUAD_STRIP:
52                 if (max < 4)
53                         max = 0;
54                 adj = 3;
55                 break;
56         default:
57                 assert(0);
58         }
59
60         *restart = start + max - adj;
61         return max;
62 }
63
64 /* Integer base-2 logarithm, rounded towards zero. */
65 static INLINE unsigned log2i(unsigned i)
66 {
67         unsigned r = 0;
68
69         if (i & 0xffff0000) {
70                 i >>= 16;
71                 r += 16;
72         }
73         if (i & 0x0000ff00) {
74                 i >>= 8;
75                 r += 8;
76         }
77         if (i & 0x000000f0) {
78                 i >>= 4;
79                 r += 4;
80         }
81         if (i & 0x0000000c) {
82                 i >>= 2;
83                 r += 2;
84         }
85         if (i & 0x00000002) {
86                 r += 1;
87         }
88         return r;
89 }
90
91 struct u_split_prim {
92    void *priv;
93    void (*emit)(void *priv, unsigned start, unsigned count);
94    void (*edge)(void *priv, boolean enabled);
95
96    unsigned mode;
97    unsigned start;
98    unsigned p_start;
99    unsigned p_end;
100
101    uint repeat_first:1;
102    uint close_first:1;
103    uint edgeflag_off:1;
104 };
105
106 static inline void
107 u_split_prim_init(struct u_split_prim *s,
108                   unsigned mode, unsigned start, unsigned count)
109 {
110    if (mode == PIPE_PRIM_LINE_LOOP) {
111       s->mode = PIPE_PRIM_LINE_STRIP;
112       s->close_first = 1;
113    } else {
114       s->mode = mode;
115       s->close_first = 0;
116    }
117    s->start = start;
118    s->p_start = start;
119    s->p_end = start + count;
120    s->edgeflag_off = 0;
121    s->repeat_first = 0;
122 }
123
124 static INLINE boolean
125 u_split_prim_next(struct u_split_prim *s, unsigned max_verts)
126 {
127    int repeat = 0;
128
129    if (s->repeat_first) {
130       s->emit(s->priv, s->start, 1);
131       max_verts--;
132       if (s->edgeflag_off) {
133          s->edge(s->priv, TRUE);
134          s->edgeflag_off = FALSE;
135       }
136    }
137
138    if (s->p_start + s->close_first + max_verts >= s->p_end) {
139       s->emit(s->priv, s->p_start, s->p_end - s->p_start);
140       if (s->close_first)
141          s->emit(s->priv, s->start, 1);
142       return TRUE;
143    }
144
145    switch (s->mode) {
146    case PIPE_PRIM_LINES:
147       max_verts &= ~1;
148       break;
149    case PIPE_PRIM_LINE_STRIP:
150       repeat = 1;
151       break;
152    case PIPE_PRIM_POLYGON:
153       max_verts--;
154       s->emit(s->priv, s->p_start, max_verts);
155       s->edge(s->priv, FALSE);
156       s->emit(s->priv, s->p_start + max_verts, 1);
157       s->p_start += max_verts;
158       s->repeat_first = TRUE;
159       s->edgeflag_off = TRUE;
160       return FALSE;
161    case PIPE_PRIM_TRIANGLES:
162       max_verts = max_verts - (max_verts % 3);
163       break;
164    case PIPE_PRIM_TRIANGLE_STRIP:
165       /* to ensure winding stays correct, always split
166        * on an even number of generated triangles
167        */
168       max_verts = max_verts & ~1;
169       repeat = 2;
170       break;
171    case PIPE_PRIM_TRIANGLE_FAN:
172       s->repeat_first = TRUE;
173       repeat = 1;
174       break;
175    case PIPE_PRIM_QUADS:
176       max_verts &= ~3;
177       break;
178    case PIPE_PRIM_QUAD_STRIP:
179       max_verts &= ~1;
180       repeat = 2;
181       break;
182    default:
183       break;
184    }
185
186    s->emit (s->priv, s->p_start, max_verts);
187    s->p_start += (max_verts - repeat);
188    return FALSE;
189 }
190
191 #endif