nv30_xv_tex.c revision 22d74663
1/*
2 * Copyright 2007-2008 Maarten Maathuis
3 * Copyright 2008 Stephane Marchesin
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include "xorg-config.h"
30#include "xf86xv.h"
31#include <X11/extensions/Xv.h>
32#include "exa.h"
33#include "damage.h"
34#include "dixstruct.h"
35#include "fourcc.h"
36
37#include "nv_include.h"
38#include "nv_dma.h"
39
40#include "hwdefs/nv30-40_3d.xml.h"
41#include "nv04_accel.h"
42
43extern Atom xvSyncToVBlank, xvSetDefaults;
44
45#define SWIZZLE(ts0x,ts0y,ts0z,ts0w,ts1x,ts1y,ts1z,ts1w)			\
46	(									\
47	NV30_3D_TEX_SWIZZLE_S0_X_##ts0x | NV30_3D_TEX_SWIZZLE_S0_Y_##ts0y	|	\
48	NV30_3D_TEX_SWIZZLE_S0_Z_##ts0z | NV30_3D_TEX_SWIZZLE_S0_W_##ts0w	|	\
49	NV30_3D_TEX_SWIZZLE_S1_X_##ts1x | NV30_3D_TEX_SWIZZLE_S1_Y_##ts1y |	\
50	NV30_3D_TEX_SWIZZLE_S1_Z_##ts1z | NV30_3D_TEX_SWIZZLE_S1_W_##ts1w		\
51	)
52
53/*
54 * Texture 0 : filter table
55 * Texture 1 : Y data
56 * Texture 2 : UV data
57 */
58static Bool
59NV30VideoTexture(ScrnInfoPtr pScrn, struct nouveau_bo *src, int offset,
60		 uint16_t width, uint16_t height, uint16_t src_pitch, int unit)
61{
62	NVPtr pNv = NVPTR(pScrn);
63	unsigned reloc = NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD;
64	struct nouveau_pushbuf *push = pNv->pushbuf;
65	uint32_t card_fmt = 0;
66	uint32_t card_swz = 0;
67	int h = log2i(height);
68	int w = log2i(width);
69
70	switch (unit) {
71	case 0:
72		card_fmt = NV30_3D_TEX_FORMAT_FORMAT_A8R8G8B8;
73		card_swz = SWIZZLE(S1, S1, S1, S1, X, Y, Z, W);
74		break;
75	case 1:
76		card_fmt = NV30_3D_TEX_FORMAT_FORMAT_I8_RECT;
77		card_swz = SWIZZLE(S1, S1, S1, S1, X, X, X, X);
78		break;
79	case 2:
80		card_fmt = NV30_3D_TEX_FORMAT_FORMAT_A8L8_RECT;
81#if X_BYTE_ORDER == X_BIG_ENDIAN
82		card_swz = SWIZZLE(S1, S1, S1, S1, Z, W, X, Y);
83#else
84		card_swz = SWIZZLE(S1, S1, S1, S1, W, Z, Y, X);
85#endif
86		break;
87	}
88
89	BEGIN_NV04(push, NV30_3D(TEX_OFFSET(unit)), 8);
90	PUSH_MTHDl(push, NV30_3D(TEX_OFFSET(unit)), src, offset, reloc);
91	if (unit == 0) {
92		PUSH_MTHD (push, NV30_3D(TEX_FORMAT(unit)), src,
93				 NV30_3D_TEX_FORMAT_DIMS_1D |
94				 card_fmt | (1 << 16) | 8 /* no idea */ |
95				 (w << NV30_3D_TEX_FORMAT_BASE_SIZE_U__SHIFT) |
96				 (h << NV30_3D_TEX_FORMAT_BASE_SIZE_V__SHIFT),
97				 reloc | NOUVEAU_BO_OR,
98				 NV30_3D_TEX_FORMAT_DMA0,
99				 NV30_3D_TEX_FORMAT_DMA1);
100		PUSH_DATA (push, NV30_3D_TEX_WRAP_S_REPEAT |
101				 NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE |
102				 NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE);
103	} else {
104		PUSH_MTHD (push, NV30_3D(TEX_FORMAT(unit)), src,
105				 NV30_3D_TEX_FORMAT_DIMS_2D |
106				 card_fmt | (1 << 16) | 8 /* no idea */ |
107				 (w << NV30_3D_TEX_FORMAT_BASE_SIZE_U__SHIFT) |
108				 (h << NV30_3D_TEX_FORMAT_BASE_SIZE_V__SHIFT),
109				 reloc | NOUVEAU_BO_OR,
110				 NV30_3D_TEX_FORMAT_DMA0,
111				 NV30_3D_TEX_FORMAT_DMA1);
112		PUSH_DATA (push, NV30_3D_TEX_WRAP_S_CLAMP_TO_EDGE |
113				 NV30_3D_TEX_WRAP_T_CLAMP_TO_EDGE |
114				 NV30_3D_TEX_WRAP_R_CLAMP_TO_EDGE);
115	}
116
117	PUSH_DATA (push, NV30_3D_TEX_ENABLE_ENABLE);
118	PUSH_DATA (push, (src_pitch << NV30_3D_TEX_SWIZZLE_RECT_PITCH__SHIFT) |
119			 card_swz);
120	if (unit == 0)
121		PUSH_DATA (push, NV30_3D_TEX_FILTER_SIGNED_ALPHA |
122				 NV30_3D_TEX_FILTER_SIGNED_RED |
123				 NV30_3D_TEX_FILTER_SIGNED_GREEN |
124				 NV30_3D_TEX_FILTER_SIGNED_BLUE |
125				 NV30_3D_TEX_FILTER_MIN_LINEAR |
126				 NV30_3D_TEX_FILTER_MAG_LINEAR | 0x2000);
127	else
128		PUSH_DATA (push, NV30_3D_TEX_FILTER_MIN_LINEAR |
129				 NV30_3D_TEX_FILTER_MAG_LINEAR | 0x2000);
130	PUSH_DATA (push, (width << NV30_3D_TEX_NPOT_SIZE_W__SHIFT) | height);
131	PUSH_DATA (push, 0); /* border ARGB */
132	BEGIN_NV04(push, NV30_3D(TEX_MATRIX_ENABLE(unit)), 1);
133	PUSH_DATA (push, 0);
134
135	return TRUE;
136}
137
138static Bool
139NV30GetSurfaceFormat(PixmapPtr ppix, int *fmt_ret)
140{
141	switch (ppix->drawable.bitsPerPixel) {
142		case 32:
143			*fmt_ret = NV30_3D_RT_FORMAT_COLOR_A8R8G8B8;
144			break;
145		case 24:
146			*fmt_ret = NV30_3D_RT_FORMAT_COLOR_X8R8G8B8;
147			break;
148		case 16:
149			*fmt_ret = NV30_3D_RT_FORMAT_COLOR_R5G6B5;
150			break;
151		case 8:
152			*fmt_ret = NV30_3D_RT_FORMAT_COLOR_B8;
153			break;
154		default:
155			return FALSE;
156	}
157
158	return TRUE;
159}
160
161void
162NV30StopTexturedVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
163{
164}
165
166#define VERTEX_OUT(sx,sy,dx,dy) do {                                           \
167	BEGIN_NV04(push, NV30_3D(VTX_ATTR_2F_X(8)), 4);                        \
168	PUSH_DATAf(push, (sx)); PUSH_DATAf(push, (sy));                        \
169	PUSH_DATAf(push, (sx)/2.0); PUSH_DATAf(push, (sy)/2.0);                \
170	BEGIN_NV04(push, NV30_3D(VTX_ATTR_2I(0)), 1);                          \
171	PUSH_DATA (push, (((dy)&0xffff)<<16)|((dx)&0xffff));                   \
172} while(0)
173
174int
175NV30PutTextureImage(ScrnInfoPtr pScrn, struct nouveau_bo *src, int src_offset,
176		    int src_offset2, int id, int src_pitch, BoxPtr dstBox,
177		    int x1, int y1, int x2, int y2,
178		    uint16_t width, uint16_t height,
179		    uint16_t src_w, uint16_t src_h,
180		    uint16_t drw_w, uint16_t drw_h,
181		    RegionPtr clipBoxes,
182		    PixmapPtr ppix,
183		    NVPortPrivPtr pPriv)
184{
185	NVPtr pNv = NVPTR(pScrn);
186	struct nouveau_pushbuf *push = pNv->pushbuf;
187	struct nouveau_bo *bo = nouveau_pixmap_bo(ppix);
188	Bool bicubic = pPriv->bicubic;
189	float X1, X2, Y1, Y2;
190	BoxPtr pbox;
191	int nbox;
192	int dst_format = 0;
193
194	if (drw_w > 4096 || drw_h > 4096) {
195		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
196			"XV: Draw size too large.\n");
197		return BadAlloc;
198	}
199
200	if (!NV30GetSurfaceFormat(ppix, &dst_format)) {
201		ErrorF("No surface format, bad.\n");
202		return BadImplementation;
203	}
204
205	pbox = REGION_RECTS(clipBoxes);
206	nbox = REGION_NUM_RECTS(clipBoxes);
207
208	if (!PUSH_SPACE(push, 128))
209		return FALSE;
210	PUSH_RESET(push);
211
212	BEGIN_NV04(push, NV30_3D(BLEND_FUNC_ENABLE), 1);
213	PUSH_DATA (push, 0);
214	BEGIN_NV04(push, NV30_3D(RT_FORMAT), 3);
215	PUSH_DATA (push, NV30_3D_RT_FORMAT_TYPE_LINEAR |
216			 NV30_3D_RT_FORMAT_ZETA_Z24S8 |
217			 dst_format);
218	PUSH_DATA (push, (exaGetPixmapPitch(ppix) << 16) |
219			  exaGetPixmapPitch(ppix));
220	PUSH_MTHDl(push, NV30_3D(COLOR0_OFFSET), bo, 0,
221			 NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
222
223	if (pNv->dev->chipset == 0x30) {
224		int x = 0;
225		int y = 0;
226		int w = ppix->drawable.x + ppix->drawable.width;
227		int h = ppix->drawable.y + ppix->drawable.height;
228
229		BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
230		PUSH_DATA (push, (w<<16)|x);
231		PUSH_DATA (push, (h<<16)|y);
232		BEGIN_NV04(push, NV30_3D(VIEWPORT_CLIP_HORIZ(0)), 2);
233		PUSH_DATA (push, (w-1+x)<<16);
234		PUSH_DATA (push, (h-1+y)<<16);
235		BEGIN_NV04(push, NV30_3D(VIEWPORT_TX_ORIGIN), 1);
236		PUSH_DATA (push, (y<<16)|x);
237	}
238
239	BEGIN_NV04(push, NV30_3D(TEX_UNITS_ENABLE), 1);
240	PUSH_DATA (push, NV30_3D_TEX_UNITS_ENABLE_TX0 |
241			 NV30_3D_TEX_UNITS_ENABLE_TX1);
242
243	if (!NV30VideoTexture(pScrn, pNv->scratch, XV_TABLE, XV_TABLE_SIZE,
244				     1, 0, 0) ||
245	    !NV30VideoTexture(pScrn, src, src_offset, src_w, src_h,
246		    	      src_pitch, 1))
247		return BadImplementation;
248
249	/* We've got NV12 format, which means half width and half height
250	 * texture of chroma channels.
251	 */
252	if (!NV30VideoTexture(pScrn, src, src_offset2, src_w/2, src_h/2,
253			      src_pitch, 2)) {
254		PUSH_RESET(push);
255		return BadImplementation;
256	}
257
258	BEGIN_NV04(push, NV30_3D(TEX_ENABLE(3)), 1);
259	PUSH_DATA (push, 0x0);
260
261	if (drw_w / 2 < src_w || drw_h / 2 < src_h)
262		bicubic = FALSE;
263
264	BEGIN_NV04(push, NV30_3D(FP_ACTIVE_PROGRAM), 1);
265	PUSH_MTHD (push, NV30_3D(FP_ACTIVE_PROGRAM), pNv->scratch,
266			 bicubic ? PFP_NV12_BICUBIC : PFP_NV12_BILINEAR,
267			 NOUVEAU_BO_VRAM | NOUVEAU_BO_RD | NOUVEAU_BO_LOW |
268			 NOUVEAU_BO_OR,
269			 NV30_3D_FP_ACTIVE_PROGRAM_DMA0,
270			 NV30_3D_FP_ACTIVE_PROGRAM_DMA1);
271	BEGIN_NV04(push, NV30_3D(FP_REG_CONTROL), 1);
272	PUSH_DATA (push, 0x0001000f);
273	BEGIN_NV04(push, NV30_3D(FP_CONTROL), 1);
274	PUSH_DATA (push, 0x00000001);
275	BEGIN_NV04(push, NV30_3D(RC_ENABLE), 1);
276	PUSH_DATA (push, 0x00000000);
277
278	nouveau_pushbuf_bufctx(push, pNv->bufctx);
279	if (nouveau_pushbuf_validate(push)) {
280		nouveau_pushbuf_bufctx(push, NULL);
281		return BadAlloc;
282	}
283
284	/* Before rendering we wait for vblank in the non-composited case. */
285	if (pPriv->SyncToVBlank)
286		NV11SyncToVBlank(ppix, dstBox);
287
288	/* These are fixed point values in the 16.16 format. */
289	X1 = (float)(x1>>16)+(float)(x1&0xFFFF)/(float)0x10000;
290	Y1 = (float)(y1>>16)+(float)(y1&0xFFFF)/(float)0x10000;
291	X2 = (float)(x2>>16)+(float)(x2&0xFFFF)/(float)0x10000;
292	Y2 = (float)(y2>>16)+(float)(y2&0xFFFF)/(float)0x10000;
293
294	BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
295	PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_TRIANGLES);
296	while (nbox--) {
297		float tx1=X1+(float)(pbox->x1 - dstBox->x1)*(X2-X1)/(float)(drw_w);
298		float tx2=X1+(float)(pbox->x2 - dstBox->x1)*(src_w)/(float)(drw_w);
299		float ty1=Y1+(float)(pbox->y1 - dstBox->y1)*(Y2-Y1)/(float)(drw_h);
300		float ty2=Y1+(float)(pbox->y2 - dstBox->y1)*(src_h)/(float)(drw_h);
301		int sx1=pbox->x1;
302		int sx2=pbox->x2;
303		int sy1=pbox->y1;
304		int sy2=pbox->y2;
305
306		if (!PUSH_SPACE(push, 64)) {
307			nouveau_pushbuf_bufctx(push, NULL);
308			return BadImplementation;
309		}
310
311		BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2);
312		PUSH_DATA (push, (sx2 << 16) | 0);
313		PUSH_DATA (push, (sy2 << 16) | 0);
314
315		VERTEX_OUT(tx1, ty1, sx1, sy1);
316		VERTEX_OUT(tx2+(tx2-tx1), ty1, sx2+(sx2-sx1), sy1);
317		VERTEX_OUT(tx1, ty2+(ty2-ty1), sx1, sy2+(sy2-sy1));
318
319		pbox++;
320	}
321	BEGIN_NV04(push, NV30_3D(VERTEX_BEGIN_END), 1);
322	PUSH_DATA (push, NV30_3D_VERTEX_BEGIN_END_STOP);
323
324	if (pNv->dev->chipset == 0x30) {
325		BEGIN_NV04(push, NV30_3D(VIEWPORT_HORIZ), 2);
326		PUSH_DATA (push, 4096 << 16);
327		PUSH_DATA (push, 4096 << 16);
328		BEGIN_NV04(push, NV30_3D(VIEWPORT_CLIP_HORIZ(0)), 2);
329		PUSH_DATA (push, 4095 << 16);
330		PUSH_DATA (push, 4095 << 16);
331		BEGIN_NV04(push, NV30_3D(VIEWPORT_TX_ORIGIN), 1);
332		PUSH_DATA (push, 0);
333	}
334
335	nouveau_pushbuf_bufctx(push, NULL);
336	PUSH_KICK(push);
337	return Success;
338}
339
340/**
341 * NV30SetTexturePortAttribute
342 * sets the attribute "attribute" of port "data" to value "value"
343 * supported attributes:
344 * Sync to vblank.
345 *
346 * @param pScrenInfo
347 * @param attribute attribute to set
348 * @param value value to which attribute is to be set
349 * @param data port from which the attribute is to be set
350 *
351 * @return Success, if setting is successful
352 * BadValue/BadMatch, if value/attribute are invalid
353 */
354int
355NV30SetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
356                       INT32 value, pointer data)
357{
358        NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
359
360        if (attribute == xvSyncToVBlank) {
361                if ((value < 0) || (value > 1))
362                        return BadValue;
363                pPriv->SyncToVBlank = value;
364        } else
365        if (attribute == xvSetDefaults) {
366                pPriv->SyncToVBlank = TRUE;
367        } else
368                return BadMatch;
369
370        return Success;
371}
372
373/**
374 * NV30GetTexturePortAttribute
375 * reads the value of attribute "attribute" from port "data" into INT32 "*value"
376 * Sync to vblank.
377 *
378 * @param pScrn unused
379 * @param attribute attribute to be read
380 * @param value value of attribute will be stored here
381 * @param data port from which attribute will be read
382 * @return Success, if queried attribute exists
383 */
384int
385NV30GetTexturePortAttribute(ScrnInfoPtr pScrn, Atom attribute,
386                       INT32 *value, pointer data)
387{
388        NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
389
390        if(attribute == xvSyncToVBlank)
391                *value = (pPriv->SyncToVBlank) ? 1 : 0;
392        else
393                return BadMatch;
394
395        return Success;
396}
397
398