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 "nv50/nv50_context.h"
9#include "nv50/nv50_resource.h"
10
11#include "nv50/nv50_3d.xml.h"
12
13struct 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
37static inline unsigned
38prim_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
47static inline unsigned
48prim_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
57static inline unsigned
58prim_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
67static void
68emit_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
106static void
107emit_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
145static void
146emit_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
184static void
185emit_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
214static inline unsigned
215nv50_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
240void
241nv50_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->indexed && 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->buffer))
268         data = nouveau_resource_map_offset(&nv50->base,
269            nv04_resource(vb->buffer), vb->buffer_offset, NOUVEAU_BO_RD);
270      else
271         data = vb->user_buffer;
272
273      if (apply_bias && likely(!(nv50->vertex->instance_bufs & (1 << i))))
274         data += (ptrdiff_t)info->index_bias * vb->stride;
275
276      ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
277   }
278
279   if (info->indexed) {
280      if (nv50->idxbuf.buffer) {
281         ctx.idxbuf = nouveau_resource_map_offset(&nv50->base,
282            nv04_resource(nv50->idxbuf.buffer), nv50->idxbuf.offset,
283            NOUVEAU_BO_RD);
284      } else {
285         ctx.idxbuf = nv50->idxbuf.user_buffer;
286      }
287      if (!ctx.idxbuf)
288         return;
289      index_size = nv50->idxbuf.index_size;
290      ctx.primitive_restart = info->primitive_restart;
291      ctx.restart_index = info->restart_index;
292   } else {
293      if (unlikely(info->count_from_stream_output)) {
294         struct pipe_context *pipe = &nv50->base.pipe;
295         struct nv50_so_target *targ;
296         targ = nv50_so_target(info->count_from_stream_output);
297         if (!targ->pq) {
298            NOUVEAU_ERR("draw_stream_output not supported on pre-NVA0 cards\n");
299            return;
300         }
301         pipe->get_query_result(pipe, targ->pq, true, (void *)&vert_count);
302         vert_count /= targ->stride;
303      }
304      ctx.idxbuf = NULL;
305      index_size = 0;
306      ctx.primitive_restart = false;
307      ctx.restart_index = 0;
308   }
309
310   ctx.start_instance = info->start_instance;
311   ctx.prim = nv50_prim_gl(info->mode);
312
313   if (info->primitive_restart) {
314      BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 2);
315      PUSH_DATA (ctx.push, 1);
316      PUSH_DATA (ctx.push, info->restart_index);
317   } else
318   if (nv50->state.prim_restart) {
319      BEGIN_NV04(ctx.push, NV50_3D(PRIM_RESTART_ENABLE), 1);
320      PUSH_DATA (ctx.push, 0);
321   }
322   nv50->state.prim_restart = info->primitive_restart;
323
324   while (inst_count--) {
325      BEGIN_NV04(ctx.push, NV50_3D(VERTEX_BEGIN_GL), 1);
326      PUSH_DATA (ctx.push, ctx.prim);
327      switch (index_size) {
328      case 0:
329         emit_vertices_seq(&ctx, info->start, vert_count);
330         break;
331      case 1:
332         emit_vertices_i08(&ctx, info->start, vert_count);
333         break;
334      case 2:
335         emit_vertices_i16(&ctx, info->start, vert_count);
336         break;
337      case 4:
338         emit_vertices_i32(&ctx, info->start, vert_count);
339         break;
340      default:
341         assert(0);
342         break;
343      }
344      BEGIN_NV04(ctx.push, NV50_3D(VERTEX_END_GL), 1);
345      PUSH_DATA (ctx.push, 0);
346
347      ctx.instance_id++;
348      ctx.prim |= NV50_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
349   }
350
351   if (unlikely(ctx.need_vertex_id)) {
352      /* Reset gl_VertexID to prevent future indexed draws to be confused. */
353      BEGIN_NV04(ctx.push, NV84_3D(VERTEX_ID_BASE), 1);
354      PUSH_DATA (ctx.push, nv50->state.index_bias);
355   }
356}
357