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