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