nouveau_xv.c revision fda9279d
1fda9279dSmrg/*
2fda9279dSmrg * Copyright 2007 Arthur Huillet
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
24fda9279dSmrg#ifdef HAVE_CONFIG_H
25fda9279dSmrg#include "config.h"
26fda9279dSmrg#endif
27fda9279dSmrg
28fda9279dSmrg#ifdef __SSE2__
29fda9279dSmrg#include <immintrin.h>
30fda9279dSmrg#endif
31fda9279dSmrg
32fda9279dSmrg#include "xf86xv.h"
33fda9279dSmrg#include <X11/extensions/Xv.h>
34fda9279dSmrg#include "exa.h"
35fda9279dSmrg#include "damage.h"
36fda9279dSmrg#include "dixstruct.h"
37fda9279dSmrg#include "fourcc.h"
38fda9279dSmrg
39fda9279dSmrg#include "nv_include.h"
40fda9279dSmrg#include "nv_dma.h"
41fda9279dSmrg#include "nouveau_glamor.h"
42fda9279dSmrg
43fda9279dSmrg#include "vl_hwmc.h"
44fda9279dSmrg
45fda9279dSmrg#include "hwdefs/nv_m2mf.xml.h"
46fda9279dSmrg
47fda9279dSmrg#define IMAGE_MAX_W 2046
48fda9279dSmrg#define IMAGE_MAX_H 2046
49fda9279dSmrg
50fda9279dSmrg#define TEX_IMAGE_MAX_W 4096
51fda9279dSmrg#define TEX_IMAGE_MAX_H 4096
52fda9279dSmrg
53fda9279dSmrg#define OFF_DELAY 	500  /* milliseconds */
54fda9279dSmrg#define FREE_DELAY 	5000
55fda9279dSmrg
56fda9279dSmrg#define NUM_BLIT_PORTS 16
57fda9279dSmrg#define NUM_TEXTURE_PORTS 32
58fda9279dSmrg
59fda9279dSmrg
60fda9279dSmrg#define NVStopOverlay(X) (((pNv->Architecture == NV_ARCH_04) ? NV04StopOverlay(X) : NV10StopOverlay(X)))
61fda9279dSmrg
62fda9279dSmrg/* Value taken by pPriv -> currentHostBuffer when we failed to allocate the two private buffers in TT memory, so that we can catch this case
63fda9279dSmrgand attempt no other allocation afterwards (performance reasons) */
64fda9279dSmrg#define NO_PRIV_HOST_BUFFER_AVAILABLE 9999
65fda9279dSmrg
66fda9279dSmrg/* NVPutImage action flags */
67fda9279dSmrgenum {
68fda9279dSmrg	IS_YV12 = 1,
69fda9279dSmrg	IS_YUY2 = 2,
70fda9279dSmrg	CONVERT_TO_YUY2=4,
71fda9279dSmrg	USE_OVERLAY=8,
72fda9279dSmrg	USE_TEXTURE=16,
73fda9279dSmrg	SWAP_UV=32,
74fda9279dSmrg	IS_RGB=64, //I am not sure how long we will support it
75fda9279dSmrg};
76fda9279dSmrg
77fda9279dSmrg#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
78fda9279dSmrg
79fda9279dSmrgAtom xvBrightness, xvContrast, xvColorKey, xvSaturation;
80fda9279dSmrgAtom xvHue, xvAutopaintColorKey, xvSetDefaults, xvDoubleBuffer;
81fda9279dSmrgAtom xvITURBT709, xvSyncToVBlank, xvOnCRTCNb;
82fda9279dSmrg
83fda9279dSmrg/* client libraries expect an encoding */
84fda9279dSmrgstatic XF86VideoEncodingRec DummyEncoding =
85fda9279dSmrg{
86fda9279dSmrg	0,
87fda9279dSmrg	"XV_IMAGE",
88fda9279dSmrg	IMAGE_MAX_W, IMAGE_MAX_H,
89fda9279dSmrg	{1, 1}
90fda9279dSmrg};
91fda9279dSmrg
92fda9279dSmrgstatic XF86VideoEncodingRec DummyEncodingTex =
93fda9279dSmrg{
94fda9279dSmrg	0,
95fda9279dSmrg	"XV_IMAGE",
96fda9279dSmrg	TEX_IMAGE_MAX_W, TEX_IMAGE_MAX_H,
97fda9279dSmrg	{1, 1}
98fda9279dSmrg};
99fda9279dSmrg
100fda9279dSmrgstatic XF86VideoEncodingRec DummyEncodingNV50 =
101fda9279dSmrg{
102fda9279dSmrg	0,
103fda9279dSmrg	"XV_IMAGE",
104fda9279dSmrg	8192, 8192,
105fda9279dSmrg	{1, 1}
106fda9279dSmrg};
107fda9279dSmrg
108fda9279dSmrg#define NUM_FORMATS_ALL 6
109fda9279dSmrg
110fda9279dSmrgXF86VideoFormatRec NVFormats[NUM_FORMATS_ALL] =
111fda9279dSmrg{
112fda9279dSmrg	{15, TrueColor}, {16, TrueColor}, {24, TrueColor},
113fda9279dSmrg	{15, DirectColor}, {16, DirectColor}, {24, DirectColor}
114fda9279dSmrg};
115fda9279dSmrg
116fda9279dSmrg#define NUM_NV04_OVERLAY_ATTRIBUTES 4
117fda9279dSmrgXF86AttributeRec NV04OverlayAttributes[NUM_NV04_OVERLAY_ATTRIBUTES] =
118fda9279dSmrg{
119fda9279dSmrg	    {XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
120fda9279dSmrg	    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
121fda9279dSmrg	    {XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
122fda9279dSmrg	    {XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
123fda9279dSmrg};
124fda9279dSmrg
125fda9279dSmrg
126fda9279dSmrg#define NUM_NV10_OVERLAY_ATTRIBUTES 10
127fda9279dSmrgXF86AttributeRec NV10OverlayAttributes[NUM_NV10_OVERLAY_ATTRIBUTES] =
128fda9279dSmrg{
129fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"},
130fda9279dSmrg	{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
131fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_AUTOPAINT_COLORKEY"},
132fda9279dSmrg	{XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
133fda9279dSmrg	{XvSettable | XvGettable, -512, 511, "XV_BRIGHTNESS"},
134fda9279dSmrg	{XvSettable | XvGettable, 0, 8191, "XV_CONTRAST"},
135fda9279dSmrg	{XvSettable | XvGettable, 0, 8191, "XV_SATURATION"},
136fda9279dSmrg	{XvSettable | XvGettable, 0, 360, "XV_HUE"},
137fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_ITURBT_709"},
138fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_ON_CRTC_NB"},
139fda9279dSmrg};
140fda9279dSmrg
141fda9279dSmrg#define NUM_BLIT_ATTRIBUTES 2
142fda9279dSmrgXF86AttributeRec NVBlitAttributes[NUM_BLIT_ATTRIBUTES] =
143fda9279dSmrg{
144fda9279dSmrg	{XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
145fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
146fda9279dSmrg};
147fda9279dSmrg
148fda9279dSmrg#define NUM_TEXTURED_ATTRIBUTES 2
149fda9279dSmrgXF86AttributeRec NVTexturedAttributes[NUM_TEXTURED_ATTRIBUTES] =
150fda9279dSmrg{
151fda9279dSmrg	{XvSettable             , 0, 0, "XV_SET_DEFAULTS"},
152fda9279dSmrg	{XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK"}
153fda9279dSmrg};
154fda9279dSmrg
155fda9279dSmrg#define NUM_TEXTURED_ATTRIBUTES_NV50 7
156fda9279dSmrgXF86AttributeRec NVTexturedAttributesNV50[NUM_TEXTURED_ATTRIBUTES_NV50] =
157fda9279dSmrg{
158fda9279dSmrg	{ XvSettable             , 0, 0, "XV_SET_DEFAULTS" },
159fda9279dSmrg	{ XvSettable | XvGettable, 0, 1, "XV_SYNC_TO_VBLANK" },
160fda9279dSmrg	{ XvSettable | XvGettable, -1000, 1000, "XV_BRIGHTNESS" },
161fda9279dSmrg	{ XvSettable | XvGettable, -1000, 1000, "XV_CONTRAST" },
162fda9279dSmrg	{ XvSettable | XvGettable, -1000, 1000, "XV_SATURATION" },
163fda9279dSmrg	{ XvSettable | XvGettable, -1000, 1000, "XV_HUE" },
164fda9279dSmrg	{ XvSettable | XvGettable, 0, 1, "XV_ITURBT_709" }
165fda9279dSmrg};
166fda9279dSmrg
167fda9279dSmrg#define NUM_IMAGES_YUV 4
168fda9279dSmrg#define NUM_IMAGES_ALL 5
169fda9279dSmrg
170fda9279dSmrg#define FOURCC_RGB 0x0000003
171fda9279dSmrg#define XVIMAGE_RGB \
172fda9279dSmrg   { \
173fda9279dSmrg        FOURCC_RGB, \
174fda9279dSmrg        XvRGB, \
175fda9279dSmrg        LSBFirst, \
176fda9279dSmrg        { 0x03, 0x00, 0x00, 0x00, \
177fda9279dSmrg          0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
178fda9279dSmrg        32, \
179fda9279dSmrg        XvPacked, \
180fda9279dSmrg        1, \
181fda9279dSmrg        24, 0x00ff0000, 0x0000ff00, 0x000000ff, \
182fda9279dSmrg        0, 0, 0, \
183fda9279dSmrg        0, 0, 0, \
184fda9279dSmrg        0, 0, 0, \
185fda9279dSmrg        {'B','G','R','X',\
186fda9279dSmrg          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
187fda9279dSmrg        XvTopToBottom \
188fda9279dSmrg   }
189fda9279dSmrg
190fda9279dSmrgstatic XF86ImageRec NVImages[NUM_IMAGES_ALL] =
191fda9279dSmrg{
192fda9279dSmrg	XVIMAGE_YUY2,
193fda9279dSmrg	XVIMAGE_YV12,
194fda9279dSmrg	XVIMAGE_UYVY,
195fda9279dSmrg	XVIMAGE_I420,
196fda9279dSmrg	XVIMAGE_RGB
197fda9279dSmrg};
198fda9279dSmrg
199fda9279dSmrgstatic void
200fda9279dSmrgnouveau_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
201fda9279dSmrg{
202fda9279dSmrg    dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
203fda9279dSmrg    dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
204fda9279dSmrg    dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
205fda9279dSmrg    dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
206fda9279dSmrg
207fda9279dSmrg    if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
208fda9279dSmrg	dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
209fda9279dSmrg}
210fda9279dSmrg
211fda9279dSmrgstatic void
212fda9279dSmrgnouveau_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
213fda9279dSmrg{
214fda9279dSmrg    if (crtc->enabled) {
215fda9279dSmrg	crtc_box->x1 = crtc->x;
216fda9279dSmrg	crtc_box->x2 = crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
217fda9279dSmrg	crtc_box->y1 = crtc->y;
218fda9279dSmrg	crtc_box->y2 = crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
219fda9279dSmrg    } else
220fda9279dSmrg	crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
221fda9279dSmrg}
222fda9279dSmrg
223fda9279dSmrgstatic int
224fda9279dSmrgnouveau_box_area(BoxPtr box)
225fda9279dSmrg{
226fda9279dSmrg    return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
227fda9279dSmrg}
228fda9279dSmrg
229fda9279dSmrgxf86CrtcPtr
230fda9279dSmrgnouveau_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled,
231fda9279dSmrg                       int x, int y, int w, int h)
232fda9279dSmrg{
233fda9279dSmrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
234fda9279dSmrg    int                 coverage, best_coverage, c;
235fda9279dSmrg    BoxRec              box, crtc_box, cover_box;
236fda9279dSmrg    RROutputPtr         primary_output = NULL;
237fda9279dSmrg    xf86CrtcPtr         best_crtc = NULL, primary_crtc = NULL;
238fda9279dSmrg
239fda9279dSmrg    if (!pScrn->vtSema)
240fda9279dSmrg	return NULL;
241fda9279dSmrg
242fda9279dSmrg    box.x1 = x;
243fda9279dSmrg    box.x2 = x + w;
244fda9279dSmrg    box.y1 = y;
245fda9279dSmrg    box.y2 = y + h;
246fda9279dSmrg    best_coverage = 0;
247fda9279dSmrg
248fda9279dSmrg    /* Prefer the CRTC of the primary output */
249fda9279dSmrg#ifdef HAS_DIXREGISTERPRIVATEKEY
250fda9279dSmrg    if (dixPrivateKeyRegistered(rrPrivKey))
251fda9279dSmrg#endif
252fda9279dSmrg    {
253fda9279dSmrg	primary_output = RRFirstOutput(pScrn->pScreen);
254fda9279dSmrg    }
255fda9279dSmrg    if (primary_output && primary_output->crtc)
256fda9279dSmrg	primary_crtc = primary_output->crtc->devPrivate;
257fda9279dSmrg
258fda9279dSmrg    /* first consider only enabled CRTCs */
259fda9279dSmrg    for (c = 0; c < xf86_config->num_crtc; c++) {
260fda9279dSmrg	xf86CrtcPtr crtc = xf86_config->crtc[c];
261fda9279dSmrg
262fda9279dSmrg	if (!crtc->enabled)
263fda9279dSmrg	    continue;
264fda9279dSmrg
265fda9279dSmrg	nouveau_crtc_box(crtc, &crtc_box);
266fda9279dSmrg	nouveau_box_intersect(&cover_box, &crtc_box, &box);
267fda9279dSmrg	coverage = nouveau_box_area(&cover_box);
268fda9279dSmrg	if (coverage > best_coverage ||
269fda9279dSmrg	    (coverage == best_coverage && crtc == primary_crtc)) {
270fda9279dSmrg	    best_crtc = crtc;
271fda9279dSmrg	    best_coverage = coverage;
272fda9279dSmrg	}
273fda9279dSmrg    }
274fda9279dSmrg    if (best_crtc || !consider_disabled)
275fda9279dSmrg	return best_crtc;
276fda9279dSmrg
277fda9279dSmrg    /* if we found nothing, repeat the search including disabled CRTCs */
278fda9279dSmrg    for (c = 0; c < xf86_config->num_crtc; c++) {
279fda9279dSmrg	xf86CrtcPtr crtc = xf86_config->crtc[c];
280fda9279dSmrg
281fda9279dSmrg	nouveau_crtc_box(crtc, &crtc_box);
282fda9279dSmrg	nouveau_box_intersect(&cover_box, &crtc_box, &box);
283fda9279dSmrg	coverage = nouveau_box_area(&cover_box);
284fda9279dSmrg	if (coverage > best_coverage ||
285fda9279dSmrg	    (coverage == best_coverage && crtc == primary_crtc)) {
286fda9279dSmrg	    best_crtc = crtc;
287fda9279dSmrg	    best_coverage = coverage;
288fda9279dSmrg	}
289fda9279dSmrg    }
290fda9279dSmrg    return best_crtc;
291fda9279dSmrg}
292fda9279dSmrg
293fda9279dSmrgunsigned int
294fda9279dSmrgnv_window_belongs_to_crtc(ScrnInfoPtr pScrn, int x, int y, int w, int h)
295fda9279dSmrg{
296fda9279dSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
297fda9279dSmrg	unsigned int mask = 0;
298fda9279dSmrg	int i;
299fda9279dSmrg
300fda9279dSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
301fda9279dSmrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
302fda9279dSmrg
303fda9279dSmrg		if (!crtc->enabled)
304fda9279dSmrg			continue;
305fda9279dSmrg
306fda9279dSmrg		if ((x < (crtc->x + crtc->mode.HDisplay)) &&
307fda9279dSmrg		    (y < (crtc->y + crtc->mode.VDisplay)) &&
308fda9279dSmrg		    ((x + w) > crtc->x) &&
309fda9279dSmrg		    ((y + h) > crtc->y))
310fda9279dSmrg		    mask |= 1 << i;
311fda9279dSmrg	}
312fda9279dSmrg
313fda9279dSmrg	return mask;
314fda9279dSmrg}
315fda9279dSmrg
316fda9279dSmrg/**
317fda9279dSmrg * NVSetPortDefaults
318fda9279dSmrg * set attributes of port "pPriv" to compiled-in (except for colorKey) defaults
319fda9279dSmrg * this function does not care about the kind of adapter the port is for
320fda9279dSmrg *
321fda9279dSmrg * @param pScrn screen to get the default colorKey from
322fda9279dSmrg * @param pPriv port to reset to defaults
323fda9279dSmrg */
324fda9279dSmrgvoid
325fda9279dSmrgNVSetPortDefaults (ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
326fda9279dSmrg{
327fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
328fda9279dSmrg
329fda9279dSmrg	pPriv->brightness		= 0;
330fda9279dSmrg	pPriv->contrast			= 4096;
331fda9279dSmrg	pPriv->saturation		= 4096;
332fda9279dSmrg	pPriv->hue			= 0;
333fda9279dSmrg	pPriv->colorKey			= pNv->videoKey;
334fda9279dSmrg	pPriv->autopaintColorKey	= TRUE;
335fda9279dSmrg	pPriv->doubleBuffer		= pNv->Architecture != NV_ARCH_04;
336fda9279dSmrg	pPriv->iturbt_709		= FALSE;
337fda9279dSmrg	pPriv->currentHostBuffer	= 0;
338fda9279dSmrg}
339fda9279dSmrg
340fda9279dSmrgstatic int
341fda9279dSmrgnouveau_xv_bo_realloc(ScrnInfoPtr pScrn, unsigned flags, unsigned size,
342fda9279dSmrg		      struct nouveau_bo **pbo)
343fda9279dSmrg{
344fda9279dSmrg	union nouveau_bo_config config = {};
345fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
346fda9279dSmrg
347fda9279dSmrg	if (*pbo) {
348fda9279dSmrg		if ((*pbo)->size >= size)
349fda9279dSmrg			return 0;
350fda9279dSmrg		nouveau_bo_ref(NULL, pbo);
351fda9279dSmrg	}
352fda9279dSmrg
353fda9279dSmrg	if (flags & NOUVEAU_BO_VRAM) {
354fda9279dSmrg		if (pNv->Architecture == NV_TESLA)
355fda9279dSmrg			config.nv50.memtype = 0x70;
356fda9279dSmrg		else
357fda9279dSmrg		if (pNv->Architecture >= NV_FERMI)
358fda9279dSmrg			config.nvc0.memtype = 0xfe;
359fda9279dSmrg	}
360fda9279dSmrg	flags |= NOUVEAU_BO_MAP;
361fda9279dSmrg
362fda9279dSmrg	return nouveau_bo_new(pNv->dev, flags, 0, size, &config, pbo);
363fda9279dSmrg}
364fda9279dSmrg
365fda9279dSmrg/**
366fda9279dSmrg * NVFreePortMemory
367fda9279dSmrg * frees memory held by a given port
368fda9279dSmrg *
369fda9279dSmrg * @param pScrn screen whose port wants to free memory
370fda9279dSmrg * @param pPriv port to free memory of
371fda9279dSmrg */
372fda9279dSmrgstatic void
373fda9279dSmrgNVFreePortMemory(ScrnInfoPtr pScrn, NVPortPrivPtr pPriv)
374fda9279dSmrg{
375fda9279dSmrg	nouveau_bo_ref(NULL, &pPriv->video_mem);
376fda9279dSmrg	nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[0]);
377fda9279dSmrg	nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[1]);
378fda9279dSmrg}
379fda9279dSmrg
380fda9279dSmrg/**
381fda9279dSmrg * NVFreeOverlayMemory
382fda9279dSmrg * frees memory held by the overlay port
383fda9279dSmrg *
384fda9279dSmrg * @param pScrn screen whose overlay port wants to free memory
385fda9279dSmrg */
386fda9279dSmrgstatic void
387fda9279dSmrgNVFreeOverlayMemory(ScrnInfoPtr pScrn)
388fda9279dSmrg{
389fda9279dSmrg	NVPtr	pNv = NVPTR(pScrn);
390fda9279dSmrg	NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
391fda9279dSmrg
392fda9279dSmrg	NVFreePortMemory(pScrn, pPriv);
393fda9279dSmrg#if NVOVL_SUPPORT
394fda9279dSmrg	/* "power cycle" the overlay */
395fda9279dSmrg	nvWriteMC(pNv, NV_PMC_ENABLE,
396fda9279dSmrg		  (nvReadMC(pNv, NV_PMC_ENABLE) & 0xEFFFFFFF));
397fda9279dSmrg	nvWriteMC(pNv, NV_PMC_ENABLE,
398fda9279dSmrg		  (nvReadMC(pNv, NV_PMC_ENABLE) | 0x10000000));
399fda9279dSmrg#endif
400fda9279dSmrg}
401fda9279dSmrg
402fda9279dSmrg/**
403fda9279dSmrg * NVFreeBlitMemory
404fda9279dSmrg * frees memory held by the blit port
405fda9279dSmrg *
406fda9279dSmrg * @param pScrn screen whose blit port wants to free memory
407fda9279dSmrg */
408fda9279dSmrgstatic void
409fda9279dSmrgNVFreeBlitMemory(ScrnInfoPtr pScrn)
410fda9279dSmrg{
411fda9279dSmrg	NVPtr	pNv = NVPTR(pScrn);
412fda9279dSmrg	NVPortPrivPtr pPriv = GET_BLIT_PRIVATE(pNv);
413fda9279dSmrg
414fda9279dSmrg	NVFreePortMemory(pScrn, pPriv);
415fda9279dSmrg}
416fda9279dSmrg
417fda9279dSmrg/**
418fda9279dSmrg * NVVideoTimerCallback
419fda9279dSmrg * callback function which perform cleanup tasks (stop overlay, free memory).
420fda9279dSmrg * within the driver
421fda9279dSmrg * purpose and use is unknown
422fda9279dSmrg */
423fda9279dSmrgvoid
424fda9279dSmrgNVVideoTimerCallback(ScrnInfoPtr pScrn, Time currentTime)
425fda9279dSmrg{
426fda9279dSmrg	NVPtr         pNv = NVPTR(pScrn);
427fda9279dSmrg	NVPortPrivPtr pOverPriv = NULL;
428fda9279dSmrg	NVPortPrivPtr pBlitPriv = NULL;
429fda9279dSmrg	Bool needCallback = FALSE;
430fda9279dSmrg
431fda9279dSmrg	if (!pScrn->vtSema)
432fda9279dSmrg		return;
433fda9279dSmrg
434fda9279dSmrg	if (pNv->overlayAdaptor) {
435fda9279dSmrg		pOverPriv = GET_OVERLAY_PRIVATE(pNv);
436fda9279dSmrg		if (!pOverPriv->videoStatus)
437fda9279dSmrg			pOverPriv = NULL;
438fda9279dSmrg	}
439fda9279dSmrg
440fda9279dSmrg	if (pNv->blitAdaptor) {
441fda9279dSmrg		pBlitPriv = GET_BLIT_PRIVATE(pNv);
442fda9279dSmrg		if (!pBlitPriv->videoStatus)
443fda9279dSmrg			pBlitPriv = NULL;
444fda9279dSmrg	}
445fda9279dSmrg
446fda9279dSmrg	if (pOverPriv) {
447fda9279dSmrg		if (pOverPriv->videoTime < currentTime) {
448fda9279dSmrg			if (pOverPriv->videoStatus & OFF_TIMER) {
449fda9279dSmrg				NVStopOverlay(pScrn);
450fda9279dSmrg				pOverPriv->videoStatus = FREE_TIMER;
451fda9279dSmrg				pOverPriv->videoTime = currentTime + FREE_DELAY;
452fda9279dSmrg				needCallback = TRUE;
453fda9279dSmrg			} else
454fda9279dSmrg			if (pOverPriv->videoStatus & FREE_TIMER) {
455fda9279dSmrg				NVFreeOverlayMemory(pScrn);
456fda9279dSmrg				pOverPriv->videoStatus = 0;
457fda9279dSmrg			}
458fda9279dSmrg		} else {
459fda9279dSmrg			needCallback = TRUE;
460fda9279dSmrg		}
461fda9279dSmrg	}
462fda9279dSmrg
463fda9279dSmrg	if (pBlitPriv) {
464fda9279dSmrg		if (pBlitPriv->videoTime < currentTime) {
465fda9279dSmrg			NVFreeBlitMemory(pScrn);
466fda9279dSmrg			pBlitPriv->videoStatus = 0;
467fda9279dSmrg		} else {
468fda9279dSmrg			needCallback = TRUE;
469fda9279dSmrg		}
470fda9279dSmrg	}
471fda9279dSmrg
472fda9279dSmrg	pNv->VideoTimerCallback = needCallback ? NVVideoTimerCallback : NULL;
473fda9279dSmrg}
474fda9279dSmrg
475fda9279dSmrg#ifndef ExaOffscreenMarkUsed
476fda9279dSmrgextern void ExaOffscreenMarkUsed(PixmapPtr);
477fda9279dSmrg#endif
478fda9279dSmrg
479fda9279dSmrg/*
480fda9279dSmrg * StopVideo
481fda9279dSmrg */
482fda9279dSmrgstatic void
483fda9279dSmrgNVStopOverlayVideo(ScrnInfoPtr pScrn, pointer data, Bool Exit)
484fda9279dSmrg{
485fda9279dSmrg	NVPtr         pNv   = NVPTR(pScrn);
486fda9279dSmrg	NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
487fda9279dSmrg
488fda9279dSmrg	if (pPriv->grabbedByV4L)
489fda9279dSmrg		return;
490fda9279dSmrg
491fda9279dSmrg	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
492fda9279dSmrg
493fda9279dSmrg	if(Exit) {
494fda9279dSmrg		if (pPriv->videoStatus & CLIENT_VIDEO_ON)
495fda9279dSmrg			NVStopOverlay(pScrn);
496fda9279dSmrg		NVFreeOverlayMemory(pScrn);
497fda9279dSmrg		pPriv->videoStatus = 0;
498fda9279dSmrg	} else {
499fda9279dSmrg		if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
500fda9279dSmrg			pPriv->videoStatus = OFF_TIMER | CLIENT_VIDEO_ON;
501fda9279dSmrg			pPriv->videoTime = currentTime.milliseconds + OFF_DELAY;
502fda9279dSmrg			pNv->VideoTimerCallback = NVVideoTimerCallback;
503fda9279dSmrg		}
504fda9279dSmrg	}
505fda9279dSmrg}
506fda9279dSmrg
507fda9279dSmrg/**
508fda9279dSmrg * QueryBestSize
509fda9279dSmrg * used by client applications to ask the driver:
510fda9279dSmrg * how would you actually scale a video of dimensions
511fda9279dSmrg * vid_w, vid_h, if i wanted you to scale it to dimensions
512fda9279dSmrg * drw_w, drw_h?
513fda9279dSmrg * function stores actual scaling size in pointers p_w, p_h.
514fda9279dSmrg *
515fda9279dSmrg *
516fda9279dSmrg * @param pScrn unused
517fda9279dSmrg * @param motion unused
518fda9279dSmrg * @param vid_w width of source video
519fda9279dSmrg * @param vid_h height of source video
520fda9279dSmrg * @param drw_w desired scaled width as requested by client
521fda9279dSmrg * @param drw_h desired scaled height as requested by client
522fda9279dSmrg * @param p_w actual scaled width as the driver is capable of
523fda9279dSmrg * @param p_h actual scaled height as the driver is capable of
524fda9279dSmrg * @param data unused
525fda9279dSmrg */
526fda9279dSmrgstatic void
527fda9279dSmrgNVQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
528fda9279dSmrg		short vid_w, short vid_h,
529fda9279dSmrg		short drw_w, short drw_h,
530fda9279dSmrg		unsigned int *p_w, unsigned int *p_h,
531fda9279dSmrg		pointer data)
532fda9279dSmrg{
533fda9279dSmrg	if(vid_w > (drw_w << 3))
534fda9279dSmrg		drw_w = vid_w >> 3;
535fda9279dSmrg	if(vid_h > (drw_h << 3))
536fda9279dSmrg		drw_h = vid_h >> 3;
537fda9279dSmrg
538fda9279dSmrg	*p_w = drw_w;
539fda9279dSmrg	*p_h = drw_h;
540fda9279dSmrg}
541fda9279dSmrg
542fda9279dSmrg/**
543fda9279dSmrg * NVCopyData420
544fda9279dSmrg * used to convert YV12 to YUY2 for the blitter and NV04 overlay.
545fda9279dSmrg * The U and V samples generated are linearly interpolated on the vertical
546fda9279dSmrg * axis for better quality
547fda9279dSmrg *
548fda9279dSmrg * @param src1 source buffer of luma
549fda9279dSmrg * @param src2 source buffer of chroma1
550fda9279dSmrg * @param src3 source buffer of chroma2
551fda9279dSmrg * @param dst1 destination buffer
552fda9279dSmrg * @param srcPitch pitch of src1
553fda9279dSmrg * @param srcPitch2 pitch of src2, src3
554fda9279dSmrg * @param dstPitch pitch of dst1
555fda9279dSmrg * @param h number of lines to copy
556fda9279dSmrg * @param w length of lines to copy
557fda9279dSmrg */
558fda9279dSmrgstatic inline void
559fda9279dSmrgNVCopyData420(unsigned char *src1, unsigned char *src2, unsigned char *src3,
560fda9279dSmrg	      unsigned char *dst1, int srcPitch, int srcPitch2, int dstPitch,
561fda9279dSmrg	      int h, int w)
562fda9279dSmrg{
563fda9279dSmrg	CARD32 *dst;
564fda9279dSmrg	CARD8 *s1, *s2, *s3;
565fda9279dSmrg	int i, j;
566fda9279dSmrg
567fda9279dSmrg#define su(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s2[X] +        \
568fda9279dSmrg		(signed int)(s2 + srcPitch2)[X]) / 2) : (s2[X]))
569fda9279dSmrg#define sv(X) (((j & 1) && j < (h-1)) ? ((unsigned)((signed int)s3[X] +        \
570fda9279dSmrg		(signed int)(s3 + srcPitch2)[X]) / 2) : (s3[X]))
571fda9279dSmrg
572fda9279dSmrg	w >>= 1;
573fda9279dSmrg
574fda9279dSmrg	for (j = 0; j < h; j++) {
575fda9279dSmrg		dst = (CARD32*)dst1;
576fda9279dSmrg		s1 = src1;  s2 = src2;  s3 = src3;
577fda9279dSmrg		i = w;
578fda9279dSmrg
579fda9279dSmrg		while (i > 4) {
580fda9279dSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
581fda9279dSmrg		dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0);
582fda9279dSmrg		dst[1] = (s1[2] << 24) | (s1[3] << 8) | (sv(1) << 16) | su(1);
583fda9279dSmrg		dst[2] = (s1[4] << 24) | (s1[5] << 8) | (sv(2) << 16) | su(2);
584fda9279dSmrg		dst[3] = (s1[6] << 24) | (s1[7] << 8) | (sv(3) << 16) | su(3);
585fda9279dSmrg#else
586fda9279dSmrg		dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24);
587fda9279dSmrg		dst[1] = s1[2] | (s1[3] << 16) | (sv(1) << 8) | (su(1) << 24);
588fda9279dSmrg		dst[2] = s1[4] | (s1[5] << 16) | (sv(2) << 8) | (su(2) << 24);
589fda9279dSmrg		dst[3] = s1[6] | (s1[7] << 16) | (sv(3) << 8) | (su(3) << 24);
590fda9279dSmrg#endif
591fda9279dSmrg		dst += 4; s2 += 4; s3 += 4; s1 += 8;
592fda9279dSmrg		i -= 4;
593fda9279dSmrg		}
594fda9279dSmrg
595fda9279dSmrg		while (i--) {
596fda9279dSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
597fda9279dSmrg		dst[0] = (s1[0] << 24) | (s1[1] << 8) | (sv(0) << 16) | su(0);
598fda9279dSmrg#else
599fda9279dSmrg		dst[0] = s1[0] | (s1[1] << 16) | (sv(0) << 8) | (su(0) << 24);
600fda9279dSmrg#endif
601fda9279dSmrg		dst++; s2++; s3++;
602fda9279dSmrg		s1 += 2;
603fda9279dSmrg		}
604fda9279dSmrg
605fda9279dSmrg		dst1 += dstPitch;
606fda9279dSmrg		src1 += srcPitch;
607fda9279dSmrg		if (j & 1) {
608fda9279dSmrg			src2 += srcPitch2;
609fda9279dSmrg			src3 += srcPitch2;
610fda9279dSmrg		}
611fda9279dSmrg	}
612fda9279dSmrg}
613fda9279dSmrg
614fda9279dSmrg/**
615fda9279dSmrg * NVCopyNV12ColorPlanes
616fda9279dSmrg * Used to convert YV12 color planes to NV12 (interleaved UV) for the overlay
617fda9279dSmrg *
618fda9279dSmrg * @param src1 source buffer of chroma1
619fda9279dSmrg * @param dst1 destination buffer
620fda9279dSmrg * @param h number of lines to copy
621fda9279dSmrg * @param w length of lines to copy
622fda9279dSmrg * @param id source pixel format (YV12 or I420)
623fda9279dSmrg */
624fda9279dSmrgstatic inline void
625fda9279dSmrgNVCopyNV12ColorPlanes(unsigned char *src1, unsigned char *src2,
626fda9279dSmrg		      unsigned char *dst, int dstPitch, int srcPitch2,
627fda9279dSmrg		      int h, int w)
628fda9279dSmrg{
629fda9279dSmrg	int i, j, l, e;
630fda9279dSmrg
631fda9279dSmrg	w >>= 1;
632fda9279dSmrg	h >>= 1;
633fda9279dSmrg#ifdef __SSE2__
634fda9279dSmrg	l = w >> 3;
635fda9279dSmrg	e = w & 7;
636fda9279dSmrg#else
637fda9279dSmrg	l = w >> 1;
638fda9279dSmrg	e = w & 1;
639fda9279dSmrg#endif
640fda9279dSmrg
641fda9279dSmrg	for (j = 0; j < h; j++) {
642fda9279dSmrg		unsigned char *us = src1;
643fda9279dSmrg		unsigned char *vs = src2;
644fda9279dSmrg		unsigned int *vuvud = (unsigned int *) dst;
645fda9279dSmrg		unsigned short *vud;
646fda9279dSmrg
647fda9279dSmrg		for (i = 0; i < l; i++) {
648fda9279dSmrg#ifdef __SSE2__
649fda9279dSmrg			_mm_storeu_si128(
650fda9279dSmrg				(void*)vuvud,
651fda9279dSmrg				_mm_unpacklo_epi8(
652fda9279dSmrg					_mm_loadl_epi64((void*)vs),
653fda9279dSmrg					_mm_loadl_epi64((void*)us)));
654fda9279dSmrg			vuvud+=4;
655fda9279dSmrg			us+=8;
656fda9279dSmrg			vs+=8;
657fda9279dSmrg#else /* __SSE2__ */
658fda9279dSmrg#  if X_BYTE_ORDER == X_BIG_ENDIAN
659fda9279dSmrg			*vuvud++ = (vs[0]<<24) | (us[0]<<16) | (vs[1]<<8) | us[1];
660fda9279dSmrg#  else
661fda9279dSmrg			*vuvud++ = vs[0] | (us[0]<<8) | (vs[1]<<16) | (us[1]<<24);
662fda9279dSmrg#  endif
663fda9279dSmrg			us+=2;
664fda9279dSmrg			vs+=2;
665fda9279dSmrg#endif /* __SSE2__ */
666fda9279dSmrg		}
667fda9279dSmrg
668fda9279dSmrg		vud = (unsigned short *)vuvud;
669fda9279dSmrg		for (i = 0; i < e; i++) {
670fda9279dSmrg#if X_BYTE_ORDER == X_BIG_ENDIAN
671fda9279dSmrg			vud[i] = us[i] | (vs[i]<<8);
672fda9279dSmrg#else
673fda9279dSmrg			vud[i] = vs[i] | (us[i]<<8);
674fda9279dSmrg#endif
675fda9279dSmrg		}
676fda9279dSmrg
677fda9279dSmrg		dst += dstPitch;
678fda9279dSmrg		src1 += srcPitch2;
679fda9279dSmrg		src2 += srcPitch2;
680fda9279dSmrg	}
681fda9279dSmrg
682fda9279dSmrg}
683fda9279dSmrg
684fda9279dSmrg
685fda9279dSmrgstatic int
686fda9279dSmrgNV_set_dimensions(ScrnInfoPtr pScrn, int action_flags, INT32 *xa, INT32 *xb,
687fda9279dSmrg		  INT32 *ya, INT32 *yb, short *src_x, short *src_y,
688fda9279dSmrg		  short *src_w, short *src_h, short *drw_x, short *drw_y,
689fda9279dSmrg		  short *drw_w, short *drw_h, int *left, int *top, int *right,
690fda9279dSmrg		  int *bottom, BoxRec *dstBox, int *npixels, int *nlines,
691fda9279dSmrg		  RegionPtr clipBoxes, short width, short height)
692fda9279dSmrg{
693fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
694fda9279dSmrg
695fda9279dSmrg	if (action_flags & USE_OVERLAY) {
696fda9279dSmrg		switch (pNv->Architecture) {
697fda9279dSmrg		case NV_ARCH_04:
698fda9279dSmrg			/* NV0x overlay can't scale down. at all. */
699fda9279dSmrg			if (*drw_w < *src_w)
700fda9279dSmrg				*drw_w = *src_w;
701fda9279dSmrg			if (*drw_h < *src_h)
702fda9279dSmrg				*drw_h = *src_h;
703fda9279dSmrg			break;
704fda9279dSmrg		case NV_ARCH_30:
705fda9279dSmrg			/* According to DirectFB, NV3x can't scale down by
706fda9279dSmrg			 * a ratio > 2
707fda9279dSmrg			 */
708fda9279dSmrg			if (*drw_w < (*src_w) >> 1)
709fda9279dSmrg				*drw_w = *src_w;
710fda9279dSmrg			if (*drw_h < (*src_h) >> 1)
711fda9279dSmrg				*drw_h = *src_h;
712fda9279dSmrg			break;
713fda9279dSmrg		default: /*NV10, NV20*/
714fda9279dSmrg			/* NV1x overlay can't scale down by a ratio > 8 */
715fda9279dSmrg			if (*drw_w < (*src_w) >> 3)
716fda9279dSmrg				*drw_w = *src_w >> 3;
717fda9279dSmrg			if (*drw_h < (*src_h >> 3))
718fda9279dSmrg				*drw_h = *src_h >> 3;
719fda9279dSmrg		}
720fda9279dSmrg	}
721fda9279dSmrg
722fda9279dSmrg	/* Clip */
723fda9279dSmrg	*xa = *src_x;
724fda9279dSmrg	*xb = *src_x + *src_w;
725fda9279dSmrg	*ya = *src_y;
726fda9279dSmrg	*yb = *src_y + *src_h;
727fda9279dSmrg
728fda9279dSmrg	dstBox->x1 = *drw_x;
729fda9279dSmrg	dstBox->x2 = *drw_x + *drw_w;
730fda9279dSmrg	dstBox->y1 = *drw_y;
731fda9279dSmrg	dstBox->y2 = *drw_y + *drw_h;
732fda9279dSmrg
733fda9279dSmrg	/* In randr 1.2 mode VIDEO_CLIP_TO_VIEWPORT is broken (hence it is not
734fda9279dSmrg	 * set in the overlay adapter flags) since pScrn->frame{X,Y}1 do not get
735fda9279dSmrg	 * updated. Hence manual clipping against the CRTC dimensions
736fda9279dSmrg	 */
737fda9279dSmrg	if (action_flags & USE_OVERLAY) {
738fda9279dSmrg		NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
739fda9279dSmrg		unsigned id = pPriv->overlayCRTC;
740fda9279dSmrg		xf86CrtcPtr crtc = XF86_CRTC_CONFIG_PTR(pScrn)->crtc[id];
741fda9279dSmrg		RegionRec VPReg;
742fda9279dSmrg		BoxRec VPBox;
743fda9279dSmrg
744fda9279dSmrg		VPBox.x1 = crtc->x;
745fda9279dSmrg		VPBox.y1 = crtc->y;
746fda9279dSmrg		VPBox.x2 = crtc->x + crtc->mode.HDisplay;
747fda9279dSmrg		VPBox.y2 = crtc->y + crtc->mode.VDisplay;
748fda9279dSmrg
749fda9279dSmrg		REGION_INIT(pScreen, &VPReg, &VPBox, 1);
750fda9279dSmrg		REGION_INTERSECT(pScreen, clipBoxes, clipBoxes, &VPReg);
751fda9279dSmrg		REGION_UNINIT(pScreen, &VPReg);
752fda9279dSmrg	}
753fda9279dSmrg
754fda9279dSmrg	if (!xf86XVClipVideoHelper(dstBox, xa, xb, ya, yb, clipBoxes,
755fda9279dSmrg				   width, height))
756fda9279dSmrg		return -1;
757fda9279dSmrg
758fda9279dSmrg	if (action_flags & USE_OVERLAY)	{
759fda9279dSmrg		xf86CrtcConfigPtr xf86_config =
760fda9279dSmrg			XF86_CRTC_CONFIG_PTR(pScrn);
761fda9279dSmrg		NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
762fda9279dSmrg
763fda9279dSmrg		dstBox->x1 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
764fda9279dSmrg		dstBox->x2 -= xf86_config->crtc[pPriv->overlayCRTC]->x;
765fda9279dSmrg		dstBox->y1 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
766fda9279dSmrg		dstBox->y2 -= xf86_config->crtc[pPriv->overlayCRTC]->y;
767fda9279dSmrg	}
768fda9279dSmrg
769fda9279dSmrg	/* Convert fixed point to integer, as xf86XVClipVideoHelper probably
770fda9279dSmrg	 * turns its parameter into fixed point values
771fda9279dSmrg	 */
772fda9279dSmrg	*left = (*xa) >> 16;
773fda9279dSmrg	if (*left < 0)
774fda9279dSmrg		*left = 0;
775fda9279dSmrg
776fda9279dSmrg	*top = (*ya) >> 16;
777fda9279dSmrg	if (*top < 0)
778fda9279dSmrg		*top = 0;
779fda9279dSmrg
780fda9279dSmrg	*right = (*xb) >> 16;
781fda9279dSmrg	if (*right > width)
782fda9279dSmrg		*right = width;
783fda9279dSmrg
784fda9279dSmrg	*bottom = (*yb) >> 16;
785fda9279dSmrg	if (*bottom > height)
786fda9279dSmrg		*bottom = height;
787fda9279dSmrg
788fda9279dSmrg	if (action_flags & IS_YV12) {
789fda9279dSmrg		/* even "left", even "top", even number of pixels per line
790fda9279dSmrg		 * and even number of lines
791fda9279dSmrg		 */
792fda9279dSmrg		*left &= ~1;
793fda9279dSmrg		*npixels = ((*right + 1) & ~1) - *left;
794fda9279dSmrg		*top &= ~1;
795fda9279dSmrg		*nlines = ((*bottom + 1) & ~1) - *top;
796fda9279dSmrg	} else
797fda9279dSmrg	if (action_flags & IS_YUY2) {
798fda9279dSmrg		/* even "left" */
799fda9279dSmrg		*left &= ~1;
800fda9279dSmrg		/* even number of pixels per line */
801fda9279dSmrg		*npixels = ((*right + 1) & ~1) - *left;
802fda9279dSmrg		*nlines = *bottom - *top;
803fda9279dSmrg		/* 16bpp */
804fda9279dSmrg		*left <<= 1;
805fda9279dSmrg	} else
806fda9279dSmrg	if (action_flags & IS_RGB) {
807fda9279dSmrg		*npixels = *right - *left;
808fda9279dSmrg		*nlines = *bottom - *top;
809fda9279dSmrg		/* 32bpp */
810fda9279dSmrg		*left <<= 2;
811fda9279dSmrg	}
812fda9279dSmrg
813fda9279dSmrg	return 0;
814fda9279dSmrg}
815fda9279dSmrg
816fda9279dSmrgstatic int
817fda9279dSmrgNV_calculate_pitches_and_mem_size(NVPtr pNv, int action_flags, int *srcPitch,
818fda9279dSmrg				  int *srcPitch2, int *dstPitch, int *s2offset,
819fda9279dSmrg				  int *s3offset, int *uv_offset,
820fda9279dSmrg				  int *newFBSize, int *newTTSize,
821fda9279dSmrg				  int *line_len, int npixels, int nlines,
822fda9279dSmrg				  int width, int height)
823fda9279dSmrg{
824fda9279dSmrg	int tmp;
825fda9279dSmrg
826fda9279dSmrg	if (pNv->Architecture >= NV_TESLA) {
827fda9279dSmrg		npixels = (npixels + 7) & ~7;
828fda9279dSmrg		nlines = (nlines + 7) & ~7;
829fda9279dSmrg	}
830fda9279dSmrg
831fda9279dSmrg	if (action_flags & IS_YV12) {
832fda9279dSmrg		*srcPitch = (width + 3) & ~3;	/* of luma */
833fda9279dSmrg		*s2offset = *srcPitch * height;
834fda9279dSmrg		*srcPitch2 = ((width >> 1) + 3) & ~3; /*of chroma*/
835fda9279dSmrg		*s3offset = (*srcPitch2 * (height >> 1)) + *s2offset;
836fda9279dSmrg		*dstPitch = (npixels + 63) & ~63; /*luma and chroma pitch*/
837fda9279dSmrg		*line_len = npixels;
838fda9279dSmrg		*uv_offset = nlines * *dstPitch;
839fda9279dSmrg		*newFBSize = *uv_offset + (nlines >> 1) * *dstPitch;
840fda9279dSmrg		*newTTSize = *uv_offset + (nlines >> 1) * *dstPitch;
841fda9279dSmrg	} else
842fda9279dSmrg	if (action_flags & IS_YUY2) {
843fda9279dSmrg		*srcPitch = width << 1; /* one luma, one chroma per pixel */
844fda9279dSmrg		*dstPitch = ((npixels << 1) + 63) & ~63;
845fda9279dSmrg		*line_len = npixels << 1;
846fda9279dSmrg		*newFBSize = nlines * *dstPitch;
847fda9279dSmrg		*newTTSize = nlines * *line_len;
848fda9279dSmrg	} else
849fda9279dSmrg	if (action_flags & IS_RGB) {
850fda9279dSmrg		/* one R, one G, one B, one X per pixel */
851fda9279dSmrg		*srcPitch = width << 2;
852fda9279dSmrg		*dstPitch = ((npixels << 2) + 63) & ~63;
853fda9279dSmrg		*line_len = npixels << 2;
854fda9279dSmrg		*newFBSize = nlines * *dstPitch;
855fda9279dSmrg		*newTTSize = nlines * *dstPitch;
856fda9279dSmrg	}
857fda9279dSmrg
858fda9279dSmrg	if (action_flags & CONVERT_TO_YUY2) {
859fda9279dSmrg		*dstPitch = ((npixels << 1) + 63) & ~63;
860fda9279dSmrg		*line_len = npixels << 1;
861fda9279dSmrg		*newFBSize = nlines * *dstPitch;
862fda9279dSmrg		*newTTSize = nlines * *line_len;
863fda9279dSmrg		*uv_offset = 0;
864fda9279dSmrg	}
865fda9279dSmrg
866fda9279dSmrg	if (action_flags & SWAP_UV)  {
867fda9279dSmrg		/* I420 swaps U and V */
868fda9279dSmrg		tmp = *s2offset;
869fda9279dSmrg		*s2offset = *s3offset;
870fda9279dSmrg		*s3offset = tmp;
871fda9279dSmrg	}
872fda9279dSmrg
873fda9279dSmrg	/* Overlay double buffering... */
874fda9279dSmrg	if (action_flags & USE_OVERLAY)
875fda9279dSmrg                (*newFBSize) <<= 1;
876fda9279dSmrg
877fda9279dSmrg	return 0;
878fda9279dSmrg}
879fda9279dSmrg
880fda9279dSmrg
881fda9279dSmrg/**
882fda9279dSmrg * NV_set_action_flags
883fda9279dSmrg * This function computes the action flags from the input image,
884fda9279dSmrg * that is, it decides what NVPutImage and its helpers must do.
885fda9279dSmrg * This eases readability by avoiding lots of switch-case statements in the
886fda9279dSmrg * core NVPutImage
887fda9279dSmrg */
888fda9279dSmrgstatic void
889fda9279dSmrgNV_set_action_flags(ScrnInfoPtr pScrn, DrawablePtr pDraw, NVPortPrivPtr pPriv,
890fda9279dSmrg		    int id, short drw_x, short drw_y, short drw_w, short drw_h,
891fda9279dSmrg		    int *action_flags)
892fda9279dSmrg{
893fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
894fda9279dSmrg
895fda9279dSmrg#define USING_OVERLAY (*action_flags & USE_OVERLAY)
896fda9279dSmrg#define USING_TEXTURE (*action_flags & USE_TEXTURE)
897fda9279dSmrg#define USING_BLITTER ((!(*action_flags & USE_OVERLAY)) &&                     \
898fda9279dSmrg		       (!(*action_flags & USE_TEXTURE)))
899fda9279dSmrg
900fda9279dSmrg	*action_flags = 0;
901fda9279dSmrg
902fda9279dSmrg	/* Pixel format-related bits */
903fda9279dSmrg	if (id == FOURCC_YUY2 || id == FOURCC_UYVY)
904fda9279dSmrg		*action_flags |= IS_YUY2;
905fda9279dSmrg
906fda9279dSmrg	if (id == FOURCC_YV12 || id == FOURCC_I420)
907fda9279dSmrg		*action_flags |= IS_YV12;
908fda9279dSmrg
909fda9279dSmrg	if (id == FOURCC_RGB) /*How long will we support it?*/
910fda9279dSmrg		*action_flags |= IS_RGB;
911fda9279dSmrg
912fda9279dSmrg	if (id == FOURCC_I420) /* I420 is YV12 with swapped UV */
913fda9279dSmrg		*action_flags |= SWAP_UV;
914fda9279dSmrg
915fda9279dSmrg	/* Desired adapter */
916fda9279dSmrg	if (!pPriv->blitter && !pPriv->texture)
917fda9279dSmrg		*action_flags |= USE_OVERLAY;
918fda9279dSmrg
919fda9279dSmrg	if (!pPriv->blitter && pPriv->texture)
920fda9279dSmrg		*action_flags |= USE_TEXTURE;
921fda9279dSmrg
922fda9279dSmrg	/* Adapter fallbacks (when the desired one can't be used)*/
923fda9279dSmrg#ifdef COMPOSITE
924fda9279dSmrg	{
925fda9279dSmrg		PixmapPtr ppix = NVGetDrawablePixmap(pDraw);
926fda9279dSmrg
927fda9279dSmrg		/* this is whether ppix is in the viewable fb, not related to
928fda9279dSmrg		   the EXA "offscreen" stuff */
929fda9279dSmrg		if (!nouveau_exa_pixmap_is_onscreen(ppix))
930fda9279dSmrg			*action_flags &= ~USE_OVERLAY;
931fda9279dSmrg	}
932fda9279dSmrg#endif
933fda9279dSmrg
934fda9279dSmrg#ifdef NVOVL_SUPPORT
935fda9279dSmrg	if (USING_OVERLAY) {
936fda9279dSmrg		char crtc = nv_window_belongs_to_crtc(pScrn, drw_x, drw_y,
937fda9279dSmrg						      drw_w, drw_h);
938fda9279dSmrg
939fda9279dSmrg		if ((crtc & (1 << 0)) && (crtc & (1 << 1))) {
940fda9279dSmrg			/* The overlay cannot be used on two CRTCs at a time,
941fda9279dSmrg			 * so we need to fallback on the blitter
942fda9279dSmrg			 */
943fda9279dSmrg			*action_flags &= ~USE_OVERLAY;
944fda9279dSmrg		} else
945fda9279dSmrg		if ((crtc & (1 << 0))) {
946fda9279dSmrg			/* We need to put the overlay on CRTC0 - if it's not
947fda9279dSmrg			 * already here
948fda9279dSmrg			 */
949fda9279dSmrg			if (pPriv->overlayCRTC == 1) {
950fda9279dSmrg				NVWriteCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL,
951fda9279dSmrg					    NVReadCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL) |
952fda9279dSmrg					    NV_CRTC_FSEL_OVERLAY);
953fda9279dSmrg				NVWriteCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL,
954fda9279dSmrg					    NVReadCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL) &
955fda9279dSmrg					    ~NV_CRTC_FSEL_OVERLAY);
956fda9279dSmrg				pPriv->overlayCRTC = 0;
957fda9279dSmrg			}
958fda9279dSmrg		} else
959fda9279dSmrg		if ((crtc & (1 << 1))) {
960fda9279dSmrg			if (pPriv->overlayCRTC == 0) {
961fda9279dSmrg				NVWriteCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL,
962fda9279dSmrg					    NVReadCRTC(pNv, 1, NV_PCRTC_ENGINE_CTRL) |
963fda9279dSmrg					    NV_CRTC_FSEL_OVERLAY);
964fda9279dSmrg				NVWriteCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL,
965fda9279dSmrg					    NVReadCRTC(pNv, 0, NV_PCRTC_ENGINE_CTRL) &
966fda9279dSmrg					    ~NV_CRTC_FSEL_OVERLAY);
967fda9279dSmrg				pPriv->overlayCRTC = 1;
968fda9279dSmrg			}
969fda9279dSmrg		}
970fda9279dSmrg
971fda9279dSmrg		if (XF86_CRTC_CONFIG_PTR(pScrn)->crtc[pPriv->overlayCRTC]
972fda9279dSmrg						 ->rotation != RR_Rotate_0)
973fda9279dSmrg			*action_flags &= ~USE_OVERLAY;
974fda9279dSmrg	}
975fda9279dSmrg#endif
976fda9279dSmrg
977fda9279dSmrg	/* At this point the adapter we're going to use is _known_.
978fda9279dSmrg	 * You cannot change it now.
979fda9279dSmrg	 */
980fda9279dSmrg
981fda9279dSmrg	/* Card/adapter format restrictions */
982fda9279dSmrg	if (USING_BLITTER) {
983fda9279dSmrg		/* The blitter does not handle YV12 natively */
984fda9279dSmrg		if (id == FOURCC_YV12 || id == FOURCC_I420)
985fda9279dSmrg			*action_flags |= CONVERT_TO_YUY2;
986fda9279dSmrg	}
987fda9279dSmrg
988fda9279dSmrg	if (USING_OVERLAY && (pNv->Architecture == NV_ARCH_04)) {
989fda9279dSmrg		/* NV04-05 don't support YV12, only YUY2 and ITU-R BT.601 */
990fda9279dSmrg		if (*action_flags & IS_YV12)
991fda9279dSmrg			*action_flags |= CONVERT_TO_YUY2;
992fda9279dSmrg	}
993fda9279dSmrg
994fda9279dSmrg	if (USING_OVERLAY && (pNv->Architecture == NV_ARCH_10 ||
995fda9279dSmrg			      pNv->Architecture == NV_ARCH_20)) {
996fda9279dSmrg		/* No YV12 overlay on NV10, 11, 15, 20, NFORCE */
997fda9279dSmrg		switch (pNv->dev->chipset) {
998fda9279dSmrg		case 0x10:
999fda9279dSmrg		case 0x11:
1000fda9279dSmrg		case 0x15:
1001fda9279dSmrg		case 0x1a: /*XXX: unsure about nforce */
1002fda9279dSmrg		case 0x20:
1003fda9279dSmrg			*action_flags |= CONVERT_TO_YUY2;
1004fda9279dSmrg			break;
1005fda9279dSmrg		default:
1006fda9279dSmrg			break;
1007fda9279dSmrg		}
1008fda9279dSmrg	}
1009fda9279dSmrg}
1010fda9279dSmrg
1011fda9279dSmrg
1012fda9279dSmrg/**
1013fda9279dSmrg * NVPutImage
1014fda9279dSmrg * PutImage is "the" important function of the Xv extension.
1015fda9279dSmrg * a client (e.g. video player) calls this function for every
1016fda9279dSmrg * image (of the video) to be displayed. this function then
1017fda9279dSmrg * scales and displays the image.
1018fda9279dSmrg *
1019fda9279dSmrg * @param pScrn screen which hold the port where the image is put
1020fda9279dSmrg * @param src_x source point in the source image to start displaying from
1021fda9279dSmrg * @param src_y see above
1022fda9279dSmrg * @param src_w width of the source image to display
1023fda9279dSmrg * @param src_h see above
1024fda9279dSmrg * @param drw_x  screen point to display to
1025fda9279dSmrg * @param drw_y
1026fda9279dSmrg * @param drw_w width of the screen drawable
1027fda9279dSmrg * @param drw_h
1028fda9279dSmrg * @param id pixel format of image
1029fda9279dSmrg * @param buf pointer to buffer containing the source image
1030fda9279dSmrg * @param width total width of the source image we are passed
1031fda9279dSmrg * @param height
1032fda9279dSmrg * @param Sync unused
1033fda9279dSmrg * @param clipBoxes ??
1034fda9279dSmrg * @param data pointer to port
1035fda9279dSmrg * @param pDraw drawable pointer
1036fda9279dSmrg */
1037fda9279dSmrgstatic int
1038fda9279dSmrgNVPutImage(ScrnInfoPtr pScrn, short src_x, short src_y, short drw_x,
1039fda9279dSmrg	   short drw_y, short src_w, short src_h, short drw_w, short drw_h,
1040fda9279dSmrg	   int id, unsigned char *buf, short width, short height,
1041fda9279dSmrg	   Bool Sync, RegionPtr clipBoxes, pointer data, DrawablePtr pDraw)
1042fda9279dSmrg{
1043fda9279dSmrg	NVPortPrivPtr pPriv = (NVPortPrivPtr)data;
1044fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1045fda9279dSmrg	PixmapPtr ppix;
1046fda9279dSmrg	/* source box */
1047fda9279dSmrg	INT32 xa = 0, xb = 0, ya = 0, yb = 0;
1048fda9279dSmrg	/* size to allocate in VRAM and in GART respectively */
1049fda9279dSmrg	int newFBSize = 0, newTTSize = 0;
1050fda9279dSmrg	/* card VRAM offsets, source offsets for U and V planes */
1051fda9279dSmrg	int offset = 0, uv_offset = 0, s2offset = 0, s3offset = 0;
1052fda9279dSmrg	/* source pitch, source pitch of U and V planes in case of YV12,
1053fda9279dSmrg	 * VRAM destination pitch
1054fda9279dSmrg	 */
1055fda9279dSmrg	int srcPitch = 0, srcPitch2 = 0, dstPitch = 0;
1056fda9279dSmrg	/* position of the given source data (using src_*), number of pixels
1057fda9279dSmrg	 * and lines we are interested in
1058fda9279dSmrg	 */
1059fda9279dSmrg	int top = 0, left = 0, right = 0, bottom = 0, npixels = 0, nlines = 0;
1060fda9279dSmrg	Bool skip = FALSE;
1061fda9279dSmrg	BoxRec dstBox;
1062fda9279dSmrg	CARD32 tmp = 0;
1063fda9279dSmrg	int line_len = 0; /* length of a line, like npixels, but in bytes */
1064fda9279dSmrg	struct nouveau_bo *destination_buffer = NULL;
1065fda9279dSmrg	int action_flags; /* what shall we do? */
1066fda9279dSmrg	unsigned char *map;
1067fda9279dSmrg	int ret, i;
1068fda9279dSmrg
1069fda9279dSmrg	if (pPriv->grabbedByV4L)
1070fda9279dSmrg		return Success;
1071fda9279dSmrg
1072fda9279dSmrg
1073fda9279dSmrg	NV_set_action_flags(pScrn, pDraw, pPriv, id, drw_x, drw_y, drw_w,
1074fda9279dSmrg			    drw_h, &action_flags);
1075fda9279dSmrg
1076fda9279dSmrg	if (NV_set_dimensions(pScrn, action_flags, &xa, &xb, &ya, &yb,
1077fda9279dSmrg			      &src_x,  &src_y, &src_w, &src_h,
1078fda9279dSmrg			      &drw_x, &drw_y, &drw_w, &drw_h,
1079fda9279dSmrg			      &left, &top, &right, &bottom, &dstBox,
1080fda9279dSmrg			      &npixels, &nlines, clipBoxes, width, height))
1081fda9279dSmrg		return Success;
1082fda9279dSmrg
1083fda9279dSmrg	if (NV_calculate_pitches_and_mem_size(pNv, action_flags, &srcPitch,
1084fda9279dSmrg					      &srcPitch2, &dstPitch, &s2offset,
1085fda9279dSmrg					      &s3offset, &uv_offset,
1086fda9279dSmrg					      &newFBSize, &newTTSize,
1087fda9279dSmrg					      &line_len, npixels, nlines,
1088fda9279dSmrg					      width, height))
1089fda9279dSmrg		return BadImplementation;
1090fda9279dSmrg
1091fda9279dSmrg	/* There are some cases (tvtime with overscan for example) where the
1092fda9279dSmrg	 * input image is larger (width/height) than the source rectangle for
1093fda9279dSmrg	 * the overlay (src_w, src_h). In those cases, we try to do something
1094fda9279dSmrg	 * optimal by uploading only the necessary data.
1095fda9279dSmrg	 */
1096fda9279dSmrg	if (action_flags & IS_YUY2 || action_flags & IS_RGB)
1097fda9279dSmrg		buf += (top * srcPitch) + left;
1098fda9279dSmrg
1099fda9279dSmrg	if (action_flags & IS_YV12) {
1100fda9279dSmrg		tmp = ((top >> 1) * srcPitch2) + (left >> 1);
1101fda9279dSmrg		s2offset += tmp;
1102fda9279dSmrg		s3offset += tmp;
1103fda9279dSmrg	}
1104fda9279dSmrg
1105fda9279dSmrg	ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, newFBSize,
1106fda9279dSmrg				    &pPriv->video_mem);
1107fda9279dSmrg	if (ret)
1108fda9279dSmrg		return BadAlloc;
1109fda9279dSmrg
1110fda9279dSmrg#ifdef NVOVL_SUPPORT
1111fda9279dSmrg	if (action_flags & USE_OVERLAY) {
1112fda9279dSmrg		ret = nouveau_bo_pin(pPriv->video_mem, NOUVEAU_BO_VRAM);
1113fda9279dSmrg		if (ret) {
1114fda9279dSmrg			nouveau_bo_ref(NULL, &pPriv->video_mem);
1115fda9279dSmrg			return BadAlloc;
1116fda9279dSmrg		}
1117fda9279dSmrg	}
1118fda9279dSmrg#endif
1119fda9279dSmrg
1120fda9279dSmrg	/* The overlay supports hardware double buffering. We handle this here*/
1121fda9279dSmrg	offset = 0;
1122fda9279dSmrg#ifdef NVOVL_SUPPORT
1123fda9279dSmrg	if (pPriv->doubleBuffer) {
1124fda9279dSmrg		int mask = 1 << (pPriv->currentBuffer << 2);
1125fda9279dSmrg
1126fda9279dSmrg		/* overwrite the newest buffer if there's not one free */
1127fda9279dSmrg		if (nvReadVIDEO(pNv, NV_PVIDEO_BUFFER) & mask) {
1128fda9279dSmrg			if (!pPriv->currentBuffer)
1129fda9279dSmrg				offset += newFBSize >> 1;
1130fda9279dSmrg			skip = TRUE;
1131fda9279dSmrg		} else {
1132fda9279dSmrg			if (pPriv->currentBuffer)
1133fda9279dSmrg				offset += newFBSize >> 1;
1134fda9279dSmrg		}
1135fda9279dSmrg	}
1136fda9279dSmrg#endif
1137fda9279dSmrg
1138fda9279dSmrg	/* Now we take a decision regarding the way we send the data to the
1139fda9279dSmrg	 * card.
1140fda9279dSmrg	 *
1141fda9279dSmrg	 * Either we use double buffering of "private" TT memory
1142fda9279dSmrg	 * Either we rely on X's GARTScratch
1143fda9279dSmrg	 * Either we fallback on CPU copy
1144fda9279dSmrg	 */
1145fda9279dSmrg
1146fda9279dSmrg	/* Try to allocate host-side double buffers, unless we have already
1147fda9279dSmrg	 * failed
1148fda9279dSmrg	 */
1149fda9279dSmrg
1150fda9279dSmrg	/* We take only nlines * line_len bytes - that is, only the pixel
1151fda9279dSmrg	 * data we are interested in - because the stuff in the GART is
1152fda9279dSmrg	 * written contiguously
1153fda9279dSmrg	 */
1154fda9279dSmrg	if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE) {
1155fda9279dSmrg		ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_GART, newTTSize,
1156fda9279dSmrg					    &pPriv->TT_mem_chunk[0]);
1157fda9279dSmrg		if (ret == 0) {
1158fda9279dSmrg			ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_GART,
1159fda9279dSmrg						    newTTSize,
1160fda9279dSmrg						    &pPriv->TT_mem_chunk[1]);
1161fda9279dSmrg			if (ret) {
1162fda9279dSmrg				nouveau_bo_ref(NULL, &pPriv->TT_mem_chunk[0]);
1163fda9279dSmrg				pPriv->currentHostBuffer =
1164fda9279dSmrg					NO_PRIV_HOST_BUFFER_AVAILABLE;
1165fda9279dSmrg			}
1166fda9279dSmrg		} else {
1167fda9279dSmrg			pPriv->currentHostBuffer =
1168fda9279dSmrg				NO_PRIV_HOST_BUFFER_AVAILABLE;
1169fda9279dSmrg		}
1170fda9279dSmrg	}
1171fda9279dSmrg
1172fda9279dSmrg	if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE) {
1173fda9279dSmrg		destination_buffer =
1174fda9279dSmrg			pPriv->TT_mem_chunk[pPriv->currentHostBuffer];
1175fda9279dSmrg	}
1176fda9279dSmrg	if (!destination_buffer) {
1177fda9279dSmrg		if (pNv->Architecture >= NV_TESLA) {
1178fda9279dSmrg			NOUVEAU_ERR("No scratch buffer for tiled upload\n");
1179fda9279dSmrg			return BadAlloc;
1180fda9279dSmrg		}
1181fda9279dSmrg
1182fda9279dSmrg		goto CPU_copy;
1183fda9279dSmrg	}
1184fda9279dSmrg
1185fda9279dSmrg	if (newTTSize <= destination_buffer->size) {
1186fda9279dSmrg		unsigned char *dst;
1187fda9279dSmrg		int i = 0;
1188fda9279dSmrg
1189fda9279dSmrg		/* Upload to GART */
1190fda9279dSmrg		nouveau_bo_map(destination_buffer, NOUVEAU_BO_WR, pNv->client);
1191fda9279dSmrg		dst = destination_buffer->map;
1192fda9279dSmrg
1193fda9279dSmrg		if (action_flags & IS_YV12) {
1194fda9279dSmrg			if (action_flags & CONVERT_TO_YUY2) {
1195fda9279dSmrg				NVCopyData420(buf + (top * srcPitch) + left,
1196fda9279dSmrg					      buf + s2offset, buf + s3offset,
1197fda9279dSmrg					      dst, srcPitch, srcPitch2,
1198fda9279dSmrg					      line_len, nlines, npixels);
1199fda9279dSmrg			} else {
1200fda9279dSmrg				/* Native YV12 */
1201fda9279dSmrg				unsigned char *tbuf = buf + top *
1202fda9279dSmrg						      srcPitch + left;
1203fda9279dSmrg				unsigned char *tdst = dst;
1204fda9279dSmrg
1205fda9279dSmrg				/* luma upload */
1206fda9279dSmrg				for (i = 0; i < nlines; i++) {
1207fda9279dSmrg					memcpy(tdst, tbuf, line_len);
1208fda9279dSmrg					tdst += line_len;
1209fda9279dSmrg					tbuf += srcPitch;
1210fda9279dSmrg				}
1211fda9279dSmrg				dst += line_len * nlines;
1212fda9279dSmrg
1213fda9279dSmrg				NVCopyNV12ColorPlanes(buf + s2offset,
1214fda9279dSmrg						      buf + s3offset, dst,
1215fda9279dSmrg						      line_len, srcPitch2,
1216fda9279dSmrg						      nlines, npixels);
1217fda9279dSmrg			}
1218fda9279dSmrg		} else {
1219fda9279dSmrg			for (i = 0; i < nlines; i++) {
1220fda9279dSmrg				memcpy(dst, buf, line_len);
1221fda9279dSmrg				dst += line_len;
1222fda9279dSmrg				buf += srcPitch;
1223fda9279dSmrg			}
1224fda9279dSmrg		}
1225fda9279dSmrg
1226fda9279dSmrg		if (uv_offset) {
1227fda9279dSmrg			NVAccelM2MF(pNv, line_len, nlines / 2, 1,
1228fda9279dSmrg				    line_len * nlines, uv_offset,
1229fda9279dSmrg				    destination_buffer, NOUVEAU_BO_GART,
1230fda9279dSmrg				    line_len, nlines >> 1, 0, 0,
1231fda9279dSmrg				    pPriv->video_mem, NOUVEAU_BO_VRAM,
1232fda9279dSmrg				    dstPitch, nlines >> 1, 0, 0);
1233fda9279dSmrg		}
1234fda9279dSmrg
1235fda9279dSmrg		NVAccelM2MF(pNv, line_len, nlines, 1, 0, 0,
1236fda9279dSmrg			    destination_buffer, NOUVEAU_BO_GART,
1237fda9279dSmrg			    line_len, nlines, 0, 0,
1238fda9279dSmrg			    pPriv->video_mem, NOUVEAU_BO_VRAM,
1239fda9279dSmrg			    dstPitch, nlines, 0, 0);
1240fda9279dSmrg
1241fda9279dSmrg	} else {
1242fda9279dSmrgCPU_copy:
1243fda9279dSmrg		nouveau_bo_map(pPriv->video_mem, NOUVEAU_BO_WR, pNv->client);
1244fda9279dSmrg		map = pPriv->video_mem->map + offset;
1245fda9279dSmrg
1246fda9279dSmrg		if (action_flags & IS_YV12) {
1247fda9279dSmrg			if (action_flags & CONVERT_TO_YUY2) {
1248fda9279dSmrg				NVCopyData420(buf + (top * srcPitch) + left,
1249fda9279dSmrg					      buf + s2offset, buf + s3offset,
1250fda9279dSmrg					      map, srcPitch, srcPitch2,
1251fda9279dSmrg					      dstPitch, nlines, npixels);
1252fda9279dSmrg			} else {
1253fda9279dSmrg				unsigned char *tbuf =
1254fda9279dSmrg					buf + left + top * srcPitch;
1255fda9279dSmrg
1256fda9279dSmrg				for (i = 0; i < nlines; i++) {
1257fda9279dSmrg					int dwords = npixels << 1;
1258fda9279dSmrg
1259fda9279dSmrg					while (dwords & ~0x03) {
1260fda9279dSmrg						*map = *tbuf;
1261fda9279dSmrg						*(map + 1) = *(tbuf + 1);
1262fda9279dSmrg						*(map + 2) = *(tbuf + 2);
1263fda9279dSmrg						*(map + 3) = *(tbuf + 3);
1264fda9279dSmrg						map += 4;
1265fda9279dSmrg						tbuf += 4;
1266fda9279dSmrg						dwords -= 4;
1267fda9279dSmrg					}
1268fda9279dSmrg
1269fda9279dSmrg					switch (dwords) {
1270fda9279dSmrg					case 3: *(map + 2) = *(tbuf + 2);
1271fda9279dSmrg					case 2: *(map + 1) = *(tbuf + 1);
1272fda9279dSmrg					case 1: *map = *tbuf;
1273fda9279dSmrg					}
1274fda9279dSmrg
1275fda9279dSmrg					map += dstPitch - (npixels << 1);
1276fda9279dSmrg					tbuf += srcPitch - (npixels << 1);
1277fda9279dSmrg				}
1278fda9279dSmrg
1279fda9279dSmrg				NVCopyNV12ColorPlanes(buf + s2offset,
1280fda9279dSmrg						      buf + s3offset,
1281fda9279dSmrg						      map, dstPitch, srcPitch2,
1282fda9279dSmrg						      nlines, npixels);
1283fda9279dSmrg			}
1284fda9279dSmrg		} else {
1285fda9279dSmrg			/* YUY2 and RGB */
1286fda9279dSmrg			for (i = 0; i < nlines; i++) {
1287fda9279dSmrg				int dwords = npixels << 1;
1288fda9279dSmrg
1289fda9279dSmrg				while (dwords & ~0x03) {
1290fda9279dSmrg					*map = *buf;
1291fda9279dSmrg					*(map + 1) = *(buf + 1);
1292fda9279dSmrg					*(map + 2) = *(buf + 2);
1293fda9279dSmrg					*(map + 3) = *(buf + 3);
1294fda9279dSmrg					map += 4;
1295fda9279dSmrg					buf += 4;
1296fda9279dSmrg					dwords -= 4;
1297fda9279dSmrg				}
1298fda9279dSmrg
1299fda9279dSmrg				switch (dwords) {
1300fda9279dSmrg				case 3: *(map + 2) = *(buf + 2);
1301fda9279dSmrg				case 2: *(map + 1) = *(buf + 1);
1302fda9279dSmrg				case 1: *map = *buf;
1303fda9279dSmrg				}
1304fda9279dSmrg
1305fda9279dSmrg				map += dstPitch - (npixels << 1);
1306fda9279dSmrg				buf += srcPitch - (npixels << 1);
1307fda9279dSmrg			}
1308fda9279dSmrg		}
1309fda9279dSmrg	}
1310fda9279dSmrg
1311fda9279dSmrg	if (skip)
1312fda9279dSmrg		return Success;
1313fda9279dSmrg
1314fda9279dSmrg	if (pPriv->currentHostBuffer != NO_PRIV_HOST_BUFFER_AVAILABLE)
1315fda9279dSmrg		pPriv->currentHostBuffer ^= 1;
1316fda9279dSmrg
1317fda9279dSmrg	/* If we're not using the hw overlay, we're rendering into a pixmap
1318fda9279dSmrg	 * and need to take a couple of additional steps...
1319fda9279dSmrg	 */
1320fda9279dSmrg	if (!(action_flags & USE_OVERLAY)) {
1321fda9279dSmrg		ppix = NVGetDrawablePixmap(pDraw);
1322fda9279dSmrg
1323fda9279dSmrg		/* Ensure pixmap is in offscreen memory */
1324fda9279dSmrg		pNv->exa_force_cp = TRUE;
1325fda9279dSmrg		exaMoveInPixmap(ppix);
1326fda9279dSmrg		pNv->exa_force_cp = FALSE;
1327fda9279dSmrg
1328fda9279dSmrg		if (!exaGetPixmapDriverPrivate(ppix))
1329fda9279dSmrg			return BadAlloc;
1330fda9279dSmrg
1331fda9279dSmrg#ifdef COMPOSITE
1332fda9279dSmrg		/* Convert screen coords to pixmap coords */
1333fda9279dSmrg		if (ppix->screen_x || ppix->screen_y) {
1334fda9279dSmrg			REGION_TRANSLATE(pScrn->pScreen, clipBoxes,
1335fda9279dSmrg					 -ppix->screen_x, -ppix->screen_y);
1336fda9279dSmrg			dstBox.x1 -= ppix->screen_x;
1337fda9279dSmrg			dstBox.x2 -= ppix->screen_x;
1338fda9279dSmrg			dstBox.y1 -= ppix->screen_y;
1339fda9279dSmrg			dstBox.y2 -= ppix->screen_y;
1340fda9279dSmrg		}
1341fda9279dSmrg#endif
1342fda9279dSmrg	}
1343fda9279dSmrg
1344fda9279dSmrg	if (action_flags & USE_OVERLAY) {
1345fda9279dSmrg		if (pNv->Architecture == NV_ARCH_04) {
1346fda9279dSmrg			NV04PutOverlayImage(pScrn, pPriv->video_mem, offset,
1347fda9279dSmrg					    id, dstPitch, &dstBox, 0, 0,
1348fda9279dSmrg					    xb, yb, npixels, nlines,
1349fda9279dSmrg					    src_w, src_h, drw_w, drw_h,
1350fda9279dSmrg					    clipBoxes);
1351fda9279dSmrg		} else {
1352fda9279dSmrg			NV10PutOverlayImage(pScrn, pPriv->video_mem, offset,
1353fda9279dSmrg					    uv_offset, id, dstPitch, &dstBox,
1354fda9279dSmrg					    0, 0, xb, yb,
1355fda9279dSmrg					    npixels, nlines, src_w, src_h,
1356fda9279dSmrg					    drw_w, drw_h, clipBoxes);
1357fda9279dSmrg		}
1358fda9279dSmrg
1359fda9279dSmrg		pPriv->currentBuffer ^= 1;
1360fda9279dSmrg	} else
1361fda9279dSmrg	if (action_flags & USE_TEXTURE) {
1362fda9279dSmrg		int ret = BadImplementation;
1363fda9279dSmrg
1364fda9279dSmrg		if (pNv->Architecture == NV_ARCH_30) {
1365fda9279dSmrg			ret = NV30PutTextureImage(pScrn, pPriv->video_mem,
1366fda9279dSmrg						  offset, uv_offset,
1367fda9279dSmrg						  id, dstPitch, &dstBox, 0, 0,
1368fda9279dSmrg						  xb, yb, npixels, nlines,
1369fda9279dSmrg						  src_w, src_h, drw_w, drw_h,
1370fda9279dSmrg						  clipBoxes, ppix, pPriv);
1371fda9279dSmrg		} else
1372fda9279dSmrg		if (pNv->Architecture == NV_ARCH_40) {
1373fda9279dSmrg			ret = NV40PutTextureImage(pScrn, pPriv->video_mem,
1374fda9279dSmrg						  offset, uv_offset,
1375fda9279dSmrg						  id, dstPitch, &dstBox, 0, 0,
1376fda9279dSmrg						  xb, yb, npixels, nlines,
1377fda9279dSmrg						  src_w, src_h, drw_w, drw_h,
1378fda9279dSmrg						  clipBoxes, ppix, pPriv);
1379fda9279dSmrg		} else
1380fda9279dSmrg		if (pNv->Architecture == NV_TESLA) {
1381fda9279dSmrg			ret = nv50_xv_image_put(pScrn, pPriv->video_mem,
1382fda9279dSmrg						offset, uv_offset,
1383fda9279dSmrg						id, dstPitch, &dstBox, 0, 0,
1384fda9279dSmrg						xb, yb, npixels, nlines,
1385fda9279dSmrg						src_w, src_h, drw_w, drw_h,
1386fda9279dSmrg						clipBoxes, ppix, pPriv);
1387fda9279dSmrg		} else {
1388fda9279dSmrg			ret = nvc0_xv_image_put(pScrn, pPriv->video_mem,
1389fda9279dSmrg						offset, uv_offset,
1390fda9279dSmrg						id, dstPitch, &dstBox, 0, 0,
1391fda9279dSmrg						xb, yb, npixels, nlines,
1392fda9279dSmrg						src_w, src_h, drw_w, drw_h,
1393fda9279dSmrg						clipBoxes, ppix, pPriv);
1394fda9279dSmrg		}
1395fda9279dSmrg
1396fda9279dSmrg		if (ret != Success)
1397fda9279dSmrg			return ret;
1398fda9279dSmrg	} else {
1399fda9279dSmrg		ret = NVPutBlitImage(pScrn, pPriv->video_mem, offset, id,
1400fda9279dSmrg				     dstPitch, &dstBox, 0, 0, xb, yb, npixels,
1401fda9279dSmrg				     nlines, src_w, src_h, drw_w, drw_h,
1402fda9279dSmrg				     clipBoxes, ppix);
1403fda9279dSmrg		if (ret != Success)
1404fda9279dSmrg			return ret;
1405fda9279dSmrg	}
1406fda9279dSmrg
1407fda9279dSmrg#ifdef COMPOSITE
1408fda9279dSmrg	/* Damage tracking */
1409fda9279dSmrg	if (!(action_flags & USE_OVERLAY))
1410fda9279dSmrg		DamageDamageRegion(&ppix->drawable, clipBoxes);
1411fda9279dSmrg#endif
1412fda9279dSmrg
1413fda9279dSmrg	return Success;
1414fda9279dSmrg}
1415fda9279dSmrg
1416fda9279dSmrg/**
1417fda9279dSmrg * QueryImageAttributes
1418fda9279dSmrg *
1419fda9279dSmrg * calculates
1420fda9279dSmrg * - size (memory required to store image),
1421fda9279dSmrg * - pitches,
1422fda9279dSmrg * - offsets
1423fda9279dSmrg * of image
1424fda9279dSmrg * depending on colorspace (id) and dimensions (w,h) of image
1425fda9279dSmrg * values of
1426fda9279dSmrg * - w,
1427fda9279dSmrg * - h
1428fda9279dSmrg * may be adjusted as needed
1429fda9279dSmrg *
1430fda9279dSmrg * @param pScrn unused
1431fda9279dSmrg * @param id colorspace of image
1432fda9279dSmrg * @param w pointer to width of image
1433fda9279dSmrg * @param h pointer to height of image
1434fda9279dSmrg * @param pitches pitches[i] = length of a scanline in plane[i]
1435fda9279dSmrg * @param offsets offsets[i] = offset of plane i from the beginning of the image
1436fda9279dSmrg * @return size of the memory required for the XvImage queried
1437fda9279dSmrg */
1438fda9279dSmrgstatic int
1439fda9279dSmrgNVQueryImageAttributes(ScrnInfoPtr pScrn, int id,
1440fda9279dSmrg		       unsigned short *w, unsigned short *h,
1441fda9279dSmrg		       int *pitches, int *offsets)
1442fda9279dSmrg{
1443fda9279dSmrg	int size, tmp;
1444fda9279dSmrg
1445fda9279dSmrg	if (*w > IMAGE_MAX_W)
1446fda9279dSmrg		*w = IMAGE_MAX_W;
1447fda9279dSmrg	if (*h > IMAGE_MAX_H)
1448fda9279dSmrg		*h = IMAGE_MAX_H;
1449fda9279dSmrg
1450fda9279dSmrg	*w = (*w + 1) & ~1; // width rounded up to an even number
1451fda9279dSmrg	if (offsets)
1452fda9279dSmrg		offsets[0] = 0;
1453fda9279dSmrg
1454fda9279dSmrg	switch (id) {
1455fda9279dSmrg	case FOURCC_YV12:
1456fda9279dSmrg	case FOURCC_I420:
1457fda9279dSmrg		*h = (*h + 1) & ~1; // height rounded up to an even number
1458fda9279dSmrg		size = (*w + 3) & ~3; // width rounded up to a multiple of 4
1459fda9279dSmrg		if (pitches)
1460fda9279dSmrg			pitches[0] = size; // width rounded up to a multiple of 4
1461fda9279dSmrg		size *= *h;
1462fda9279dSmrg		if (offsets)
1463fda9279dSmrg			offsets[1] = size; // number of pixels in "rounded up" image
1464fda9279dSmrg		tmp = ((*w >> 1) + 3) & ~3; // width/2 rounded up to a multiple of 4
1465fda9279dSmrg		if (pitches)
1466fda9279dSmrg			pitches[1] = pitches[2] = tmp; // width/2 rounded up to a multiple of 4
1467fda9279dSmrg		tmp *= (*h >> 1); // 1/4*number of pixels in "rounded up" image
1468fda9279dSmrg		size += tmp; // 5/4*number of pixels in "rounded up" image
1469fda9279dSmrg		if (offsets)
1470fda9279dSmrg			offsets[2] = size; // 5/4*number of pixels in "rounded up" image
1471fda9279dSmrg		size += tmp; // = 3/2*number of pixels in "rounded up" image
1472fda9279dSmrg		break;
1473fda9279dSmrg	case FOURCC_UYVY:
1474fda9279dSmrg	case FOURCC_YUY2:
1475fda9279dSmrg		size = *w << 1; // 2*width
1476fda9279dSmrg		if (pitches)
1477fda9279dSmrg			pitches[0] = size; // 2*width
1478fda9279dSmrg		size *= *h; // 2*width*height
1479fda9279dSmrg		break;
1480fda9279dSmrg	case FOURCC_RGB:
1481fda9279dSmrg		size = *w << 2; // 4*width (32 bit per pixel)
1482fda9279dSmrg		if (pitches)
1483fda9279dSmrg			pitches[0] = size; // 4*width
1484fda9279dSmrg		size *= *h; // 4*width*height
1485fda9279dSmrg		break;
1486fda9279dSmrg	case FOURCC_AI44:
1487fda9279dSmrg	case FOURCC_IA44:
1488fda9279dSmrg		size = *w; // width
1489fda9279dSmrg		if (pitches)
1490fda9279dSmrg			pitches[0] = size; // width
1491fda9279dSmrg		size *= *h; // width*height
1492fda9279dSmrg		break;
1493fda9279dSmrg	default:
1494fda9279dSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown colorspace: %x\n", id);
1495fda9279dSmrg		*w = *h = size = 0;
1496fda9279dSmrg		break;
1497fda9279dSmrg	}
1498fda9279dSmrg
1499fda9279dSmrg	return size;
1500fda9279dSmrg}
1501fda9279dSmrg
1502fda9279dSmrg/***** Exported offscreen surface stuff ****/
1503fda9279dSmrg
1504fda9279dSmrg
1505fda9279dSmrgstatic int
1506fda9279dSmrgNVAllocSurface(ScrnInfoPtr pScrn, int id,
1507fda9279dSmrg	       unsigned short w, unsigned short h,
1508fda9279dSmrg	       XF86SurfacePtr surface)
1509fda9279dSmrg{
1510fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1511fda9279dSmrg	NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1512fda9279dSmrg	int size, bpp, ret;
1513fda9279dSmrg
1514fda9279dSmrg	bpp = pScrn->bitsPerPixel >> 3;
1515fda9279dSmrg
1516fda9279dSmrg	if (pPriv->grabbedByV4L)
1517fda9279dSmrg		return BadAlloc;
1518fda9279dSmrg
1519fda9279dSmrg	if ((w > IMAGE_MAX_W) || (h > IMAGE_MAX_H))
1520fda9279dSmrg		return BadValue;
1521fda9279dSmrg
1522fda9279dSmrg	w = (w + 1) & ~1;
1523fda9279dSmrg	pPriv->pitch = ((w << 1) + 63) & ~63;
1524fda9279dSmrg	size = h * pPriv->pitch / bpp;
1525fda9279dSmrg
1526fda9279dSmrg	ret = nouveau_xv_bo_realloc(pScrn, NOUVEAU_BO_VRAM, size,
1527fda9279dSmrg				    &pPriv->video_mem);
1528fda9279dSmrg	if (ret)
1529fda9279dSmrg		return BadAlloc;
1530fda9279dSmrg	pPriv->offset = 0;
1531fda9279dSmrg
1532fda9279dSmrg	surface->width = w;
1533fda9279dSmrg	surface->height = h;
1534fda9279dSmrg	surface->pScrn = pScrn;
1535fda9279dSmrg	surface->pitches = &pPriv->pitch;
1536fda9279dSmrg	surface->offsets = &pPriv->offset;
1537fda9279dSmrg	surface->devPrivate.ptr = (pointer)pPriv;
1538fda9279dSmrg	surface->id = id;
1539fda9279dSmrg
1540fda9279dSmrg	/* grab the video */
1541fda9279dSmrg	NVStopOverlay(pScrn);
1542fda9279dSmrg	pPriv->videoStatus = 0;
1543fda9279dSmrg	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1544fda9279dSmrg	pPriv->grabbedByV4L = TRUE;
1545fda9279dSmrg
1546fda9279dSmrg	return Success;
1547fda9279dSmrg}
1548fda9279dSmrg
1549fda9279dSmrgstatic int
1550fda9279dSmrgNVStopSurface(XF86SurfacePtr surface)
1551fda9279dSmrg{
1552fda9279dSmrg	NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1553fda9279dSmrg
1554fda9279dSmrg	if (pPriv->grabbedByV4L && pPriv->videoStatus) {
1555fda9279dSmrg		NV10StopOverlay(surface->pScrn);
1556fda9279dSmrg		pPriv->videoStatus = 0;
1557fda9279dSmrg	}
1558fda9279dSmrg
1559fda9279dSmrg	return Success;
1560fda9279dSmrg}
1561fda9279dSmrg
1562fda9279dSmrgstatic int
1563fda9279dSmrgNVFreeSurface(XF86SurfacePtr surface)
1564fda9279dSmrg{
1565fda9279dSmrg	NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1566fda9279dSmrg
1567fda9279dSmrg	if (pPriv->grabbedByV4L) {
1568fda9279dSmrg		NVStopSurface(surface);
1569fda9279dSmrg		NVFreeOverlayMemory(surface->pScrn);
1570fda9279dSmrg		pPriv->grabbedByV4L = FALSE;
1571fda9279dSmrg	}
1572fda9279dSmrg
1573fda9279dSmrg	return Success;
1574fda9279dSmrg}
1575fda9279dSmrg
1576fda9279dSmrgstatic int
1577fda9279dSmrgNVGetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 *value)
1578fda9279dSmrg{
1579fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1580fda9279dSmrg	NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1581fda9279dSmrg
1582fda9279dSmrg	return NV10GetOverlayPortAttribute(pScrn, attribute,
1583fda9279dSmrg					 value, (pointer)pPriv);
1584fda9279dSmrg}
1585fda9279dSmrg
1586fda9279dSmrgstatic int
1587fda9279dSmrgNVSetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
1588fda9279dSmrg{
1589fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1590fda9279dSmrg	NVPortPrivPtr pPriv = GET_OVERLAY_PRIVATE(pNv);
1591fda9279dSmrg
1592fda9279dSmrg	return NV10SetOverlayPortAttribute(pScrn, attribute,
1593fda9279dSmrg					 value, (pointer)pPriv);
1594fda9279dSmrg}
1595fda9279dSmrg
1596fda9279dSmrgstatic int
1597fda9279dSmrgNVDisplaySurface(XF86SurfacePtr surface,
1598fda9279dSmrg		 short src_x, short src_y,
1599fda9279dSmrg		 short drw_x, short drw_y,
1600fda9279dSmrg		 short src_w, short src_h,
1601fda9279dSmrg		 short drw_w, short drw_h,
1602fda9279dSmrg		 RegionPtr clipBoxes)
1603fda9279dSmrg{
1604fda9279dSmrg	ScrnInfoPtr pScrn = surface->pScrn;
1605fda9279dSmrg	NVPortPrivPtr pPriv = (NVPortPrivPtr)(surface->devPrivate.ptr);
1606fda9279dSmrg	INT32 xa, xb, ya, yb;
1607fda9279dSmrg	BoxRec dstBox;
1608fda9279dSmrg
1609fda9279dSmrg	if (!pPriv->grabbedByV4L)
1610fda9279dSmrg		return Success;
1611fda9279dSmrg
1612fda9279dSmrg	if (src_w > (drw_w << 3))
1613fda9279dSmrg		drw_w = src_w >> 3;
1614fda9279dSmrg	if (src_h > (drw_h << 3))
1615fda9279dSmrg		drw_h = src_h >> 3;
1616fda9279dSmrg
1617fda9279dSmrg	/* Clip */
1618fda9279dSmrg	xa = src_x;
1619fda9279dSmrg	xb = src_x + src_w;
1620fda9279dSmrg	ya = src_y;
1621fda9279dSmrg	yb = src_y + src_h;
1622fda9279dSmrg
1623fda9279dSmrg	dstBox.x1 = drw_x;
1624fda9279dSmrg	dstBox.x2 = drw_x + drw_w;
1625fda9279dSmrg	dstBox.y1 = drw_y;
1626fda9279dSmrg	dstBox.y2 = drw_y + drw_h;
1627fda9279dSmrg
1628fda9279dSmrg	if(!xf86XVClipVideoHelper(&dstBox, &xa, &xb, &ya, &yb, clipBoxes,
1629fda9279dSmrg				  surface->width, surface->height))
1630fda9279dSmrg		return Success;
1631fda9279dSmrg
1632fda9279dSmrg	dstBox.x1 -= pScrn->frameX0;
1633fda9279dSmrg	dstBox.x2 -= pScrn->frameX0;
1634fda9279dSmrg	dstBox.y1 -= pScrn->frameY0;
1635fda9279dSmrg	dstBox.y2 -= pScrn->frameY0;
1636fda9279dSmrg
1637fda9279dSmrg	pPriv->currentBuffer = 0;
1638fda9279dSmrg
1639fda9279dSmrg	NV10PutOverlayImage(pScrn, pPriv->video_mem, surface->offsets[0],
1640fda9279dSmrg			    0, surface->id, surface->pitches[0], &dstBox,
1641fda9279dSmrg			    xa, ya, xb, yb, surface->width, surface->height,
1642fda9279dSmrg			    src_w, src_h, drw_w, drw_h, clipBoxes);
1643fda9279dSmrg
1644fda9279dSmrg	return Success;
1645fda9279dSmrg}
1646fda9279dSmrg
1647fda9279dSmrg/**
1648fda9279dSmrg * NVSetupBlitVideo
1649fda9279dSmrg * this function does all the work setting up a blit port
1650fda9279dSmrg *
1651fda9279dSmrg * @return blit port
1652fda9279dSmrg */
1653fda9279dSmrgstatic XF86VideoAdaptorPtr
1654fda9279dSmrgNVSetupBlitVideo (ScreenPtr pScreen)
1655fda9279dSmrg{
1656fda9279dSmrg	ScrnInfoPtr         pScrn = xf86ScreenToScrn(pScreen);
1657fda9279dSmrg	NVPtr               pNv       = NVPTR(pScrn);
1658fda9279dSmrg	XF86VideoAdaptorPtr adapt;
1659fda9279dSmrg	NVPortPrivPtr       pPriv;
1660fda9279dSmrg	int i;
1661fda9279dSmrg
1662fda9279dSmrg	if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
1663fda9279dSmrg					sizeof(NVPortPrivRec) +
1664fda9279dSmrg					(sizeof(DevUnion) * NUM_BLIT_PORTS)))) {
1665fda9279dSmrg		return NULL;
1666fda9279dSmrg	}
1667fda9279dSmrg
1668fda9279dSmrg	adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
1669fda9279dSmrg	adapt->flags		= 0;
1670fda9279dSmrg	adapt->name		= "NV Video Blitter";
1671fda9279dSmrg	adapt->nEncodings	= 1;
1672fda9279dSmrg	adapt->pEncodings	= &DummyEncoding;
1673fda9279dSmrg	adapt->nFormats		= NUM_FORMATS_ALL;
1674fda9279dSmrg	adapt->pFormats		= NVFormats;
1675fda9279dSmrg	adapt->nPorts		= NUM_BLIT_PORTS;
1676fda9279dSmrg	adapt->pPortPrivates	= (DevUnion*)(&adapt[1]);
1677fda9279dSmrg
1678fda9279dSmrg	pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_BLIT_PORTS]);
1679fda9279dSmrg	for(i = 0; i < NUM_BLIT_PORTS; i++)
1680fda9279dSmrg		adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1681fda9279dSmrg
1682fda9279dSmrg	if (pNv->dev->chipset >= 0x11) {
1683fda9279dSmrg		adapt->pAttributes = NVBlitAttributes;
1684fda9279dSmrg		adapt->nAttributes = NUM_BLIT_ATTRIBUTES;
1685fda9279dSmrg	} else {
1686fda9279dSmrg		adapt->pAttributes = NULL;
1687fda9279dSmrg		adapt->nAttributes = 0;
1688fda9279dSmrg	}
1689fda9279dSmrg
1690fda9279dSmrg	adapt->pImages			= NVImages;
1691fda9279dSmrg	adapt->nImages			= NUM_IMAGES_ALL;
1692fda9279dSmrg	adapt->PutVideo			= NULL;
1693fda9279dSmrg	adapt->PutStill			= NULL;
1694fda9279dSmrg	adapt->GetVideo			= NULL;
1695fda9279dSmrg	adapt->GetStill			= NULL;
1696fda9279dSmrg	adapt->StopVideo		= NVStopBlitVideo;
1697fda9279dSmrg	adapt->SetPortAttribute		= NVSetBlitPortAttribute;
1698fda9279dSmrg	adapt->GetPortAttribute		= NVGetBlitPortAttribute;
1699fda9279dSmrg	adapt->QueryBestSize		= NVQueryBestSize;
1700fda9279dSmrg	adapt->PutImage			= NVPutImage;
1701fda9279dSmrg	adapt->QueryImageAttributes	= NVQueryImageAttributes;
1702fda9279dSmrg
1703fda9279dSmrg	pPriv->videoStatus		= 0;
1704fda9279dSmrg	pPriv->grabbedByV4L		= FALSE;
1705fda9279dSmrg	pPriv->blitter			= TRUE;
1706fda9279dSmrg	pPriv->texture			= FALSE;
1707fda9279dSmrg	pPriv->bicubic			= FALSE;
1708fda9279dSmrg	pPriv->doubleBuffer		= FALSE;
1709fda9279dSmrg	pPriv->SyncToVBlank		= (pNv->dev->chipset >= 0x11);
1710fda9279dSmrg
1711fda9279dSmrg	pNv->blitAdaptor		= adapt;
1712fda9279dSmrg
1713fda9279dSmrg	return adapt;
1714fda9279dSmrg}
1715fda9279dSmrg
1716fda9279dSmrg/**
1717fda9279dSmrg * NVSetupOverlayVideo
1718fda9279dSmrg * this function does all the work setting up an overlay port
1719fda9279dSmrg *
1720fda9279dSmrg * @return overlay port
1721fda9279dSmrg */
1722fda9279dSmrgstatic XF86VideoAdaptorPtr
1723fda9279dSmrgNVSetupOverlayVideoAdapter(ScreenPtr pScreen)
1724fda9279dSmrg{
1725fda9279dSmrg	ScrnInfoPtr         pScrn = xf86ScreenToScrn(pScreen);
1726fda9279dSmrg	NVPtr               pNv       = NVPTR(pScrn);
1727fda9279dSmrg	XF86VideoAdaptorPtr adapt;
1728fda9279dSmrg	NVPortPrivPtr       pPriv;
1729fda9279dSmrg
1730fda9279dSmrg	if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
1731fda9279dSmrg					sizeof(NVPortPrivRec) +
1732fda9279dSmrg					sizeof(DevUnion)))) {
1733fda9279dSmrg		return NULL;
1734fda9279dSmrg	}
1735fda9279dSmrg
1736fda9279dSmrg	adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
1737fda9279dSmrg	adapt->flags		= VIDEO_OVERLAID_IMAGES;
1738fda9279dSmrg	adapt->name		= "NV Video Overlay";
1739fda9279dSmrg	adapt->nEncodings	= 1;
1740fda9279dSmrg	adapt->pEncodings	= &DummyEncoding;
1741fda9279dSmrg	adapt->nFormats		= NUM_FORMATS_ALL;
1742fda9279dSmrg	adapt->pFormats		= NVFormats;
1743fda9279dSmrg	adapt->nPorts		= 1;
1744fda9279dSmrg	adapt->pPortPrivates	= (DevUnion*)(&adapt[1]);
1745fda9279dSmrg
1746fda9279dSmrg	pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[1]);
1747fda9279dSmrg	adapt->pPortPrivates[0].ptr	= (pointer)(pPriv);
1748fda9279dSmrg
1749fda9279dSmrg	adapt->pAttributes		= (pNv->Architecture != NV_ARCH_04) ? NV10OverlayAttributes : NV04OverlayAttributes;
1750fda9279dSmrg	adapt->nAttributes		= (pNv->Architecture != NV_ARCH_04) ? NUM_NV10_OVERLAY_ATTRIBUTES : NUM_NV04_OVERLAY_ATTRIBUTES;
1751fda9279dSmrg	adapt->pImages			= NVImages;
1752fda9279dSmrg	adapt->nImages			= NUM_IMAGES_YUV;
1753fda9279dSmrg	adapt->PutVideo			= NULL;
1754fda9279dSmrg	adapt->PutStill			= NULL;
1755fda9279dSmrg	adapt->GetVideo			= NULL;
1756fda9279dSmrg	adapt->GetStill			= NULL;
1757fda9279dSmrg	adapt->StopVideo		= NVStopOverlayVideo;
1758fda9279dSmrg	adapt->SetPortAttribute		= (pNv->Architecture != NV_ARCH_04) ? NV10SetOverlayPortAttribute : NV04SetOverlayPortAttribute;
1759fda9279dSmrg	adapt->GetPortAttribute		= (pNv->Architecture != NV_ARCH_04) ? NV10GetOverlayPortAttribute : NV04GetOverlayPortAttribute;
1760fda9279dSmrg	adapt->QueryBestSize		= NVQueryBestSize;
1761fda9279dSmrg	adapt->PutImage			= NVPutImage;
1762fda9279dSmrg	adapt->QueryImageAttributes	= NVQueryImageAttributes;
1763fda9279dSmrg
1764fda9279dSmrg	pPriv->videoStatus		= 0;
1765fda9279dSmrg	pPriv->currentBuffer		= 0;
1766fda9279dSmrg	pPriv->grabbedByV4L		= FALSE;
1767fda9279dSmrg	pPriv->blitter			= FALSE;
1768fda9279dSmrg	pPriv->texture			= FALSE;
1769fda9279dSmrg	pPriv->bicubic			= FALSE;
1770fda9279dSmrg
1771fda9279dSmrg	NVSetPortDefaults (pScrn, pPriv);
1772fda9279dSmrg
1773fda9279dSmrg	/* gotta uninit this someplace */
1774fda9279dSmrg	REGION_NULL(pScreen, &pPriv->clip);
1775fda9279dSmrg
1776fda9279dSmrg	pNv->overlayAdaptor	= adapt;
1777fda9279dSmrg
1778fda9279dSmrg	xvBrightness		= MAKE_ATOM("XV_BRIGHTNESS");
1779fda9279dSmrg	xvColorKey		= MAKE_ATOM("XV_COLORKEY");
1780fda9279dSmrg	xvAutopaintColorKey     = MAKE_ATOM("XV_AUTOPAINT_COLORKEY");
1781fda9279dSmrg	xvSetDefaults           = MAKE_ATOM("XV_SET_DEFAULTS");
1782fda9279dSmrg
1783fda9279dSmrg	if ( pNv->Architecture != NV_ARCH_04 )
1784fda9279dSmrg		{
1785fda9279dSmrg		xvDoubleBuffer		= MAKE_ATOM("XV_DOUBLE_BUFFER");
1786fda9279dSmrg		xvContrast		= MAKE_ATOM("XV_CONTRAST");
1787fda9279dSmrg		xvSaturation		= MAKE_ATOM("XV_SATURATION");
1788fda9279dSmrg		xvHue			= MAKE_ATOM("XV_HUE");
1789fda9279dSmrg		xvITURBT709		= MAKE_ATOM("XV_ITURBT_709");
1790fda9279dSmrg		xvOnCRTCNb		= MAKE_ATOM("XV_ON_CRTC_NB");
1791fda9279dSmrg		NV10WriteOverlayParameters(pScrn);
1792fda9279dSmrg		}
1793fda9279dSmrg
1794fda9279dSmrg	return adapt;
1795fda9279dSmrg}
1796fda9279dSmrg
1797fda9279dSmrg
1798fda9279dSmrgXF86OffscreenImageRec NVOffscreenImages[2] = {
1799fda9279dSmrg	{
1800fda9279dSmrg		&NVImages[0],
1801fda9279dSmrg		VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1802fda9279dSmrg		NVAllocSurface,
1803fda9279dSmrg		NVFreeSurface,
1804fda9279dSmrg		NVDisplaySurface,
1805fda9279dSmrg		NVStopSurface,
1806fda9279dSmrg		NVGetSurfaceAttribute,
1807fda9279dSmrg		NVSetSurfaceAttribute,
1808fda9279dSmrg		IMAGE_MAX_W, IMAGE_MAX_H,
1809fda9279dSmrg		NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1810fda9279dSmrg		&NV10OverlayAttributes[1]
1811fda9279dSmrg	},
1812fda9279dSmrg	{
1813fda9279dSmrg		&NVImages[2],
1814fda9279dSmrg		VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT,
1815fda9279dSmrg		NVAllocSurface,
1816fda9279dSmrg		NVFreeSurface,
1817fda9279dSmrg		NVDisplaySurface,
1818fda9279dSmrg		NVStopSurface,
1819fda9279dSmrg		NVGetSurfaceAttribute,
1820fda9279dSmrg		NVSetSurfaceAttribute,
1821fda9279dSmrg		IMAGE_MAX_W, IMAGE_MAX_H,
1822fda9279dSmrg		NUM_NV10_OVERLAY_ATTRIBUTES - 1,
1823fda9279dSmrg		&NV10OverlayAttributes[1]
1824fda9279dSmrg	}
1825fda9279dSmrg};
1826fda9279dSmrg
1827fda9279dSmrgstatic void
1828fda9279dSmrgNVInitOffscreenImages (ScreenPtr pScreen)
1829fda9279dSmrg{
1830fda9279dSmrg	xf86XVRegisterOffscreenImages(pScreen, NVOffscreenImages, 2);
1831fda9279dSmrg}
1832fda9279dSmrg
1833fda9279dSmrg/**
1834fda9279dSmrg * NVChipsetHasOverlay
1835fda9279dSmrg *
1836fda9279dSmrg * newer chips don't support overlay anymore.
1837fda9279dSmrg * overlay feature is emulated via textures.
1838fda9279dSmrg *
1839fda9279dSmrg * @param pNv
1840fda9279dSmrg * @return true, if chipset supports overlay
1841fda9279dSmrg */
1842fda9279dSmrgstatic Bool
1843fda9279dSmrgNVChipsetHasOverlay(NVPtr pNv)
1844fda9279dSmrg{
1845fda9279dSmrg	switch (pNv->Architecture) {
1846fda9279dSmrg	case NV_ARCH_04: /*NV04 has a different overlay than NV10+*/
1847fda9279dSmrg	case NV_ARCH_10:
1848fda9279dSmrg	case NV_ARCH_20:
1849fda9279dSmrg	case NV_ARCH_30:
1850fda9279dSmrg		return TRUE;
1851fda9279dSmrg	case NV_ARCH_40:
1852fda9279dSmrg		if (pNv->dev->chipset == 0x40)
1853fda9279dSmrg			return TRUE;
1854fda9279dSmrg		break;
1855fda9279dSmrg	default:
1856fda9279dSmrg		break;
1857fda9279dSmrg	}
1858fda9279dSmrg
1859fda9279dSmrg	return FALSE;
1860fda9279dSmrg}
1861fda9279dSmrg
1862fda9279dSmrg/**
1863fda9279dSmrg * NVSetupOverlayVideo
1864fda9279dSmrg * check if chipset supports Overla
1865fda9279dSmrg * if so, setup overlay port
1866fda9279dSmrg *
1867fda9279dSmrg * @return overlay port
1868fda9279dSmrg * @see NVChipsetHasOverlay(NVPtr pNv)
1869fda9279dSmrg * @see NV10SetupOverlayVideo(ScreenPtr pScreen)
1870fda9279dSmrg * @see NVInitOffscreenImages(ScreenPtr pScreen)
1871fda9279dSmrg */
1872fda9279dSmrgstatic XF86VideoAdaptorPtr
1873fda9279dSmrgNVSetupOverlayVideo(ScreenPtr pScreen)
1874fda9279dSmrg{
1875fda9279dSmrg	ScrnInfoPtr          pScrn = xf86ScreenToScrn(pScreen);
1876fda9279dSmrg	XF86VideoAdaptorPtr  overlayAdaptor = NULL;
1877fda9279dSmrg	NVPtr                pNv   = NVPTR(pScrn);
1878fda9279dSmrg
1879fda9279dSmrg	if (1 /*pNv->kms_enable*/ || !NVChipsetHasOverlay(pNv))
1880fda9279dSmrg		return NULL;
1881fda9279dSmrg
1882fda9279dSmrg	overlayAdaptor = NVSetupOverlayVideoAdapter(pScreen);
1883fda9279dSmrg	/* I am not sure what this call does. */
1884fda9279dSmrg	if (overlayAdaptor && pNv->Architecture != NV_ARCH_04 )
1885fda9279dSmrg		NVInitOffscreenImages(pScreen);
1886fda9279dSmrg
1887fda9279dSmrg	#ifdef COMPOSITE
1888fda9279dSmrg	if (!noCompositeExtension) {
1889fda9279dSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1890fda9279dSmrg			   "Xv: Composite is enabled, enabling overlay with "
1891fda9279dSmrg			   "smart blitter fallback\n");
1892fda9279dSmrg		overlayAdaptor->name = "NV Video Overlay with Composite";
1893fda9279dSmrg	}
1894fda9279dSmrg	#endif
1895fda9279dSmrg
1896fda9279dSmrg	return overlayAdaptor;
1897fda9279dSmrg}
1898fda9279dSmrg
1899fda9279dSmrg/**
1900fda9279dSmrg * NV30 texture adapter.
1901fda9279dSmrg */
1902fda9279dSmrg
1903fda9279dSmrg#define NUM_FORMAT_TEXTURED 2
1904fda9279dSmrg
1905fda9279dSmrgstatic XF86ImageRec NV30TexturedImages[NUM_FORMAT_TEXTURED] =
1906fda9279dSmrg{
1907fda9279dSmrg	XVIMAGE_YV12,
1908fda9279dSmrg	XVIMAGE_I420,
1909fda9279dSmrg};
1910fda9279dSmrg
1911fda9279dSmrg/**
1912fda9279dSmrg * NV30SetupTexturedVideo
1913fda9279dSmrg * this function does all the work setting up textured video port
1914fda9279dSmrg *
1915fda9279dSmrg * @return texture port
1916fda9279dSmrg */
1917fda9279dSmrgstatic XF86VideoAdaptorPtr
1918fda9279dSmrgNV30SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic)
1919fda9279dSmrg{
1920fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1921fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
1922fda9279dSmrg	XF86VideoAdaptorPtr adapt;
1923fda9279dSmrg	NVPortPrivPtr pPriv;
1924fda9279dSmrg	int i;
1925fda9279dSmrg
1926fda9279dSmrg	if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
1927fda9279dSmrg				 sizeof(NVPortPrivRec) +
1928fda9279dSmrg				 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
1929fda9279dSmrg		return NULL;
1930fda9279dSmrg	}
1931fda9279dSmrg
1932fda9279dSmrg	adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
1933fda9279dSmrg	adapt->flags		= 0;
1934fda9279dSmrg	if (bicubic)
1935fda9279dSmrg		adapt->name		= "NV30 high quality adapter";
1936fda9279dSmrg	else
1937fda9279dSmrg		adapt->name		= "NV30 texture adapter";
1938fda9279dSmrg	adapt->nEncodings	= 1;
1939fda9279dSmrg	adapt->pEncodings	= &DummyEncodingTex;
1940fda9279dSmrg	adapt->nFormats		= NUM_FORMATS_ALL;
1941fda9279dSmrg	adapt->pFormats		= NVFormats;
1942fda9279dSmrg	adapt->nPorts		= NUM_TEXTURE_PORTS;
1943fda9279dSmrg	adapt->pPortPrivates	= (DevUnion*)(&adapt[1]);
1944fda9279dSmrg
1945fda9279dSmrg	pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
1946fda9279dSmrg	for(i = 0; i < NUM_TEXTURE_PORTS; i++)
1947fda9279dSmrg		adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
1948fda9279dSmrg
1949fda9279dSmrg	adapt->pAttributes		= NVTexturedAttributes;
1950fda9279dSmrg	adapt->nAttributes		= NUM_TEXTURED_ATTRIBUTES;
1951fda9279dSmrg	adapt->pImages			= NV30TexturedImages;
1952fda9279dSmrg	adapt->nImages			= NUM_FORMAT_TEXTURED;
1953fda9279dSmrg	adapt->PutVideo			= NULL;
1954fda9279dSmrg	adapt->PutStill			= NULL;
1955fda9279dSmrg	adapt->GetVideo			= NULL;
1956fda9279dSmrg	adapt->GetStill			= NULL;
1957fda9279dSmrg	adapt->StopVideo		= NV30StopTexturedVideo;
1958fda9279dSmrg	adapt->SetPortAttribute		= NV30SetTexturePortAttribute;
1959fda9279dSmrg	adapt->GetPortAttribute		= NV30GetTexturePortAttribute;
1960fda9279dSmrg	adapt->QueryBestSize		= NVQueryBestSize;
1961fda9279dSmrg	adapt->PutImage			= NVPutImage;
1962fda9279dSmrg	adapt->QueryImageAttributes	= NVQueryImageAttributes;
1963fda9279dSmrg
1964fda9279dSmrg	pPriv->videoStatus		= 0;
1965fda9279dSmrg	pPriv->grabbedByV4L		= FALSE;
1966fda9279dSmrg	pPriv->blitter			= FALSE;
1967fda9279dSmrg	pPriv->texture			= TRUE;
1968fda9279dSmrg	pPriv->bicubic			= bicubic;
1969fda9279dSmrg	pPriv->doubleBuffer		= FALSE;
1970fda9279dSmrg	pPriv->SyncToVBlank		= TRUE;
1971fda9279dSmrg
1972fda9279dSmrg	if (bicubic)
1973fda9279dSmrg		pNv->textureAdaptor[1]	= adapt;
1974fda9279dSmrg	else
1975fda9279dSmrg		pNv->textureAdaptor[0]	= adapt;
1976fda9279dSmrg
1977fda9279dSmrg	return adapt;
1978fda9279dSmrg}
1979fda9279dSmrg
1980fda9279dSmrg/**
1981fda9279dSmrg * NV40 texture adapter.
1982fda9279dSmrg */
1983fda9279dSmrg
1984fda9279dSmrg#define NUM_FORMAT_TEXTURED 2
1985fda9279dSmrg
1986fda9279dSmrgstatic XF86ImageRec NV40TexturedImages[NUM_FORMAT_TEXTURED] =
1987fda9279dSmrg{
1988fda9279dSmrg	XVIMAGE_YV12,
1989fda9279dSmrg	XVIMAGE_I420,
1990fda9279dSmrg};
1991fda9279dSmrg
1992fda9279dSmrg/**
1993fda9279dSmrg * NV40SetupTexturedVideo
1994fda9279dSmrg * this function does all the work setting up textured video port
1995fda9279dSmrg *
1996fda9279dSmrg * @return texture port
1997fda9279dSmrg */
1998fda9279dSmrgstatic XF86VideoAdaptorPtr
1999fda9279dSmrgNV40SetupTexturedVideo (ScreenPtr pScreen, Bool bicubic)
2000fda9279dSmrg{
2001fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2002fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
2003fda9279dSmrg	XF86VideoAdaptorPtr adapt;
2004fda9279dSmrg	NVPortPrivPtr pPriv;
2005fda9279dSmrg	int i;
2006fda9279dSmrg
2007fda9279dSmrg	if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
2008fda9279dSmrg				 sizeof(NVPortPrivRec) +
2009fda9279dSmrg				 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
2010fda9279dSmrg		return NULL;
2011fda9279dSmrg	}
2012fda9279dSmrg
2013fda9279dSmrg	adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
2014fda9279dSmrg	adapt->flags		= 0;
2015fda9279dSmrg	if (bicubic)
2016fda9279dSmrg		adapt->name		= "NV40 high quality adapter";
2017fda9279dSmrg	else
2018fda9279dSmrg		adapt->name		= "NV40 texture adapter";
2019fda9279dSmrg	adapt->nEncodings	= 1;
2020fda9279dSmrg	adapt->pEncodings	= &DummyEncodingTex;
2021fda9279dSmrg	adapt->nFormats		= NUM_FORMATS_ALL;
2022fda9279dSmrg	adapt->pFormats		= NVFormats;
2023fda9279dSmrg	adapt->nPorts		= NUM_TEXTURE_PORTS;
2024fda9279dSmrg	adapt->pPortPrivates	= (DevUnion*)(&adapt[1]);
2025fda9279dSmrg
2026fda9279dSmrg	pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
2027fda9279dSmrg	for(i = 0; i < NUM_TEXTURE_PORTS; i++)
2028fda9279dSmrg		adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
2029fda9279dSmrg
2030fda9279dSmrg	adapt->pAttributes		= NVTexturedAttributes;
2031fda9279dSmrg	adapt->nAttributes		= NUM_TEXTURED_ATTRIBUTES;
2032fda9279dSmrg	adapt->pImages			= NV40TexturedImages;
2033fda9279dSmrg	adapt->nImages			= NUM_FORMAT_TEXTURED;
2034fda9279dSmrg	adapt->PutVideo			= NULL;
2035fda9279dSmrg	adapt->PutStill			= NULL;
2036fda9279dSmrg	adapt->GetVideo			= NULL;
2037fda9279dSmrg	adapt->GetStill			= NULL;
2038fda9279dSmrg	adapt->StopVideo		= NV40StopTexturedVideo;
2039fda9279dSmrg	adapt->SetPortAttribute		= NV40SetTexturePortAttribute;
2040fda9279dSmrg	adapt->GetPortAttribute		= NV40GetTexturePortAttribute;
2041fda9279dSmrg	adapt->QueryBestSize		= NVQueryBestSize;
2042fda9279dSmrg	adapt->PutImage			= NVPutImage;
2043fda9279dSmrg	adapt->QueryImageAttributes	= NVQueryImageAttributes;
2044fda9279dSmrg
2045fda9279dSmrg	pPriv->videoStatus		= 0;
2046fda9279dSmrg	pPriv->grabbedByV4L		= FALSE;
2047fda9279dSmrg	pPriv->blitter			= FALSE;
2048fda9279dSmrg	pPriv->texture			= TRUE;
2049fda9279dSmrg	pPriv->bicubic			= bicubic;
2050fda9279dSmrg	pPriv->doubleBuffer		= FALSE;
2051fda9279dSmrg	pPriv->SyncToVBlank		= TRUE;
2052fda9279dSmrg
2053fda9279dSmrg	if (bicubic)
2054fda9279dSmrg		pNv->textureAdaptor[1]	= adapt;
2055fda9279dSmrg	else
2056fda9279dSmrg		pNv->textureAdaptor[0]	= adapt;
2057fda9279dSmrg
2058fda9279dSmrg	return adapt;
2059fda9279dSmrg}
2060fda9279dSmrg
2061fda9279dSmrgstatic XF86ImageRec
2062fda9279dSmrgNV50TexturedImages[] =
2063fda9279dSmrg{
2064fda9279dSmrg	XVIMAGE_YV12,
2065fda9279dSmrg	XVIMAGE_I420,
2066fda9279dSmrg	XVIMAGE_YUY2,
2067fda9279dSmrg	XVIMAGE_UYVY
2068fda9279dSmrg};
2069fda9279dSmrg
2070fda9279dSmrgstatic XF86VideoAdaptorPtr
2071fda9279dSmrgNV50SetupTexturedVideo (ScreenPtr pScreen)
2072fda9279dSmrg{
2073fda9279dSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2074fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
2075fda9279dSmrg	XF86VideoAdaptorPtr adapt;
2076fda9279dSmrg	NVPortPrivPtr pPriv;
2077fda9279dSmrg	int i;
2078fda9279dSmrg
2079fda9279dSmrg	if (!(adapt = calloc(1, sizeof(XF86VideoAdaptorRec) +
2080fda9279dSmrg				 sizeof(NVPortPrivRec) +
2081fda9279dSmrg				 (sizeof(DevUnion) * NUM_TEXTURE_PORTS)))) {
2082fda9279dSmrg		return NULL;
2083fda9279dSmrg	}
2084fda9279dSmrg
2085fda9279dSmrg	adapt->type		= XvWindowMask | XvInputMask | XvImageMask;
2086fda9279dSmrg	adapt->flags		= 0;
2087fda9279dSmrg	adapt->name		= "Nouveau GeForce 8/9 Textured Video";
2088fda9279dSmrg	adapt->nEncodings	= 1;
2089fda9279dSmrg	adapt->pEncodings	= &DummyEncodingNV50;
2090fda9279dSmrg	adapt->nFormats		= NUM_FORMATS_ALL;
2091fda9279dSmrg	adapt->pFormats		= NVFormats;
2092fda9279dSmrg	adapt->nPorts		= NUM_TEXTURE_PORTS;
2093fda9279dSmrg	adapt->pPortPrivates	= (DevUnion*)(&adapt[1]);
2094fda9279dSmrg
2095fda9279dSmrg	pPriv = (NVPortPrivPtr)(&adapt->pPortPrivates[NUM_TEXTURE_PORTS]);
2096fda9279dSmrg	for(i = 0; i < NUM_TEXTURE_PORTS; i++)
2097fda9279dSmrg		adapt->pPortPrivates[i].ptr = (pointer)(pPriv);
2098fda9279dSmrg
2099fda9279dSmrg	adapt->pAttributes		= NVTexturedAttributesNV50;
2100fda9279dSmrg	adapt->nAttributes		= NUM_TEXTURED_ATTRIBUTES_NV50;
2101fda9279dSmrg	adapt->pImages			= NV50TexturedImages;
2102fda9279dSmrg	adapt->nImages			= sizeof(NV50TexturedImages) /
2103fda9279dSmrg					  sizeof(NV50TexturedImages[0]);
2104fda9279dSmrg	adapt->PutVideo			= NULL;
2105fda9279dSmrg	adapt->PutStill			= NULL;
2106fda9279dSmrg	adapt->GetVideo			= NULL;
2107fda9279dSmrg	adapt->GetStill			= NULL;
2108fda9279dSmrg	adapt->StopVideo		= nv50_xv_video_stop;
2109fda9279dSmrg	adapt->SetPortAttribute		= nv50_xv_port_attribute_set;
2110fda9279dSmrg	adapt->GetPortAttribute		= nv50_xv_port_attribute_get;
2111fda9279dSmrg	adapt->QueryBestSize		= NVQueryBestSize;
2112fda9279dSmrg	adapt->PutImage			= NVPutImage;
2113fda9279dSmrg	adapt->QueryImageAttributes	= NVQueryImageAttributes;
2114fda9279dSmrg
2115fda9279dSmrg	pNv->textureAdaptor[0]		= adapt;
2116fda9279dSmrg
2117fda9279dSmrg	nv50_xv_set_port_defaults(pScrn, pPriv);
2118fda9279dSmrg	nv50_xv_csc_update(pScrn, pPriv);
2119fda9279dSmrg
2120fda9279dSmrg	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
2121fda9279dSmrg	xvContrast   = MAKE_ATOM("XV_CONTRAST");
2122fda9279dSmrg	xvSaturation = MAKE_ATOM("XV_SATURATION");
2123fda9279dSmrg	xvHue        = MAKE_ATOM("XV_HUE");
2124fda9279dSmrg	xvITURBT709  = MAKE_ATOM("XV_ITURBT_709");
2125fda9279dSmrg	return adapt;
2126fda9279dSmrg}
2127fda9279dSmrg
2128fda9279dSmrgvoid
2129fda9279dSmrgNVSetupTexturedVideo (ScreenPtr pScreen, XF86VideoAdaptorPtr *textureAdaptor)
2130fda9279dSmrg{
2131fda9279dSmrg	ScrnInfoPtr          pScrn = xf86ScreenToScrn(pScreen);
2132fda9279dSmrg	NVPtr                pNv = NVPTR(pScrn);
2133fda9279dSmrg
2134fda9279dSmrg	if (!pNv->Nv3D)
2135fda9279dSmrg		return;
2136fda9279dSmrg
2137fda9279dSmrg	if (pNv->Architecture == NV_ARCH_30) {
2138fda9279dSmrg		textureAdaptor[0] = NV30SetupTexturedVideo(pScreen, FALSE);
2139fda9279dSmrg		textureAdaptor[1] = NV30SetupTexturedVideo(pScreen, TRUE);
2140fda9279dSmrg	} else
2141fda9279dSmrg	if (pNv->Architecture == NV_ARCH_40) {
2142fda9279dSmrg		textureAdaptor[0] = NV40SetupTexturedVideo(pScreen, FALSE);
2143fda9279dSmrg		textureAdaptor[1] = NV40SetupTexturedVideo(pScreen, TRUE);
2144fda9279dSmrg	} else
2145fda9279dSmrg	if (pNv->Architecture >= NV_TESLA && pNv->Architecture < NV_MAXWELL) {
2146fda9279dSmrg		textureAdaptor[0] = NV50SetupTexturedVideo(pScreen);
2147fda9279dSmrg	}
2148fda9279dSmrg}
2149fda9279dSmrg
2150fda9279dSmrg/**
2151fda9279dSmrg * NVInitVideo
2152fda9279dSmrg * tries to initialize the various supported adapters
2153fda9279dSmrg * and add them to the list of ports on screen "pScreen".
2154fda9279dSmrg *
2155fda9279dSmrg * @param pScreen
2156fda9279dSmrg * @see NVSetupOverlayVideo(ScreenPtr pScreen)
2157fda9279dSmrg * @see NVSetupBlitVideo(ScreenPtr pScreen)
2158fda9279dSmrg */
2159fda9279dSmrgvoid
2160fda9279dSmrgNVInitVideo(ScreenPtr pScreen)
2161fda9279dSmrg{
2162fda9279dSmrg	ScrnInfoPtr          pScrn = xf86ScreenToScrn(pScreen);
2163fda9279dSmrg	NVPtr                pNv = NVPTR(pScrn);
2164fda9279dSmrg	XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
2165fda9279dSmrg	XF86VideoAdaptorPtr  overlayAdaptor = NULL;
2166fda9279dSmrg	XF86VideoAdaptorPtr  blitAdaptor = NULL;
2167fda9279dSmrg	XF86VideoAdaptorPtr  textureAdaptor[2] = {NULL, NULL};
2168fda9279dSmrg	int                  num_adaptors;
2169fda9279dSmrg
2170fda9279dSmrg	/*
2171fda9279dSmrg	 * Driving the blitter requires the DMA FIFO. Using the FIFO
2172fda9279dSmrg	 * without accel causes DMA errors. While the overlay might
2173fda9279dSmrg	 * might work without accel, we also disable it for now when
2174fda9279dSmrg	 * acceleration is disabled:
2175fda9279dSmrg	 */
2176fda9279dSmrg	if (pScrn->bitsPerPixel != 8 && pNv->AccelMethod == EXA) {
2177fda9279dSmrg		xvSyncToVBlank = MAKE_ATOM("XV_SYNC_TO_VBLANK");
2178fda9279dSmrg
2179fda9279dSmrg		if (pNv->Architecture < NV_TESLA) {
2180fda9279dSmrg			overlayAdaptor = NVSetupOverlayVideo(pScreen);
2181fda9279dSmrg			blitAdaptor    = NVSetupBlitVideo(pScreen);
2182fda9279dSmrg		}
2183fda9279dSmrg
2184fda9279dSmrg		NVSetupTexturedVideo(pScreen, textureAdaptor);
2185fda9279dSmrg	} else
2186fda9279dSmrg	if (pNv->AccelMethod == GLAMOR) {
2187fda9279dSmrg		blitAdaptor = nouveau_glamor_xv_init(pScreen, 16);
2188fda9279dSmrg	}
2189fda9279dSmrg
2190fda9279dSmrg	num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
2191fda9279dSmrg	if (blitAdaptor || overlayAdaptor || textureAdaptor[0]) {
2192fda9279dSmrg		int size = num_adaptors;
2193fda9279dSmrg
2194fda9279dSmrg		if(overlayAdaptor) size++;
2195fda9279dSmrg		if(blitAdaptor)    size++;
2196fda9279dSmrg		if(textureAdaptor[0]) size++;
2197fda9279dSmrg		if(textureAdaptor[1]) size++;
2198fda9279dSmrg
2199fda9279dSmrg		newAdaptors = malloc(size * sizeof(XF86VideoAdaptorPtr *));
2200fda9279dSmrg		if(newAdaptors) {
2201fda9279dSmrg			if(num_adaptors) {
2202fda9279dSmrg				memcpy(newAdaptors, adaptors, num_adaptors *
2203fda9279dSmrg						sizeof(XF86VideoAdaptorPtr));
2204fda9279dSmrg			}
2205fda9279dSmrg
2206fda9279dSmrg			if(overlayAdaptor) {
2207fda9279dSmrg				newAdaptors[num_adaptors] = overlayAdaptor;
2208fda9279dSmrg				num_adaptors++;
2209fda9279dSmrg			}
2210fda9279dSmrg
2211fda9279dSmrg			if (textureAdaptor[0]) { /* bilinear */
2212fda9279dSmrg				newAdaptors[num_adaptors] = textureAdaptor[0];
2213fda9279dSmrg				num_adaptors++;
2214fda9279dSmrg			}
2215fda9279dSmrg
2216fda9279dSmrg			if (textureAdaptor[1]) { /* bicubic */
2217fda9279dSmrg				newAdaptors[num_adaptors] = textureAdaptor[1];
2218fda9279dSmrg				num_adaptors++;
2219fda9279dSmrg			}
2220fda9279dSmrg
2221fda9279dSmrg			if(blitAdaptor) {
2222fda9279dSmrg				newAdaptors[num_adaptors] = blitAdaptor;
2223fda9279dSmrg				num_adaptors++;
2224fda9279dSmrg			}
2225fda9279dSmrg
2226fda9279dSmrg			adaptors = newAdaptors;
2227fda9279dSmrg		}
2228fda9279dSmrg	}
2229fda9279dSmrg
2230fda9279dSmrg	if (num_adaptors)
2231fda9279dSmrg		xf86XVScreenInit(pScreen, adaptors, num_adaptors);
2232fda9279dSmrg	if (newAdaptors)
2233fda9279dSmrg		free(newAdaptors);
2234fda9279dSmrg
2235fda9279dSmrg	/*
2236fda9279dSmrg	 * For now we associate with the plain texture adapter since it is logical, but we can
2237fda9279dSmrg	 * associate with any/all adapters since VL doesn't depend on Xv for color conversion.
2238fda9279dSmrg	 */
2239fda9279dSmrg	if (textureAdaptor[0]) {
2240fda9279dSmrg		XF86MCAdaptorPtr *adaptorsXvMC = malloc(sizeof(XF86MCAdaptorPtr));
2241fda9279dSmrg
2242fda9279dSmrg		if (adaptorsXvMC) {
2243fda9279dSmrg			adaptorsXvMC[0] = vlCreateAdaptorXvMC(pScreen, textureAdaptor[0]->name);
2244fda9279dSmrg
2245fda9279dSmrg			if (adaptorsXvMC[0]) {
2246fda9279dSmrg				vlInitXvMC(pScreen, 1, adaptorsXvMC);
2247fda9279dSmrg				vlDestroyAdaptorXvMC(adaptorsXvMC[0]);
2248fda9279dSmrg			}
2249fda9279dSmrg
2250fda9279dSmrg			free(adaptorsXvMC);
2251fda9279dSmrg		}
2252fda9279dSmrg	}
2253fda9279dSmrg}
2254fda9279dSmrg
2255fda9279dSmrgvoid
2256fda9279dSmrgNVTakedownVideo(ScrnInfoPtr pScrn)
2257fda9279dSmrg{
2258fda9279dSmrg	NVPtr pNv = NVPTR(pScrn);
2259fda9279dSmrg
2260fda9279dSmrg	if (pNv->blitAdaptor)
2261fda9279dSmrg		NVFreePortMemory(pScrn, GET_BLIT_PRIVATE(pNv));
2262fda9279dSmrg	if (pNv->textureAdaptor[0]) {
2263fda9279dSmrg		NVFreePortMemory(pScrn,
2264fda9279dSmrg				 pNv->textureAdaptor[0]->pPortPrivates[0].ptr);
2265fda9279dSmrg	}
2266fda9279dSmrg	if (pNv->textureAdaptor[1]) {
2267fda9279dSmrg		NVFreePortMemory(pScrn,
2268fda9279dSmrg				 pNv->textureAdaptor[1]->pPortPrivates[0].ptr);
2269fda9279dSmrg	}
2270fda9279dSmrg}
2271fda9279dSmrg
2272fda9279dSmrg/* The filtering function used for video scaling. We use a cubic filter as
2273fda9279dSmrg * defined in  "Reconstruction Filters in Computer Graphics" Mitchell &
2274fda9279dSmrg * Netravali in SIGGRAPH '88
2275fda9279dSmrg */
2276fda9279dSmrgstatic float filter_func(float x)
2277fda9279dSmrg{
2278fda9279dSmrg	const double B=0.75;
2279fda9279dSmrg	const double C=(1.0-B)/2.0;
2280fda9279dSmrg	double x1=fabs(x);
2281fda9279dSmrg	double x2=fabs(x)*x1;
2282fda9279dSmrg	double x3=fabs(x)*x2;
2283fda9279dSmrg
2284fda9279dSmrg	if (fabs(x)<1.0)
2285fda9279dSmrg		return ( (12.0-9.0*B-6.0*C)*x3+(-18.0+12.0*B+6.0*C)*x2+(6.0-2.0*B) )/6.0;
2286fda9279dSmrg	else
2287fda9279dSmrg		return ( (-B-6.0*C)*x3+(6.0*B+30.0*C)*x2+(-12.0*B-48.0*C)*x1+(8.0*B+24.0*C) )/6.0;
2288fda9279dSmrg}
2289fda9279dSmrg
2290fda9279dSmrgstatic int8_t f32tosb8(float v)
2291fda9279dSmrg{
2292fda9279dSmrg	return (int8_t)(v*127.0);
2293fda9279dSmrg}
2294fda9279dSmrg
2295fda9279dSmrgvoid
2296fda9279dSmrgNVXVComputeBicubicFilter(struct nouveau_bo *bo, unsigned offset, unsigned size)
2297fda9279dSmrg{
2298fda9279dSmrg	int8_t *t = (int8_t *)(bo->map + offset);
2299fda9279dSmrg	int i;
2300fda9279dSmrg
2301fda9279dSmrg	for(i = 0; i < size; i++) {
2302fda9279dSmrg		float  x = (i + 0.5) / size;
2303fda9279dSmrg		float w0 = filter_func(x+1.0);
2304fda9279dSmrg		float w1 = filter_func(x);
2305fda9279dSmrg		float w2 = filter_func(x-1.0);
2306fda9279dSmrg		float w3 = filter_func(x-2.0);
2307fda9279dSmrg
2308fda9279dSmrg		t[4*i+2]=f32tosb8(1.0+x-w1/(w0+w1));
2309fda9279dSmrg		t[4*i+1]=f32tosb8(1.0-x+w3/(w2+w3));
2310fda9279dSmrg		t[4*i+0]=f32tosb8(w0+w1);
2311fda9279dSmrg		t[4*i+3]=f32tosb8(0.0);
2312fda9279dSmrg	}
2313fda9279dSmrg}
2314