Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / gallium / drivers / nvc0 / nvc0_push.c
1
2 #include "pipe/p_context.h"
3 #include "pipe/p_state.h"
4 #include "util/u_inlines.h"
5 #include "util/u_format.h"
6 #include "translate/translate.h"
7
8 #include "nvc0_context.h"
9 #include "nvc0_resource.h"
10
11 #include "nvc0_3d.xml.h"
12
13 struct push_context {
14    struct nouveau_channel *chan;
15
16    void *idxbuf;
17
18    uint32_t vertex_words;
19    uint32_t packet_vertex_limit;
20
21    struct translate *translate;
22
23    boolean primitive_restart;
24    uint32_t prim;
25    uint32_t restart_index;
26    uint32_t instance_id;
27
28    struct {
29       int buffer;
30       float value;
31       uint8_t *data;
32       unsigned offset;
33       unsigned stride;
34    } edgeflag;
35 };
36
37 static void
38 init_push_context(struct nvc0_context *nvc0, struct push_context *ctx)
39 {
40    struct pipe_vertex_element *ve;
41
42    ctx->chan = nvc0->screen->base.channel;
43    ctx->translate = nvc0->vertex->translate;
44
45    ctx->edgeflag.value = 0.5f;
46
47    if (NVC0_USING_EDGEFLAG(nvc0)) {
48       ve = &nvc0->vertex->element[nvc0->vertprog->vp.edgeflag].pipe;
49
50       ctx->edgeflag.buffer = ve->vertex_buffer_index;
51       ctx->edgeflag.offset = ve->src_offset;
52
53       ctx->packet_vertex_limit = 1;
54    } else {
55       ctx->edgeflag.buffer = -1;
56       ctx->edgeflag.offset = 0;
57       ctx->edgeflag.stride = 0;
58       ctx->edgeflag.data = NULL;
59
60       ctx->packet_vertex_limit = nvc0->vertex->vtx_per_packet_max;
61    }
62
63    ctx->vertex_words = nvc0->vertex->vtx_size;
64 }
65
66 static INLINE void
67 set_edgeflag(struct push_context *ctx, unsigned vtx_id)
68 {
69    float f = *(float *)(ctx->edgeflag.data + vtx_id * ctx->edgeflag.stride);
70
71    if (ctx->edgeflag.value != f) {
72       ctx->edgeflag.value = f;
73       IMMED_RING(ctx->chan, RING_3D(EDGEFLAG_ENABLE), f ? 1 : 0);
74    }
75 }
76
77 static INLINE unsigned
78 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
79 {
80    unsigned i;
81    for (i = 0; i < push; ++i)
82       if (elts[i] == index)
83          break;
84    return i;
85 }
86
87 static INLINE unsigned
88 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
89 {
90    unsigned i;
91    for (i = 0; i < push; ++i)
92       if (elts[i] == index)
93          break;
94    return i;
95 }
96
97 static INLINE unsigned
98 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
99 {
100    unsigned i;
101    for (i = 0; i < push; ++i)
102       if (elts[i] == index)
103          break;
104    return i;
105 }
106
107 static void
108 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
109 {
110    uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start;
111
112    while (count) {
113       unsigned push = MIN2(count, ctx->packet_vertex_limit);
114       unsigned size, nr;
115
116       nr = push;
117       if (ctx->primitive_restart)
118          nr = prim_restart_search_i08(elts, push, ctx->restart_index);
119
120       if (unlikely(ctx->edgeflag.buffer >= 0) && nr)
121          set_edgeflag(ctx, elts[0]);
122
123       size = ctx->vertex_words * nr;
124
125       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
126
127       ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id,
128                                 ctx->chan->cur);
129
130       ctx->chan->cur += size;
131       count -= nr;
132       elts += nr;
133
134       if (nr != push) {
135          count--;
136          elts++;
137          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
138          OUT_RING  (ctx->chan, 0);
139          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
140                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
141       }
142    }
143 }
144
145 static void
146 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
147 {
148    uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start;
149
150    while (count) {
151       unsigned push = MIN2(count, ctx->packet_vertex_limit);
152       unsigned size, nr;
153
154       nr = push;
155       if (ctx->primitive_restart)
156          nr = prim_restart_search_i16(elts, push, ctx->restart_index);
157
158       if (unlikely(ctx->edgeflag.buffer >= 0) && nr)
159          set_edgeflag(ctx, elts[0]);
160
161       size = ctx->vertex_words * nr;
162
163       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
164
165       ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id,
166                                  ctx->chan->cur);
167
168       ctx->chan->cur += size;
169       count -= nr;
170       elts += nr;
171
172       if (nr != push) {
173          count--;
174          elts++;
175          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
176          OUT_RING  (ctx->chan, 0);
177          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
178                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
179       }
180    }
181 }
182
183 static void
184 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
185 {
186    uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start;
187
188    while (count) {
189       unsigned push = MIN2(count, ctx->packet_vertex_limit);
190       unsigned size, nr;
191
192       nr = push;
193       if (ctx->primitive_restart)
194          nr = prim_restart_search_i32(elts, push, ctx->restart_index);
195
196       if (unlikely(ctx->edgeflag.buffer >= 0) && nr)
197          set_edgeflag(ctx, elts[0]);
198
199       size = ctx->vertex_words * nr;
200
201       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
202
203       ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id,
204                                ctx->chan->cur);
205
206       ctx->chan->cur += size;
207       count -= nr;
208       elts += nr;
209
210       if (nr != push) {
211          count--;
212          elts++;
213          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
214          OUT_RING  (ctx->chan, 0);
215          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
216                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
217       }
218    }
219 }
220
221 static void
222 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
223 {
224    while (count) {
225       unsigned push = MIN2(count, ctx->packet_vertex_limit);
226       unsigned size = ctx->vertex_words * push;
227
228       if (unlikely(ctx->edgeflag.buffer >= 0))
229          set_edgeflag(ctx, start);
230
231       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
232
233       ctx->translate->run(ctx->translate, start, push, ctx->instance_id,
234                           ctx->chan->cur);
235       ctx->chan->cur += size;
236       count -= push;
237       start += push;
238    }
239 }
240
241
242 #define NVC0_PRIM_GL_CASE(n) \
243    case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
244
245 static INLINE unsigned
246 nvc0_prim_gl(unsigned prim)
247 {
248    switch (prim) {
249    NVC0_PRIM_GL_CASE(POINTS);
250    NVC0_PRIM_GL_CASE(LINES);
251    NVC0_PRIM_GL_CASE(LINE_LOOP);
252    NVC0_PRIM_GL_CASE(LINE_STRIP);
253    NVC0_PRIM_GL_CASE(TRIANGLES);
254    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
255    NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
256    NVC0_PRIM_GL_CASE(QUADS);
257    NVC0_PRIM_GL_CASE(QUAD_STRIP);
258    NVC0_PRIM_GL_CASE(POLYGON);
259    NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
260    NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
261    NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
262    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
263    /*
264    NVC0_PRIM_GL_CASE(PATCHES); */
265    default:
266       return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
267       break;
268    }
269 }
270
271 void
272 nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
273 {
274    struct push_context ctx;
275    unsigned i, index_size;
276    unsigned inst = info->instance_count;
277    boolean apply_bias = info->indexed && info->index_bias;
278
279    init_push_context(nvc0, &ctx);
280
281    for (i = 0; i < nvc0->num_vtxbufs; ++i) {
282       uint8_t *data;
283       struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
284       struct nv04_resource *res = nv04_resource(vb->buffer);
285
286       data = nouveau_resource_map_offset(&nvc0->base, res,
287                                          vb->buffer_offset, NOUVEAU_BO_RD);
288
289       if (apply_bias && likely(!(nvc0->vertex->instance_bufs & (1 << i))))
290          data += info->index_bias * vb->stride;
291
292       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
293
294       if (unlikely(i == ctx.edgeflag.buffer)) {
295          ctx.edgeflag.data = data + ctx.edgeflag.offset;
296          ctx.edgeflag.stride = vb->stride;
297       }
298    }
299
300    if (info->indexed) {
301       ctx.idxbuf =
302          nouveau_resource_map_offset(&nvc0->base,
303                                      nv04_resource(nvc0->idxbuf.buffer),
304                                      nvc0->idxbuf.offset, NOUVEAU_BO_RD);
305       if (!ctx.idxbuf)
306          return;
307       index_size = nvc0->idxbuf.index_size;
308       ctx.primitive_restart = info->primitive_restart;
309       ctx.restart_index = info->restart_index;
310    } else {
311       ctx.idxbuf = NULL;
312       index_size = 0;
313       ctx.primitive_restart = FALSE;
314       ctx.restart_index = 0;
315    }
316
317    ctx.instance_id = info->start_instance;
318    ctx.prim = nvc0_prim_gl(info->mode);
319
320    while (inst--) {
321       BEGIN_RING(ctx.chan, RING_3D(VERTEX_BEGIN_GL), 1);
322       OUT_RING  (ctx.chan, ctx.prim);
323       switch (index_size) {
324       case 0:
325          emit_vertices_seq(&ctx, info->start, info->count);
326          break;
327       case 1:
328          emit_vertices_i08(&ctx, info->start, info->count);
329          break;
330       case 2:
331          emit_vertices_i16(&ctx, info->start, info->count);
332          break;
333       case 4:
334          emit_vertices_i32(&ctx, info->start, info->count);
335          break;
336       default:
337          assert(0);
338          break;
339       }
340       IMMED_RING(ctx.chan, RING_3D(VERTEX_END_GL), 0);
341
342       ctx.instance_id++;
343       ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
344    }
345
346    if (unlikely(ctx.edgeflag.value == 0.0f))
347       IMMED_RING(ctx.chan, RING_3D(EDGEFLAG_ENABLE), 1);
348
349    if (info->indexed)
350       nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
351
352    for (i = 0; i < nvc0->num_vtxbufs; ++i)
353       nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
354 }