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