1/*
2 * Copyright 2007 Stephane Marchesin
3 * Copyright 2007 Arthur Huillet
4 * Copyright 2007 Peter Winters
5 * Copyright 2009 Francisco Jerez
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "nv_include.h"
31
32#include "hwdefs/nv_object.xml.h"
33#include "hwdefs/nv10_3d.xml.h"
34#include "nv04_accel.h"
35
36/* Texture/Render target formats. */
37static struct pict_format {
38	int exa;
39	int hw;
40} nv10_tex_format_pot[] = {
41	{ PICT_a8,       0x80  },
42	{ PICT_r5g6b5,	 0x280 },
43	{ PICT_x8r8g8b8, 0x300 },
44	{ PICT_a8r8g8b8, 0x300 },
45	{},
46
47}, nv10_tex_format_rect[] = {
48	{ PICT_a8,       0x980 },
49	{ PICT_r5g6b5,   0x880 },
50	{ PICT_x8r8g8b8, 0x900 },
51	{ PICT_a8r8g8b8, 0x900 },
52	{},
53
54}, nv20_tex_format_rect[] = {
55	{ PICT_a8,	 0xd80 },
56	{ PICT_r5g6b5,   0x880 },
57	{ PICT_x8r8g8b8, 0x900 },
58	{ PICT_a8r8g8b8, 0x900 },
59	{},
60
61}, nv10_rt_format[] = {
62	{ PICT_r5g6b5,	 0x103 },
63	{ PICT_x8r8g8b8, 0x108 },
64	{ PICT_a8r8g8b8, 0x108 },
65	{},
66};
67
68static int
69get_tex_format(NVPtr pNv, PicturePtr pict)
70{
71	/* If repeat is set we're always handling a 1x1 texture with
72	 * ARGB/XRGB destination, in that case we change the format to
73	 * use the POT (swizzled) matching format.
74	 */
75	struct pict_format *format =
76		pict->repeat != RepeatNone ? nv10_tex_format_pot :
77		pNv->Architecture == NV_ARCH_20 ? nv20_tex_format_rect :
78		nv10_tex_format_rect;
79
80	for (; format->hw; format++) {
81		if (format->exa == pict->format)
82			return format->hw;
83	}
84
85	return 0;
86}
87
88static int
89get_rt_format(PicturePtr pict)
90{
91	struct pict_format *format = nv10_rt_format;
92
93	for (; format->hw; format++) {
94		if (format->exa == pict->format)
95			return format->hw;
96	}
97
98	return 0;
99}
100
101/* Blending functions. */
102#define SF(x) NV10_3D_BLEND_FUNC_SRC_##x
103#define DF(x) NV10_3D_BLEND_FUNC_DST_##x
104
105static struct pict_op {
106	int src;
107	int dst;
108
109} nv10_pict_op[] = {
110	{ SF(ZERO),		   DF(ZERO) },		      /* Clear */
111	{ SF(ONE),		   DF(ZERO) },		      /* Src */
112	{ SF(ZERO),		   DF(ONE) },		      /* Dst */
113	{ SF(ONE),		   DF(ONE_MINUS_SRC_ALPHA) }, /* Over */
114	{ SF(ONE_MINUS_DST_ALPHA), DF(ONE) },		      /* OverReverse */
115	{ SF(DST_ALPHA),	   DF(ZERO) },                /* In */
116	{ SF(ZERO),		   DF(SRC_ALPHA) },           /* InReverse */
117	{ SF(ONE_MINUS_DST_ALPHA), DF(ZERO) },		      /* Out */
118	{ SF(ZERO),		   DF(ONE_MINUS_SRC_ALPHA) }, /* OutReverse */
119	{ SF(DST_ALPHA),	   DF(ONE_MINUS_SRC_ALPHA) }, /* Atop */
120	{ SF(ONE_MINUS_DST_ALPHA), DF(SRC_ALPHA) },	      /* AtopReverse */
121	{ SF(ONE_MINUS_DST_ALPHA), DF(ONE_MINUS_SRC_ALPHA) }, /* Xor */
122	{ SF(ONE),		   DF(ONE) },		      /* Add */
123};
124
125static inline Bool
126needs_src_alpha(int op)
127{
128	return nv10_pict_op[op].dst == DF(ONE_MINUS_SRC_ALPHA)
129		|| nv10_pict_op[op].dst == DF(SRC_ALPHA);
130}
131
132static inline Bool
133needs_src(int op)
134{
135	return nv10_pict_op[op].src != SF(ZERO);
136}
137
138static inline Bool
139effective_component_alpha(PicturePtr mask)
140{
141	return mask && mask->componentAlpha && PICT_FORMAT_RGB(mask->format);
142}
143
144static Bool
145check_texture(NVPtr pNv, PicturePtr pict)
146{
147	int w = 1, h = 1;
148
149	if (pict->pDrawable) {
150		w = pict->pDrawable->width;
151		h = pict->pDrawable->height;
152	} else {
153		if (pict->pSourcePict->type != SourcePictTypeSolidFill)
154			NOUVEAU_FALLBACK("gradient pictures unsupported\n");
155	}
156
157	if (w > 2046 || h > 2046)
158		NOUVEAU_FALLBACK("picture too large, %dx%d\n", w, h);
159
160	if (!get_tex_format(pNv, pict))
161		return FALSE;
162
163	if (pict->filter != PictFilterNearest &&
164	    pict->filter != PictFilterBilinear)
165		return FALSE;
166
167	/* We cannot repeat on NV10 because NPOT textures do not
168	 * support this. unfortunately. */
169	if (pict->repeat != RepeatNone)
170		/* we can repeat 1x1 textures */
171		if (!(w == 1 && h == 1))
172			return FALSE;
173
174	return TRUE;
175}
176
177static Bool
178check_render_target(PicturePtr pict)
179{
180	int w = pict->pDrawable->width;
181	int h = pict->pDrawable->height;
182
183	if (w > 4096 || h > 4096)
184		return FALSE;
185
186	if (!get_rt_format(pict))
187		return FALSE;
188
189	return TRUE;
190}
191
192static Bool
193check_pict_op(int op)
194{
195	/* We do no saturate, disjoint, conjoint, though we
196	 * could do e.g. DisjointClear which really is
197	 * Clear. */
198	return op < PictOpSaturate;
199}
200
201#if 0
202static void
203print_fallback_info(char *reason, int op, PicturePtr src, PicturePtr mask,
204		    PicturePtr dst)
205{
206	char out2[4096];
207	char *out = out2;
208
209	sprintf(out, "%s  ", reason);
210	out += strlen(out);
211
212	switch (op) {
213	case PictOpClear:
214		sprintf(out, "PictOpClear ");
215		break;
216	case PictOpSrc:
217		sprintf(out, "PictOpSrc ");
218		break;
219	case PictOpDst:
220		sprintf(out, "PictOpDst ");
221		break;
222	case PictOpOver:
223		sprintf(out, "PictOpOver ");
224		break;
225	case PictOpOutReverse:
226		sprintf(out, "PictOpOutReverse ");
227		break;
228	case PictOpAdd:
229		sprintf(out, "PictOpAdd ");
230		break;
231	default:
232		sprintf(out, "PictOp%d ", op);
233	}
234	out += strlen(out);
235
236	switch (src->format) {
237	case PICT_a8r8g8b8:
238		sprintf(out, "A8R8G8B8 ");
239		break;
240	case PICT_x8r8g8b8:
241		sprintf(out, "X8R8G8B8 ");
242		break;
243	case PICT_x8b8g8r8:
244		sprintf(out, "X8B8G8R8 ");
245		break;
246	case PICT_r5g6b5:
247		sprintf(out, "R5G6B5 ");
248		break;
249	case PICT_a8:
250		sprintf(out, "A8 ");
251		break;
252	case PICT_a1:
253		sprintf(out, "A1 ");
254		break;
255	default:
256		sprintf(out, "%x ", src->format);
257	}
258	out += strlen(out);
259
260	sprintf(out, "(%dx%d) ", src->pDrawable->width,
261		src->pDrawable->height);
262	if (src->repeat != RepeatNone)
263		strcat(out, "R ");
264	strcat(out, "-> ");
265	out += strlen(out);
266
267	switch (dst->format) {
268	case PICT_a8r8g8b8:
269		sprintf(out, "A8R8G8B8 ");
270		break;
271	case PICT_x8r8g8b8:
272		sprintf(out, "X8R8G8B8  ");
273		break;
274	case PICT_x8b8g8r8:
275		sprintf(out, "X8B8G8R8  ");
276		break;
277	case PICT_r5g6b5:
278		sprintf(out, "R5G6B5 ");
279		break;
280	case PICT_a8:
281		sprintf(out, "A8  ");
282		break;
283	case PICT_a1:
284		sprintf(out, "A1  ");
285		break;
286	default:
287		sprintf(out, "%x  ", dst->format);
288	}
289	out += strlen(out);
290
291	sprintf(out, "(%dx%d) ", dst->pDrawable->width,
292		dst->pDrawable->height);
293	if (dst->repeat != RepeatNone)
294		strcat(out, "R ");
295	out += strlen(out);
296
297	if (!mask)
298		sprintf(out, "& NONE");
299	else {
300		switch (mask->format) {
301		case PICT_a8r8g8b8:
302			sprintf(out, "& A8R8G8B8 ");
303			break;
304		case PICT_x8r8g8b8:
305			sprintf(out, "& X8R8G8B8  ");
306			break;
307		case PICT_x8b8g8r8:
308			sprintf(out, "& X8B8G8R8  ");
309			break;
310		case PICT_a8:
311			sprintf(out, "& A8  ");
312			break;
313		case PICT_a1:
314			sprintf(out, "& A1  ");
315			break;
316		default:
317			sprintf(out, "& %x  ", mask->format);
318		}
319		out += strlen(out);
320
321		sprintf(out, "(%dx%d) ", mask->pDrawable->width,
322			mask->pDrawable->height);
323		if (mask->repeat != RepeatNone)
324			strcat(out, "R ");
325		if (mask->componentAlpha)
326			strcat(out, "C ");
327		out += strlen(out);
328	}
329	strcat(out, "\n");
330
331	xf86DrvMsg(0, X_INFO, "%s", out2);
332}
333#else
334#define print_fallback_info(...)
335#endif
336
337Bool
338NV10EXACheckComposite(int op, PicturePtr src, PicturePtr mask, PicturePtr dst)
339{
340	ScrnInfoPtr pScrn = xf86ScreenToScrn(dst->pDrawable->pScreen);
341	NVPtr pNv = NVPTR(pScrn);
342
343	if (!check_pict_op(op)) {
344		print_fallback_info("pictop", op, src, mask, dst);
345		return FALSE;
346	}
347
348	if (!check_render_target(dst)) {
349		print_fallback_info("dst", op, src, mask, dst);
350		return FALSE;
351	}
352
353	if (!check_texture(pNv, src)) {
354		print_fallback_info("src", op, src, mask, dst);
355		return FALSE;
356	}
357
358	if (mask) {
359		if (!check_texture(pNv, mask)) {
360			print_fallback_info("mask", op, src,
361					    mask, dst);
362			return FALSE;
363		}
364
365		if (effective_component_alpha(mask) &&
366		    needs_src(op) && needs_src_alpha(op)) {
367			print_fallback_info("ca-mask", op, src,
368					    mask, dst);
369			return FALSE;
370		}
371	}
372
373	print_fallback_info("Accelerating", op, src, mask, dst);
374	return TRUE;
375}
376
377static Bool
378setup_texture(NVPtr pNv, int unit, PicturePtr pict, PixmapPtr pixmap)
379{
380	struct nouveau_pushbuf *push = pNv->pushbuf;
381	struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap);
382	unsigned reloc = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
383	unsigned h = pict->pDrawable->height;
384	unsigned w = pict->pDrawable->width;
385	unsigned format;
386
387	format = NV10_3D_TEX_FORMAT_WRAP_T_CLAMP_TO_EDGE |
388		 NV10_3D_TEX_FORMAT_WRAP_S_CLAMP_TO_EDGE |
389		 log2i(w) << 20 | log2i(h) << 16 |
390		 1 << 12 | /* lod == 1 */
391		 get_tex_format(pNv, pict) |
392		 0x50 /* UNK */;
393
394	/* NPOT_SIZE expects an even number for width, we can round up uneven
395	 * numbers here because EXA always gives 64 byte aligned pixmaps and
396	 * for all formats we support 64 bytes represents an even number of
397	 * pixels
398	 */
399	w = (w + 1) & ~1;
400
401	BEGIN_NV04(push, NV10_3D(TEX_OFFSET(unit)), 1);
402	PUSH_MTHDl(push, NV10_3D(TEX_OFFSET(unit)), bo, 0, reloc);
403	BEGIN_NV04(push, NV10_3D(TEX_FORMAT(unit)), 1);
404	PUSH_MTHDs(push, NV10_3D(TEX_FORMAT(unit)), bo, format, reloc,
405			 NV10_3D_TEX_FORMAT_DMA0,
406			 NV10_3D_TEX_FORMAT_DMA1);
407	BEGIN_NV04(push, NV10_3D(TEX_ENABLE(unit)), 1 );
408	PUSH_DATA (push, NV10_3D_TEX_ENABLE_ENABLE);
409	BEGIN_NV04(push, NV10_3D(TEX_NPOT_PITCH(unit)), 1);
410	PUSH_DATA (push, exaGetPixmapPitch(pixmap) << 16);
411	BEGIN_NV04(push, NV10_3D(TEX_NPOT_SIZE(unit)), 1);
412	PUSH_DATA (push, (w << 16) | h);
413	BEGIN_NV04(push, NV10_3D(TEX_FILTER(unit)), 1);
414	if (pict->filter == PictFilterNearest)
415		PUSH_DATA(push, NV10_3D_TEX_FILTER_MAGNIFY_NEAREST |
416				NV10_3D_TEX_FILTER_MINIFY_NEAREST);
417	else
418		PUSH_DATA(push, NV10_3D_TEX_FILTER_MAGNIFY_LINEAR |
419				NV10_3D_TEX_FILTER_MINIFY_LINEAR);
420	if (pict->transform) {
421		BEGIN_NV04(push, NV10_3D(TEX_MATRIX_ENABLE(unit)), 1);
422		PUSH_DATA (push, 1);
423		BEGIN_NV04(push, NV10_3D(TEX_MATRIX(unit, 0)), 16);
424		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[0][0]));
425		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[0][1]));
426		PUSH_DATAf(push, 0.f);
427		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[0][2]));
428		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[1][0]));
429		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[1][1]));
430		PUSH_DATAf(push, 0.f);
431		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[1][2]));
432		PUSH_DATAf(push, 0.0f);
433		PUSH_DATAf(push, 0.0f);
434		PUSH_DATAf(push, 0.0f);
435		PUSH_DATAf(push, 0.0f);
436		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[2][0]));
437		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[2][1]));
438		PUSH_DATAf(push, 0.0f);
439		PUSH_DATAf(push, xFixedToFloat(pict->transform->matrix[2][2]));
440	} else {
441		BEGIN_NV04(push, NV10_3D(TEX_MATRIX_ENABLE(unit)), 1);
442		PUSH_DATA (push, 0);
443	}
444
445	return TRUE;
446}
447
448static Bool
449setup_render_target(NVPtr pNv, PicturePtr pict, PixmapPtr pixmap)
450{
451	struct nouveau_pushbuf *push = pNv->pushbuf;
452	struct nouveau_bo *bo = nouveau_pixmap_bo(pixmap);
453
454	BEGIN_NV04(push, NV10_3D(RT_FORMAT), 3);
455	PUSH_DATA (push, get_rt_format(pict));
456	PUSH_DATA (push, (exaGetPixmapPitch(pixmap) << 16 |
457			  exaGetPixmapPitch(pixmap)));
458	PUSH_MTHDl(push, NV10_3D(COLOR_OFFSET), bo, 0,
459			 NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
460	return TRUE;
461}
462
463static void
464setup_blend_function(NVPtr pNv, PicturePtr pdpict, PicturePtr pmpict, int alu)
465{
466	struct nouveau_pushbuf *push = pNv->pushbuf;
467	struct pict_op *op = &nv10_pict_op[alu];
468	int src_factor = op->src;
469	int dst_factor = op->dst;
470
471	if (src_factor == SF(ONE_MINUS_DST_ALPHA) &&
472	    !PICT_FORMAT_A(pdpict->format))
473		/* ONE_MINUS_DST_ALPHA doesn't always do the right thing for
474		 * framebuffers without alpha channel. But it's the same as
475		 * ZERO in that case.
476		 */
477		src_factor = SF(ZERO);
478
479	if (effective_component_alpha(pmpict)) {
480		if (dst_factor == DF(SRC_ALPHA))
481			dst_factor = DF(SRC_COLOR);
482		else if (dst_factor == DF(ONE_MINUS_SRC_ALPHA))
483			dst_factor = DF(ONE_MINUS_SRC_COLOR);
484	}
485
486	BEGIN_NV04(push, NV10_3D(BLEND_FUNC_SRC), 2);
487	PUSH_DATA (push, src_factor);
488	PUSH_DATA (push, dst_factor);
489	BEGIN_NV04(push, NV10_3D(BLEND_FUNC_ENABLE), 1);
490	PUSH_DATA (push, 1);
491}
492
493#define RCSRC_COL(i)  (0x01 + (unit))
494#define RCSRC_TEX(i)  (0x08 + (unit))
495#define RCSEL_COLOR   (0x00)
496#define RCSEL_ALPHA   (0x10)
497#define RCINP_ZERO    (0x00)
498#define RCINP_ONE     (0x20)
499#define RCINP_A__SHIFT 24
500#define RCINP_B__SHIFT 16
501
502static Bool
503setup_picture(NVPtr pNv, PicturePtr pict, PixmapPtr pixmap, int unit,
504	      uint32_t *color, uint32_t *alpha)
505{
506	struct nouveau_pushbuf *push = pNv->pushbuf;
507	uint32_t shift, source;
508
509	if (pict && pict->pDrawable) {
510		if (!setup_texture(pNv, unit, pict, pixmap))
511			return FALSE;
512		source = RCSRC_TEX(unit);
513	} else
514	if (pict) {
515		BEGIN_NV04(push, NV10_3D(RC_COLOR(unit)), 1);
516		PUSH_DATA (push, pict->pSourcePict->solidFill.color);
517		source = RCSRC_COL(unit);
518	}
519
520	if (pict && PICT_FORMAT_RGB(pict->format))
521		*color = RCSEL_COLOR | source;
522	else
523		*color = RCSEL_COLOR | RCINP_ZERO;
524
525	if (pict && PICT_FORMAT_A(pict->format))
526		*alpha = RCSEL_ALPHA | source;
527	else
528		*alpha = RCSEL_ALPHA | RCINP_ONE;
529
530	if (unit)
531		shift = RCINP_B__SHIFT;
532	else
533		shift = RCINP_A__SHIFT;
534	*color <<= shift;
535	*alpha <<= shift;
536	return TRUE;
537}
538
539Bool
540NV10EXAPrepareComposite(int op,
541			PicturePtr pict_src,
542			PicturePtr pict_mask,
543			PicturePtr pict_dst,
544			PixmapPtr src,
545			PixmapPtr mask,
546			PixmapPtr dst)
547{
548	ScrnInfoPtr pScrn = xf86ScreenToScrn(dst->drawable.pScreen);
549	NVPtr pNv = NVPTR(pScrn);
550	struct nouveau_pushbuf *push = pNv->pushbuf;
551	uint32_t sc, sa, mc, ma;
552
553	if (!PUSH_SPACE(push, 128))
554		return FALSE;
555	PUSH_RESET(push);
556
557	/* setup render target and blending */
558	if (!setup_render_target(pNv, pict_dst, dst))
559		return FALSE;
560	setup_blend_function(pNv, pict_dst, pict_mask, op);
561
562	/* select picture sources */
563	if (!setup_picture(pNv, pict_src, src, 0, &sc, &sa))
564		return FALSE;
565	if (!setup_picture(pNv, pict_mask, mask, 1, &mc, &ma))
566		return FALSE;
567
568	/* configure register combiners */
569	BEGIN_NV04(push, NV10_3D(RC_IN_ALPHA(0)), 1);
570	PUSH_DATA (push, sa | ma);
571	BEGIN_NV04(push, NV10_3D(RC_IN_RGB(0)), 1);
572	if (effective_component_alpha(pict_mask)) {
573		if (needs_src_alpha(op))
574			PUSH_DATA(push, sa | mc);
575		else
576			PUSH_DATA(push, sc | mc);
577	} else {
578		PUSH_DATA(push, sc | ma);
579	}
580
581	nouveau_pushbuf_bufctx(push, pNv->bufctx);
582	if (nouveau_pushbuf_validate(push)) {
583		nouveau_pushbuf_bufctx(push, NULL);
584		return FALSE;
585	}
586
587	pNv->pspict = pict_src;
588	pNv->pmpict = pict_mask;
589	return TRUE;
590}
591
592static inline void
593PUSH_VTX2s(struct nouveau_pushbuf *push,
594	   int x1, int y1, int x2, int y2, int dx, int dy)
595{
596	BEGIN_NV04(push, NV10_3D(VERTEX_TX0_2I), 1);
597	PUSH_DATA (push, ((y1 & 0xffff) << 16) | (x1 & 0xffff));
598	BEGIN_NV04(push, NV10_3D(VERTEX_TX1_2I), 1);
599	PUSH_DATA (push, ((y2 & 0xffff) << 16) | (x2 & 0xffff));
600	BEGIN_NV04(push, NV10_3D(VERTEX_POS_3F_X), 3);
601	PUSH_DATAf(push, dx);
602	PUSH_DATAf(push, dy);
603	PUSH_DATAf(push, 0.0);
604}
605
606void
607NV10EXAComposite(PixmapPtr pix_dst,
608		 int sx, int sy, int mx, int my, int dx, int dy, int w, int h)
609{
610	ScrnInfoPtr pScrn = xf86ScreenToScrn(pix_dst->drawable.pScreen);
611	NVPtr pNv = NVPTR(pScrn);
612	struct nouveau_pushbuf *push = pNv->pushbuf;
613
614	if (!PUSH_SPACE(push, 64))
615		return;
616
617	BEGIN_NV04(push, NV10_3D(VERTEX_BEGIN_END), 1);
618	PUSH_DATA (push, NV10_3D_VERTEX_BEGIN_END_QUADS);
619	PUSH_VTX2s(push, sx, sy, mx, my, dx, dy);
620	PUSH_VTX2s(push, sx + w, sy, mx + w, my, dx + w, dy);
621	PUSH_VTX2s(push, sx + w, sy + h, mx + w, my + h, dx + w, dy + h);
622	PUSH_VTX2s(push, sx, sy + h, mx, my + h, dx, dy + h);
623	BEGIN_NV04(push, NV10_3D(VERTEX_BEGIN_END), 1);
624	PUSH_DATA (push, NV10_3D_VERTEX_BEGIN_END_STOP);
625}
626
627void
628NV10EXADoneComposite(PixmapPtr dst)
629{
630	ScrnInfoPtr pScrn = xf86ScreenToScrn(dst->drawable.pScreen);
631	nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL);
632}
633
634Bool
635NVAccelInitNV10TCL(ScrnInfoPtr pScrn)
636{
637	NVPtr pNv = NVPTR(pScrn);
638	struct nouveau_pushbuf *push = pNv->pushbuf;
639	struct nv04_fifo *fifo = pNv->channel->data;
640	uint32_t class = 0;
641	int i;
642
643	if (((pNv->dev->chipset & 0xf0) != NV_ARCH_10) &&
644	    ((pNv->dev->chipset & 0xf0) != NV_ARCH_20))
645		return FALSE;
646
647	if (pNv->dev->chipset >= 0x20 || pNv->dev->chipset == 0x1a)
648		class = NV15_3D_CLASS;
649	else if (pNv->dev->chipset >= 0x17)
650		class = NV17_3D_CLASS;
651	else if (pNv->dev->chipset >= 0x11)
652		class = NV15_3D_CLASS;
653	else
654		class = NV10_3D_CLASS;
655
656	if (nouveau_object_new(pNv->channel, Nv3D, class, NULL, 0, &pNv->Nv3D))
657		return FALSE;
658
659	if (!PUSH_SPACE(push, 256))
660		return FALSE;
661
662	BEGIN_NV04(push, NV01_SUBC(3D, OBJECT), 1);
663	PUSH_DATA (push, pNv->Nv3D->handle);
664	BEGIN_NV04(push, NV10_3D(DMA_NOTIFY), 1);
665	PUSH_DATA (push, pNv->NvNull->handle);
666
667	BEGIN_NV04(push, NV10_3D(DMA_TEXTURE0), 2);
668	PUSH_DATA (push, fifo->vram);
669	PUSH_DATA (push, fifo->gart);
670
671	BEGIN_NV04(push, NV10_3D(DMA_COLOR), 2);
672	PUSH_DATA (push, fifo->vram);
673	PUSH_DATA (push, fifo->vram);
674
675	BEGIN_NV04(push, NV04_GRAPH(3D, NOP), 1);
676	PUSH_DATA (push, 0);
677
678	BEGIN_NV04(push, NV10_3D(RT_HORIZ), 2);
679	PUSH_DATA (push, 2048 << 16 | 0);
680	PUSH_DATA (push, 2048 << 16 | 0);
681
682	BEGIN_NV04(push, NV10_3D(ZETA_OFFSET), 1);
683	PUSH_DATA (push, 0);
684
685	BEGIN_NV04(push, NV10_3D(VIEWPORT_CLIP_MODE), 1);
686	PUSH_DATA (push, 0);
687
688	BEGIN_NV04(push, NV10_3D(VIEWPORT_CLIP_HORIZ(0)), 1);
689	PUSH_DATA (push, 0x7ff << 16 | 0x800);
690	BEGIN_NV04(push, NV10_3D(VIEWPORT_CLIP_VERT(0)), 1);
691	PUSH_DATA (push, 0x7ff << 16 | 0x800);
692
693	for (i = 1; i < 8; i++) {
694		BEGIN_NV04(push, NV10_3D(VIEWPORT_CLIP_HORIZ(i)), 1);
695		PUSH_DATA (push, 0);
696		BEGIN_NV04(push, NV10_3D(VIEWPORT_CLIP_VERT(i)), 1);
697		PUSH_DATA (push, 0);
698	}
699
700	BEGIN_NV04(push, NV10_3D(UNK0290), 1);
701	PUSH_DATA (push, (0x10<<16)|1);
702	BEGIN_NV04(push, NV10_3D(UNK03F4), 1);
703	PUSH_DATA (push, 0);
704
705	BEGIN_NV04(push, NV04_GRAPH(3D, NOP), 1);
706	PUSH_DATA (push, 0);
707
708	if (class != NV10_3D_CLASS) {
709		/* For nv11, nv17 */
710		BEGIN_NV04(push, SUBC_3D(NV15_3D_FLIP_SET_READ), 3);
711		PUSH_DATA (push, 0);
712		PUSH_DATA (push, 1);
713		PUSH_DATA (push, 2);
714
715		BEGIN_NV04(push, NV15_BLIT(FLIP_SET_READ), 3);
716		PUSH_DATA (push, 0);
717		PUSH_DATA (push, 1);
718		PUSH_DATA (push, 2);
719
720		BEGIN_NV04(push, NV04_GRAPH(3D, NOP), 1);
721		PUSH_DATA (push, 0);
722	}
723
724	BEGIN_NV04(push, NV04_GRAPH(3D, NOP), 1);
725	PUSH_DATA (push, 0);
726
727	/* Set state */
728	BEGIN_NV04(push, NV10_3D(FOG_ENABLE), 1);
729	PUSH_DATA (push, 0);
730	BEGIN_NV04(push, NV10_3D(ALPHA_FUNC_ENABLE), 1);
731	PUSH_DATA (push, 0);
732	BEGIN_NV04(push, NV10_3D(ALPHA_FUNC_FUNC), 2);
733	PUSH_DATA (push, 0x207);
734	PUSH_DATA (push, 0);
735	BEGIN_NV04(push, NV10_3D(TEX_ENABLE(0)), 2);
736	PUSH_DATA (push, 0);
737	PUSH_DATA (push, 0);
738	BEGIN_NV04(push, NV10_3D(RC_IN_ALPHA(0)), 6);
739	PUSH_DATA (push, 0);
740	PUSH_DATA (push, 0);
741	PUSH_DATA (push, 0);
742	PUSH_DATA (push, 0);
743	PUSH_DATA (push, 0);
744	PUSH_DATA (push, 0);
745	BEGIN_NV04(push, NV10_3D(RC_OUT_ALPHA(0)), 6);
746	PUSH_DATA (push, 0x00000c00);
747	PUSH_DATA (push, 0);
748	PUSH_DATA (push, 0x00000c00);
749	PUSH_DATA (push, 0x18000000);
750	PUSH_DATA (push, 0x300c0000);
751	PUSH_DATA (push, 0x00001c80);
752	BEGIN_NV04(push, NV10_3D(BLEND_FUNC_ENABLE), 1);
753	PUSH_DATA (push, 0);
754	BEGIN_NV04(push, NV10_3D(DITHER_ENABLE), 2);
755	PUSH_DATA (push, 1);
756	PUSH_DATA (push, 0);
757	BEGIN_NV04(push, NV10_3D(LINE_SMOOTH_ENABLE), 1);
758	PUSH_DATA (push, 0);
759	BEGIN_NV04(push, NV10_3D(VERTEX_WEIGHT_ENABLE), 2);
760	PUSH_DATA (push, 0);
761	PUSH_DATA (push, 0);
762	BEGIN_NV04(push, NV10_3D(BLEND_FUNC_SRC), 4);
763	PUSH_DATA (push, 1);
764	PUSH_DATA (push, 0);
765	PUSH_DATA (push, 0);
766	PUSH_DATA (push, 0x8006);
767	BEGIN_NV04(push, NV10_3D(STENCIL_MASK), 8);
768	PUSH_DATA (push, 0xff);
769	PUSH_DATA (push, 0x207);
770	PUSH_DATA (push, 0);
771	PUSH_DATA (push, 0xff);
772	PUSH_DATA (push, 0x1e00);
773	PUSH_DATA (push, 0x1e00);
774	PUSH_DATA (push, 0x1e00);
775	PUSH_DATA (push, 0x1d01);
776	BEGIN_NV04(push, NV10_3D(NORMALIZE_ENABLE), 1);
777	PUSH_DATA (push, 0);
778	BEGIN_NV04(push, NV10_3D(FOG_ENABLE), 2);
779	PUSH_DATA (push, 0);
780	PUSH_DATA (push, 0);
781	BEGIN_NV04(push, NV10_3D(LIGHT_MODEL), 1);
782	PUSH_DATA (push, 0);
783	BEGIN_NV04(push, NV10_3D(SEPARATE_SPECULAR_ENABLE), 1);
784	PUSH_DATA (push, 0);
785	BEGIN_NV04(push, NV10_3D(ENABLED_LIGHTS), 1);
786	PUSH_DATA (push, 0);
787	BEGIN_NV04(push, NV10_3D(POLYGON_OFFSET_POINT_ENABLE), 3);
788	PUSH_DATA (push, 0);
789	PUSH_DATA (push, 0);
790	PUSH_DATA (push, 0);
791	BEGIN_NV04(push, NV10_3D(DEPTH_FUNC), 1);
792	PUSH_DATA (push, 0x201);
793	BEGIN_NV04(push, NV10_3D(DEPTH_WRITE_ENABLE), 1);
794	PUSH_DATA (push, 0);
795	BEGIN_NV04(push, NV10_3D(DEPTH_TEST_ENABLE), 1);
796	PUSH_DATA (push, 0);
797	BEGIN_NV04(push, NV10_3D(POLYGON_OFFSET_FACTOR), 2);
798	PUSH_DATA (push, 0);
799	PUSH_DATA (push, 0);
800	BEGIN_NV04(push, NV10_3D(POINT_SIZE), 1);
801	PUSH_DATA (push, 8);
802	BEGIN_NV04(push, NV10_3D(POINT_PARAMETERS_ENABLE), 2);
803	PUSH_DATA (push, 0);
804	PUSH_DATA (push, 0);
805	BEGIN_NV04(push, NV10_3D(LINE_WIDTH), 1);
806	PUSH_DATA (push, 8);
807	BEGIN_NV04(push, NV10_3D(LINE_SMOOTH_ENABLE), 1);
808	PUSH_DATA (push, 0);
809	BEGIN_NV04(push, NV10_3D(POLYGON_MODE_FRONT), 2);
810	PUSH_DATA (push, 0x1b02);
811	PUSH_DATA (push, 0x1b02);
812	BEGIN_NV04(push, NV10_3D(CULL_FACE), 2);
813	PUSH_DATA (push, 0x405);
814	PUSH_DATA (push, 0x901);
815	BEGIN_NV04(push, NV10_3D(POLYGON_SMOOTH_ENABLE), 1);
816	PUSH_DATA (push, 0);
817	BEGIN_NV04(push, NV10_3D(CULL_FACE_ENABLE), 1);
818	PUSH_DATA (push, 0);
819	BEGIN_NV04(push, NV10_3D(TEX_GEN_MODE(0, 0)), 8);
820	for (i = 0; i < 8; i++)
821		PUSH_DATA (push, 0);
822
823	BEGIN_NV04(push, NV10_3D(FOG_COEFF(0)), 3);
824	PUSH_DATA (push, 0x3fc00000);	/* -1.50 */
825	PUSH_DATA (push, 0xbdb8aa0a);	/* -0.09 */
826	PUSH_DATA (push, 0);		/*  0.00 */
827
828	BEGIN_NV04(push, NV04_GRAPH(3D, NOP), 1);
829	PUSH_DATA (push, 0);
830
831	BEGIN_NV04(push, NV10_3D(FOG_MODE), 2);
832	PUSH_DATA (push, 0x802);
833	PUSH_DATA (push, 2);
834	/* for some reason VIEW_MATRIX_ENABLE need to be 6 instead of 4 when
835	 * using texturing, except when using the texture matrix
836	 */
837	BEGIN_NV04(push, NV10_3D(VIEW_MATRIX_ENABLE), 1);
838	PUSH_DATA (push, 6);
839	BEGIN_NV04(push, NV10_3D(COLOR_MASK), 1);
840	PUSH_DATA (push, 0x01010101);
841
842	BEGIN_NV04(push, NV10_3D(PROJECTION_MATRIX(0)), 16);
843	for(i = 0; i < 16; i++)
844		PUSH_DATAf(push, i/4 == i%4 ? 1.0 : 0.0);
845
846	BEGIN_NV04(push, NV10_3D(DEPTH_RANGE_NEAR), 2);
847	PUSH_DATA (push, 0);
848	PUSH_DATAf(push, 65536.0);
849
850	BEGIN_NV04(push, NV10_3D(VIEWPORT_TRANSLATE_X), 4);
851	PUSH_DATAf(push, -2048.0);
852	PUSH_DATAf(push, -2048.0);
853	PUSH_DATAf(push, 0);
854	PUSH_DATA (push, 0);
855
856	/* Set vertex component */
857	BEGIN_NV04(push, NV10_3D(VERTEX_COL_4F_R), 4);
858	PUSH_DATAf(push, 1.0);
859	PUSH_DATAf(push, 1.0);
860	PUSH_DATAf(push, 1.0);
861	PUSH_DATAf(push, 1.0);
862	BEGIN_NV04(push, NV10_3D(VERTEX_COL2_3F_R), 3);
863	PUSH_DATA (push, 0);
864	PUSH_DATA (push, 0);
865	PUSH_DATA (push, 0);
866	BEGIN_NV04(push, NV10_3D(VERTEX_NOR_3F_X), 3);
867	PUSH_DATA (push, 0);
868	PUSH_DATA (push, 0);
869	PUSH_DATAf(push, 1.0);
870	BEGIN_NV04(push, NV10_3D(VERTEX_TX0_4F_S), 4);
871	PUSH_DATAf(push, 0.0);
872	PUSH_DATAf(push, 0.0);
873	PUSH_DATAf(push, 0.0);
874	PUSH_DATAf(push, 1.0);
875	BEGIN_NV04(push, NV10_3D(VERTEX_TX1_4F_S), 4);
876	PUSH_DATAf(push, 0.0);
877	PUSH_DATAf(push, 0.0);
878	PUSH_DATAf(push, 0.0);
879	PUSH_DATAf(push, 1.0);
880	BEGIN_NV04(push, NV10_3D(VERTEX_FOG_1F), 1);
881	PUSH_DATAf(push, 0.0);
882	BEGIN_NV04(push, NV10_3D(EDGEFLAG_ENABLE), 1);
883	PUSH_DATA (push, 1);
884
885	return TRUE;
886}
887