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