nvc0_exa.c revision fda9279d
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, SUBC_2D(0x088c), 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
578	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
579	if (!nv50_style_tiled_pixmap(ppix))
580		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
581
582	PUSH_REFN (push, bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
583	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET + (unit * 32), 8);
584	switch (ppict->format) {
585	case PICT_a8r8g8b8:
586		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8));
587		break;
588	case PICT_a8b8g8r8:
589		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_C3, 8_8_8_8));
590		break;
591	case PICT_x8r8g8b8:
592		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_ONE, 8_8_8_8));
593		break;
594	case PICT_x8b8g8r8:
595		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_ONE, 8_8_8_8));
596		break;
597	case PICT_r5g6b5:
598		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_ONE, 5_6_5));
599		break;
600	case PICT_a8:
601		PUSH_DATA (push, _(A_C0, B_ZERO, G_ZERO, R_ZERO, 8));
602		break;
603	case PICT_x1r5g5b5:
604		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_ONE, 1_5_5_5));
605		break;
606	case PICT_x1b5g5r5:
607		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_ONE, 1_5_5_5));
608		break;
609	case PICT_a1r5g5b5:
610		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 1_5_5_5));
611		break;
612	case PICT_a1b5g5r5:
613		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_C3, 1_5_5_5));
614		break;
615	case PICT_b5g6r5:
616		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_ONE, 5_6_5));
617		break;
618	case PICT_b8g8r8x8:
619		PUSH_DATA (push, _(A_ONE, R_C1, G_C2, B_C3, 8_8_8_8));
620		break;
621	case PICT_b8g8r8a8:
622		PUSH_DATA (push, _(A_C0, R_C1, G_C2, B_C3, 8_8_8_8));
623		break;
624	case PICT_a2b10g10r10:
625		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_C3, 2_10_10_10));
626		break;
627	case PICT_x2b10g10r10:
628		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_ONE, 2_10_10_10));
629		break;
630	case PICT_x2r10g10b10:
631		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_ONE, 2_10_10_10));
632		break;
633	case PICT_a2r10g10b10:
634		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 2_10_10_10));
635		break;
636	case PICT_x4r4g4b4:
637		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_ONE, 4_4_4_4));
638		break;
639	case PICT_x4b4g4r4:
640		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_ONE, 4_4_4_4));
641		break;
642	case PICT_a4r4g4b4:
643		PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 4_4_4_4));
644		break;
645	case PICT_a4b4g4r4:
646		PUSH_DATA (push, _(R_C0, G_C1, B_C2, A_C3, 4_4_4_4));
647		break;
648	default:
649		NOUVEAU_FALLBACK("invalid picture format, this SHOULD NOT HAPPEN. Expect trouble.\n");
650	}
651#undef _
652
653	PUSH_DATA (push, bo->offset);
654	PUSH_DATA (push, (bo->offset >> 32) |
655			 (bo->config.nvc0.tile_mode << 18) |
656			 0xd0005000);
657	PUSH_DATA (push, 0x00300000);
658	PUSH_DATA (push, (1 << 31) | ppix->drawable.width);
659	PUSH_DATA (push, (1 << 16) | ppix->drawable.height);
660	PUSH_DATA (push, 0x03000000);
661	PUSH_DATA (push, 0x00000000);
662
663	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET + (unit * 32), 8);
664	if (ppict->repeat) {
665		switch (ppict->repeatType) {
666		case RepeatPad:
667			PUSH_DATA (push, 0x00024000 |
668					 NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
669					 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
670					 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
671			break;
672		case RepeatReflect:
673			PUSH_DATA (push, 0x00024000 |
674					 NV50TSC_1_0_WRAPS_MIRROR_REPEAT |
675					 NV50TSC_1_0_WRAPT_MIRROR_REPEAT |
676					 NV50TSC_1_0_WRAPR_MIRROR_REPEAT);
677			break;
678		case RepeatNormal:
679		default:
680			PUSH_DATA (push, 0x00024000 |
681					 NV50TSC_1_0_WRAPS_REPEAT |
682					 NV50TSC_1_0_WRAPT_REPEAT |
683					 NV50TSC_1_0_WRAPR_REPEAT);
684			break;
685		}
686	} else {
687		PUSH_DATA (push, 0x00024000 |
688				 NV50TSC_1_0_WRAPS_CLAMP_TO_BORDER |
689				 NV50TSC_1_0_WRAPT_CLAMP_TO_BORDER |
690				 NV50TSC_1_0_WRAPR_CLAMP_TO_BORDER);
691	}
692	if (ppict->filter == PictFilterBilinear) {
693		PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR |
694				 NV50TSC_1_1_MINF_LINEAR |
695				 NV50TSC_1_1_MIPF_NONE);
696	} else {
697		PUSH_DATA (push, NV50TSC_1_1_MAGF_NEAREST |
698				 NV50TSC_1_1_MINF_NEAREST |
699				 NV50TSC_1_1_MIPF_NONE);
700	}
701	PUSH_DATA (push, 0x00000000);
702	PUSH_DATA (push, 0x00000000);
703	PUSH_DATA (push, 0x00000000);
704	PUSH_DATA (push, 0x00000000);
705	PUSH_DATA (push, 0x00000000);
706	PUSH_DATA (push, 0x00000000);
707
708	PUSH_DATAu(push, pNv->scratch, PVP_DATA + (unit * 11 * 4), 11);
709	if (ppict->transform) {
710		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][0]));
711		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][1]));
712		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][2]));
713		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][0]));
714		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][1]));
715		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][2]));
716		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][0]));
717		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][1]));
718		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][2]));
719	} else {
720		PUSH_DATAf(push, 1.0);
721		PUSH_DATAf(push, 0.0);
722		PUSH_DATAf(push, 0.0);
723		PUSH_DATAf(push, 0.0);
724		PUSH_DATAf(push, 1.0);
725		PUSH_DATAf(push, 0.0);
726		PUSH_DATAf(push, 0.0);
727		PUSH_DATAf(push, 0.0);
728		PUSH_DATAf(push, 1.0);
729	}
730	PUSH_DATAf(push, 1.0 / ppix->drawable.width);
731	PUSH_DATAf(push, 1.0 / ppix->drawable.height);
732	return TRUE;
733}
734
735static Bool
736NVC0EXAPicture(NVPtr pNv, PixmapPtr ppix, PicturePtr ppict, int unit)
737{
738	if (ppict->pDrawable)
739		return NVC0EXAPictTexture(pNv, ppix, ppict, unit);
740
741	switch (ppict->pSourcePict->type) {
742	case SourcePictTypeSolidFill:
743		return NVC0EXAPictSolid(pNv, ppict, unit);
744	case SourcePictTypeLinear:
745		return NVC0EXAPictGradient(pNv, ppict, unit);
746	default:
747		break;
748	}
749
750	return FALSE;
751}
752static Bool
753NVC0EXACheckBlend(int op)
754{
755	if (op > PictOpAdd)
756		NOUVEAU_FALLBACK("unsupported blend op %d\n", op);
757	return TRUE;
758}
759
760static void
761NVC0EXABlend(PixmapPtr ppix, PicturePtr ppict, int op, int component_alpha)
762{
763	NVC0EXA_LOCALS(ppix);
764	struct nvc0_blend_op *b = &NVC0EXABlendOp[op];
765	unsigned sblend = b->src_blend;
766	unsigned dblend = b->dst_blend;
767
768	if (b->dst_alpha) {
769		if (!PICT_FORMAT_A(ppict->format)) {
770			if (sblend == BF(DST_ALPHA))
771				sblend = BF(ONE);
772			else
773			if (sblend == BF(ONE_MINUS_DST_ALPHA))
774				sblend = BF(ZERO);
775		}
776	}
777
778	if (b->src_alpha && component_alpha) {
779		if (dblend == BF(SRC_ALPHA))
780			dblend = BF(SRC_COLOR);
781		else
782		if (dblend == BF(ONE_MINUS_SRC_ALPHA))
783			dblend = BF(ONE_MINUS_SRC_COLOR);
784	}
785
786	if (sblend == BF(ONE) && dblend == BF(ZERO)) {
787		BEGIN_NVC0(push, NVC0_3D(BLEND_ENABLE(0)), 1);
788		PUSH_DATA (push, 0);
789	} else {
790		BEGIN_NVC0(push, NVC0_3D(BLEND_ENABLE(0)), 1);
791		PUSH_DATA (push, 1);
792		BEGIN_NVC0(push, NVC0_3D(BLEND_EQUATION_RGB), 5);
793		PUSH_DATA (push, NVC0_3D_BLEND_EQUATION_RGB_FUNC_ADD);
794		PUSH_DATA (push, sblend);
795		PUSH_DATA (push, dblend);
796		PUSH_DATA (push, NVC0_3D_BLEND_EQUATION_ALPHA_FUNC_ADD);
797		PUSH_DATA (push, sblend);
798		BEGIN_NVC0(push, NVC0_3D(BLEND_FUNC_DST_ALPHA), 1);
799		PUSH_DATA (push, dblend);
800	}
801}
802
803Bool
804NVC0EXACheckComposite(int op,
805		      PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict)
806{
807	if (!NVC0EXACheckBlend(op))
808		NOUVEAU_FALLBACK("blend not supported\n");
809
810	if (!NVC0EXACheckRenderTarget(pdpict))
811		NOUVEAU_FALLBACK("render target invalid\n");
812
813	if (!NVC0EXACheckTexture(pspict, pdpict, op))
814		NOUVEAU_FALLBACK("src picture invalid\n");
815
816	if (pmpict) {
817		if (pmpict->componentAlpha &&
818		    PICT_FORMAT_RGB(pmpict->format) &&
819		    NVC0EXABlendOp[op].src_alpha &&
820		    NVC0EXABlendOp[op].src_blend != BF(ZERO))
821			NOUVEAU_FALLBACK("component-alpha not supported\n");
822
823		if (!NVC0EXACheckTexture(pmpict, pdpict, op))
824			NOUVEAU_FALLBACK("mask picture invalid\n");
825	}
826
827	return TRUE;
828}
829
830Bool
831NVC0EXAPrepareComposite(int op,
832			PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict,
833			PixmapPtr pspix, PixmapPtr pmpix, PixmapPtr pdpix)
834{
835	struct nouveau_bo *dst = nouveau_pixmap_bo(pdpix);
836	NVC0EXA_LOCALS(pdpix);
837
838	if (!PUSH_SPACE(push, 256))
839		NOUVEAU_FALLBACK("space\n");
840
841	BEGIN_NVC0(push, SUBC_2D(NV50_GRAPH_SERIALIZE), 1);
842	PUSH_DATA (push, 0);
843
844	if (!NVC0EXARenderTarget(pdpix, pdpict))
845		NOUVEAU_FALLBACK("render target invalid\n");
846
847	NVC0EXABlend(pdpix, pdpict, op, pmpict && pmpict->componentAlpha &&
848		     PICT_FORMAT_RGB(pmpict->format));
849
850	if (!NVC0EXAPicture(pNv, pspix, pspict, 0))
851		NOUVEAU_FALLBACK("src picture invalid\n");
852
853	if (pmpict) {
854		if (!NVC0EXAPicture(pNv, pmpix, pmpict, 1))
855			NOUVEAU_FALLBACK("mask picture invalid\n");
856
857		BEGIN_NVC0(push, NVC0_3D(SP_START_ID(5)), 1);
858		if (pdpict->format == PICT_a8) {
859			PUSH_DATA (push, PFP_C_A8);
860		} else {
861			if (pmpict->componentAlpha &&
862			    PICT_FORMAT_RGB(pmpict->format)) {
863				if (NVC0EXABlendOp[op].src_alpha)
864					PUSH_DATA (push, PFP_CCASA);
865				else
866					PUSH_DATA (push, PFP_CCA);
867			} else {
868				PUSH_DATA (push, PFP_C);
869			}
870		}
871	} else {
872		BEGIN_NVC0(push, NVC0_3D(SP_START_ID(5)), 1);
873		if (pdpict->format == PICT_a8)
874			PUSH_DATA (push, PFP_S_A8);
875		else
876			PUSH_DATA (push, PFP_S);
877	}
878
879	BEGIN_NVC0(push, NVC0_3D(TSC_FLUSH), 1);
880	PUSH_DATA (push, 0);
881	BEGIN_NVC0(push, NVC0_3D(TIC_FLUSH), 1);
882	PUSH_DATA (push, 0);
883	BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
884	PUSH_DATA (push, 0);
885
886	PUSH_RESET(push);
887	PUSH_REFN (push, pNv->scratch, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
888	if (pspict->pDrawable)
889		PUSH_REFN (push, nouveau_pixmap_bo(pspix),
890			   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
891	PUSH_REFN (push, dst, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
892	if (pmpict && pmpict->pDrawable)
893		PUSH_REFN (push, nouveau_pixmap_bo(pmpix),
894			   NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
895
896	nouveau_pushbuf_bufctx(push, pNv->bufctx);
897	if (nouveau_pushbuf_validate(push)) {
898		nouveau_pushbuf_bufctx(push, NULL);
899		NOUVEAU_FALLBACK("validate\n");
900	}
901
902	return TRUE;
903}
904
905void
906NVC0EXAComposite(PixmapPtr pdpix,
907		 int sx, int sy, int mx, int my,
908		 int dx, int dy, int w, int h)
909{
910	NVC0EXA_LOCALS(pdpix);
911
912	if (!PUSH_SPACE(push, 64))
913		return;
914
915	BEGIN_NVC0(push, NVC0_3D(SCISSOR_HORIZ(0)), 2);
916	PUSH_DATA (push, ((dx + w) << 16) | dx);
917	PUSH_DATA (push, ((dy + h) << 16) | dy);
918	BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
919	PUSH_DATA (push, NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES);
920	PUSH_VTX2s(push, sx, sy + (h * 2), mx, my + (h * 2), dx, dy + (h * 2));
921	PUSH_VTX2s(push, sx, sy, mx, my, dx, dy);
922	PUSH_VTX2s(push, sx + (w * 2), sy, mx + (w * 2), my, dx + (w * 2), dy);
923	BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 1);
924	PUSH_DATA (push, 0);
925}
926
927void
928NVC0EXADoneComposite(PixmapPtr pdpix)
929{
930	NVC0EXA_LOCALS(pdpix);
931	nouveau_pushbuf_bufctx(push, NULL);
932}
933
934Bool
935NVC0EXARectM2MF(NVPtr pNv, int w, int h, int cpp,
936		struct nouveau_bo *src, uint32_t src_off, int src_dom,
937		int src_pitch, int src_h, int src_x, int src_y,
938		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
939		int dst_pitch, int dst_h, int dst_x, int dst_y)
940{
941	struct nouveau_pushbuf_refn refs[] = {
942		{ src, src_dom | NOUVEAU_BO_RD },
943		{ dst, dst_dom | NOUVEAU_BO_WR },
944	};
945	struct nouveau_pushbuf *push = pNv->pushbuf;
946	unsigned exec = 0;
947
948	if (!PUSH_SPACE(push, 64))
949		return FALSE;
950
951	if (src->config.nvc0.memtype) {
952		BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_IN), 5);
953		PUSH_DATA (push, src->config.nvc0.tile_mode);
954		PUSH_DATA (push, src_pitch);
955		PUSH_DATA (push, src_h);
956		PUSH_DATA (push, 1);
957		PUSH_DATA (push, 0);
958	} else {
959		BEGIN_NVC0(push, NVC0_M2MF(PITCH_IN), 1);
960		PUSH_DATA (push, src_pitch);
961
962		src_off += src_y * src_pitch + src_x * cpp;
963		exec |= NVC0_M2MF_EXEC_LINEAR_IN;
964	}
965
966	if (dst->config.nvc0.memtype) {
967		BEGIN_NVC0(push, NVC0_M2MF(TILING_MODE_OUT), 5);
968		PUSH_DATA (push, dst->config.nvc0.tile_mode);
969		PUSH_DATA (push, dst_pitch);
970		PUSH_DATA (push, dst_h);
971		PUSH_DATA (push, 1);
972		PUSH_DATA (push, 0);
973	} else {
974		BEGIN_NVC0(push, NVC0_M2MF(PITCH_OUT), 1);
975		PUSH_DATA (push, dst_pitch);
976
977		dst_off += dst_y * dst_pitch + dst_x * cpp;
978		exec |= NVC0_M2MF_EXEC_LINEAR_OUT;
979	}
980
981	while (h) {
982		int line_count = h;
983		if (line_count > 2047)
984			line_count = 2047;
985
986		if (nouveau_pushbuf_space(push, 32, 0, 0) ||
987		    nouveau_pushbuf_refn (push, refs, 2))
988			return FALSE;
989
990		BEGIN_NVC0(push, NVC0_M2MF(OFFSET_OUT_HIGH), 2);
991		PUSH_DATA (push, (dst->offset + dst_off) >> 32);
992		PUSH_DATA (push, (dst->offset + dst_off));
993		BEGIN_NVC0(push, NVC0_M2MF(OFFSET_IN_HIGH), 2);
994		PUSH_DATA (push, (src->offset + src_off) >> 32);
995		PUSH_DATA (push, (src->offset + src_off));
996
997		if (src->config.nvc0.memtype) {
998			BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_IN_X), 2);
999			PUSH_DATA (push, src_x * cpp);
1000			PUSH_DATA (push, src_y);
1001		} else {
1002			src_off += line_count * src_pitch;
1003		}
1004
1005		if (dst->config.nvc0.memtype) {
1006			BEGIN_NVC0(push, NVC0_M2MF(TILING_POSITION_OUT_X), 2);
1007			PUSH_DATA (push, dst_x * cpp);
1008			PUSH_DATA (push, dst_y);
1009		} else {
1010			dst_off += line_count * dst_pitch;
1011		}
1012
1013		BEGIN_NVC0(push, NVC0_M2MF(LINE_LENGTH_IN), 2);
1014		PUSH_DATA (push, w * cpp);
1015		PUSH_DATA (push, line_count);
1016		BEGIN_NVC0(push, NVC0_M2MF(EXEC), 1);
1017		PUSH_DATA (push, NVC0_M2MF_EXEC_QUERY_SHORT | exec);
1018
1019		src_y += line_count;
1020		dst_y += line_count;
1021		h  -= line_count;
1022	}
1023
1024	return TRUE;
1025}
1026
1027Bool
1028NVE0EXARectCopy(NVPtr pNv, int w, int h, int cpp,
1029		struct nouveau_bo *src, uint32_t src_off, int src_dom,
1030		int src_pitch, int src_h, int src_x, int src_y,
1031		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
1032		int dst_pitch, int dst_h, int dst_x, int dst_y)
1033{
1034	return nouveau_copya0b5_rect(pNv->pushbuf, pNv->NvCOPY, w, h, cpp,
1035				     src, src_off, src_dom, src_pitch,
1036				     src_h, src_x, src_y, dst, dst_off,
1037				     dst_dom, dst_pitch, dst_h, dst_x, dst_y);
1038}
1039