• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)241 nv50_push_vbo(struct nv50_context *nv50, const struct pipe_draw_info *info)
242 {
243    struct push_context ctx;
244    unsigned i, index_size;
245    unsigned inst_count = info->instance_count;
246    unsigned vert_count = info->count;
247    bool apply_bias = info->index_size && info->index_bias;
248 
249    ctx.push = nv50->base.pushbuf;
250    ctx.translate = nv50->vertex->translate;
251 
252    ctx.need_vertex_id = nv50->screen->base.class_3d >= NV84_3D_CLASS &&
253       nv50->vertprog->vp.need_vertex_id && (nv50->vertex->num_elements < 32);
254    ctx.index_bias = info->index_bias;
255    ctx.instance_id = 0;
256 
257    /* For indexed draws, gl_VertexID must be emitted for every vertex. */
258    ctx.packet_vertex_limit =
259       ctx.need_vertex_id ? 1 : nv50->vertex->packet_vertex_limit;
260    ctx.vertex_words = nv50->vertex->vertex_size;
261 
262    assert(nv50->num_vtxbufs <= PIPE_MAX_ATTRIBS);
263    for (i = 0; i < nv50->num_vtxbufs; ++i) {
264       const struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
265       const uint8_t *data;
266 
267       if (unlikely(!vb->is_user_buffer)) {
268          if (!vb->buffer.resource)
269             continue;
270 
271          data = nouveau_resource_map_offset(&nv50->base,
272             nv04_resource(vb->buffer.resource), vb->buffer_offset, NOUVEAU_BO_RD);
273       } else
274          data = vb->buffer.user;
275 
276       if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
277          data += (ptrdiff_t)info->index_bias * vb->stride;
278 
279       ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
280    }
281 
282    if (info->index_size) {
283       if (!info->has_user_indices) {
284          ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
285             nv04_resource(info->index.resource), 0, NOUVEAU_BO_RD);
286       } else {
287          ctx.idxbuf = info->index.user;
288       }
289       if (!ctx.idxbuf)
290          return;
291       index_size = info->index_size;
292       ctx.primitive_restart = info->primitive_restart;
293       ctx.restart_index = info->restart_index;
294    } else {
295       if (unlikely(info->count_from_stream_output)) {
296          struct pipe_context *pipe = &nv50->base.pipe;
297          struct nv50_so_target *targ;
298          targ = nv50_so_target(info->count_from_stream_output);
299          if (!targ->pq) {
300             NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n");
301             return;
302          }
303          pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
304          vert_count /= targ->stride;
305       }
306       ctx.idxbuf = NULL;
307       index_size = 0;
308       ctx.primitive_restart = false;
309       ctx.restart_index = 0;
310    }
311 
312    ctx.start_instance = info->start_instance;
313    ctx.prim = nv50_prim_gl(info->mode);
314 
315    if (info->primitive_restart) {
316       BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2);
317       PUSH_DATA (ctx.push, 1);
318       PUSH_DATA (ctx.push, info->restart_index);
319    } else
320    if (nv50->state.prim_restart) {
321       BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1);
322       PUSH_DATA (ctx.push, 0);
323    }
324    nv50->state.prim_restart = info->primitive_restart;
325 
326    while (inst_count--) {
327       BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1);
328       PUSH_DATA (ctx.push, ctx.prim);
329       switch (index_size) {
330       case 0:
331          emit_vertices_seq(&ctx, info->start, vert_count);
332          break;
333       case 1:
334          emit_vertices_i08(&ctx, info->start, vert_count);
335          break;
336       case 2:
337          emit_vertices_i16(&ctx, info->start, vert_count);
338          break;
339       case 4:
340          emit_vertices_i32(&ctx, info->start, vert_count);
341          break;
342       default:
343          assert(0);
344          break;
345       }
346       BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1);
347       PUSH_DATA (ctx.push, 0);
348 
349       ctx.instance_id++;
350       ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
351    }
352 
353    if (unlikely(ctx.need_vertex_id)) {
354       /* Reset gl_VertexID to prevent future indexed draws to be confused. */
355       BEGIN_NV04(ctx.push, NV84_3D(VERTEX_ID_BASE), 1);
356       PUSH_DATA (ctx.push, nv50->state.index_bias);
357    }
358 }
359