1/***************************************************************************
2
3 Copyright 2000 Intel Corporation.  All Rights Reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sub license, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice (including the
14 next paragraph) shall be included in all copies or substantial portions
15 of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23 THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27/*
28 * i830_video.c: i830/i845 Xv driver.
29 *
30 * Copyright © 2002 by Alan Hourihane and David Dawes
31 *
32 * Authors:
33 *	Alan Hourihane <alanh@tungstengraphics.com>
34 *	David Dawes <dawes@xfree86.org>
35 *
36 * Derived from i810 Xv driver:
37 *
38 * Authors of i810 code:
39 * 	Jonathan Bian <jonathan.bian@intel.com>
40 *      Offscreen Images:
41 *        Matt Sottek <matthew.j.sottek@intel.com>
42 */
43
44/*
45 * XXX Could support more formats.
46 */
47
48#ifdef HAVE_CONFIG_H
49#include "config.h"
50#endif
51
52#include <inttypes.h>
53#include <math.h>
54#include <string.h>
55#include <assert.h>
56
57#include "xf86.h"
58#include "xf86_OSproc.h"
59#include "compiler.h"
60#include "xf86PciInfo.h"
61#include "xf86Pci.h"
62#include "xf86fbman.h"
63#include "regionstr.h"
64#include "randrstr.h"
65#include "windowstr.h"
66#include "damage.h"
67#include "i830.h"
68#include "i830_video.h"
69#include "xf86xv.h"
70#include <X11/extensions/Xv.h>
71#include "dixstruct.h"
72#include "fourcc.h"
73
74#ifdef INTEL_XVMC
75#define _INTEL_XVMC_SERVER_
76#include "i830_hwmc.h"
77#include "i915_hwmc.h"
78#endif
79
80#define OFF_DELAY 	250		/* milliseconds */
81#define FREE_DELAY 	15000
82
83#define OFF_TIMER 	0x01
84#define FREE_TIMER	0x02
85#define CLIENT_VIDEO_ON	0x04
86
87#define TIMER_MASK      (OFF_TIMER | FREE_TIMER)
88
89static void I830InitOffscreenImages(ScreenPtr);
90
91static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr);
92static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr);
93static void I830StopVideo(ScrnInfoPtr, pointer, Bool);
94static int I830SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
95static int I830SetPortAttributeTextured(ScrnInfoPtr, Atom, INT32, pointer);
96static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
97static void I830QueryBestSize(ScrnInfoPtr, Bool,
98			      short, short, short, short, unsigned int *,
99			      unsigned int *, pointer);
100static int I830PutImage(ScrnInfoPtr, short, short, short, short, short, short,
101			short, short, int, unsigned char *, short, short,
102			Bool, RegionPtr, pointer, DrawablePtr);
103static int I830QueryImageAttributes(ScrnInfoPtr, int, unsigned short *,
104					   unsigned short *, int *, int *);
105
106#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
107
108static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe, xvDoubleBuffer;
109static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
110static Atom xvSyncToVblank;
111
112/* Limits for the overlay/textured video source sizes.  The documented hardware
113 * limits are 2048x2048 or better for overlay and both of our textured video
114 * implementations.  Additionally, on the 830 and 845, larger sizes resulted in
115 * the card hanging, so we keep the limits lower there.
116 */
117#define IMAGE_MAX_WIDTH		2048
118#define IMAGE_MAX_HEIGHT	2048
119#define IMAGE_MAX_WIDTH_LEGACY	1024
120#define IMAGE_MAX_HEIGHT_LEGACY	1088
121
122/* overlay debugging printf function */
123#if 0
124#define OVERLAY_DEBUG ErrorF
125#else
126#define OVERLAY_DEBUG if (0) ErrorF
127#endif
128
129/*
130 * OCMD - Overlay Command Register
131 */
132#define OCMD_REGISTER		0x30168
133#define MIRROR_MODE		(0x3<<17)
134#define MIRROR_HORIZONTAL	(0x1<<17)
135#define MIRROR_VERTICAL		(0x2<<17)
136#define MIRROR_BOTH		(0x3<<17)
137#define OV_BYTE_ORDER		(0x3<<14)
138#define UV_SWAP			(0x1<<14)
139#define Y_SWAP			(0x2<<14)
140#define Y_AND_UV_SWAP		(0x3<<14)
141#define SOURCE_FORMAT		(0xf<<10)
142#define RGB_888			(0x1<<10)
143#define	RGB_555			(0x2<<10)
144#define	RGB_565			(0x3<<10)
145#define	YUV_422			(0x8<<10)
146#define	YUV_411			(0x9<<10)
147#define	YUV_420			(0xc<<10)
148#define	YUV_422_PLANAR		(0xd<<10)
149#define	YUV_410			(0xe<<10)
150#define TVSYNC_FLIP_PARITY	(0x1<<9)
151#define TVSYNC_FLIP_ENABLE	(0x1<<7)
152#define BUF_TYPE		(0x1<<5)
153#define BUF_TYPE_FRAME		(0x0<<5)
154#define BUF_TYPE_FIELD		(0x1<<5)
155#define TEST_MODE		(0x1<<4)
156#define BUFFER_SELECT		(0x3<<2)
157#define BUFFER0			(0x0<<2)
158#define BUFFER1			(0x1<<2)
159#define FIELD_SELECT		(0x1<<1)
160#define FIELD0			(0x0<<1)
161#define FIELD1			(0x1<<1)
162#define OVERLAY_ENABLE		0x1
163
164#define OFC_UPDATE		0x1
165
166/* OCONFIG register */
167#define CC_OUT_8BIT		(0x1<<3)
168#define OVERLAY_PIPE_MASK	(0x1<<18)
169#define OVERLAY_PIPE_A		(0x0<<18)
170#define OVERLAY_PIPE_B		(0x1<<18)
171#define GAMMA2_ENBL		(0x1<<16)
172#define CSC_MODE_BT709		(0x1<<5)
173#define CSC_MODE_BT601		(0x0<<5)
174#define THREE_LINE_BUFFERS	(0x1<<0)
175#define TWO_LINE_BUFFERS	(0x0<<0)
176
177/* DCLRKM register */
178#define DEST_KEY_ENABLE		(0x1<<31)
179
180/* Polyphase filter coefficients */
181#define N_HORIZ_Y_TAPS		5
182#define N_VERT_Y_TAPS		3
183#define N_HORIZ_UV_TAPS		3
184#define N_VERT_UV_TAPS		3
185#define N_PHASES		17
186#define MAX_TAPS		5
187
188/* Filter cutoff frequency limits. */
189#define MIN_CUTOFF_FREQ		1.0
190#define MAX_CUTOFF_FREQ		3.0
191
192#define RGB16ToColorKey(c) \
193(((c & 0xF800) << 8) | ((c & 0x07E0) << 5) | ((c & 0x001F) << 3))
194
195#define RGB15ToColorKey(c) \
196(((c & 0x7c00) << 9) | ((c & 0x03E0) << 6) | ((c & 0x001F) << 3))
197
198/* client libraries expect an encoding */
199static XF86VideoEncodingRec DummyEncoding[1] = {
200    {
201	0,
202	"XV_IMAGE",
203	IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
204	{1, 1}
205    }
206};
207
208#define NUM_FORMATS 3
209
210static XF86VideoFormatRec Formats[NUM_FORMATS] = {
211    {15, TrueColor}, {16, TrueColor}, {24, TrueColor}
212};
213
214#define CLONE_ATTRIBUTES 1
215static XF86AttributeRec CloneAttributes[CLONE_ATTRIBUTES] = {
216    {XvSettable | XvGettable, -1, 1, "XV_PIPE"}
217};
218
219#define NUM_ATTRIBUTES 5
220static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
221    {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
222    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
223    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
224    {XvSettable | XvGettable, 0, 1023, "XV_SATURATION"},
225    {XvSettable | XvGettable, 0, 1, "XV_DOUBLE_BUFFER"}
226};
227
228#define NUM_TEXTURED_ATTRIBUTES 3
229static XF86AttributeRec TexturedAttributes[NUM_TEXTURED_ATTRIBUTES] = {
230    {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
231    {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
232    {XvSettable | XvGettable, -1, 1, "XV_SYNC_TO_VBLANK"},
233};
234
235#define GAMMA_ATTRIBUTES 6
236static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = {
237    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"},
238    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"},
239    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
240    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"},
241    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"},
242    {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"}
243};
244
245#define NUM_IMAGES 5
246
247static XF86ImageRec Images[NUM_IMAGES] = {
248    XVIMAGE_YUY2,
249    XVIMAGE_YV12,
250    XVIMAGE_I420,
251    XVIMAGE_UYVY,
252#ifdef INTEL_XVMC
253    {
254        /*
255         * Below, a dummy picture type that is used in XvPutImage only to do
256         * an overlay update. Introduced for the XvMC client lib.
257         * Defined to have a zero data size.
258         */
259        FOURCC_XVMC,
260        XvYUV,
261        LSBFirst,
262        {'X', 'V', 'M', 'C',
263         0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00,
264         0x38, 0x9B, 0x71},
265        12,
266        XvPlanar,
267        3,
268        0, 0, 0, 0,
269        8, 8, 8,
270        1, 2, 2,
271        1, 2, 2,
272        {'Y', 'V', 'U',
273         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274         0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
275        XvTopToBottom
276    },
277#endif
278};
279
280typedef struct {
281    uint32_t OBUF_0Y;
282    uint32_t OBUF_1Y;
283    uint32_t OBUF_0U;
284    uint32_t OBUF_0V;
285    uint32_t OBUF_1U;
286    uint32_t OBUF_1V;
287    uint32_t OSTRIDE;
288    uint32_t YRGB_VPH;
289    uint32_t UV_VPH;
290    uint32_t HORZ_PH;
291    uint32_t INIT_PHS;
292    uint32_t DWINPOS;
293    uint32_t DWINSZ;
294    uint32_t SWIDTH;
295    uint32_t SWIDTHSW;
296    uint32_t SHEIGHT;
297    uint32_t YRGBSCALE;
298    uint32_t UVSCALE;
299    uint32_t OCLRC0;
300    uint32_t OCLRC1;
301    uint32_t DCLRKV;
302    uint32_t DCLRKM;
303    uint32_t SCLRKVH;
304    uint32_t SCLRKVL;
305    uint32_t SCLRKEN;
306    uint32_t OCONFIG;
307    uint32_t OCMD;
308    uint32_t RESERVED1;			/* 0x6C */
309    uint32_t OSTART_0Y; 		/* for i965 */
310    uint32_t OSTART_1Y;		/* for i965 */
311    uint32_t OSTART_0U;
312    uint32_t OSTART_0V;
313    uint32_t OSTART_1U;
314    uint32_t OSTART_1V;
315    uint32_t OTILEOFF_0Y;
316    uint32_t OTILEOFF_1Y;
317    uint32_t OTILEOFF_0U;
318    uint32_t OTILEOFF_0V;
319    uint32_t OTILEOFF_1U;
320    uint32_t OTILEOFF_1V;
321    uint32_t FASTHSCALE;			/* 0xA0 */
322    uint32_t UVSCALEV;			/* 0xA4 */
323
324    uint32_t RESERVEDC[(0x200 - 0xA8) / 4];		   /* 0xA8 - 0x1FC */
325    uint16_t Y_VCOEFS[N_VERT_Y_TAPS * N_PHASES];		   /* 0x200 */
326    uint16_t RESERVEDD[0x100 / 2 - N_VERT_Y_TAPS * N_PHASES];
327    uint16_t Y_HCOEFS[N_HORIZ_Y_TAPS * N_PHASES];		   /* 0x300 */
328    uint16_t RESERVEDE[0x200 / 2 - N_HORIZ_Y_TAPS * N_PHASES];
329    uint16_t UV_VCOEFS[N_VERT_UV_TAPS * N_PHASES];		   /* 0x500 */
330    uint16_t RESERVEDF[0x100 / 2 - N_VERT_UV_TAPS * N_PHASES];
331    uint16_t UV_HCOEFS[N_HORIZ_UV_TAPS * N_PHASES];	   /* 0x600 */
332    uint16_t RESERVEDG[0x100 / 2 - N_HORIZ_UV_TAPS * N_PHASES];
333} I830OverlayRegRec, *I830OverlayRegPtr;
334
335#define I830OVERLAYREG(pI830) ((I830OverlayRegPtr)\
336			       ((pI830)->FbBase + \
337				(pI830)->overlay_regs->offset))
338#if VIDEO_DEBUG
339static void
340CompareOverlay(I830Ptr pI830, uint32_t * overlay, int size)
341{
342    int i;
343    uint32_t val;
344    int bad = 0;
345
346    for (i = 0; i < size; i += 4) {
347	val = INREG(0x30100 + i);
348	if (val != overlay[i / 4]) {
349	    OVERLAY_DEBUG("0x%05x value doesn't match (0x%lx != 0x%lx)\n",
350			  0x30100 + i, val, overlay[i / 4]);
351	    bad++;
352	}
353    }
354    if (!bad)
355	OVERLAY_DEBUG("CompareOverlay: no differences\n");
356}
357#endif
358
359static void
360I830SetOneLineModeRatio(ScrnInfoPtr pScrn);
361
362static void
363i830_overlay_switch_to_crtc (ScrnInfoPtr pScrn, xf86CrtcPtr crtc)
364{
365    I830Ptr		pI830 = I830PTR(pScrn);
366    I830PortPrivPtr	pPriv = GET_PORT_PRIVATE(pScrn);
367    I830CrtcPrivatePtr  intel_crtc = crtc->driver_private;
368    int			pipeconf_reg = intel_crtc->pipe == 0 ? PIPEACONF : PIPEBCONF;
369
370    /* overlay can't be used on pipe with double wide, and pipe must be enabled. */
371    if ((!IS_I965G(pI830) && (INREG(pipeconf_reg) & PIPEACONF_DOUBLE_WIDE))
372	    || (intel_crtc->dpms_mode == DPMSModeOff))
373	pPriv->overlayOK = FALSE;
374    else
375	pPriv->overlayOK = TRUE;
376
377    if (!pPriv->overlayOK)
378	return;
379
380    /* Check we have an LFP connected */
381    if (i830PipeHasType(crtc, I830_OUTPUT_LVDS))
382    {
383
384	int	vtotal_reg = intel_crtc->pipe == 0 ? VTOTAL_A : VTOTAL_B;
385	uint32_t size = intel_crtc->pipe ? INREG(PIPEBSRC) : INREG(PIPEASRC);
386	uint32_t active;
387	uint32_t hsize, vsize;
388
389	hsize = (size >> 16) & 0x7FF;
390	vsize = size & 0x7FF;
391	active = INREG(vtotal_reg) & 0x7FF;
392
393	if (vsize < active && hsize > 1024)
394	    I830SetOneLineModeRatio(pScrn);
395
396	if (pPriv->scaleRatio & 0xFFFE0000)
397	{
398	    /* Possible bogus ratio, using in-accurate fallback */
399	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
400		       "Bogus panel fit register, Xvideo positioning may not "
401		       "be accurate.\n");
402	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
403		       "Using fallback ratio - was 0x%x, now 0x%x\n",
404		       pPriv->scaleRatio,
405		       (int)(((float)active * 65536)/(float)vsize));
406
407	    pPriv->scaleRatio = (int)(((float)active * 65536) / (float)vsize);
408	}
409    }
410}
411
412/*
413 * This is more or less the correct way to initalise, update, and shut down
414 * the overlay.
415 *
416 * XXX Need to make sure that the overlay engine is cleanly shutdown in
417 * all modes of server exit.
418 */
419
420static void
421i830_overlay_on(ScrnInfoPtr pScrn)
422{
423    I830Ptr		pI830 = I830PTR(pScrn);
424    I830OverlayRegPtr	overlay = I830OVERLAYREG(pI830);
425    I830PortPrivPtr	pPriv = pI830->adaptor->pPortPrivates[0].ptr;
426    Bool		deactivate = FALSE;
427
428    if (pI830->overlayOn)
429	return;
430
431    /*
432     * On I830, if pipe A is off when the overlayis enabled, it will fail to
433     * turn on and blank the entire screen or lock up the ring. Light up pipe
434     * A in this case to provide a clock for the overlay hardware
435     */
436    if (pPriv->current_crtc && i830_crtc_pipe (pPriv->current_crtc) != 0)
437	deactivate = i830_pipe_a_require_activate (pScrn);
438
439    overlay->OCMD &= ~OVERLAY_ENABLE;
440    BEGIN_BATCH(6);
441    OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE);
442    OUT_BATCH(MI_NOOP);
443    OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_ON);
444    if (OVERLAY_NOPHYSICAL(pI830))
445	OUT_BATCH(pI830->overlay_regs->offset | OFC_UPDATE);
446    else
447	OUT_BATCH(pI830->overlay_regs->bus_addr | OFC_UPDATE);
448    /* Wait for the overlay to light up before attempting to use it */
449    OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
450    OUT_BATCH(MI_NOOP);
451    ADVANCE_BATCH();
452    I830Sync(pScrn);
453
454    /*
455     * If we turned pipe A on up above, turn it
456     * back off
457     */
458    if (deactivate)
459	i830_pipe_a_require_deactivate (pScrn);
460
461    OVERLAY_DEBUG("overlay_on\n");
462    pI830->overlayOn = TRUE;
463
464    overlay->OCMD |= OVERLAY_ENABLE;
465}
466
467static void
468i830_overlay_continue(ScrnInfoPtr pScrn, Bool update_filter)
469{
470    I830Ptr		pI830 = I830PTR(pScrn);
471    uint32_t		flip_addr;
472    I830OverlayRegPtr	overlay = I830OVERLAYREG(pI830);
473
474    if (!pI830->overlayOn)
475	return;
476
477    if (OVERLAY_NOPHYSICAL(pI830))
478	flip_addr = pI830->overlay_regs->offset;
479    else
480	flip_addr = pI830->overlay_regs->bus_addr;
481    if (update_filter)
482	flip_addr |= OFC_UPDATE;
483    OVERLAY_DEBUG ("overlay_continue cmd 0x%08x  -> 0x%08x sta 0x%08x\n",
484		   overlay->OCMD, INREG(OCMD_REGISTER), INREG(DOVSTA));
485    BEGIN_BATCH(4);
486    OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE);
487    OUT_BATCH(MI_NOOP);
488    OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE);
489    OUT_BATCH(flip_addr);
490    ADVANCE_BATCH();
491    OVERLAY_DEBUG("overlay_continue\n");
492}
493
494static void
495i830_overlay_off(ScrnInfoPtr pScrn)
496{
497    I830Ptr pI830 = I830PTR(pScrn);
498    I830OverlayRegPtr	overlay = I830OVERLAYREG(pI830);
499
500    if (!pI830->overlayOn)
501	return;
502
503    /*
504     * Wait for overlay to go idle. This has to be
505     * separated from the turning off state by a Sync
506     * to ensure the overlay will not read OCMD early and
507     * disable the overlay before the commands here are
508     * executed
509     */
510    {
511	BEGIN_BATCH(2);
512	OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
513	OUT_BATCH(MI_NOOP);
514	ADVANCE_BATCH();
515	I830Sync(pScrn);
516    }
517
518    /*
519     * Turn overlay off
520     */
521    {
522	overlay->OCMD &= ~OVERLAY_ENABLE;
523	OVERLAY_DEBUG ("overlay_off cmd 0x%08x -> 0x%08x sta 0x%08x\n",
524		       overlay->OCMD, INREG(OCMD_REGISTER), INREG(DOVSTA));
525	BEGIN_BATCH(6);
526	OUT_BATCH(MI_FLUSH | MI_WRITE_DIRTY_STATE);
527	OUT_BATCH(MI_NOOP);
528	OUT_BATCH(MI_OVERLAY_FLIP | MI_OVERLAY_FLIP_CONTINUE);
529	if (OVERLAY_NOPHYSICAL(pI830))
530	    OUT_BATCH(pI830->overlay_regs->offset);
531	else
532	    OUT_BATCH(pI830->overlay_regs->bus_addr);
533	OUT_BATCH(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
534	OUT_BATCH(MI_NOOP);
535	ADVANCE_BATCH();
536	I830Sync(pScrn);
537    }
538    pI830->overlayOn = FALSE;
539    OVERLAY_DEBUG("overlay_off\n");
540}
541
542void
543I830InitVideo(ScreenPtr pScreen)
544{
545    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
546    I830Ptr pI830 = I830PTR(pScrn);
547    XF86VideoAdaptorPtr *adaptors, *newAdaptors = NULL;
548    XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL;
549    int num_adaptors;
550#ifdef INTEL_XVMC
551    Bool xvmc_status = FALSE;
552#endif
553
554#if 0
555    {
556	I830OverlayRegRec tmp;
557
558	ErrorF("sizeof I830OverlayRegRec is 0x%x\n", sizeof(I830OverlayRegRec));
559	ErrorF("Reserved C, D, E, F, G are %x, %x, %x, %x, %x\n",
560	       (unsigned long)&(tmp.RESERVEDC[0]) - (unsigned long)&tmp,
561	       (unsigned long)&(tmp.RESERVEDD[0]) - (unsigned long)&tmp,
562	       (unsigned long)&(tmp.RESERVEDE[0]) - (unsigned long)&tmp,
563	       (unsigned long)&(tmp.RESERVEDF[0]) - (unsigned long)&tmp,
564	       (unsigned long)&(tmp.RESERVEDG[0]) - (unsigned long)&tmp);
565    }
566#endif
567
568    num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors);
569    /* Give our adaptor list enough space for the overlay and/or texture video
570     * adaptors.
571     */
572    newAdaptors = xalloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *));
573    if (newAdaptors == NULL)
574	return;
575
576    memcpy(newAdaptors, adaptors, num_adaptors * sizeof(XF86VideoAdaptorPtr));
577    adaptors = newAdaptors;
578
579    /* Add the adaptors supported by our hardware.  First, set up the atoms
580     * that will be used by both output adaptors.
581     */
582    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
583    xvContrast = MAKE_ATOM("XV_CONTRAST");
584
585    /* Set up textured video if we can do it at this depth and we are on
586     * supported hardware.
587     */
588    if (pScrn->bitsPerPixel >= 16 && (IS_I9XX(pI830) || IS_I965G(pI830)) &&
589	!(!IS_I965G(pI830) && pScrn->displayWidth > 2048))
590    {
591	texturedAdaptor = I830SetupImageVideoTextured(pScreen);
592	if (texturedAdaptor != NULL) {
593	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up textured video\n");
594	} else {
595	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
596		       "Failed to set up textured video\n");
597	}
598    }
599
600    /* Set up overlay video if we can do it at this depth. */
601    if (!OVERLAY_NOEXIST(pI830) && pScrn->bitsPerPixel != 8 &&
602	!pI830->use_drm_mode && pI830->overlay_regs != NULL)
603    {
604	overlayAdaptor = I830SetupImageVideoOverlay(pScreen);
605	if (overlayAdaptor != NULL) {
606	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Set up overlay video\n");
607	} else {
608	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
609		       "Failed to set up overlay video\n");
610	}
611	I830InitOffscreenImages(pScreen);
612    }
613
614    if (overlayAdaptor && pI830->XvPreferOverlay)
615       adaptors[num_adaptors++] = overlayAdaptor;
616
617    if (texturedAdaptor)
618       adaptors[num_adaptors++] = texturedAdaptor;
619
620    if (overlayAdaptor && !pI830->XvPreferOverlay)
621       adaptors[num_adaptors++] = overlayAdaptor;
622
623#ifdef INTEL_XVMC
624    if (intel_xvmc_probe(pScrn)) {
625	if (texturedAdaptor)
626	    xvmc_status = intel_xvmc_driver_init(pScreen, texturedAdaptor);
627    }
628#endif
629
630    if (num_adaptors) {
631	xf86XVScreenInit(pScreen, adaptors, num_adaptors);
632    } else {
633	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
634		   "Disabling Xv because no adaptors could be initialized.\n");
635	pI830->XvEnabled = FALSE;
636    }
637
638#ifdef INTEL_XVMC
639    if (xvmc_status)
640	intel_xvmc_screen_init(pScreen);
641#endif
642    xfree(adaptors);
643}
644
645static void
646I830ResetVideo(ScrnInfoPtr pScrn)
647{
648    I830Ptr pI830 = I830PTR(pScrn);
649    I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
650    I830OverlayRegPtr	overlay = I830OVERLAYREG(pI830);
651
652    OVERLAY_DEBUG("I830ResetVideo: base: %p, offset: 0x%lx, obase: %p\n",
653		  pI830->FbBase, pI830->overlay_regs->offset, overlay);
654    /*
655     * Default to maximum image size in YV12
656     */
657
658    memset(overlay, 0, sizeof(*overlay));
659    overlay->YRGB_VPH = 0;
660    overlay->UV_VPH = 0;
661    overlay->HORZ_PH = 0;
662    overlay->INIT_PHS = 0;
663    overlay->DWINPOS = 0;
664    overlay->DWINSZ = 0;
665    overlay->SWIDTH = 0;
666    overlay->SWIDTHSW = 0;
667    overlay->SHEIGHT = 0;
668    overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
669    overlay->OCLRC1 = pPriv->saturation;
670#if 0
671    overlay->AWINPOS = 0;
672    overlay->AWINSZ = 0;
673#endif
674    overlay->FASTHSCALE = 0;
675
676    /*
677     * Enable destination color keying
678     */
679    switch (pScrn->depth) {
680    case 8:
681	overlay->DCLRKV = 0;
682	overlay->DCLRKM = 0xffffff | DEST_KEY_ENABLE;
683	break;
684    case 15:
685	overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
686	overlay->DCLRKM = 0x070707 | DEST_KEY_ENABLE;
687	break;
688    case 16:
689	overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
690	overlay->DCLRKM = 0x070307 | DEST_KEY_ENABLE;
691	break;
692    default:
693	overlay->DCLRKV = pPriv->colorKey;
694	overlay->DCLRKM = DEST_KEY_ENABLE;
695	break;
696    }
697
698    overlay->SCLRKVH = 0;
699    overlay->SCLRKVL = 0;
700    overlay->SCLRKEN = 0;		/* source color key disable */
701    overlay->OCONFIG = CC_OUT_8BIT;
702    if (IS_I965GM(pI830))
703	overlay->OCONFIG |= CSC_MODE_BT709;
704
705    /*
706     * Select which pipe the overlay is enabled on.
707     */
708    overlay->OCONFIG &= ~OVERLAY_PIPE_MASK;
709    if (i830_crtc_pipe (pPriv->current_crtc) == 0)
710	overlay->OCONFIG |= OVERLAY_PIPE_A;
711    else
712	overlay->OCONFIG |= OVERLAY_PIPE_B;
713
714#if 0
715    /*
716     * XXX DUMP REGISTER CODE !!!
717     * This allows us to dump the complete i845 registers and compare
718     * with warm boot situations before we upload our first copy.
719     */
720    {
721	int i;
722	for (i = 0x30000; i < 0x31000; i += 4)
723	    ErrorF("0x%x 0x%" PRIx32 "\n", i, INREG(i));
724    }
725#endif
726}
727
728#define PFIT_CONTROLS 0x61230
729#define PFIT_AUTOVSCALE_MASK 0x200
730#define PFIT_ON_MASK 0x80000000
731#define PFIT_AUTOSCALE_RATIO 0x61238
732#define PFIT_PROGRAMMED_SCALE_RATIO 0x61234
733
734static void
735I830SetOneLineModeRatio(ScrnInfoPtr pScrn)
736{
737    I830Ptr pI830 = I830PTR(pScrn);
738    I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
739    uint32_t panelFitControl = INREG(PFIT_CONTROLS);
740    int vertScale;
741
742    pPriv->scaleRatio = 0x10000;
743
744    if (panelFitControl & PFIT_ON_MASK) {
745	if (panelFitControl & PFIT_AUTOVSCALE_MASK) {
746	    vertScale = INREG(PFIT_AUTOSCALE_RATIO) >> 16;
747	} else {
748	    vertScale = INREG(PFIT_PROGRAMMED_SCALE_RATIO) >> 16;
749	}
750
751	if (vertScale != 0)
752	    pPriv->scaleRatio = ((double) 0x10000 / (double)vertScale) * 0x10000;
753
754	pPriv->oneLineMode = TRUE;
755
756	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabling Xvideo one-line mode\n");
757    }
758
759    if (pPriv->scaleRatio == 0x10000)
760	pPriv->oneLineMode = FALSE;
761}
762
763static uint32_t I830BoundGammaElt (uint32_t elt, uint32_t eltPrev)
764{
765    elt &= 0xff;
766    eltPrev &= 0xff;
767    if (elt < eltPrev)
768	elt = eltPrev;
769    else if ((elt - eltPrev) > 0x7e)
770	elt = eltPrev + 0x7e;
771    return elt;
772}
773
774static uint32_t I830BoundGamma (uint32_t gamma, uint32_t gammaPrev)
775{
776    return (I830BoundGammaElt (gamma >> 16, gammaPrev >> 16) << 16 |
777	    I830BoundGammaElt (gamma >>  8, gammaPrev >>  8) <<  8 |
778	    I830BoundGammaElt (gamma      , gammaPrev      ));
779}
780
781static uint32_t I830Gamma5Errata(uint32_t gamma)
782{
783    int i;
784
785    for (i = 0; i < 3; i++) {
786	if ((gamma >> i*8 & 0xff) == 0x80) {
787	    /* According to Intel docs, overlay fails if GAMMA5 is 0x80.
788	     * In this case, change the value to 0x81 */
789	    gamma += 1 << i*8;
790	}
791    }
792
793    return gamma;
794}
795
796static void
797I830UpdateGamma(ScrnInfoPtr pScrn)
798{
799    I830Ptr pI830 = I830PTR(pScrn);
800    I830PortPrivPtr pPriv = pI830->adaptor->pPortPrivates[0].ptr;
801    uint32_t gamma0 = pPriv->gamma0;
802    uint32_t gamma1 = pPriv->gamma1;
803    uint32_t gamma2 = pPriv->gamma2;
804    uint32_t gamma3 = pPriv->gamma3;
805    uint32_t gamma4 = pPriv->gamma4;
806    uint32_t gamma5 = pPriv->gamma5;
807
808#if 0
809    ErrorF ("Original gamma: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
810	    gamma0, gamma1, gamma2, gamma3, gamma4, gamma5);
811#endif
812    gamma1 = I830BoundGamma (gamma1, gamma0);
813    gamma2 = I830BoundGamma (gamma2, gamma1);
814    gamma3 = I830BoundGamma (gamma3, gamma2);
815    gamma4 = I830BoundGamma (gamma4, gamma3);
816    gamma5 = I830BoundGamma (gamma5, gamma4);
817    gamma5 = I830Gamma5Errata(gamma5);
818#if 0
819    ErrorF ("Bounded  gamma: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
820	    gamma0, gamma1, gamma2, gamma3, gamma4, gamma5);
821#endif
822
823    OUTREG(OGAMC5, gamma5);
824    OUTREG(OGAMC4, gamma4);
825    OUTREG(OGAMC3, gamma3);
826    OUTREG(OGAMC2, gamma2);
827    OUTREG(OGAMC1, gamma1);
828    OUTREG(OGAMC0, gamma0);
829}
830
831static XF86VideoAdaptorPtr
832I830SetupImageVideoOverlay(ScreenPtr pScreen)
833{
834    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
835    I830Ptr pI830 = I830PTR(pScrn);
836    XF86VideoAdaptorPtr adapt;
837    I830PortPrivPtr pPriv;
838    XF86AttributePtr att;
839
840    OVERLAY_DEBUG("I830SetupImageVideoOverlay\n");
841
842    if (!(adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec) +
843			  sizeof(I830PortPrivRec) + sizeof(DevUnion))))
844	return NULL;
845
846    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
847    adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/;
848    adapt->name = "Intel(R) Video Overlay";
849    adapt->nEncodings = 1;
850    adapt->pEncodings = DummyEncoding;
851    /* update the DummyEncoding for these two chipsets */
852    if (IS_845G(pI830) || IS_I830(pI830)) {
853	adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY;
854	adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY;
855    }
856    adapt->nFormats = NUM_FORMATS;
857    adapt->pFormats = Formats;
858    adapt->nPorts = 1;
859    adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
860
861    pPriv = (I830PortPrivPtr) (&adapt->pPortPrivates[1]);
862
863    adapt->pPortPrivates[0].ptr = (pointer) (pPriv);
864    adapt->nAttributes = NUM_ATTRIBUTES;
865    adapt->nAttributes += CLONE_ATTRIBUTES;
866    if (IS_I9XX(pI830))
867	adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */
868    adapt->pAttributes = xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes);
869    /* Now copy the attributes */
870    att = adapt->pAttributes;
871    memcpy((char *)att, (char*)Attributes, sizeof(XF86AttributeRec)* NUM_ATTRIBUTES);
872    att+=NUM_ATTRIBUTES;
873    memcpy((char*)att, (char*)CloneAttributes, sizeof(XF86AttributeRec) * CLONE_ATTRIBUTES);
874    att+=CLONE_ATTRIBUTES;
875    if (IS_I9XX(pI830)) {
876	memcpy((char*)att, (char*)GammaAttributes, sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES);
877	att+=GAMMA_ATTRIBUTES;
878    }
879    adapt->nImages = NUM_IMAGES;
880    adapt->pImages = Images;
881    adapt->PutVideo = NULL;
882    adapt->PutStill = NULL;
883    adapt->GetVideo = NULL;
884    adapt->GetStill = NULL;
885    adapt->StopVideo = I830StopVideo;
886    adapt->SetPortAttribute = I830SetPortAttributeOverlay;
887    adapt->GetPortAttribute = I830GetPortAttribute;
888    adapt->QueryBestSize = I830QueryBestSize;
889    adapt->PutImage = I830PutImage;
890    adapt->QueryImageAttributes = I830QueryImageAttributes;
891
892    pPriv->textured = FALSE;
893    pPriv->colorKey = pI830->colorKey & ((1 << pScrn->depth) - 1);
894    pPriv->videoStatus = 0;
895    pPriv->brightness = -19; /* (255/219) * -16 */
896    pPriv->contrast = 75;  /* 255/219 * 64 */
897    pPriv->saturation = 146; /* 128/112 * 128 */
898    pPriv->current_crtc = NULL;
899    pPriv->desired_crtc = NULL;
900    pPriv->buf = NULL;
901    pPriv->currentBuf = 0;
902    pPriv->gamma5 = 0xc0c0c0;
903    pPriv->gamma4 = 0x808080;
904    pPriv->gamma3 = 0x404040;
905    pPriv->gamma2 = 0x202020;
906    pPriv->gamma1 = 0x101010;
907    pPriv->gamma0 = 0x080808;
908    pPriv->doubleBuffer = 1;
909
910    pPriv->rotation = RR_Rotate_0;
911
912    /* gotta uninit this someplace */
913    REGION_NULL(pScreen, &pPriv->clip);
914
915    pI830->adaptor = adapt;
916
917    /* With LFP's we need to detect whether we're in One Line Mode, which
918     * essentially means a resolution greater than 1024x768, and fix up
919     * the scaler accordingly. */
920    pPriv->scaleRatio = 0x10000;
921    pPriv->oneLineMode = FALSE;
922
923    /*
924     * Initialise pPriv->overlayOK.  Set it to TRUE here so that a warning will
925     * be generated if i830_crtc_dpms_video() sets it to FALSE during mode
926     * setup.
927     */
928    pPriv->overlayOK = TRUE;
929
930    xvColorKey = MAKE_ATOM("XV_COLORKEY");
931    xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
932    xvContrast = MAKE_ATOM("XV_CONTRAST");
933    xvSaturation = MAKE_ATOM("XV_SATURATION");
934    xvDoubleBuffer = MAKE_ATOM("XV_DOUBLE_BUFFER");
935
936    /* Allow the pipe to be switched from pipe A to B when in clone mode */
937    xvPipe = MAKE_ATOM("XV_PIPE");
938
939    if (IS_I9XX(pI830)) {
940	xvGamma0 = MAKE_ATOM("XV_GAMMA0");
941	xvGamma1 = MAKE_ATOM("XV_GAMMA1");
942	xvGamma2 = MAKE_ATOM("XV_GAMMA2");
943	xvGamma3 = MAKE_ATOM("XV_GAMMA3");
944	xvGamma4 = MAKE_ATOM("XV_GAMMA4");
945	xvGamma5 = MAKE_ATOM("XV_GAMMA5");
946    }
947
948    I830ResetVideo(pScrn);
949
950    I830UpdateGamma(pScrn);
951
952    return adapt;
953}
954
955static XF86VideoAdaptorPtr
956I830SetupImageVideoTextured(ScreenPtr pScreen)
957{
958    XF86VideoAdaptorPtr adapt;
959    XF86AttributePtr attrs;
960    I830PortPrivPtr portPrivs;
961    DevUnion *devUnions;
962    int nports = 16, i;
963    int nAttributes;
964
965    OVERLAY_DEBUG("I830SetupImageVideoOverlay\n");
966
967    nAttributes = NUM_TEXTURED_ATTRIBUTES;
968
969    adapt = xcalloc(1, sizeof(XF86VideoAdaptorRec));
970    portPrivs = xcalloc(nports, sizeof(I830PortPrivRec));
971    devUnions = xcalloc(nports, sizeof(DevUnion));
972    attrs = xcalloc(nAttributes, sizeof(XF86AttributeRec));
973    if (adapt == NULL || portPrivs == NULL || devUnions == NULL ||
974	attrs == NULL)
975    {
976	xfree(adapt);
977	xfree(portPrivs);
978	xfree(devUnions);
979	xfree(attrs);
980	return NULL;
981    }
982
983    adapt->type = XvWindowMask | XvInputMask | XvImageMask;
984    adapt->flags = 0;
985    adapt->name = "Intel(R) Textured Video";
986    adapt->nEncodings = 1;
987    adapt->pEncodings = DummyEncoding;
988    adapt->nFormats = NUM_FORMATS;
989    adapt->pFormats = Formats;
990    adapt->nPorts = nports;
991    adapt->pPortPrivates = devUnions;
992    adapt->nAttributes = nAttributes;
993    adapt->pAttributes = attrs;
994    memcpy(attrs, TexturedAttributes, nAttributes * sizeof(XF86AttributeRec));
995    adapt->nImages = NUM_IMAGES;
996    adapt->pImages = Images;
997    adapt->PutVideo = NULL;
998    adapt->PutStill = NULL;
999    adapt->GetVideo = NULL;
1000    adapt->GetStill = NULL;
1001    adapt->StopVideo = I830StopVideo;
1002    adapt->SetPortAttribute = I830SetPortAttributeTextured;
1003    adapt->GetPortAttribute = I830GetPortAttribute;
1004    adapt->QueryBestSize = I830QueryBestSize;
1005    adapt->PutImage = I830PutImage;
1006    adapt->QueryImageAttributes = I830QueryImageAttributes;
1007
1008    for (i = 0; i < nports; i++) {
1009	I830PortPrivPtr pPriv = &portPrivs[i];
1010
1011	pPriv->textured = TRUE;
1012	pPriv->videoStatus = 0;
1013	pPriv->buf = NULL;
1014	pPriv->currentBuf = 0;
1015	pPriv->doubleBuffer = 0;
1016
1017	pPriv->rotation = RR_Rotate_0;
1018	pPriv->SyncToVblank = 1;
1019
1020	/* gotta uninit this someplace, XXX: shouldn't be necessary for textured */
1021	REGION_NULL(pScreen, &pPriv->clip);
1022
1023	adapt->pPortPrivates[i].ptr = (pointer) (pPriv);
1024    }
1025
1026    xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK");
1027
1028    return adapt;
1029}
1030
1031static void
1032I830StopVideo(ScrnInfoPtr pScrn, pointer data, Bool shutdown)
1033{
1034    I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
1035
1036    if (pPriv->textured)
1037	return;
1038
1039    OVERLAY_DEBUG("I830StopVideo\n");
1040
1041    REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1042
1043    if (shutdown) {
1044	if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
1045	    i830_overlay_off(pScrn);
1046	}
1047
1048	if (pPriv->buf) {
1049	    drm_intel_bo_unpin(pPriv->buf);
1050	    drm_intel_bo_unreference(pPriv->buf);
1051	    pPriv->buf = NULL;
1052	    pPriv->videoStatus = 0;
1053	}
1054    } else {
1055	if (pPriv->videoStatus & CLIENT_VIDEO_ON) {
1056	    pPriv->videoStatus |= OFF_TIMER;
1057	    pPriv->offTime = currentTime.milliseconds + OFF_DELAY;
1058	}
1059    }
1060
1061}
1062
1063static int
1064I830SetPortAttributeTextured(ScrnInfoPtr pScrn,
1065			     Atom attribute, INT32 value, pointer data)
1066{
1067    I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
1068
1069    if (attribute == xvBrightness) {
1070	if ((value < -128) || (value > 127))
1071	    return BadValue;
1072	pPriv->brightness = value;
1073	return Success;
1074    } else if (attribute == xvContrast) {
1075	if ((value < 0) || (value > 255))
1076	    return BadValue;
1077	pPriv->contrast = value;
1078	return Success;
1079    } else if (attribute == xvSyncToVblank) {
1080        if ((value < -1) || (value > 1))
1081            return BadValue;
1082
1083        pPriv->SyncToVblank = value;
1084        return Success;
1085    } else {
1086	return BadMatch;
1087    }
1088}
1089
1090static int
1091I830SetPortAttributeOverlay(ScrnInfoPtr pScrn,
1092		     Atom attribute, INT32 value, pointer data)
1093{
1094    I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
1095    I830Ptr pI830 = I830PTR(pScrn);
1096    I830OverlayRegPtr overlay;
1097
1098    overlay = I830OVERLAYREG(pI830);
1099
1100    if (attribute == xvBrightness) {
1101	if ((value < -128) || (value > 127))
1102	    return BadValue;
1103	pPriv->brightness = value;
1104	overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
1105	OVERLAY_DEBUG("BRIGHTNESS\n");
1106	i830_overlay_continue (pScrn, FALSE);
1107    } else if (attribute == xvContrast) {
1108	if ((value < 0) || (value > 255))
1109	    return BadValue;
1110	pPriv->contrast = value;
1111	overlay->OCLRC0 = (pPriv->contrast << 18) | (pPriv->brightness & 0xff);
1112	OVERLAY_DEBUG("CONTRAST\n");
1113	i830_overlay_continue (pScrn, FALSE);
1114    } else if (attribute == xvSaturation) {
1115	if ((value < 0) || (value > 1023))
1116	    return BadValue;
1117	pPriv->saturation = value;
1118	overlay->OCLRC1 = pPriv->saturation;
1119	i830_overlay_continue (pScrn, FALSE);
1120    } else if (attribute == xvPipe) {
1121	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1122	if ((value < -1) || (value > xf86_config->num_crtc))
1123	    return BadValue;
1124	if (value < 0)
1125	    pPriv->desired_crtc = NULL;
1126	else
1127	    pPriv->desired_crtc = xf86_config->crtc[value];
1128	/*
1129	 * Leave this to be updated at the next frame
1130	 */
1131    } else if (attribute == xvGamma0 && (IS_I9XX(pI830))) {
1132	pPriv->gamma0 = value;
1133    } else if (attribute == xvGamma1 && (IS_I9XX(pI830))) {
1134	pPriv->gamma1 = value;
1135    } else if (attribute == xvGamma2 && (IS_I9XX(pI830))) {
1136	pPriv->gamma2 = value;
1137    } else if (attribute == xvGamma3 && (IS_I9XX(pI830))) {
1138	pPriv->gamma3 = value;
1139    } else if (attribute == xvGamma4 && (IS_I9XX(pI830))) {
1140	pPriv->gamma4 = value;
1141    } else if (attribute == xvGamma5 && (IS_I9XX(pI830))) {
1142	pPriv->gamma5 = value;
1143    } else if (attribute == xvColorKey) {
1144	pPriv->colorKey = value;
1145	switch (pScrn->depth) {
1146	case 16:
1147	    overlay->DCLRKV = RGB16ToColorKey(pPriv->colorKey);
1148	    break;
1149	case 15:
1150	    overlay->DCLRKV = RGB15ToColorKey(pPriv->colorKey);
1151	    break;
1152	default:
1153	    overlay->DCLRKV = pPriv->colorKey;
1154	    break;
1155	}
1156	OVERLAY_DEBUG("COLORKEY\n");
1157	i830_overlay_continue (pScrn, FALSE);
1158	REGION_EMPTY(pScrn->pScreen, &pPriv->clip);
1159    } else if(attribute == xvDoubleBuffer) {
1160	if ((value < 0) || (value > 1))
1161	    return BadValue;
1162	/* Do not allow buffer change while playing video */
1163	if(!pI830->overlayOn)
1164	    pPriv->doubleBuffer = value;
1165    } else
1166	return BadMatch;
1167
1168    /* Ensure that the overlay is off, ready for updating */
1169    if ((attribute == xvGamma0 ||
1170	 attribute == xvGamma1 ||
1171	 attribute == xvGamma2 ||
1172	 attribute == xvGamma3 ||
1173	 attribute == xvGamma4 ||
1174	 attribute == xvGamma5) && (IS_I9XX(pI830))) {
1175	OVERLAY_DEBUG("GAMMA\n");
1176	I830UpdateGamma(pScrn);
1177    }
1178
1179    return Success;
1180}
1181
1182static int
1183I830GetPortAttribute(ScrnInfoPtr pScrn,
1184		     Atom attribute, INT32 * value, pointer data)
1185{
1186    I830Ptr pI830 = I830PTR(pScrn);
1187    I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
1188
1189    if (attribute == xvBrightness) {
1190	*value = pPriv->brightness;
1191    } else if (attribute == xvContrast) {
1192	*value = pPriv->contrast;
1193    } else if (attribute == xvSaturation) {
1194	*value = pPriv->saturation;
1195    } else if (attribute == xvPipe) {
1196	int		c;
1197	xf86CrtcConfigPtr	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1198	for (c = 0; c < xf86_config->num_crtc; c++)
1199	    if (xf86_config->crtc[c] == pPriv->desired_crtc)
1200		break;
1201	if (c == xf86_config->num_crtc)
1202	    c = -1;
1203	*value = c;
1204    } else if (attribute == xvGamma0 && (IS_I9XX(pI830))) {
1205	*value = pPriv->gamma0;
1206    } else if (attribute == xvGamma1 && (IS_I9XX(pI830))) {
1207	*value = pPriv->gamma1;
1208    } else if (attribute == xvGamma2 && (IS_I9XX(pI830))) {
1209	*value = pPriv->gamma2;
1210    } else if (attribute == xvGamma3 && (IS_I9XX(pI830))) {
1211	*value = pPriv->gamma3;
1212    } else if (attribute == xvGamma4 && (IS_I9XX(pI830))) {
1213	*value = pPriv->gamma4;
1214    } else if (attribute == xvGamma5 && (IS_I9XX(pI830))) {
1215	*value = pPriv->gamma5;
1216    } else if (attribute == xvColorKey) {
1217	*value = pPriv->colorKey;
1218    } else if (attribute == xvDoubleBuffer) {
1219	*value = pPriv->doubleBuffer;
1220    } else if (attribute == xvSyncToVblank) {
1221        *value = pPriv->SyncToVblank;
1222    } else
1223	return BadMatch;
1224
1225    return Success;
1226}
1227
1228static void
1229I830QueryBestSize(ScrnInfoPtr pScrn,
1230		  Bool motion,
1231		  short vid_w, short vid_h,
1232		  short drw_w, short drw_h,
1233		  unsigned int *p_w, unsigned int *p_h, pointer data)
1234{
1235    if (vid_w > (drw_w << 1))
1236	drw_w = vid_w >> 1;
1237    if (vid_h > (drw_h << 1))
1238	drw_h = vid_h >> 1;
1239
1240    *p_w = drw_w;
1241    *p_h = drw_h;
1242}
1243
1244static void
1245I830CopyPackedData(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv,
1246		   unsigned char *buf,
1247		   int srcPitch,
1248		   int dstPitch, int top, int left, int h, int w)
1249{
1250    I830Ptr pI830 = I830PTR(pScrn);
1251    unsigned char *src, *dst, *dst_base;
1252    int i,j;
1253    unsigned char *s;
1254
1255#if 0
1256    ErrorF("I830CopyPackedData: (%d,%d) (%d,%d)\n"
1257	   "srcPitch: %d, dstPitch: %d\n", top, left, h, w,
1258	   srcPitch, dstPitch);
1259#endif
1260
1261    src = buf + (top * srcPitch) + (left << 1);
1262
1263    if (pPriv->textured) {
1264	drm_intel_bo_map(pPriv->buf, TRUE);
1265	dst_base = pPriv->buf->virtual;
1266    } else {
1267	drm_intel_gem_bo_start_gtt_access(pPriv->buf, TRUE);
1268	dst_base = pI830->FbBase;
1269    }
1270
1271    if (pPriv->currentBuf == 0)
1272	dst = dst_base + pPriv->YBuf0offset;
1273    else
1274	dst = dst_base + pPriv->YBuf1offset;
1275
1276    switch (pPriv->rotation) {
1277    case RR_Rotate_0:
1278	w <<= 1;
1279	for (i = 0; i < h; i++) {
1280	    memcpy(dst, src, w);
1281	    src += srcPitch;
1282	    dst += dstPitch;
1283	}
1284	break;
1285    case RR_Rotate_90:
1286	h <<= 1;
1287	for (i = 0; i < h; i+=2) {
1288	    s = src;
1289	    for (j = 0; j < w; j++) {
1290		/* Copy Y */
1291		dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++;
1292		(void)*s++;
1293	    }
1294	    src += srcPitch;
1295	}
1296	h >>= 1;
1297	src = buf + (top * srcPitch) + (left << 1);
1298	for (i = 0; i < h; i+=2) {
1299	    for (j = 0; j < w; j+=2) {
1300		/* Copy U */
1301		dst[((i*2) + 1) + ((w - j - 1) * dstPitch)] = src[(j*2) + 1 + (i * srcPitch)];
1302		dst[((i*2) + 1) + ((w - j - 2) * dstPitch)] = src[(j*2) + 1 + ((i+1) * srcPitch)];
1303		/* Copy V */
1304		dst[((i*2) + 3) + ((w - j - 1) * dstPitch)] = src[(j*2) + 3 + (i * srcPitch)];
1305		dst[((i*2) + 3) + ((w - j - 2) * dstPitch)] = src[(j*2) + 3 + ((i+1) * srcPitch)];
1306	    }
1307	}
1308	break;
1309    case RR_Rotate_180:
1310	w <<= 1;
1311	for (i = 0; i < h; i++) {
1312	    s = src;
1313	    for (j = 0; j < w; j+=4) {
1314		dst[(w - j - 4) + ((h - i - 1) * dstPitch)] = *s++;
1315		dst[(w - j - 3) + ((h - i - 1) * dstPitch)] = *s++;
1316		dst[(w - j - 2) + ((h - i - 1) * dstPitch)] = *s++;
1317		dst[(w - j - 1) + ((h - i - 1) * dstPitch)] = *s++;
1318	    }
1319	    src += srcPitch;
1320	}
1321	break;
1322    case RR_Rotate_270:
1323	h <<= 1;
1324	for (i = 0; i < h; i+=2) {
1325	    s = src;
1326	    for (j = 0; j < w; j++) {
1327		/* Copy Y */
1328		dst[(h - i - 2) + (j * dstPitch)] = *s++;
1329		(void)*s++;
1330	    }
1331	    src += srcPitch;
1332	}
1333	h >>= 1;
1334	src = buf + (top * srcPitch) + (left << 1);
1335	for (i = 0; i < h; i+=2) {
1336	    for (j = 0; j < w; j+=2) {
1337		/* Copy U */
1338		dst[(((h - i)*2) - 3) + (j * dstPitch)] = src[(j*2) + 1 + (i * srcPitch)];
1339		dst[(((h - i)*2) - 3) + ((j - 1) * dstPitch)] = src[(j*2) + 1 + ((i+1) * srcPitch)];
1340		/* Copy V */
1341		dst[(((h - i)*2) - 1) + (j * dstPitch)] = src[(j*2) + 3 + (i * srcPitch)];
1342		dst[(((h - i)*2) - 1) + ((j - 1) * dstPitch)] = src[(j*2) + 3 + ((i+1) * srcPitch)];
1343	    }
1344	}
1345	break;
1346    }
1347
1348    if (pPriv->textured)
1349	drm_intel_bo_unmap(pPriv->buf);
1350}
1351
1352static void
1353I830CopyPlanarData(ScrnInfoPtr pScrn, I830PortPrivPtr pPriv,
1354		   unsigned char *buf, int srcPitch,
1355		   int srcPitch2, int dstPitch, int srcH, int top, int left,
1356		   int h, int w, int id)
1357{
1358    I830Ptr pI830 = I830PTR(pScrn);
1359    int i, j = 0;
1360    unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3;
1361    unsigned char *s;
1362    int dstPitch2 = dstPitch << 1;
1363
1364#if 0
1365    ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n"
1366	   "nlines %d, npixels %d, top %d, left %d\n",
1367	   srcPitch, srcPitch2, dstPitch,
1368	   h, w, top, left);
1369#endif
1370
1371    /* Copy Y data */
1372    src1 = buf + (top * srcPitch) + left;
1373#if 0
1374    ErrorF("src1 is %p, offset is %ld\n", src1,
1375	   (unsigned long)src1 - (unsigned long)buf);
1376#endif
1377
1378    if (pPriv->textured) {
1379	drm_intel_bo_map(pPriv->buf, TRUE);
1380	dst_base = pPriv->buf->virtual;
1381    } else {
1382	drm_intel_gem_bo_start_gtt_access(pPriv->buf, TRUE);
1383	dst_base = pI830->FbBase;
1384    }
1385
1386    if (pPriv->currentBuf == 0)
1387	dst1 = dst_base + pPriv->YBuf0offset;
1388    else
1389	dst1 = dst_base + pPriv->YBuf1offset;
1390
1391    switch (pPriv->rotation) {
1392    case RR_Rotate_0:
1393       /* optimise for the case of no clipping */
1394	if (srcPitch == dstPitch2 && srcPitch == w)
1395	    memcpy (dst1, src1, srcPitch * h);
1396	else
1397	    for (i = 0; i < h; i++) {
1398		memcpy(dst1, src1, w);
1399		src1 += srcPitch;
1400		dst1 += dstPitch2;
1401	    }
1402	break;
1403    case RR_Rotate_90:
1404	for (i = 0; i < h; i++) {
1405	    s = src1;
1406	    for (j = 0; j < w; j++) {
1407		dst1[(i) + ((w - j - 1) * dstPitch2)] = *s++;
1408	    }
1409	    src1 += srcPitch;
1410	}
1411	break;
1412    case RR_Rotate_180:
1413	for (i = 0; i < h; i++) {
1414	    s = src1;
1415	    for (j = 0; j < w; j++) {
1416		dst1[(w - j - 1) + ((h - i - 1) * dstPitch2)] = *s++;
1417	    }
1418	    src1 += srcPitch;
1419	}
1420	break;
1421    case RR_Rotate_270:
1422	for (i = 0; i < h; i++) {
1423	    s = src1;
1424	    for (j = 0; j < w; j++) {
1425		dst1[(h - i - 1) + (j * dstPitch2)] = *s++;
1426	    }
1427	    src1 += srcPitch;
1428	}
1429	break;
1430    }
1431
1432    /* Copy V data for YV12, or U data for I420 */
1433    src2 = buf +                            /* start of YUV data */
1434                (srcH * srcPitch) +         /* move over Luma plane */
1435                ((top * srcPitch) >> 2) +   /* move down from by top lines */
1436                    (left >> 1);            /* move left by left pixels */
1437
1438#if 0
1439    ErrorF("src2 is %p, offset is %ld\n", src2,
1440	   (unsigned long)src2 - (unsigned long)buf);
1441#endif
1442    if (pPriv->currentBuf == 0) {
1443	if (id == FOURCC_I420)
1444	    dst2 = dst_base + pPriv->UBuf0offset;
1445	else
1446	    dst2 = dst_base + pPriv->VBuf0offset;
1447    } else {
1448	if (id == FOURCC_I420)
1449	    dst2 = dst_base + pPriv->UBuf1offset;
1450	else
1451	    dst2 = dst_base + pPriv->VBuf1offset;
1452    }
1453
1454    switch (pPriv->rotation) {
1455    case RR_Rotate_0:
1456       /* optimise for the case of no clipping */
1457	if (srcPitch2 == dstPitch && srcPitch2 == (w/2))
1458	    memcpy (dst2, src2, h/2 * srcPitch2);
1459	else
1460	    for (i = 0; i < h / 2; i++) {
1461		memcpy(dst2, src2, w / 2);
1462		src2 += srcPitch2;
1463		dst2 += dstPitch;
1464	    }
1465	break;
1466    case RR_Rotate_90:
1467	for (i = 0; i < (h/2); i++) {
1468	    s = src2;
1469	    for (j = 0; j < (w/2); j++) {
1470		dst2[(i) + (((w/2) - j - 1) * (dstPitch))] = *s++;
1471	    }
1472	    src2 += srcPitch2;
1473	}
1474	break;
1475    case RR_Rotate_180:
1476	for (i = 0; i < (h/2); i++) {
1477	    s = src2;
1478	    for (j = 0; j < (w/2); j++) {
1479		dst2[((w/2) - j - 1) + (((h/2) - i - 1) * dstPitch)] = *s++;
1480	    }
1481	    src2 += srcPitch2;
1482	}
1483	break;
1484    case RR_Rotate_270:
1485	for (i = 0; i < (h/2); i++) {
1486	    s = src2;
1487	    for (j = 0; j < (w/2); j++) {
1488		dst2[((h/2) - i - 1) + (j * dstPitch)] = *s++;
1489	    }
1490	    src2 += srcPitch2;
1491	}
1492	break;
1493    }
1494
1495    /* Copy U data for YV12, or V data for I420 */
1496    src3 = buf +                            /* start of YUV data */
1497                (srcH * srcPitch) +         /* move over Luma plane */
1498                ((srcH >> 1) * srcPitch2) + /* move over Chroma plane */
1499                ((top * srcPitch) >> 2) +   /* move down from by top lines */
1500                    (left >> 1);            /* move left by left pixels */
1501#if 0
1502    ErrorF("src3 is %p, offset is %ld\n", src3,
1503	   (unsigned long)src3 - (unsigned long)buf);
1504#endif
1505    if (pPriv->currentBuf == 0) {
1506	if (id == FOURCC_I420)
1507	    dst3 = dst_base + pPriv->VBuf0offset;
1508	else
1509	    dst3 = dst_base + pPriv->UBuf0offset;
1510    } else {
1511	if (id == FOURCC_I420)
1512	    dst3 = dst_base + pPriv->VBuf1offset;
1513	else
1514	    dst3 = dst_base + pPriv->UBuf1offset;
1515    }
1516
1517    switch (pPriv->rotation) {
1518    case RR_Rotate_0:
1519       /* optimise for the case of no clipping */
1520	if (srcPitch2 == dstPitch && srcPitch2 == (w/2))
1521	    memcpy (dst3, src3, srcPitch2 * h/2);
1522	else
1523	    for (i = 0; i < h / 2; i++) {
1524		memcpy(dst3, src3, w / 2);
1525		src3 += srcPitch2;
1526		dst3 += dstPitch;
1527	    }
1528	break;
1529    case RR_Rotate_90:
1530	for (i = 0; i < (h/2); i++) {
1531	    s = src3;
1532	    for (j = 0; j < (w/2); j++) {
1533		dst3[(i) + (((w/2) - j - 1) * (dstPitch))] = *s++;
1534	    }
1535	    src3 += srcPitch2;
1536	}
1537	break;
1538    case RR_Rotate_180:
1539	for (i = 0; i < (h/2); i++) {
1540	    s = src3;
1541	    for (j = 0; j < (w/2); j++) {
1542		dst3[((w/2) - j - 1) + (((h/2) - i - 1) * dstPitch)] = *s++;
1543	    }
1544	    src3 += srcPitch2;
1545	}
1546	break;
1547    case RR_Rotate_270:
1548	for (i = 0; i < (h/2); i++) {
1549	    s = src3;
1550	    for (j = 0; j < (w/2); j++) {
1551		dst3[((h/2) - i - 1) + (j * dstPitch)] = *s++;
1552	    }
1553	    src3 += srcPitch2;
1554	}
1555	break;
1556    }
1557
1558    if (pPriv->textured)
1559	drm_intel_bo_unmap(pPriv->buf);
1560}
1561
1562typedef struct {
1563    uint8_t sign;
1564    uint16_t mantissa;
1565    uint8_t exponent;
1566} coeffRec, *coeffPtr;
1567
1568static Bool
1569SetCoeffRegs(double *coeff, int mantSize, coeffPtr pCoeff, int pos)
1570{
1571    int maxVal, icoeff, res;
1572    int sign;
1573    double c;
1574
1575    sign = 0;
1576    maxVal = 1 << mantSize;
1577    c = *coeff;
1578    if (c < 0.0) {
1579	sign = 1;
1580	c = -c;
1581    }
1582
1583    res = 12 - mantSize;
1584    if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) {
1585	pCoeff[pos].exponent = 3;
1586	pCoeff[pos].mantissa = icoeff << res;
1587	*coeff = (double)icoeff / (double)(4 * maxVal);
1588    } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) {
1589	pCoeff[pos].exponent = 2;
1590	pCoeff[pos].mantissa = icoeff << res;
1591	*coeff = (double)icoeff / (double)(2 * maxVal);
1592    } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) {
1593	pCoeff[pos].exponent = 1;
1594	pCoeff[pos].mantissa = icoeff << res;
1595	*coeff = (double)icoeff / (double)(maxVal);
1596    } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) {
1597	pCoeff[pos].exponent = 0;
1598	pCoeff[pos].mantissa = icoeff << res;
1599	*coeff = (double)icoeff / (double)(maxVal / 2);
1600    } else {
1601	/* Coeff out of range */
1602	return FALSE;
1603    }
1604
1605    pCoeff[pos].sign = sign;
1606    if (sign)
1607	*coeff = -(*coeff);
1608    return TRUE;
1609}
1610
1611static void
1612UpdateCoeff(int taps, double fCutoff, Bool isHoriz, Bool isY, coeffPtr pCoeff)
1613{
1614    int i, j, j1, num, pos, mantSize;
1615    double pi = 3.1415926535, val, sinc, window, sum;
1616    double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS];
1617    double diff;
1618    int tapAdjust[MAX_TAPS], tap2Fix;
1619    Bool isVertAndUV;
1620
1621    if (isHoriz)
1622	mantSize = 7;
1623    else
1624	mantSize = 6;
1625
1626    isVertAndUV = !isHoriz && !isY;
1627    num = taps * 16;
1628    for (i = 0; i < num  * 2; i++) {
1629	val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num);
1630	if (val == 0.0)
1631	    sinc = 1.0;
1632	else
1633	    sinc = sin(val) / val;
1634
1635	/* Hamming window */
1636	window = (0.5 - 0.5 * cos(i * pi / num));
1637	rawCoeff[i] = sinc * window;
1638    }
1639
1640    for (i = 0; i < N_PHASES; i++) {
1641	/* Normalise the coefficients. */
1642	sum = 0.0;
1643	for (j = 0; j < taps; j++) {
1644	    pos = i + j * 32;
1645	    sum += rawCoeff[pos];
1646	}
1647	for (j = 0; j < taps; j++) {
1648	    pos = i + j * 32;
1649	    coeffs[i][j] = rawCoeff[pos] / sum;
1650	}
1651
1652	/* Set the register values. */
1653	for (j = 0; j < taps; j++) {
1654	    pos = j + i * taps;
1655	    if ((j == (taps - 1) / 2) && !isVertAndUV)
1656		SetCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos);
1657	    else
1658		SetCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos);
1659	}
1660
1661	tapAdjust[0] = (taps - 1) / 2;
1662	for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) {
1663	    tapAdjust[j1] = tapAdjust[0] - j;
1664	    tapAdjust[++j1] = tapAdjust[0] + j;
1665	}
1666
1667	/* Adjust the coefficients. */
1668	sum = 0.0;
1669	for (j = 0; j < taps; j++)
1670	    sum += coeffs[i][j];
1671	if (sum != 1.0) {
1672	    for (j1 = 0; j1 < taps; j1++) {
1673		tap2Fix = tapAdjust[j1];
1674		diff = 1.0 - sum;
1675		coeffs[i][tap2Fix] += diff;
1676		pos = tap2Fix + i * taps;
1677		if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV)
1678		    SetCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos);
1679		else
1680		    SetCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos);
1681
1682		sum = 0.0;
1683		for (j = 0; j < taps; j++)
1684		    sum += coeffs[i][j];
1685		if (sum == 1.0)
1686		    break;
1687	    }
1688	}
1689    }
1690}
1691
1692static void
1693i830_box_intersect (BoxPtr dest, BoxPtr a, BoxPtr b)
1694{
1695    dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
1696    dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
1697    dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
1698    dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
1699    if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2)
1700	dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
1701}
1702
1703static void
1704i830_crtc_box (xf86CrtcPtr crtc, BoxPtr crtc_box)
1705{
1706    if (crtc->enabled)
1707    {
1708	crtc_box->x1 = crtc->x;
1709	crtc_box->x2 = crtc->x + xf86ModeWidth (&crtc->mode, crtc->rotation);
1710	crtc_box->y1 = crtc->y;
1711	crtc_box->y2 = crtc->y + xf86ModeHeight (&crtc->mode, crtc->rotation);
1712    }
1713    else
1714	crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
1715}
1716
1717static int
1718i830_box_area (BoxPtr box)
1719{
1720    return (int) (box->x2 - box->x1) * (int) (box->y2 - box->y1);
1721}
1722
1723/*
1724 * Return the crtc covering 'box'. If two crtcs cover a portion of
1725 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
1726 * with greater coverage
1727 */
1728
1729xf86CrtcPtr
1730i830_covering_crtc (ScrnInfoPtr pScrn,
1731		    BoxPtr	box,
1732		    xf86CrtcPtr desired,
1733		    BoxPtr	crtc_box_ret)
1734{
1735    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1736    xf86CrtcPtr		crtc, best_crtc;
1737    int			coverage, best_coverage;
1738    int			c;
1739    BoxRec		crtc_box, cover_box;
1740
1741    best_crtc = NULL;
1742    best_coverage = 0;
1743    crtc_box_ret->x1 = 0;
1744    crtc_box_ret->x2 = 0;
1745    crtc_box_ret->y1 = 0;
1746    crtc_box_ret->y2 = 0;
1747    for (c = 0; c < xf86_config->num_crtc; c++)
1748    {
1749	crtc = xf86_config->crtc[c];
1750
1751	/* If the CRTC is off, treat it as not covering */
1752	if (!i830_crtc_on(crtc))
1753	    continue;
1754
1755	i830_crtc_box (crtc, &crtc_box);
1756	i830_box_intersect (&cover_box, &crtc_box, box);
1757	coverage = i830_box_area (&cover_box);
1758	if (coverage && crtc == desired)
1759	{
1760	    *crtc_box_ret = crtc_box;
1761	    return crtc;
1762	}
1763	if (coverage > best_coverage)
1764	{
1765	    *crtc_box_ret = crtc_box;
1766	    best_crtc = crtc;
1767	    best_coverage = coverage;
1768	}
1769    }
1770    return best_crtc;
1771}
1772
1773static int
1774i830_swidth (I830Ptr pI830, unsigned int offset,
1775	     unsigned int width, unsigned int mask, int shift)
1776{
1777    int	swidth = ((offset + width + mask) >> shift) - (offset >> shift);
1778    if (IS_I9XX(pI830))
1779	swidth <<= 1;
1780    swidth -= 1;
1781    return swidth << 2;
1782}
1783
1784static void
1785i830_update_dst_box_to_crtc_coords(ScrnInfoPtr pScrn, xf86CrtcPtr crtc,
1786		BoxPtr dstBox)
1787{
1788    int tmp;
1789
1790    /* for overlay, we should take it from crtc's screen
1791     * coordinate to current crtc's display mode.
1792     * yeah, a bit confusing.
1793     */
1794    switch (crtc->rotation & 0xf) {
1795    case RR_Rotate_0:
1796	dstBox->x1 -= crtc->x;
1797	dstBox->x2 -= crtc->x;
1798	dstBox->y1 -= crtc->y;
1799	dstBox->y2 -= crtc->y;
1800	break;
1801    case RR_Rotate_90:
1802	tmp = dstBox->x1;
1803	dstBox->x1 = dstBox->y1 - crtc->x;
1804	dstBox->y1 = pScrn->virtualX - tmp - crtc->y;
1805	tmp = dstBox->x2;
1806	dstBox->x2 = dstBox->y2 - crtc->x;
1807	dstBox->y2 = pScrn->virtualX - tmp - crtc->y;
1808	tmp = dstBox->y1;
1809	dstBox->y1 = dstBox->y2;
1810	dstBox->y2 = tmp;
1811	break;
1812    case RR_Rotate_180:
1813	tmp = dstBox->x1;
1814	dstBox->x1 = pScrn->virtualX - dstBox->x2 - crtc->x;
1815	dstBox->x2 = pScrn->virtualX - tmp - crtc->x;
1816	tmp = dstBox->y1;
1817	dstBox->y1 = pScrn->virtualY - dstBox->y2 - crtc->y;
1818	dstBox->y2 = pScrn->virtualY - tmp - crtc->y;
1819	break;
1820    case RR_Rotate_270:
1821	tmp = dstBox->x1;
1822	dstBox->x1 = pScrn->virtualY - dstBox->y1 - crtc->x;
1823	dstBox->y1 = tmp - crtc->y;
1824	tmp = dstBox->x2;
1825	dstBox->x2 = pScrn->virtualY - dstBox->y2 - crtc->x;
1826	dstBox->y2 = tmp - crtc->y;
1827	tmp = dstBox->x1;
1828	dstBox->x1 = dstBox->x2;
1829	dstBox->x2 = tmp;
1830	break;
1831    }
1832
1833    return;
1834}
1835
1836static void
1837i830_store_coeffs_in_overlay_regs(uint16_t *reg_coeffs, coeffPtr new_coeffs,
1838	int max_taps)
1839{
1840    int i, j, pos;
1841
1842    for (i = 0; i < N_PHASES; i++) {
1843	for (j = 0; j < max_taps; j++) {
1844	    pos = i * max_taps + j;
1845	    reg_coeffs[pos] = (new_coeffs[pos].sign << 15 |
1846				      new_coeffs[pos].exponent << 12 |
1847				      new_coeffs[pos].mantissa);
1848	}
1849    }
1850}
1851
1852static double
1853i830_limit_coeff(double coeff)
1854{
1855    /* Limit to between 1.0 and 3.0. */
1856    if (coeff < MIN_CUTOFF_FREQ)
1857	coeff = MIN_CUTOFF_FREQ;
1858    if (coeff > MAX_CUTOFF_FREQ)
1859	coeff = MAX_CUTOFF_FREQ;
1860
1861    return coeff;
1862}
1863
1864static void
1865i830_update_polyphase_coeffs(I830OverlayRegPtr	overlay,
1866	int xscaleFract, int xscaleFractUV)
1867{
1868    /*
1869     * Only Horizontal coefficients so far.
1870     */
1871    double fCutoffY;
1872    double fCutoffUV;
1873    coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
1874    coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
1875
1876    fCutoffY = xscaleFract / 4096.0;
1877    fCutoffUV = xscaleFractUV / 4096.0;
1878
1879    fCutoffUV = i830_limit_coeff(fCutoffUV);
1880    fCutoffY = i830_limit_coeff(fCutoffY);
1881
1882    UpdateCoeff(N_HORIZ_Y_TAPS, fCutoffY, TRUE, TRUE, xcoeffY);
1883    UpdateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, TRUE, FALSE, xcoeffUV);
1884
1885    i830_store_coeffs_in_overlay_regs(overlay->Y_HCOEFS, xcoeffY,
1886		    N_HORIZ_Y_TAPS);
1887    i830_store_coeffs_in_overlay_regs(overlay->UV_HCOEFS, xcoeffUV,
1888		    N_HORIZ_UV_TAPS);
1889}
1890
1891/*
1892 * Calculate horizontal and vertical scaling factors and polyphase
1893 * coefficients.
1894 */
1895
1896static Bool
1897i830_update_scaling_factors(I830OverlayRegPtr overlay,
1898	short src_w, short src_h, short drw_w, short drw_h)
1899{
1900    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
1901    int xscaleIntUV, xscaleFractUV;
1902    int yscaleIntUV, yscaleFractUV;
1903    uint32_t newval;
1904    Bool scaleChanged = FALSE;
1905
1906    /*
1907     * Y down-scale factor as a multiple of 4096.
1908     */
1909    xscaleFract = ((src_w - 1) << 12) / drw_w;
1910    yscaleFract = ((src_h - 1) << 12) / drw_h;
1911
1912    /* Calculate the UV scaling factor.
1913     * UV is half the size of Y -- YUV420 */
1914    xscaleFractUV = xscaleFract / 2;
1915    yscaleFractUV = yscaleFract / 2;
1916
1917    /*
1918     * To keep the relative Y and UV ratios exact, round the Y scales
1919     * to a multiple of the Y/UV ratio.
1920     */
1921    xscaleFract = xscaleFractUV * 2;
1922    yscaleFract = yscaleFractUV * 2;
1923
1924    /* Integer (un-multiplied) values. */
1925    xscaleInt = xscaleFract >> 12;
1926    yscaleInt = yscaleFract >> 12;
1927
1928    xscaleIntUV = xscaleFractUV >> 12;
1929    yscaleIntUV = yscaleFractUV >> 12;
1930
1931    OVERLAY_DEBUG("xscale: %x.%03x, yscale: %x.%03x\n", xscaleInt,
1932		  xscaleFract & 0xFFF, yscaleInt, yscaleFract & 0xFFF);
1933    OVERLAY_DEBUG("UV xscale: %x.%03x, UV yscale: %x.%03x\n", xscaleIntUV,
1934		  xscaleFractUV & 0xFFF, yscaleIntUV, yscaleFractUV & 0xFFF);
1935
1936    /* shouldn't get here */
1937    if (xscaleInt > 7) {
1938	OVERLAY_DEBUG("xscale: bad scale\n");
1939	return FALSE;
1940    }
1941
1942    /* shouldn't get here */
1943    if (xscaleIntUV > 7) {
1944	OVERLAY_DEBUG("xscaleUV: bad scale\n");
1945	return FALSE;
1946    }
1947
1948    newval = (xscaleInt << 16) |
1949    ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
1950    if (newval != overlay->YRGBSCALE) {
1951	scaleChanged = TRUE;
1952	overlay->YRGBSCALE = newval;
1953    }
1954
1955    newval = (xscaleIntUV << 16) | ((xscaleFractUV & 0xFFF) << 3) |
1956    ((yscaleFractUV & 0xFFF) << 20);
1957    if (newval != overlay->UVSCALE) {
1958	scaleChanged = TRUE;
1959	overlay->UVSCALE = newval;
1960    }
1961
1962    newval = yscaleInt << 16 | yscaleIntUV;
1963    if (newval != overlay->UVSCALEV) {
1964	scaleChanged = TRUE;
1965	overlay->UVSCALEV = newval;
1966    }
1967
1968    if (scaleChanged) {
1969	i830_update_polyphase_coeffs(overlay, xscaleFract, xscaleFractUV);
1970    }
1971
1972    return scaleChanged;
1973}
1974
1975static void
1976i830_display_video(ScrnInfoPtr pScrn, xf86CrtcPtr crtc,
1977		   int id, short width, short height,
1978		   int dstPitch, int x1, int y1, int x2, int y2, BoxPtr dstBox,
1979		   short src_w, short src_h, short drw_w, short drw_h)
1980{
1981    I830Ptr		pI830 = I830PTR(pScrn);
1982    I830PortPrivPtr	pPriv = pI830->adaptor->pPortPrivates[0].ptr;
1983    I830OverlayRegPtr	overlay = I830OVERLAYREG(pI830);
1984    unsigned int	swidth, swidthy, swidthuv;
1985    unsigned int	mask, shift, offsety, offsetu;
1986    int			tmp;
1987    uint32_t		OCMD;
1988    Bool		scaleChanged = FALSE;
1989
1990    OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
1991		  dstPitch);
1992
1993#if VIDEO_DEBUG
1994    CompareOverlay(pI830, (uint32_t *) overlay, 0x100);
1995#endif
1996
1997    /*
1998     * If the video isn't visible on any CRTC, turn it off
1999     */
2000    if (!crtc)
2001    {
2002	pPriv->current_crtc = NULL;
2003	i830_overlay_off (pScrn);
2004	return;
2005    }
2006
2007    if (crtc != pPriv->current_crtc)
2008    {
2009	i830_overlay_switch_to_crtc (pScrn, crtc);
2010	if (pPriv->overlayOK) {
2011	    pPriv->current_crtc = crtc;
2012	    I830ResetVideo (pScrn);
2013	}
2014    }
2015
2016    if (!pPriv->overlayOK)
2017	return;
2018
2019    i830_update_dst_box_to_crtc_coords(pScrn, crtc, dstBox);
2020
2021    if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
2022	tmp = width;
2023	width = height;
2024	height = tmp;
2025	tmp = drw_w;
2026	drw_w = drw_h;
2027	drw_h = tmp;
2028	tmp = src_w;
2029	src_w = src_h;
2030	src_h = tmp;
2031    }
2032
2033    if (pPriv->oneLineMode) {
2034	/* change the coordinates with panel fitting active */
2035	dstBox->y1 = (((dstBox->y1 - 1) * pPriv->scaleRatio) >> 16) + 1;
2036	dstBox->y2 = ((dstBox->y2 * pPriv->scaleRatio) >> 16) + 1;
2037
2038	/* Now, alter the height, so we scale to the correct size */
2039	drw_h = ((drw_h * pPriv->scaleRatio) >> 16) + 1;
2040    }
2041
2042    if (IS_I9XX(pI830)) {
2043	shift = 6;
2044	mask = 0x3f;
2045    } else {
2046	shift = 5;
2047	mask = 0x1f;
2048    }
2049
2050    if (pPriv->currentBuf == 0) {
2051	offsety = pPriv->YBuf0offset;
2052	offsetu = pPriv->UBuf0offset;
2053    } else {
2054	offsety = pPriv->YBuf1offset;
2055	offsetu = pPriv->UBuf1offset;
2056    }
2057
2058    switch (id) {
2059    case FOURCC_YV12:
2060    case FOURCC_I420:
2061	overlay->SWIDTH = width | ((width/2 & 0x7ff) << 16);
2062	swidthy  = i830_swidth (pI830, offsety, width, mask, shift);
2063	swidthuv = i830_swidth (pI830, offsetu, width/2, mask, shift);
2064	overlay->SWIDTHSW = (swidthy) | (swidthuv << 16);
2065	overlay->SHEIGHT = height | ((height / 2) << 16);
2066	break;
2067    case FOURCC_UYVY:
2068    case FOURCC_YUY2:
2069    default:
2070	overlay->SWIDTH = width;
2071	swidth = ((offsety + (width << 1) + mask) >> shift) -
2072	(offsety >> shift);
2073
2074	if (IS_I9XX(pI830))
2075	    swidth <<= 1;
2076
2077	swidth -= 1;
2078
2079	swidth <<= 2;
2080
2081	OVERLAY_DEBUG("swidthsw is old %d new %d\n",
2082		      swidth,
2083		      i830_swidth (pI830, offsety, width << 1,
2084				   mask, shift));
2085
2086	overlay->SWIDTHSW = swidth;
2087	overlay->SHEIGHT = height;
2088	break;
2089    }
2090
2091    overlay->DWINPOS = (dstBox->y1 << 16) | dstBox->x1;
2092
2093    overlay->DWINSZ = (((dstBox->y2 - dstBox->y1) << 16) |
2094		       (dstBox->x2 - dstBox->x1));
2095
2096    OVERLAY_DEBUG("dstBox: x1: %d, y1: %d, x2: %d, y2: %d\n",
2097		  dstBox->x1, dstBox->y1, dstBox->x2, dstBox->y2);
2098
2099    /* buffer locations */
2100    overlay->OBUF_0Y = pPriv->YBuf0offset;
2101    overlay->OBUF_0U = pPriv->UBuf0offset;
2102    overlay->OBUF_0V = pPriv->VBuf0offset;
2103    if(pPriv->doubleBuffer) {
2104	overlay->OBUF_1Y = pPriv->YBuf1offset;
2105	overlay->OBUF_1U = pPriv->UBuf1offset;
2106	overlay->OBUF_1V = pPriv->VBuf1offset;
2107    }
2108
2109    OVERLAY_DEBUG("pos: 0x%x, size: 0x%x\n",
2110		  overlay->DWINPOS, overlay->DWINSZ);
2111    OVERLAY_DEBUG("dst: %d x %d, src: %d x %d\n", drw_w, drw_h, src_w, src_h);
2112
2113    scaleChanged = i830_update_scaling_factors(overlay,
2114	    src_w, src_h, drw_w, drw_h);
2115
2116    OCMD = OVERLAY_ENABLE;
2117
2118    switch (id) {
2119    case FOURCC_YV12:
2120    case FOURCC_I420:
2121#ifdef INTEL_XVMC
2122    case FOURCC_XVMC:
2123#endif
2124	OVERLAY_DEBUG("YUV420\n");
2125#if 0
2126	/* set UV vertical phase to -0.25 */
2127	overlay->UV_VPH = 0x30003000;
2128#endif
2129	OVERLAY_DEBUG("UV stride is %d, Y stride is %d\n",
2130		      dstPitch, dstPitch * 2);
2131	overlay->OSTRIDE = (dstPitch * 2) | (dstPitch << 16);
2132	OCMD &= ~SOURCE_FORMAT;
2133	OCMD &= ~OV_BYTE_ORDER;
2134	OCMD |= YUV_420;
2135	break;
2136    case FOURCC_UYVY:
2137    case FOURCC_YUY2:
2138	OVERLAY_DEBUG("YUV422\n");
2139	overlay->OSTRIDE = dstPitch;
2140	OCMD &= ~SOURCE_FORMAT;
2141	OCMD |= YUV_422;
2142	OCMD &= ~OV_BYTE_ORDER;
2143	if (id == FOURCC_UYVY)
2144	    OCMD |= Y_SWAP;
2145	break;
2146    }
2147
2148    OCMD &= ~(BUFFER_SELECT | FIELD_SELECT);
2149    if (pPriv->currentBuf == 0)
2150	OCMD |= BUFFER0;
2151    else
2152	OCMD |= BUFFER1;
2153
2154    overlay->OCMD = OCMD;
2155    OVERLAY_DEBUG("OCMD is 0x%x\n", OCMD);
2156
2157    /* make sure the overlay is on */
2158    i830_overlay_on (pScrn);
2159    /* and show this frame */
2160    i830_overlay_continue (pScrn, scaleChanged);
2161}
2162
2163static Bool
2164i830_clip_video_helper (ScrnInfoPtr pScrn,
2165			I830PortPrivPtr pPriv,
2166			xf86CrtcPtr *crtc_ret,
2167			BoxPtr	    dst,
2168			INT32	    *xa,
2169			INT32	    *xb,
2170			INT32	    *ya,
2171			INT32	    *yb,
2172			RegionPtr   reg,
2173			INT32	    width,
2174			INT32	    height)
2175{
2176    Bool	ret;
2177    RegionRec	crtc_region_local;
2178    RegionPtr	crtc_region = reg;
2179
2180    /*
2181     * For overlay video, compute the relevant CRTC and
2182     * clip video to that
2183     */
2184    if (crtc_ret)
2185    {
2186	BoxRec		crtc_box;
2187	xf86CrtcPtr	crtc = i830_covering_crtc (pScrn, dst,
2188						   pPriv->desired_crtc,
2189						   &crtc_box);
2190
2191	/* For textured video, we don't actually want to clip at all. */
2192	if (crtc && !pPriv->textured)
2193	{
2194	    REGION_INIT (pScreen, &crtc_region_local, &crtc_box, 1);
2195	    crtc_region = &crtc_region_local;
2196	    REGION_INTERSECT (pScreen, crtc_region, crtc_region, reg);
2197	}
2198	*crtc_ret = crtc;
2199    }
2200    ret = xf86XVClipVideoHelper (dst, xa, xb, ya, yb,
2201				 crtc_region, width, height);
2202    if (crtc_region != reg)
2203	REGION_UNINIT (pScreen, &crtc_region_local);
2204    return ret;
2205}
2206
2207/*
2208 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h).
2209 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h).
2210 * id is a fourcc code for the format of the video.
2211 * buf is the pointer to the source data in system memory.
2212 * width and height are the w/h of the source data.
2213 * If "sync" is TRUE, then we must be finished with *buf at the point of return
2214 * (which we always are).
2215 * clipBoxes is the clipping region in screen space.
2216 * data is a pointer to our port private.
2217 * pDraw is a Drawable, which might not be the screen in the case of
2218 * compositing.  It's a new argument to the function in the 1.1 server.
2219 */
2220static int
2221I830PutImage(ScrnInfoPtr pScrn,
2222	     short src_x, short src_y,
2223	     short drw_x, short drw_y,
2224	     short src_w, short src_h,
2225	     short drw_w, short drw_h,
2226	     int id, unsigned char *buf,
2227	     short width, short height,
2228	     Bool sync, RegionPtr clipBoxes, pointer data,
2229	     DrawablePtr pDraw)
2230{
2231    I830Ptr pI830 = I830PTR(pScrn);
2232    I830PortPrivPtr pPriv = (I830PortPrivPtr) data;
2233    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
2234    I830OverlayRegPtr overlay;
2235    PixmapPtr pPixmap = get_drawable_pixmap(pDraw);;
2236    INT32 x1, x2, y1, y2;
2237    int srcPitch = 0, srcPitch2 = 0, dstPitch, destId;
2238    int dstPitch2 = 0;
2239    int top, left, npixels, nlines, size;
2240    BoxRec dstBox;
2241    int pitchAlignMask;
2242    int alloc_size;
2243    xf86CrtcPtr	crtc;
2244
2245    if (pPriv->textured)
2246	overlay = NULL;
2247    else
2248	overlay = I830OVERLAYREG(pI830);
2249
2250#if 0
2251    ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n"
2252	   "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, drw_y,
2253	   drw_w, drw_h, width, height);
2254#endif
2255
2256    if (!pPriv->textured) {
2257        /* If dst width and height are less than 1/8th the src size, the
2258         * src/dst scale factor becomes larger than 8 and doesn't fit in
2259         * the scale register. */
2260        if(src_w >= (drw_w * 8))
2261            drw_w = src_w/7;
2262
2263        if(src_h >= (drw_h * 8))
2264            drw_h = src_h/7;
2265    }
2266
2267    /* Clip */
2268    x1 = src_x;
2269    x2 = src_x + src_w;
2270    y1 = src_y;
2271    y2 = src_y + src_h;
2272
2273    dstBox.x1 = drw_x;
2274    dstBox.x2 = drw_x + drw_w;
2275    dstBox.y1 = drw_y;
2276    dstBox.y2 = drw_y + drw_h;
2277
2278    if (!i830_clip_video_helper(pScrn,
2279				pPriv,
2280				&crtc,
2281				&dstBox, &x1, &x2, &y1, &y2, clipBoxes,
2282				width, height))
2283	return Success;
2284
2285     if (!pPriv->textured) {
2286	 /* texture video handles rotation differently. */
2287	if (crtc)
2288	    pPriv->rotation = crtc->rotation;
2289	else {
2290	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2291		    "Fail to clip video to any crtc!\n");
2292	    return Success;
2293	}
2294     }
2295
2296    destId = id;
2297    switch (id) {
2298    case FOURCC_YV12:
2299    case FOURCC_I420:
2300	srcPitch = (width + 0x3) & ~0x3;
2301	srcPitch2 = ((width >> 1) + 0x3) & ~0x3;
2302	break;
2303#ifdef INTEL_XVMC
2304    case FOURCC_XVMC:
2305	srcPitch = (width + 0x3) & ~0x3;
2306	srcPitch2 = ((width >> 1) + 0x3) & ~0x3;
2307	break;
2308#endif
2309    case FOURCC_UYVY:
2310    case FOURCC_YUY2:
2311    default:
2312	srcPitch = width << 1;
2313	break;
2314    }
2315
2316    /* Only needs to be DWORD-aligned for textured on i915, but overlay has
2317     * stricter requirements.
2318     */
2319    if (pPriv->textured) {
2320	pitchAlignMask = 3;
2321#ifdef INTEL_XVMC
2322	/* for i915 xvmc, hw requires at least 1kb aligned surface */
2323	if ((id == FOURCC_XVMC) && IS_I915(pI830))
2324	    pitchAlignMask = 0x3ff;
2325#endif
2326    } else {
2327	if (IS_I965G(pI830))
2328	    pitchAlignMask = 255;
2329	else
2330	    pitchAlignMask = 63;
2331    }
2332
2333    /* Determine the desired destination pitch (representing the chroma's pitch,
2334     * in the planar case.
2335     */
2336    switch (destId) {
2337    case FOURCC_YV12:
2338    case FOURCC_I420:
2339	if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
2340	    dstPitch = ((height / 2) + pitchAlignMask) & ~pitchAlignMask;
2341	    size = dstPitch * width * 3;
2342	} else {
2343	    dstPitch = ((width / 2) + pitchAlignMask) & ~pitchAlignMask;
2344	    size = dstPitch * height * 3;
2345	}
2346	break;
2347    case FOURCC_UYVY:
2348    case FOURCC_YUY2:
2349
2350	if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
2351	    dstPitch = ((height << 1) + pitchAlignMask) & ~pitchAlignMask;
2352	    size = dstPitch * width;
2353	} else {
2354	    dstPitch = ((width << 1) + pitchAlignMask) & ~pitchAlignMask;
2355	    size = dstPitch * height;
2356	}
2357	break;
2358#ifdef INTEL_XVMC
2359    case FOURCC_XVMC:
2360	dstPitch = ((width / 2) + pitchAlignMask ) & ~pitchAlignMask;
2361	dstPitch2 = (width + pitchAlignMask ) & ~pitchAlignMask;
2362	size = 0;
2363	break;
2364#endif
2365    default:
2366	dstPitch = 0;
2367	size = 0;
2368	break;
2369    }
2370#if 0
2371    ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, dstPitch, size);
2372#endif
2373
2374    alloc_size = size;
2375    if (pPriv->doubleBuffer)
2376	alloc_size *= 2;
2377
2378    /* Free the current buffer if we're going to have to reallocate */
2379    if (pPriv->buf && pPriv->buf->size < alloc_size) {
2380	if (!pPriv->textured)
2381	    drm_intel_bo_unpin(pPriv->buf);
2382	drm_intel_bo_unreference(pPriv->buf);
2383	pPriv->buf = NULL;
2384    }
2385
2386#ifdef INTEL_XVMC
2387    if (id == FOURCC_XVMC &&
2388        pPriv->rotation == RR_Rotate_0) {
2389        if (pPriv->buf) {
2390            assert(pPriv->textured);
2391            drm_intel_bo_unreference(pPriv->buf);
2392            pPriv->buf = NULL;
2393        }
2394    } else {
2395#endif
2396        if (pPriv->buf == NULL) {
2397            pPriv->buf = drm_intel_bo_alloc(pI830->bufmgr,
2398                                         "xv buffer", alloc_size, 4096);
2399            if (pPriv->buf == NULL)
2400                return BadAlloc;
2401            if (!pPriv->textured && drm_intel_bo_pin(pPriv->buf, 4096) != 0) {
2402                drm_intel_bo_unreference(pPriv->buf);
2403                pPriv->buf = NULL;
2404                xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2405                           "Failed to pin xv buffer\n");
2406                return BadAlloc;
2407            }
2408        }
2409#ifdef INTEL_XVMC
2410    }
2411#endif
2412
2413    /* fixup pointers */
2414#ifdef INTEL_XVMC
2415    if (id == FOURCC_XVMC && IS_I915(pI830)) {
2416	pPriv->YBuf0offset = (uint32_t)((uintptr_t)buf);
2417	pPriv->VBuf0offset = pPriv->YBuf0offset + (dstPitch2 * height);
2418	pPriv->UBuf0offset = pPriv->VBuf0offset + (dstPitch * height / 2);
2419	destId = FOURCC_YV12;
2420    } else {
2421#endif
2422	if (pPriv->textured)
2423	    pPriv->YBuf0offset = 0;
2424	else
2425	    pPriv->YBuf0offset = pPriv->buf->offset;
2426
2427	if (pPriv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
2428	    pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * width);
2429	    pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * width / 2);
2430	    if(pPriv->doubleBuffer) {
2431		pPriv->YBuf1offset = pPriv->YBuf0offset + size;
2432		pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * width);
2433		pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * width / 2);
2434	    }
2435	} else {
2436	    pPriv->UBuf0offset = pPriv->YBuf0offset + (dstPitch * 2 * height);
2437	    pPriv->VBuf0offset = pPriv->UBuf0offset + (dstPitch * height / 2);
2438	    if(pPriv->doubleBuffer) {
2439		pPriv->YBuf1offset = pPriv->YBuf0offset + size;
2440		pPriv->UBuf1offset = pPriv->YBuf1offset + (dstPitch * 2 * height);
2441		pPriv->VBuf1offset = pPriv->UBuf1offset + (dstPitch * height / 2);
2442	    }
2443	}
2444#ifdef INTEL_XVMC
2445    }
2446#endif
2447
2448    /* Pick the idle buffer */
2449    if (!pPriv->textured && pI830->overlayOn && pPriv->doubleBuffer)
2450	pPriv->currentBuf = !((INREG(DOVSTA) & OC_BUF) >> 20);
2451
2452    /* copy data */
2453    top = y1 >> 16;
2454    left = (x1 >> 16) & ~1;
2455    npixels = ((((x2 + 0xffff) >> 16) + 1) & ~1) - left;
2456
2457    switch (id) {
2458    case FOURCC_YV12:
2459    case FOURCC_I420:
2460	top &= ~1;
2461	nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
2462	I830CopyPlanarData(pScrn, pPriv, buf, srcPitch, srcPitch2, dstPitch,
2463	    	       height, top, left, nlines, npixels, id);
2464	break;
2465    case FOURCC_UYVY:
2466    case FOURCC_YUY2:
2467	nlines = ((y2 + 0xffff) >> 16) - top;
2468	I830CopyPackedData(pScrn, pPriv, buf, srcPitch, dstPitch, top, left,
2469			   nlines, npixels);
2470	break;
2471#ifdef INTEL_XVMC
2472    case FOURCC_XVMC:
2473	if (pPriv->rotation != RR_Rotate_0) {
2474	    top &= ~1;
2475	    nlines = ((((y2 + 0xffff) >> 16) + 1) & ~1) - top;
2476	    I830CopyPlanarData(pScrn, pPriv, buf, srcPitch, srcPitch2, dstPitch,
2477		    height, top, left, nlines, npixels, id);
2478	}
2479
2480	break;
2481#endif
2482    default:
2483	break;
2484    }
2485
2486    if (!pPriv->textured) {
2487	i830_display_video(pScrn, crtc, destId, width, height, dstPitch,
2488			   x1, y1, x2, y2, &dstBox, src_w, src_h,
2489			   drw_w, drw_h);
2490
2491	/* update cliplist */
2492	if (!REGION_EQUAL(pScrn->pScreen, &pPriv->clip, clipBoxes)) {
2493	    REGION_COPY(pScrn->pScreen, &pPriv->clip, clipBoxes);
2494	    xf86XVFillKeyHelper(pScrn->pScreen, pPriv->colorKey, clipBoxes);
2495	}
2496    } else {
2497        Bool sync = TRUE;
2498
2499        if (crtc == NULL) {
2500            sync = FALSE;
2501        } else if (pPriv->SyncToVblank == 0) {
2502            sync = FALSE;
2503        }
2504
2505        if (sync) {
2506	    BoxPtr box;
2507	    pixman_box16_t box_in_crtc_coordinates;
2508	    int pipe = -1, event, load_scan_lines_pipe;
2509
2510	    if (pixmap_is_scanout(pPixmap))
2511		pipe = i830_crtc_to_pipe(crtc);
2512
2513	    if (pipe >= 0) {
2514		if (pipe == 0) {
2515		    event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
2516		    load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
2517		} else {
2518		    event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
2519		    load_scan_lines_pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
2520		}
2521
2522		box = REGION_EXTENTS(unused, clipBoxes);
2523		box_in_crtc_coordinates = *box;
2524		if (crtc->transform_in_use)
2525		    pixman_f_transform_bounds (&crtc->f_framebuffer_to_crtc, &box_in_crtc_coordinates);
2526
2527		BEGIN_BATCH(5);
2528		/* The documentation says that the LOAD_SCAN_LINES command
2529		 * always comes in pairs. Don't ask me why. */
2530		OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe);
2531		OUT_BATCH((box_in_crtc_coordinates.y1 << 16) | box_in_crtc_coordinates.y2);
2532		OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | load_scan_lines_pipe);
2533		OUT_BATCH((box_in_crtc_coordinates.y1 << 16) | box_in_crtc_coordinates.y2);
2534		OUT_BATCH(MI_WAIT_FOR_EVENT | event);
2535		ADVANCE_BATCH();
2536	    }
2537        }
2538
2539        if (IS_I965G(pI830)) {
2540#ifdef INTEL_XVMC
2541            if (id == FOURCC_XVMC && pPriv->rotation == RR_Rotate_0) {
2542                pPriv->YBuf0offset = buf -  pI830->FbBase;
2543                pPriv->UBuf0offset = pPriv->YBuf0offset + height*width;
2544                pPriv->VBuf0offset = pPriv->UBuf0offset + height*width/4;
2545            }
2546#endif
2547            I965DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height,
2548                                     dstPitch, x1, y1, x2, y2,
2549                                     src_w, src_h, drw_w, drw_h, pPixmap);
2550        } else {
2551            I915DisplayVideoTextured(pScrn, pPriv, destId, clipBoxes, width, height,
2552                                     dstPitch, dstPitch2, x1, y1, x2, y2,
2553                                     src_w, src_h, drw_w, drw_h, pPixmap);
2554        }
2555    }
2556    if (pPriv->textured) {
2557	DamageDamageRegion(pDraw, clipBoxes);
2558    }
2559
2560    pPriv->videoStatus = CLIENT_VIDEO_ON;
2561
2562    return Success;
2563}
2564
2565static int
2566I830QueryImageAttributes(ScrnInfoPtr pScrn,
2567			 int id,
2568			 unsigned short *w, unsigned short *h,
2569			 int *pitches, int *offsets)
2570{
2571    I830Ptr pI830 = I830PTR(pScrn);
2572    int size, tmp;
2573
2574#if 0
2575    ErrorF("I830QueryImageAttributes: w is %d, h is %d\n", *w, *h);
2576#endif
2577
2578    if (IS_845G(pI830) || IS_I830(pI830)) {
2579	if (*w > IMAGE_MAX_WIDTH_LEGACY)
2580	    *w = IMAGE_MAX_WIDTH_LEGACY;
2581	if (*h > IMAGE_MAX_HEIGHT_LEGACY)
2582	    *h = IMAGE_MAX_HEIGHT_LEGACY;
2583    } else {
2584	if (*w > IMAGE_MAX_WIDTH)
2585	    *w = IMAGE_MAX_WIDTH;
2586	if (*h > IMAGE_MAX_HEIGHT)
2587	    *h = IMAGE_MAX_HEIGHT;
2588    }
2589
2590    *w = (*w + 1) & ~1;
2591    if (offsets)
2592	offsets[0] = 0;
2593
2594    switch (id) {
2595	/* IA44 is for XvMC only */
2596    case FOURCC_IA44:
2597    case FOURCC_AI44:
2598	if (pitches)
2599	    pitches[0] = *w;
2600	size = *w * *h;
2601	break;
2602    case FOURCC_YV12:
2603    case FOURCC_I420:
2604	*h = (*h + 1) & ~1;
2605	size = (*w + 3) & ~3;
2606	if (pitches)
2607	    pitches[0] = size;
2608	size *= *h;
2609	if (offsets)
2610	    offsets[1] = size;
2611	tmp = ((*w >> 1) + 3) & ~3;
2612	if (pitches)
2613	    pitches[1] = pitches[2] = tmp;
2614	tmp *= (*h >> 1);
2615	size += tmp;
2616	if (offsets)
2617	    offsets[2] = size;
2618	size += tmp;
2619#if 0
2620	if (pitches)
2621	    ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", pitches[0],
2622		   pitches[1], pitches[2]);
2623	if (offsets)
2624	    ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], offsets[2]);
2625	if (offsets)
2626	    ErrorF("size is %d\n", size);
2627#endif
2628	break;
2629#ifdef INTEL_XVMC
2630    case FOURCC_XVMC:
2631        *h = (*h + 1) & ~1;
2632        size = sizeof(struct intel_xvmc_command);
2633        if (pitches)
2634            pitches[0] = size;
2635        break;
2636#endif
2637    case FOURCC_UYVY:
2638    case FOURCC_YUY2:
2639    default:
2640	size = *w << 1;
2641	if (pitches)
2642	    pitches[0] = size;
2643	size *= *h;
2644	break;
2645    }
2646
2647    return size;
2648}
2649
2650void
2651I830VideoBlockHandler(int i, pointer blockData, pointer pTimeout,
2652		      pointer pReadmask)
2653{
2654    ScrnInfoPtr pScrn = xf86Screens[i];
2655    I830Ptr pI830 = I830PTR(pScrn);
2656    I830PortPrivPtr pPriv;
2657
2658    /* no overlay */
2659    if (pI830->adaptor == NULL)
2660        return;
2661
2662    pPriv = GET_PORT_PRIVATE(pScrn);
2663
2664    if (pPriv->videoStatus & TIMER_MASK) {
2665#if 1
2666	Time now = currentTime.milliseconds;
2667#else
2668	UpdateCurrentTime();
2669#endif
2670	if (pPriv->videoStatus & OFF_TIMER) {
2671	    if (pPriv->offTime < now) {
2672		/* Turn off the overlay */
2673		OVERLAY_DEBUG("BLOCKHANDLER\n");
2674
2675		i830_overlay_off (pScrn);
2676
2677		pPriv->videoStatus = FREE_TIMER;
2678		pPriv->freeTime = now + FREE_DELAY;
2679	    }
2680	} else {				/* FREE_TIMER */
2681	    if (pPriv->freeTime < now) {
2682		if (!pPriv->textured)
2683		    drm_intel_bo_unpin(pPriv->buf);
2684		drm_intel_bo_unreference(pPriv->buf);
2685		pPriv->buf = NULL;
2686		pPriv->videoStatus = 0;
2687	    }
2688	}
2689    }
2690}
2691
2692/***************************************************************************
2693 * Offscreen Images
2694 ***************************************************************************/
2695
2696typedef struct {
2697    Bool isOn;
2698} OffscreenPrivRec, *OffscreenPrivPtr;
2699
2700static int
2701I830AllocateSurface(ScrnInfoPtr pScrn,
2702		    int id,
2703		    unsigned short w,
2704		    unsigned short h, XF86SurfacePtr surface)
2705{
2706    int pitch, fbpitch, size;
2707    OffscreenPrivPtr pPriv;
2708    I830Ptr pI830 = I830PTR(pScrn);
2709
2710    OVERLAY_DEBUG("I830AllocateSurface\n");
2711
2712    if (IS_845G(pI830) || IS_I830(pI830)) {
2713	if ((w > IMAGE_MAX_WIDTH_LEGACY) || (h > IMAGE_MAX_HEIGHT_LEGACY))
2714	    return BadAlloc;
2715    } else {
2716	if ((w > IMAGE_MAX_WIDTH) || (h > IMAGE_MAX_HEIGHT))
2717	    return BadAlloc;
2718    }
2719
2720    if (!(surface->pitches = xalloc(sizeof(int))))
2721	return BadAlloc;
2722    if (!(surface->offsets = xalloc(sizeof(int)))) {
2723	xfree(surface->pitches);
2724	return BadAlloc;
2725    }
2726    if (!(pPriv = xalloc(sizeof(OffscreenPrivRec)))) {
2727	xfree(surface->pitches);
2728	xfree(surface->offsets);
2729	return BadAlloc;
2730    }
2731
2732    w = (w + 1) & ~1;
2733    pitch = ((w << 1) + 15) & ~15;
2734    fbpitch = pI830->cpp * pScrn->displayWidth;
2735    size = pitch * h;
2736
2737    surface->width = w;
2738    surface->height = h;
2739
2740    pPriv->isOn = FALSE;
2741
2742    surface->pScrn = pScrn;
2743    surface->id = id;
2744    surface->pitches[0] = pitch;
2745    surface->offsets[0] = 0;
2746    surface->devPrivate.ptr = (pointer) pPriv;
2747
2748    return Success;
2749}
2750
2751static int
2752I830StopSurface(XF86SurfacePtr surface)
2753{
2754    OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr;
2755    ScrnInfoPtr pScrn = surface->pScrn;
2756
2757    if (pPriv->isOn) {
2758	OVERLAY_DEBUG("StopSurface\n");
2759
2760	i830_overlay_off (pScrn);
2761
2762	pPriv->isOn = FALSE;
2763    }
2764
2765    return Success;
2766}
2767
2768static int
2769I830FreeSurface(XF86SurfacePtr surface)
2770{
2771    I830StopSurface(surface);
2772    xfree(surface->pitches);
2773    xfree(surface->offsets);
2774    xfree(surface->devPrivate.ptr);
2775
2776    return Success;
2777}
2778
2779static int
2780I830GetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 * value)
2781{
2782    return I830GetPortAttribute(pScrn, attribute, value, NULL);
2783}
2784
2785static int
2786I830SetSurfaceAttribute(ScrnInfoPtr pScrn, Atom attribute, INT32 value)
2787{
2788    return I830SetPortAttributeOverlay(pScrn, attribute, value, NULL);
2789}
2790
2791static int
2792I830DisplaySurface(XF86SurfacePtr surface,
2793		   short src_x, short src_y,
2794		   short drw_x, short drw_y,
2795		   short src_w, short src_h,
2796		   short drw_w, short drw_h, RegionPtr clipBoxes)
2797{
2798    OffscreenPrivPtr pPriv = (OffscreenPrivPtr) surface->devPrivate.ptr;
2799    ScrnInfoPtr pScrn = surface->pScrn;
2800    ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
2801    I830Ptr pI830 = I830PTR(pScrn);
2802    I830PortPrivPtr pI830Priv = GET_PORT_PRIVATE(pScrn);
2803    INT32 x1, y1, x2, y2;
2804    BoxRec dstBox;
2805    xf86CrtcPtr crtc;
2806
2807    OVERLAY_DEBUG("I830DisplaySurface\n");
2808
2809    x1 = src_x;
2810    x2 = src_x + src_w;
2811    y1 = src_y;
2812    y2 = src_y + src_h;
2813
2814    dstBox.x1 = drw_x;
2815    dstBox.x2 = drw_x + drw_w;
2816    dstBox.y1 = drw_y;
2817    dstBox.y2 = drw_y + drw_h;
2818
2819    if (!i830_clip_video_helper (pScrn, pI830Priv, &crtc, &dstBox,
2820				 &x1, &x2, &y1, &y2, clipBoxes,
2821				 surface->width, surface->height))
2822	return Success;
2823
2824    /* fixup pointers */
2825    pI830Priv->YBuf0offset = surface->offsets[0];
2826    pI830Priv->YBuf1offset = pI830Priv->YBuf0offset;
2827
2828    /* Pick the idle buffer */
2829    if (!pI830Priv->textured && pI830->overlayOn && pI830Priv->doubleBuffer)
2830	pI830Priv->currentBuf = !((INREG(DOVSTA) & OC_BUF) >> 20);
2831
2832    i830_display_video(pScrn, crtc, surface->id, surface->width, surface->height,
2833		     surface->pitches[0], x1, y1, x2, y2, &dstBox,
2834		     src_w, src_h, drw_w, drw_h);
2835
2836    xf86XVFillKeyHelper(pScrn->pScreen, pI830Priv->colorKey, clipBoxes);
2837
2838    pPriv->isOn = TRUE;
2839    /* we've prempted the XvImage stream so set its free timer */
2840    if (pI830Priv->videoStatus & CLIENT_VIDEO_ON) {
2841	REGION_EMPTY(pScrn->pScreen, &pI830Priv->clip);
2842	UpdateCurrentTime();
2843	pI830Priv->videoStatus = FREE_TIMER;
2844	pI830Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
2845    }
2846
2847    return Success;
2848}
2849
2850static void
2851I830InitOffscreenImages(ScreenPtr pScreen)
2852{
2853    XF86OffscreenImagePtr offscreenImages;
2854    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
2855    I830Ptr pI830 = I830PTR(pScrn);
2856
2857    if (!(offscreenImages = xalloc(sizeof(XF86OffscreenImageRec)))) {
2858	return;
2859    }
2860
2861    pI830->offscreenImages = offscreenImages;
2862
2863    offscreenImages[0].image = &Images[0];
2864    offscreenImages[0].flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT*/;
2865    offscreenImages[0].alloc_surface = I830AllocateSurface;
2866    offscreenImages[0].free_surface = I830FreeSurface;
2867    offscreenImages[0].display = I830DisplaySurface;
2868    offscreenImages[0].stop = I830StopSurface;
2869    offscreenImages[0].setAttribute = I830SetSurfaceAttribute;
2870    offscreenImages[0].getAttribute = I830GetSurfaceAttribute;
2871    if (IS_845G(pI830) || IS_I830(pI830)) {
2872	offscreenImages[0].max_width = IMAGE_MAX_WIDTH_LEGACY;
2873	offscreenImages[0].max_height = IMAGE_MAX_HEIGHT_LEGACY;
2874    } else {
2875	offscreenImages[0].max_width = IMAGE_MAX_WIDTH;
2876	offscreenImages[0].max_height = IMAGE_MAX_HEIGHT;
2877    }
2878    offscreenImages[0].num_attributes = 1;
2879    offscreenImages[0].attributes = Attributes;
2880
2881    xf86XVRegisterOffscreenImages(pScreen, offscreenImages, 1);
2882}
2883
2884void
2885i830_crtc_dpms_video(xf86CrtcPtr crtc, Bool on)
2886{
2887    ScrnInfoPtr pScrn = crtc->scrn;
2888    I830Ptr pI830 = I830PTR(pScrn);
2889    I830PortPrivPtr pPriv;
2890
2891    /* no overlay */
2892    if (pI830->adaptor == NULL)
2893	return;
2894
2895    pPriv = GET_PORT_PRIVATE(pScrn);
2896
2897    if (crtc != pPriv->current_crtc)
2898	return;
2899
2900    /* Check if it's the crtc the overlay is off */
2901    if (!on) {
2902	/* We stop the video when mode switching, so we don't lock up
2903	 * the engine. The overlayOK will determine whether we can re-enable
2904	 * with the current video on completion of the mode switch.
2905	 */
2906	I830StopVideo(pScrn, pPriv, TRUE);
2907	pPriv->current_crtc = NULL;
2908	pPriv->overlayOK = FALSE;
2909	pPriv->oneLineMode = FALSE;
2910    }
2911}
2912