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
27#include "nv50_accel.h"
28
29#define NV50EXA_LOCALS(p)                                                      \
30	ScrnInfoPtr pScrn = xf86ScreenToScrn((p)->drawable.pScreen);         \
31	NVPtr pNv = NVPTR(pScrn);                                              \
32	struct nouveau_pushbuf *push = pNv->pushbuf; (void)push;
33
34#define BF(f) NV50_BLEND_FACTOR_##f
35
36struct nv50_blend_op {
37	unsigned src_alpha;
38	unsigned dst_alpha;
39	unsigned src_blend;
40	unsigned dst_blend;
41};
42
43static struct nv50_blend_op
44NV50EXABlendOp[] = {
45/* Clear       */ { 0, 0, BF(               ZERO), BF(               ZERO) },
46/* Src         */ { 0, 0, BF(                ONE), BF(               ZERO) },
47/* Dst         */ { 0, 0, BF(               ZERO), BF(                ONE) },
48/* Over        */ { 1, 0, BF(                ONE), BF(ONE_MINUS_SRC_ALPHA) },
49/* OverReverse */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(                ONE) },
50/* In          */ { 0, 1, BF(          DST_ALPHA), BF(               ZERO) },
51/* InReverse   */ { 1, 0, BF(               ZERO), BF(          SRC_ALPHA) },
52/* Out         */ { 0, 1, BF(ONE_MINUS_DST_ALPHA), BF(               ZERO) },
53/* OutReverse  */ { 1, 0, BF(               ZERO), BF(ONE_MINUS_SRC_ALPHA) },
54/* Atop        */ { 1, 1, BF(          DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
55/* AtopReverse */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(          SRC_ALPHA) },
56/* Xor         */ { 1, 1, BF(ONE_MINUS_DST_ALPHA), BF(ONE_MINUS_SRC_ALPHA) },
57/* Add         */ { 0, 0, BF(                ONE), BF(                ONE) },
58};
59
60static Bool
61NV50EXA2DSurfaceFormat(PixmapPtr ppix, uint32_t *fmt)
62{
63	NV50EXA_LOCALS(ppix);
64
65	switch (ppix->drawable.bitsPerPixel) {
66	case 8 : *fmt = NV50_SURFACE_FORMAT_R8_UNORM; break;
67	case 15: *fmt = NV50_SURFACE_FORMAT_BGR5_X1_UNORM; break;
68	case 16: *fmt = NV50_SURFACE_FORMAT_B5G6R5_UNORM; break;
69	case 24: *fmt = NV50_SURFACE_FORMAT_BGRX8_UNORM; break;
70	case 30: *fmt = NV50_SURFACE_FORMAT_RGB10_A2_UNORM; break;
71	case 32: *fmt = NV50_SURFACE_FORMAT_BGRA8_UNORM; break;
72	default:
73		 NOUVEAU_FALLBACK("Unknown surface format for bpp=%d\n",
74				  ppix->drawable.bitsPerPixel);
75		 return FALSE;
76	}
77
78	return TRUE;
79}
80
81static void NV50EXASetClip(PixmapPtr ppix, int x, int y, int w, int h)
82{
83	NV50EXA_LOCALS(ppix);
84
85	BEGIN_NV04(push, NV50_2D(CLIP_X), 4);
86	PUSH_DATA (push, x);
87	PUSH_DATA (push, y);
88	PUSH_DATA (push, w);
89	PUSH_DATA (push, h);
90}
91
92static void
93NV50EXAAcquireSurface2D(PixmapPtr ppix, int is_src, uint32_t fmt)
94{
95	NV50EXA_LOCALS(ppix);
96	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
97	struct nouveau_pixmap *nvpix = nouveau_pixmap(ppix);
98	int mthd = is_src ? NV50_2D_SRC_FORMAT : NV50_2D_DST_FORMAT;
99	uint32_t bo_flags;
100
101	bo_flags = nvpix->shared ? NOUVEAU_BO_GART : NOUVEAU_BO_VRAM;
102	bo_flags |= is_src ? NOUVEAU_BO_RD : NOUVEAU_BO_WR;
103
104	if (!nv50_style_tiled_pixmap(ppix)) {
105		BEGIN_NV04(push, SUBC_2D(mthd), 2);
106		PUSH_DATA (push, fmt);
107		PUSH_DATA (push, 1);
108		BEGIN_NV04(push, SUBC_2D(mthd + 0x14), 1);
109		PUSH_DATA (push, (uint32_t)exaGetPixmapPitch(ppix));
110	} else {
111		BEGIN_NV04(push, SUBC_2D(mthd), 5);
112		PUSH_DATA (push, fmt);
113		PUSH_DATA (push, 0);
114		PUSH_DATA (push, bo->config.nv50.tile_mode);
115		PUSH_DATA (push, 1);
116		PUSH_DATA (push, 0);
117	}
118
119	BEGIN_NV04(push, SUBC_2D(mthd + 0x18), 4);
120	PUSH_DATA (push, ppix->drawable.width);
121	PUSH_DATA (push, ppix->drawable.height);
122	PUSH_DATA (push, bo->offset >> 32);
123	PUSH_DATA (push, bo->offset);
124
125	if (is_src == 0)
126		NV50EXASetClip(ppix, 0, 0, ppix->drawable.width, ppix->drawable.height);
127
128	PUSH_REFN (push, bo, bo_flags);
129}
130
131static void
132NV50EXASetPattern(PixmapPtr pdpix, int col0, int col1, int pat0, int pat1)
133{
134	NV50EXA_LOCALS(pdpix);
135
136	BEGIN_NV04(push, NV50_2D(PATTERN_COLOR(0)), 4);
137	PUSH_DATA (push, col0);
138	PUSH_DATA (push, col1);
139	PUSH_DATA (push, pat0);
140	PUSH_DATA (push, pat1);
141}
142
143static void
144NV50EXASetROP(PixmapPtr pdpix, int alu, Pixel planemask)
145{
146	NV50EXA_LOCALS(pdpix);
147	int rop;
148
149	if (planemask != ~0)
150		rop = NVROP[alu].copy_planemask;
151	else
152		rop = NVROP[alu].copy;
153
154	BEGIN_NV04(push, NV50_2D(OPERATION), 1);
155	if (alu == GXcopy && EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
156		PUSH_DATA (push, NV50_2D_OPERATION_SRCCOPY);
157		return;
158	} else {
159		PUSH_DATA (push, NV50_2D_OPERATION_ROP);
160	}
161
162	BEGIN_NV04(push, NV50_2D(PATTERN_COLOR_FORMAT), 2);
163	switch (pdpix->drawable.bitsPerPixel) {
164		case  8: PUSH_DATA (push, 3); break;
165		case 15: PUSH_DATA (push, 1); break;
166		case 16: PUSH_DATA (push, 0); break;
167		case 24:
168		case 32:
169		default:
170			 PUSH_DATA (push, 2);
171			 break;
172	}
173	PUSH_DATA (push, 1);
174
175	/* There are 16 alu's.
176	 * 0-15: copy
177	 * 16-31: copy_planemask
178	 */
179
180	if (!EXA_PM_IS_SOLID(&pdpix->drawable, planemask)) {
181		alu += 16;
182		NV50EXASetPattern(pdpix, 0, planemask, ~0, ~0);
183	} else {
184		if (pNv->currentRop > 15)
185			NV50EXASetPattern(pdpix, ~0, ~0, ~0, ~0);
186	}
187
188	if (pNv->currentRop != alu) {
189		BEGIN_NV04(push, NV50_2D(ROP), 1);
190		PUSH_DATA (push, rop);
191		pNv->currentRop = alu;
192	}
193}
194
195Bool
196NV50EXAPrepareSolid(PixmapPtr pdpix, int alu, Pixel planemask, Pixel fg)
197{
198	NV50EXA_LOCALS(pdpix);
199	uint32_t fmt;
200
201	if (!NV50EXA2DSurfaceFormat(pdpix, &fmt))
202		NOUVEAU_FALLBACK("rect format\n");
203
204	if (!PUSH_SPACE(push, 64))
205		NOUVEAU_FALLBACK("space\n");
206	PUSH_RESET(push);
207
208	NV50EXAAcquireSurface2D(pdpix, 0, fmt);
209	NV50EXASetROP(pdpix, alu, planemask);
210
211	BEGIN_NV04(push, NV50_2D(DRAW_SHAPE), 3);
212	PUSH_DATA (push, NV50_2D_DRAW_SHAPE_RECTANGLES);
213	PUSH_DATA (push, fmt);
214	PUSH_DATA (push, fg);
215
216	nouveau_pushbuf_bufctx(push, pNv->bufctx);
217	if (nouveau_pushbuf_validate(push)) {
218		nouveau_pushbuf_bufctx(push, NULL);
219		NOUVEAU_FALLBACK("validate\n");
220	}
221
222	return TRUE;
223}
224
225void
226NV50EXASolid(PixmapPtr pdpix, int x1, int y1, int x2, int y2)
227{
228	NV50EXA_LOCALS(pdpix);
229
230	if (!PUSH_SPACE(push, 8))
231		return;
232
233	BEGIN_NV04(push, NV50_2D(DRAW_POINT32_X(0)), 4);
234	PUSH_DATA (push, x1);
235	PUSH_DATA (push, y1);
236	PUSH_DATA (push, x2);
237	PUSH_DATA (push, y2);
238
239	if ((x2 - x1) * (y2 - y1) >= 512)
240		PUSH_KICK(push);
241}
242
243void
244NV50EXADoneSolid(PixmapPtr pdpix)
245{
246	NV50EXA_LOCALS(pdpix);
247	nouveau_pushbuf_bufctx(push, NULL);
248}
249
250Bool
251NV50EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
252		   int alu, Pixel planemask)
253{
254	NV50EXA_LOCALS(pdpix);
255	uint32_t src, dst;
256
257	if (!NV50EXA2DSurfaceFormat(pspix, &src))
258		NOUVEAU_FALLBACK("src format\n");
259	if (!NV50EXA2DSurfaceFormat(pdpix, &dst))
260		NOUVEAU_FALLBACK("dst format\n");
261
262	if (!PUSH_SPACE(push, 64))
263		NOUVEAU_FALLBACK("space\n");
264	PUSH_RESET(push);
265
266	NV50EXAAcquireSurface2D(pspix, 1, src);
267	NV50EXAAcquireSurface2D(pdpix, 0, dst);
268	NV50EXASetROP(pdpix, alu, planemask);
269
270	nouveau_pushbuf_bufctx(push, pNv->bufctx);
271	if (nouveau_pushbuf_validate(push)) {
272		nouveau_pushbuf_bufctx(push, NULL);
273		NOUVEAU_FALLBACK("validate\n");
274	}
275
276	return TRUE;
277}
278
279void
280NV50EXACopy(PixmapPtr pdpix, int srcX , int srcY,
281			     int dstX , int dstY,
282			     int width, int height)
283{
284	NV50EXA_LOCALS(pdpix);
285
286	if (!PUSH_SPACE(push, 32))
287		return;
288
289	BEGIN_NV04(push, SUBC_2D(NV50_GRAPH_SERIALIZE), 1);
290	PUSH_DATA (push, 0);
291	BEGIN_NV04(push, NV50_2D(BLIT_CONTROL), 1);
292	PUSH_DATA (push, 0);
293	BEGIN_NV04(push, NV50_2D(BLIT_DST_X), 12);
294	PUSH_DATA (push, dstX);
295	PUSH_DATA (push, dstY);
296	PUSH_DATA (push, width);
297	PUSH_DATA (push, height);
298	PUSH_DATA (push, 0);
299	PUSH_DATA (push, 1);
300	PUSH_DATA (push, 0);
301	PUSH_DATA (push, 1);
302	PUSH_DATA (push, 0);
303	PUSH_DATA (push, srcX);
304	PUSH_DATA (push, 0);
305	PUSH_DATA (push, srcY);
306
307	if (width * height >= 512)
308		PUSH_KICK(push);
309}
310
311void
312NV50EXADoneCopy(PixmapPtr pdpix)
313{
314	NV50EXA_LOCALS(pdpix);
315	nouveau_pushbuf_bufctx(push, NULL);
316}
317
318Bool
319NV50EXAUploadSIFC(const char *src, int src_pitch,
320		  PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
321{
322	NV50EXA_LOCALS(pdpix);
323	ScreenPtr pScreen = pdpix->drawable.pScreen;
324	int line_dwords = (w * cpp + 3) / 4;
325	uint32_t sifc_fmt;
326	Bool ret = FALSE;
327
328	if (!NV50EXA2DSurfaceFormat(pdpix, &sifc_fmt))
329		NOUVEAU_FALLBACK("hostdata format\n");
330
331	if (!PUSH_SPACE(push, 64))
332		NOUVEAU_FALLBACK("space\n");
333	PUSH_RESET(push);
334
335	NV50EXAAcquireSurface2D(pdpix, 0, sifc_fmt);
336	NV50EXASetClip(pdpix, x, y, w, h);
337
338	BEGIN_NV04(push, NV50_2D(OPERATION), 1);
339	PUSH_DATA (push, NV50_2D_OPERATION_SRCCOPY);
340	BEGIN_NV04(push, NV50_2D(SIFC_BITMAP_ENABLE), 2);
341	PUSH_DATA (push, 0);
342	PUSH_DATA (push, sifc_fmt);
343	BEGIN_NV04(push, NV50_2D(SIFC_WIDTH), 10);
344	PUSH_DATA (push, (line_dwords * 4) / cpp);
345	PUSH_DATA (push, h);
346	PUSH_DATA (push, 0);
347	PUSH_DATA (push, 1);
348	PUSH_DATA (push, 0);
349	PUSH_DATA (push, 1);
350	PUSH_DATA (push, 0);
351	PUSH_DATA (push, x);
352	PUSH_DATA (push, 0);
353	PUSH_DATA (push, y);
354
355	nouveau_pushbuf_bufctx(push, pNv->bufctx);
356	if (nouveau_pushbuf_validate(push))
357		goto out;
358
359	while (h--) {
360		int count = line_dwords;
361		const char *p = src;
362
363		while(count) {
364			int size = count > 1792 ? 1792 : count;
365
366			if (!PUSH_SPACE(push, size + 1))
367				goto out;
368			BEGIN_NI04(push, NV50_2D(SIFC_DATA), size);
369			PUSH_DATAp(push, p, size);
370
371			p += size * 4;
372			count -= size;
373		}
374
375		src += src_pitch;
376	}
377
378	ret = TRUE;
379out:
380	nouveau_pushbuf_bufctx(push, NULL);
381	if (pdpix == pScreen->GetScreenPixmap(pScreen))
382		PUSH_KICK(push);
383	return ret;
384}
385
386static Bool
387NV50EXACheckRenderTarget(PicturePtr ppict)
388{
389	if (ppict->pDrawable->width > 8192 ||
390	    ppict->pDrawable->height > 8192)
391		NOUVEAU_FALLBACK("render target dimensions exceeded %dx%d\n",
392				 ppict->pDrawable->width,
393				 ppict->pDrawable->height);
394
395	switch (ppict->format) {
396	case PICT_a8r8g8b8:
397	case PICT_x8r8g8b8:
398	case PICT_r5g6b5:
399	case PICT_a8:
400	case PICT_x1r5g5b5:
401	case PICT_a1r5g5b5:
402	case PICT_x8b8g8r8:
403	case PICT_a2b10g10r10:
404	case PICT_x2b10g10r10:
405	case PICT_a2r10g10b10:
406	case PICT_x2r10g10b10:
407		break;
408	default:
409		NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
410	}
411
412	return TRUE;
413}
414
415static Bool
416NV50EXARenderTarget(PixmapPtr ppix, PicturePtr ppict)
417{
418	NV50EXA_LOCALS(ppix);
419	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
420	unsigned format;
421
422	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
423	if (!nv50_style_tiled_pixmap(ppix))
424		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
425
426	switch (ppict->format) {
427	case PICT_a8r8g8b8: format = NV50_SURFACE_FORMAT_BGRA8_UNORM; break;
428	case PICT_x8r8g8b8: format = NV50_SURFACE_FORMAT_BGRX8_UNORM; break;
429	case PICT_r5g6b5  : format = NV50_SURFACE_FORMAT_B5G6R5_UNORM; break;
430	case PICT_a8      : format = NV50_SURFACE_FORMAT_A8_UNORM; break;
431	case PICT_x1r5g5b5:
432	case PICT_a1r5g5b5:
433		format = NV50_SURFACE_FORMAT_BGR5_A1_UNORM;
434		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	PUSH_REFN (push, bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
449	BEGIN_NV04(push, NV50_3D(RT_ADDRESS_HIGH(0)), 5);
450	PUSH_DATA (push, bo->offset >> 32);
451	PUSH_DATA (push, bo->offset);
452	PUSH_DATA (push, format);
453	PUSH_DATA (push, bo->config.nv50.tile_mode);
454	PUSH_DATA (push, 0x00000000);
455	BEGIN_NV04(push, NV50_3D(RT_HORIZ(0)), 2);
456	PUSH_DATA (push, ppix->drawable.width);
457	PUSH_DATA (push, ppix->drawable.height);
458	BEGIN_NV04(push, NV50_3D(RT_ARRAY_MODE), 1);
459	PUSH_DATA (push, 0x00000001);
460
461	return TRUE;
462}
463
464static Bool
465NV50EXACheckTexture(PicturePtr ppict, PicturePtr pdpict, int op)
466{
467	if (ppict->pDrawable) {
468		if (ppict->pDrawable->width > 8192 ||
469		    ppict->pDrawable->height > 8192)
470			NOUVEAU_FALLBACK("texture too large\n");
471	} else {
472		switch (ppict->pSourcePict->type) {
473		case SourcePictTypeSolidFill:
474			break;
475		default:
476			NOUVEAU_FALLBACK("pict %d\n", ppict->pSourcePict->type);
477			break;
478		}
479	}
480
481	switch (ppict->format) {
482	case PICT_a8r8g8b8:
483	case PICT_a8b8g8r8:
484	case PICT_x8r8g8b8:
485	case PICT_x8b8g8r8:
486	case PICT_r5g6b5:
487	case PICT_a8:
488	case PICT_x1r5g5b5:
489	case PICT_x1b5g5r5:
490	case PICT_a1r5g5b5:
491	case PICT_a1b5g5r5:
492	case PICT_b5g6r5:
493	case PICT_b8g8r8a8:
494	case PICT_b8g8r8x8:
495	case PICT_a2b10g10r10:
496	case PICT_x2b10g10r10:
497	case PICT_x2r10g10b10:
498	case PICT_a2r10g10b10:
499	case PICT_x4r4g4b4:
500	case PICT_x4b4g4r4:
501	case PICT_a4r4g4b4:
502	case PICT_a4b4g4r4:
503		break;
504	default:
505		NOUVEAU_FALLBACK("picture format 0x%08x\n", ppict->format);
506	}
507
508	switch (ppict->filter) {
509	case PictFilterNearest:
510	case PictFilterBilinear:
511		break;
512	default:
513		NOUVEAU_FALLBACK("picture filter %d\n", ppict->filter);
514	}
515
516	/* Opengl and Render disagree on what should be sampled outside an XRGB
517	 * texture (with no repeating). Opengl has a hardcoded alpha value of
518	 * 1.0, while render expects 0.0. We assume that clipping is done for
519	 * untranformed sources.
520	 */
521	if (NV50EXABlendOp[op].src_alpha && !ppict->repeat &&
522		ppict->transform && (PICT_FORMAT_A(ppict->format) == 0)
523		&& (PICT_FORMAT_A(pdpict->format) != 0))
524		NOUVEAU_FALLBACK("REPEAT_NONE unsupported for XRGB source\n");
525
526	return TRUE;
527}
528
529#define _(X1,X2,X3,X4,FMT) (NV50TIC_0_0_TYPER_UNORM | NV50TIC_0_0_TYPEG_UNORM | NV50TIC_0_0_TYPEB_UNORM | NV50TIC_0_0_TYPEA_UNORM | \
530			    NV50TIC_0_0_MAP##X1 | NV50TIC_0_0_MAP##X2 | NV50TIC_0_0_MAP##X3 | NV50TIC_0_0_MAP##X4 | \
531			    NV50TIC_0_0_FMT_##FMT)
532
533static Bool
534NV50EXAPictSolid(NVPtr pNv, PicturePtr ppict, unsigned unit)
535{
536	uint64_t offset = pNv->scratch->offset + SOLID(unit);
537	struct nouveau_pushbuf *push = pNv->pushbuf;
538
539	PUSH_DATAu(push, pNv->scratch, SOLID(unit), 1);
540	PUSH_DATA (push, ppict->pSourcePict->solidFill.color);
541	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET + (unit * 32), 8);
542	PUSH_DATA (push, _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8));
543	PUSH_DATA (push,  offset);
544	PUSH_DATA (push, (offset >> 32) | 0xd005d000);
545	PUSH_DATA (push, 0x00300000);
546	PUSH_DATA (push, 0x00000001);
547	PUSH_DATA (push, 0x00010001);
548	PUSH_DATA (push, 0x03000000);
549	PUSH_DATA (push, 0x00000000);
550	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET + (unit * 32), 8);
551	PUSH_DATA (push, NV50TSC_1_0_WRAPS_REPEAT |
552			 NV50TSC_1_0_WRAPT_REPEAT |
553			 NV50TSC_1_0_WRAPR_REPEAT | 0x00024000);
554	PUSH_DATA (push, NV50TSC_1_1_MAGF_NEAREST |
555			 NV50TSC_1_1_MINF_NEAREST |
556			 NV50TSC_1_1_MIPF_NONE);
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	PUSH_DATA (push, 0x00000000);
563
564	return TRUE;
565}
566
567static Bool
568NV50EXAPictGradient(NVPtr pNv, PicturePtr ppict, unsigned unit)
569{
570	return FALSE;
571}
572
573static Bool
574NV50EXAPictTexture(NVPtr pNv, PixmapPtr ppix, PicturePtr ppict, unsigned unit)
575{
576	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
577	struct nouveau_pushbuf *push = pNv->pushbuf;
578	uint32_t format;
579
580	/*XXX: Scanout buffer not tiled, someone needs to figure it out */
581	if (!nv50_style_tiled_pixmap(ppix))
582		NOUVEAU_FALLBACK("pixmap is scanout buffer\n");
583
584	switch (ppict->format) {
585	case PICT_a8r8g8b8:
586		format = _(B_C0, G_C1, R_C2, A_C3, 8_8_8_8);
587		break;
588	case PICT_a8b8g8r8:
589		format = _(R_C0, G_C1, B_C2, A_C3, 8_8_8_8);
590		break;
591	case PICT_x8r8g8b8:
592		format = _(B_C0, G_C1, R_C2, A_ONE, 8_8_8_8);
593		break;
594	case PICT_x8b8g8r8:
595		format = _(R_C0, G_C1, B_C2, A_ONE, 8_8_8_8);
596		break;
597	case PICT_r5g6b5:
598		format = _(B_C0, G_C1, R_C2, A_ONE, 5_6_5);
599		break;
600	case PICT_a8:
601		format = _(A_C0, B_ZERO, G_ZERO, R_ZERO, 8);
602		break;
603	case PICT_x1r5g5b5:
604		format = _(B_C0, G_C1, R_C2, A_ONE, 1_5_5_5);
605		break;
606	case PICT_x1b5g5r5:
607		format = _(R_C0, G_C1, B_C2, A_ONE, 1_5_5_5);
608		break;
609	case PICT_a1r5g5b5:
610		format = _(B_C0, G_C1, R_C2, A_C3, 1_5_5_5);
611		break;
612	case PICT_a1b5g5r5:
613		format = _(R_C0, G_C1, B_C2, A_C3, 1_5_5_5);
614		break;
615	case PICT_b5g6r5:
616		format = _(R_C0, G_C1, B_C2, A_ONE, 5_6_5);
617		break;
618	case PICT_b8g8r8x8:
619		format = _(A_ONE, R_C1, G_C2, B_C3, 8_8_8_8);
620		break;
621	case PICT_b8g8r8a8:
622		format = _(A_C0, R_C1, G_C2, B_C3, 8_8_8_8);
623		break;
624	case PICT_a2b10g10r10:
625		format = _(R_C0, G_C1, B_C2, A_C3, 2_10_10_10);
626		break;
627	case PICT_x2b10g10r10:
628		format = _(R_C0, G_C1, B_C2, A_ONE, 2_10_10_10);
629		break;
630	case PICT_x2r10g10b10:
631		format = _(B_C0, G_C1, R_C2, A_ONE, 2_10_10_10);
632		break;
633	case PICT_a2r10g10b10:
634		format = _(B_C0, G_C1, R_C2, A_C3, 2_10_10_10);
635		break;
636	case PICT_x4r4g4b4:
637		format = _(B_C0, G_C1, R_C2, A_ONE, 4_4_4_4);
638		break;
639	case PICT_x4b4g4r4:
640		format = _(R_C0, G_C1, B_C2, A_ONE, 4_4_4_4);
641		break;
642	case PICT_a4r4g4b4:
643		format = _(B_C0, G_C1, R_C2, A_C3, 4_4_4_4);
644		break;
645	case PICT_a4b4g4r4:
646		format = _(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_REFN (push, bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
654	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET + (unit * 32), 8);
655	PUSH_DATA (push, format);
656	PUSH_DATA (push, bo->offset);
657	PUSH_DATA (push, (bo->offset >> 32) |
658			 (bo->config.nv50.tile_mode << 18) |
659			 0xd0005000);
660	PUSH_DATA (push, 0x00300000);
661	PUSH_DATA (push, ppix->drawable.width);
662	PUSH_DATA (push, (1 << NV50TIC_0_5_DEPTH_SHIFT) | ppix->drawable.height);
663	PUSH_DATA (push, 0x03000000);
664	PUSH_DATA (push, 0x00000000);
665
666	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET + (unit * 32), 8);
667	if (ppict->repeat) {
668		switch (ppict->repeatType) {
669		case RepeatPad:
670			PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
671				 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
672				 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE | 0x00024000);
673			break;
674		case RepeatReflect:
675			PUSH_DATA (push, NV50TSC_1_0_WRAPS_MIRROR_REPEAT |
676				 NV50TSC_1_0_WRAPT_MIRROR_REPEAT |
677				 NV50TSC_1_0_WRAPR_MIRROR_REPEAT | 0x00024000);
678			break;
679		case RepeatNormal:
680		default:
681			PUSH_DATA (push, NV50TSC_1_0_WRAPS_REPEAT |
682				 NV50TSC_1_0_WRAPT_REPEAT |
683				 NV50TSC_1_0_WRAPR_REPEAT | 0x00024000);
684			break;
685		}
686	} else {
687		PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_BORDER |
688			 NV50TSC_1_0_WRAPT_CLAMP_TO_BORDER |
689			 NV50TSC_1_0_WRAPR_CLAMP_TO_BORDER | 0x00024000);
690	}
691	if (ppict->filter == PictFilterBilinear) {
692		PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR |
693			 NV50TSC_1_1_MINF_LINEAR |
694			 NV50TSC_1_1_MIPF_NONE);
695	} else {
696		PUSH_DATA (push, NV50TSC_1_1_MAGF_NEAREST |
697			 NV50TSC_1_1_MINF_NEAREST |
698			 NV50TSC_1_1_MIPF_NONE);
699	}
700	PUSH_DATA (push, 0x00000000);
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
707	PUSH_DATAu(push, pNv->scratch, PVP_DATA + (unit * 11 * 4), 11);
708	if (ppict->transform) {
709		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][0]));
710		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][1]));
711		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[0][2]));
712		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][0]));
713		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][1]));
714		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[1][2]));
715		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][0]));
716		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][1]));
717		PUSH_DATAf(push, xFixedToFloat(ppict->transform->matrix[2][2]));
718	} else {
719		PUSH_DATAf(push, 1.0);
720		PUSH_DATAf(push, 0.0);
721		PUSH_DATAf(push, 0.0);
722		PUSH_DATAf(push, 0.0);
723		PUSH_DATAf(push, 1.0);
724		PUSH_DATAf(push, 0.0);
725		PUSH_DATAf(push, 0.0);
726		PUSH_DATAf(push, 0.0);
727		PUSH_DATAf(push, 1.0);
728	}
729	PUSH_DATAf(push, 1.0 / ppix->drawable.width);
730	PUSH_DATAf(push, 1.0 / ppix->drawable.height);
731	return TRUE;
732}
733
734static Bool
735NV50EXAPicture(NVPtr pNv, PixmapPtr ppix, PicturePtr ppict, int unit)
736{
737	if (ppict->pDrawable)
738		return NV50EXAPictTexture(pNv, ppix, ppict, unit);
739
740	switch (ppict->pSourcePict->type) {
741	case SourcePictTypeSolidFill:
742		return NV50EXAPictSolid(pNv, ppict, unit);
743	case SourcePictTypeLinear:
744		return NV50EXAPictGradient(pNv, ppict, unit);
745	default:
746		break;
747	}
748
749	return FALSE;
750}
751
752static Bool
753NV50EXACheckBlend(int op)
754{
755	if (op > PictOpAdd)
756		NOUVEAU_FALLBACK("unsupported blend op %d\n", op);
757	return TRUE;
758}
759
760static void
761NV50EXABlend(PixmapPtr ppix, PicturePtr ppict, int op, int component_alpha)
762{
763	NV50EXA_LOCALS(ppix);
764	struct nv50_blend_op *b = &NV50EXABlendOp[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_NV04(push, NV50_3D(BLEND_ENABLE(0)), 1);
788		PUSH_DATA (push, 0);
789	} else {
790		BEGIN_NV04(push, NV50_3D(BLEND_ENABLE(0)), 1);
791		PUSH_DATA (push, 1);
792		BEGIN_NV04(push, NV50_3D(BLEND_EQUATION_RGB), 5);
793		PUSH_DATA (push, NV50_3D_BLEND_EQUATION_RGB_FUNC_ADD);
794		PUSH_DATA (push, sblend);
795		PUSH_DATA (push, dblend);
796		PUSH_DATA (push, NV50_3D_BLEND_EQUATION_ALPHA_FUNC_ADD);
797		PUSH_DATA (push, sblend);
798		BEGIN_NV04(push, NV50_3D(BLEND_FUNC_DST_ALPHA), 1);
799		PUSH_DATA (push, dblend);
800	}
801}
802
803Bool
804NV50EXACheckComposite(int op,
805		      PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict)
806{
807	if (!NV50EXACheckBlend(op))
808		NOUVEAU_FALLBACK("blend not supported\n");
809
810	if (!NV50EXACheckRenderTarget(pdpict))
811		NOUVEAU_FALLBACK("render target invalid\n");
812
813	if (!NV50EXACheckTexture(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		    NV50EXABlendOp[op].src_alpha &&
820		    NV50EXABlendOp[op].src_blend != BF(ZERO))
821			NOUVEAU_FALLBACK("component-alpha not supported\n");
822
823		if (!NV50EXACheckTexture(pmpict, pdpict, op))
824			NOUVEAU_FALLBACK("mask picture invalid\n");
825	}
826
827	return TRUE;
828}
829
830Bool
831NV50EXAPrepareComposite(int op,
832			PicturePtr pspict, PicturePtr pmpict, PicturePtr pdpict,
833			PixmapPtr pspix, PixmapPtr pmpix, PixmapPtr pdpix)
834{
835	NV50EXA_LOCALS(pdpix);
836
837	if (!PUSH_SPACE(push, 256))
838		NOUVEAU_FALLBACK("space\n");
839	PUSH_RESET(push);
840	PUSH_REFN (push, pNv->scratch, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR);
841
842	BEGIN_NV04(push, SUBC_2D(NV50_GRAPH_SERIALIZE), 1);
843	PUSH_DATA (push, 0);
844
845	if (!NV50EXARenderTarget(pdpix, pdpict))
846		NOUVEAU_FALLBACK("render target invalid\n");
847
848	NV50EXABlend(pdpix, pdpict, op, pmpict && pmpict->componentAlpha &&
849		     PICT_FORMAT_RGB(pmpict->format));
850
851	if (!NV50EXAPicture(pNv, pspix, pspict, 0))
852		NOUVEAU_FALLBACK("src picture invalid\n");
853
854	if (pmpict) {
855		if (!NV50EXAPicture(pNv, pmpix, pmpict, 1))
856			NOUVEAU_FALLBACK("mask picture invalid\n");
857
858		BEGIN_NV04(push, NV50_3D(FP_START_ID), 1);
859		if (pdpict->format == PICT_a8) {
860			PUSH_DATA (push, PFP_C_A8);
861		} else {
862			if (pmpict->componentAlpha &&
863			    PICT_FORMAT_RGB(pmpict->format)) {
864				if (NV50EXABlendOp[op].src_alpha)
865					PUSH_DATA (push, PFP_CCASA);
866				else
867					PUSH_DATA (push, PFP_CCA);
868			} else {
869				PUSH_DATA (push, PFP_C);
870			}
871		}
872	} else {
873		BEGIN_NV04(push, NV50_3D(FP_START_ID), 1);
874		if (pdpict->format == PICT_a8)
875			PUSH_DATA (push, PFP_S_A8);
876		else
877			PUSH_DATA (push, PFP_S);
878	}
879
880	BEGIN_NV04(push, NV50_3D(TIC_FLUSH), 1);
881	PUSH_DATA (push, 0);
882
883	BEGIN_NV04(push, NV50_3D(BIND_TIC(2)), 1);
884	PUSH_DATA (push, 1);
885	BEGIN_NV04(push, NV50_3D(BIND_TIC(2)), 1);
886	PUSH_DATA (push, 0x203);
887
888	nouveau_pushbuf_bufctx(push, pNv->bufctx);
889	if (nouveau_pushbuf_validate(push)) {
890		nouveau_pushbuf_bufctx(push, NULL);
891		NOUVEAU_FALLBACK("validate\n");
892	}
893
894	return TRUE;
895}
896
897void
898NV50EXAComposite(PixmapPtr pdpix, int sx, int sy, int mx, int my,
899		 int dx, int dy, int w, int h)
900{
901	NV50EXA_LOCALS(pdpix);
902
903	if (!PUSH_SPACE(push, 64))
904		return;
905
906	BEGIN_NV04(push, NV50_3D(SCISSOR_HORIZ(0)), 2);
907	PUSH_DATA (push, (dx + w) << 16 | dx);
908	PUSH_DATA (push, (dy + h) << 16 | dy);
909	BEGIN_NV04(push, NV50_3D(VERTEX_BEGIN_GL), 1);
910	PUSH_DATA (push, NV50_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES);
911	PUSH_VTX2s(push, sx, sy + (h * 2), mx, my + (h * 2), dx, dy + (h * 2));
912	PUSH_VTX2s(push, sx, sy, mx, my, dx, dy);
913	PUSH_VTX2s(push, sx + (w * 2), sy, mx + (w * 2), my, dx + (w * 2), dy);
914	BEGIN_NV04(push, NV50_3D(VERTEX_END_GL), 1);
915	PUSH_DATA (push, 0);
916}
917
918void
919NV50EXADoneComposite(PixmapPtr pdpix)
920{
921	NV50EXA_LOCALS(pdpix);
922	nouveau_pushbuf_bufctx(push, NULL);
923}
924
925Bool
926NV50EXARectM2MF(NVPtr pNv, int w, int h, int cpp,
927		struct nouveau_bo *src, uint32_t src_off, int src_dom,
928		int src_pitch, int src_h, int src_x, int src_y,
929		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
930		int dst_pitch, int dst_h, int dst_x, int dst_y)
931{
932	struct nouveau_pushbuf *push = pNv->pushbuf;
933	struct nouveau_pushbuf_refn refs[] = {
934		{ src, src_dom | NOUVEAU_BO_RD },
935		{ dst, dst_dom | NOUVEAU_BO_WR },
936	};
937
938	if (!PUSH_SPACE(push, 64))
939		return FALSE;
940
941	if (src->config.nv50.memtype) {
942		BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 6);
943		PUSH_DATA (push, 0);
944		PUSH_DATA (push, src->config.nv50.tile_mode);
945		PUSH_DATA (push, src_pitch);
946		PUSH_DATA (push, src_h);
947		PUSH_DATA (push, 1);
948		PUSH_DATA (push, 0);
949	} else {
950		BEGIN_NV04(push, NV50_M2MF(LINEAR_IN), 1);
951		PUSH_DATA (push, 1);
952		BEGIN_NV04(push, NV03_M2MF(PITCH_IN), 1);
953		PUSH_DATA (push, src_pitch);
954		src_off += src_y * src_pitch + src_x * cpp;
955	}
956
957	if (dst->config.nv50.memtype) {
958		BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 6);
959		PUSH_DATA (push, 0);
960		PUSH_DATA (push, dst->config.nv50.tile_mode);
961		PUSH_DATA (push, dst_pitch);
962		PUSH_DATA (push, dst_h);
963		PUSH_DATA (push, 1);
964		PUSH_DATA (push, 0);
965	} else {
966		BEGIN_NV04(push, NV50_M2MF(LINEAR_OUT), 1);
967		PUSH_DATA (push, 1);
968		BEGIN_NV04(push, NV03_M2MF(PITCH_OUT), 1);
969		PUSH_DATA (push, dst_pitch);
970		dst_off += dst_y * dst_pitch + dst_x * cpp;
971	}
972
973	while (h) {
974		int line_count = h;
975		if (line_count > 2047)
976			line_count = 2047;
977
978		if (nouveau_pushbuf_space(push, 32, 0, 0) ||
979		    nouveau_pushbuf_refn (push, refs, 2))
980			return FALSE;
981
982		BEGIN_NV04(push, NV50_M2MF(OFFSET_IN_HIGH), 2);
983		PUSH_DATA (push, (src->offset + src_off) >> 32);
984		PUSH_DATA (push, (dst->offset + dst_off) >> 32);
985		BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 2);
986		PUSH_DATA (push, (src->offset + src_off));
987		PUSH_DATA (push, (dst->offset + dst_off));
988
989		if (src->config.nv50.memtype) {
990			BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_IN), 1);
991			PUSH_DATA (push, (src_y << 16) | (src_x * cpp));
992		} else {
993			src_off += line_count * src_pitch;
994		}
995
996		if (dst->config.nv50.memtype) {
997			BEGIN_NV04(push, NV50_M2MF(TILING_POSITION_OUT), 1);
998			PUSH_DATA (push, (dst_y << 16) | (dst_x * cpp));
999		} else {
1000			dst_off += line_count * dst_pitch;
1001		}
1002
1003		BEGIN_NV04(push, NV03_M2MF(LINE_LENGTH_IN), 4);
1004		PUSH_DATA (push, w * cpp);
1005		PUSH_DATA (push, line_count);
1006		PUSH_DATA (push, 0x00000101);
1007		PUSH_DATA (push, 0x00000000);
1008
1009		src_y += line_count;
1010		dst_y += line_count;
1011		h  -= line_count;
1012	}
1013
1014	return TRUE;
1015}
1016