Merge commit 'origin/master' into gallium-sw-api-2
[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 int repeat_first:1;
102 int close_first:1;
103 int 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