e5f9bd5668a307737ff2ba6c0ea62d9637b12acb
[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 struct pipe_screen *pscreen = &nv40->screen->pipe;
79 unsigned type;
80
81 if (!ib) {
82 nv40->idxbuf = NULL;
83 nv40->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 = 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, struct nouveau_stateobj *so,
113 int attrib, struct pipe_vertex_element *ve,
114 struct pipe_vertex_buffer *vb)
115 {
116 struct pipe_winsys *ws = nv40->pipe.winsys;
117 struct nouveau_grobj *curie = nv40->screen->curie;
118 unsigned type, ncomp;
119 void *map;
120
121 if (nv40_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 NV40TCL_VTXFMT_TYPE_FLOAT:
129 {
130 float *v = map;
131
132 switch (ncomp) {
133 case 4:
134 so_method(so, curie, NV40TCL_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, curie, NV40TCL_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, curie, NV40TCL_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, curie, 0x1e40 + (attrib * 4), 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 nv40_draw_arrays(struct pipe_context *pipe,
173 unsigned mode, unsigned start, unsigned count)
174 {
175 struct nv40_context *nv40 = nv40_context(pipe);
176 struct nouveau_channel *chan = nv40->nvws->channel;
177 unsigned restart;
178
179 nv40_vbo_set_idxbuf(nv40, NULL, 0);
180 if (FORCE_SWTNL || !nv40_state_validate(nv40)) {
181 return nv40_draw_elements_swtnl(pipe, NULL, 0,
182 mode, start, count);
183 }
184
185 while (count) {
186 unsigned vc, nr;
187
188 nv40_state_emit(nv40);
189
190 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
191 mode, start, count, &restart);
192 if (!vc) {
193 FIRE_RING(NULL);
194 continue;
195 }
196
197 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
198 OUT_RING (nvgl_primitive(mode));
199
200 nr = (vc & 0xff);
201 if (nr) {
202 BEGIN_RING(curie, NV40TCL_VB_VERTEX_BATCH, 1);
203 OUT_RING (((nr - 1) << 24) | start);
204 start += nr;
205 }
206
207 nr = vc >> 8;
208 while (nr) {
209 unsigned push = nr > 2047 ? 2047 : nr;
210
211 nr -= push;
212
213 BEGIN_RING_NI(curie, NV40TCL_VB_VERTEX_BATCH, push);
214 while (push--) {
215 OUT_RING(((0x100 - 1) << 24) | start);
216 start += 0x100;
217 }
218 }
219
220 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
221 OUT_RING (0);
222
223 count -= vc;
224 start = restart;
225 }
226
227 pipe->flush(pipe, 0, NULL);
228 return TRUE;
229 }
230
231 static INLINE void
232 nv40_draw_elements_u08(struct nv40_context *nv40, void *ib,
233 unsigned mode, unsigned start, unsigned count)
234 {
235 struct nouveau_channel *chan = nv40->nvws->channel;
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(NULL);
247 continue;
248 }
249 count -= vc;
250
251 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
252 OUT_RING (nvgl_primitive(mode));
253
254 if (vc & 1) {
255 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
256 OUT_RING (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(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
266 for (i = 0; i < push; i+=2)
267 OUT_RING((elts[i+1] << 16) | elts[i]);
268
269 vc -= push;
270 elts += push;
271 }
272
273 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
274 OUT_RING (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 nouveau_channel *chan = nv40->nvws->channel;
285
286 while (count) {
287 uint16_t *elts = (uint16_t *)ib + start;
288 unsigned vc, push, restart;
289
290 nv40_state_emit(nv40);
291
292 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
293 mode, start, count, &restart);
294 if (vc == 0) {
295 FIRE_RING(NULL);
296 continue;
297 }
298 count -= vc;
299
300 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
301 OUT_RING (nvgl_primitive(mode));
302
303 if (vc & 1) {
304 BEGIN_RING(curie, NV40TCL_VB_ELEMENT_U32, 1);
305 OUT_RING (elts[0]);
306 elts++; vc--;
307 }
308
309 while (vc) {
310 unsigned i;
311
312 push = MIN2(vc, 2047 * 2);
313
314 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U16, push >> 1);
315 for (i = 0; i < push; i+=2)
316 OUT_RING((elts[i+1] << 16) | elts[i]);
317
318 vc -= push;
319 elts += push;
320 }
321
322 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
323 OUT_RING (0);
324
325 start = restart;
326 }
327 }
328
329 static INLINE void
330 nv40_draw_elements_u32(struct nv40_context *nv40, void *ib,
331 unsigned mode, unsigned start, unsigned count)
332 {
333 struct nouveau_channel *chan = nv40->nvws->channel;
334
335 while (count) {
336 uint32_t *elts = (uint32_t *)ib + start;
337 unsigned vc, push, restart;
338
339 nv40_state_emit(nv40);
340
341 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
342 mode, start, count, &restart);
343 if (vc == 0) {
344 FIRE_RING(NULL);
345 continue;
346 }
347 count -= vc;
348
349 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
350 OUT_RING (nvgl_primitive(mode));
351
352 while (vc) {
353 push = MIN2(vc, 2047);
354
355 BEGIN_RING_NI(curie, NV40TCL_VB_ELEMENT_U32, push);
356 OUT_RINGp (elts, push);
357
358 vc -= push;
359 elts += push;
360 }
361
362 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
363 OUT_RING (0);
364
365 start = restart;
366 }
367 }
368
369 static boolean
370 nv40_draw_elements_inline(struct pipe_context *pipe,
371 struct pipe_buffer *ib, unsigned ib_size,
372 unsigned mode, unsigned start, unsigned count)
373 {
374 struct nv40_context *nv40 = nv40_context(pipe);
375 struct pipe_winsys *ws = pipe->winsys;
376 void *map;
377
378 map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
379 if (!ib) {
380 NOUVEAU_ERR("failed mapping ib\n");
381 return FALSE;
382 }
383
384 switch (ib_size) {
385 case 1:
386 nv40_draw_elements_u08(nv40, map, mode, start, count);
387 break;
388 case 2:
389 nv40_draw_elements_u16(nv40, map, mode, start, count);
390 break;
391 case 4:
392 nv40_draw_elements_u32(nv40, map, mode, start, count);
393 break;
394 default:
395 NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
396 break;
397 }
398
399 ws->buffer_unmap(ws, ib);
400 return TRUE;
401 }
402
403 static boolean
404 nv40_draw_elements_vbo(struct pipe_context *pipe,
405 unsigned mode, unsigned start, unsigned count)
406 {
407 struct nv40_context *nv40 = nv40_context(pipe);
408 struct nouveau_channel *chan = nv40->nvws->channel;
409 unsigned restart;
410
411 while (count) {
412 unsigned nr, vc;
413
414 nv40_state_emit(nv40);
415
416 vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
417 mode, start, count, &restart);
418 if (!vc) {
419 FIRE_RING(NULL);
420 continue;
421 }
422
423 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
424 OUT_RING (nvgl_primitive(mode));
425
426 nr = (vc & 0xff);
427 if (nr) {
428 BEGIN_RING(curie, NV40TCL_VB_INDEX_BATCH, 1);
429 OUT_RING (((nr - 1) << 24) | start);
430 start += nr;
431 }
432
433 nr = vc >> 8;
434 while (nr) {
435 unsigned push = nr > 2047 ? 2047 : nr;
436
437 nr -= push;
438
439 BEGIN_RING_NI(curie, NV40TCL_VB_INDEX_BATCH, push);
440 while (push--) {
441 OUT_RING(((0x100 - 1) << 24) | start);
442 start += 0x100;
443 }
444 }
445
446 BEGIN_RING(curie, NV40TCL_BEGIN_END, 1);
447 OUT_RING (0);
448
449 count -= vc;
450 start = restart;
451 }
452
453 return TRUE;
454 }
455
456 boolean
457 nv40_draw_elements(struct pipe_context *pipe,
458 struct pipe_buffer *indexBuffer, unsigned indexSize,
459 unsigned mode, unsigned start, unsigned count)
460 {
461 struct nv40_context *nv40 = nv40_context(pipe);
462 boolean idxbuf;
463
464 idxbuf = nv40_vbo_set_idxbuf(nv40, indexBuffer, indexSize);
465 if (FORCE_SWTNL || !nv40_state_validate(nv40)) {
466 return nv40_draw_elements_swtnl(pipe, NULL, 0,
467 mode, start, count);
468 }
469
470 if (idxbuf) {
471 nv40_draw_elements_vbo(pipe, mode, start, count);
472 } else {
473 nv40_draw_elements_inline(pipe, indexBuffer, indexSize,
474 mode, start, count);
475 }
476
477 pipe->flush(pipe, 0, NULL);
478 return TRUE;
479 }
480
481 static boolean
482 nv40_vbo_validate(struct nv40_context *nv40)
483 {
484 struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
485 struct nouveau_grobj *curie = nv40->screen->curie;
486 struct pipe_buffer *ib = nv40->idxbuf;
487 unsigned ib_format = nv40->idxbuf_format;
488 unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
489 int hw;
490
491 if (nv40->edgeflags) {
492 nv40->fallback_swtnl |= NV40_NEW_ARRAYS;
493 return FALSE;
494 }
495
496 vtxbuf = so_new(20, 18);
497 so_method(vtxbuf, curie, NV40TCL_VTXBUF_ADDRESS(0), nv40->vtxelt_nr);
498 vtxfmt = so_new(17, 0);
499 so_method(vtxfmt, curie, NV40TCL_VTXFMT(0), nv40->vtxelt_nr);
500
501 for (hw = 0; hw < nv40->vtxelt_nr; hw++) {
502 struct pipe_vertex_element *ve;
503 struct pipe_vertex_buffer *vb;
504 unsigned type, ncomp;
505
506 ve = &nv40->vtxelt[hw];
507 vb = &nv40->vtxbuf[ve->vertex_buffer_index];
508
509 if (!vb->pitch) {
510 if (!sattr)
511 sattr = so_new(16 * 5, 0);
512
513 if (nv40_vbo_static_attrib(nv40, sattr, hw, ve, vb)) {
514 so_data(vtxbuf, 0);
515 so_data(vtxfmt, NV40TCL_VTXFMT_TYPE_FLOAT);
516 continue;
517 }
518 }
519
520 if (nv40_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
521 nv40->fallback_swtnl |= NV40_NEW_ARRAYS;
522 so_ref(NULL, &vtxbuf);
523 so_ref(NULL, &vtxfmt);
524 return FALSE;
525 }
526
527 so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
528 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
529 0, NV40TCL_VTXBUF_ADDRESS_DMA1);
530 so_data (vtxfmt, ((vb->pitch << NV40TCL_VTXFMT_STRIDE_SHIFT) |
531 (ncomp << NV40TCL_VTXFMT_SIZE_SHIFT) | type));
532 }
533
534 if (ib) {
535 so_method(vtxbuf, curie, NV40TCL_IDXBUF_ADDRESS, 2);
536 so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
537 so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
538 0, NV40TCL_IDXBUF_FORMAT_DMA1);
539 }
540
541 so_method(vtxbuf, curie, 0x1710, 1);
542 so_data (vtxbuf, 0);
543
544 so_ref(vtxbuf, &nv40->state.hw[NV40_STATE_VTXBUF]);
545 nv40->state.dirty |= (1ULL << NV40_STATE_VTXBUF);
546 so_ref(vtxfmt, &nv40->state.hw[NV40_STATE_VTXFMT]);
547 nv40->state.dirty |= (1ULL << NV40_STATE_VTXFMT);
548 so_ref(sattr, &nv40->state.hw[NV40_STATE_VTXATTR]);
549 nv40->state.dirty |= (1ULL << NV40_STATE_VTXATTR);
550 return FALSE;
551 }
552
553 struct nv40_state_entry nv40_state_vbo = {
554 .validate = nv40_vbo_validate,
555 .dirty = {
556 .pipe = NV40_NEW_ARRAYS,
557 .hw = 0,
558 }
559 };
560