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