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