nv30: Emit vertex buffer objects using state objects
[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_util.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 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 = NV34TCL_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 = NV34TCL_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 = NV34TCL_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 nv30_vbo_set_idxbuf(struct nv30_context *nv30, struct pipe_buffer *ib,
76 unsigned ib_size)
77 {
78 struct pipe_screen *pscreen = &nv30->screen->pipe;
79 unsigned type;
80
81 if (!ib) {
82 nv30->idxbuf = NULL;
83 nv30->idxbuf_format = 0xdeadbeef;
84 return FALSE;
85 }
86
87 if (!pscreen->get_param(pscreen, NOUVEAU_CAP_HW_IDXBUF) || ib_size == 1)
88 return FALSE;
89
90 switch (ib_size) {
91 case 2:
92 type = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
93 break;
94 case 4:
95 type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
96 break;
97 default:
98 return FALSE;
99 }
100
101 if (ib != nv30->idxbuf ||
102 type != nv30->idxbuf_format) {
103 nv30->dirty |= NV30_NEW_ARRAYS;
104 nv30->idxbuf = ib;
105 nv30->idxbuf_format = type;
106 }
107
108 return TRUE;
109 }
110
111 static boolean
112 nv30_vbo_static_attrib(struct nv30_context *nv30, struct nouveau_stateobj *so,
113 int attrib, struct pipe_vertex_element *ve,
114 struct pipe_vertex_buffer *vb)
115 {
116 struct pipe_winsys *ws = nv30->pipe.winsys;
117 struct nouveau_grobj *rankine = nv30->screen->rankine;
118 unsigned type, ncomp;
119 void *map;
120
121 if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp))
122 return FALSE;
123
124 map = ws->buffer_map(ws, vb->buffer, PIPE_BUFFER_USAGE_CPU_READ);
125 map += vb->buffer_offset + ve->src_offset;
126
127 switch (type) {
128 case NV34TCL_VTXFMT_TYPE_FLOAT:
129 {
130 float *v = map;
131
132 switch (ncomp) {
133 case 4:
134 so_method(so, rankine, NV34TCL_VTX_ATTR_4F_X(attrib), 4);
135 so_data (so, fui(v[0]));
136 so_data (so, fui(v[1]));
137 so_data (so, fui(v[2]));
138 so_data (so, fui(v[3]));
139 break;
140 case 3:
141 so_method(so, rankine, NV34TCL_VTX_ATTR_3F_X(attrib), 3);
142 so_data (so, fui(v[0]));
143 so_data (so, fui(v[1]));
144 so_data (so, fui(v[2]));
145 break;
146 case 2:
147 so_method(so, rankine, NV34TCL_VTX_ATTR_2F_X(attrib), 2);
148 so_data (so, fui(v[0]));
149 so_data (so, fui(v[1]));
150 break;
151 case 1:
152 so_method(so, rankine, NV34TCL_VTX_ATTR_1F(attrib), 1);
153 so_data (so, fui(v[0]));
154 break;
155 default:
156 ws->buffer_unmap(ws, vb->buffer);
157 return FALSE;
158 }
159 }
160 break;
161 default:
162 ws->buffer_unmap(ws, vb->buffer);
163 return FALSE;
164 }
165
166 ws->buffer_unmap(ws, vb->buffer);
167
168 return TRUE;
169 }
170
171 boolean
172 nv30_draw_arrays(struct pipe_context *pipe,
173 unsigned mode, unsigned start, unsigned count)
174 {
175 struct nv30_context *nv30 = nv30_context(pipe);
176 struct nouveau_channel *chan = nv30->nvws->channel;
177 unsigned restart = 0;
178
179 nv30_vbo_set_idxbuf(nv30, NULL, 0);
180 if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
181 /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
182 mode, start, count);*/
183 return FALSE;
184 }
185
186 while (count) {
187 unsigned vc, nr;
188
189 nv30_state_emit(nv30);
190
191 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
192 mode, start, count, &restart);
193 if (!vc) {
194 FIRE_RING(NULL);
195 continue;
196 }
197
198 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
199 OUT_RING (nvgl_primitive(mode));
200
201 nr = (vc & 0xff);
202 if (nr) {
203 BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
204 OUT_RING (((nr - 1) << 24) | start);
205 start += nr;
206 }
207
208 nr = vc >> 8;
209 while (nr) {
210 unsigned push = nr > 2047 ? 2047 : nr;
211
212 nr -= push;
213
214 BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
215 while (push--) {
216 OUT_RING(((0x100 - 1) << 24) | start);
217 start += 0x100;
218 }
219 }
220
221 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
222 OUT_RING (0);
223
224 count -= vc;
225 start = restart;
226 }
227
228 pipe->flush(pipe, 0, NULL);
229 return TRUE;
230 }
231
232 static INLINE void
233 nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
234 unsigned mode, unsigned start, unsigned count)
235 {
236 struct nouveau_channel *chan = nv30->nvws->channel;
237
238 while (count) {
239 uint8_t *elts = (uint8_t *)ib + start;
240 unsigned vc, push, restart = 0;
241
242 nv30_state_emit(nv30);
243
244 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
245 mode, start, count, &restart);
246 if (vc == 0) {
247 FIRE_RING(NULL);
248 continue;
249 }
250 count -= vc;
251
252 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
253 OUT_RING (nvgl_primitive(mode));
254
255 if (vc & 1) {
256 BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
257 OUT_RING (elts[0]);
258 elts++; vc--;
259 }
260
261 while (vc) {
262 unsigned i;
263
264 push = MIN2(vc, 2047 * 2);
265
266 BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
267 for (i = 0; i < push; i+=2)
268 OUT_RING((elts[i+1] << 16) | elts[i]);
269
270 vc -= push;
271 elts += push;
272 }
273
274 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
275 OUT_RING (0);
276
277 start = restart;
278 }
279 }
280
281 static INLINE void
282 nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
283 unsigned mode, unsigned start, unsigned count)
284 {
285 struct nouveau_channel *chan = nv30->nvws->channel;
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(NULL);
297 continue;
298 }
299 count -= vc;
300
301 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
302 OUT_RING (nvgl_primitive(mode));
303
304 if (vc & 1) {
305 BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
306 OUT_RING (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(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
316 for (i = 0; i < push; i+=2)
317 OUT_RING((elts[i+1] << 16) | elts[i]);
318
319 vc -= push;
320 elts += push;
321 }
322
323 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
324 OUT_RING (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 nouveau_channel *chan = nv30->nvws->channel;
335
336 while (count) {
337 uint32_t *elts = (uint32_t *)ib + start;
338 unsigned vc, push, restart = 0;
339
340 nv30_state_emit(nv30);
341
342 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
343 mode, start, count, &restart);
344 if (vc == 0) {
345 FIRE_RING(NULL);
346 continue;
347 }
348 count -= vc;
349
350 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
351 OUT_RING (nvgl_primitive(mode));
352
353 while (vc) {
354 push = MIN2(vc, 2047);
355
356 BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
357 OUT_RINGp (elts, push);
358
359 vc -= push;
360 elts += push;
361 }
362
363 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
364 OUT_RING (0);
365
366 start = restart;
367 }
368 }
369
370 static boolean
371 nv30_draw_elements_inline(struct pipe_context *pipe,
372 struct pipe_buffer *ib, unsigned ib_size,
373 unsigned mode, unsigned start, unsigned count)
374 {
375 struct nv30_context *nv30 = nv30_context(pipe);
376 struct pipe_winsys *ws = pipe->winsys;
377 void *map;
378
379 map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
380 if (!ib) {
381 NOUVEAU_ERR("failed mapping ib\n");
382 return FALSE;
383 }
384
385 switch (ib_size) {
386 case 1:
387 nv30_draw_elements_u08(nv30, map, mode, start, count);
388 break;
389 case 2:
390 nv30_draw_elements_u16(nv30, map, mode, start, count);
391 break;
392 case 4:
393 nv30_draw_elements_u32(nv30, map, mode, start, count);
394 break;
395 default:
396 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
397 break;
398 }
399
400 ws->buffer_unmap(ws, ib);
401 return TRUE;
402 }
403
404 static boolean
405 nv30_draw_elements_vbo(struct pipe_context *pipe,
406 unsigned mode, unsigned start, unsigned count)
407 {
408 struct nv30_context *nv30 = nv30_context(pipe);
409 struct nouveau_channel *chan = nv30->nvws->channel;
410 unsigned restart = 0;
411
412 while (count) {
413 unsigned nr, vc;
414
415 nv30_state_emit(nv30);
416
417 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
418 mode, start, count, &restart);
419 if (!vc) {
420 FIRE_RING(NULL);
421 continue;
422 }
423
424 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
425 OUT_RING (nvgl_primitive(mode));
426
427 nr = (vc & 0xff);
428 if (nr) {
429 BEGIN_RING(rankine, NV34TCL_VB_INDEX_BATCH, 1);
430 OUT_RING (((nr - 1) << 24) | start);
431 start += nr;
432 }
433
434 nr = vc >> 8;
435 while (nr) {
436 unsigned push = nr > 2047 ? 2047 : nr;
437
438 nr -= push;
439
440 BEGIN_RING_NI(rankine, NV34TCL_VB_INDEX_BATCH, push);
441 while (push--) {
442 OUT_RING(((0x100 - 1) << 24) | start);
443 start += 0x100;
444 }
445 }
446
447 BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
448 OUT_RING (0);
449
450 count -= vc;
451 start = restart;
452 }
453
454 return TRUE;
455 }
456
457 boolean
458 nv30_draw_elements(struct pipe_context *pipe,
459 struct pipe_buffer *indexBuffer, unsigned indexSize,
460 unsigned mode, unsigned start, unsigned count)
461 {
462 struct nv30_context *nv30 = nv30_context(pipe);
463 boolean idxbuf;
464
465 idxbuf = nv30_vbo_set_idxbuf(nv30, indexBuffer, indexSize);
466 if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
467 /*return nv30_draw_elements_swtnl(pipe, NULL, 0,
468 mode, start, count);*/
469 return FALSE;
470 }
471
472 if (idxbuf) {
473 nv30_draw_elements_vbo(pipe, mode, start, count);
474 } else {
475 nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
476 mode, start, count);
477 }
478
479 pipe->flush(pipe, 0, NULL);
480 return TRUE;
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 if (nv30->edgeflags) {
494 /*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
495 return FALSE;
496 }
497
498 vtxbuf = so_new(20, 18);
499 so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
500 vtxfmt = so_new(17, 0);
501 so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
502
503 for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
504 struct pipe_vertex_element *ve;
505 struct pipe_vertex_buffer *vb;
506 unsigned type, ncomp;
507
508 ve = &nv30->vtxelt[hw];
509 vb = &nv30->vtxbuf[ve->vertex_buffer_index];
510
511 if (!vb->pitch) {
512 if (!sattr)
513 sattr = so_new(16 * 5, 0);
514
515 if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
516 so_data(vtxbuf, 0);
517 so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
518 continue;
519 }
520 }
521
522 if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
523 /*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
524 so_ref(NULL, &vtxbuf);
525 so_ref(NULL, &vtxfmt);
526 return FALSE;
527 }
528
529 so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
530 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
531 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
532 so_data (vtxfmt, ((vb->pitch << NV34TCL_VTXFMT_STRIDE_SHIFT) |
533 (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
534 }
535
536 if (ib) {
537 so_method(vtxbuf, rankine, NV34TCL_IDXBUF_ADDRESS, 2);
538 so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
539 so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
540 0, NV34TCL_IDXBUF_FORMAT_DMA1);
541 }
542
543 so_method(vtxbuf, rankine, 0x1710, 1);
544 so_data (vtxbuf, 0);
545
546 so_ref(vtxbuf, &nv30->state.hw[NV30_STATE_VTXBUF]);
547 nv30->state.dirty |= (1ULL << NV30_STATE_VTXBUF);
548 so_ref(vtxfmt, &nv30->state.hw[NV30_STATE_VTXFMT]);
549 nv30->state.dirty |= (1ULL << NV30_STATE_VTXFMT);
550 so_ref(sattr, &nv30->state.hw[NV30_STATE_VTXATTR]);
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 };