nv50: rip out inline push draw paths temporarily
[mesa.git] / src / gallium / drivers / nv50 / nv50_vbo.c
1 /*
2 * Copyright 2008 Ben Skeggs
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "pipe/p_context.h"
24 #include "pipe/p_state.h"
25 #include "util/u_inlines.h"
26 #include "util/u_format.h"
27
28 #include "nv50_context.h"
29
30 #define NV50_USING_LOATHED_EDGEFLAG(ctx) ((ctx)->vertprog->cfg.edgeflag_in < 16)
31
32 static INLINE unsigned
33 nv50_prim(unsigned mode)
34 {
35 switch (mode) {
36 case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
37 case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
38 case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
39 case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
40 case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
41 case PIPE_PRIM_TRIANGLE_STRIP:
42 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
43 case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
44 case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
45 case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
46 case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
47 case PIPE_PRIM_LINES_ADJACENCY:
48 return NV50TCL_VERTEX_BEGIN_LINES_ADJACENCY;
49 case PIPE_PRIM_LINE_STRIP_ADJACENCY:
50 return NV50TCL_VERTEX_BEGIN_LINE_STRIP_ADJACENCY;
51 case PIPE_PRIM_TRIANGLES_ADJACENCY:
52 return NV50TCL_VERTEX_BEGIN_TRIANGLES_ADJACENCY;
53 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
54 return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP_ADJACENCY;
55 default:
56 break;
57 }
58
59 NOUVEAU_ERR("invalid primitive type %d\n", mode);
60 return NV50TCL_VERTEX_BEGIN_POINTS;
61 }
62
63 static INLINE uint32_t
64 nv50_vbo_type_to_hw(enum pipe_format format)
65 {
66 const struct util_format_description *desc;
67
68 desc = util_format_description(format);
69 assert(desc);
70
71 switch (desc->channel[0].type) {
72 case UTIL_FORMAT_TYPE_FLOAT:
73 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT;
74 case UTIL_FORMAT_TYPE_UNSIGNED:
75 if (desc->channel[0].normalized) {
76 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UNORM;
77 }
78 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_USCALED;
79 case UTIL_FORMAT_TYPE_SIGNED:
80 if (desc->channel[0].normalized) {
81 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SNORM;
82 }
83 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SSCALED;
84 /*
85 case PIPE_FORMAT_TYPE_UINT:
86 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UINT;
87 case PIPE_FORMAT_TYPE_SINT:
88 return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SINT; */
89 default:
90 return 0;
91 }
92 }
93
94 static INLINE uint32_t
95 nv50_vbo_size_to_hw(unsigned size, unsigned nr_c)
96 {
97 static const uint32_t hw_values[] = {
98 0, 0, 0, 0,
99 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8,
100 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8,
101 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8,
102 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_8_8_8_8,
103 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16,
104 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16,
105 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16,
106 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_16_16_16_16,
107 0, 0, 0, 0,
108 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32,
109 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32,
110 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32,
111 NV50TCL_VERTEX_ARRAY_ATTRIB_FORMAT_32_32_32_32 };
112
113 /* we'd also have R11G11B10 and R10G10B10A2 */
114
115 assert(nr_c > 0 && nr_c <= 4);
116
117 if (size > 32)
118 return 0;
119 size >>= (3 - 2);
120
121 return hw_values[size + (nr_c - 1)];
122 }
123
124 static INLINE uint32_t
125 nv50_vbo_vtxelt_to_hw(struct pipe_vertex_element *ve)
126 {
127 uint32_t hw_type, hw_size;
128 enum pipe_format pf = ve->src_format;
129 const struct util_format_description *desc;
130 unsigned size, nr_components;
131
132 desc = util_format_description(pf);
133 assert(desc);
134
135 size = util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0);
136 nr_components = util_format_get_nr_components(pf);
137
138 hw_type = nv50_vbo_type_to_hw(pf);
139 hw_size = nv50_vbo_size_to_hw(size, nr_components);
140
141 if (!hw_type || !hw_size) {
142 NOUVEAU_ERR("unsupported vbo format: %s\n", util_format_name(pf));
143 abort();
144 return 0x24e80000;
145 }
146
147 if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z) /* BGRA */
148 hw_size |= (1 << 31); /* no real swizzle bits :-( */
149
150 return (hw_type | hw_size);
151 }
152
153 static void
154 nv50_set_static_vtxattr(struct nv50_context *nv50, unsigned i, void *data)
155 {
156 struct nouveau_grobj *tesla = nv50->screen->tesla;
157 struct nouveau_channel *chan = tesla->channel;
158 float v[4];
159 enum pipe_format pf = nv50->vtxelt->pipe[i].src_format;
160 unsigned nr_components = util_format_get_nr_components(pf);
161
162 util_format_read_4f(pf, v, 0, data, 0, 0, 0, 1, 1);
163
164 switch (nr_components) {
165 case 4:
166 BEGIN_RING(chan, tesla, NV50TCL_VTX_ATTR_4F_X(i), 4);
167 OUT_RINGf (chan, v[0]);
168 OUT_RINGf (chan, v[1]);
169 OUT_RINGf (chan, v[2]);
170 OUT_RINGf (chan, v[3]);
171 break;
172 case 3:
173 BEGIN_RING(chan, tesla, NV50TCL_VTX_ATTR_3F_X(i), 3);
174 OUT_RINGf (chan, v[0]);
175 OUT_RINGf (chan, v[1]);
176 OUT_RINGf (chan, v[2]);
177 break;
178 case 2:
179 BEGIN_RING(chan, tesla, NV50TCL_VTX_ATTR_2F_X(i), 2);
180 OUT_RINGf (chan, v[0]);
181 OUT_RINGf (chan, v[1]);
182 break;
183 case 1:
184 BEGIN_RING(chan, tesla, NV50TCL_VTX_ATTR_1F(i), 1);
185 OUT_RINGf (chan, v[0]);
186 break;
187 default:
188 assert(0);
189 break;
190 }
191 }
192
193 static unsigned
194 init_per_instance_arrays(struct nv50_context *nv50,
195 unsigned startInstance,
196 unsigned pos[16], unsigned step[16])
197 {
198 struct nouveau_grobj *tesla = nv50->screen->tesla;
199 struct nouveau_channel *chan = tesla->channel;
200 struct nouveau_bo *bo;
201 struct nouveau_stateobj *so;
202 unsigned i, b, count = 0, num_elements = nv50->vtxelt->num_elements;
203 const uint32_t rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
204
205 so = so_new(num_elements, num_elements * 2, num_elements * 2);
206
207 for (i = 0; i < nv50->vtxelt->num_elements; ++i) {
208 if (!nv50->vtxelt->pipe[i].instance_divisor)
209 continue;
210 ++count;
211 b = nv50->vtxelt->pipe[i].vertex_buffer_index;
212
213 pos[i] = nv50->vtxelt->pipe[i].src_offset +
214 nv50->vtxbuf[b].buffer_offset +
215 startInstance * nv50->vtxbuf[b].stride;
216
217 if (!startInstance) {
218 step[i] = 0;
219 continue;
220 }
221 step[i] = startInstance %
222 nv50->vtxelt->pipe[i].instance_divisor;
223
224 bo = nouveau_bo(nv50->vtxbuf[b].buffer);
225
226 so_method(so, tesla, NV50TCL_VERTEX_ARRAY_START_HIGH(i), 2);
227 so_reloc (so, bo, pos[i], rl | NOUVEAU_BO_HIGH, 0, 0);
228 so_reloc (so, bo, pos[i], rl | NOUVEAU_BO_LOW, 0, 0);
229 }
230
231 if (count && startInstance) {
232 so_ref (so, &nv50->state.instbuf); /* for flush notify */
233 so_emit(chan, nv50->state.instbuf);
234 }
235 so_ref (NULL, &so);
236
237 return count;
238 }
239
240 static void
241 step_per_instance_arrays(struct nv50_context *nv50,
242 unsigned pos[16], unsigned step[16])
243 {
244 struct nouveau_grobj *tesla = nv50->screen->tesla;
245 struct nouveau_channel *chan = tesla->channel;
246 struct nouveau_bo *bo;
247 struct nouveau_stateobj *so;
248 unsigned i, b, num_elements = nv50->vtxelt->num_elements;
249 const uint32_t rl = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
250
251 so = so_new(num_elements, num_elements * 2, num_elements * 2);
252
253 for (i = 0; i < nv50->vtxelt->num_elements; ++i) {
254 if (!nv50->vtxelt->pipe[i].instance_divisor)
255 continue;
256 b = nv50->vtxelt->pipe[i].vertex_buffer_index;
257
258 if (++step[i] == nv50->vtxelt->pipe[i].instance_divisor) {
259 step[i] = 0;
260 pos[i] += nv50->vtxbuf[b].stride;
261 }
262
263 bo = nouveau_bo(nv50->vtxbuf[b].buffer);
264
265 so_method(so, tesla, NV50TCL_VERTEX_ARRAY_START_HIGH(i), 2);
266 so_reloc (so, bo, pos[i], rl | NOUVEAU_BO_HIGH, 0, 0);
267 so_reloc (so, bo, pos[i], rl | NOUVEAU_BO_LOW, 0, 0);
268 }
269
270 so_ref (so, &nv50->state.instbuf); /* for flush notify */
271 so_ref (NULL, &so);
272
273 so_emit(chan, nv50->state.instbuf);
274 }
275
276 void
277 nv50_draw_arrays_instanced(struct pipe_context *pipe,
278 unsigned mode, unsigned start, unsigned count,
279 unsigned startInstance, unsigned instanceCount)
280 {
281 struct nv50_context *nv50 = nv50_context(pipe);
282 struct nouveau_channel *chan = nv50->screen->tesla->channel;
283 struct nouveau_grobj *tesla = nv50->screen->tesla;
284 unsigned i, nz_divisors;
285 unsigned step[16], pos[16];
286
287 if (!nv50_state_validate(nv50, 0))
288 return;
289 chan->flush_notify = nv50_state_flush_notify;
290
291 nz_divisors = init_per_instance_arrays(nv50, startInstance, pos, step);
292
293 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
294 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
295 OUT_RING (chan, startInstance);
296
297 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
298 OUT_RING (chan, nv50_prim(mode));
299 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
300 OUT_RING (chan, start);
301 OUT_RING (chan, count);
302 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
303 OUT_RING (chan, 0);
304
305 for (i = 1; i < instanceCount; i++) {
306 if (nz_divisors) /* any non-zero array divisors ? */
307 step_per_instance_arrays(nv50, pos, step);
308
309 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
310 OUT_RING (chan, nv50_prim(mode) | (1 << 28));
311 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
312 OUT_RING (chan, start);
313 OUT_RING (chan, count);
314 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
315 OUT_RING (chan, 0);
316 }
317
318 chan->flush_notify = NULL;
319
320 so_ref(NULL, &nv50->state.instbuf);
321 }
322
323 void
324 nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
325 unsigned count)
326 {
327 struct nv50_context *nv50 = nv50_context(pipe);
328 struct nouveau_channel *chan = nv50->screen->tesla->channel;
329 struct nouveau_grobj *tesla = nv50->screen->tesla;
330
331 if (!nv50_state_validate(nv50, 11))
332 return;
333 chan->flush_notify = nv50_state_flush_notify;
334
335 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
336 OUT_RING (chan, nv50_prim(mode));
337 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
338 OUT_RING (chan, start);
339 OUT_RING (chan, count);
340 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
341 OUT_RING (chan, 0);
342
343 chan->flush_notify = NULL;
344 }
345
346 static INLINE boolean
347 nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map,
348 unsigned start, unsigned count)
349 {
350 struct nouveau_channel *chan = nv50->screen->tesla->channel;
351 struct nouveau_grobj *tesla = nv50->screen->tesla;
352
353 map += start;
354
355 if (count & 1) {
356 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
357 OUT_RING (chan, map[0]);
358 map++;
359 count--;
360 }
361
362 while (count) {
363 unsigned nr = count > 2046 ? 2046 : count;
364 int i;
365
366 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
367 for (i = 0; i < nr; i += 2)
368 OUT_RING (chan, (map[i + 1] << 16) | map[i]);
369
370 count -= nr;
371 map += nr;
372 }
373 return TRUE;
374 }
375
376 static INLINE boolean
377 nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map,
378 unsigned start, unsigned count)
379 {
380 struct nouveau_channel *chan = nv50->screen->tesla->channel;
381 struct nouveau_grobj *tesla = nv50->screen->tesla;
382
383 map += start;
384
385 if (count & 1) {
386 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32, 1);
387 OUT_RING (chan, map[0]);
388 map++;
389 count--;
390 }
391
392 while (count) {
393 unsigned nr = count > 2046 ? 2046 : count;
394 int i;
395
396 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U16, nr >> 1);
397 for (i = 0; i < nr; i += 2)
398 OUT_RING (chan, (map[i + 1] << 16) | map[i]);
399
400 count -= nr;
401 map += nr;
402 }
403 return TRUE;
404 }
405
406 static INLINE boolean
407 nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint32_t *map,
408 unsigned start, unsigned count)
409 {
410 struct nouveau_channel *chan = nv50->screen->tesla->channel;
411 struct nouveau_grobj *tesla = nv50->screen->tesla;
412
413 map += start;
414
415 while (count) {
416 unsigned nr = count > 2047 ? 2047 : count;
417
418 BEGIN_RING_NI(chan, tesla, NV50TCL_VB_ELEMENT_U32, nr);
419 OUT_RINGp (chan, map, nr);
420
421 count -= nr;
422 map += nr;
423 }
424 return TRUE;
425 }
426
427 static INLINE void
428 nv50_draw_elements_inline(struct nv50_context *nv50,
429 void *map, unsigned indexSize,
430 unsigned start, unsigned count)
431 {
432 switch (indexSize) {
433 case 1:
434 nv50_draw_elements_inline_u08(nv50, map, start, count);
435 break;
436 case 2:
437 nv50_draw_elements_inline_u16(nv50, map, start, count);
438 break;
439 case 4:
440 nv50_draw_elements_inline_u32(nv50, map, start, count);
441 break;
442 }
443 }
444
445 void
446 nv50_draw_elements_instanced(struct pipe_context *pipe,
447 struct pipe_buffer *indexBuffer,
448 unsigned indexSize,
449 unsigned mode, unsigned start, unsigned count,
450 unsigned startInstance, unsigned instanceCount)
451 {
452 struct nv50_context *nv50 = nv50_context(pipe);
453 struct nouveau_grobj *tesla = nv50->screen->tesla;
454 struct nouveau_channel *chan = tesla->channel;
455 struct pipe_screen *pscreen = pipe->screen;
456 void *map;
457 unsigned i, nz_divisors;
458 unsigned step[16], pos[16];
459
460 map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
461
462 if (!nv50_state_validate(nv50, 0))
463 return;
464 chan->flush_notify = nv50_state_flush_notify;
465
466 nz_divisors = init_per_instance_arrays(nv50, startInstance, pos, step);
467
468 BEGIN_RING(chan, tesla, NV50TCL_CB_ADDR, 2);
469 OUT_RING (chan, NV50_CB_AUX | (24 << 8));
470 OUT_RING (chan, startInstance);
471
472 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
473 OUT_RING (chan, nv50_prim(mode));
474
475 nv50_draw_elements_inline(nv50, map, indexSize, start, count);
476
477 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
478 OUT_RING (chan, 0);
479
480 for (i = 1; i < instanceCount; ++i) {
481 if (nz_divisors) /* any non-zero array divisors ? */
482 step_per_instance_arrays(nv50, pos, step);
483
484 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
485 OUT_RING (chan, nv50_prim(mode) | (1 << 28));
486
487 nv50_draw_elements_inline(nv50, map, indexSize, start, count);
488
489 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
490 OUT_RING (chan, 0);
491 }
492
493 chan->flush_notify = NULL;
494
495 so_ref(NULL, &nv50->state.instbuf);
496 }
497
498 void
499 nv50_draw_elements(struct pipe_context *pipe,
500 struct pipe_buffer *indexBuffer, unsigned indexSize,
501 unsigned mode, unsigned start, unsigned count)
502 {
503 struct nv50_context *nv50 = nv50_context(pipe);
504 struct nouveau_channel *chan = nv50->screen->tesla->channel;
505 struct nouveau_grobj *tesla = nv50->screen->tesla;
506 struct pipe_screen *pscreen = pipe->screen;
507 void *map;
508
509 if (!nv50_state_validate(nv50, 14))
510 return;
511 chan->flush_notify = nv50_state_flush_notify;
512
513 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
514 OUT_RING (chan, nv50_prim(mode));
515
516 if (indexSize == 4) {
517 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U32 | 0x30000, 0);
518 OUT_RING (chan, count);
519 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
520 start << 2, count << 2);
521 } else
522 if (indexSize == 2) {
523 unsigned vb_start = (start & ~1);
524 unsigned vb_end = (start + count + 1) & ~1;
525 unsigned dwords = (vb_end - vb_start) >> 1;
526
527 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
528 OUT_RING (chan, ((start & 1) << 31) | count);
529 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16 | 0x30000, 0);
530 OUT_RING (chan, dwords);
531 nouveau_pushbuf_submit(chan, nouveau_bo(indexBuffer),
532 vb_start << 1, dwords << 2);
533 BEGIN_RING(chan, tesla, NV50TCL_VB_ELEMENT_U16_SETUP, 1);
534 OUT_RING (chan, 0);
535 } else {
536 map = pipe_buffer_map(pscreen, indexBuffer,
537 PIPE_BUFFER_USAGE_CPU_READ);
538 nv50_draw_elements_inline(nv50, map, indexSize, start, count);
539 pipe_buffer_unmap(pscreen, indexBuffer);
540 }
541
542 BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
543 OUT_RING (chan, 0);
544 chan->flush_notify = NULL;
545 }
546
547 static INLINE boolean
548 nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
549 struct nouveau_stateobj **pso,
550 struct pipe_vertex_element *ve,
551 struct pipe_vertex_buffer *vb)
552
553 {
554 struct nouveau_stateobj *so;
555 struct nouveau_grobj *tesla = nv50->screen->tesla;
556 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
557 float v[4];
558 int ret;
559 unsigned nr_components = util_format_get_nr_components(ve->src_format);
560
561 ret = nouveau_bo_map(bo, NOUVEAU_BO_RD);
562 if (ret)
563 return FALSE;
564
565 util_format_read_4f(ve->src_format, v, 0, (uint8_t *)bo->map +
566 (vb->buffer_offset + ve->src_offset), 0,
567 0, 0, 1, 1);
568 so = *pso;
569 if (!so)
570 *pso = so = so_new(nv50->vtxelt->num_elements,
571 nv50->vtxelt->num_elements * 4, 0);
572
573 switch (nr_components) {
574 case 4:
575 so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4);
576 so_data (so, fui(v[0]));
577 so_data (so, fui(v[1]));
578 so_data (so, fui(v[2]));
579 so_data (so, fui(v[3]));
580 break;
581 case 3:
582 so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3);
583 so_data (so, fui(v[0]));
584 so_data (so, fui(v[1]));
585 so_data (so, fui(v[2]));
586 break;
587 case 2:
588 so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2);
589 so_data (so, fui(v[0]));
590 so_data (so, fui(v[1]));
591 break;
592 case 1:
593 if (attrib == nv50->vertprog->cfg.edgeflag_in) {
594 so_method(so, tesla, NV50TCL_EDGEFLAG_ENABLE, 1);
595 so_data (so, v[0] ? 1 : 0);
596 }
597 so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
598 so_data (so, fui(v[0]));
599 break;
600 default:
601 nouveau_bo_unmap(bo);
602 return FALSE;
603 }
604
605 nouveau_bo_unmap(bo);
606 return TRUE;
607 }
608
609 void
610 nv50_vtxelt_construct(struct nv50_vtxelt_stateobj *cso)
611 {
612 unsigned i;
613
614 for (i = 0; i < cso->num_elements; ++i) {
615 struct pipe_vertex_element *ve = &cso->pipe[i];
616
617 cso->hw[i] = nv50_vbo_vtxelt_to_hw(ve);
618 }
619 }
620
621 struct nouveau_stateobj *
622 nv50_vbo_validate(struct nv50_context *nv50)
623 {
624 struct nouveau_grobj *tesla = nv50->screen->tesla;
625 struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
626 unsigned i, n_ve;
627
628 /* don't validate if Gallium took away our buffers */
629 if (nv50->vtxbuf_nr == 0)
630 return NULL;
631
632 assert(!NV50_USING_LOATHED_EDGEFLAG(nv50));
633
634 n_ve = MAX2(nv50->vtxelt->num_elements, nv50->state.vtxelt_nr);
635
636 vtxattr = NULL;
637 vtxbuf = so_new(n_ve * 2, n_ve * 5, nv50->vtxelt->num_elements * 4);
638 vtxfmt = so_new(1, n_ve, 0);
639 so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
640
641 for (i = 0; i < nv50->vtxelt->num_elements; i++) {
642 struct pipe_vertex_element *ve = &nv50->vtxelt->pipe[i];
643 struct pipe_vertex_buffer *vb =
644 &nv50->vtxbuf[ve->vertex_buffer_index];
645 struct nouveau_bo *bo = nouveau_bo(vb->buffer);
646 uint32_t hw = nv50->vtxelt->hw[i];
647
648 if (!vb->stride &&
649 nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
650 so_data(vtxfmt, hw | (1 << 4));
651
652 so_method(vtxbuf, tesla,
653 NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
654 so_data (vtxbuf, 0);
655 continue;
656 }
657
658 so_data(vtxfmt, hw | i);
659
660 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
661 so_data (vtxbuf, 0x20000000 |
662 (ve->instance_divisor ? 0 : vb->stride));
663 so_reloc (vtxbuf, bo, vb->buffer_offset +
664 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
665 NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
666 so_reloc (vtxbuf, bo, vb->buffer_offset +
667 ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
668 NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
669
670 /* vertex array limits */
671 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_LIMIT_HIGH(i), 2);
672 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
673 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
674 NOUVEAU_BO_HIGH, 0, 0);
675 so_reloc (vtxbuf, bo, vb->buffer->size - 1,
676 NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
677 NOUVEAU_BO_LOW, 0, 0);
678 }
679 for (; i < n_ve; ++i) {
680 so_data (vtxfmt, 0x7e080010);
681
682 so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
683 so_data (vtxbuf, 0);
684 }
685 nv50->state.vtxelt_nr = nv50->vtxelt->num_elements;
686
687 so_ref (vtxbuf, &nv50->state.vtxbuf);
688 so_ref (vtxattr, &nv50->state.vtxattr);
689 so_ref (NULL, &vtxbuf);
690 so_ref (NULL, &vtxattr);
691 return vtxfmt;
692 }
693
694