a83ddf11546dabf0554bfecb3ce50beae07116d6
[mesa.git] / src / gallium / drivers / nv30 / nv30_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "util/u_inlines.h"
4
5 #include "nv30_context.h"
6 #include "nv30_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 nv30_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_R8_UNORM:
25 case PIPE_FORMAT_R8G8_UNORM:
26 case PIPE_FORMAT_R8G8B8_UNORM:
27 case PIPE_FORMAT_R8G8B8A8_UNORM:
28 *fmt = NV34TCL_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 = NV34TCL_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 nv30_vbo_set_idxbuf(struct nv30_context *nv30, struct pipe_buffer *ib,
72 unsigned ib_size)
73 {
74 struct pipe_screen *pscreen = &nv30->screen->base.base;
75 unsigned type;
76
77 if (!ib) {
78 nv30->idxbuf = NULL;
79 nv30->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 = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
89 break;
90 case 4:
91 type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
92 break;
93 default:
94 return FALSE;
95 }
96
97 if (ib != nv30->idxbuf ||
98 type != nv30->idxbuf_format) {
99 nv30->dirty |= NV30_NEW_ARRAYS;
100 nv30->idxbuf = ib;
101 nv30->idxbuf_format = type;
102 }
103
104 return TRUE;
105 }
106
107 static boolean
108 nv30_vbo_static_attrib(struct nv30_context *nv30, struct nouveau_stateobj *so,
109 int attrib, struct pipe_vertex_element *ve,
110 struct pipe_vertex_buffer *vb)
111 {
112 struct pipe_screen *pscreen = nv30->pipe.screen;
113 struct nouveau_grobj *rankine = nv30->screen->rankine;
114 unsigned type, ncomp;
115 void *map;
116
117 if (nv30_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 NV34TCL_VTXFMT_TYPE_FLOAT:
125 {
126 float *v = map;
127
128 switch (ncomp) {
129 case 4:
130 so_method(so, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_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 return TRUE;
164 }
165
166 void
167 nv30_draw_arrays(struct pipe_context *pipe,
168 unsigned mode, unsigned start, unsigned count)
169 {
170 struct nv30_context *nv30 = nv30_context(pipe);
171 struct nv30_screen *screen = nv30->screen;
172 struct nouveau_channel *chan = screen->base.channel;
173 struct nouveau_grobj *rankine = screen->rankine;
174 unsigned restart = 0;
175
176 nv30_vbo_set_idxbuf(nv30, NULL, 0);
177 if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
178 /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
179 mode, start, count);*/
180 return;
181 }
182
183 while (count) {
184 unsigned vc, nr;
185
186 nv30_state_emit(nv30);
187
188 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
189 mode, start, count, &restart);
190 if (!vc) {
191 FIRE_RING(chan);
192 continue;
193 }
194
195 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
196 OUT_RING (chan, nvgl_primitive(mode));
197
198 nr = (vc & 0xff);
199 if (nr) {
200 BEGIN_RING(chan, rankine, NV34TCL_VB_VERTEX_BATCH, 1);
201 OUT_RING (chan, ((nr - 1) << 24) | start);
202 start += nr;
203 }
204
205 nr = vc >> 8;
206 while (nr) {
207 unsigned push = nr > 2047 ? 2047 : nr;
208
209 nr -= push;
210
211 BEGIN_RING_NI(chan, rankine, NV34TCL_VB_VERTEX_BATCH, push);
212 while (push--) {
213 OUT_RING(chan, ((0x100 - 1) << 24) | start);
214 start += 0x100;
215 }
216 }
217
218 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
219 OUT_RING (chan, 0);
220
221 count -= vc;
222 start = restart;
223 }
224
225 pipe->flush(pipe, 0, NULL);
226 }
227
228 static INLINE void
229 nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
230 unsigned mode, unsigned start, unsigned count)
231 {
232 struct nv30_screen *screen = nv30->screen;
233 struct nouveau_channel *chan = screen->base.channel;
234 struct nouveau_grobj *rankine = screen->rankine;
235
236 while (count) {
237 uint8_t *elts = (uint8_t *)ib + start;
238 unsigned vc, push, restart = 0;
239
240 nv30_state_emit(nv30);
241
242 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
243 mode, start, count, &restart);
244 if (vc == 0) {
245 FIRE_RING(chan);
246 continue;
247 }
248 count -= vc;
249
250 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
251 OUT_RING (chan, nvgl_primitive(mode));
252
253 if (vc & 1) {
254 BEGIN_RING(chan, rankine, NV34TCL_VB_ELEMENT_U32, 1);
255 OUT_RING (chan, elts[0]);
256 elts++; vc--;
257 }
258
259 while (vc) {
260 unsigned i;
261
262 push = MIN2(vc, 2047 * 2);
263
264 BEGIN_RING_NI(chan, rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
265 for (i = 0; i < push; i+=2)
266 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
267
268 vc -= push;
269 elts += push;
270 }
271
272 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
273 OUT_RING (chan, 0);
274
275 start = restart;
276 }
277 }
278
279 static INLINE void
280 nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
281 unsigned mode, unsigned start, unsigned count)
282 {
283 struct nv30_screen *screen = nv30->screen;
284 struct nouveau_channel *chan = screen->base.channel;
285 struct nouveau_grobj *rankine = screen->rankine;
286
287 while (count) {
288 uint16_t *elts = (uint16_t *)ib + start;
289 unsigned vc, push, restart = 0;
290
291 nv30_state_emit(nv30);
292
293 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
294 mode, start, count, &restart);
295 if (vc == 0) {
296 FIRE_RING(chan);
297 continue;
298 }
299 count -= vc;
300
301 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
302 OUT_RING (chan, nvgl_primitive(mode));
303
304 if (vc & 1) {
305 BEGIN_RING(chan, rankine, NV34TCL_VB_ELEMENT_U32, 1);
306 OUT_RING (chan, elts[0]);
307 elts++; vc--;
308 }
309
310 while (vc) {
311 unsigned i;
312
313 push = MIN2(vc, 2047 * 2);
314
315 BEGIN_RING_NI(chan, rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
316 for (i = 0; i < push; i+=2)
317 OUT_RING(chan, (elts[i+1] << 16) | elts[i]);
318
319 vc -= push;
320 elts += push;
321 }
322
323 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
324 OUT_RING (chan, 0);
325
326 start = restart;
327 }
328 }
329
330 static INLINE void
331 nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
332 unsigned mode, unsigned start, unsigned count)
333 {
334 struct nv30_screen *screen = nv30->screen;
335 struct nouveau_channel *chan = screen->base.channel;
336 struct nouveau_grobj *rankine = screen->rankine;
337
338 while (count) {
339 uint32_t *elts = (uint32_t *)ib + start;
340 unsigned vc, push, restart = 0;
341
342 nv30_state_emit(nv30);
343
344 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
345 mode, start, count, &restart);
346 if (vc == 0) {
347 FIRE_RING(chan);
348 continue;
349 }
350 count -= vc;
351
352 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
353 OUT_RING (chan, nvgl_primitive(mode));
354
355 while (vc) {
356 push = MIN2(vc, 2047);
357
358 BEGIN_RING_NI(chan, rankine, NV34TCL_VB_ELEMENT_U32, push);
359 OUT_RINGp (chan, elts, push);
360
361 vc -= push;
362 elts += push;
363 }
364
365 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
366 OUT_RING (chan, 0);
367
368 start = restart;
369 }
370 }
371
372 static void
373 nv30_draw_elements_inline(struct pipe_context *pipe,
374 struct pipe_buffer *ib, unsigned ib_size,
375 unsigned mode, unsigned start, unsigned count)
376 {
377 struct nv30_context *nv30 = nv30_context(pipe);
378 struct pipe_screen *pscreen = pipe->screen;
379 void *map;
380
381 map = pipe_buffer_map(pscreen, ib, PIPE_BUFFER_USAGE_CPU_READ);
382 if (!ib) {
383 NOUVEAU_ERR("failed mapping ib\n");
384 return;
385 }
386
387 switch (ib_size) {
388 case 1:
389 nv30_draw_elements_u08(nv30, map, mode, start, count);
390 break;
391 case 2:
392 nv30_draw_elements_u16(nv30, map, mode, start, count);
393 break;
394 case 4:
395 nv30_draw_elements_u32(nv30, map, mode, start, count);
396 break;
397 default:
398 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
399 break;
400 }
401
402 pipe_buffer_unmap(pscreen, ib);
403 }
404
405 static void
406 nv30_draw_elements_vbo(struct pipe_context *pipe,
407 unsigned mode, unsigned start, unsigned count)
408 {
409 struct nv30_context *nv30 = nv30_context(pipe);
410 struct nv30_screen *screen = nv30->screen;
411 struct nouveau_channel *chan = screen->base.channel;
412 struct nouveau_grobj *rankine = screen->rankine;
413 unsigned restart = 0;
414
415 while (count) {
416 unsigned nr, vc;
417
418 nv30_state_emit(nv30);
419
420 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
421 mode, start, count, &restart);
422 if (!vc) {
423 FIRE_RING(chan);
424 continue;
425 }
426
427 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
428 OUT_RING (chan, nvgl_primitive(mode));
429
430 nr = (vc & 0xff);
431 if (nr) {
432 BEGIN_RING(chan, rankine, NV34TCL_VB_INDEX_BATCH, 1);
433 OUT_RING (chan, ((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(chan, rankine, NV34TCL_VB_INDEX_BATCH, push);
444 while (push--) {
445 OUT_RING(chan, ((0x100 - 1) << 24) | start);
446 start += 0x100;
447 }
448 }
449
450 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
451 OUT_RING (chan, 0);
452
453 count -= vc;
454 start = restart;
455 }
456 }
457
458 void
459 nv30_draw_elements(struct pipe_context *pipe,
460 struct pipe_buffer *indexBuffer, unsigned indexSize,
461 unsigned mode, unsigned start, unsigned count)
462 {
463 struct nv30_context *nv30 = nv30_context(pipe);
464 boolean idxbuf;
465
466 idxbuf = nv30_vbo_set_idxbuf(nv30, indexBuffer, indexSize);
467 if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
468 /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
469 mode, start, count);*/
470 return;
471 }
472
473 if (idxbuf) {
474 nv30_draw_elements_vbo(pipe, mode, start, count);
475 } else {
476 nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
477 mode, start, count);
478 }
479
480 pipe->flush(pipe, 0, NULL);
481 }
482
483 static boolean
484 nv30_vbo_validate(struct nv30_context *nv30)
485 {
486 struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
487 struct nouveau_grobj *rankine = nv30->screen->rankine;
488 struct pipe_buffer *ib = nv30->idxbuf;
489 unsigned ib_format = nv30->idxbuf_format;
490 unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
491 int hw;
492
493 vtxbuf = so_new(3, 17, 18);
494 so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
495 vtxfmt = so_new(1, 16, 0);
496 so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
497
498 for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
499 struct pipe_vertex_element *ve;
500 struct pipe_vertex_buffer *vb;
501 unsigned type, ncomp;
502
503 ve = &nv30->vtxelt[hw];
504 vb = &nv30->vtxbuf[ve->vertex_buffer_index];
505
506 if (!vb->stride) {
507 if (!sattr)
508 sattr = so_new(16, 16 * 4, 0);
509
510 if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
511 so_data(vtxbuf, 0);
512 so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
513 continue;
514 }
515 }
516
517 if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
518 /*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
519 so_ref(NULL, &vtxbuf);
520 so_ref(NULL, &vtxfmt);
521 return FALSE;
522 }
523
524 so_reloc(vtxbuf, nouveau_bo(vb->buffer), vb->buffer_offset +
525 ve->src_offset, vb_flags | NOUVEAU_BO_LOW |
526 NOUVEAU_BO_OR, 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
527 so_data (vtxfmt, ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) |
528 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
529 }
530
531 if (ib) {
532 struct nouveau_bo *bo = nouveau_bo(ib);
533
534 so_method(vtxbuf, rankine, NV34TCL_IDXBUF_ADDRESS, 2);
535 so_reloc (vtxbuf, bo, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
536 so_reloc (vtxbuf, bo, ib_format, vb_flags | NOUVEAU_BO_OR,
537 0, NV34TCL_IDXBUF_FORMAT_DMA1);
538 }
539
540 so_method(vtxbuf, rankine, 0x1710, 1);
541 so_data (vtxbuf, 0);
542
543 so_ref(vtxbuf, &nv30->state.hw[NV30_STATE_VTXBUF]);
544 so_ref(NULL, &vtxbuf);
545 nv30->state.dirty |= (1ULL << NV30_STATE_VTXBUF);
546 so_ref(vtxfmt, &nv30->state.hw[NV30_STATE_VTXFMT]);
547 so_ref(NULL, &vtxfmt);
548 nv30->state.dirty |= (1ULL << NV30_STATE_VTXFMT);
549 so_ref(sattr, &nv30->state.hw[NV30_STATE_VTXATTR]);
550 so_ref(NULL, &sattr);
551 nv30->state.dirty |= (1ULL << NV30_STATE_VTXATTR);
552 return FALSE;
553 }
554
555 struct nv30_state_entry nv30_state_vbo = {
556 .validate = nv30_vbo_validate,
557 .dirty = {
558 .pipe = NV30_NEW_ARRAYS,
559 .hw = 0,
560 }
561 };