Merge branch 'mesa_7_7_branch'
[mesa.git] / src / gallium / drivers / nv30 / nv30_vbo.c
1 #include "pipe/p_context.h"
2 #include "pipe/p_state.h"
3 #include "pipe/p_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 return TRUE;
227 }
228
229 static INLINE void
230 nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
231 unsigned mode, unsigned start, unsigned count)
232 {
233 struct nv30_screen *screen = nv30->screen;
234 struct nouveau_channel *chan = screen->base.channel;
235 struct nouveau_grobj *rankine = screen->rankine;
236
237 while (count) {
238 uint8_t *elts = (uint8_t *)ib + start;
239 unsigned vc, push, restart = 0;
240
241 nv30_state_emit(nv30);
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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
252 OUT_RING (chan, nvgl_primitive(mode));
253
254 if (vc & 1) {
255 BEGIN_RING(chan, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
274 OUT_RING (chan, 0);
275
276 start = restart;
277 }
278 }
279
280 static INLINE void
281 nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
282 unsigned mode, unsigned start, unsigned count)
283 {
284 struct nv30_screen *screen = nv30->screen;
285 struct nouveau_channel *chan = screen->base.channel;
286 struct nouveau_grobj *rankine = screen->rankine;
287
288 while (count) {
289 uint16_t *elts = (uint16_t *)ib + start;
290 unsigned vc, push, restart = 0;
291
292 nv30_state_emit(nv30);
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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
303 OUT_RING (chan, nvgl_primitive(mode));
304
305 if (vc & 1) {
306 BEGIN_RING(chan, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
325 OUT_RING (chan, 0);
326
327 start = restart;
328 }
329 }
330
331 static INLINE void
332 nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
333 unsigned mode, unsigned start, unsigned count)
334 {
335 struct nv30_screen *screen = nv30->screen;
336 struct nouveau_channel *chan = screen->base.channel;
337 struct nouveau_grobj *rankine = screen->rankine;
338
339 while (count) {
340 uint32_t *elts = (uint32_t *)ib + start;
341 unsigned vc, push, restart = 0;
342
343 nv30_state_emit(nv30);
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, rankine, NV34TCL_VERTEX_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, rankine, NV34TCL_VB_ELEMENT_U32, push);
360 OUT_RINGp (chan, elts, push);
361
362 vc -= push;
363 elts += push;
364 }
365
366 BEGIN_RING(chan, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
367 OUT_RING (chan, 0);
368
369 start = restart;
370 }
371 }
372
373 static void
374 nv30_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 nv30_context *nv30 = nv30_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 nv30_draw_elements_u08(nv30, map, mode, start, count);
391 break;
392 case 2:
393 nv30_draw_elements_u16(nv30, map, mode, start, count);
394 break;
395 case 4:
396 nv30_draw_elements_u32(nv30, 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 nv30_draw_elements_vbo(struct pipe_context *pipe,
408 unsigned mode, unsigned start, unsigned count)
409 {
410 struct nv30_context *nv30 = nv30_context(pipe);
411 struct nv30_screen *screen = nv30->screen;
412 struct nouveau_channel *chan = screen->base.channel;
413 struct nouveau_grobj *rankine = screen->rankine;
414 unsigned restart = 0;
415
416 while (count) {
417 unsigned nr, vc;
418
419 nv30_state_emit(nv30);
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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
429 OUT_RING (chan, nvgl_primitive(mode));
430
431 nr = (vc & 0xff);
432 if (nr) {
433 BEGIN_RING(chan, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_VERTEX_BEGIN_END, 1);
452 OUT_RING (chan, 0);
453
454 count -= vc;
455 start = restart;
456 }
457 }
458
459 void
460 nv30_draw_elements(struct pipe_context *pipe,
461 struct pipe_buffer *indexBuffer, unsigned indexSize,
462 unsigned mode, unsigned start, unsigned count)
463 {
464 struct nv30_context *nv30 = nv30_context(pipe);
465 boolean idxbuf;
466
467 idxbuf = nv30_vbo_set_idxbuf(nv30, indexBuffer, indexSize);
468 if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
469 /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
470 mode, start, count);*/
471 return;
472 }
473
474 if (idxbuf) {
475 nv30_draw_elements_vbo(pipe, mode, start, count);
476 } else {
477 nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
478 mode, start, count);
479 }
480
481 pipe->flush(pipe, 0, NULL);
482 }
483
484 static boolean
485 nv30_vbo_validate(struct nv30_context *nv30)
486 {
487 struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
488 struct nouveau_grobj *rankine = nv30->screen->rankine;
489 struct pipe_buffer *ib = nv30->idxbuf;
490 unsigned ib_format = nv30->idxbuf_format;
491 unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
492 int hw;
493
494 vtxbuf = so_new(3, 17, 18);
495 so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
496 vtxfmt = so_new(1, 16, 0);
497 so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
498
499 for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
500 struct pipe_vertex_element *ve;
501 struct pipe_vertex_buffer *vb;
502 unsigned type, ncomp;
503
504 ve = &nv30->vtxelt[hw];
505 vb = &nv30->vtxbuf[ve->vertex_buffer_index];
506
507 if (!vb->stride) {
508 if (!sattr)
509 sattr = so_new(16, 16 * 4, 0);
510
511 if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
512 so_data(vtxbuf, 0);
513 so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
514 continue;
515 }
516 }
517
518 if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
519 /*nv30->fallback_swtnl |= NV30_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), vb->buffer_offset +
526 ve->src_offset, vb_flags | NOUVEAU_BO_LOW |
527 NOUVEAU_BO_OR, 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
528 so_data (vtxfmt, ((vb->stride << NV34TCL_VTXFMT_STRIDE_SHIFT) |
529 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
530 }
531
532 if (ib) {
533 struct nouveau_bo *bo = nouveau_bo(ib);
534
535 so_method(vtxbuf, rankine, NV34TCL_IDXBUF_ADDRESS, 2);
536 so_reloc (vtxbuf, bo, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
537 so_reloc (vtxbuf, bo, ib_format, vb_flags | NOUVEAU_BO_OR,
538 0, NV34TCL_IDXBUF_FORMAT_DMA1);
539 }
540
541 so_method(vtxbuf, rankine, 0x1710, 1);
542 so_data (vtxbuf, 0);
543
544 so_ref(vtxbuf, &nv30->state.hw[NV30_STATE_VTXBUF]);
545 so_ref(NULL, &vtxbuf);
546 nv30->state.dirty |= (1ULL << NV30_STATE_VTXBUF);
547 so_ref(vtxfmt, &nv30->state.hw[NV30_STATE_VTXFMT]);
548 so_ref(NULL, &vtxfmt);
549 nv30->state.dirty |= (1ULL << NV30_STATE_VTXFMT);
550 so_ref(sattr, &nv30->state.hw[NV30_STATE_VTXATTR]);
551 so_ref(NULL, &sattr);
552 nv30->state.dirty |= (1ULL << NV30_STATE_VTXATTR);
553 return FALSE;
554 }
555
556 struct nv30_state_entry nv30_state_vbo = {
557 .validate = nv30_vbo_validate,
558 .dirty = {
559 .pipe = NV30_NEW_ARRAYS,
560 .hw = 0,
561 }
562 };