1 
2 #include "pipe/p_context.h"
3 #include "pipe/p_state.h"
4 #include "util/u_inlines.h"
5 #include "util/format/u_format.h"
6 #include "translate/translate.h"
7 
8 #include "nv50/nv50_context.h"
9 #include "nv50/nv50_resource.h"
10 
11 #include "nv50/nv50_3d.xml.h"
12 
13 struct push_context {
14    struct nouveau_pushbuf *push;
15 
16    const void *idxbuf;
17 
18    float edgeflag;
19    int edgeflag_attr;
20 
21    uint32_t vertex_words;
22    uint32_t packet_vertex_limit;
23 
24    struct translate *translate;
25 
26    bool primitive_restart;
27 
28    bool need_vertex_id;
29    int32_t index_bias;
30 
31    uint32_t prim;
32    uint32_t restart_index;
33    uint32_t start_instance;
34    uint32_t instance_id;
35 };
36 
37 static inline unsigned
prim_restart_search_i08(uint8_t * elts,unsigned push,uint8_t index)38 prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
39 {
40    unsigned i;
41    for (i = 0; i < push; ++i)
42       if (elts[i] == index)
43          break;
44    return i;
45 }
46 
47 static inline unsigned
prim_restart_search_i16(uint16_t * elts,unsigned push,uint16_t index)48 prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
49 {
50    unsigned i;
51    for (i = 0; i < push; ++i)
52       if (elts[i] == index)
53          break;
54    return i;
55 }
56 
57 static inline unsigned
prim_restart_search_i32(uint32_t * elts,unsigned push,uint32_t index)58 prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
59 {
60    unsigned i;
61    for (i = 0; i < push; ++i)
62       if (elts[i] == index)
63          break;
64    return i;
65 }
66 
67 static void
emit_vertices_i08(struct push_context * ctx,unsigned start,unsigned count)68 emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
69 {
70    uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
71 
72    while (count) {
73       unsigned push = MIN2(count, ctx->packet_vertex_limit);
74       unsigned size, nr;
75 
76       nr = push;
77       if (ctx->primitive_restart)
78          nr = prim_restart_search_i08(elts, push, ctx->restart_index);
79 
80       size = ctx->vertex_words * nr;
81 
82       if (unlikely(ctx->need_vertex_id)) {
83          BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
84          PUSH_DATA (ctx->push, *elts + ctx->index_bias);
85       }
86 
87       BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
88 
89       ctx->translate->run_elts8(ctx->translate, elts, nr,
90                                 ctx->start_instance, ctx->instance_id,
91                                 ctx->push->cur);
92 
93       ctx->push->cur += size;
94       count -= nr;
95       elts += nr;
96 
97       if (nr != push) {
98          count--;
99          elts++;
100          BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
101          PUSH_DATA (ctx->push, ctx->restart_index);
102       }
103    }
104 }
105 
106 static void
emit_vertices_i16(struct push_context * ctx,unsigned start,unsigned count)107 emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
108 {
109    uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
110 
111    while (count) {
112       unsigned push = MIN2(count, ctx->packet_vertex_limit);
113       unsigned size, nr;
114 
115       nr = push;
116       if (ctx->primitive_restart)
117          nr = prim_restart_search_i16(elts, push, ctx->restart_index);
118 
119       size = ctx->vertex_words * nr;
120 
121       if (unlikely(ctx->need_vertex_id)) {
122          BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
123          PUSH_DATA (ctx->push, *elts + ctx->index_bias);
124       }
125 
126       BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
127 
128       ctx->translate->run_elts16(ctx->translate, elts, nr,
129                                  ctx->start_instance, ctx->instance_id,
130                                  ctx->push->cur);
131 
132       ctx->push->cur += size;
133       count -= nr;
134       elts += nr;
135 
136       if (nr != push) {
137          count--;
138          elts++;
139          BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
140          PUSH_DATA (ctx->push, ctx->restart_index);
141       }
142    }
143 }
144 
145 static void
emit_vertices_i32(struct push_context * ctx,unsigned start,unsigned count)146 emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
147 {
148    uint32_t *elts = (uint32_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_i32(elts, push, ctx->restart_index);
157 
158       size = ctx->vertex_words * nr;
159 
160       if (unlikely(ctx->need_vertex_id)) {
161          BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
162          PUSH_DATA (ctx->push, *elts + ctx->index_bias);
163       }
164 
165       BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
166 
167       ctx->translate->run_elts(ctx->translate, elts, nr,
168                                ctx->start_instance, ctx->instance_id,
169                                ctx->push->cur);
170 
171       ctx->push->cur += size;
172       count -= nr;
173       elts += nr;
174 
175       if (nr != push) {
176          count--;
177          elts++;
178          BEGIN_NV04(ctx->push, NV50_3D(VB_ELEMENT_U32), 1);
179          PUSH_DATA (ctx->push, ctx->restart_index);
180       }
181    }
182 }
183 
184 static void
emit_vertices_seq(struct push_context * ctx,unsigned start,unsigned count)185 emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
186 {
187    uint32_t elts = 0;
188 
189    while (count) {
190       unsigned push = MIN2(count, ctx->packet_vertex_limit);
191       unsigned size = ctx->vertex_words * push;
192 
193       if (unlikely(ctx->need_vertex_id)) {
194          /* For non-indexed draws, gl_VertexID goes up after each vertex. */
195          BEGIN_NV04(ctx->push, NV84_3D(VERTEX_ID_BASE), 1);
196          PUSH_DATA (ctx->push, elts++);
197       }
198 
199       BEGIN_NI04(ctx->push, NV50_3D(VERTEX_DATA), size);
200 
201       ctx->translate->run(ctx->translate, start, push,
202                           ctx->start_instance, ctx->instance_id,
203                           ctx->push->cur);
204       ctx->push->cur += size;
205       count -= push;
206       start += push;
207    }
208 }
209 
210 
211 #define NV50_PRIM_GL_CASE(n) \
212    case PIPE_PRIM_##n: return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
213 
214 static inline unsigned
nv50_prim_gl(unsigned prim)215 nv50_prim_gl(unsigned prim)
216 {
217    switch (prim) {
218    NV50_PRIM_GL_CASE(POINTS);
219    NV50_PRIM_GL_CASE(LINES);
220    NV50_PRIM_GL_CASE(LINE_LOOP);
221    NV50_PRIM_GL_CASE(LINE_STRIP);
222    NV50_PRIM_GL_CASE(TRIANGLES);
223    NV50_PRIM_GL_CASE(TRIANGLE_STRIP);
224    NV50_PRIM_GL_CASE(TRIANGLE_FAN);
225    NV50_PRIM_GL_CASE(QUADS);
226    NV50_PRIM_GL_CASE(QUAD_STRIP);
227    NV50_PRIM_GL_CASE(POLYGON);
228    NV50_PRIM_GL_CASE(LINES_ADJACENCY);
229    NV50_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
230    NV50_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
231    NV50_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
232    /*
233    NV50_PRIM_GL_CASE(PATCHES); */
234    default:
235       return NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
236       break;
237    }
238 }
239 
240 void
nv50_push_vbo(struct nv50_context * nv50,const struct pipe_draw_info * info,const struct pipe_draw_indirect_info * indirect,const struct pipe_draw_start_count_bias * draw)241 nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info,
242               const struct pipe_draw_indirect_info *indirect,
243               const struct pipe_draw_start_count_bias *draw)
244 {
245    struct push_context ctx;
246    unsigned i, index_size;
247    unsigned inst_count = info->instance_count;
248    unsigned vert_count = draw->count;
249    bool apply_bias = info->index_size && draw->index_bias;
250 
251    ctx.push = nv50->base.pushbuf;
252    ctx.translate = nv50->vertex->translate;
253 
254    ctx.need_vertex_id = nv50->screen->base.class_3d >= NV84_3D_CLASS &&
255       nv50->vertprog->vp.need_vertex_id && (nv50->vertex->num_elements < 32);
256    ctx.index_bias = info->index_size ? draw->index_bias : 0;
257    ctx.instance_id = 0;
258 
259    /* For indexed draws, gl_VertexID must be emitted for every vertex. */
260    ctx.packet_vertex_limit =
261       ctx.need_vertex_id ? 1 : nv50->vertex->packet_vertex_limit;
262    ctx.vertex_words = nv50->vertex->vertex_size;
263 
264    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
265    for (i = 0; i < nv50->num_vtxbufs; ++i) {
266       const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
267       const uint8_t *data;
268 
269       if (unlikely(!vb->is_user_buffer)) {
270          if (!vb->buffer.resource)
271             continue;
272 
273          data = nouveau_resource_map_offset(&nv50->base,
274             nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
275       } else
276          data = vb->buffer.user;
277 
278       if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
279          data += (ptrdiff_t)(info->index_size ? draw->index_bias : 0) * vb->stride;
280 
281       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
282    }
283 
284    if (info->index_size) {
285       if (!info->has_user_indices) {
286          ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
287             nv04_resource(info->index.resource), 0, NOUVEAU_BO_RD);
288       } else {
289          ctx.idxbuf = info->index.user;
290       }
291       if (!ctx.idxbuf)
292          return;
293       index_size = info->index_size;
294       ctx.primitive_restart = info->primitive_restart;
295       ctx.restart_index = info->restart_index;
296    } else {
297       if (unlikely(indirect && indirect->count_from_stream_output)) {
298          struct pipe_context *pipe = &nv50->base.pipe;
299          struct nv50_so_target *targ;
300          targ = nv50_so_target(indirect->count_from_stream_output);
301          if (!targ->pq) {
302             NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n");
303             return;
304          }
305          pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
306          vert_count /= targ->stride;
307       }
308       ctx.idxbuf = NULL;
309       index_size = 0;
310       ctx.primitive_restart = false;
311       ctx.restart_index = 0;
312    }
313 
314    ctx.start_instance = info->start_instance;
315    ctx.prim = nv50_prim_gl(info->mode);
316 
317    if (info->primitive_restart) {
318       BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2);
319       PUSH_DATA (ctx.push, 1);
320       PUSH_DATA (ctx.push, info->restart_index);
321    } else
322    if (nv50->state.prim_restart) {
323       BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1);
324       PUSH_DATA (ctx.push, 0);
325    }
326    nv50->state.prim_restart = info->primitive_restart;
327 
328    while (inst_count--) {
329       BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1);
330       PUSH_DATA (ctx.push, ctx.prim);
331       switch (index_size) {
332       case 0:
333          emit_vertices_seq(&ctx, draw->start, vert_count);
334          break;
335       case 1:
336          emit_vertices_i08(&ctx, draw->start, vert_count);
337          break;
338       case 2:
339          emit_vertices_i16(&ctx, draw->start, vert_count);
340          break;
341       case 4:
342          emit_vertices_i32(&ctx, draw->start, vert_count);
343          break;
344       default:
345          assert(0);
346          break;
347       }
348       BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1);
349       PUSH_DATA (ctx.push, 0);
350 
351       ctx.instance_id++;
352       ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
353    }
354 
355    if (unlikely(ctx.need_vertex_id)) {
356       /* Reset gl_VertexID to prevent future indexed draws to be confused. */
357       BEGIN_NV04(ctx.push, NV84_3D(VERTEX_ID_BASE), 1);
358       PUSH_DATA (ctx.push, nv50->state.index_bias);
359    }
360 }
361