1fda9279dSmrg/*
2fda9279dSmrg * Copyright 2008 Ben Skeggs
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#ifdef HAVE_CONFIG_H
24fda9279dSmrg#include "config.h"
25fda9279dSmrg#endif
26fda9279dSmrg
27479f40c1Smrg#include "xorg-config.h"
28fda9279dSmrg#include "xf86xv.h"
29fda9279dSmrg#include <X11/extensions/Xv.h>
30fda9279dSmrg#include "exa.h"
31fda9279dSmrg#include "damage.h"
32fda9279dSmrg#include "dixstruct.h"
33fda9279dSmrg#include "fourcc.h"
34fda9279dSmrg
35fda9279dSmrg#include "nv_include.h"
36fda9279dSmrg#include "nvc0_accel.h"
37fda9279dSmrg
38fda9279dSmrgextern Atom xvSyncToVBlank, xvSetDefaults;
39fda9279dSmrg
40fda9279dSmrgstatic Bool
41fda9279dSmrgnvc0_xv_check_image_put(PixmapPtr ppix)
42fda9279dSmrg{
43fda9279dSmrg	switch (ppix->drawable.bitsPerPixel) {
44fda9279dSmrg	case 32:
45fda9279dSmrg	case 24:
46fda9279dSmrg	case 16:
47fda9279dSmrg	case 15:
48fda9279dSmrg		break;
49fda9279dSmrg	default:
50fda9279dSmrg		return FALSE;
51fda9279dSmrg	}
52fda9279dSmrg
53fda9279dSmrg	if (!nv50_style_tiled_pixmap(ppix))
54fda9279dSmrg		return FALSE;
55fda9279dSmrg
56fda9279dSmrg	return TRUE;
57fda9279dSmrg}
58fda9279dSmrg
59fda9279dSmrgint
60fda9279dSmrgnvc0_xv_image_put(ScrnInfoPtr pScrn,
61fda9279dSmrg		  struct nouveau_bo *src, int packed_y, int uv,
62fda9279dSmrg		  int id, int src_pitch, BoxPtr dstBox,
63fda9279dSmrg		  int x1, int y1, int x2, int y2,
64fda9279dSmrg		  uint16_t width, uint16_t height,
65fda9279dSmrg		  uint16_t src_w, uint16_t src_h,
66fda9279dSmrg		  uint16_t drw_w, uint16_t drw_h,
67fda9279dSmrg		  RegionPtr clipBoxes, PixmapPtr ppix,
68fda9279dSmrg		  NVPortPrivPtr pPriv)
69fda9279dSmrg{
70fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
71fda9279dSmrg	struct nouveau_bo *dst = nouveau_pixmap_bo(ppix);
72fda9279dSmrg	struct nouveau_pushbuf_refn refs[] = {
73fda9279dSmrg		{ pNv->scratch, NOUVEAU_BO_VRAM | NOUVEAU_BO_RDWR },
74fda9279dSmrg		{ src, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD },
75fda9279dSmrg		{ dst, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR },
76fda9279dSmrg	};
77fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
78fda9279dSmrg	float X1, X2, Y1, Y2;
79fda9279dSmrg	BoxPtr pbox;
80fda9279dSmrg	int nbox;
81fda9279dSmrg
82fda9279dSmrg	if (!nvc0_xv_check_image_put(ppix))
83fda9279dSmrg		return BadMatch;
84fda9279dSmrg
85fda9279dSmrg	if (!PUSH_SPACE(push, 256))
86fda9279dSmrg		return BadImplementation;
87fda9279dSmrg
88fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(RT_ADDRESS_HIGH(0)), 8);
89fda9279dSmrg	PUSH_DATA (push, dst->offset >> 32);
90fda9279dSmrg	PUSH_DATA (push, dst->offset);
91fda9279dSmrg	PUSH_DATA (push, ppix->drawable.width);
92fda9279dSmrg	PUSH_DATA (push, ppix->drawable.height);
9322d74663Smrg	switch (ppix->drawable.depth) {
94fda9279dSmrg	case 32: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGRA8_UNORM); break;
9522d74663Smrg	case 30: PUSH_DATA (push, NV50_SURFACE_FORMAT_RGB10_A2_UNORM); break;
96fda9279dSmrg	case 24: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGRX8_UNORM); break;
97fda9279dSmrg	case 16: PUSH_DATA (push, NV50_SURFACE_FORMAT_B5G6R5_UNORM); break;
98fda9279dSmrg	case 15: PUSH_DATA (push, NV50_SURFACE_FORMAT_BGR5_X1_UNORM); break;
99fda9279dSmrg	}
100fda9279dSmrg	PUSH_DATA (push, dst->config.nvc0.tile_mode);
101fda9279dSmrg	PUSH_DATA (push, 1);
102fda9279dSmrg	PUSH_DATA (push, 0);
103fda9279dSmrg
104fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(BLEND_ENABLE(0)), 1);
105fda9279dSmrg	PUSH_DATA (push, 0);
106fda9279dSmrg
107fda9279dSmrg	PUSH_DATAu(push, pNv->scratch, TIC_OFFSET, 16);
108fda9279dSmrg	if (id == FOURCC_YV12 || id == FOURCC_I420) {
1091090d90aSmrg		PUSH_TIC(push, src, packed_y, width, height, 0,
1101090d90aSmrg			 NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM |
111fda9279dSmrg			 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
112fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
113fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
114fda9279dSmrg			 NV50TIC_0_0_FMT_8);
1151090d90aSmrg		PUSH_TIC(push, src, uv, width >> 1, height >> 1, 0,
1161090d90aSmrg			 NV50TIC_0_0_MAPA_C1 | NV50TIC_0_0_TYPEA_UNORM |
117fda9279dSmrg			 NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEB_UNORM |
118fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
119fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
120fda9279dSmrg			 NV50TIC_0_0_FMT_8_8);
121fda9279dSmrg	} else {
1221090d90aSmrg		unsigned format;
1231090d90aSmrg		if (id == FOURCC_UYVY) {
1241090d90aSmrg		format = NV50TIC_0_0_MAPA_C1 | NV50TIC_0_0_TYPEA_UNORM |
125fda9279dSmrg			 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
126fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
127fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
1281090d90aSmrg			 NV50TIC_0_0_FMT_8_8;
1291090d90aSmrg		} else {
1301090d90aSmrg		format = NV50TIC_0_0_MAPA_C0 | NV50TIC_0_0_TYPEA_UNORM |
131fda9279dSmrg			 NV50TIC_0_0_MAPB_ZERO | NV50TIC_0_0_TYPEB_UNORM |
132fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
133fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
1341090d90aSmrg			 NV50TIC_0_0_FMT_8_8;
1351090d90aSmrg		}
1361090d90aSmrg		PUSH_TIC(push, src, packed_y, width, height, 0, format);
1371090d90aSmrg
1381090d90aSmrg		if (id == FOURCC_UYVY) {
1391090d90aSmrg		format = NV50TIC_0_0_MAPA_C2 | NV50TIC_0_0_TYPEA_UNORM |
140fda9279dSmrg			 NV50TIC_0_0_MAPB_C0 | NV50TIC_0_0_TYPEB_UNORM |
141fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
142fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
1431090d90aSmrg			 NV50TIC_0_0_FMT_8_8_8_8;
1441090d90aSmrg		} else {
1451090d90aSmrg		format = NV50TIC_0_0_MAPA_C3 | NV50TIC_0_0_TYPEA_UNORM |
146fda9279dSmrg			 NV50TIC_0_0_MAPB_C1 | NV50TIC_0_0_TYPEB_UNORM |
147fda9279dSmrg			 NV50TIC_0_0_MAPG_ZERO | NV50TIC_0_0_TYPEG_UNORM |
148fda9279dSmrg			 NV50TIC_0_0_MAPR_ZERO | NV50TIC_0_0_TYPER_UNORM |
1491090d90aSmrg			 NV50TIC_0_0_FMT_8_8_8_8;
1501090d90aSmrg		}
1511090d90aSmrg		PUSH_TIC(push, src, packed_y, width >> 1, height, 0, format);
152fda9279dSmrg	}
153fda9279dSmrg
154fda9279dSmrg	PUSH_DATAu(push, pNv->scratch, TSC_OFFSET, 16);
155fda9279dSmrg	PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
156fda9279dSmrg			 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
157fda9279dSmrg			 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
158fda9279dSmrg	PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR |
159fda9279dSmrg			 NV50TSC_1_1_MINF_LINEAR |
160fda9279dSmrg			 NV50TSC_1_1_MIPF_NONE);
161fda9279dSmrg	PUSH_DATA (push, 0x00000000);
162fda9279dSmrg	PUSH_DATA (push, 0x00000000);
163fda9279dSmrg	PUSH_DATA (push, 0x00000000);
164fda9279dSmrg	PUSH_DATA (push, 0x00000000);
165fda9279dSmrg	PUSH_DATA (push, 0x00000000);
166fda9279dSmrg	PUSH_DATA (push, 0x00000000);
167fda9279dSmrg	PUSH_DATA (push, NV50TSC_1_0_WRAPS_CLAMP_TO_EDGE |
168fda9279dSmrg			 NV50TSC_1_0_WRAPT_CLAMP_TO_EDGE |
169fda9279dSmrg			 NV50TSC_1_0_WRAPR_CLAMP_TO_EDGE);
170fda9279dSmrg	PUSH_DATA (push, NV50TSC_1_1_MAGF_LINEAR |
171fda9279dSmrg			 NV50TSC_1_1_MINF_LINEAR |
172fda9279dSmrg			 NV50TSC_1_1_MIPF_NONE);
173fda9279dSmrg	PUSH_DATA (push, 0x00000000);
174fda9279dSmrg	PUSH_DATA (push, 0x00000000);
175fda9279dSmrg	PUSH_DATA (push, 0x00000000);
176fda9279dSmrg	PUSH_DATA (push, 0x00000000);
177fda9279dSmrg	PUSH_DATA (push, 0x00000000);
178fda9279dSmrg	PUSH_DATA (push, 0x00000000);
179fda9279dSmrg
180fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(SP_START_ID(5)), 1);
181fda9279dSmrg	PUSH_DATA (push, PFP_NV12);
182fda9279dSmrg
183fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(TSC_FLUSH), 1);
184fda9279dSmrg	PUSH_DATA (push, 0);
185fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(TIC_FLUSH), 1);
186fda9279dSmrg	PUSH_DATA (push, 0);
187fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(TEX_CACHE_CTL), 1);
188fda9279dSmrg	PUSH_DATA (push, 0);
189fda9279dSmrg
190fda9279dSmrg	PUSH_DATAu(push, pNv->scratch, PVP_DATA, 11);
191fda9279dSmrg	PUSH_DATAf(push, 1.0);
192fda9279dSmrg	PUSH_DATAf(push, 0.0);
193fda9279dSmrg	PUSH_DATAf(push, 0.0);
194fda9279dSmrg	PUSH_DATAf(push, 0.0);
195fda9279dSmrg	PUSH_DATAf(push, 1.0);
196fda9279dSmrg	PUSH_DATAf(push, 0.0);
197fda9279dSmrg	PUSH_DATAf(push, 0.0);
198fda9279dSmrg	PUSH_DATAf(push, 0.0);
199fda9279dSmrg	PUSH_DATAf(push, 1.0);
200fda9279dSmrg	PUSH_DATAf(push, 1.0 / width);
201fda9279dSmrg	PUSH_DATAf(push, 1.0 / height);
202fda9279dSmrg
203fda9279dSmrg	if (pPriv->SyncToVBlank) {
204fda9279dSmrg		NVC0SyncToVBlank(ppix, dstBox);
205fda9279dSmrg	}
206fda9279dSmrg
207fda9279dSmrg	/* These are fixed point values in the 16.16 format. */
208fda9279dSmrg	X1 = (float)(x1>>16)+(float)(x1&0xFFFF)/(float)0x10000;
209fda9279dSmrg	Y1 = (float)(y1>>16)+(float)(y1&0xFFFF)/(float)0x10000;
210fda9279dSmrg	X2 = (float)(x2>>16)+(float)(x2&0xFFFF)/(float)0x10000;
211fda9279dSmrg	Y2 = (float)(y2>>16)+(float)(y2&0xFFFF)/(float)0x10000;
212fda9279dSmrg
213fda9279dSmrg	pbox = REGION_RECTS(clipBoxes);
214fda9279dSmrg	nbox = REGION_NUM_RECTS(clipBoxes);
215fda9279dSmrg	while(nbox--) {
216fda9279dSmrg		float tx1=X1+(float)(pbox->x1 - dstBox->x1)*(X2-X1)/(float)(drw_w);
217fda9279dSmrg		float tx2=X1+(float)(pbox->x2 - dstBox->x1)*(src_w)/(float)(drw_w);
218fda9279dSmrg		float ty1=Y1+(float)(pbox->y1 - dstBox->y1)*(Y2-Y1)/(float)(drw_h);
219fda9279dSmrg		float ty2=Y1+(float)(pbox->y2 - dstBox->y1)*(src_h)/(float)(drw_h);
220fda9279dSmrg		int sx1=pbox->x1;
221fda9279dSmrg		int sx2=pbox->x2;
222fda9279dSmrg		int sy1=pbox->y1;
223fda9279dSmrg		int sy2=pbox->y2;
224fda9279dSmrg
225fda9279dSmrg		if (nouveau_pushbuf_space(push, 64, 0, 0) ||
226fda9279dSmrg		    nouveau_pushbuf_refn (push, refs, 3))
227fda9279dSmrg			return BadImplementation;
228fda9279dSmrg
2291090d90aSmrg		if (pNv->dev->chipset >= 0x110) {
2301090d90aSmrg			BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
2311090d90aSmrg			PUSH_DATA (push, 256);
2321090d90aSmrg			PUSH_DATA (push, (pNv->scratch->offset + PVP_DATA) >> 32);
2331090d90aSmrg			PUSH_DATA (push, (pNv->scratch->offset + PVP_DATA));
2341090d90aSmrg			BEGIN_1IC0(push, NVC0_3D(CB_POS), 24 + 1);
2351090d90aSmrg			PUSH_DATA (push, 0x80);
2361090d90aSmrg
2371090d90aSmrg			PUSH_DATAf(push, sx1);
2381090d90aSmrg			PUSH_DATAf(push, sy1);
2391090d90aSmrg			PUSH_DATAf(push, 0);
2401090d90aSmrg			PUSH_DATAf(push, 1);
2411090d90aSmrg			PUSH_DATAf(push, tx1);
2421090d90aSmrg			PUSH_DATAf(push, ty1);
2431090d90aSmrg			PUSH_DATAf(push, 0);
2441090d90aSmrg			PUSH_DATAf(push, 0);
2451090d90aSmrg
2461090d90aSmrg			PUSH_DATAf(push, sx2+(sx2-sx1));
2471090d90aSmrg			PUSH_DATAf(push, sy1);
2481090d90aSmrg			PUSH_DATAf(push, 0);
2491090d90aSmrg			PUSH_DATAf(push, 1);
2501090d90aSmrg			PUSH_DATAf(push, tx2+(tx2-tx1));
2511090d90aSmrg			PUSH_DATAf(push, ty1);
2521090d90aSmrg			PUSH_DATAf(push, 0);
2531090d90aSmrg			PUSH_DATAf(push, 0);
2541090d90aSmrg
2551090d90aSmrg			PUSH_DATAf(push, sx1);
2561090d90aSmrg			PUSH_DATAf(push, sy2+(sy2-sy1));
2571090d90aSmrg			PUSH_DATAf(push, 0);
2581090d90aSmrg			PUSH_DATAf(push, 1);
2591090d90aSmrg			PUSH_DATAf(push, tx1);
2601090d90aSmrg			PUSH_DATAf(push, ty2+(ty2-ty1));
2611090d90aSmrg			PUSH_DATAf(push, 0);
2621090d90aSmrg			PUSH_DATAf(push, 0);
2631090d90aSmrg		}
2641090d90aSmrg
265fda9279dSmrg		BEGIN_NVC0(push, NVC0_3D(SCISSOR_HORIZ(0)), 2);
266fda9279dSmrg		PUSH_DATA (push, sx2 << NVC0_3D_SCISSOR_HORIZ_MAX__SHIFT | sx1);
267fda9279dSmrg		PUSH_DATA (push, sy2 << NVC0_3D_SCISSOR_VERT_MAX__SHIFT | sy1 );
268fda9279dSmrg
269fda9279dSmrg		BEGIN_NVC0(push, NVC0_3D(VERTEX_BEGIN_GL), 1);
270fda9279dSmrg		PUSH_DATA (push, NVC0_3D_VERTEX_BEGIN_GL_PRIMITIVE_TRIANGLES);
2711090d90aSmrg		if (pNv->dev->chipset < 0x110) {
2721090d90aSmrg			PUSH_VTX1s(push, tx1, ty1, sx1, sy1);
2731090d90aSmrg			PUSH_VTX1s(push, tx2+(tx2-tx1), ty1, sx2+(sx2-sx1), sy1);
2741090d90aSmrg			PUSH_VTX1s(push, tx1, ty2+(ty2-ty1), sx1, sy2+(sy2-sy1));
2751090d90aSmrg		} else {
2761090d90aSmrg			BEGIN_NVC0(push, NVC0_3D(VERTEX_BUFFER_FIRST), 2);
2771090d90aSmrg			PUSH_DATA (push, 0);
2781090d90aSmrg			PUSH_DATA (push, 3);
2791090d90aSmrg		}
280fda9279dSmrg		BEGIN_NVC0(push, NVC0_3D(VERTEX_END_GL), 1);
281fda9279dSmrg		PUSH_DATA (push, 0);
282fda9279dSmrg
283fda9279dSmrg		pbox++;
284fda9279dSmrg	}
285fda9279dSmrg
286fda9279dSmrg	PUSH_KICK(push);
287fda9279dSmrg	return Success;
288fda9279dSmrg}
289fda9279dSmrg
290fda9279dSmrgvoid
291fda9279dSmrgnvc0_xv_csc_update(NVPtr pNv, float yco, float *off, float *uco, float *vco)
292fda9279dSmrg{
293fda9279dSmrg	struct nouveau_pushbuf *push = pNv->pushbuf;
294fda9279dSmrg
295fda9279dSmrg	if (nouveau_pushbuf_space(push, 64, 0, 0) ||
296fda9279dSmrg	    nouveau_pushbuf_refn (push, &(struct nouveau_pushbuf_refn) {
297fda9279dSmrg					pNv->scratch, NOUVEAU_BO_WR |
298fda9279dSmrg					NOUVEAU_BO_VRAM }, 1))
299fda9279dSmrg		return;
300fda9279dSmrg
301fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(CB_SIZE), 3);
302fda9279dSmrg	PUSH_DATA (push, 256);
303fda9279dSmrg	PUSH_DATA (push, (pNv->scratch->offset + PFP_DATA) >> 32);
304fda9279dSmrg	PUSH_DATA (push, (pNv->scratch->offset + PFP_DATA));
305fda9279dSmrg	BEGIN_NVC0(push, NVC0_3D(CB_POS), 11);
306fda9279dSmrg	PUSH_DATA (push, 0);
307fda9279dSmrg	PUSH_DATAf(push, yco);
308fda9279dSmrg	PUSH_DATAf(push, off[0]);
309fda9279dSmrg	PUSH_DATAf(push, off[1]);
310fda9279dSmrg	PUSH_DATAf(push, off[2]);
311fda9279dSmrg	PUSH_DATAf(push, uco[0]);
312fda9279dSmrg	PUSH_DATAf(push, uco[1]);
313fda9279dSmrg	PUSH_DATAf(push, uco[2]);
314fda9279dSmrg	PUSH_DATAf(push, vco[0]);
315fda9279dSmrg	PUSH_DATAf(push, vco[1]);
316fda9279dSmrg	PUSH_DATAf(push, vco[2]);
317fda9279dSmrg}
318