nv30_vbo.c revision f302fca5eb63e4bca8af5b35c585451486143e6a
1#include "pipe/p_context.h"
2#include "pipe/p_state.h"
3
4#include "nv30_context.h"
5#include "nv30_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
13static INLINE int
14nv30_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 = NV34TCL_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 = NV34TCL_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 = NV34TCL_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
69static boolean
70nv30_vbo_set_idxbuf(struct nv30_context *nv30, struct pipe_buffer *ib,
71		    unsigned ib_size)
72{
73	struct pipe_screen *pscreen = &nv30->screen->pipe;
74	unsigned type;
75
76	if (!ib) {
77		nv30->idxbuf = NULL;
78		nv30->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 = NV34TCL_IDXBUF_FORMAT_TYPE_U16;
88		break;
89	case 4:
90		type = NV34TCL_IDXBUF_FORMAT_TYPE_U32;
91		break;
92	default:
93		return FALSE;
94	}
95
96	if (ib != nv30->idxbuf ||
97	    type != nv30->idxbuf_format) {
98		nv30->dirty |= NV30_NEW_ARRAYS;
99		nv30->idxbuf = ib;
100		nv30->idxbuf_format = type;
101	}
102
103	return TRUE;
104}
105
106static boolean
107nv30_vbo_static_attrib(struct nv30_context *nv30, struct nouveau_stateobj *so,
108		       int attrib, struct pipe_vertex_element *ve,
109		       struct pipe_vertex_buffer *vb)
110{
111	struct pipe_winsys *ws = nv30->pipe.winsys;
112	struct nouveau_grobj *rankine = nv30->screen->rankine;
113	unsigned type, ncomp;
114	void *map;
115
116	if (nv30_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 NV34TCL_VTXFMT_TYPE_FLOAT:
124	{
125		float *v = map;
126
127		switch (ncomp) {
128		case 4:
129			so_method(so, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_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, rankine, NV34TCL_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
166boolean
167nv30_draw_arrays(struct pipe_context *pipe,
168		 unsigned mode, unsigned start, unsigned count)
169{
170	struct nv30_context *nv30 = nv30_context(pipe);
171	struct nouveau_channel *chan = nv30->nvws->channel;
172	unsigned restart = 0;
173
174	nv30_vbo_set_idxbuf(nv30, NULL, 0);
175	if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
176		/*return nv30_draw_elements_swtnl(pipe, NULL, 0,
177						mode, start, count);*/
178		return FALSE;
179	}
180
181	while (count) {
182		unsigned vc, nr;
183
184		nv30_state_emit(nv30);
185
186		vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
187					mode, start, count, &restart);
188		if (!vc) {
189			FIRE_RING(NULL);
190			continue;
191		}
192
193		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
194		OUT_RING  (nvgl_primitive(mode));
195
196		nr = (vc & 0xff);
197		if (nr) {
198			BEGIN_RING(rankine, NV34TCL_VB_VERTEX_BATCH, 1);
199			OUT_RING  (((nr - 1) << 24) | start);
200			start += nr;
201		}
202
203		nr = vc >> 8;
204		while (nr) {
205			unsigned push = nr > 2047 ? 2047 : nr;
206
207			nr -= push;
208
209			BEGIN_RING_NI(rankine, NV34TCL_VB_VERTEX_BATCH, push);
210			while (push--) {
211				OUT_RING(((0x100 - 1) << 24) | start);
212				start += 0x100;
213			}
214		}
215
216		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
217		OUT_RING  (0);
218
219		count -= vc;
220		start = restart;
221	}
222
223	pipe->flush(pipe, 0, NULL);
224	return TRUE;
225}
226
227static INLINE void
228nv30_draw_elements_u08(struct nv30_context *nv30, void *ib,
229		       unsigned mode, unsigned start, unsigned count)
230{
231	struct nouveau_channel *chan = nv30->nvws->channel;
232
233	while (count) {
234		uint8_t *elts = (uint8_t *)ib + start;
235		unsigned vc, push, restart = 0;
236
237		nv30_state_emit(nv30);
238
239		vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
240					mode, start, count, &restart);
241		if (vc == 0) {
242			FIRE_RING(NULL);
243			continue;
244		}
245		count -= vc;
246
247		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
248		OUT_RING  (nvgl_primitive(mode));
249
250		if (vc & 1) {
251			BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
252			OUT_RING  (elts[0]);
253			elts++; vc--;
254		}
255
256		while (vc) {
257			unsigned i;
258
259			push = MIN2(vc, 2047 * 2);
260
261			BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
262			for (i = 0; i < push; i+=2)
263				OUT_RING((elts[i+1] << 16) | elts[i]);
264
265			vc -= push;
266			elts += push;
267		}
268
269		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
270		OUT_RING  (0);
271
272		start = restart;
273	}
274}
275
276static INLINE void
277nv30_draw_elements_u16(struct nv30_context *nv30, void *ib,
278		       unsigned mode, unsigned start, unsigned count)
279{
280	struct nouveau_channel *chan = nv30->nvws->channel;
281
282	while (count) {
283		uint16_t *elts = (uint16_t *)ib + start;
284		unsigned vc, push, restart = 0;
285
286		nv30_state_emit(nv30);
287
288		vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 2,
289					mode, start, count, &restart);
290		if (vc == 0) {
291			FIRE_RING(NULL);
292			continue;
293		}
294		count -= vc;
295
296		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
297		OUT_RING  (nvgl_primitive(mode));
298
299		if (vc & 1) {
300			BEGIN_RING(rankine, NV34TCL_VB_ELEMENT_U32, 1);
301			OUT_RING  (elts[0]);
302			elts++; vc--;
303		}
304
305		while (vc) {
306			unsigned i;
307
308			push = MIN2(vc, 2047 * 2);
309
310			BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U16, push >> 1);
311			for (i = 0; i < push; i+=2)
312				OUT_RING((elts[i+1] << 16) | elts[i]);
313
314			vc -= push;
315			elts += push;
316		}
317
318		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
319		OUT_RING  (0);
320
321		start = restart;
322	}
323}
324
325static INLINE void
326nv30_draw_elements_u32(struct nv30_context *nv30, void *ib,
327		       unsigned mode, unsigned start, unsigned count)
328{
329	struct nouveau_channel *chan = nv30->nvws->channel;
330
331	while (count) {
332		uint32_t *elts = (uint32_t *)ib + start;
333		unsigned vc, push, restart = 0;
334
335		nv30_state_emit(nv30);
336
337		vc = nouveau_vbuf_split(chan->pushbuf->remaining, 5, 1,
338					mode, start, count, &restart);
339		if (vc == 0) {
340			FIRE_RING(NULL);
341			continue;
342		}
343		count -= vc;
344
345		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
346		OUT_RING  (nvgl_primitive(mode));
347
348		while (vc) {
349			push = MIN2(vc, 2047);
350
351			BEGIN_RING_NI(rankine, NV34TCL_VB_ELEMENT_U32, push);
352			OUT_RINGp    (elts, push);
353
354			vc -= push;
355			elts += push;
356		}
357
358		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
359		OUT_RING  (0);
360
361		start = restart;
362	}
363}
364
365static boolean
366nv30_draw_elements_inline(struct pipe_context *pipe,
367			  struct pipe_buffer *ib, unsigned ib_size,
368			  unsigned mode, unsigned start, unsigned count)
369{
370	struct nv30_context *nv30 = nv30_context(pipe);
371	struct pipe_winsys *ws = pipe->winsys;
372	void *map;
373
374	map = ws->buffer_map(ws, ib, PIPE_BUFFER_USAGE_CPU_READ);
375	if (!ib) {
376		NOUVEAU_ERR("failed mapping ib\n");
377		return FALSE;
378	}
379
380	switch (ib_size) {
381	case 1:
382		nv30_draw_elements_u08(nv30, map, mode, start, count);
383		break;
384	case 2:
385		nv30_draw_elements_u16(nv30, map, mode, start, count);
386		break;
387	case 4:
388		nv30_draw_elements_u32(nv30, map, mode, start, count);
389		break;
390	default:
391		NOUVEAU_ERR("invalid idxbuf fmt %d\n", ib_size);
392		break;
393	}
394
395	ws->buffer_unmap(ws, ib);
396	return TRUE;
397}
398
399static boolean
400nv30_draw_elements_vbo(struct pipe_context *pipe,
401		       unsigned mode, unsigned start, unsigned count)
402{
403	struct nv30_context *nv30 = nv30_context(pipe);
404	struct nouveau_channel *chan = nv30->nvws->channel;
405	unsigned restart = 0;
406
407	while (count) {
408		unsigned nr, vc;
409
410		nv30_state_emit(nv30);
411
412		vc = nouveau_vbuf_split(chan->pushbuf->remaining, 6, 256,
413					mode, start, count, &restart);
414		if (!vc) {
415			FIRE_RING(NULL);
416			continue;
417		}
418
419		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
420		OUT_RING  (nvgl_primitive(mode));
421
422		nr = (vc & 0xff);
423		if (nr) {
424			BEGIN_RING(rankine, NV34TCL_VB_INDEX_BATCH, 1);
425			OUT_RING  (((nr - 1) << 24) | start);
426			start += nr;
427		}
428
429		nr = vc >> 8;
430		while (nr) {
431			unsigned push = nr > 2047 ? 2047 : nr;
432
433			nr -= push;
434
435			BEGIN_RING_NI(rankine, NV34TCL_VB_INDEX_BATCH, push);
436			while (push--) {
437				OUT_RING(((0x100 - 1) << 24) | start);
438				start += 0x100;
439			}
440		}
441
442		BEGIN_RING(rankine, NV34TCL_VERTEX_BEGIN_END, 1);
443		OUT_RING  (0);
444
445		count -= vc;
446		start = restart;
447	}
448
449	return TRUE;
450}
451
452boolean
453nv30_draw_elements(struct pipe_context *pipe,
454		   struct pipe_buffer *indexBuffer, unsigned indexSize,
455		   unsigned mode, unsigned start, unsigned count)
456{
457	struct nv30_context *nv30 = nv30_context(pipe);
458	boolean idxbuf;
459
460	idxbuf = nv30_vbo_set_idxbuf(nv30, indexBuffer, indexSize);
461	if (FORCE_SWTNL || !nv30_state_validate(nv30)) {
462		/*return nv30_draw_elements_swtnl(pipe, NULL, 0,
463						mode, start, count);*/
464		return FALSE;
465	}
466
467	if (idxbuf) {
468		nv30_draw_elements_vbo(pipe, mode, start, count);
469	} else {
470		nv30_draw_elements_inline(pipe, indexBuffer, indexSize,
471					  mode, start, count);
472	}
473
474	pipe->flush(pipe, 0, NULL);
475	return TRUE;
476}
477
478static boolean
479nv30_vbo_validate(struct nv30_context *nv30)
480{
481	struct nouveau_stateobj *vtxbuf, *vtxfmt, *sattr = NULL;
482	struct nouveau_grobj *rankine = nv30->screen->rankine;
483	struct pipe_buffer *ib = nv30->idxbuf;
484	unsigned ib_format = nv30->idxbuf_format;
485	unsigned vb_flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
486	int hw;
487
488	if (nv30->edgeflags) {
489		/*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
490		return FALSE;
491	}
492
493	vtxbuf = so_new(20, 18);
494	so_method(vtxbuf, rankine, NV34TCL_VTXBUF_ADDRESS(0), nv30->vtxelt_nr);
495	vtxfmt = so_new(17, 0);
496	so_method(vtxfmt, rankine, NV34TCL_VTXFMT(0), nv30->vtxelt_nr);
497
498	for (hw = 0; hw < nv30->vtxelt_nr; hw++) {
499		struct pipe_vertex_element *ve;
500		struct pipe_vertex_buffer *vb;
501		unsigned type, ncomp;
502
503		ve = &nv30->vtxelt[hw];
504		vb = &nv30->vtxbuf[ve->vertex_buffer_index];
505
506		if (!vb->pitch) {
507			if (!sattr)
508				sattr = so_new(16 * 5, 0);
509
510			if (nv30_vbo_static_attrib(nv30, sattr, hw, ve, vb)) {
511				so_data(vtxbuf, 0);
512				so_data(vtxfmt, NV34TCL_VTXFMT_TYPE_FLOAT);
513				continue;
514			}
515		}
516
517		if (nv30_vbo_format_to_hw(ve->src_format, &type, &ncomp)) {
518			/*nv30->fallback_swtnl |= NV30_NEW_ARRAYS;*/
519			so_ref(NULL, &vtxbuf);
520			so_ref(NULL, &vtxfmt);
521			return FALSE;
522		}
523
524		so_reloc(vtxbuf, vb->buffer, vb->buffer_offset + ve->src_offset,
525			 vb_flags | NOUVEAU_BO_LOW | NOUVEAU_BO_OR,
526			 0, NV34TCL_VTXBUF_ADDRESS_DMA1);
527		so_data (vtxfmt, ((vb->pitch << NV34TCL_VTXFMT_STRIDE_SHIFT) |
528				  (ncomp << NV34TCL_VTXFMT_SIZE_SHIFT) | type));
529	}
530
531	if (ib) {
532		so_method(vtxbuf, rankine, NV34TCL_IDXBUF_ADDRESS, 2);
533		so_reloc (vtxbuf, ib, 0, vb_flags | NOUVEAU_BO_LOW, 0, 0);
534		so_reloc (vtxbuf, ib, ib_format, vb_flags | NOUVEAU_BO_OR,
535			  0, NV34TCL_IDXBUF_FORMAT_DMA1);
536	}
537
538	so_method(vtxbuf, rankine, 0x1710, 1);
539	so_data  (vtxbuf, 0);
540
541	so_ref(vtxbuf, &nv30->state.hw[NV30_STATE_VTXBUF]);
542	nv30->state.dirty |= (1ULL << NV30_STATE_VTXBUF);
543	so_ref(vtxfmt, &nv30->state.hw[NV30_STATE_VTXFMT]);
544	nv30->state.dirty |= (1ULL << NV30_STATE_VTXFMT);
545	so_ref(sattr, &nv30->state.hw[NV30_STATE_VTXATTR]);
546	nv30->state.dirty |= (1ULL << NV30_STATE_VTXATTR);
547	return FALSE;
548}
549
550struct nv30_state_entry nv30_state_vbo = {
551	.validate = nv30_vbo_validate,
552	.dirty = {
553		.pipe = NV30_NEW_ARRAYS,
554		.hw = 0,
555	}
556};
557