nvc0_exa.c revision c2e4ac43
1/*
2 * Copyright 2007 NVIDIA, Corporation
3 * Copyright 2008 Ben Skeggs
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
20 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "nv_include.h"
25#include "nv_rop.h"
26#include "nvc0_accel.h"
27#include "nouveau_copy.h"
28
29#define NOUVEAU_BO(a, b, c) (NOUVEAU_BO_##a | NOUVEAU_BO_##b | NOUVEAU_BO_##c)
30
31#define NVC0EXA_LOCALS(p)                                                      \
32	ScrnInfoPtr pScrn = xf86ScreenToScrn((p)->drawable.pScreen);         \
33	NVPtr pNv = NVPTR(pScrn);                                              \
34	struct nouveau_pushbuf *push = pNv->pushbuf; (void)push;
35
36#define BF(f) NV50_BLEND_FACTOR_##f
37
38struct nvc0_blend_op {
39	unsigned src_alpha;
40	unsigned dst_alpha;
41	unsigned src_blend;
42	unsigned dst_blend;
43};
44
45static struct nvc0_blend_op
46NVC0EXABlendOp[] = {
47/* Clear       */ { 0, 0, BF(               ZERO), BF(               ZERO) },
48/* Src         */ { 0, 0, BF(                ONE), BF(               ZERO) },
49/* Dst         */ { 0, 0, BF(               ZERO), BF(                ONE) },
50/* Over        */ { 1, 0, BF(                ONE), BF(ONE_MINUS_SRC_ALPHA) },
51/* OverReverse */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(                ONE) },
52/* In          */ { 0, 1, BF(          DST_ALPHA), BF(               ZERO) },
53/* InReverse   */ { 1, 0, BF(               ZERO), BF(          SRC_ALPHA) },
54/* Out         */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(               ZERO) },
55/* OutReverse  */ { 1, 0, BF(               ZERO), BF(ONE_MINUS_SRC_ALPHA) },
56/* Atop        */ { 1, 1, BF(          DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
57/* AtopReverse */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(          SRC_ALPHA) },
58/* Xor         */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
59/* Add         */ { 0, 0, BF(                ONE), BF(                ONE) },
60};
61
62static Bool
63NVC0EXA2DSurfaceFormat(PixmapPtr ppix, uint32_t *fmt)
64{
65	NVC0EXA_LOCALS(ppix);
66
67	switch (ppix->drawable.bitsPerPixel) {
68	case 8 : *fmt = NV50_SURFACE_FORMAT_R8_UNORM; break;
69	case 15: *fmt = NV50_SURFACE_FORMAT_BGR5_X1_UNORM; break;
70	case 16: *fmt = NV50_SURFACE_FORMAT_B5G6R5_UNORM; break;
71	case 24: *fmt = NV50_SURFACE_FORMAT_BGRX8_UNORM; break;
72	case 30: *fmt = NV50_SURFACE_FORMAT_RGB10_A2_UNORM; break;
73	case 32: *fmt = NV50_SURFACE_FORMAT_BGRA8_UNORM; break;
74	default:
75		 NOUVEAU_FALLBACK("Unknown surface format for bpp=%d\n",
76				  ppix->drawable.bitsPerPixel);
77		 return FALSE;
78	}
79
80	return TRUE;
81}
82
83static void NVC0EXASetClip(PixmapPtr ppix, int x, int y, int w, int h)
84{
85	NVC0EXA_LOCALS(ppix);
86
87	BEGIN_NVC0(push, NV50_2D(CLIP_X), 4);
88	PUSH_DATA (push, x);
89	PUSH_DATA (push, y);
90	PUSH_DATA (push, w);
91	PUSH_DATA (push, h);
92}
93
94static void
95NVC0EXAAcquireSurface2D(PixmapPtr ppix, int is_src, uint32_t fmt)
96{
97	NVC0EXA_LOCALS(ppix);
98	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
99	struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
100	int mthd = is_src ? NV50_2D_SRC_FORMAT : NV50_2D_DST_FORMAT;
101	uint32_t bo_flags;
102
103	bo_flags = nvpix->shared ? NOUVEAU_BO_GART : NOUVEAU_BO_VRAM;
104	bo_flags |= is_src ? NOUVEAU_BO_RD : NOUVEAU_BO_WR;
105
106	if (!nv50_style_tiled_pixmap(ppix)) {
107		BEGIN_NVC0(push, SUBC_2D(mthd), 2);
108		PUSH_DATA (push, fmt);
109		PUSH_DATA (push, 1);
110		BEGIN_NVC0(push, SUBC_2D(mthd + 0x14), 1);
111		PUSH_DATA (push, (uint32_t)exaGetPixmapPitch(ppix));
112	} else {
113		BEGIN_NVC0(push, SUBC_2D(mthd), 5);
114		PUSH_DATA (push, fmt);
115		PUSH_DATA (push, 0);
116		PUSH_DATA (push, bo->config.nvc0.tile_mode);
117		PUSH_DATA (push, 1);
118		PUSH_DATA (push, 0);
119	}
120
121	BEGIN_NVC0(push, SUBC_2D(mthd + 0x18), 4);
122	PUSH_DATA (push, ppix->drawable.width);
123	PUSH_DATA (push, ppix->drawable.height);
124	PUSH_DATA (push, bo->offset >> 32);
125	PUSH_DATA (push, bo->offset);
126
127	if (is_src == 0)
128		NVC0EXASetClip(ppix, 0, 0, ppix->drawable.width, ppix->drawable.height);
129
130	PUSH_REFN (push, bo, bo_flags);
131}
132
133static void
134NVC0EXASetPattern(PixmapPtr pdpix, int col0, int col1, int pat0, int pat1)
135{
136	NVC0EXA_LOCALS(pdpix);
137
138	BEGIN_NVC0(push, NV50_2D(PATTERN_COLOR(0)), 4);
139	PUSH_DATA (push, col0);
140	PUSH_DATA (push, col1);
141	PUSH_DATA (push, pat0);
142	PUSH_DATA (push, pat1);
143}
144
145static void
146NVC0EXASetROP(PixmapPtr pdpix, int alu, Pixel planemask)
147{
148	NVC0EXA_LOCALS(pdpix);
149	int rop;
150
151	if (planemask != ~0)
152		rop = NVROP[alu].copy_planemask;
153	else
154		rop = NVROP[alu].copy;
155
156	BEGIN_NVC0(push, NV50_2D(OPERATION), 1);
157	if (alu == GXcopy && EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
158		PUSH_DATA (push, NV50_2D_OPERATION_SRCCOPY);
159		return;
160	} else {
161		PUSH_DATA (push, NV50_2D_OPERATION_ROP);
162	}
163
164	BEGIN_NVC0(push, NV50_2D(PATTERN_COLOR_FORMAT), 2);
165	switch (pdpix->drawable.bitsPerPixel) {
166	case  8: PUSH_DATA (push, 3); break;
167	case 15: PUSH_DATA (push, 1); break;
168	case 16: PUSH_DATA (push, 0); break;
169	case 24:
170	case 32:
171	default:
172		 PUSH_DATA (push, 2);
173		 break;
174	}
175	PUSH_DATA (push, 1);
176
177	/* There are 16 ALUs.
178	 * 0-15: copy
179	 * 16-31: copy_planemask
180	 */
181
182	if (!EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
183		alu += 16;
184		NVC0EXASetPattern(pdpix, 0, planemask, ~0, ~0);
185	} else {
186		if (pNv->currentRop > 15)
187			NVC0EXASetPattern(pdpix, ~0, ~0, ~0, ~0);
188	}
189
190	if (pNv->currentRop != alu) {
191		BEGIN_NVC0(push, NV50_2D(ROP), 1);
192		PUSH_DATA (push, rop);
193		pNv->currentRop = alu;
194	}
195}
196
197Bool
198NVC0EXAPrepareSolid(PixmapPtr pdpix, int alu, Pixel planemask, Pixel fg)
199{
200	NVC0EXA_LOCALS(pdpix);
201	uint32_t fmt;
202
203	if (!NVC0EXA2DSurfaceFormat(pdpix, &fmt))
204		NOUVEAU_FALLBACK("rect format\n");
205
206	if (!PUSH_SPACE(push, 64))
207		NOUVEAU_FALLBACK("space\n");
208	PUSH_RESET(push);
209
210	NVC0EXAAcquireSurface2D(pdpix, 0, fmt);
211	NVC0EXASetROP(pdpix, alu, planemask);
212
213	BEGIN_NVC0(push, NV50_2D(DRAW_SHAPE), 3);
214	PUSH_DATA (push, NV50_2D_DRAW_SHAPE_RECTANGLES);
215	PUSH_DATA (push, fmt);
216	PUSH_DATA (push, fg);
217
218	nouveau_pushbuf_bufctx(push, pNv->bufctx);
219	if (nouveau_pushbuf_validate(push)) {
220		nouveau_pushbuf_bufctx(push, NULL);
221		NOUVEAU_FALLBACK("validate\n");
222	}
223
224	return TRUE;
225}
226
227void
228NVC0EXASolid(PixmapPtr pdpix, int x1, int y1, int x2, int y2)
229{
230	NVC0EXA_LOCALS(pdpix);
231
232	if (!PUSH_SPACE(push, 8))
233		return;
234
235	BEGIN_NVC0(push, NV50_2D(DRAW_POINT32_X(0)), 4);
236	PUSH_DATA (push, x1);
237	PUSH_DATA (push, y1);
238	PUSH_DATA (push, x2);
239	PUSH_DATA (push, y2);
240
241	if ((x2 - x1) * (y2 - y1) >= 512)
242		PUSH_KICK(push);
243}
244
245void
246NVC0EXADoneSolid(PixmapPtr pdpix)
247{
248	NVC0EXA_LOCALS(pdpix);
249	nouveau_pushbuf_bufctx(push, NULL);
250}
251
252Bool
253NVC0EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
254		   int alu, Pixel planemask)
255{
256	NVC0EXA_LOCALS(pdpix);
257	uint32_t src, dst;
258
259	if (!NVC0EXA2DSurfaceFormat(pspix, &src))
260		NOUVEAU_FALLBACK("src format\n");
261	if (!NVC0EXA2DSurfaceFormat(pdpix, &dst))
262		NOUVEAU_FALLBACK("dst format\n");
263
264	if (!PUSH_SPACE(push, 64))
265		NOUVEAU_FALLBACK("space\n");
266	PUSH_RESET(push);
267
268	NVC0EXAAcquireSurface2D(pspix, 1, src);
269	NVC0EXAAcquireSurface2D(pdpix, 0, dst);
270	NVC0EXASetROP(pdpix, alu, planemask);
271
272	nouveau_pushbuf_bufctx(push, pNv->bufctx);
273	if (nouveau_pushbuf_validate(push)) {
274		nouveau_pushbuf_bufctx(push, NULL);
275		NOUVEAU_FALLBACK("validate\n");
276	}
277
278	return TRUE;
279}
280
281void
282NVC0EXACopy(PixmapPtr pdpix, int srcX , int srcY,
283			     int dstX , int dstY,
284			     int width, int height)
285{
286	NVC0EXA_LOCALS(pdpix);
287
288	if (!PUSH_SPACE(push, 32))
289		return;
290
291	BEGIN_NVC0(push, SUBC_2D(NV50_GRAPH_SERIALIZE), 1);
292	PUSH_DATA (push, 0);
293	BEGIN_NVC0(push, NV50_2D(BLIT_CONTROL), 1);
294	PUSH_DATA (push, 0);
295	BEGIN_NVC0(push, NV50_2D(BLIT_DST_X), 12);
296	PUSH_DATA (push, dstX);
297	PUSH_DATA (push, dstY);
298	PUSH_DATA (push, width);
299	PUSH_DATA (push, height);
300	PUSH_DATA (push, 0); /* DU,V_DX,Y_FRACT,INT */
301	PUSH_DATA (push, 1);
302	PUSH_DATA (push, 0);
303	PUSH_DATA (push, 1);
304	PUSH_DATA (push, 0); /* BLIT_SRC_X,Y_FRACT,INT */
305	PUSH_DATA (push, srcX);
306	PUSH_DATA (push, 0);
307	PUSH_DATA (push, srcY);
308
309	if (width * height >= 512)
310		PUSH_KICK(push);
311}
312
313void
314NVC0EXADoneCopy(PixmapPtr pdpix)
315{
316	NVC0EXA_LOCALS(pdpix);
317	nouveau_pushbuf_bufctx(push, NULL);
318}
319
320Bool
321NVC0EXAUploadSIFC(const char *src, int src_pitch,
322		  PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
323{
324	NVC0EXA_LOCALS(pdpix);
325	ScreenPtr pScreen = pdpix->drawable.pScreen;
326	int line_dwords = (w * cpp + 3) / 4;
327	uint32_t sifc_fmt;
328	Bool ret = FALSE;
329
330	if (!NVC0EXA2DSurfaceFormat(pdpix, &sifc_fmt))
331		NOUVEAU_FALLBACK("hostdata format\n");
332
333	if (!PUSH_SPACE(push, 64))
334		NOUVEAU_FALLBACK("pushbuf\n");
335	PUSH_RESET(push);
336
337	NVC0EXAAcquireSurface2D(pdpix, 0, sifc_fmt);
338	NVC0EXASetClip(pdpix, x, y, w, h);
339
340	BEGIN_NVC0(push, NV50_2D(OPERATION), 1);
341	PUSH_DATA (push, NV50_2D_OPERATION_SRCCOPY);
342	BEGIN_NVC0(push, NV50_2D(SIFC_BITMAP_ENABLE), 2);
343	PUSH_DATA (push, 0);
344	PUSH_DATA (push, sifc_fmt);
345	BEGIN_NVC0(push, NV50_2D(SIFC_WIDTH), 10);
346	PUSH_DATA (push, (line_dwords * 4) / cpp);
347	PUSH_DATA (push, h);
348	PUSH_DATA (push, 0); /* SIFC_DX,Y_DU,V_FRACT,INT */
349	PUSH_DATA (push, 1);
350	PUSH_DATA (push, 0);
351	PUSH_DATA (push, 1);
352	PUSH_DATA (push, 0); /* SIFC_DST_X,Y_FRACT,INT */
353	PUSH_DATA (push, x);
354	PUSH_DATA (push, 0);
355	PUSH_DATA (push, y);
356
357	nouveau_pushbuf_bufctx(push, pNv->bufctx);
358	if (nouveau_pushbuf_validate(push))
359		goto out;
360
361	while (h--) {
362		const char *ptr = src;
363		int count = line_dwords;
364
365		while (count) {
366			int size = count > 1792 ? 1792 : count;
367
368			if (!PUSH_SPACE(push, size + 1))
369				goto out;
370			BEGIN_NIC0(push, NV50_2D(SIFC_DATA), size);
371			PUSH_DATAp(push, ptr, size);
372
373			ptr += size * 4;
374			count -= size;
375		}
376
377		src += src_pitch;
378	}
379
380	ret = TRUE;
381out:
382	nouveau_pushbuf_bufctx(push, NULL);
383	if (pdpix == pScreen->GetScreenPixmap(pScreen))
384		PUSH_KICK(push);
385	return ret;
386}
387
388static Bool
389NVC0EXACheckRenderTarget(PicturePtr ppict)
390{
391	if (ppict->pDrawable->width > 8192 ||
392	    ppict->pDrawable->height > 8192)
393		NOUVEAU_FALLBACK("render target dimensions exceeded %dx%d\n",
394				 ppict->pDrawable->width,
395				 ppict->pDrawable->height);
396
397	switch (ppict->format) {
398	case PICT_a8r8g8b8:
399	case PICT_x8r8g8b8:
400	case PICT_r5g6b5:
401	case PICT_a8:
402	case PICT_x1r5g5b5:
403	case PICT_a1r5g5b5:
404	case PICT_x8b8g8r8:
405	case PICT_a2b10g10r10:
406	case PICT_x2b10g10r10:
407	case PICT_a2r10g10b10:
408	case PICT_x2r10g10b10:
409		break;
410	default:
411		NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
412	}
413
414	return TRUE;
415}
416
417static Bool
418NVC0EXARenderTarget(PixmapPtr ppix, PicturePtr ppict)
419{
420	NVC0EXA_LOCALS(ppix);
421	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
422	unsigned format;
423
424	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
425	if (!nv50_style_tiled_pixmap(ppix))
426		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
427
428	switch (ppict->format) {
429	case PICT_a8r8g8b8: format = NV50_SURFACE_FORMAT_BGRA8_UNORM; break;
430	case PICT_x8r8g8b8: format = NV50_SURFACE_FORMAT_BGRX8_UNORM; break;
431	case PICT_r5g6b5  : format = NV50_SURFACE_FORMAT_B5G6R5_UNORM; break;
432	case PICT_a8      : format = NV50_SURFACE_FORMAT_A8_UNORM; break;
433	case PICT_x1r5g5b5: format = NV50_SURFACE_FORMAT_BGR5_X1_UNORM; break;
434	case PICT_a1r5g5b5: format = NV50_SURFACE_FORMAT_BGR5_A1_UNORM; break;
435	case PICT_x8b8g8r8: format = NV50_SURFACE_FORMAT_RGBX8_UNORM; break;
436	case PICT_a2b10g10r10:
437	case PICT_x2b10g10r10:
438		format = NV50_SURFACE_FORMAT_RGB10_A2_UNORM;
439		break;
440	case PICT_a2r10g10b10:
441	case PICT_x2r10g10b10:
442		format = NV50_SURFACE_FORMAT_BGR10_A2_UNORM;
443		break;
444	default:
445		NOUVEAU_FALLBACK("invalid picture format\n");
446	}
447
448	BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(0)), 8);
449	PUSH_DATA (push, bo->offset >> 32);
450	PUSH_DATA (push, bo->offset);
451	PUSH_DATA (push, ppix->drawable.width);
452	PUSH_DATA (push, ppix->drawable.height);
453	PUSH_DATA (push, format);
454	PUSH_DATA (push, bo->config.nvc0.tile_mode);
455	PUSH_DATA (push, 0x00000001);
456	PUSH_DATA (push, 0x00000000);
457	return TRUE;
458}
459
460static Bool
461NVC0EXACheckTexture(PicturePtr ppict, PicturePtr pdpict, int op)
462{
463	if (ppict->pDrawable) {
464		if (ppict->pDrawable->width > 8192 ||
465		    ppict->pDrawable->height > 8192)
466			NOUVEAU_FALLBACK("texture too large\n");
467	} else {
468		switch (ppict->pSourcePict->type) {
469		case SourcePictTypeSolidFill:
470			break;
471		default:
472			NOUVEAU_FALLBACK("pict %d\n", ppict->pSourcePict->type);
473			break;
474		}
475	}
476
477	switch (ppict->format) {
478	case PICT_a8r8g8b8:
479	case PICT_a8b8g8r8:
480	case PICT_x8r8g8b8:
481	case PICT_x8b8g8r8:
482	case PICT_r5g6b5:
483	case PICT_a8:
484	case PICT_x1r5g5b5:
485	case PICT_x1b5g5r5:
486	case PICT_a1r5g5b5:
487	case PICT_a1b5g5r5:
488	case PICT_b5g6r5:
489	case PICT_b8g8r8a8:
490	case PICT_b8g8r8x8:
491	case PICT_a2b10g10r10:
492	case PICT_x2b10g10r10:
493	case PICT_x2r10g10b10:
494	case PICT_a2r10g10b10:
495	case PICT_x4r4g4b4:
496	case PICT_x4b4g4r4:
497	case PICT_a4r4g4b4:
498	case PICT_a4b4g4r4:
499		break;
500	default:
501		NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
502	}
503
504	switch (ppict->filter) {
505	case PictFilterNearest:
506	case PictFilterBilinear:
507		break;
508	default:
509		NOUVEAU_FALLBACK("picture filter %d\n", ppict->filter);
510	}
511
512	/* OpenGL and Render disagree on what should be sampled outside an XRGB
513	 * texture (with no repeating). Opengl has a hardcoded alpha value of
514	 * 1.0, while render expects 0.0. We assume that clipping is done for
515	 * untranformed sources.
516	 */
517	if (NVC0EXABlendOp[op].src_alpha && !ppict->repeat &&
518	    ppict->transform && (PICT_FORMAT_A(ppict->format) == 0)
519	    && (PICT_FORMAT_A(pdpict->format) != 0))
520		NOUVEAU_FALLBACK("REPEAT_NONE unsupported for XRGB source\n");
521
522	return TRUE;
523}
524
525#define _(X1, X2, X3, X4, FMT)						\
526	(NV50TIC_0_0_TYPER_UNORM | NV50TIC_0_0_TYPEG_UNORM |		\
527	 NV50TIC_0_0_TYPEB_UNORM | NV50TIC_0_0_TYPEA_UNORM |		\
528	 NV50TIC_0_0_MAP##X1 | NV50TIC_0_0_MAP##X2 |			\
529	 NV50TIC_0_0_MAP##X3 | NV50TIC_0_0_MAP##X4 |			\
530	 NV50TIC_0_0_FMT_##FMT)
531
532static Bool
533NVC0EXAPictSolid(NVPtr pNv, PicturePtr ppict, unsigned unit)
534{
535	uint64_t offset = pNv->scratch->offset + SOLID(unit);
536	struct nouveau_pushbuf *push = pNv->pushbuf;
537
538	PUSH_DATAu(push, pNv->scratch, SOLID(unit), 1);
539	PUSH_DATA (push, ppict->pSourcePict->solidFill.color);
540	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET + (unit * 32), 8);
541	PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8));
542	PUSH_DATA (push,  offset);
543	PUSH_DATA (push, (offset >> 32) | 0xd005d000);
544	PUSH_DATA (push, 0x00300000);
545	PUSH_DATA (push, 0x00000001);
546	PUSH_DATA (push, 0x00010001);
547	PUSH_DATA (push, 0x03000000);
548	PUSH_DATA (push, 0x00000000);
549	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET + (unit * 32), 8);
550	PUSH_DATA (push, NV50TSC_1_0_WRAPS_REPEAT |
551			 NV50TSC_1_0_WRAPT_REPEAT |
552			 NV50TSC_1_0_WRAPR_REPEAT | 0x00024000);
553	PUSH_DATA (push, NV50TSC_1_1_MAGF_NEAREST |
554			 NV50TSC_1_1_MINF_NEAREST |
555			 NV50TSC_1_1_MIPF_NONE);
556	PUSH_DATA (push, 0x00000000);
557	PUSH_DATA (push, 0x00000000);
558	PUSH_DATA (push, 0x00000000);
559	PUSH_DATA (push, 0x00000000);
560	PUSH_DATA (push, 0x00000000);
561	PUSH_DATA (push, 0x00000000);
562
563	return TRUE;
564}
565
566static Bool
567NVC0EXAPictGradient(NVPtr pNv, PicturePtr ppict, unsigned unit)
568{
569	return FALSE;
570}
571
572static Bool
573NVC0EXAPictTexture(NVPtr pNv, PixmapPtr ppix, PicturePtr ppict, unsigned unit)
574{
575	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
576	struct nouveau_pushbuf *push = pNv->pushbuf;
577	uint32_t format;
578
579	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
580	if (!nv50_style_tiled_pixmap(ppix))
581		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
582
583	switch (ppict->format) {
584	case PICT_a8r8g8b8:
585		format = _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8);
586		break;
587	case PICT_a8b8g8r8:
588		format = _(R_C0, G_C1, B_C2, A_C3, 8_8_8_8);
589		break;
590	case PICT_x8r8g8b8:
591		format = _(B_C0, G_C1, R_C2, A_ONE, 8_8_8_8);
592		break;
593	case PICT_x8b8g8r8:
594		format = _(R_C0, G_C1, B_C2, A_ONE, 8_8_8_8);
595		break;
596	case PICT_r5g6b5:
597		format = _(B_C0, G_C1, R_C2, A_ONE, 5_6_5);
598		break;
599	case PICT_a8:
600		format = _(A_C0, B_ZERO, G_ZERO, R_ZERO, 8);
601		break;
602	case PICT_x1r5g5b5:
603		format = _(B_C0, G_C1, R_C2, A_ONE, 1_5_5_5);
604		break;
605	case PICT_x1b5g5r5:
606		format = _(R_C0, G_C1, B_C2, A_ONE, 1_5_5_5);
607		break;
608	case PICT_a1r5g5b5:
609		format = _(B_C0, G_C1, R_C2, A_C3, 1_5_5_5);
610		break;
611	case PICT_a1b5g5r5:
612		format = _(R_C0, G_C1, B_C2, A_C3, 1_5_5_5);
613		break;
614	case PICT_b5g6r5:
615		format = _(R_C0, G_C1, B_C2, A_ONE, 5_6_5);
616		break;
617	case PICT_b8g8r8x8:
618		format = _(A_ONE, R_C1, G_C2, B_C3, 8_8_8_8);
619		break;
620	case PICT_b8g8r8a8:
621		format = _(A_C0, R_C1, G_C2, B_C3, 8_8_8_8);
622		break;
623	case PICT_a2b10g10r10:
624		format = _(R_C0, G_C1, B_C2, A_C3, 2_10_10_10);
625		break;
626	case PICT_x2b10g10r10:
627		format = _(R_C0, G_C1, B_C2, A_ONE, 2_10_10_10);
628		break;
629	case PICT_x2r10g10b10:
630		format = _(B_C0, G_C1, R_C2, A_ONE, 2_10_10_10);
631		break;
632	case PICT_a2r10g10b10:
633		format = _(B_C0, G_C1, R_C2, A_C3, 2_10_10_10);
634		break;
635	case PICT_x4r4g4b4:
636		format = _(B_C0, G_C1, R_C2, A_ONE, 4_4_4_4);
637		break;
638	case PICT_x4b4g4r4:
639		format = _(R_C0, G_C1, B_C2, A_ONE, 4_4_4_4);
640		break;
641	case PICT_a4r4g4b4:
642		format = _(B_C0, G_C1, R_C2, A_C3, 4_4_4_4);
643		break;
644	case PICT_a4b4g4r4:
645		format = _(R_C0, G_C1, B_C2, A_C3, 4_4_4_4);
646		break;
647	default:
648		NOUVEAU_FALLBACK("invalid picture format, this SHOULD NOT HAPPEN. Expect trouble.\n");
649	}
650#undef _
651
652	PUSH_REFN (push, bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
653	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET + (unit * 32), 8);
654	PUSH_DATA (push, format);
655	PUSH_DATA (push, bo->offset);
656	PUSH_DATA (push, (bo->offset >> 32) |
657			 (bo->config.nvc0.tile_mode << 18) |
658			 0xd0005000);
659	PUSH_DATA (push, 0x00300000);
660	PUSH_DATA (push, (1 << 31) | ppix->drawable.width);
661	PUSH_DATA (push, (1 << 16) | ppix->drawable.height);
662	PUSH_DATA (push, 0x03000000);
663	PUSH_DATA (push, 0x00000000);
664
665	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET + (unit * 32), 8);
666	if (ppict->repeat) {
667		switch (ppict->repeatType) {
668		case RepeatPad:
669			PUSH_DATA (push, 0x00024000 |
670					 NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
671					 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
672					 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
673			break;
674		case RepeatReflect:
675			PUSH_DATA (push, 0x00024000 |
676					 NV50TSC_1_0_WRAPS_MIRROR_REPEAT |
677					 NV50TSC_1_0_WRAPT_MIRROR_REPEAT |
678					 NV50TSC_1_0_WRAPR_MIRROR_REPEAT);
679			break;
680		case RepeatNormal:
681		default:
682			PUSH_DATA (push, 0x00024000 |
683					 NV50TSC_1_0_WRAPS_REPEAT |
684					 NV50TSC_1_0_WRAPT_REPEAT |
685					 NV50TSC_1_0_WRAPR_REPEAT);
686			break;
687		}
688	} else {
689		PUSH_DATA (push, 0x00024000 |
690				 NV50TSC_1_0_WRAPS_CLAMP_TO_BORDER |
691				 NV50TSC_1_0_WRAPT_CLAMP_TO_BORDER |
692				 NV50TSC_1_0_WRAPR_CLAMP_TO_BORDER);
693	}
694	if (ppict->filter == PictFilterBilinear) {
695		PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR |
696				 NV50TSC_1_1_MINF_LINEAR |
697				 NV50TSC_1_1_MIPF_NONE);
698	} else {
699		PUSH_DATA (push, NV50TSC_1_1_MAGF_NEAREST |
700				 NV50TSC_1_1_MINF_NEAREST |
701				 NV50TSC_1_1_MIPF_NONE);
702	}
703	PUSH_DATA (push, 0x00000000);
704	PUSH_DATA (push, 0x00000000);
705	PUSH_DATA (push, 0x00000000);
706	PUSH_DATA (push, 0x00000000);
707	PUSH_DATA (push, 0x00000000);
708	PUSH_DATA (push, 0x00000000);
709
710	PUSH_DATAu(push, pNv->scratch, PVP_DATA + (unit * 11 * 4), 11);
711	if (ppict->transform) {
712		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][0]));
713		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][1]));
714		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][2]));
715		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][0]));
716		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][1]));
717		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][2]));
718		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][0]));
719		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][1]));
720		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][2]));
721	} else {
722		PUSH_DATAf(push, 1.0);
723		PUSH_DATAf(push, 0.0);
724		PUSH_DATAf(push, 0.0);
725		PUSH_DATAf(push, 0.0);
726		PUSH_DATAf(push, 1.0);
727		PUSH_DATAf(push, 0.0);
728		PUSH_DATAf(push, 0.0);
729		PUSH_DATAf(push, 0.0);
730		PUSH_DATAf(push, 1.0);
731	}
732	PUSH_DATAf(push, 1.0 / ppix->drawable.width);
733	PUSH_DATAf(push, 1.0 / ppix->drawable.height);
734	return TRUE;
735}
736
737static Bool
738NVC0EXAPicture(NVPtr pNv, PixmapPtr ppix, PicturePtr ppict, int unit)
739{
740	if (ppict->pDrawable)
741		return NVC0EXAPictTexture(pNv, ppix, ppict, unit);
742
743	switch (ppict->pSourcePict->type) {
744	case SourcePictTypeSolidFill:
745		return NVC0EXAPictSolid(pNv, ppict, unit);
746	case SourcePictTypeLinear:
747		return NVC0EXAPictGradient(pNv, ppict, unit);
748	default:
749		break;
750	}
751
752	return FALSE;
753}
754static Bool
755NVC0EXACheckBlend(int op)
756{
757	if (op > PictOpAdd)
758		NOUVEAU_FALLBACK("unsupported blend op %d\n", op);
759	return TRUE;
760}
761
762static void
763NVC0EXABlend(PixmapPtr ppix, PicturePtr ppict, int op, int component_alpha)
764{
765	NVC0EXA_LOCALS(ppix);
766	struct nvc0_blend_op *b = &NVC0EXABlendOp[op];
767	unsigned sblend = b->src_blend;
768	unsigned dblend = b->dst_blend;
769
770	if (b->dst_alpha) {
771		if (!PICT_FORMAT_A(ppict->format)) {
772			if (sblend == BF(DST_ALPHA))
773				sblend = BF(ONE);
774			else
775			if (sblend == BF(ONE_MINUS_DST_ALPHA))
776				sblend = BF(ZERO);
777		}
778	}
779
780	if (b->src_alpha && component_alpha) {
781		if (dblend == BF(SRC_ALPHA))
782			dblend = BF(SRC_COLOR);
783		else
784		if (dblend == BF(ONE_MINUS_SRC_ALPHA))
785			dblend = BF(ONE_MINUS_SRC_COLOR);
786	}
787
788	if (sblend == BF(ONE) && dblend == BF(ZERO)) {
789		BEGIN_NVC0(push, NVC0_3D(BLEND_ENABLE(0)), 1);
790		PUSH_DATA (push, 0);
791	} else {
792		BEGIN_NVC0(push, NVC0_3D(BLEND_ENABLE(0)), 1);
793		PUSH_DATA (push, 1);
794		BEGIN_NVC0(push, NVC0_3D(BLEND_EQUATION_RGB), 5);
795		PUSH_DATA (push, NVC0_3D_BLEND_EQUATION_RGB_FUNC_ADD);
796		PUSH_DATA (push, sblend);
797		PUSH_DATA (push, dblend);
798		PUSH_DATA (push, NVC0_3D_BLEND_EQUATION_ALPHA_FUNC_ADD);
799		PUSH_DATA (push, sblend);
800		BEGIN_NVC0(push, NVC0_3D(BLEND_FUNC_DST_ALPHA), 1);
801		PUSH_DATA (push, dblend);
802	}
803}
804
805Bool
806NVC0EXACheckComposite(int op,
807		      PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict)
808{
809	if (!NVC0EXACheckBlend(op))
810		NOUVEAU_FALLBACK("blend not supported\n");
811
812	if (!NVC0EXACheckRenderTarget(pdpict))
813		NOUVEAU_FALLBACK("render target invalid\n");
814
815	if (!NVC0EXACheckTexture(pspict, pdpict, op))
816		NOUVEAU_FALLBACK("src picture invalid\n");
817
818	if (pmpict) {
819		if (pmpict->componentAlpha &&
820		    PICT_FORMAT_RGB(pmpict->format) &&
821		    NVC0EXABlendOp[op].src_alpha &&
822		    NVC0EXABlendOp[op].src_blend != BF(ZERO))
823			NOUVEAU_FALLBACK("component-alpha not supported\n");
824
825		if (!NVC0EXACheckTexture(pmpict, pdpict, op))
826			NOUVEAU_FALLBACK("mask picture invalid\n");
827	}
828
829	return TRUE;
830}
831
832Bool
833NVC0EXAPrepareComposite(int op,
834			PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict,
835			PixmapPtr pspix, PixmapPtr pmpix, PixmapPtr pdpix)
836{
837	struct nouveau_bo *dst = nouveau_pixmap_bo(pdpix);
838	NVC0EXA_LOCALS(pdpix);
839
840	if (!PUSH_SPACE(push, 256))
841		NOUVEAU_FALLBACK("space\n");
842
843	BEGIN_NVC0(push, SUBC_2D(NV50_GRAPH_SERIALIZE), 1);
844	PUSH_DATA (push, 0);
845
846	if (!NVC0EXARenderTarget(pdpix, pdpict))
847		NOUVEAU_FALLBACK("render target invalid\n");
848
849	NVC0EXABlend(pdpix, pdpict, op, pmpict && pmpict->componentAlpha &&
850		     PICT_FORMAT_RGB(pmpict->format));
851
852	if (!NVC0EXAPicture(pNv, pspix, pspict, 0))
853		NOUVEAU_FALLBACK("src picture invalid\n");
854
855	if (pmpict) {
856		if (!NVC0EXAPicture(pNv, pmpix, pmpict, 1))
857			NOUVEAU_FALLBACK("mask picture invalid\n");
858
859		BEGIN_NVC0(push, NVC0_3D(SP_START_ID(5)), 1);
860		if (pdpict->format == PICT_a8) {
861			PUSH_DATA (push, PFP_C_A8);
862		} else {
863			if (pmpict->componentAlpha &&
864			    PICT_FORMAT_RGB(pmpict->format)) {
865				if (NVC0EXABlendOp[op].src_alpha)
866					PUSH_DATA (push, PFP_CCASA);
867				else
868					PUSH_DATA (push, PFP_CCA);
869			} else {
870				PUSH_DATA (push, PFP_C);
871			}
872		}
873	} else {
874		BEGIN_NVC0(push, NVC0_3D(SP_START_ID(5)), 1);
875		if (pdpict->format == PICT_a8)
876			PUSH_DATA (push, PFP_S_A8);
877		else
878			PUSH_DATA (push, PFP_S);
879	}
880
881	BEGIN_NVC0(push, NVC0_3D(TSC_FLUSH), 1);
882	PUSH_DATA (push, 0);
883	BEGIN_NVC0(push, NVC0_3D(TIC_FLUSH), 1);
884	PUSH_DATA (push, 0);
885	BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
886	PUSH_DATA (push, 0);
887
888	PUSH_RESET(push);
889	PUSH_REFN (push, pNv->scratch, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
890	if (pspict->pDrawable)
891		PUSH_REFN (push, nouveau_pixmap_bo(pspix),
892			   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
893	PUSH_REFN (push, dst, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
894	if (pmpict && pmpict->pDrawable)
895		PUSH_REFN (push, nouveau_pixmap_bo(pmpix),
896			   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
897
898	nouveau_pushbuf_bufctx(push, pNv->bufctx);
899	if (nouveau_pushbuf_validate(push)) {
900		nouveau_pushbuf_bufctx(push, NULL);
901		NOUVEAU_FALLBACK("validate\n");
902	}
903
904	return TRUE;
905}
906
907void
908NVC0EXAComposite(PixmapPtr pdpix,
909		 int sx, int sy, int mx, int my,
910		 int dx, int dy, int w, int h)
911{
912	NVC0EXA_LOCALS(pdpix);
913
914	if (!PUSH_SPACE(push, 64))
915		return;
916
917	BEGIN_NVC0(push, NVC0_3D(SCISSOR_HORIZ(0)), 2);
918	PUSH_DATA (push, ((dx + w) << 16) | dx);
919	PUSH_DATA (push, ((dy + h) << 16) | dy);
920	BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
921	PUSH_DATA (push, NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES);
922	PUSH_VTX2s(push, sx, sy + (h * 2), mx, my + (h * 2), dx, dy + (h * 2));
923	PUSH_VTX2s(push, sx, sy, mx, my, dx, dy);
924	PUSH_VTX2s(push, sx + (w * 2), sy, mx + (w * 2), my, dx + (w * 2), dy);
925	BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 1);
926	PUSH_DATA (push, 0);
927}
928
929void
930NVC0EXADoneComposite(PixmapPtr pdpix)
931{
932	NVC0EXA_LOCALS(pdpix);
933	nouveau_pushbuf_bufctx(push, NULL);
934}
935
936Bool
937NVC0EXARectM2MF(NVPtr pNv, int w, int h, int cpp,
938		struct nouveau_bo *src, uint32_t src_off, int src_dom,
939		int src_pitch, int src_h, int src_x, int src_y,
940		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
941		int dst_pitch, int dst_h, int dst_x, int dst_y)
942{
943	struct nouveau_pushbuf_refn refs[] = {
944		{ src, src_dom | NOUVEAU_BO_RD },
945		{ dst, dst_dom | NOUVEAU_BO_WR },
946	};
947	struct nouveau_pushbuf *push = pNv->pushbuf;
948	unsigned exec = 0;
949
950	if (!PUSH_SPACE(push, 64))
951		return FALSE;
952
953	if (src->config.nvc0.memtype) {
954		BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_IN), 5);
955		PUSH_DATA (push, src->config.nvc0.tile_mode);
956		PUSH_DATA (push, src_pitch);
957		PUSH_DATA (push, src_h);
958		PUSH_DATA (push, 1);
959		PUSH_DATA (push, 0);
960	} else {
961		BEGIN_NVC0(push, NVC0_M2MF(PITCH_IN), 1);
962		PUSH_DATA (push, src_pitch);
963
964		src_off += src_y * src_pitch + src_x * cpp;
965		exec |= NVC0_M2MF_EXEC_LINEAR_IN;
966	}
967
968	if (dst->config.nvc0.memtype) {
969		BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_OUT), 5);
970		PUSH_DATA (push, dst->config.nvc0.tile_mode);
971		PUSH_DATA (push, dst_pitch);
972		PUSH_DATA (push, dst_h);
973		PUSH_DATA (push, 1);
974		PUSH_DATA (push, 0);
975	} else {
976		BEGIN_NVC0(push, NVC0_M2MF(PITCH_OUT), 1);
977		PUSH_DATA (push, dst_pitch);
978
979		dst_off += dst_y * dst_pitch + dst_x * cpp;
980		exec |= NVC0_M2MF_EXEC_LINEAR_OUT;
981	}
982
983	while (h) {
984		int line_count = h;
985		if (line_count > 2047)
986			line_count = 2047;
987
988		if (nouveau_pushbuf_space(push, 32, 0, 0) ||
989		    nouveau_pushbuf_refn (push, refs, 2))
990			return FALSE;
991
992		BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
993		PUSH_DATA (push, (dst->offset + dst_off) >> 32);
994		PUSH_DATA (push, (dst->offset + dst_off));
995		BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);
996		PUSH_DATA (push, (src->offset + src_off) >> 32);
997		PUSH_DATA (push, (src->offset + src_off));
998
999		if (src->config.nvc0.memtype) {
1000			BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_IN_X), 2);
1001			PUSH_DATA (push, src_x * cpp);
1002			PUSH_DATA (push, src_y);
1003		} else {
1004			src_off += line_count * src_pitch;
1005		}
1006
1007		if (dst->config.nvc0.memtype) {
1008			BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_OUT_X), 2);
1009			PUSH_DATA (push, dst_x * cpp);
1010			PUSH_DATA (push, dst_y);
1011		} else {
1012			dst_off += line_count * dst_pitch;
1013		}
1014
1015		BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
1016		PUSH_DATA (push, w * cpp);
1017		PUSH_DATA (push, line_count);
1018		BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
1019		PUSH_DATA (push, NVC0_M2MF_EXEC_QUERY_SHORT | exec);
1020
1021		src_y += line_count;
1022		dst_y += line_count;
1023		h  -= line_count;
1024	}
1025
1026	return TRUE;
1027}
1028
1029Bool
1030NVE0EXARectCopy(NVPtr pNv, int w, int h, int cpp,
1031		struct nouveau_bo *src, uint32_t src_off, int src_dom,
1032		int src_pitch, int src_h, int src_x, int src_y,
1033		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
1034		int dst_pitch, int dst_h, int dst_x, int dst_y)
1035{
1036	return nouveau_copya0b5_rect(pNv->pushbuf, pNv->NvCOPY, w, h, cpp,
1037				     src, src_off, src_dom, src_pitch,
1038				     src_h, src_x, src_y, dst, dst_off,
1039				     dst_dom, dst_pitch, dst_h, dst_x, dst_y);
1040}
1041