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