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