nv50: Adapt for index bias interface change.
[mesa.git] / src / gallium / drivers / nv50 / nv50_push.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5
6 #include "nouveau/nouveau_util.h"
7 #include "nv50_context.h"
8 #include "nv50_resource.h"
9
10 struct push_context {
11 struct nv50_context *nv50;
12
13 unsigned vtx_size;
14
15 void *idxbuf;
16 unsigned idxsize;
17
18 float edgeflag;
19 int edgeflag_attr;
20
21 struct {
22 void *map;
23 unsigned stride;
24 unsigned divisor;
25 unsigned step;
26 void (*push)(struct nouveau_channel *, void *);
27 } attr[16];
28 unsigned attr_nr;
29 };
30
31 static void
32 emit_b32_1(struct nouveau_channel *chan, void *data)
33 {
34 uint32_t *v = data;
35
36 OUT_RING(chan, v[0]);
37 }
38
39 static void
40 emit_b32_2(struct nouveau_channel *chan, void *data)
41 {
42 uint32_t *v = data;
43
44 OUT_RING(chan, v[0]);
45 OUT_RING(chan, v[1]);
46 }
47
48 static void
49 emit_b32_3(struct nouveau_channel *chan, void *data)
50 {
51 uint32_t *v = data;
52
53 OUT_RING(chan, v[0]);
54 OUT_RING(chan, v[1]);
55 OUT_RING(chan, v[2]);
56 }
57
58 static void
59 emit_b32_4(struct nouveau_channel *chan, void *data)
60 {
61 uint32_t *v = data;
62
63 OUT_RING(chan, v[0]);
64 OUT_RING(chan, v[1]);
65 OUT_RING(chan, v[2]);
66 OUT_RING(chan, v[3]);
67 }
68
69 static void
70 emit_b16_1(struct nouveau_channel *chan, void *data)
71 {
72 uint16_t *v = data;
73
74 OUT_RING(chan, v[0]);
75 }
76
77 static void
78 emit_b16_3(struct nouveau_channel *chan, void *data)
79 {
80 uint16_t *v = data;
81
82 OUT_RING(chan, (v[1] << 16) | v[0]);
83 OUT_RING(chan, v[2]);
84 }
85
86 static void
87 emit_b08_1(struct nouveau_channel *chan, void *data)
88 {
89 uint8_t *v = data;
90
91 OUT_RING(chan, v[0]);
92 }
93
94 static void
95 emit_b08_3(struct nouveau_channel *chan, void *data)
96 {
97 uint8_t *v = data;
98
99 OUT_RING(chan, (v[2] << 16) | (v[1] << 8) | v[0]);
100 }
101
102 static INLINE void
103 emit_vertex(struct push_context *ctx, unsigned n)
104 {
105 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
106 struct nouveau_channel *chan = tesla->channel;
107 int i;
108
109 if (ctx->edgeflag_attr < 16) {
110 float *edgeflag = ctx->attr[ctx->edgeflag_attr].map +
111 ctx->attr[ctx->edgeflag_attr].stride * n;
112
113 if (*edgeflag != ctx->edgeflag) {
114 BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
115 OUT_RING (chan, *edgeflag ? 1 : 0);
116 ctx->edgeflag = *edgeflag;
117 }
118 }
119
120 BEGIN_RING_NI(chan, tesla, NV50TCL_VERTEX_DATA, ctx->vtx_size);
121 for (i = 0; i < ctx->attr_nr; i++)
122 ctx->attr[i].push(chan, ctx->attr[i].map + ctx->attr[i].stride * n);
123 }
124
125 static void
126 emit_edgeflag(void *priv, boolean enabled)
127 {
128 struct push_context *ctx = priv;
129 struct nouveau_grobj *tesla = ctx->nv50->screen->tesla;
130 struct nouveau_channel *chan = tesla->channel;
131
132 BEGIN_RING(chan, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
133 OUT_RING (chan, enabled ? 1 : 0);
134 }
135
136 static void
137 emit_elt08(void *priv, unsigned start, unsigned count)
138 {
139 struct push_context *ctx = priv;
140 uint8_t *idxbuf = ctx->idxbuf;
141
142 while (count--)
143 emit_vertex(ctx, idxbuf[start++]);
144 }
145
146 static void
147 emit_elt16(void *priv, unsigned start, unsigned count)
148 {
149 struct push_context *ctx = priv;
150 uint16_t *idxbuf = ctx->idxbuf;
151
152 while (count--)
153 emit_vertex(ctx, idxbuf[start++]);
154 }
155
156 static void
157 emit_elt32(void *priv, unsigned start, unsigned count)
158 {
159 struct push_context *ctx = priv;
160 uint32_t *idxbuf = ctx->idxbuf;
161
162 while (count--)
163 emit_vertex(ctx, idxbuf[start++]);
164 }
165
166 static void
167 emit_verts(void *priv, unsigned start, unsigned count)
168 {
169 while (count--)
170 emit_vertex(priv, start++);
171 }
172
173 void
174 nv50_push_elements_instanced(struct pipe_context *pipe,
175 struct pipe_resource *idxbuf,
176 unsigned idxsize, int idxbias,
177 unsigned mode, unsigned start, unsigned count,
178 unsigned i_start, unsigned i_count)
179 {
180 struct nv50_context *nv50 = nv50_context(pipe);
181 struct nouveau_grobj *tesla = nv50->screen->tesla;
182 struct nouveau_channel *chan = tesla->channel;
183 struct push_context ctx;
184 const unsigned p_overhead = 4 + /* begin/end */
185 4; /* potential edgeflag enable/disable */
186 const unsigned v_overhead = 1 + /* VERTEX_DATA packet header */
187 2; /* potential edgeflag modification */
188 struct u_split_prim s;
189 unsigned vtx_size;
190 boolean nzi = FALSE;
191 int i;
192
193 ctx.nv50 = nv50;
194 ctx.attr_nr = 0;
195 ctx.idxbuf = NULL;
196 ctx.vtx_size = 0;
197 ctx.edgeflag = 0.5f;
198 ctx.edgeflag_attr = nv50->vertprog->cfg.edgeflag_in;
199
200 /* map vertex buffers, determine vertex size */
201 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
202 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
203 struct pipe_vertex_buffer *vb = &nv50->vtxbuf[ve->vertex_buffer_index];
204 struct nouveau_bo *bo = nv50_resource(vb->buffer)->bo;
205 unsigned size, nr_components, n;
206
207 if (!(nv50->vbo_fifo & (1 << i)))
208 continue;
209 n = ctx.attr_nr++;
210
211 if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) {
212 assert(bo->map);
213 return;
214 }
215 ctx.attr[n].map = bo->map + vb->buffer_offset + ve->src_offset;
216 nouveau_bo_unmap(bo);
217
218 ctx.attr[n].stride = vb->stride;
219 ctx.attr[n].divisor = ve->instance_divisor;
220 if (ctx.attr[n].divisor) {
221 ctx.attr[n].step = i_start % ve->instance_divisor;
222 ctx.attr[n].map += i_start * vb->stride;
223 }
224
225 size = util_format_get_component_bits(ve->src_format,
226 UTIL_FORMAT_COLORSPACE_RGB, 0);
227 nr_components = util_format_get_nr_components(ve->src_format);
228 switch (size) {
229 case 8:
230 switch (nr_components) {
231 case 1: ctx.attr[n].push = emit_b08_1; break;
232 case 2: ctx.attr[n].push = emit_b16_1; break;
233 case 3: ctx.attr[n].push = emit_b08_3; break;
234 case 4: ctx.attr[n].push = emit_b32_1; break;
235 }
236 ctx.vtx_size++;
237 break;
238 case 16:
239 switch (nr_components) {
240 case 1: ctx.attr[n].push = emit_b16_1; break;
241 case 2: ctx.attr[n].push = emit_b32_1; break;
242 case 3: ctx.attr[n].push = emit_b16_3; break;
243 case 4: ctx.attr[n].push = emit_b32_2; break;
244 }
245 ctx.vtx_size += (nr_components + 1) >> 1;
246 break;
247 case 32:
248 switch (nr_components) {
249 case 1: ctx.attr[n].push = emit_b32_1; break;
250 case 2: ctx.attr[n].push = emit_b32_2; break;
251 case 3: ctx.attr[n].push = emit_b32_3; break;
252 case 4: ctx.attr[n].push = emit_b32_4; break;
253 }
254 ctx.vtx_size += nr_components;
255 break;
256 default:
257 assert(0);
258 return;
259 }
260 }
261 vtx_size = ctx.vtx_size + v_overhead;
262
263 /* map index buffer, if present */
264 if (idxbuf) {
265 struct nouveau_bo *bo = nv50_resource(idxbuf)->bo;
266
267 if (nouveau_bo_map(bo, NOUVEAU_BO_RD)) {
268 assert(bo->map);
269 return;
270 }
271 ctx.idxbuf = bo->map;
272 ctx.idxsize = idxsize;
273 assert(idxbias == 0);
274 nouveau_bo_unmap(bo);
275 }
276
277 s.priv = &ctx;
278 s.edge = emit_edgeflag;
279 if (idxbuf) {
280 if (idxsize == 1)
281 s.emit = emit_elt08;
282 else
283 if (idxsize == 2)
284 s.emit = emit_elt16;
285 else
286 s.emit = emit_elt32;
287 } else
288 s.emit = emit_verts;
289
290 /* per-instance loop */
291 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
292 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
293 OUT_RING (chan, i_start);
294 while (i_count--) {
295 unsigned max_verts;
296 boolean done;
297
298 for (i = 0; i < ctx.attr_nr; i++) {
299 if (!ctx.attr[i].divisor ||
300 ctx.attr[i].divisor != ++ctx.attr[i].step)
301 continue;
302 ctx.attr[i].step = 0;
303 ctx.attr[i].map += ctx.attr[i].stride;
304 }
305
306 u_split_prim_init(&s, mode, start, count);
307 do {
308 if (AVAIL_RING(chan) < p_overhead + (6 * vtx_size)) {
309 FIRE_RING(chan);
310 if (!nv50_state_validate(nv50, p_overhead + (6 * vtx_size))) {
311 assert(0);
312 return;
313 }
314 }
315
316 max_verts = AVAIL_RING(chan);
317 max_verts -= p_overhead;
318 max_verts /= vtx_size;
319
320 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
321 OUT_RING (chan, nv50_prim(s.mode) | (nzi ? (1 << 28) : 0));
322 done = u_split_prim_next(&s, max_verts);
323 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
324 OUT_RING (chan, 0);
325 } while (!done);
326
327 nzi = TRUE;
328 }
329 }