Merge remote branch 'origin/7.8'
[mesa.git] / src / gallium / drivers / nvfx / nvfx_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_inlines.h"
4 #include "util/u_format.h"
5
6 #include "nvfx_context.h"
7 #include "nvfx_state.h"
8 #include "nvfx_resource.h"
9
10 #include "nouveau/nouveau_channel.h"
11 #include "nouveau/nouveau_pushbuf.h"
12 #include "nouveau/nouveau_util.h"
13
14 static INLINE int
15 nvfx_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
16 {
17 switch (pipe) {
18 case PIPE_FORMAT_R32_FLOAT:
19 case PIPE_FORMAT_R32G32_FLOAT:
20 case PIPE_FORMAT_R32G32B32_FLOAT:
21 case PIPE_FORMAT_R32G32B32A32_FLOAT:
22 *fmt = NV34TCL_VTXFMT_TYPE_FLOAT;
23 break;
24 case PIPE_FORMAT_R16_FLOAT:
25 case PIPE_FORMAT_R16G16_FLOAT:
26 case PIPE_FORMAT_R16G16B16_FLOAT:
27 case PIPE_FORMAT_R16G16B16A16_FLOAT:
28 *fmt = NV34TCL_VTXFMT_TYPE_HALF;
29 break;
30 case PIPE_FORMAT_R8_UNORM:
31 case PIPE_FORMAT_R8G8_UNORM:
32 case PIPE_FORMAT_R8G8B8_UNORM:
33 case PIPE_FORMAT_R8G8B8A8_UNORM:
34 *fmt = NV34TCL_VTXFMT_TYPE_UBYTE;
35 break;
36 case PIPE_FORMAT_R16_SSCALED:
37 case PIPE_FORMAT_R16G16_SSCALED:
38 case PIPE_FORMAT_R16G16B16_SSCALED:
39 case PIPE_FORMAT_R16G16B16A16_SSCALED:
40 *fmt = NV34TCL_VTXFMT_TYPE_USHORT;
41 break;
42 default:
43 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
44 return 1;
45 }
46
47 switch (pipe) {
48 case PIPE_FORMAT_R8_UNORM:
49 case PIPE_FORMAT_R32_FLOAT:
50 case PIPE_FORMAT_R16_FLOAT:
51 case PIPE_FORMAT_R16_SSCALED:
52 *ncomp = 1;
53 break;
54 case PIPE_FORMAT_R8G8_UNORM:
55 case PIPE_FORMAT_R32G32_FLOAT:
56 case PIPE_FORMAT_R16G16_FLOAT:
57 case PIPE_FORMAT_R16G16_SSCALED:
58 *ncomp = 2;
59 break;
60 case PIPE_FORMAT_R8G8B8_UNORM:
61 case PIPE_FORMAT_R32G32B32_FLOAT:
62 case PIPE_FORMAT_R16G16B16_FLOAT:
63 case PIPE_FORMAT_R16G16B16_SSCALED:
64 *ncomp = 3;
65 break;
66 case PIPE_FORMAT_R8G8B8A8_UNORM:
67 case PIPE_FORMAT_R32G32B32A32_FLOAT:
68 case PIPE_FORMAT_R16G16B16A16_FLOAT:
69 case PIPE_FORMAT_R16G16B16A16_SSCALED:
70 *ncomp = 4;
71 break;
72 default:
73 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
74 return 1;
75 }
76
77 return 0;
78 }
79
80 static boolean
81 nvfx_vbo_set_idxbuf(struct nvfx_context *nvfx, struct pipe_resource *ib,
82 unsigned ib_size)
83 {
84 unsigned type;
85
86 if (!ib) {
87 nvfx->idxbuf = NULL;
88 nvfx->idxbuf_format = 0xdeadbeef;
89 return FALSE;
90 }
91
92 if (!nvfx->screen->index_buffer_reloc_flags || ib_size == 1)
93 return FALSE;
94
95 switch (ib_size) {
96 case 2:
97 type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
98 break;
99 case 4:
100 type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
101 break;
102 default:
103 return FALSE;
104 }
105
106 if (ib != nvfx->idxbuf ||
107 type != nvfx->idxbuf_format) {
108 nvfx->dirty |= NVFX_NEW_ARRAYS;
109 nvfx->idxbuf = ib;
110 nvfx->idxbuf_format = type;
111 }
112
113 return TRUE;
114 }
115
116 // type must be floating point
117 static inline void
118 nvfx_vbo_static_attrib(struct nvfx_context *nvfx,
119 int attrib, struct pipe_vertex_element *ve,
120 struct pipe_vertex_buffer *vb, unsigned ncomp)
121 {
122 struct pipe_transfer *transfer;
123 struct nouveau_channel* chan = nvfx->screen->base.channel;
124 void *map;
125 float *v;
126
127 map = pipe_buffer_map(&nvfx->pipe, vb->buffer, PIPE_TRANSFER_READ, &transfer);
128 map = (uint8_t *) map + vb->buffer_offset + ve->src_offset;
129
130 v = map;
131
132 switch (ncomp) {
133 case 4:
134 OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_4F_X(attrib), 4));
135 OUT_RING(chan, fui(v[0]));
136 OUT_RING(chan, fui(v[1]));
137 OUT_RING(chan, fui(v[2]));
138 OUT_RING(chan, fui(v[3]));
139 break;
140 case 3:
141 OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_3F_X(attrib), 3));
142 OUT_RING(chan, fui(v[0]));
143 OUT_RING(chan, fui(v[1]));
144 OUT_RING(chan, fui(v[2]));
145 break;
146 case 2:
147 OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_2F_X(attrib), 2));
148 OUT_RING(chan, fui(v[0]));
149 OUT_RING(chan, fui(v[1]));
150 break;
151 case 1:
152 OUT_RING(chan, RING_3D(NV34TCL_VTX_ATTR_1F(attrib), 1));
153 OUT_RING(chan, fui(v[0]));
154 break;
155 }
156
157 pipe_buffer_unmap(&nvfx->pipe, vb->buffer, transfer);
158 }
159
160 void
161 nvfx_draw_arrays(struct pipe_context *pipe,
162 unsigned mode, unsigned start, unsigned count)
163 {
164 struct nvfx_context *nvfx = nvfx_context(pipe);
165 struct nvfx_screen *screen = nvfx->screen;
166 struct nouveau_channel *chan = screen->base.channel;
167 unsigned restart = 0;
168
169 nvfx_vbo_set_idxbuf(nvfx, NULL, 0);
170 if (nvfx->screen->force_swtnl || !nvfx_state_validate(nvfx)) {
171 nvfx_draw_elements_swtnl(pipe, NULL, 0, 0,
172 mode, start, count);
173 return;
174 }
175
176 while (count) {
177 unsigned vc, nr, avail;
178
179 nvfx_state_emit(nvfx);
180
181 avail = AVAIL_RING(chan);
182 avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */
183
184 vc = nouveau_vbuf_split(avail, 6, 256,
185 mode, start, count, &restart);
186 if (!vc) {
187 FIRE_RING(chan);
188 continue;
189 }
190
191 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
192 OUT_RING (chan, nvgl_primitive(mode));
193
194 nr = (vc & 0xff);
195 if (nr) {
196 OUT_RING(chan, RING_3D(NV34TCL_VB_VERTEX_BATCH, 1));
197 OUT_RING (chan, ((nr - 1) << 24) | start);
198 start += nr;
199 }
200
201 nr = vc >> 8;
202 while (nr) {
203 unsigned push = nr > 2047 ? 2047 : nr;
204
205 nr -= push;
206
207 OUT_RING(chan, RING_3D_NI(NV34TCL_VB_VERTEX_BATCH, push));
208 while (push--) {
209 OUT_RING(chan, ((0x100 - 1) << 24) | start);
210 start += 0x100;
211 }
212 }
213
214 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
215 OUT_RING (chan, 0);
216
217 count -= vc;
218 start = restart;
219 }
220
221 pipe->flush(pipe, 0, NULL);
222 }
223
224 static INLINE void
225 nvfx_draw_elements_u08(struct nvfx_context *nvfx, void *ib,
226 unsigned mode, unsigned start, unsigned count)
227 {
228 struct nvfx_screen *screen = nvfx->screen;
229 struct nouveau_channel *chan = screen->base.channel;
230
231 while (count) {
232 uint8_t *elts = (uint8_t *)ib + start;
233 unsigned vc, push, restart = 0, avail;
234
235 nvfx_state_emit(nvfx);
236
237 avail = AVAIL_RING(chan);
238 avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */
239
240 vc = nouveau_vbuf_split(avail, 6, 2,
241 mode, start, count, &restart);
242 if (vc == 0) {
243 FIRE_RING(chan);
244 continue;
245 }
246 count -= vc;
247
248 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
249 OUT_RING (chan, nvgl_primitive(mode));
250
251 if (vc & 1) {
252 OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1));
253 OUT_RING (chan, elts[0]);
254 elts++; vc--;
255 }
256
257 while (vc) {
258 unsigned i;
259
260 push = MIN2(vc, 2047 * 2);
261
262 OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1));
263 for (i = 0; i < push; i+=2)
264 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
265
266 vc -= push;
267 elts += push;
268 }
269
270 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
271 OUT_RING (chan, 0);
272
273 start = restart;
274 }
275 }
276
277 static INLINE void
278 nvfx_draw_elements_u16(struct nvfx_context *nvfx, void *ib,
279 unsigned mode, unsigned start, unsigned count)
280 {
281 struct nvfx_screen *screen = nvfx->screen;
282 struct nouveau_channel *chan = screen->base.channel;
283
284 while (count) {
285 uint16_t *elts = (uint16_t *)ib + start;
286 unsigned vc, push, restart = 0, avail;
287
288 nvfx_state_emit(nvfx);
289
290 avail = AVAIL_RING(chan);
291 avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */
292
293 vc = nouveau_vbuf_split(avail, 6, 2,
294 mode, start, count, &restart);
295 if (vc == 0) {
296 FIRE_RING(chan);
297 continue;
298 }
299 count -= vc;
300
301 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
302 OUT_RING (chan, nvgl_primitive(mode));
303
304 if (vc & 1) {
305 OUT_RING(chan, RING_3D(NV34TCL_VB_ELEMENT_U32, 1));
306 OUT_RING (chan, elts[0]);
307 elts++; vc--;
308 }
309
310 while (vc) {
311 unsigned i;
312
313 push = MIN2(vc, 2047 * 2);
314
315 OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U16, push >> 1));
316 for (i = 0; i < push; i+=2)
317 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
318
319 vc -= push;
320 elts += push;
321 }
322
323 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
324 OUT_RING (chan, 0);
325
326 start = restart;
327 }
328 }
329
330 static INLINE void
331 nvfx_draw_elements_u32(struct nvfx_context *nvfx, void *ib,
332 unsigned mode, unsigned start, unsigned count)
333 {
334 struct nvfx_screen *screen = nvfx->screen;
335 struct nouveau_channel *chan = screen->base.channel;
336
337 while (count) {
338 uint32_t *elts = (uint32_t *)ib + start;
339 unsigned vc, push, restart = 0, avail;
340
341 nvfx_state_emit(nvfx);
342
343 avail = AVAIL_RING(chan);
344 avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */
345
346 vc = nouveau_vbuf_split(avail, 5, 1,
347 mode, start, count, &restart);
348 if (vc == 0) {
349 FIRE_RING(chan);
350 continue;
351 }
352 count -= vc;
353
354 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
355 OUT_RING (chan, nvgl_primitive(mode));
356
357 while (vc) {
358 push = MIN2(vc, 2047);
359
360 OUT_RING(chan, RING_3D_NI(NV34TCL_VB_ELEMENT_U32, push));
361 OUT_RINGp (chan, elts, push);
362
363 vc -= push;
364 elts += push;
365 }
366
367 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
368 OUT_RING (chan, 0);
369
370 start = restart;
371 }
372 }
373
374 static void
375 nvfx_draw_elements_inline(struct pipe_context *pipe,
376 struct pipe_resource *ib,
377 unsigned ib_size, int ib_bias,
378 unsigned mode, unsigned start, unsigned count)
379 {
380 struct nvfx_context *nvfx = nvfx_context(pipe);
381 struct pipe_transfer *transfer;
382 void *map;
383
384 map = pipe_buffer_map(pipe, ib, PIPE_TRANSFER_READ, &transfer);
385 if (!ib) {
386 NOUVEAU_ERR("failed mapping ib\n");
387 return;
388 }
389
390 assert(ib_bias == 0);
391
392 switch (ib_size) {
393 case 1:
394 nvfx_draw_elements_u08(nvfx, map, mode, start, count);
395 break;
396 case 2:
397 nvfx_draw_elements_u16(nvfx, map, mode, start, count);
398 break;
399 case 4:
400 nvfx_draw_elements_u32(nvfx, map, mode, start, count);
401 break;
402 default:
403 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
404 break;
405 }
406
407 pipe_buffer_unmap(pipe, ib, transfer);
408 }
409
410 static void
411 nvfx_draw_elements_vbo(struct pipe_context *pipe,
412 unsigned mode, unsigned start, unsigned count)
413 {
414 struct nvfx_context *nvfx = nvfx_context(pipe);
415 struct nvfx_screen *screen = nvfx->screen;
416 struct nouveau_channel *chan = screen->base.channel;
417 unsigned restart = 0;
418
419 while (count) {
420 unsigned nr, vc, avail;
421
422 nvfx_state_emit(nvfx);
423
424 avail = AVAIL_RING(chan);
425 avail -= 16 + (avail >> 10); /* for the BEGIN_RING_NIs, conservatively assuming one every 1024, plus 16 for safety */
426
427 vc = nouveau_vbuf_split(avail, 6, 256,
428 mode, start, count, &restart);
429 if (!vc) {
430 FIRE_RING(chan);
431 continue;
432 }
433
434 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
435 OUT_RING (chan, nvgl_primitive(mode));
436
437 nr = (vc & 0xff);
438 if (nr) {
439 OUT_RING(chan, RING_3D(NV34TCL_VB_INDEX_BATCH, 1));
440 OUT_RING (chan, ((nr - 1) << 24) | start);
441 start += nr;
442 }
443
444 nr = vc >> 8;
445 while (nr) {
446 unsigned push = nr > 2047 ? 2047 : nr;
447
448 nr -= push;
449
450 OUT_RING(chan, RING_3D_NI(NV34TCL_VB_INDEX_BATCH, push));
451 while (push--) {
452 OUT_RING(chan, ((0x100 - 1) << 24) | start);
453 start += 0x100;
454 }
455 }
456
457 OUT_RING(chan, RING_3D(NV34TCL_VERTEX_BEGIN_END, 1));
458 OUT_RING (chan, 0);
459
460 count -= vc;
461 start = restart;
462 }
463 }
464
465 void
466 nvfx_draw_elements(struct pipe_context *pipe,
467 struct pipe_resource *indexBuffer,
468 unsigned indexSize, int indexBias,
469 unsigned mode, unsigned start, unsigned count)
470 {
471 struct nvfx_context *nvfx = nvfx_context(pipe);
472 boolean idxbuf;
473
474 idxbuf = nvfx_vbo_set_idxbuf(nvfx, indexBuffer, indexSize);
475 if (nvfx->screen->force_swtnl || !nvfx_state_validate(nvfx)) {
476 nvfx_draw_elements_swtnl(pipe,
477 indexBuffer, indexSize, indexBias,
478 mode, start, count);
479 return;
480 }
481
482 if (idxbuf) {
483 nvfx_draw_elements_vbo(pipe, mode, start, count);
484 } else {
485 nvfx_draw_elements_inline(pipe,
486 indexBuffer, indexSize, indexBias,
487 mode, start, count);
488 }
489
490 pipe->flush(pipe, 0, NULL);
491 }
492
493 boolean
494 nvfx_vbo_validate(struct nvfx_context *nvfx)
495 {
496 struct nouveau_channel* chan = nvfx->screen->base.channel;
497 struct pipe_resource *ib = nvfx->idxbuf;
498 unsigned ib_format = nvfx->idxbuf_format;
499 int i;
500 int elements = MAX2(nvfx->vtxelt->num_elements, nvfx->hw_vtxelt_nr);
501 uint32_t vtxfmt[16];
502 unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD;
503
504 if (!elements)
505 return TRUE;
506
507 nvfx->vbo_bo = 0;
508
509 MARK_RING(chan, (5 + 2) * 16 + 2 + 11, 16 + 2);
510 for (i = 0; i < nvfx->vtxelt->num_elements; i++) {
511 struct pipe_vertex_element *ve;
512 struct pipe_vertex_buffer *vb;
513 unsigned type, ncomp;
514
515 ve = &nvfx->vtxelt->pipe[i];
516 vb = &nvfx->vtxbuf[ve->vertex_buffer_index];
517
518 if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
519 MARK_UNDO(chan);
520 nvfx->fallback_swtnl |= NVFX_NEW_ARRAYS;
521 return FALSE;
522 }
523
524 if (!vb->stride && type == NV34TCL_VTXFMT_TYPE_FLOAT) {
525 nvfx_vbo_static_attrib(nvfx, i, ve, vb, ncomp);
526 vtxfmt[i] = type;
527 } else {
528 vtxfmt[i] = ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) |
529 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type);
530 nvfx->vbo_bo |= (1 << i);
531 }
532 }
533
534 for(; i < elements; ++i)
535 vtxfmt[i] = NV34TCL_VTXFMT_TYPE_FLOAT;
536
537 OUT_RING(chan, RING_3D(NV34TCL_VTXFMT(0), elements));
538 OUT_RINGp(chan, vtxfmt, elements);
539
540 if(nvfx->is_nv4x) {
541 unsigned i;
542 /* seems to be some kind of cache flushing */
543 for(i = 0; i < 3; ++i) {
544 OUT_RING(chan, RING_3D(0x1718, 1));
545 OUT_RING(chan, 0);
546 }
547 }
548
549 OUT_RING(chan, RING_3D(NV34TCL_VTXBUF_ADDRESS(0), elements));
550 for (i = 0; i < nvfx->vtxelt->num_elements; i++) {
551 struct pipe_vertex_element *ve;
552 struct pipe_vertex_buffer *vb;
553
554 ve = &nvfx->vtxelt->pipe[i];
555 vb = &nvfx->vtxbuf[ve->vertex_buffer_index];
556
557 if (!(nvfx->vbo_bo & (1 << i)))
558 OUT_RING(chan, 0);
559 else
560 {
561 struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo;
562 OUT_RELOC(chan, bo,
563 vb->buffer_offset + ve->src_offset,
564 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
565 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
566 }
567 }
568
569 for (; i < elements; i++)
570 OUT_RING(chan, 0);
571
572 OUT_RING(chan, RING_3D(0x1710, 1));
573 OUT_RING(chan, 0);
574
575 if (ib) {
576 unsigned ib_flags = nvfx->screen->index_buffer_reloc_flags | NOUVEAU_BO_RD;
577 struct nouveau_bo* bo = nvfx_resource(ib)->bo;
578
579 assert(nvfx->screen->index_buffer_reloc_flags);
580
581 OUT_RING(chan, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2));
582 OUT_RELOC(chan, bo, 0, ib_flags | NOUVEAU_BO_LOW, 0, 0);
583 OUT_RELOC(chan, bo, ib_format, ib_flags | NOUVEAU_BO_OR,
584 0, NV34TCL_IDXBUF_FORMAT_DMA1);
585 }
586
587 nvfx->hw_vtxelt_nr = nvfx->vtxelt->num_elements;
588 return TRUE;
589 }
590
591 void
592 nvfx_vbo_relocate(struct nvfx_context *nvfx)
593 {
594 struct nouveau_channel* chan = nvfx->screen->base.channel;
595 unsigned vb_flags = nvfx->screen->vertex_buffer_reloc_flags | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY;
596 int i;
597
598 MARK_RING(chan, 2 * 16 + 3, 2 * 16 + 3);
599 for(i = 0; i < nvfx->vtxelt->num_elements; ++i) {
600 if(nvfx->vbo_bo & (1 << i)) {
601 struct pipe_vertex_element *ve = &nvfx->vtxelt->pipe[i];
602 struct pipe_vertex_buffer *vb = &nvfx->vtxbuf[ve->vertex_buffer_index];
603 struct nouveau_bo* bo = nvfx_resource(vb->buffer)->bo;
604 OUT_RELOC(chan, bo, RING_3D(NV34TCL_VTXBUF_ADDRESS(i), 1),
605 vb_flags, 0, 0);
606 OUT_RELOC(chan, bo, vb->buffer_offset + ve->src_offset,
607 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
608 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
609 }
610 }
611
612 if(nvfx->idxbuf)
613 {
614 unsigned ib_flags = nvfx->screen->index_buffer_reloc_flags | NOUVEAU_BO_RD | NOUVEAU_BO_DUMMY;
615 struct nouveau_bo* bo = nvfx_resource(nvfx->idxbuf)->bo;
616
617 assert(nvfx->screen->index_buffer_reloc_flags);
618
619 OUT_RELOC(chan, bo, RING_3D(NV34TCL_IDXBUF_ADDRESS, 2),
620 ib_flags, 0, 0);
621 OUT_RELOC(chan, bo, 0,
622 ib_flags | NOUVEAU_BO_LOW, 0, 0);
623 OUT_RELOC(chan, bo, nvfx->idxbuf_format,
624 ib_flags | NOUVEAU_BO_OR,
625 0, NV34TCL_IDXBUF_FORMAT_DMA1);
626 }
627 }