nv50_vbo.c revision d29f55546dec74ca77dce3a3bf581c251be1d397
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 "pipe/p_inlines.h"
26
27#include "util/u_format.h"
28
29#include "nv50_context.h"
30
31static boolean
32nv50_push_elements_u08(struct nv50_context *, uint8_t *, unsigned);
33
34static boolean
35nv50_push_elements_u16(struct nv50_context *, uint16_t *, unsigned);
36
37static boolean
38nv50_push_elements_u32(struct nv50_context *, uint32_t *, unsigned);
39
40static boolean
41nv50_push_arrays(struct nv50_context *, unsigned, unsigned);
42
43static INLINE unsigned
44nv50_prim(unsigned mode)
45{
46	switch (mode) {
47	case PIPE_PRIM_POINTS: return NV50TCL_VERTEX_BEGIN_POINTS;
48	case PIPE_PRIM_LINES: return NV50TCL_VERTEX_BEGIN_LINES;
49	case PIPE_PRIM_LINE_LOOP: return NV50TCL_VERTEX_BEGIN_LINE_LOOP;
50	case PIPE_PRIM_LINE_STRIP: return NV50TCL_VERTEX_BEGIN_LINE_STRIP;
51	case PIPE_PRIM_TRIANGLES: return NV50TCL_VERTEX_BEGIN_TRIANGLES;
52	case PIPE_PRIM_TRIANGLE_STRIP:
53		return NV50TCL_VERTEX_BEGIN_TRIANGLE_STRIP;
54	case PIPE_PRIM_TRIANGLE_FAN: return NV50TCL_VERTEX_BEGIN_TRIANGLE_FAN;
55	case PIPE_PRIM_QUADS: return NV50TCL_VERTEX_BEGIN_QUADS;
56	case PIPE_PRIM_QUAD_STRIP: return NV50TCL_VERTEX_BEGIN_QUAD_STRIP;
57	case PIPE_PRIM_POLYGON: return NV50TCL_VERTEX_BEGIN_POLYGON;
58	default:
59		break;
60	}
61
62	NOUVEAU_ERR("invalid primitive type %d\n", mode);
63	return NV50TCL_VERTEX_BEGIN_POINTS;
64}
65
66static INLINE uint32_t
67nv50_vbo_type_to_hw(enum pipe_format format)
68{
69	const struct util_format_description *desc;
70
71	desc = util_format_description(format);
72	assert(desc);
73
74	switch (desc->channel[0].type) {
75	case UTIL_FORMAT_TYPE_FLOAT:
76		return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_FLOAT;
77	case UTIL_FORMAT_TYPE_UNSIGNED:
78		if (desc->channel[0].normalized) {
79			return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UNORM;
80		}
81		return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_USCALED;
82	case UTIL_FORMAT_TYPE_SIGNED:
83		if (desc->channel[0].normalized) {
84			return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SNORM;
85		}
86		return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SSCALED;
87	/*
88	case PIPE_FORMAT_TYPE_UINT:
89		return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_UINT;
90	case PIPE_FORMAT_TYPE_SINT:
91		return NV50TCL_VERTEX_ARRAY_ATTRIB_TYPE_SINT; */
92	default:
93		return 0;
94	}
95}
96
97static INLINE uint32_t
98nv50_vbo_size_to_hw(unsigned size, unsigned nr_c)
99{
100	static const uint32_t hw_values[] = {
101		0, 0, 0, 0,
102		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8,
103		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8,
104		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8_8,
105		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_8_8_8_8,
106		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16,
107		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16,
108		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16_16,
109		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_16_16_16_16,
110		0, 0, 0, 0,
111		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32,
112		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32,
113		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32_32,
114		NV50TCL_VERTEX_ARRAY_ATTRIB_SIZE_32_32_32_32 };
115
116	/* we'd also have R11G11B10 and R10G10B10A2 */
117
118	assert(nr_c > 0 && nr_c <= 4);
119
120	if (size > 32)
121		return 0;
122	size >>= (3 - 2);
123
124	return hw_values[size + (nr_c - 1)];
125}
126
127static INLINE uint32_t
128nv50_vbo_vtxelt_to_hw(struct pipe_vertex_element *ve)
129{
130	uint32_t hw_type, hw_size;
131	enum pipe_format pf = ve->src_format;
132	const struct util_format_description *desc;
133	unsigned size;
134
135	desc = util_format_description(pf);
136	assert(desc);
137
138	size = util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0);
139
140	hw_type = nv50_vbo_type_to_hw(pf);
141	hw_size = nv50_vbo_size_to_hw(size, ve->nr_components);
142
143	if (!hw_type || !hw_size) {
144		NOUVEAU_ERR("unsupported vbo format: %s\n", pf_name(pf));
145		abort();
146		return 0x24e80000;
147	}
148
149	if (desc->swizzle[0] == UTIL_FORMAT_SWIZZLE_Z) /* BGRA */
150		hw_size |= (1 << 31); /* no real swizzle bits :-( */
151
152	return (hw_type | hw_size);
153}
154
155boolean
156nv50_draw_arrays(struct pipe_context *pipe, unsigned mode, unsigned start,
157		 unsigned count)
158{
159	struct nv50_context *nv50 = nv50_context(pipe);
160	struct nouveau_channel *chan = nv50->screen->tesla->channel;
161	struct nouveau_grobj *tesla = nv50->screen->tesla;
162	boolean ret;
163
164	nv50_state_validate(nv50);
165
166	BEGIN_RING(chan, tesla, 0x142c, 1);
167	OUT_RING  (chan, 0);
168	BEGIN_RING(chan, tesla, 0x142c, 1);
169	OUT_RING  (chan, 0);
170
171	BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
172	OUT_RING  (chan, nv50_prim(mode));
173
174	if (nv50->vbo_fifo)
175		ret = nv50_push_arrays(nv50, start, count);
176	else {
177		BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BUFFER_FIRST, 2);
178		OUT_RING  (chan, start);
179		OUT_RING  (chan, count);
180		ret = TRUE;
181	}
182	BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
183	OUT_RING  (chan, 0);
184
185	return ret;
186}
187
188static INLINE boolean
189nv50_draw_elements_inline_u08(struct nv50_context *nv50, uint8_t *map,
190			      unsigned start, unsigned count)
191{
192	struct nouveau_channel *chan = nv50->screen->tesla->channel;
193	struct nouveau_grobj *tesla = nv50->screen->tesla;
194
195	map += start;
196
197	if (nv50->vbo_fifo)
198		return nv50_push_elements_u08(nv50, map, count);
199
200	if (count & 1) {
201		BEGIN_RING(chan, tesla, 0x15e8, 1);
202		OUT_RING  (chan, map[0]);
203		map++;
204		count--;
205	}
206
207	while (count) {
208		unsigned nr = count > 2046 ? 2046 : count;
209		int i;
210
211		BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1);
212		for (i = 0; i < nr; i += 2)
213			OUT_RING  (chan, (map[i + 1] << 16) | map[i]);
214
215		count -= nr;
216		map += nr;
217	}
218	return TRUE;
219}
220
221static INLINE boolean
222nv50_draw_elements_inline_u16(struct nv50_context *nv50, uint16_t *map,
223			      unsigned start, unsigned count)
224{
225	struct nouveau_channel *chan = nv50->screen->tesla->channel;
226	struct nouveau_grobj *tesla = nv50->screen->tesla;
227
228	map += start;
229
230	if (nv50->vbo_fifo)
231		return nv50_push_elements_u16(nv50, map, count);
232
233	if (count & 1) {
234		BEGIN_RING(chan, tesla, 0x15e8, 1);
235		OUT_RING  (chan, map[0]);
236		map++;
237		count--;
238	}
239
240	while (count) {
241		unsigned nr = count > 2046 ? 2046 : count;
242		int i;
243
244		BEGIN_RING(chan, tesla, 0x400015f0, nr >> 1);
245		for (i = 0; i < nr; i += 2)
246			OUT_RING  (chan, (map[i + 1] << 16) | map[i]);
247
248		count -= nr;
249		map += nr;
250	}
251	return TRUE;
252}
253
254static INLINE boolean
255nv50_draw_elements_inline_u32(struct nv50_context *nv50, uint32_t *map,
256			      unsigned start, unsigned count)
257{
258	struct nouveau_channel *chan = nv50->screen->tesla->channel;
259	struct nouveau_grobj *tesla = nv50->screen->tesla;
260
261	map += start;
262
263	if (nv50->vbo_fifo)
264		return nv50_push_elements_u32(nv50, map, count);
265
266	while (count) {
267		unsigned nr = count > 2047 ? 2047 : count;
268
269		BEGIN_RING(chan, tesla, 0x400015e8, nr);
270		OUT_RINGp (chan, map, nr);
271
272		count -= nr;
273		map += nr;
274	}
275	return TRUE;
276}
277
278boolean
279nv50_draw_elements(struct pipe_context *pipe,
280		   struct pipe_buffer *indexBuffer, unsigned indexSize,
281		   unsigned mode, unsigned start, unsigned count)
282{
283	struct nv50_context *nv50 = nv50_context(pipe);
284	struct nouveau_channel *chan = nv50->screen->tesla->channel;
285	struct nouveau_grobj *tesla = nv50->screen->tesla;
286	struct pipe_screen *pscreen = pipe->screen;
287	void *map;
288	boolean ret;
289
290	map = pipe_buffer_map(pscreen, indexBuffer, PIPE_BUFFER_USAGE_CPU_READ);
291
292	nv50_state_validate(nv50);
293
294	BEGIN_RING(chan, tesla, 0x142c, 1);
295	OUT_RING  (chan, 0);
296	BEGIN_RING(chan, tesla, 0x142c, 1);
297	OUT_RING  (chan, 0);
298
299	BEGIN_RING(chan, tesla, NV50TCL_VERTEX_BEGIN, 1);
300	OUT_RING  (chan, nv50_prim(mode));
301	switch (indexSize) {
302	case 1:
303		ret = nv50_draw_elements_inline_u08(nv50, map, start, count);
304		break;
305	case 2:
306		ret = nv50_draw_elements_inline_u16(nv50, map, start, count);
307		break;
308	case 4:
309		ret = nv50_draw_elements_inline_u32(nv50, map, start, count);
310		break;
311	default:
312		assert(0);
313		ret = FALSE;
314		break;
315	}
316	BEGIN_RING(chan, tesla, NV50TCL_VERTEX_END, 1);
317	OUT_RING  (chan, 0);
318
319	pipe_buffer_unmap(pscreen, indexBuffer);
320
321	return ret;
322}
323
324static INLINE boolean
325nv50_vbo_static_attrib(struct nv50_context *nv50, unsigned attrib,
326		       struct nouveau_stateobj **pso,
327		       struct pipe_vertex_element *ve,
328		       struct pipe_vertex_buffer *vb)
329
330{
331	struct nouveau_stateobj *so;
332	struct nouveau_grobj *tesla = nv50->screen->tesla;
333	struct nouveau_bo *bo = nouveau_bo(vb->buffer);
334	float *v;
335	int ret;
336	enum pipe_format pf = ve->src_format;
337	const struct util_format_description *desc;
338
339	desc = util_format_description(pf);
340	assert(desc);
341
342	if ((desc->channel[0].type != UTIL_FORMAT_TYPE_FLOAT) ||
343	    util_format_get_component_bits(pf, UTIL_FORMAT_COLORSPACE_RGB, 0) != 32)
344		return FALSE;
345
346	ret = nouveau_bo_map(bo, NOUVEAU_BO_RD);
347	if (ret)
348		return FALSE;
349	v = (float *)(bo->map + (vb->buffer_offset + ve->src_offset));
350
351	so = *pso;
352	if (!so)
353		*pso = so = so_new(nv50->vtxelt_nr * 5, 0);
354
355	switch (ve->nr_components) {
356	case 4:
357		so_method(so, tesla, NV50TCL_VTX_ATTR_4F_X(attrib), 4);
358		so_data  (so, fui(v[0]));
359		so_data  (so, fui(v[1]));
360		so_data  (so, fui(v[2]));
361		so_data  (so, fui(v[3]));
362		break;
363	case 3:
364		so_method(so, tesla, NV50TCL_VTX_ATTR_3F_X(attrib), 3);
365		so_data  (so, fui(v[0]));
366		so_data  (so, fui(v[1]));
367		so_data  (so, fui(v[2]));
368		break;
369	case 2:
370		so_method(so, tesla, NV50TCL_VTX_ATTR_2F_X(attrib), 2);
371		so_data  (so, fui(v[0]));
372		so_data  (so, fui(v[1]));
373		break;
374	case 1:
375		if (attrib == nv50->vertprog->cfg.edgeflag_in) {
376			so_method(so, tesla, 0x15e4, 1);
377			so_data  (so, v[0] ? 1 : 0);
378		}
379		so_method(so, tesla, NV50TCL_VTX_ATTR_1F(attrib), 1);
380		so_data  (so, fui(v[0]));
381		break;
382	default:
383		nouveau_bo_unmap(bo);
384		return FALSE;
385	}
386
387	nouveau_bo_unmap(bo);
388	return TRUE;
389}
390
391void
392nv50_vbo_validate(struct nv50_context *nv50)
393{
394	struct nouveau_grobj *tesla = nv50->screen->tesla;
395	struct nouveau_stateobj *vtxbuf, *vtxfmt, *vtxattr;
396	unsigned i, n_ve;
397
398	/* don't validate if Gallium took away our buffers */
399	if (nv50->vtxbuf_nr == 0)
400		return;
401	nv50->vbo_fifo = 0;
402
403	for (i = 0; i < nv50->vtxbuf_nr; ++i)
404		if (nv50->vtxbuf[i].stride &&
405		    !(nv50->vtxbuf[i].buffer->usage & PIPE_BUFFER_USAGE_VERTEX))
406			nv50->vbo_fifo = 0xffff;
407
408	if (nv50->vertprog->cfg.edgeflag_in < 16)
409		nv50->vbo_fifo = 0xffff; /* vertprog can't set edgeflag */
410
411	n_ve = MAX2(nv50->vtxelt_nr, nv50->state.vtxelt_nr);
412
413	vtxattr = NULL;
414	vtxbuf = so_new(n_ve * 7, nv50->vtxelt_nr * 4);
415	vtxfmt = so_new(n_ve + 1, 0);
416	so_method(vtxfmt, tesla, NV50TCL_VERTEX_ARRAY_ATTRIB(0), n_ve);
417
418	for (i = 0; i < nv50->vtxelt_nr; i++) {
419		struct pipe_vertex_element *ve = &nv50->vtxelt[i];
420		struct pipe_vertex_buffer *vb =
421			&nv50->vtxbuf[ve->vertex_buffer_index];
422		struct nouveau_bo *bo = nouveau_bo(vb->buffer);
423		uint32_t hw = nv50_vbo_vtxelt_to_hw(ve);
424
425		if (!vb->stride &&
426		    nv50_vbo_static_attrib(nv50, i, &vtxattr, ve, vb)) {
427			so_data(vtxfmt, hw | (1 << 4));
428
429			so_method(vtxbuf, tesla,
430				  NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
431			so_data  (vtxbuf, 0);
432
433			nv50->vbo_fifo &= ~(1 << i);
434			continue;
435		}
436		so_data(vtxfmt, hw | i);
437
438		if (nv50->vbo_fifo) {
439			so_method(vtxbuf, tesla,
440				  NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
441			so_data  (vtxbuf, 0);
442			continue;
443		}
444
445		so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 3);
446		so_data  (vtxbuf, 0x20000000 | vb->stride);
447		so_reloc (vtxbuf, bo, vb->buffer_offset +
448			  ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
449			  NOUVEAU_BO_RD | NOUVEAU_BO_HIGH, 0, 0);
450		so_reloc (vtxbuf, bo, vb->buffer_offset +
451			  ve->src_offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_GART |
452			  NOUVEAU_BO_RD | NOUVEAU_BO_LOW, 0, 0);
453
454		/* vertex array limits */
455		so_method(vtxbuf, tesla, 0x1080 + (i * 8), 2);
456		so_reloc (vtxbuf, bo, vb->buffer->size - 1,
457			  NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
458			  NOUVEAU_BO_HIGH, 0, 0);
459		so_reloc (vtxbuf, bo, vb->buffer->size - 1,
460			  NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD |
461			  NOUVEAU_BO_LOW, 0, 0);
462	}
463	for (; i < n_ve; ++i) {
464		so_data  (vtxfmt, 0x7e080010);
465
466		so_method(vtxbuf, tesla, NV50TCL_VERTEX_ARRAY_FORMAT(i), 1);
467		so_data  (vtxbuf, 0);
468	}
469	nv50->state.vtxelt_nr = nv50->vtxelt_nr;
470
471	so_ref (vtxfmt, &nv50->state.vtxfmt);
472	so_ref (vtxbuf, &nv50->state.vtxbuf);
473	so_ref (vtxattr, &nv50->state.vtxattr);
474	so_ref (NULL, &vtxbuf);
475	so_ref (NULL, &vtxfmt);
476	so_ref (NULL, &vtxattr);
477}
478
479typedef void (*pfn_push)(struct nouveau_channel *, void *);
480
481struct nv50_vbo_emitctx
482{
483	pfn_push push[16];
484	void *map[16];
485	unsigned stride[16];
486	unsigned nr_ve;
487	unsigned vtx_dwords;
488	unsigned vtx_max;
489
490	float edgeflag;
491	unsigned ve_edgeflag;
492};
493
494static INLINE void
495emit_vtx_next(struct nouveau_channel *chan, struct nv50_vbo_emitctx *emit)
496{
497	unsigned i;
498
499	for (i = 0; i < emit->nr_ve; ++i) {
500		emit->push[i](chan, emit->map[i]);
501		emit->map[i] += emit->stride[i];
502	}
503}
504
505static INLINE void
506emit_vtx(struct nouveau_channel *chan, struct nv50_vbo_emitctx *emit,
507	 uint32_t vi)
508{
509	unsigned i;
510
511	for (i = 0; i < emit->nr_ve; ++i)
512		emit->push[i](chan, emit->map[i] + emit->stride[i] * vi);
513}
514
515static INLINE boolean
516nv50_map_vbufs(struct nv50_context *nv50)
517{
518	int i;
519
520	for (i = 0; i < nv50->vtxbuf_nr; ++i) {
521		struct pipe_vertex_buffer *vb = &nv50->vtxbuf[i];
522		unsigned size, delta;
523
524		if (nouveau_bo(vb->buffer)->map)
525			continue;
526
527		size = vb->stride * (vb->max_index + 1);
528		delta = vb->buffer_offset;
529
530		if (!size)
531			size = vb->buffer->size - vb->buffer_offset;
532
533		if (nouveau_bo_map_range(nouveau_bo(vb->buffer),
534					 delta, size, NOUVEAU_BO_RD))
535			break;
536	}
537
538	if (i == nv50->vtxbuf_nr)
539		return TRUE;
540	for (; i >= 0; --i)
541		nouveau_bo_unmap(nouveau_bo(nv50->vtxbuf[i].buffer));
542	return FALSE;
543}
544
545static INLINE void
546nv50_unmap_vbufs(struct nv50_context *nv50)
547{
548        unsigned i;
549
550        for (i = 0; i < nv50->vtxbuf_nr; ++i)
551                if (nouveau_bo(nv50->vtxbuf[i].buffer)->map)
552                        nouveau_bo_unmap(nouveau_bo(nv50->vtxbuf[i].buffer));
553}
554
555static void
556emit_b32_1(struct nouveau_channel *chan, void *data)
557{
558	uint32_t *v = data;
559
560	OUT_RING(chan, v[0]);
561}
562
563static void
564emit_b32_2(struct nouveau_channel *chan, void *data)
565{
566	uint32_t *v = data;
567
568	OUT_RING(chan, v[0]);
569	OUT_RING(chan, v[1]);
570}
571
572static void
573emit_b32_3(struct nouveau_channel *chan, void *data)
574{
575	uint32_t *v = data;
576
577	OUT_RING(chan, v[0]);
578	OUT_RING(chan, v[1]);
579	OUT_RING(chan, v[2]);
580}
581
582static void
583emit_b32_4(struct nouveau_channel *chan, void *data)
584{
585	uint32_t *v = data;
586
587	OUT_RING(chan, v[0]);
588	OUT_RING(chan, v[1]);
589	OUT_RING(chan, v[2]);
590	OUT_RING(chan, v[3]);
591}
592
593static void
594emit_b16_1(struct nouveau_channel *chan, void *data)
595{
596	uint16_t *v = data;
597
598	OUT_RING(chan, v[0]);
599}
600
601static void
602emit_b16_3(struct nouveau_channel *chan, void *data)
603{
604	uint16_t *v = data;
605
606	OUT_RING(chan, (v[1] << 16) | v[0]);
607	OUT_RING(chan, v[2]);
608}
609
610static void
611emit_b08_1(struct nouveau_channel *chan, void *data)
612{
613	uint8_t *v = data;
614
615	OUT_RING(chan, v[0]);
616}
617
618static void
619emit_b08_3(struct nouveau_channel *chan, void *data)
620{
621	uint8_t *v = data;
622
623	OUT_RING(chan, (v[2] << 16) | (v[1] << 8) | v[0]);
624}
625
626static boolean
627emit_prepare(struct nv50_context *nv50, struct nv50_vbo_emitctx *emit,
628	     unsigned start)
629{
630	unsigned i;
631
632	if (nv50_map_vbufs(nv50) == FALSE)
633		return FALSE;
634
635	emit->ve_edgeflag = nv50->vertprog->cfg.edgeflag_in;
636
637	emit->edgeflag = 0.5f;
638	emit->nr_ve = 0;
639	emit->vtx_dwords = 0;
640
641	for (i = 0; i < nv50->vtxelt_nr; ++i) {
642		struct pipe_vertex_element *ve;
643		struct pipe_vertex_buffer *vb;
644		unsigned n, size;
645		const struct util_format_description *desc;
646
647		ve = &nv50->vtxelt[i];
648		vb = &nv50->vtxbuf[ve->vertex_buffer_index];
649		if (!(nv50->vbo_fifo & (1 << i)))
650			continue;
651		n = emit->nr_ve++;
652
653		emit->stride[n] = vb->stride;
654		emit->map[n] = nouveau_bo(vb->buffer)->map +
655			(start * vb->stride + ve->src_offset);
656
657		desc = util_format_description(ve->src_format);
658		assert(desc);
659
660		size = util_format_get_component_bits(
661			ve->src_format, UTIL_FORMAT_COLORSPACE_RGB, 0);
662
663		assert(ve->nr_components > 0 && ve->nr_components <= 4);
664
665		/* It shouldn't be necessary to push the implicit 1s
666		 * for case 3 and size 8 cases 1, 2, 3.
667		 */
668		switch (size) {
669		default:
670			NOUVEAU_ERR("unsupported vtxelt size: %u\n", size);
671			return FALSE;
672		case 32:
673			switch (ve->nr_components) {
674			case 1: emit->push[n] = emit_b32_1; break;
675			case 2: emit->push[n] = emit_b32_2; break;
676			case 3: emit->push[n] = emit_b32_3; break;
677			case 4: emit->push[n] = emit_b32_4; break;
678			}
679			emit->vtx_dwords += ve->nr_components;
680			break;
681		case 16:
682			switch (ve->nr_components) {
683			case 1: emit->push[n] = emit_b16_1; break;
684			case 2: emit->push[n] = emit_b32_1; break;
685			case 3: emit->push[n] = emit_b16_3; break;
686			case 4: emit->push[n] = emit_b32_2; break;
687			}
688			emit->vtx_dwords += (ve->nr_components + 1) >> 1;
689			break;
690		case 8:
691			switch (ve->nr_components) {
692			case 1: emit->push[n] = emit_b08_1; break;
693			case 2: emit->push[n] = emit_b16_1; break;
694			case 3: emit->push[n] = emit_b08_3; break;
695			case 4: emit->push[n] = emit_b32_1; break;
696			}
697			emit->vtx_dwords += 1;
698			break;
699		}
700	}
701
702	emit->vtx_max = 512 / emit->vtx_dwords;
703	if (emit->ve_edgeflag < 16)
704		emit->vtx_max = 1;
705
706	return TRUE;
707}
708
709static INLINE void
710set_edgeflag(struct nouveau_channel *chan,
711	     struct nouveau_grobj *tesla,
712	     struct nv50_vbo_emitctx *emit, uint32_t index)
713{
714	unsigned i = emit->ve_edgeflag;
715
716	if (i < 16) {
717		float f = *((float *)(emit->map[i] + index * emit->stride[i]));
718
719		if (emit->edgeflag != f) {
720			emit->edgeflag = f;
721
722			BEGIN_RING(chan, tesla, 0x15e4, 1);
723			OUT_RING  (chan, f ? 1 : 0);
724		}
725	}
726}
727
728static boolean
729nv50_push_arrays(struct nv50_context *nv50, unsigned start, unsigned count)
730{
731	struct nouveau_channel *chan = nv50->screen->base.channel;
732	struct nouveau_grobj *tesla = nv50->screen->tesla;
733	struct nv50_vbo_emitctx emit;
734
735	if (emit_prepare(nv50, &emit, start) == FALSE)
736		return FALSE;
737
738	while (count) {
739		unsigned i, dw, nr = MIN2(count, emit.vtx_max);
740	        dw = nr * emit.vtx_dwords;
741
742		set_edgeflag(chan, tesla, &emit, 0); /* nr will be 1 */
743
744		BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
745		for (i = 0; i < nr; ++i)
746			emit_vtx_next(chan, &emit);
747
748		count -= nr;
749	}
750	nv50_unmap_vbufs(nv50);
751
752	return TRUE;
753}
754
755static boolean
756nv50_push_elements_u32(struct nv50_context *nv50, uint32_t *map, unsigned count)
757{
758	struct nouveau_channel *chan = nv50->screen->base.channel;
759	struct nouveau_grobj *tesla = nv50->screen->tesla;
760	struct nv50_vbo_emitctx emit;
761
762	if (emit_prepare(nv50, &emit, 0) == FALSE)
763		return FALSE;
764
765	while (count) {
766		unsigned i, dw, nr = MIN2(count, emit.vtx_max);
767	        dw = nr * emit.vtx_dwords;
768
769		set_edgeflag(chan, tesla, &emit, *map);
770
771		BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
772		for (i = 0; i < nr; ++i)
773			emit_vtx(chan, &emit, *map++);
774
775		count -= nr;
776	}
777	nv50_unmap_vbufs(nv50);
778
779	return TRUE;
780}
781
782static boolean
783nv50_push_elements_u16(struct nv50_context *nv50, uint16_t *map, unsigned count)
784{
785	struct nouveau_channel *chan = nv50->screen->base.channel;
786	struct nouveau_grobj *tesla = nv50->screen->tesla;
787	struct nv50_vbo_emitctx emit;
788
789	if (emit_prepare(nv50, &emit, 0) == FALSE)
790		return FALSE;
791
792	while (count) {
793		unsigned i, dw, nr = MIN2(count, emit.vtx_max);
794	        dw = nr * emit.vtx_dwords;
795
796		set_edgeflag(chan, tesla, &emit, *map);
797
798		BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
799		for (i = 0; i < nr; ++i)
800			emit_vtx(chan, &emit, *map++);
801
802		count -= nr;
803	}
804	nv50_unmap_vbufs(nv50);
805
806	return TRUE;
807}
808
809static boolean
810nv50_push_elements_u08(struct nv50_context *nv50, uint8_t *map, unsigned count)
811{
812	struct nouveau_channel *chan = nv50->screen->base.channel;
813	struct nouveau_grobj *tesla = nv50->screen->tesla;
814	struct nv50_vbo_emitctx emit;
815
816	if (emit_prepare(nv50, &emit, 0) == FALSE)
817		return FALSE;
818
819	while (count) {
820		unsigned i, dw, nr = MIN2(count, emit.vtx_max);
821	        dw = nr * emit.vtx_dwords;
822
823		set_edgeflag(chan, tesla, &emit, *map);
824
825		BEGIN_RING(chan, tesla, NV50TCL_VERTEX_DATA | 0x40000000, dw);
826		for (i = 0; i < nr; ++i)
827			emit_vtx(chan, &emit, *map++);
828
829		count -= nr;
830	}
831	nv50_unmap_vbufs(nv50);
832
833	return TRUE;
834}
835