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