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