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_pushbuf *push;
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
init_push_context(struct nvc0_context * nvc0,struct push_context * ctx)39 init_push_context(struct nvc0_context *nvc0, struct push_context *ctx)
40 {
41    struct pipe_vertex_element *ve;
42 
43    ctx->push = nvc0->base.pushbuf;
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
set_edgeflag(struct push_context * ctx,unsigned vtx_id)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_NVC0(ctx->push, NVC0_3D(EDGEFLAG), f ? 1 : 0);
76    }
77 }
78 
79 static INLINE void
set_vertexid(struct push_context * ctx,uint32_t vtx_id)80 set_vertexid(struct push_context *ctx, uint32_t vtx_id)
81 {
82 #if 0
83    BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_ID), 1); /* broken on nvc0 */
84 #else
85    BEGIN_NVC0(ctx->push, NVC0_3D(VERTEX_DATA), 1); /* as last attribute */
86 #endif
87    PUSH_DATA (ctx->push, vtx_id);
88 }
89 
90 static INLINE unsigned
prim_restart_search_i08(uint8_t * elts,unsigned push,uint8_t index)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
prim_restart_search_i16(uint16_t * elts,unsigned push,uint16_t index)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
prim_restart_search_i32(uint32_t * elts,unsigned push,uint32_t index)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
emit_vertices_i08(struct push_context * ctx,unsigned start,unsigned count)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_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
139 
140       ctx->translate->run_elts8(ctx->translate, elts, nr, ctx->instance_id,
141                                 ctx->push->cur);
142       ctx->push->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_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
154          PUSH_DATA (ctx->push, 0);
155          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
156                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
157       }
158    }
159 }
160 
161 static void
emit_vertices_i16(struct push_context * ctx,unsigned start,unsigned count)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_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
180 
181       ctx->translate->run_elts16(ctx->translate, elts, nr, ctx->instance_id,
182                                  ctx->push->cur);
183       ctx->push->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_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
195          PUSH_DATA (ctx->push, 0);
196          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
197                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
198       }
199    }
200 }
201 
202 static void
emit_vertices_i32(struct push_context * ctx,unsigned start,unsigned count)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_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
221 
222       ctx->translate->run_elts(ctx->translate, elts, nr, ctx->instance_id,
223                                ctx->push->cur);
224       ctx->push->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_NVC0(ctx->push, NVC0_3D(VERTEX_END_GL), 2);
236          PUSH_DATA (ctx->push, 0);
237          PUSH_DATA (ctx->push, NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_CONT |
238                     (ctx->prim & ~NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT));
239       }
240    }
241 }
242 
243 static void
emit_vertices_seq(struct push_context * ctx,unsigned start,unsigned count)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_NIC0(ctx->push, NVC0_3D(VERTEX_DATA), size);
254 
255       ctx->translate->run(ctx->translate, start, push, ctx->instance_id,
256                           ctx->push->cur);
257       ctx->push->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
nvc0_prim_gl(unsigned prim)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
nvc0_push_vbo(struct nvc0_context * nvc0,const struct pipe_draw_info * info)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, (void*)&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_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
358       PUSH_DATA (ctx.push, (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_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 1);
362       PUSH_DATA (ctx.push, (((0x80 + a * 0x10) / 4) << 4) | 1);
363    }
364 
365    while (inst_count--) {
366       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_BEGIN_GL), 1);
367       PUSH_DATA (ctx.push, 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_NVC0(ctx.push, NVC0_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_NVC0(ctx.push, NVC0_3D(EDGEFLAG), 1);
393 
394    if (unlikely(ctx.need_vertex_id)) {
395       const unsigned a = nvc0->vertex->num_elements;
396       IMMED_NVC0(ctx.push, NVC0_3D(VERTEX_ID_REPLACE), 0);
397       BEGIN_NVC0(ctx.push, NVC0_3D(VERTEX_ATTRIB_FORMAT(a)), 1);
398       PUSH_DATA (ctx.push,
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 }
410