Merge commit '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 boolean
15 nvfx_force_swtnl(struct nvfx_context *nvfx)
16 {
17 static int force_swtnl = -1;
18 if(force_swtnl < 0)
19 force_swtnl = debug_get_bool_option("NOUVEAU_SWTNL", 0);
20 return force_swtnl;
21 }
22
23 static INLINE int
24 nvfx_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
25 {
26 switch (pipe) {
27 case PIPE_FORMAT_R32_FLOAT:
28 case PIPE_FORMAT_R32G32_FLOAT:
29 case PIPE_FORMAT_R32G32B32_FLOAT:
30 case PIPE_FORMAT_R32G32B32A32_FLOAT:
31 *fmt = NV34TCL_VTXFMT_TYPE_FLOAT;
32 break;
33 case PIPE_FORMAT_R8_UNORM:
34 case PIPE_FORMAT_R8G8_UNORM:
35 case PIPE_FORMAT_R8G8B8_UNORM:
36 case PIPE_FORMAT_R8G8B8A8_UNORM:
37 *fmt = NV34TCL_VTXFMT_TYPE_UBYTE;
38 break;
39 case PIPE_FORMAT_R16_SSCALED:
40 case PIPE_FORMAT_R16G16_SSCALED:
41 case PIPE_FORMAT_R16G16B16_SSCALED:
42 case PIPE_FORMAT_R16G16B16A16_SSCALED:
43 *fmt = NV34TCL_VTXFMT_TYPE_USHORT;
44 break;
45 default:
46 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
47 return 1;
48 }
49
50 switch (pipe) {
51 case PIPE_FORMAT_R8_UNORM:
52 case PIPE_FORMAT_R32_FLOAT:
53 case PIPE_FORMAT_R16_SSCALED:
54 *ncomp = 1;
55 break;
56 case PIPE_FORMAT_R8G8_UNORM:
57 case PIPE_FORMAT_R32G32_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_SSCALED:
64 *ncomp = 3;
65 break;
66 case PIPE_FORMAT_R8G8B8A8_UNORM:
67 case PIPE_FORMAT_R32G32B32A32_FLOAT:
68 case PIPE_FORMAT_R16G16B16A16_SSCALED:
69 *ncomp = 4;
70 break;
71 default:
72 NOUVEAU_ERR("Unknown format %s\n", util_format_name(pipe));
73 return 1;
74 }
75
76 return 0;
77 }
78
79 static boolean
80 nvfx_vbo_set_idxbuf(struct nvfx_context *nvfx, struct pipe_resource *ib,
81 unsigned ib_size)
82 {
83 struct pipe_screen *pscreen = &nvfx->screen->base.base;
84 unsigned type;
85
86 if (!ib) {
87 nvfx->idxbuf = NULL;
88 nvfx->idxbuf_format = 0xdeadbeef;
89 return FALSE;
90 }
91
92 if (!pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF) || 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 static boolean
117 nvfx_vbo_static_attrib(struct nvfx_context *nvfx, struct nouveau_stateobj *so,
118 int attrib, struct pipe_vertex_element *ve,
119 struct pipe_vertex_buffer *vb)
120 {
121 struct pipe_context *pipe = &nvfx->pipe;
122 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
123 struct pipe_transfer *transfer;
124 unsigned type, ncomp;
125 uint8_t *map;
126
127 if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp))
128 return FALSE;
129
130 map = pipe_buffer_map(pipe, vb->buffer, PIPE_TRANSFER_READ, &transfer);
131 map += vb->buffer_offset + ve->src_offset;
132
133 switch (type) {
134 case NV34TCL_VTXFMT_TYPE_FLOAT:
135 {
136 float *v = (float *)map;
137
138 switch (ncomp) {
139 case 4:
140 so_method(so, eng3d, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
141 so_data (so, fui(v[0]));
142 so_data (so, fui(v[1]));
143 so_data (so, fui(v[2]));
144 so_data (so, fui(v[3]));
145 break;
146 case 3:
147 so_method(so, eng3d, NV34TCL_VTX_ATTR_3F_X(attrib), 3);
148 so_data (so, fui(v[0]));
149 so_data (so, fui(v[1]));
150 so_data (so, fui(v[2]));
151 break;
152 case 2:
153 so_method(so, eng3d, NV34TCL_VTX_ATTR_2F_X(attrib), 2);
154 so_data (so, fui(v[0]));
155 so_data (so, fui(v[1]));
156 break;
157 case 1:
158 so_method(so, eng3d, NV34TCL_VTX_ATTR_1F(attrib), 1);
159 so_data (so, fui(v[0]));
160 break;
161 default:
162 pipe_buffer_unmap(pipe, vb->buffer, transfer);
163 return FALSE;
164 }
165 }
166 break;
167 default:
168 pipe_buffer_unmap(pipe, vb->buffer, transfer);
169 return FALSE;
170 }
171
172 pipe_buffer_unmap(pipe, vb->buffer, transfer);
173 return TRUE;
174 }
175
176 void
177 nvfx_draw_arrays(struct pipe_context *pipe,
178 unsigned mode, unsigned start, unsigned count)
179 {
180 struct nvfx_context *nvfx = nvfx_context(pipe);
181 struct nvfx_screen *screen = nvfx->screen;
182 struct nouveau_channel *chan = screen->base.channel;
183 struct nouveau_grobj *eng3d = screen->eng3d;
184 unsigned restart = 0;
185
186 nvfx_vbo_set_idxbuf(nvfx, NULL, 0);
187 if (nvfx_force_swtnl(nvfx) || !nvfx_state_validate(nvfx)) {
188 nvfx_draw_elements_swtnl(pipe, NULL, 0,
189 mode, start, count);
190 return;
191 }
192
193 while (count) {
194 unsigned vc, nr;
195
196 nvfx_state_emit(nvfx);
197
198 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 256,
199 mode, start, count, &restart);
200 if (!vc) {
201 FIRE_RING(chan);
202 continue;
203 }
204
205 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
206 OUT_RING (chan, nvgl_primitive(mode));
207
208 nr = (vc & 0xff);
209 if (nr) {
210 BEGIN_RING(chan, eng3d, NV34TCL_VB_VERTEX_BATCH, 1);
211 OUT_RING (chan, ((nr - 1) << 24) | start);
212 start += nr;
213 }
214
215 nr = vc >> 8;
216 while (nr) {
217 unsigned push = nr > 2047 ? 2047 : nr;
218
219 nr -= push;
220
221 BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_VERTEX_BATCH, push);
222 while (push--) {
223 OUT_RING(chan, ((0x100 - 1) << 24) | start);
224 start += 0x100;
225 }
226 }
227
228 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
229 OUT_RING (chan, 0);
230
231 count -= vc;
232 start = restart;
233 }
234
235 pipe->flush(pipe, 0, NULL);
236 }
237
238 static INLINE void
239 nvfx_draw_elements_u08(struct nvfx_context *nvfx, void *ib,
240 unsigned mode, unsigned start, unsigned count)
241 {
242 struct nvfx_screen *screen = nvfx->screen;
243 struct nouveau_channel *chan = screen->base.channel;
244 struct nouveau_grobj *eng3d = screen->eng3d;
245
246 while (count) {
247 uint8_t *elts = (uint8_t *)ib + start;
248 unsigned vc, push, restart = 0;
249
250 nvfx_state_emit(nvfx);
251
252 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 2,
253 mode, start, count, &restart);
254 if (vc == 0) {
255 FIRE_RING(chan);
256 continue;
257 }
258 count -= vc;
259
260 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
261 OUT_RING (chan, nvgl_primitive(mode));
262
263 if (vc & 1) {
264 BEGIN_RING(chan, eng3d, NV34TCL_VB_ELEMENT_U32, 1);
265 OUT_RING (chan, elts[0]);
266 elts++; vc--;
267 }
268
269 while (vc) {
270 unsigned i;
271
272 push = MIN2(vc, 2047 * 2);
273
274 BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U16, push >> 1);
275 for (i = 0; i < push; i+=2)
276 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
277
278 vc -= push;
279 elts += push;
280 }
281
282 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
283 OUT_RING (chan, 0);
284
285 start = restart;
286 }
287 }
288
289 static INLINE void
290 nvfx_draw_elements_u16(struct nvfx_context *nvfx, void *ib,
291 unsigned mode, unsigned start, unsigned count)
292 {
293 struct nvfx_screen *screen = nvfx->screen;
294 struct nouveau_channel *chan = screen->base.channel;
295 struct nouveau_grobj *eng3d = screen->eng3d;
296
297 while (count) {
298 uint16_t *elts = (uint16_t *)ib + start;
299 unsigned vc, push, restart = 0;
300
301 nvfx_state_emit(nvfx);
302
303 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 2,
304 mode, start, count, &restart);
305 if (vc == 0) {
306 FIRE_RING(chan);
307 continue;
308 }
309 count -= vc;
310
311 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
312 OUT_RING (chan, nvgl_primitive(mode));
313
314 if (vc & 1) {
315 BEGIN_RING(chan, eng3d, NV34TCL_VB_ELEMENT_U32, 1);
316 OUT_RING (chan, elts[0]);
317 elts++; vc--;
318 }
319
320 while (vc) {
321 unsigned i;
322
323 push = MIN2(vc, 2047 * 2);
324
325 BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U16, push >> 1);
326 for (i = 0; i < push; i+=2)
327 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
328
329 vc -= push;
330 elts += push;
331 }
332
333 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
334 OUT_RING (chan, 0);
335
336 start = restart;
337 }
338 }
339
340 static INLINE void
341 nvfx_draw_elements_u32(struct nvfx_context *nvfx, void *ib,
342 unsigned mode, unsigned start, unsigned count)
343 {
344 struct nvfx_screen *screen = nvfx->screen;
345 struct nouveau_channel *chan = screen->base.channel;
346 struct nouveau_grobj *eng3d = screen->eng3d;
347
348 while (count) {
349 uint32_t *elts = (uint32_t *)ib + start;
350 unsigned vc, push, restart = 0;
351
352 nvfx_state_emit(nvfx);
353
354 vc = nouveau_vbuf_split(AVAIL_RING(chan), 5, 1,
355 mode, start, count, &restart);
356 if (vc == 0) {
357 FIRE_RING(chan);
358 continue;
359 }
360 count -= vc;
361
362 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
363 OUT_RING (chan, nvgl_primitive(mode));
364
365 while (vc) {
366 push = MIN2(vc, 2047);
367
368 BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_ELEMENT_U32, push);
369 OUT_RINGp (chan, elts, push);
370
371 vc -= push;
372 elts += push;
373 }
374
375 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
376 OUT_RING (chan, 0);
377
378 start = restart;
379 }
380 }
381
382 static void
383 nvfx_draw_elements_inline(struct pipe_context *pipe,
384 struct pipe_resource *ib, unsigned ib_size,
385 unsigned mode, unsigned start, unsigned count)
386 {
387 struct nvfx_context *nvfx = nvfx_context(pipe);
388 struct pipe_transfer *transfer;
389 void *map;
390
391 map = pipe_buffer_map(pipe, ib, PIPE_TRANSFER_READ, &transfer);
392 if (!ib) {
393 NOUVEAU_ERR("failed mapping ib\n");
394 return;
395 }
396
397 switch (ib_size) {
398 case 1:
399 nvfx_draw_elements_u08(nvfx, map, mode, start, count);
400 break;
401 case 2:
402 nvfx_draw_elements_u16(nvfx, map, mode, start, count);
403 break;
404 case 4:
405 nvfx_draw_elements_u32(nvfx, map, mode, start, count);
406 break;
407 default:
408 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
409 break;
410 }
411
412 pipe_buffer_unmap(pipe, ib, transfer);
413 }
414
415 static void
416 nvfx_draw_elements_vbo(struct pipe_context *pipe,
417 unsigned mode, unsigned start, unsigned count)
418 {
419 struct nvfx_context *nvfx = nvfx_context(pipe);
420 struct nvfx_screen *screen = nvfx->screen;
421 struct nouveau_channel *chan = screen->base.channel;
422 struct nouveau_grobj *eng3d = screen->eng3d;
423 unsigned restart = 0;
424
425 while (count) {
426 unsigned nr, vc;
427
428 nvfx_state_emit(nvfx);
429
430 vc = nouveau_vbuf_split(AVAIL_RING(chan), 6, 256,
431 mode, start, count, &restart);
432 if (!vc) {
433 FIRE_RING(chan);
434 continue;
435 }
436
437 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
438 OUT_RING (chan, nvgl_primitive(mode));
439
440 nr = (vc & 0xff);
441 if (nr) {
442 BEGIN_RING(chan, eng3d, NV34TCL_VB_INDEX_BATCH, 1);
443 OUT_RING (chan, ((nr - 1) << 24) | start);
444 start += nr;
445 }
446
447 nr = vc >> 8;
448 while (nr) {
449 unsigned push = nr > 2047 ? 2047 : nr;
450
451 nr -= push;
452
453 BEGIN_RING_NI(chan, eng3d, NV34TCL_VB_INDEX_BATCH, push);
454 while (push--) {
455 OUT_RING(chan, ((0x100 - 1) << 24) | start);
456 start += 0x100;
457 }
458 }
459
460 BEGIN_RING(chan, eng3d, NV34TCL_VERTEX_BEGIN_END, 1);
461 OUT_RING (chan, 0);
462
463 count -= vc;
464 start = restart;
465 }
466 }
467
468 void
469 nvfx_draw_elements(struct pipe_context *pipe,
470 struct pipe_resource *indexBuffer, unsigned indexSize,
471 unsigned mode, unsigned start, unsigned count)
472 {
473 struct nvfx_context *nvfx = nvfx_context(pipe);
474 boolean idxbuf;
475
476 idxbuf = nvfx_vbo_set_idxbuf(nvfx, indexBuffer, indexSize);
477 if (nvfx_force_swtnl(nvfx) || !nvfx_state_validate(nvfx)) {
478 nvfx_draw_elements_swtnl(pipe, indexBuffer, indexSize,
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, indexBuffer, indexSize,
487 mode, start, count);
488 }
489
490 pipe->flush(pipe, 0, NULL);
491 }
492
493 static boolean
494 nvfx_vbo_validate(struct nvfx_context *nvfx)
495 {
496 struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
497 struct nouveau_grobj *eng3d = nvfx->screen->eng3d;
498 struct pipe_resource *ib = nvfx->idxbuf;
499 unsigned ib_format = nvfx->idxbuf_format;
500 unsigned vb_flags = nvfx->screen->vertex_buffer_flags | NOUVEAU_BO_RD;
501 int hw;
502
503 vtxbuf = so_new(3, 17, 18);
504 so_method(vtxbuf, eng3d, NV34TCL_VTXBUF_ADDRESS(0), nvfx->vtxelt->num_elements);
505 vtxfmt = so_new(1, 16, 0);
506 so_method(vtxfmt, eng3d, NV34TCL_VTXFMT(0), nvfx->vtxelt->num_elements);
507
508 for (hw = 0; hw < nvfx->vtxelt->num_elements; hw++) {
509 struct pipe_vertex_element *ve;
510 struct pipe_vertex_buffer *vb;
511 unsigned type, ncomp;
512
513 ve = &nvfx->vtxelt->pipe[hw];
514 vb = &nvfx->vtxbuf[ve->vertex_buffer_index];
515
516 if (!vb->stride) {
517 if (!sattr)
518 sattr = so_new(16, 16 * 4, 0);
519
520 if (nvfx_vbo_static_attrib(nvfx, sattr, hw, ve, vb)) {
521 so_data(vtxbuf, 0);
522 so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
523 continue;
524 }
525 }
526
527 if (nvfx_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
528 nvfx->fallback_swtnl |= NVFX_NEW_ARRAYS;
529 so_ref(NULL, &vtxbuf);
530 so_ref(NULL, &vtxfmt);
531 return FALSE;
532 }
533
534 so_reloc(vtxbuf, nvfx_resource(vb->buffer)->bo,
535 vb->buffer_offset + ve->src_offset,
536 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
537 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
538 so_data (vtxfmt, ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) |
539 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
540 }
541
542 if (ib) {
543 struct nouveau_bo *bo = nvfx_resource(ib)->bo;
544
545 so_method(vtxbuf, eng3d, NV34TCL_IDXBUF_ADDRESS, 2);
546 so_reloc (vtxbuf, bo, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
547 so_reloc (vtxbuf, bo, ib_format, vb_flags | NOUVEAU_BO_OR,
548 0, NV34TCL_IDXBUF_FORMAT_DMA1);
549 }
550
551 so_method(vtxbuf, eng3d, 0x1710, 1);
552 so_data (vtxbuf, 0);
553
554 so_ref(vtxbuf, &nvfx->state.hw[NVFX_STATE_VTXBUF]);
555 so_ref(NULL, &vtxbuf);
556 nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXBUF);
557 so_ref(vtxfmt, &nvfx->state.hw[NVFX_STATE_VTXFMT]);
558 so_ref(NULL, &vtxfmt);
559 nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXFMT);
560 so_ref(sattr, &nvfx->state.hw[NVFX_STATE_VTXATTR]);
561 so_ref(NULL, &sattr);
562 nvfx->state.dirty |= (1ULL << NVFX_STATE_VTXATTR);
563 return FALSE;
564 }
565
566 struct nvfx_state_entry nvfx_state_vbo = {
567 .validate = nvfx_vbo_validate,
568 .dirty = {
569 .pipe = NVFX_NEW_ARRAYS,
570 .hw = 0,
571 }
572 };