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