nv04_exa.c revision 16ee1e9a
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	if (ppix->drawable.bitsPerPixel < 32)
53		planemask |= ~0 << ppix->drawable.bitsPerPixel;
54	if (planemask != ~0 || alu != GXcopy) {
55		if (ppix->drawable.bitsPerPixel == 32)
56			return FALSE;
57		if (planemask != ~0) {
58			NV04EXASetPattern(pNv, 0, planemask, ~0, ~0);
59			if (pNv->currentRop != (alu + 32)) {
60				BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
61				PUSH_DATA (push, pNv->NvRop->handle);
62				BEGIN_NV04(push, NV01_ROP(ROP), 1);
63				PUSH_DATA (push, NVROP[alu].copy_planemask);
64				pNv->currentRop = alu + 32;
65			}
66		} else
67		if (pNv->currentRop != alu) {
68			if(pNv->currentRop >= 16)
69				NV04EXASetPattern(pNv, ~0, ~0, ~0, ~0);
70			BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
71			PUSH_DATA (push, pNv->NvRop->handle);
72			BEGIN_NV04(push, NV01_ROP(ROP), 1);
73			PUSH_DATA (push, NVROP[alu].copy);
74			pNv->currentRop = alu;
75		}
76
77		BEGIN_NV04(push, subc, mthd, 1);
78		PUSH_DATA (push, 1); /* ROP_AND */
79	} else {
80		BEGIN_NV04(push, subc, mthd, 1);
81		PUSH_DATA (push, 3); /* SRCCOPY */
82	}
83
84	return TRUE;
85}
86
87Bool
88NV04EXAPrepareSolid(PixmapPtr ppix, int alu, Pixel planemask, Pixel fg)
89{
90	ScrnInfoPtr pScrn = xf86ScreenToScrn(ppix->drawable.pScreen);
91	NVPtr pNv = NVPTR(pScrn);
92	struct nouveau_pushbuf *push = pNv->pushbuf;
93	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
94	unsigned pitch = exaGetPixmapPitch(ppix);
95	unsigned surf_fmt, rect_fmt;
96
97	/* When SURFACE_FORMAT_A8R8G8B8 is used with GDI_RECTANGLE_TEXT, the
98	 * alpha channel gets forced to 0xFF for some reason.  We're using
99	 * SURFACE_FORMAT_Y32 as a workaround
100	 */
101	if (!NVAccelGetCtxSurf2DFormatFromPixmap(ppix, (int*)&surf_fmt))
102		return FALSE;
103	if (surf_fmt == NV04_SURFACE_2D_FORMAT_A8R8G8B8)
104		surf_fmt = NV04_SURFACE_2D_FORMAT_Y32;
105
106	rect_fmt = NV04_GDI_COLOR_FORMAT_A8R8G8B8;
107	if (ppix->drawable.bitsPerPixel == 16) {
108		if (ppix->drawable.depth == 16)
109			rect_fmt = NV04_GDI_COLOR_FORMAT_A16R5G6B5;
110		else
111			rect_fmt = NV04_GDI_COLOR_FORMAT_X16A1R5G5B5;
112	}
113
114	if (!PUSH_SPACE(push, 64))
115		return FALSE;
116	PUSH_RESET(push);
117
118	if (!NV04EXASetROP(ppix, NV04_RECT(OPERATION), alu, planemask))
119		return FALSE;
120
121	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
122	PUSH_DATA (push, surf_fmt);
123	PUSH_DATA (push, (pitch << 16) | pitch);
124	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0,
125			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
126	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0,
127			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
128	BEGIN_NV04(push, NV04_RECT(COLOR_FORMAT), 1);
129	PUSH_DATA (push, rect_fmt);
130
131	nouveau_pushbuf_bufctx(push, pNv->bufctx);
132	if (nouveau_pushbuf_validate(push)) {
133		nouveau_pushbuf_bufctx(push, NULL);
134		return FALSE;
135	}
136
137	pNv->fg_colour = fg;
138	return TRUE;
139}
140
141void
142NV04EXASolid (PixmapPtr pPixmap, int x, int y, int x2, int y2)
143{
144	ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
145	NVPtr pNv = NVPTR(pScrn);
146	struct nouveau_pushbuf *push = pNv->pushbuf;
147	int w = x2 - x;
148	int h = y2 - y;
149
150	if (!PUSH_SPACE(push, 5))
151		return;
152
153	BEGIN_NV04(push, NV04_RECT(COLOR1_A), 1);
154	PUSH_DATA (push, pNv->fg_colour);
155	BEGIN_NV04(push, NV04_RECT(UNCLIPPED_RECTANGLE_POINT(0)), 2);
156	PUSH_DATA (push, (x << 16) | y);
157	PUSH_DATA (push, (w << 16) | h);
158	if ((w * h) >= 512)
159		PUSH_KICK(push);
160}
161
162void
163NV04EXADoneSolid (PixmapPtr pPixmap)
164{
165	ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen);
166	nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL);
167}
168
169Bool
170NV04EXAPrepareCopy(PixmapPtr pspix, PixmapPtr pdpix, int dx, int dy,
171		   int alu, Pixel planemask)
172{
173	ScrnInfoPtr pScrn = xf86ScreenToScrn(pspix->drawable.pScreen);
174	NVPtr pNv = NVPTR(pScrn);
175	struct nouveau_pushbuf *push = pNv->pushbuf;
176	struct nouveau_bo *src_bo = nouveau_pixmap_bo(pspix);
177	struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
178	int surf_fmt;
179
180	if (pspix->drawable.bitsPerPixel != pdpix->drawable.bitsPerPixel)
181		return FALSE;
182
183	if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt))
184		return FALSE;
185
186	if (!PUSH_SPACE(push, 64))
187		return FALSE;
188	PUSH_RESET(push);
189
190	if (!NV04EXASetROP(pdpix, NV01_BLIT(OPERATION), alu, planemask))
191		return FALSE;
192
193	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
194	PUSH_DATA (push, surf_fmt);
195	PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) |
196			  exaGetPixmapPitch(pspix));
197	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), src_bo, 0,
198			 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
199	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), dst_bo, 0,
200			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
201
202	nouveau_pushbuf_bufctx(push, pNv->bufctx);
203	if (nouveau_pushbuf_validate(push)) {
204		nouveau_pushbuf_bufctx(push, NULL);
205		return FALSE;
206	}
207
208	pNv->pspix = pspix;
209	pNv->pmpix = NULL;
210	pNv->pdpix = pdpix;
211	return TRUE;
212}
213
214void
215NV04EXACopy(PixmapPtr pdpix, int srcX, int srcY, int dstX, int dstY,
216	    int width, int height)
217{
218	ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen);
219	NVPtr pNv = NVPTR(pScrn);
220	struct nouveau_pushbuf *push = pNv->pushbuf;
221	int split_dstY = NOUVEAU_ALIGN(dstY + 1, 64);
222	int split_height = split_dstY - dstY;
223
224	if (nouveau_pushbuf_space(push, 16, 2, 0))
225		return;
226
227	if ((width * height) >= 200000 && pNv->pspix != pNv->pdpix &&
228	    (dstY > srcY || dstX > srcX) && split_height < height) {
229		/*
230		 * KLUDGE - Split the destination rectangle in an
231		 * upper misaligned half and a lower tile-aligned
232		 * half, then get IMAGE_BLIT to blit the lower piece
233		 * downwards (required for sync-to-vblank if the area
234		 * to be blitted is large enough). The blob does a
235		 * different (not nicer) trick to achieve the same
236		 * effect.
237		 */
238		struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
239		unsigned dst_pitch = exaGetPixmapPitch(pdpix);
240
241		BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3);
242		PUSH_DATA (push, (srcY << 16) | srcX);
243		PUSH_DATA (push, (dstY << 16) | dstX);
244		PUSH_DATA (push, (split_height  << 16) | width);
245		BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1);
246		PUSH_RELOC(push, dst_bo, split_dstY * dst_pitch,
247				 NOUVEAU_BO_LOW, 0, 0);
248
249		srcY += split_height;
250		height -= split_height;
251		dstY = 0;
252		pNv->pmpix = pdpix;
253	}
254
255	BEGIN_NV04(push, NV01_BLIT(POINT_IN), 3);
256	PUSH_DATA (push, (srcY << 16) | srcX);
257	PUSH_DATA (push, (dstY << 16) | dstX);
258	PUSH_DATA (push, (height  << 16) | width);
259
260	if (pNv->pmpix) {
261		struct nouveau_bo *dst_bo = nouveau_pixmap_bo(pdpix);
262
263		BEGIN_NV04(push, NV04_SF2D(OFFSET_DESTIN), 1);
264		PUSH_RELOC(push, dst_bo, 0, NOUVEAU_BO_LOW, 0, 0);
265		pNv->pmpix = NULL;
266	}
267
268	if ((width * height) >= 512)
269		PUSH_KICK(push);
270}
271
272void
273NV04EXADoneCopy(PixmapPtr pdpix)
274{
275	ScrnInfoPtr pScrn = xf86ScreenToScrn(pdpix->drawable.pScreen);
276	nouveau_pushbuf_bufctx(NVPTR(pScrn)->pushbuf, NULL);
277}
278
279Bool
280NV04EXAUploadIFC(ScrnInfoPtr pScrn, const char *src, int src_pitch,
281		 PixmapPtr pdpix, int x, int y, int w, int h, int cpp)
282{
283	NVPtr pNv = NVPTR(pScrn);
284	ScreenPtr pScreen = pdpix->drawable.pScreen;
285	struct nouveau_bo *bo = nouveau_pixmap_bo(pdpix);
286	struct nouveau_pushbuf *push = pNv->pushbuf;
287	int line_len = w * cpp;
288	int surf_fmt, ifc_fmt;
289	int iw, id, py, ph;
290	int padbytes;
291	Bool ret = FALSE;
292
293	if (pNv->Architecture >= NV_TESLA)
294		return FALSE;
295
296	if (h > 1024)
297		return FALSE;
298
299	if (line_len < 4)
300		return FALSE;
301
302	switch (cpp) {
303	case 2: ifc_fmt = 1; break;
304	case 4: ifc_fmt = 4; break;
305	default:
306		return FALSE;
307	}
308
309	if (!NVAccelGetCtxSurf2DFormatFromPixmap(pdpix, &surf_fmt))
310		return FALSE;
311
312	/* Pad out input width to cover both COLORA() and COLORB() */
313	iw  = (line_len + 7) & ~7;
314	padbytes = iw - line_len;
315	id  = iw / 4; /* line push size */
316	iw /= cpp;
317
318	/* Don't support lines longer than max push size yet.. */
319	if (id > 1792)
320		return FALSE;
321
322	if (!PUSH_SPACE(push, 16))
323		return FALSE;
324	PUSH_RESET(push);
325
326	BEGIN_NV04(push, NV01_SUBC(MISC, OBJECT), 1);
327	PUSH_DATA (push, pNv->NvClipRectangle->handle);
328	BEGIN_NV04(push, NV01_CLIP(POINT), 2);
329	PUSH_DATA (push, (y << 16) | x);
330	PUSH_DATA (push, (h << 16) | w);
331
332	BEGIN_NV04(push, NV04_SF2D(FORMAT), 4);
333	PUSH_DATA (push, surf_fmt);
334	PUSH_DATA (push, (exaGetPixmapPitch(pdpix) << 16) |
335			  exaGetPixmapPitch(pdpix));
336	PUSH_MTHDl(push, NV04_SF2D(OFFSET_SOURCE), bo, 0,
337			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
338	PUSH_MTHDl(push, NV04_SF2D(OFFSET_DESTIN), bo, 0,
339			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
340
341	nouveau_pushbuf_bufctx(push, pNv->bufctx);
342	if (nouveau_pushbuf_validate(push))
343		goto out;
344
345	py = y;
346	ph = h;
347	while (ph--) {
348		if (PUSH_AVAIL(push) < id + 1 || (py == y)) {
349			if (!PUSH_SPACE(push, id + 8))
350				goto out;
351			BEGIN_NV04(push, NV01_IFC(OPERATION), 2);
352			PUSH_DATA (push, NV01_IFC_OPERATION_SRCCOPY);
353			PUSH_DATA (push, ifc_fmt);
354			BEGIN_NV04(push, NV01_IFC(POINT), 3);
355			PUSH_DATA (push, (py << 16) | x);
356			PUSH_DATA (push, (h << 16) | w);
357			PUSH_DATA (push, (h << 16) | iw);
358		}
359
360		/* send a line */
361		if (ph > 0 || !padbytes) {
362			BEGIN_NV04(push, NV01_IFC(COLOR(0)), id);
363			PUSH_DATAp(push, src, id);
364		} else {
365			char padding[8];
366			int aux = (padbytes + 7) >> 2;
367			memcpy(padding, src + (id - aux) * 4, padbytes);
368			BEGIN_NV04(push, NV01_IFC(COLOR(0)), id);
369			PUSH_DATAp(push, src, id - aux);
370			PUSH_DATAp(push, padding, aux);
371		}
372
373		src += src_pitch;
374		py++;
375	}
376
377	ret = TRUE;
378out:
379	nouveau_pushbuf_bufctx(push, NULL);
380	if (pdpix == pScreen->GetScreenPixmap(pScreen))
381		PUSH_KICK(push);
382	return ret;
383}
384
385Bool
386NV04EXARectM2MF(NVPtr pNv, int w, int h, int cpp,
387		struct nouveau_bo *src, uint32_t src_off, int src_dom,
388		int src_pitch, int src_h, int src_x, int src_y,
389		struct nouveau_bo *dst, uint32_t dst_off, int dst_dom,
390		int dst_pitch, int dst_h, int dst_x, int dst_y)
391{
392	struct nv04_fifo *fifo = pNv->channel->data;
393	struct nouveau_pushbuf *push = pNv->pushbuf;
394	struct nouveau_pushbuf_refn refs[] = {
395		{ src, src_dom | NOUVEAU_BO_RD },
396		{ dst, dst_dom | NOUVEAU_BO_WR },
397	};
398
399	src_off += src_y * src_pitch + src_x * cpp;
400	dst_off += dst_y * dst_pitch + dst_x * cpp;
401
402	while (h) {
403		int line_count = h;
404		if (line_count > 2047)
405			line_count = 2047;
406		h -= line_count;
407
408		if (nouveau_pushbuf_space(push, 16, 4, 0) ||
409		    nouveau_pushbuf_refn (push, refs, 2))
410			return FALSE;
411
412		BEGIN_NV04(push, NV03_M2MF(DMA_BUFFER_IN), 2);
413		PUSH_RELOC(push, src, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
414		PUSH_RELOC(push, dst, 0, NOUVEAU_BO_OR, fifo->vram, fifo->gart);
415		BEGIN_NV04(push, NV03_M2MF(OFFSET_IN), 8);
416		PUSH_RELOC(push, src, src_off, NOUVEAU_BO_LOW, 0, 0);
417		PUSH_RELOC(push, dst, dst_off, NOUVEAU_BO_LOW, 0, 0);
418		PUSH_DATA (push, src_pitch);
419		PUSH_DATA (push, dst_pitch);
420		PUSH_DATA (push, w * cpp);
421		PUSH_DATA (push, line_count);
422		PUSH_DATA (push, 0x00000101);
423		PUSH_DATA (push, 0x00000000);
424		BEGIN_NV04(push, NV04_GRAPH(M2MF, NOP), 1);
425		PUSH_DATA (push, 0x00000000);
426		BEGIN_NV04(push, NV03_M2MF(OFFSET_OUT), 1);
427		PUSH_DATA (push, 0x00000000);
428
429		src_off += src_pitch * line_count;
430		dst_off += dst_pitch * line_count;
431	}
432
433	return TRUE;
434}
435