nv04_exa.c revision 16ee1e9a
1fda9279dSmrg/*
2fda9279dSmrg * Copyright 2003 NVIDIA, Corporation
3fda9279dSmrg *
4fda9279dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5fda9279dSmrg * copy of this software and associated documentation files (the "Software"),
6fda9279dSmrg * to deal in the Software without restriction, including without limitation
7fda9279dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fda9279dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9fda9279dSmrg * Software is furnished to do so, subject to the following conditions:
10fda9279dSmrg *
11fda9279dSmrg * The above copyright notice and this permission notice shall be included in
12fda9279dSmrg * all copies or substantial portions of the Software.
13fda9279dSmrg *
14fda9279dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fda9279dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fda9279dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17fda9279dSmrg * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18fda9279dSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19fda9279dSmrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20fda9279dSmrg * SOFTWARE.
21fda9279dSmrg */
22fda9279dSmrg
23fda9279dSmrg#include "nv_include.h"
24fda9279dSmrg#include "nv_rop.h"
25fda9279dSmrg
26fda9279dSmrg#include "hwdefs/nv_object.xml.h"
27fda9279dSmrg#include "hwdefs/nv_m2mf.xml.h"
28fda9279dSmrg#include "hwdefs/nv01_2d.xml.h"
29fda9279dSmrg#include "nv04_accel.h"
30fda9279dSmrg
31fda9279dSmrgstatic void
32fda9279dSmrgNV04EXASetPattern(NVPtr pNv, CARD32 clr0, CARD32 clr1, CARD32 pat0, CARD32 pat1)
33fda9279dSmrg{
34fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
35fda9279dSmrg
36fda9279dSmrg	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
37fda9279dSmrg	PUSH_DATA (push, pNv->NvImagePattern->handle);
38fda9279dSmrg	BEGIN_NV04(push, NV01_PATT(MONOCHROME_COLOR(0)), 4);
39fda9279dSmrg	PUSH_DATA (push, clr0);
40fda9279dSmrg	PUSH_DATA (push, clr1);
41fda9279dSmrg	PUSH_DATA (push, pat0);
42fda9279dSmrg	PUSH_DATA (push, pat1);
43fda9279dSmrg}
44fda9279dSmrg
45fda9279dSmrgstatic Bool
46fda9279dSmrgNV04EXASetROP(PixmapPtr ppix, int subc, int mthd, int alu, Pixel planemask)
47fda9279dSmrg{
48fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
49fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
50fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
51fda9279dSmrg
5216ee1e9aSmrg	if (ppix->drawable.bitsPerPixel < 32)
5316ee1e9aSmrg		planemask |= ~0 << ppix->drawable.bitsPerPixel;
54fda9279dSmrg	if (planemask != ~0 || alu != GXcopy) {
55fda9279dSmrg		if (ppix->drawable.bitsPerPixel == 32)
56fda9279dSmrg			return FALSE;
57fda9279dSmrg		if (planemask != ~0) {
58fda9279dSmrg			NV04EXASetPattern(pNv, 0, planemask, ~0, ~0);
59fda9279dSmrg			if (pNv->currentRop != (alu + 32)) {
60fda9279dSmrg				BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
61fda9279dSmrg				PUSH_DATA (push, pNv->NvRop->handle);
62fda9279dSmrg				BEGIN_NV04(push, NV01_ROP(ROP), 1);
63fda9279dSmrg				PUSH_DATA (push, NVROP[alu].copy_planemask);
64fda9279dSmrg				pNv->currentRop = alu + 32;
65fda9279dSmrg			}
66fda9279dSmrg		} else
67fda9279dSmrg		if (pNv->currentRop != alu) {
68fda9279dSmrg			if(pNv->currentRop >= 16)
69fda9279dSmrg				NV04EXASetPattern(pNv, ~0, ~0, ~0, ~0);
70fda9279dSmrg			BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
71fda9279dSmrg			PUSH_DATA (push, pNv->NvRop->handle);
72fda9279dSmrg			BEGIN_NV04(push, NV01_ROP(ROP), 1);
73fda9279dSmrg			PUSH_DATA (push, NVROP[alu].copy);
74fda9279dSmrg			pNv->currentRop = alu;
75fda9279dSmrg		}
76fda9279dSmrg
77fda9279dSmrg		BEGIN_NV04(push, subc, mthd, 1);
78fda9279dSmrg		PUSH_DATA (push, 1); /* ROP_AND */
79fda9279dSmrg	} else {
80fda9279dSmrg		BEGIN_NV04(push, subc, mthd, 1);
81fda9279dSmrg		PUSH_DATA (push, 3); /* SRCCOPY */
82fda9279dSmrg	}
83fda9279dSmrg
84fda9279dSmrg	return TRUE;
85fda9279dSmrg}
86fda9279dSmrg
87fda9279dSmrgBool
88fda9279dSmrgNV04EXAPrepareSolid(PixmapPtr ppix, int alu, Pixel planemask, Pixel fg)
89fda9279dSmrg{
90fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
91fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
92fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
93fda9279dSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
94fda9279dSmrg	unsigned pitch = exaGetPixmapPitch(ppix);
95fda9279dSmrg	unsigned surf_fmt, rect_fmt;
96fda9279dSmrg
97fda9279dSmrg	/* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the
98fda9279dSmrg	 * alpha channel gets forced to 0xFF for some reason.  We're using
99fda9279dSmrg	 * SURFACE_FORMAT_Y32 as a workaround
100fda9279dSmrg	 */
101fda9279dSmrg	if (!NVAccelGetCtxSurf2DFormatFromPixmap(ppix, (int*)&surf_fmt))
102fda9279dSmrg		return FALSE;
103fda9279dSmrg	if (surf_fmt == NV04_SURFACE_2D_FORMAT_A8R8G8B8)
104fda9279dSmrg		surf_fmt = NV04_SURFACE_2D_FORMAT_Y32;
105fda9279dSmrg
106fda9279dSmrg	rect_fmt = NV04_GDI_COLOR_FORMAT_A8R8G8B8;
107fda9279dSmrg	if (ppix->drawable.bitsPerPixel == 16) {
108fda9279dSmrg		if (ppix->drawable.depth == 16)
109fda9279dSmrg			rect_fmt = NV04_GDI_COLOR_FORMAT_A16R5G6B5;
110fda9279dSmrg		else
111fda9279dSmrg			rect_fmt = NV04_GDI_COLOR_FORMAT_X16A1R5G5B5;
112fda9279dSmrg	}
113fda9279dSmrg
114fda9279dSmrg	if (!PUSH_SPACE(push, 64))
115fda9279dSmrg		return FALSE;
116fda9279dSmrg	PUSH_RESET(push);
117fda9279dSmrg
118fda9279dSmrg	if (!NV04EXASetROP(ppix, NV04_RECT(OPERATION), alu, planemask))
119fda9279dSmrg		return FALSE;
120fda9279dSmrg
121fda9279dSmrg	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
122fda9279dSmrg	PUSH_DATA (push, surf_fmt);
123fda9279dSmrg	PUSH_DATA (push, (pitch << 16) | pitch);
124fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0,
125fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
126fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0,
127fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
128fda9279dSmrg	BEGIN_NV04(push, NV04_RECT(COLOR_FORMAT), 1);
129fda9279dSmrg	PUSH_DATA (push, rect_fmt);
130fda9279dSmrg
131fda9279dSmrg	nouveau_pushbuf_bufctx(push, pNv->bufctx);
132fda9279dSmrg	if (nouveau_pushbuf_validate(push)) {
133fda9279dSmrg		nouveau_pushbuf_bufctx(push, NULL);
134fda9279dSmrg		return FALSE;
135fda9279dSmrg	}
136fda9279dSmrg
137fda9279dSmrg	pNv->fg_colour = fg;
138fda9279dSmrg	return TRUE;
139fda9279dSmrg}
140fda9279dSmrg
141fda9279dSmrgvoid
142fda9279dSmrgNV04EXASolid (PixmapPtr pPixmap, int x, int y, int x2, int y2)
143fda9279dSmrg{
144fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
145fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
146fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
147fda9279dSmrg	int w = x2 - x;
148fda9279dSmrg	int h = y2 - y;
149fda9279dSmrg
150fda9279dSmrg	if (!PUSH_SPACE(push, 5))
151fda9279dSmrg		return;
152fda9279dSmrg
153fda9279dSmrg	BEGIN_NV04(push, NV04_RECT(COLOR1_A), 1);
154fda9279dSmrg	PUSH_DATA (push, pNv->fg_colour);
155fda9279dSmrg	BEGIN_NV04(push, NV04_RECT(UNCLIPPED_RECTANGLE_POINT(0)), 2);
156fda9279dSmrg	PUSH_DATA (push, (x << 16) | y);
157fda9279dSmrg	PUSH_DATA (push, (w << 16) | h);
158fda9279dSmrg	if ((w * h) >= 512)
159fda9279dSmrg		PUSH_KICK(push);
160fda9279dSmrg}
161fda9279dSmrg
162fda9279dSmrgvoid
163fda9279dSmrgNV04EXADoneSolid (PixmapPtr pPixmap)
164fda9279dSmrg{
165fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
166fda9279dSmrg	nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL);
167fda9279dSmrg}
168fda9279dSmrg
169fda9279dSmrgBool
170fda9279dSmrgNV04EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
171fda9279dSmrg		   int alu, Pixel planemask)
172fda9279dSmrg{
173fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen);
174fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
175fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
176fda9279dSmrg	struct nouveau_bo *src_bo = nouveau_pixmap_bo(pspix);
177fda9279dSmrg	struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
178fda9279dSmrg	int surf_fmt;
179fda9279dSmrg
180fda9279dSmrg	if (pspix->drawable.bitsPerPixel != pdpix->drawable.bitsPerPixel)
181fda9279dSmrg		return FALSE;
182fda9279dSmrg
183fda9279dSmrg	if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt))
184fda9279dSmrg		return FALSE;
185fda9279dSmrg
186fda9279dSmrg	if (!PUSH_SPACE(push, 64))
187fda9279dSmrg		return FALSE;
188fda9279dSmrg	PUSH_RESET(push);
189fda9279dSmrg
190fda9279dSmrg	if (!NV04EXASetROP(pdpix, NV01_BLIT(OPERATION), alu, planemask))
191fda9279dSmrg		return FALSE;
192fda9279dSmrg
193fda9279dSmrg	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
194fda9279dSmrg	PUSH_DATA (push, surf_fmt);
195fda9279dSmrg	PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) |
196fda9279dSmrg			  exaGetPixmapPitch(pspix));
197fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), src_bo, 0,
198fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
199fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), dst_bo, 0,
200fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
201fda9279dSmrg
202fda9279dSmrg	nouveau_pushbuf_bufctx(push, pNv->bufctx);
203fda9279dSmrg	if (nouveau_pushbuf_validate(push)) {
204fda9279dSmrg		nouveau_pushbuf_bufctx(push, NULL);
205fda9279dSmrg		return FALSE;
206fda9279dSmrg	}
207fda9279dSmrg
208fda9279dSmrg	pNv->pspix = pspix;
209fda9279dSmrg	pNv->pmpix = NULL;
210fda9279dSmrg	pNv->pdpix = pdpix;
211fda9279dSmrg	return TRUE;
212fda9279dSmrg}
213fda9279dSmrg
214fda9279dSmrgvoid
215fda9279dSmrgNV04EXACopy(PixmapPtr pdpix, int srcX, int srcY, int dstX, int dstY,
216fda9279dSmrg	    int width, int height)
217fda9279dSmrg{
218fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen);
219fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
220fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
221fda9279dSmrg	int split_dstY = NOUVEAU_ALIGN(dstY + 1, 64);
222fda9279dSmrg	int split_height = split_dstY - dstY;
223fda9279dSmrg
224fda9279dSmrg	if (nouveau_pushbuf_space(push, 16, 2, 0))
225fda9279dSmrg		return;
226fda9279dSmrg
227fda9279dSmrg	if ((width * height) >= 200000 && pNv->pspix != pNv->pdpix &&
228fda9279dSmrg	    (dstY > srcY || dstX > srcX) && split_height < height) {
229fda9279dSmrg		/*
230fda9279dSmrg		 * KLUDGE - Split the destination rectangle in an
231fda9279dSmrg		 * upper misaligned half and a lower tile-aligned
232fda9279dSmrg		 * half, then get IMAGE_BLIT to blit the lower piece
233fda9279dSmrg		 * downwards (required for sync-to-vblank if the area
234fda9279dSmrg		 * to be blitted is large enough). The blob does a
235fda9279dSmrg		 * different (not nicer) trick to achieve the same
236fda9279dSmrg		 * effect.
237fda9279dSmrg		 */
238fda9279dSmrg		struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
239fda9279dSmrg		unsigned dst_pitch = exaGetPixmapPitch(pdpix);
240fda9279dSmrg
241fda9279dSmrg		BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3);
242fda9279dSmrg		PUSH_DATA (push, (srcY << 16) | srcX);
243fda9279dSmrg		PUSH_DATA (push, (dstY << 16) | dstX);
244fda9279dSmrg		PUSH_DATA (push, (split_height  << 16) | width);
245fda9279dSmrg		BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1);
246fda9279dSmrg		PUSH_RELOC(push, dst_bo, split_dstY * dst_pitch,
247fda9279dSmrg				 NOUVEAU_BO_LOW, 0, 0);
248fda9279dSmrg
249fda9279dSmrg		srcY += split_height;
250fda9279dSmrg		height -= split_height;
251fda9279dSmrg		dstY = 0;
252fda9279dSmrg		pNv->pmpix = pdpix;
253fda9279dSmrg	}
254fda9279dSmrg
255fda9279dSmrg	BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3);
256fda9279dSmrg	PUSH_DATA (push, (srcY << 16) | srcX);
257fda9279dSmrg	PUSH_DATA (push, (dstY << 16) | dstX);
258fda9279dSmrg	PUSH_DATA (push, (height  << 16) | width);
259fda9279dSmrg
260fda9279dSmrg	if (pNv->pmpix) {
261fda9279dSmrg		struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
262fda9279dSmrg
263fda9279dSmrg		BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1);
264fda9279dSmrg		PUSH_RELOC(push, dst_bo, 0, NOUVEAU_BO_LOW, 0, 0);
265fda9279dSmrg		pNv->pmpix = NULL;
266fda9279dSmrg	}
267fda9279dSmrg
268fda9279dSmrg	if ((width * height) >= 512)
269fda9279dSmrg		PUSH_KICK(push);
270fda9279dSmrg}
271fda9279dSmrg
272fda9279dSmrgvoid
273fda9279dSmrgNV04EXADoneCopy(PixmapPtr pdpix)
274fda9279dSmrg{
275fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen);
276fda9279dSmrg	nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL);
277fda9279dSmrg}
278fda9279dSmrg
279fda9279dSmrgBool
280fda9279dSmrgNV04EXAUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch,
281fda9279dSmrg		 PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
282fda9279dSmrg{
283fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
284fda9279dSmrg	ScreenPtr pScreen = pdpix->drawable.pScreen;
285fda9279dSmrg	struct nouveau_bo *bo = nouveau_pixmap_bo(pdpix);
286fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
287fda9279dSmrg	int line_len = w * cpp;
288fda9279dSmrg	int surf_fmt, ifc_fmt;
289fda9279dSmrg	int iw, id, py, ph;
290fda9279dSmrg	int padbytes;
291fda9279dSmrg	Bool ret = FALSE;
292fda9279dSmrg
293fda9279dSmrg	if (pNv->Architecture >= NV_TESLA)
294fda9279dSmrg		return FALSE;
295fda9279dSmrg
296fda9279dSmrg	if (h > 1024)
297fda9279dSmrg		return FALSE;
298fda9279dSmrg
299fda9279dSmrg	if (line_len < 4)
300fda9279dSmrg		return FALSE;
301fda9279dSmrg
302fda9279dSmrg	switch (cpp) {
303fda9279dSmrg	case 2: ifc_fmt = 1; break;
304fda9279dSmrg	case 4: ifc_fmt = 4; break;
305fda9279dSmrg	default:
306fda9279dSmrg		return FALSE;
307fda9279dSmrg	}
308fda9279dSmrg
309fda9279dSmrg	if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt))
310fda9279dSmrg		return FALSE;
311fda9279dSmrg
312fda9279dSmrg	/* Pad out input width to cover both COLORA() and COLORB() */
313fda9279dSmrg	iw  = (line_len + 7) & ~7;
314fda9279dSmrg	padbytes = iw - line_len;
315fda9279dSmrg	id  = iw / 4; /* line push size */
316fda9279dSmrg	iw /= cpp;
317fda9279dSmrg
318fda9279dSmrg	/* Don't support lines longer than max push size yet.. */
319fda9279dSmrg	if (id > 1792)
320fda9279dSmrg		return FALSE;
321fda9279dSmrg
322fda9279dSmrg	if (!PUSH_SPACE(push, 16))
323fda9279dSmrg		return FALSE;
324fda9279dSmrg	PUSH_RESET(push);
325fda9279dSmrg
326fda9279dSmrg	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
327fda9279dSmrg	PUSH_DATA (push, pNv->NvClipRectangle->handle);
328fda9279dSmrg	BEGIN_NV04(push, NV01_CLIP(POINT), 2);
329fda9279dSmrg	PUSH_DATA (push, (y << 16) | x);
330fda9279dSmrg	PUSH_DATA (push, (h << 16) | w);
331fda9279dSmrg
332fda9279dSmrg	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
333fda9279dSmrg	PUSH_DATA (push, surf_fmt);
334fda9279dSmrg	PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) |
335fda9279dSmrg			  exaGetPixmapPitch(pdpix));
336fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0,
337fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
338fda9279dSmrg	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0,
339fda9279dSmrg			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
340fda9279dSmrg
341fda9279dSmrg	nouveau_pushbuf_bufctx(push, pNv->bufctx);
342fda9279dSmrg	if (nouveau_pushbuf_validate(push))
343fda9279dSmrg		goto out;
344fda9279dSmrg
345fda9279dSmrg	py = y;
346fda9279dSmrg	ph = h;
347fda9279dSmrg	while (ph--) {
348fda9279dSmrg		if (PUSH_AVAIL(push) < id + 1 || (py == y)) {
349fda9279dSmrg			if (!PUSH_SPACE(push, id + 8))
350fda9279dSmrg				goto out;
351fda9279dSmrg			BEGIN_NV04(push, NV01_IFC(OPERATION), 2);
352fda9279dSmrg			PUSH_DATA (push, NV01_IFC_OPERATION_SRCCOPY);
353fda9279dSmrg			PUSH_DATA (push, ifc_fmt);
354fda9279dSmrg			BEGIN_NV04(push, NV01_IFC(POINT), 3);
355fda9279dSmrg			PUSH_DATA (push, (py << 16) | x);
356fda9279dSmrg			PUSH_DATA (push, (h << 16) | w);
357fda9279dSmrg			PUSH_DATA (push, (h << 16) | iw);
358fda9279dSmrg		}
359fda9279dSmrg
360fda9279dSmrg		/* send a line */
361fda9279dSmrg		if (ph > 0 || !padbytes) {
362fda9279dSmrg			BEGIN_NV04(push, NV01_IFC(COLOR(0)), id);
363fda9279dSmrg			PUSH_DATAp(push, src, id);
364fda9279dSmrg		} else {
365fda9279dSmrg			char padding[8];
366fda9279dSmrg			int aux = (padbytes + 7) >> 2;
367fda9279dSmrg			memcpy(padding, src + (id - aux) * 4, padbytes);
368fda9279dSmrg			BEGIN_NV04(push, NV01_IFC(COLOR(0)), id);
369fda9279dSmrg			PUSH_DATAp(push, src, id - aux);
370fda9279dSmrg			PUSH_DATAp(push, padding, aux);
371fda9279dSmrg		}
372fda9279dSmrg
373fda9279dSmrg		src += src_pitch;
374fda9279dSmrg		py++;
375fda9279dSmrg	}
376fda9279dSmrg
377fda9279dSmrg	ret = TRUE;
378fda9279dSmrgout:
379fda9279dSmrg	nouveau_pushbuf_bufctx(push, NULL);
380fda9279dSmrg	if (pdpix == pScreen->GetScreenPixmap(pScreen))
381fda9279dSmrg		PUSH_KICK(push);
382fda9279dSmrg	return ret;
383fda9279dSmrg}
384fda9279dSmrg
385fda9279dSmrgBool
386fda9279dSmrgNV04EXARectM2MF(NVPtr pNv, int w, int h, int cpp,
387fda9279dSmrg		struct nouveau_bo *src, uint32_t src_off, int src_dom,
388fda9279dSmrg		int src_pitch, int src_h, int src_x, int src_y,
389fda9279dSmrg		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
390fda9279dSmrg		int dst_pitch, int dst_h, int dst_x, int dst_y)
391fda9279dSmrg{
392fda9279dSmrg	struct nv04_fifo *fifo = pNv->channel->data;
393fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
394fda9279dSmrg	struct nouveau_pushbuf_refn refs[] = {
395fda9279dSmrg		{ src, src_dom | NOUVEAU_BO_RD },
396fda9279dSmrg		{ dst, dst_dom | NOUVEAU_BO_WR },
397fda9279dSmrg	};
398fda9279dSmrg
399fda9279dSmrg	src_off += src_y * src_pitch + src_x * cpp;
400fda9279dSmrg	dst_off += dst_y * dst_pitch + dst_x * cpp;
401fda9279dSmrg
402fda9279dSmrg	while (h) {
403fda9279dSmrg		int line_count = h;
404fda9279dSmrg		if (line_count > 2047)
405fda9279dSmrg			line_count = 2047;
406fda9279dSmrg		h -= line_count;
407fda9279dSmrg
408fda9279dSmrg		if (nouveau_pushbuf_space(push, 16, 4, 0) ||
409fda9279dSmrg		    nouveau_pushbuf_refn (push, refs, 2))
410fda9279dSmrg			return FALSE;
411fda9279dSmrg
412fda9279dSmrg		BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
413fda9279dSmrg		PUSH_RELOC(push, src, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
414fda9279dSmrg		PUSH_RELOC(push, dst, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
415fda9279dSmrg		BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
416fda9279dSmrg		PUSH_RELOC(push, src, src_off, NOUVEAU_BO_LOW, 0, 0);
417fda9279dSmrg		PUSH_RELOC(push, dst, dst_off, NOUVEAU_BO_LOW, 0, 0);
418fda9279dSmrg		PUSH_DATA (push, src_pitch);
419fda9279dSmrg		PUSH_DATA (push, dst_pitch);
420fda9279dSmrg		PUSH_DATA (push, w * cpp);
421fda9279dSmrg		PUSH_DATA (push, line_count);
422fda9279dSmrg		PUSH_DATA (push, 0x00000101);
423fda9279dSmrg		PUSH_DATA (push, 0x00000000);
424fda9279dSmrg		BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
425fda9279dSmrg		PUSH_DATA (push, 0x00000000);
426fda9279dSmrg		BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
427fda9279dSmrg		PUSH_DATA (push, 0x00000000);
428fda9279dSmrg
429fda9279dSmrg		src_off += src_pitch * line_count;
430fda9279dSmrg		dst_off += dst_pitch * line_count;
431fda9279dSmrg	}
432fda9279dSmrg
433fda9279dSmrg	return TRUE;
434fda9279dSmrg}
435