sync with tizen_2.2
[sdk/emulator/qemu.git] / gl / mesa / 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    boolean need_vertex_id;
25    uint32_t prim;
26    uint32_t restart_index;
27    uint32_t instance_id;
28
29    struct {
30       int buffer;
31       float value;
32       uint8_t *data;
33       unsigned offset;
34       unsigned stride;
35    } edgeflag;
36 };
37
38 static void
39 init_push_context(struct nvc0_context *nvc0, struct push_context *ctx)
40 {
41    struct pipe_vertex_element *ve;
42
43    ctx->chan = nvc0->screen->base.channel;
44    ctx->translate = nvc0->vertex->translate;
45
46    if (likely(nvc0->vertex->num_elements < 32))
47       ctx->need_vertex_id = nvc0->vertprog->vp.need_vertex_id;
48    else
49       ctx->need_vertex_id = FALSE;
50
51    ctx->edgeflag.buffer = -1;
52    ctx->edgeflag.value = 0.5f;
53
54    if (unlikely(nvc0->vertprog->vp.edgeflag < PIPE_MAX_ATTRIBS)) {
55       ve = &nvc0->vertex->element[nvc0->vertprog->vp.edgeflag].pipe;
56       ctx->edgeflag.buffer = ve->vertex_buffer_index;
57       ctx->edgeflag.offset = ve->src_offset;
58       ctx->packet_vertex_limit = 1;
59    } else {
60       ctx->packet_vertex_limit = nvc0->vertex->vtx_per_packet_max;
61       if (unlikely(ctx->need_vertex_id))
62          ctx->packet_vertex_limit = 1;
63    }
64
65    ctx->vertex_words = nvc0->vertex->vtx_size;
66 }
67
68 static INLINE void
69 set_edgeflag(struct push_context *ctx, unsigned vtx_id)
70 {
71    float f = *(float *)(ctx->edgeflag.data + vtx_id * ctx->edgeflag.stride);
72
73    if (ctx->edgeflag.value != f) {
74       ctx->edgeflag.value = f;
75       IMMED_RING(ctx->chan, RING_3D(EDGEFLAG_ENABLE), f ? 1 : 0);
76    }
77 }
78
79 static INLINE void
80 set_vertexid(struct push_context *ctx, uint32_t vtx_id)
81 {
82 #if 0
83    BEGIN_RING(ctx->chan, RING_3D(VERTEX_ID), 1); /* broken on nvc0 */
84 #else
85    BEGIN_RING(ctx->chan, RING_3D(VERTEX_DATA), 1); /* as last attribute */
86 #endif
87    OUT_RING  (ctx->chan, vtx_id);
88 }
89
90 static INLINE unsigned
91 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
92 {
93    unsigned i;
94    for (i = 0; i < push; ++i)
95       if (elts[i] == index)
96          break;
97    return i;
98 }
99
100 static INLINE unsigned
101 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
102 {
103    unsigned i;
104    for (i = 0; i < push; ++i)
105       if (elts[i] == index)
106          break;
107    return i;
108 }
109
110 static INLINE unsigned
111 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
112 {
113    unsigned i;
114    for (i = 0; i < push; ++i)
115       if (elts[i] == index)
116          break;
117    return i;
118 }
119
120 static void
121 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
122 {
123    uint8_t *restrict elts = (uint8_t *)ctx->idxbuf + start;
124
125    while (count) {
126       unsigned push = MIN2(count, ctx->packet_vertex_limit);
127       unsigned size, nr;
128
129       nr = push;
130       if (ctx->primitive_restart)
131          nr = prim_restart_search_i08(elts, push, ctx->restart_index);
132
133       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
134          set_edgeflag(ctx, elts[0]);
135
136       size = ctx->vertex_words * nr;
137
138       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
139
140       ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id,
141                                 ctx->chan->cur);
142       ctx->chan->cur += size;
143
144       if (unlikely(ctx->need_vertex_id) && likely(size))
145          set_vertexid(ctx, elts[0]);
146
147       count -= nr;
148       elts += nr;
149
150       if (nr != push) {
151          count--;
152          elts++;
153          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
154          OUT_RING  (ctx->chan, 0);
155          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
156                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
157       }
158    }
159 }
160
161 static void
162 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
163 {
164    uint16_t *restrict elts = (uint16_t *)ctx->idxbuf + start;
165
166    while (count) {
167       unsigned push = MIN2(count, ctx->packet_vertex_limit);
168       unsigned size, nr;
169
170       nr = push;
171       if (ctx->primitive_restart)
172          nr = prim_restart_search_i16(elts, push, ctx->restart_index);
173
174       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
175          set_edgeflag(ctx, elts[0]);
176
177       size = ctx->vertex_words * nr;
178
179       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
180
181       ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id,
182                                  ctx->chan->cur);
183       ctx->chan->cur += size;
184
185       if (unlikely(ctx->need_vertex_id))
186          set_vertexid(ctx, elts[0]);
187
188       count -= nr;
189       elts += nr;
190
191       if (nr != push) {
192          count--;
193          elts++;
194          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
195          OUT_RING  (ctx->chan, 0);
196          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
197                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
198       }
199    }
200 }
201
202 static void
203 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
204 {
205    uint32_t *restrict elts = (uint32_t *)ctx->idxbuf + start;
206
207    while (count) {
208       unsigned push = MIN2(count, ctx->packet_vertex_limit);
209       unsigned size, nr;
210
211       nr = push;
212       if (ctx->primitive_restart)
213          nr = prim_restart_search_i32(elts, push, ctx->restart_index);
214
215       if (unlikely(ctx->edgeflag.buffer >= 0) && likely(nr))
216          set_edgeflag(ctx, elts[0]);
217
218       size = ctx->vertex_words * nr;
219
220       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
221
222       ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id,
223                                ctx->chan->cur);
224       ctx->chan->cur += size;
225
226       if (unlikely(ctx->need_vertex_id))
227          set_vertexid(ctx, elts[0]);
228
229       count -= nr;
230       elts += nr;
231
232       if (nr != push) {
233          count--;
234          elts++;
235          BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
236          OUT_RING  (ctx->chan, 0);
237          OUT_RING  (ctx->chan, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
238                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
239       }
240    }
241 }
242
243 static void
244 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
245 {
246    while (count) {
247       unsigned push = MIN2(count, ctx->packet_vertex_limit);
248       unsigned size = ctx->vertex_words * push;
249
250       if (unlikely(ctx->edgeflag.buffer >= 0))
251          set_edgeflag(ctx, start);
252
253       BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
254
255       ctx->translate->run(ctx->translate, start, push, ctx->instance_id,
256                           ctx->chan->cur);
257       ctx->chan->cur += size;
258
259       if (unlikely(ctx->need_vertex_id))
260          set_vertexid(ctx, start);
261
262       count -= push;
263       start += push;
264    }
265 }
266
267
268 #define NVC0_PRIM_GL_CASE(n) \
269    case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
270
271 static INLINE unsigned
272 nvc0_prim_gl(unsigned prim)
273 {
274    switch (prim) {
275    NVC0_PRIM_GL_CASE(POINTS);
276    NVC0_PRIM_GL_CASE(LINES);
277    NVC0_PRIM_GL_CASE(LINE_LOOP);
278    NVC0_PRIM_GL_CASE(LINE_STRIP);
279    NVC0_PRIM_GL_CASE(TRIANGLES);
280    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
281    NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
282    NVC0_PRIM_GL_CASE(QUADS);
283    NVC0_PRIM_GL_CASE(QUAD_STRIP);
284    NVC0_PRIM_GL_CASE(POLYGON);
285    NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
286    NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
287    NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
288    NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
289    /*
290    NVC0_PRIM_GL_CASE(PATCHES); */
291    default:
292       return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
293       break;
294    }
295 }
296
297 void
298 nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
299 {
300    struct push_context ctx;
301    unsigned i, index_size;
302    unsigned inst_count = info->instance_count;
303    unsigned vert_count = info->count;
304    boolean apply_bias = info->indexed && info->index_bias;
305
306    init_push_context(nvc0, &ctx);
307
308    for (i = 0; i < nvc0->num_vtxbufs; ++i) {
309       uint8_t *data;
310       struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
311       struct nv04_resource *res = nv04_resource(vb->buffer);
312
313       data = nouveau_resource_map_offset(&nvc0->base, res,
314                                          vb->buffer_offset, NOUVEAU_BO_RD);
315
316       if (apply_bias && likely(!(nvc0->vertex->instance_bufs & (1 << i))))
317          data += info->index_bias * vb->stride;
318
319       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
320
321       if (unlikely(i == ctx.edgeflag.buffer)) {
322          ctx.edgeflag.data = data + ctx.edgeflag.offset;
323          ctx.edgeflag.stride = vb->stride;
324       }
325    }
326
327    if (info->indexed) {
328       ctx.idxbuf =
329          nouveau_resource_map_offset(&nvc0->base,
330                                      nv04_resource(nvc0->idxbuf.buffer),
331                                      nvc0->idxbuf.offset, NOUVEAU_BO_RD);
332       if (!ctx.idxbuf)
333          return;
334       index_size = nvc0->idxbuf.index_size;
335       ctx.primitive_restart = info->primitive_restart;
336       ctx.restart_index = info->restart_index;
337    } else {
338       ctx.idxbuf = NULL;
339       index_size = 0;
340       ctx.primitive_restart = FALSE;
341       ctx.restart_index = 0;
342
343       if (info->count_from_stream_output) {
344          struct pipe_context *pipe = &nvc0->base.pipe;
345          struct nvc0_so_target *targ;
346          targ = nvc0_so_target(info->count_from_stream_output);
347          pipe->get_query_result(pipe, targ->pq, TRUE, &vert_count);
348          vert_count /= targ->stride;
349       }
350    }
351
352    ctx.instance_id = info->start_instance;
353    ctx.prim = nvc0_prim_gl(info->mode);
354
355    if (unlikely(ctx.need_vertex_id)) {
356       const unsigned a = nvc0->vertex->num_elements;
357       BEGIN_RING(ctx.chan, RING_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
358       OUT_RING  (ctx.chan, (a << NVC0_3D_VERTEX_ATTRIB_FORMAT_BUFFER__SHIFT) |
359                  NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
360                  NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
361       BEGIN_RING(ctx.chan, RING_3D(VERTEX_ID_REPLACE), 1);
362       OUT_RING  (ctx.chan, (((0x80 + a * 0x10) / 4) << 4) | 1);
363    }
364
365    while (inst_count--) {
366       BEGIN_RING(ctx.chan, RING_3D(VERTEX_BEGIN_GL), 1);
367       OUT_RING  (ctx.chan, ctx.prim);
368       switch (index_size) {
369       case 0:
370          emit_vertices_seq(&ctx, info->start, vert_count);
371          break;
372       case 1:
373          emit_vertices_i08(&ctx, info->start, vert_count);
374          break;
375       case 2:
376          emit_vertices_i16(&ctx, info->start, vert_count);
377          break;
378       case 4:
379          emit_vertices_i32(&ctx, info->start, vert_count);
380          break;
381       default:
382          assert(0);
383          break;
384       }
385       IMMED_RING(ctx.chan, RING_3D(VERTEX_END_GL), 0);
386
387       ctx.instance_id++;
388       ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
389    }
390
391    if (unlikely(ctx.edgeflag.value == 0.0f))
392       IMMED_RING(ctx.chan, RING_3D(EDGEFLAG_ENABLE), 1);
393
394    if (unlikely(ctx.need_vertex_id)) {
395       const unsigned a = nvc0->vertex->num_elements;
396       IMMED_RING(ctx.chan, RING_3D(VERTEX_ID_REPLACE), 0);
397       BEGIN_RING(ctx.chan, RING_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
398       OUT_RING  (ctx.chan,
399                  NVC0_3D_VERTEX_ATTRIB_FORMAT_CONST |
400                  NVC0_3D_VERTEX_ATTRIB_FORMAT_TYPE_FLOAT |
401                  NVC0_3D_VERTEX_ATTRIB_FORMAT_SIZE_32);
402    }
403
404    if (info->indexed)
405       nouveau_resource_unmap(nv04_resource(nvc0->idxbuf.buffer));
406
407    for (i = 0; i < nvc0->num_vtxbufs; ++i)
408       nouveau_resource_unmap(nv04_resource(nvc0->vtxbuf[i].buffer));
409 }