nvc0_push.c revision 5655f8d42d919270791588162399ac7a2c718733
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
13struct push_context {
14   struct nouveau_channel *chan;
15
16   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   boolean primitive_restart;
27   uint32_t prim;
28   uint32_t restart_index;
29};
30
31static INLINE unsigned
32prim_restart_search_i08(uint8_t *elts, unsigned push, uint8_t index)
33{
34   unsigned i;
35   for (i = 0; i < push; ++i)
36      if (elts[i] == index)
37         break;
38   return i;
39}
40
41static INLINE unsigned
42prim_restart_search_i16(uint16_t *elts, unsigned push, uint16_t index)
43{
44   unsigned i;
45   for (i = 0; i < push; ++i)
46      if (elts[i] == index)
47         break;
48   return i;
49}
50
51static INLINE unsigned
52prim_restart_search_i32(uint32_t *elts, unsigned push, uint32_t index)
53{
54   unsigned i;
55   for (i = 0; i < push; ++i)
56      if (elts[i] == index)
57         break;
58   return i;
59}
60
61static void
62emit_vertices_i08(struct push_context *ctx, unsigned start, unsigned count)
63{
64   uint8_t *elts = (uint8_t *)ctx->idxbuf + start;
65
66   while (count) {
67      unsigned push = MIN2(count, ctx->packet_vertex_limit);
68      unsigned size, nr;
69
70      nr = push;
71      if (ctx->primitive_restart)
72         nr = prim_restart_search_i08(elts, push, ctx->restart_index);
73
74      size = ctx->vertex_words * nr;
75
76      BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
77
78      ctx->translate->run_elts8(ctx->translate, elts, push, 0, ctx->chan->cur);
79
80      ctx->chan->cur += size;
81      count -= push;
82      elts += push;
83
84      if (nr != push) {
85         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
86         OUT_RING  (ctx->chan, 0);
87         OUT_RING  (ctx->chan, ctx->prim);
88      }
89   }
90}
91
92static void
93emit_vertices_i16(struct push_context *ctx, unsigned start, unsigned count)
94{
95   uint16_t *elts = (uint16_t *)ctx->idxbuf + start;
96
97   while (count) {
98      unsigned push = MIN2(count, ctx->packet_vertex_limit);
99      unsigned size, nr;
100
101      nr = push;
102      if (ctx->primitive_restart)
103         nr = prim_restart_search_i16(elts, push, ctx->restart_index);
104
105      size = ctx->vertex_words * nr;
106
107      BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
108
109      ctx->translate->run_elts16(ctx->translate, elts, push, 0, ctx->chan->cur);
110
111      ctx->chan->cur += size;
112      count -= push;
113      elts += push;
114
115      if (nr != push) {
116         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
117         OUT_RING  (ctx->chan, 0);
118         OUT_RING  (ctx->chan, ctx->prim);
119      }
120   }
121}
122
123static void
124emit_vertices_i32(struct push_context *ctx, unsigned start, unsigned count)
125{
126   uint32_t *elts = (uint32_t *)ctx->idxbuf + start;
127
128   while (count) {
129      unsigned push = MIN2(count, ctx->packet_vertex_limit);
130      unsigned size, nr;
131
132      nr = push;
133      if (ctx->primitive_restart)
134         nr = prim_restart_search_i32(elts, push, ctx->restart_index);
135
136      size = ctx->vertex_words * nr;
137
138      BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
139
140      ctx->translate->run_elts(ctx->translate, elts, push, 0, ctx->chan->cur);
141
142      ctx->chan->cur += size;
143      count -= push;
144      elts += push;
145
146      if (nr != push) {
147         BEGIN_RING(ctx->chan, RING_3D(VERTEX_END_GL), 2);
148         OUT_RING  (ctx->chan, 0);
149         OUT_RING  (ctx->chan, ctx->prim);
150      }
151   }
152}
153
154static void
155emit_vertices_seq(struct push_context *ctx, unsigned start, unsigned count)
156{
157   while (count) {
158      unsigned push = MIN2(count, ctx->packet_vertex_limit);
159      unsigned size = ctx->vertex_words * push;
160
161      BEGIN_RING_NI(ctx->chan, RING_3D(VERTEX_DATA), size);
162
163      ctx->translate->run(ctx->translate, start, push, 0, ctx->chan->cur);
164      ctx->chan->cur += size;
165      count -= push;
166      start += push;
167   }
168}
169
170
171#define NVC0_PRIM_GL_CASE(n) \
172   case PIPE_PRIM_##n: return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_##n
173
174static INLINE unsigned
175nvc0_prim_gl(unsigned prim)
176{
177   switch (prim) {
178   NVC0_PRIM_GL_CASE(POINTS);
179   NVC0_PRIM_GL_CASE(LINES);
180   NVC0_PRIM_GL_CASE(LINE_LOOP);
181   NVC0_PRIM_GL_CASE(LINE_STRIP);
182   NVC0_PRIM_GL_CASE(TRIANGLES);
183   NVC0_PRIM_GL_CASE(TRIANGLE_STRIP);
184   NVC0_PRIM_GL_CASE(TRIANGLE_FAN);
185   NVC0_PRIM_GL_CASE(QUADS);
186   NVC0_PRIM_GL_CASE(QUAD_STRIP);
187   NVC0_PRIM_GL_CASE(POLYGON);
188   NVC0_PRIM_GL_CASE(LINES_ADJACENCY);
189   NVC0_PRIM_GL_CASE(LINE_STRIP_ADJACENCY);
190   NVC0_PRIM_GL_CASE(TRIANGLES_ADJACENCY);
191   NVC0_PRIM_GL_CASE(TRIANGLE_STRIP_ADJACENCY);
192   /*
193   NVC0_PRIM_GL_CASE(PATCHES); */
194   default:
195      return NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_POINTS;
196      break;
197   }
198}
199
200void
201nvc0_push_vbo(struct nvc0_context *nvc0, const struct pipe_draw_info *info)
202{
203   struct push_context ctx;
204   struct pipe_transfer *transfer = NULL;
205   unsigned i, index_size;
206   unsigned inst = info->instance_count;
207
208   ctx.chan = nvc0->screen->base.channel;
209   ctx.translate = nvc0->vertex->translate;
210   ctx.packet_vertex_limit = nvc0->vertex->vtx_per_packet_max;
211   ctx.vertex_words = nvc0->vertex->vtx_size;
212
213   for (i = 0; i < nvc0->num_vtxbufs; ++i) {
214      uint8_t *data;
215      struct pipe_vertex_buffer *vb = &nvc0->vtxbuf[i];
216      struct nvc0_resource *res = nvc0_resource(vb->buffer);
217
218      if (nouveau_bo_map(res->bo, NOUVEAU_BO_RD))
219         return;
220      data = (uint8_t *)res->bo->map + vb->buffer_offset;
221      if (info->indexed)
222         data += info->index_bias * vb->stride;
223
224      ctx.translate->set_buffer(ctx.translate, i, data, vb->stride, ~0);
225   }
226
227   if (info->indexed) {
228      ctx.idxbuf = pipe_buffer_map(&nvc0->pipe, nvc0->idxbuf.buffer,
229                                   PIPE_TRANSFER_READ, &transfer);
230      if (!ctx.idxbuf)
231         return;
232      index_size = nvc0->idxbuf.index_size;
233      ctx.primitive_restart = info->primitive_restart;
234      ctx.restart_index = info->restart_index;
235   } else {
236      ctx.idxbuf = NULL;
237      index_size = 0;
238      ctx.primitive_restart = FALSE;
239      ctx.restart_index = 0;
240   }
241
242   ctx.prim = nvc0_prim_gl(info->mode);
243
244   while (inst--) {
245      BEGIN_RING(ctx.chan, RING_3D(VERTEX_BEGIN_GL), 1);
246      OUT_RING  (ctx.chan, ctx.prim);
247      switch (index_size) {
248      case 0:
249         emit_vertices_seq(&ctx, info->start, info->count);
250         break;
251      case 1:
252         emit_vertices_i08(&ctx, info->start, info->count);
253         break;
254      case 2:
255         emit_vertices_i16(&ctx, info->start, info->count);
256         break;
257      case 4:
258         emit_vertices_i32(&ctx, info->start, info->count);
259         break;
260      default:
261         assert(0);
262         break;
263      }
264      INLIN_RING(ctx.chan, RING_3D(VERTEX_END_GL), 0);
265
266      ctx.prim |= NVC0_3D_VERTEX_BEGIN_GL_INSTANCE_NEXT;
267   }
268
269   if (info->indexed)
270	   pipe_buffer_unmap(&nvc0->pipe, nvc0->idxbuf.buffer, transfer);
271
272   for (i = 0; i < nvc0->num_vtxbufs; ++i) {
273      struct nvc0_resource *res = nvc0_resource(nvc0->vtxbuf[i].buffer);
274
275      if (res->bo)
276         nouveau_bo_unmap(res->bo);
277   }
278}
279