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