nv40: convert the inline idxbuf paths also
[mesa.git] / src / gallium / drivers / nv40 / nv40_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "pipe/p_util.h"
4
5 #include "nv40_context.h"
6 #include "nv40_state.h"
7
8 #include "nouveau/nouveau_channel.h"
9 #include "nouveau/nouveau_pushbuf.h"
10 #include "nouveau/nouveau_util.h"
11
12 #define FORCE_SWTNL 0
13
14 static INLINE int
15 nv40_vbo_format_to_hw(enum pipe_format pipe, unsigned *fmt, unsigned *ncomp)
16 {
17 char fs[128];
18
19 switch (pipe) {
20 case PIPE_FORMAT_R32_FLOAT:
21 case PIPE_FORMAT_R32G32_FLOAT:
22 case PIPE_FORMAT_R32G32B32_FLOAT:
23 case PIPE_FORMAT_R32G32B32A32_FLOAT:
24 *fmt = NV40TCL_VTXFMT_TYPE_FLOAT;
25 break;
26 case PIPE_FORMAT_R8_UNORM:
27 case PIPE_FORMAT_R8G8_UNORM:
28 case PIPE_FORMAT_R8G8B8_UNORM:
29 case PIPE_FORMAT_R8G8B8A8_UNORM:
30 *fmt = NV40TCL_VTXFMT_TYPE_UBYTE;
31 break;
32 case PIPE_FORMAT_R16_SSCALED:
33 case PIPE_FORMAT_R16G16_SSCALED:
34 case PIPE_FORMAT_R16G16B16_SSCALED:
35 case PIPE_FORMAT_R16G16B16A16_SSCALED:
36 *fmt = NV40TCL_VTXFMT_TYPE_USHORT;
37 break;
38 default:
39 pf_sprint_name(fs, pipe);
40 NOUVEAU_ERR("Unknown format %s\n", fs);
41 return 1;
42 }
43
44 switch (pipe) {
45 case PIPE_FORMAT_R8_UNORM:
46 case PIPE_FORMAT_R32_FLOAT:
47 case PIPE_FORMAT_R16_SSCALED:
48 *ncomp = 1;
49 break;
50 case PIPE_FORMAT_R8G8_UNORM:
51 case PIPE_FORMAT_R32G32_FLOAT:
52 case PIPE_FORMAT_R16G16_SSCALED:
53 *ncomp = 2;
54 break;
55 case PIPE_FORMAT_R8G8B8_UNORM:
56 case PIPE_FORMAT_R32G32B32_FLOAT:
57 case PIPE_FORMAT_R16G16B16_SSCALED:
58 *ncomp = 3;
59 break;
60 case PIPE_FORMAT_R8G8B8A8_UNORM:
61 case PIPE_FORMAT_R32G32B32A32_FLOAT:
62 case PIPE_FORMAT_R16G16B16A16_SSCALED:
63 *ncomp = 4;
64 break;
65 default:
66 pf_sprint_name(fs, pipe);
67 NOUVEAU_ERR("Unknown format %s\n", fs);
68 return 1;
69 }
70
71 return 0;
72 }
73
74 static boolean
75 nv40_vbo_set_idxbuf(struct nv40_context *nv40, struct pipe_buffer *ib,
76 unsigned ib_size)
77 {
78 unsigned type;
79
80 if (!ib) {
81 nv40->idxbuf = NULL;
82 nv40->idxbuf_format = 0xdeadbeef;
83 return FALSE;
84 }
85
86 /* No support for 8bit indices, no support at all on 0x4497 chips */
87 if (nv40->screen->curie->grclass == NV44TCL || ib_size == 1)
88 return FALSE;
89
90 switch (ib_size) {
91 case 2:
92 type = NV40TCL_IDXBUF_FORMAT_TYPE_U16;
93 break;
94 case 4:
95 type = NV40TCL_IDXBUF_FORMAT_TYPE_U32;
96 break;
97 default:
98 return FALSE;
99 }
100
101 if (ib != nv40->idxbuf ||
102 type != nv40->idxbuf_format) {
103 nv40->dirty |= NV40_NEW_ARRAYS;
104 nv40->idxbuf = ib;
105 nv40->idxbuf_format = type;
106 }
107
108 return TRUE;
109 }
110
111 static boolean
112 nv40_vbo_static_attrib(struct nv40_context *nv40, int attrib,
113 struct pipe_vertex_element *ve,
114 struct pipe_vertex_buffer *vb)
115 {
116 struct pipe_winsys *ws = nv40->pipe.winsys;
117 unsigned type, ncomp;
118 void *map;
119
120 if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp))
121 return FALSE;
122
123 map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
124 map += vb->buffer_offset + ve->src_offset;
125
126 switch (type) {
127 case NV40TCL_VTXFMT_TYPE_FLOAT:
128 {
129 float *v = map;
130
131 BEGIN_RING(curie, NV40TCL_VTX_ATTR_4F_X(attrib), 4);
132 switch (ncomp) {
133 case 4:
134 OUT_RINGf(v[0]);
135 OUT_RINGf(v[1]);
136 OUT_RINGf(v[2]);
137 OUT_RINGf(v[3]);
138 break;
139 case 3:
140 OUT_RINGf(v[0]);
141 OUT_RINGf(v[1]);
142 OUT_RINGf(v[2]);
143 OUT_RINGf(1.0);
144 break;
145 case 2:
146 OUT_RINGf(v[0]);
147 OUT_RINGf(v[1]);
148 OUT_RINGf(0.0);
149 OUT_RINGf(1.0);
150 break;
151 case 1:
152 OUT_RINGf(v[0]);
153 OUT_RINGf(0.0);
154 OUT_RINGf(0.0);
155 OUT_RINGf(1.0);
156 break;
157 default:
158 ws->buffer_unmap(ws, vb->buffer);
159 return FALSE;
160 }
161 }
162 break;
163 default:
164 ws->buffer_unmap(ws, vb->buffer);
165 return FALSE;
166 }
167
168 ws->buffer_unmap(ws, vb->buffer);
169
170 return TRUE;
171 }
172
173 boolean
174 nv40_draw_arrays(struct pipe_context *pipe,
175 unsigned mode, unsigned start, unsigned count)
176 {
177 struct nv40_context *nv40 = nv40_context(pipe);
178 struct nouveau_channel *chan = nv40->nvws->channel;
179 unsigned restart;
180
181 nv40_vbo_set_idxbuf(nv40, NULL, 0);
182 if (FORCE_SWTNL || !nv40_state_validate(nv40)) {
183 return nv40_draw_elements_swtnl(pipe, NULL, 0,
184 mode, start, count);
185 }
186
187 while (count) {
188 unsigned vc, nr;
189
190 nv40_state_emit(nv40);
191
192 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
193 mode, start, count, &restart);
194 if (!vc) {
195 FIRE_RING(NULL);
196 continue;
197 }
198
199 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
200 OUT_RING (nvgl_primitive(mode));
201
202 nr = (vc & 0xff);
203 if (nr) {
204 BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
205 OUT_RING (((nr - 1) << 24) | start);
206 start += nr;
207 }
208
209 nr = vc >> 8;
210 while (nr) {
211 unsigned push = nr > 2047 ? 2047 : nr;
212
213 nr -= push;
214
215 BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push);
216 while (push--) {
217 OUT_RING(((0x100 - 1) << 24) | start);
218 start += 0x100;
219 }
220 }
221
222 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
223 OUT_RING (0);
224
225 count -= vc;
226 start = restart;
227 }
228
229 pipe->flush(pipe, 0, NULL);
230 return TRUE;
231 }
232
233 static INLINE void
234 nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
235 unsigned mode, unsigned start, unsigned count)
236 {
237 struct nouveau_channel *chan = nv40->nvws->channel;
238
239 while (count) {
240 uint8_t *elts = (uint8_t *)ib + start;
241 unsigned vc, push, restart;
242
243 nv40_state_emit(nv40);
244
245 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
246 mode, start, count, &restart);
247 if (vc == 0) {
248 FIRE_RING(NULL);
249 continue;
250 }
251 count -= vc;
252
253 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
254 OUT_RING (nvgl_primitive(mode));
255
256 if (vc & 1) {
257 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
258 OUT_RING (elts[0]);
259 elts++; vc--;
260 }
261
262 while (vc) {
263 unsigned i;
264
265 push = MIN2(vc, 2047 * 2);
266
267 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
268 for (i = 0; i < push; i+=2)
269 OUT_RING((elts[i+1] << 16) | elts[i]);
270
271 vc -= push;
272 elts += push;
273 }
274
275 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
276 OUT_RING (0);
277
278 start = restart;
279 }
280 }
281
282 static INLINE void
283 nv40_draw_elements_u16(struct nv40_context *nv40, void *ib,
284 unsigned mode, unsigned start, unsigned count)
285 {
286 struct nouveau_channel *chan = nv40->nvws->channel;
287
288 while (count) {
289 uint16_t *elts = (uint16_t *)ib + start;
290 unsigned vc, push, restart;
291
292 nv40_state_emit(nv40);
293
294 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
295 mode, start, count, &restart);
296 if (vc == 0) {
297 FIRE_RING(NULL);
298 continue;
299 }
300 count -= vc;
301
302 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
303 OUT_RING (nvgl_primitive(mode));
304
305 if (vc & 1) {
306 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
307 OUT_RING (elts[0]);
308 elts++; vc--;
309 }
310
311 while (vc) {
312 unsigned i;
313
314 push = MIN2(vc, 2047 * 2);
315
316 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
317 for (i = 0; i < push; i+=2)
318 OUT_RING((elts[i+1] << 16) | elts[i]);
319
320 vc -= push;
321 elts += push;
322 }
323
324 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
325 OUT_RING (0);
326
327 start = restart;
328 }
329 }
330
331 static INLINE void
332 nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
333 unsigned mode, unsigned start, unsigned count)
334 {
335 struct nouveau_channel *chan = nv40->nvws->channel;
336
337 while (count) {
338 uint32_t *elts = (uint32_t *)ib + start;
339 unsigned vc, push, restart;
340
341 nv40_state_emit(nv40);
342
343 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
344 mode, start, count, &restart);
345 if (vc == 0) {
346 FIRE_RING(NULL);
347 continue;
348 }
349 count -= vc;
350
351 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
352 OUT_RING (nvgl_primitive(mode));
353
354 while (vc) {
355 push = MIN2(vc, 2047);
356
357 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
358 OUT_RINGp (elts, push);
359
360 vc -= push;
361 elts += push;
362 }
363
364 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
365 OUT_RING (0);
366
367 start = restart;
368 }
369 }
370
371 static boolean
372 nv40_draw_elements_inline(struct pipe_context *pipe,
373 struct pipe_buffer *ib, unsigned ib_size,
374 unsigned mode, unsigned start, unsigned count)
375 {
376 struct nv40_context *nv40 = nv40_context(pipe);
377 struct pipe_winsys *ws = pipe->winsys;
378 void *map;
379
380 nv40_state_emit(nv40);
381
382 map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
383 if (!ib) {
384 NOUVEAU_ERR("failed mapping ib\n");
385 return FALSE;
386 }
387
388 switch (ib_size) {
389 case 1:
390 nv40_draw_elements_u08(nv40, map, mode, start, count);
391 break;
392 case 2:
393 nv40_draw_elements_u16(nv40, map, mode, start, count);
394 break;
395 case 4:
396 nv40_draw_elements_u32(nv40, map, mode, start, count);
397 break;
398 default:
399 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
400 break;
401 }
402
403 ws->buffer_unmap(ws, ib);
404 return TRUE;
405 }
406
407 static boolean
408 nv40_draw_elements_vbo(struct pipe_context *pipe,
409 unsigned mode, unsigned start, unsigned count)
410 {
411 struct nv40_context *nv40 = nv40_context(pipe);
412 struct nouveau_channel *chan = nv40->nvws->channel;
413 unsigned restart;
414
415 while (count) {
416 unsigned nr, vc;
417
418 nv40_state_emit(nv40);
419
420 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
421 mode, start, count, &restart);
422 if (!vc) {
423 FIRE_RING(NULL);
424 continue;
425 }
426
427 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
428 OUT_RING (nvgl_primitive(mode));
429
430 nr = (vc & 0xff);
431 if (nr) {
432 BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1);
433 OUT_RING (((nr - 1) << 24) | start);
434 start += nr;
435 }
436
437 nr = vc >> 8;
438 while (nr) {
439 unsigned push = nr > 2047 ? 2047 : nr;
440
441 nr -= push;
442
443 BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push);
444 while (push--) {
445 OUT_RING(((0x100 - 1) << 24) | start);
446 start += 0x100;
447 }
448 }
449
450 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
451 OUT_RING (0);
452
453 count -= vc;
454 start = restart;
455 }
456
457 return TRUE;
458 }
459
460 boolean
461 nv40_draw_elements(struct pipe_context *pipe,
462 struct pipe_buffer *indexBuffer, unsigned indexSize,
463 unsigned mode, unsigned start, unsigned count)
464 {
465 struct nv40_context *nv40 = nv40_context(pipe);
466 boolean idxbuf;
467
468 idxbuf = nv40_vbo_set_idxbuf(nv40, indexBuffer, indexSize);
469 if (FORCE_SWTNL || !nv40_state_validate(nv40)) {
470 return nv40_draw_elements_swtnl(pipe, NULL, 0,
471 mode, start, count);
472 }
473 nv40_state_emit(nv40);
474
475 if (idxbuf) {
476 nv40_draw_elements_vbo(pipe, mode, start, count);
477 } else {
478 nv40_draw_elements_inline(pipe, indexBuffer, indexSize,
479 mode, start, count);
480 }
481
482 pipe->flush(pipe, 0, NULL);
483 return TRUE;
484 }
485
486 static boolean
487 nv40_vbo_validate(struct nv40_context *nv40)
488 {
489 struct nv40_vertex_program *vp = nv40->vertprog;
490 struct nouveau_stateobj *vtxbuf, *vtxfmt;
491 struct pipe_buffer *ib = nv40->idxbuf;
492 unsigned ib_format = nv40->idxbuf_format;
493 unsigned inputs, hw, num_hw;
494 unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
495
496 inputs = vp->ir;
497 for (hw = 0; hw < 16 && inputs; hw++) {
498 if (inputs & (1 << hw)) {
499 num_hw = hw;
500 inputs &= ~(1 << hw);
501 }
502 }
503 num_hw++;
504
505 vtxbuf = so_new(20, 18);
506 so_method(vtxbuf, nv40->screen->curie, NV40TCL_VTXBUF_ADDRESS(0), num_hw);
507 vtxfmt = so_new(17, 0);
508 so_method(vtxfmt, nv40->screen->curie, NV40TCL_VTXFMT(0), num_hw);
509
510 inputs = vp->ir;
511 for (hw = 0; hw < num_hw; hw++) {
512 struct pipe_vertex_element *ve;
513 struct pipe_vertex_buffer *vb;
514 unsigned type, ncomp;
515
516 if (!(inputs & (1 << hw))) {
517 so_data(vtxbuf, 0);
518 so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
519 continue;
520 }
521
522 ve = &nv40->vtxelt[hw];
523 vb = &nv40->vtxbuf[ve->vertex_buffer_index];
524
525 if (!vb->pitch && nv40_vbo_static_attrib(nv40, hw, ve, vb)) {
526 so_data(vtxbuf, 0);
527 so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
528 continue;
529 }
530
531 if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
532 nv40->fallback_swtnl |= NV40_NEW_ARRAYS;
533 so_ref(NULL, &vtxbuf);
534 so_ref(NULL, &vtxfmt);
535 return FALSE;
536 }
537
538 so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
539 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
540 0, NV40TCL_VTXBUF_ADDRESS_DMA1);
541 so_data (vtxfmt, ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
542 (ncomp << NV40TCL_VTXFMT_SIZE_SHIFT) | type));
543 }
544
545 if (ib) {
546 so_method(vtxbuf, nv40->screen->curie, NV40TCL_IDXBUF_ADDRESS, 2);
547 so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
548 so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
549 0, NV40TCL_IDXBUF_FORMAT_DMA1);
550 }
551
552 so_method(vtxbuf, nv40->screen->curie, 0x1710, 1);
553 so_data (vtxbuf, 0);
554
555 so_ref(vtxbuf, &nv40->state.hw[NV40_STATE_VTXBUF]);
556 nv40->state.dirty |= (1ULL << NV40_STATE_VTXBUF);
557 so_ref(vtxfmt, &nv40->state.hw[NV40_STATE_VTXFMT]);
558 nv40->state.dirty |= (1ULL << NV40_STATE_VTXFMT);
559 return FALSE;
560 }
561
562 struct nv40_state_entry nv40_state_vbo = {
563 .validate = nv40_vbo_validate,
564 .dirty = {
565 .pipe = NV40_NEW_ARRAYS,
566 .hw = 0,
567 }
568 };
569