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