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