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