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->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