intel_video.c revision 42542f5f
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#include <errno.h>
57
58#include "xorg-server.h"
59#include "xf86.h"
60#include "xf86_OSproc.h"
61#include "compiler.h"
62#include "xf86Pci.h"
63#include "xf86fbman.h"
64#include "xf86drm.h"
65#include "regionstr.h"
66#include "randrstr.h"
67#include "windowstr.h"
68#include "damage.h"
69#include "intel.h"
70#include "intel_video.h"
71#include "i830_reg.h"
72#include "xf86xv.h"
73#include <X11/extensions/Xv.h>
74#include "dixstruct.h"
75#include "fourcc.h"
76
77#ifdef INTEL_XVMC
78#define _INTEL_XVMC_SERVER_
79#include "intel_xvmc.h"
80#endif
81#include "intel_glamor.h"
82
83#define OFF_DELAY	250	/* milliseconds */
84
85#define OFF_TIMER	0x01
86#define CLIENT_VIDEO_ON	0x02
87
88static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr);
89static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr);
90static void I830StopVideo(ScrnInfoPtr, pointer, Bool);
91static int I830SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer);
92static int I830SetPortAttributeTextured(ScrnInfoPtr, Atom, INT32, pointer);
93static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer);
94static void I830QueryBestSize(ScrnInfoPtr, Bool,
95			      short, short, short, short, unsigned int *,
96			      unsigned int *, pointer);
97static int I830PutImageTextured(ScrnInfoPtr, short, short, short, short, short, short,
98			short, short, int, unsigned char *, short, short,
99			Bool, RegionPtr, pointer, DrawablePtr);
100static int I830PutImageOverlay(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;
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/* client libraries expect an encoding */
130static const XF86VideoEncodingRec DummyEncoding[1] = {
131	{
132	 0,
133	 "XV_IMAGE",
134	 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
135	 {1, 1}
136	 }
137};
138
139#define NUM_FORMATS 3
140
141static XF86VideoFormatRec Formats[NUM_FORMATS] = {
142	{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
143};
144
145#define NUM_ATTRIBUTES 5
146static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
147	{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
148	{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
149	{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
150	{XvSettable | XvGettable, 0, 1023, "XV_SATURATION"},
151	{XvSettable | XvGettable, -1, 1, "XV_PIPE"}
152};
153
154#define GAMMA_ATTRIBUTES 6
155static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = {
156	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"},
157	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"},
158	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
159	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"},
160	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"},
161	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"}
162};
163
164#ifdef INTEL_XVMC
165#define NUM_IMAGES 5
166#define XVMC_IMAGE 1
167#else
168#define NUM_IMAGES 4
169#define XVMC_IMAGE 0
170#endif
171
172static XF86ImageRec Images[NUM_IMAGES] = {
173	XVIMAGE_YUY2,
174	XVIMAGE_YV12,
175	XVIMAGE_I420,
176	XVIMAGE_UYVY,
177#ifdef INTEL_XVMC
178	{
179	 /*
180	  * Below, a dummy picture type that is used in XvPutImage only to do
181	  * an overlay update. Introduced for the XvMC client lib.
182	  * Defined to have a zero data size.
183	  */
184	 FOURCC_XVMC,
185	 XvYUV,
186	 LSBFirst,
187	 {'X', 'V', 'M', 'C',
188	  0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00,
189	  0x38, 0x9B, 0x71},
190	 12,
191	 XvPlanar,
192	 3,
193	 0, 0, 0, 0,
194	 8, 8, 8,
195	 1, 2, 2,
196	 1, 2, 2,
197	 {'Y', 'V', 'U',
198	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
200	 XvTopToBottom},
201#endif
202};
203
204/* kernel modesetting overlay functions */
205static Bool intel_has_overlay(intel_screen_private *intel)
206{
207	struct drm_i915_getparam gp;
208	int has_overlay = 0;
209	int ret;
210
211	gp.param = I915_PARAM_HAS_OVERLAY;
212	gp.value = &has_overlay;
213	ret = drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, sizeof(gp));
214
215	return ret == 0 && !! has_overlay;
216}
217
218static Bool intel_overlay_update_attrs(intel_screen_private *intel)
219{
220	intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel);
221	struct drm_intel_overlay_attrs attrs;
222
223	attrs.flags = I915_OVERLAY_UPDATE_ATTRS;
224	attrs.brightness = adaptor_priv->brightness;
225	attrs.contrast = adaptor_priv->contrast;
226	attrs.saturation = adaptor_priv->saturation;
227	attrs.color_key = adaptor_priv->colorKey;
228	attrs.gamma0 = adaptor_priv->gamma0;
229	attrs.gamma1 = adaptor_priv->gamma1;
230	attrs.gamma2 = adaptor_priv->gamma2;
231	attrs.gamma3 = adaptor_priv->gamma3;
232	attrs.gamma4 = adaptor_priv->gamma4;
233	attrs.gamma5 = adaptor_priv->gamma5;
234
235	return drmCommandWriteRead(intel->drmSubFD, DRM_I915_OVERLAY_ATTRS,
236				   &attrs, sizeof(attrs)) == 0;
237}
238
239static void intel_overlay_off(intel_screen_private *intel)
240{
241	struct drm_intel_overlay_put_image request;
242	int ret;
243
244	request.flags = 0;
245
246	ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE,
247			      &request, sizeof(request));
248	(void) ret;
249}
250
251static Bool
252intel_overlay_put_image(intel_screen_private *intel,
253			  xf86CrtcPtr crtc,
254			  int id, short width, short height,
255			  int dstPitch, int dstPitch2,
256			  BoxPtr dstBox, short src_w, short src_h, short drw_w,
257			  short drw_h)
258{
259	intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel);
260	struct drm_intel_overlay_put_image request;
261	int ret;
262	int planar = is_planar_fourcc(id);
263	float scale;
264	dri_bo *tmp;
265
266	request.flags = I915_OVERLAY_ENABLE;
267
268	request.bo_handle = adaptor_priv->buf->handle;
269	if (planar) {
270		request.stride_Y = dstPitch2;
271		request.stride_UV = dstPitch;
272	} else {
273		request.stride_Y = dstPitch;
274		request.stride_UV = 0;
275	}
276	request.offset_Y = adaptor_priv->YBufOffset;
277	request.offset_U = adaptor_priv->UBufOffset;
278	request.offset_V = adaptor_priv->VBufOffset;
279	OVERLAY_DEBUG("off_Y: %i, off_U: %i, off_V: %i\n", request.offset_Y,
280		      request.offset_U, request.offset_V);
281
282	request.crtc_id = intel_crtc_id(crtc);
283	request.dst_x = dstBox->x1;
284	request.dst_y = dstBox->y1;
285	request.dst_width = dstBox->x2 - dstBox->x1;
286	request.dst_height = dstBox->y2 - dstBox->y1;
287
288	request.src_width = width;
289	request.src_height = height;
290	/* adjust src dimensions */
291	if (request.dst_height > 1) {
292		scale = ((float)request.dst_height - 1) / ((float)drw_h - 1);
293		request.src_scan_height = src_h * scale;
294	} else
295		request.src_scan_height = 1;
296
297	if (request.dst_width > 1) {
298		scale = ((float)request.dst_width - 1) / ((float)drw_w - 1);
299		request.src_scan_width = src_w * scale;
300	} else
301		request.src_scan_width = 1;
302
303	if (planar) {
304		request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420;
305	} else {
306		request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422;
307		if (id == FOURCC_UYVY)
308			request.flags |= I915_OVERLAY_Y_SWAP;
309	}
310
311	ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE,
312			      &request, sizeof(request));
313	if (ret)
314		return FALSE;
315
316	if (!adaptor_priv->reusable) {
317		drm_intel_bo_unreference(adaptor_priv->buf);
318		adaptor_priv->buf = NULL;
319		adaptor_priv->reusable = TRUE;
320	}
321
322	tmp = adaptor_priv->old_buf[1];
323	adaptor_priv->old_buf[1] = adaptor_priv->old_buf[0];
324	adaptor_priv->old_buf[0] = adaptor_priv->buf;
325	adaptor_priv->buf = tmp;
326
327	return TRUE;
328}
329
330void I830InitVideo(ScreenPtr screen)
331{
332	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
333	intel_screen_private *intel = intel_get_screen_private(scrn);
334	XF86VideoAdaptorPtr *adaptors = NULL, *newAdaptors = NULL;
335	XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL, glamorAdaptor = NULL;
336	int num_adaptors = xf86XVListGenericAdaptors(scrn, &adaptors);
337	/* Give our adaptor list enough space for the overlay and/or texture video
338	 * adaptors.
339	 */
340	newAdaptors = realloc(adaptors,
341			      (num_adaptors + 3) * sizeof(XF86VideoAdaptorPtr));
342	if (newAdaptors == NULL) {
343		free(adaptors);
344		return;
345	}
346	adaptors = newAdaptors;
347
348	/* Add the adaptors supported by our hardware.  First, set up the atoms
349	 * that will be used by both output adaptors.
350	 */
351	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
352	xvContrast = MAKE_ATOM("XV_CONTRAST");
353
354	/* Set up textured video if we can do it at this depth and we are on
355	 * supported hardware.
356	 */
357	if (!intel->force_fallback &&
358	    scrn->bitsPerPixel >= 16 &&
359	    INTEL_INFO(intel)->gen >= 030 &&
360	    INTEL_INFO(intel)->gen < 0100) {
361		texturedAdaptor = I830SetupImageVideoTextured(screen);
362		if (texturedAdaptor != NULL) {
363			xf86DrvMsg(scrn->scrnIndex, X_INFO,
364				   "Set up textured video\n");
365		} else {
366			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
367				   "Failed to set up textured video\n");
368		}
369	}
370
371	/* Set up overlay video if it is available */
372	intel->use_overlay = intel_has_overlay(intel);
373	if (intel->use_overlay) {
374		overlayAdaptor = I830SetupImageVideoOverlay(screen);
375		if (overlayAdaptor != NULL) {
376			xf86DrvMsg(scrn->scrnIndex, X_INFO,
377				   "Set up overlay video\n");
378		} else {
379			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
380				   "Failed to set up overlay video\n");
381		}
382	}
383
384	glamorAdaptor = intel_glamor_xv_init(screen, 16);
385	if (glamorAdaptor != NULL)
386		xf86DrvMsg(scrn->scrnIndex, X_INFO,
387			   "Set up textured video using glamor\n");
388
389	if (overlayAdaptor && intel->XvPreferOverlay)
390		adaptors[num_adaptors++] = overlayAdaptor;
391
392	if (texturedAdaptor)
393		adaptors[num_adaptors++] = texturedAdaptor;
394
395	if (glamorAdaptor)
396		adaptors[num_adaptors++] = glamorAdaptor;
397
398	if (overlayAdaptor && !intel->XvPreferOverlay)
399		adaptors[num_adaptors++] = overlayAdaptor;
400
401	if (num_adaptors) {
402		xf86XVScreenInit(screen, adaptors, num_adaptors);
403	} else {
404		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
405			   "Disabling Xv because no adaptors could be initialized.\n");
406		intel->XvEnabled = FALSE;
407	}
408
409#ifdef INTEL_XVMC
410	if (texturedAdaptor)
411		intel_xvmc_adaptor_init(screen);
412#endif
413	free(adaptors);
414}
415
416static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr screen)
417{
418	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
419	intel_screen_private *intel = intel_get_screen_private(scrn);
420	XF86VideoAdaptorPtr adapt;
421	intel_adaptor_private *adaptor_priv;
422	XF86AttributePtr att;
423
424	OVERLAY_DEBUG("I830SetupImageVideoOverlay\n");
425
426	if (!(adapt = calloc(1,
427			     sizeof(XF86VideoAdaptorRec) +
428			     sizeof(intel_adaptor_private) +
429			     sizeof(DevUnion))))
430		return NULL;
431
432	adapt->type = XvWindowMask | XvInputMask | XvImageMask;
433	adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ;
434	adapt->name = "Intel(R) Video Overlay";
435	adapt->nEncodings = 1;
436	adapt->pEncodings = xnfalloc(sizeof(DummyEncoding));
437	memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding));
438	if (IS_845G(intel) || IS_I830(intel)) {
439		adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY;
440		adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY;
441	}
442	adapt->nFormats = NUM_FORMATS;
443	adapt->pFormats = Formats;
444	adapt->nPorts = 1;
445	adapt->pPortPrivates = (DevUnion *) (&adapt[1]);
446
447	adaptor_priv = (intel_adaptor_private *)&adapt->pPortPrivates[1];
448
449	adapt->pPortPrivates[0].ptr = (pointer) (adaptor_priv);
450	adapt->nAttributes = NUM_ATTRIBUTES;
451	if (INTEL_INFO(intel)->gen >= 030)
452		adapt->nAttributes += GAMMA_ATTRIBUTES;	/* has gamma */
453	adapt->pAttributes =
454	    xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes);
455	/* Now copy the attributes */
456	att = adapt->pAttributes;
457	memcpy((char *)att, (char *)Attributes,
458	       sizeof(XF86AttributeRec) * NUM_ATTRIBUTES);
459	att += NUM_ATTRIBUTES;
460	if (INTEL_INFO(intel)->gen >= 030) {
461		memcpy((char *)att, (char *)GammaAttributes,
462		       sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES);
463	}
464	adapt->nImages = NUM_IMAGES - XVMC_IMAGE;
465
466	adapt->pImages = Images;
467	adapt->PutVideo = NULL;
468	adapt->PutStill = NULL;
469	adapt->GetVideo = NULL;
470	adapt->GetStill = NULL;
471	adapt->StopVideo = I830StopVideo;
472	adapt->SetPortAttribute = I830SetPortAttributeOverlay;
473	adapt->GetPortAttribute = I830GetPortAttribute;
474	adapt->QueryBestSize = I830QueryBestSize;
475	adapt->PutImage = I830PutImageOverlay;
476	adapt->QueryImageAttributes = I830QueryImageAttributes;
477
478	adaptor_priv->textured = FALSE;
479	adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1);
480	adaptor_priv->videoStatus = 0;
481	adaptor_priv->brightness = -19;	/* (255/219) * -16 */
482	adaptor_priv->contrast = 75;	/* 255/219 * 64 */
483	adaptor_priv->saturation = 146;	/* 128/112 * 128 */
484	adaptor_priv->desired_crtc = NULL;
485	adaptor_priv->buf = NULL;
486	adaptor_priv->old_buf[0] = NULL;
487	adaptor_priv->old_buf[1] = NULL;
488	adaptor_priv->gamma5 = 0xc0c0c0;
489	adaptor_priv->gamma4 = 0x808080;
490	adaptor_priv->gamma3 = 0x404040;
491	adaptor_priv->gamma2 = 0x202020;
492	adaptor_priv->gamma1 = 0x101010;
493	adaptor_priv->gamma0 = 0x080808;
494
495	adaptor_priv->rotation = RR_Rotate_0;
496
497	/* gotta uninit this someplace */
498	REGION_NULL(screen, &adaptor_priv->clip);
499
500	intel->adaptor = adapt;
501
502	xvColorKey = MAKE_ATOM("XV_COLORKEY");
503	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
504	xvContrast = MAKE_ATOM("XV_CONTRAST");
505	xvSaturation = MAKE_ATOM("XV_SATURATION");
506
507	/* Allow the pipe to be switched from pipe A to B when in clone mode */
508	xvPipe = MAKE_ATOM("XV_PIPE");
509
510	if (INTEL_INFO(intel)->gen >= 030) {
511		xvGamma0 = MAKE_ATOM("XV_GAMMA0");
512		xvGamma1 = MAKE_ATOM("XV_GAMMA1");
513		xvGamma2 = MAKE_ATOM("XV_GAMMA2");
514		xvGamma3 = MAKE_ATOM("XV_GAMMA3");
515		xvGamma4 = MAKE_ATOM("XV_GAMMA4");
516		xvGamma5 = MAKE_ATOM("XV_GAMMA5");
517	}
518
519	intel_overlay_update_attrs(intel);
520
521	return adapt;
522}
523
524static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr screen)
525{
526	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
527	intel_screen_private *intel = intel_get_screen_private(scrn);
528	XF86VideoAdaptorPtr adapt;
529	intel_adaptor_private *adaptor_privs;
530	DevUnion *devUnions;
531	int nports = 16, i;
532
533	OVERLAY_DEBUG("I830SetupImageVideoOverlay\n");
534
535	adapt = calloc(1, sizeof(XF86VideoAdaptorRec));
536	adaptor_privs = calloc(nports, sizeof(intel_adaptor_private));
537	devUnions = calloc(nports, sizeof(DevUnion));
538	if (adapt == NULL || adaptor_privs == NULL || devUnions == NULL) {
539		free(adapt);
540		free(adaptor_privs);
541		free(devUnions);
542		return NULL;
543	}
544
545	adapt->type = XvWindowMask | XvInputMask | XvImageMask;
546	adapt->flags = 0;
547	adapt->name = "Intel(R) Textured Video";
548	adapt->nEncodings = 1;
549	adapt->pEncodings = xnfalloc(sizeof(DummyEncoding));
550	memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding));
551	adapt->nFormats = NUM_FORMATS;
552	adapt->pFormats = Formats;
553	adapt->nPorts = nports;
554	adapt->pPortPrivates = devUnions;
555	adapt->nAttributes = 0;
556	adapt->pAttributes = NULL;
557	if (IS_I915G(intel) || IS_I915GM(intel))
558		adapt->nImages = NUM_IMAGES - XVMC_IMAGE;
559	else
560		adapt->nImages = NUM_IMAGES;
561
562	adapt->pImages = Images;
563	adapt->PutVideo = NULL;
564	adapt->PutStill = NULL;
565	adapt->GetVideo = NULL;
566	adapt->GetStill = NULL;
567	adapt->StopVideo = I830StopVideo;
568	adapt->SetPortAttribute = I830SetPortAttributeTextured;
569	adapt->GetPortAttribute = I830GetPortAttribute;
570	adapt->QueryBestSize = I830QueryBestSize;
571	adapt->PutImage = I830PutImageTextured;
572	adapt->QueryImageAttributes = I830QueryImageAttributes;
573
574	for (i = 0; i < nports; i++) {
575		intel_adaptor_private *adaptor_priv = &adaptor_privs[i];
576
577		adaptor_priv->textured = TRUE;
578		adaptor_priv->videoStatus = 0;
579		adaptor_priv->buf = NULL;
580		adaptor_priv->old_buf[0] = NULL;
581		adaptor_priv->old_buf[1] = NULL;
582
583		adaptor_priv->rotation = RR_Rotate_0;
584		adaptor_priv->SyncToVblank = 1;
585
586		/* gotta uninit this someplace, XXX: shouldn't be necessary for textured */
587		REGION_NULL(screen, &adaptor_priv->clip);
588
589		adapt->pPortPrivates[i].ptr = (pointer) (adaptor_priv);
590	}
591
592	xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK");
593
594	return adapt;
595}
596
597static void intel_free_video_buffers(intel_adaptor_private *adaptor_priv)
598{
599	int i;
600
601	for (i = 0; i < 2; i++) {
602		if (adaptor_priv->old_buf[i]) {
603			drm_intel_bo_disable_reuse(adaptor_priv->old_buf[i]);
604			drm_intel_bo_unreference(adaptor_priv->old_buf[i]);
605			adaptor_priv->old_buf[i] = NULL;
606		}
607	}
608
609	if (adaptor_priv->buf) {
610		drm_intel_bo_unreference(adaptor_priv->buf);
611		adaptor_priv->buf = NULL;
612	}
613}
614
615static void I830StopVideo(ScrnInfoPtr scrn, pointer data, Bool shutdown)
616{
617	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
618
619	if (adaptor_priv->textured)
620		return;
621
622	OVERLAY_DEBUG("I830StopVideo\n");
623
624	REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip);
625
626	if (shutdown) {
627		if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON)
628			intel_overlay_off(intel_get_screen_private(scrn));
629
630		intel_free_video_buffers(adaptor_priv);
631		adaptor_priv->videoStatus = 0;
632	} else {
633		if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) {
634			adaptor_priv->videoStatus |= OFF_TIMER;
635			adaptor_priv->offTime = currentTime.milliseconds + OFF_DELAY;
636		}
637	}
638
639}
640
641static int
642I830SetPortAttributeTextured(ScrnInfoPtr scrn,
643			     Atom attribute, INT32 value, pointer data)
644{
645	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
646
647	if (attribute == xvBrightness) {
648		if ((value < -128) || (value > 127))
649			return BadValue;
650		adaptor_priv->brightness = value;
651		return Success;
652	} else if (attribute == xvContrast) {
653		if ((value < 0) || (value > 255))
654			return BadValue;
655		adaptor_priv->contrast = value;
656		return Success;
657	} else if (attribute == xvSyncToVblank) {
658		if ((value < -1) || (value > 1))
659			return BadValue;
660		adaptor_priv->SyncToVblank = value;
661		return Success;
662	} else {
663		return BadMatch;
664	}
665}
666
667static int
668I830SetPortAttributeOverlay(ScrnInfoPtr scrn,
669			    Atom attribute, INT32 value, pointer data)
670{
671	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
672	intel_screen_private *intel = intel_get_screen_private(scrn);
673
674	if (attribute == xvBrightness) {
675		if ((value < -128) || (value > 127))
676			return BadValue;
677		adaptor_priv->brightness = value;
678		OVERLAY_DEBUG("BRIGHTNESS\n");
679	} else if (attribute == xvContrast) {
680		if ((value < 0) || (value > 255))
681			return BadValue;
682		adaptor_priv->contrast = value;
683		OVERLAY_DEBUG("CONTRAST\n");
684	} else if (attribute == xvSaturation) {
685		if ((value < 0) || (value > 1023))
686			return BadValue;
687		adaptor_priv->saturation = value;
688	} else if (attribute == xvPipe) {
689		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
690		if ((value < -1) || (value >= xf86_config->num_crtc))
691			return BadValue;
692		if (value < 0)
693			adaptor_priv->desired_crtc = NULL;
694		else
695			adaptor_priv->desired_crtc = xf86_config->crtc[value];
696	} else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) {
697		adaptor_priv->gamma0 = value;
698	} else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) {
699		adaptor_priv->gamma1 = value;
700	} else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) {
701		adaptor_priv->gamma2 = value;
702	} else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) {
703		adaptor_priv->gamma3 = value;
704	} else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) {
705		adaptor_priv->gamma4 = value;
706	} else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) {
707		adaptor_priv->gamma5 = value;
708	} else if (attribute == xvColorKey) {
709		adaptor_priv->colorKey = value;
710		OVERLAY_DEBUG("COLORKEY\n");
711	} else
712		return BadMatch;
713
714	if ((attribute == xvGamma0 ||
715	     attribute == xvGamma1 ||
716	     attribute == xvGamma2 ||
717	     attribute == xvGamma3 ||
718	     attribute == xvGamma4 ||
719	     attribute == xvGamma5) && (INTEL_INFO(intel)->gen >= 030)) {
720		OVERLAY_DEBUG("GAMMA\n");
721	}
722
723	if (!intel_overlay_update_attrs(intel))
724		return BadValue;
725
726	if (attribute == xvColorKey)
727		REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip);
728
729	return Success;
730}
731
732static int
733I830GetPortAttribute(ScrnInfoPtr scrn,
734		     Atom attribute, INT32 * value, pointer data)
735{
736	intel_screen_private *intel = intel_get_screen_private(scrn);
737	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
738
739	if (attribute == xvBrightness) {
740		*value = adaptor_priv->brightness;
741	} else if (attribute == xvContrast) {
742		*value = adaptor_priv->contrast;
743	} else if (attribute == xvSaturation) {
744		*value = adaptor_priv->saturation;
745	} else if (attribute == xvPipe) {
746		int c;
747		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
748		for (c = 0; c < xf86_config->num_crtc; c++)
749			if (xf86_config->crtc[c] == adaptor_priv->desired_crtc)
750				break;
751		if (c == xf86_config->num_crtc)
752			c = -1;
753		*value = c;
754	} else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) {
755		*value = adaptor_priv->gamma0;
756	} else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) {
757		*value = adaptor_priv->gamma1;
758	} else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) {
759		*value = adaptor_priv->gamma2;
760	} else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) {
761		*value = adaptor_priv->gamma3;
762	} else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) {
763		*value = adaptor_priv->gamma4;
764	} else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) {
765		*value = adaptor_priv->gamma5;
766	} else if (attribute == xvColorKey) {
767		*value = adaptor_priv->colorKey;
768	} else if (attribute == xvSyncToVblank) {
769		*value = adaptor_priv->SyncToVblank;
770	} else
771		return BadMatch;
772
773	return Success;
774}
775
776static void
777I830QueryBestSize(ScrnInfoPtr scrn,
778		  Bool motion,
779		  short vid_w, short vid_h,
780		  short drw_w, short drw_h,
781		  unsigned int *p_w, unsigned int *p_h, pointer data)
782{
783	if (vid_w > (drw_w << 1))
784		drw_w = vid_w >> 1;
785	if (vid_h > (drw_h << 1))
786		drw_h = vid_h >> 1;
787
788	*p_w = drw_w;
789	*p_h = drw_h;
790}
791
792static Bool
793I830CopyPackedData(intel_adaptor_private *adaptor_priv,
794		   unsigned char *buf,
795		   int srcPitch, int dstPitch, int top, int left, int h, int w)
796{
797	unsigned char *src, *dst, *dst_base;
798	int i, j;
799	unsigned char *s;
800
801#if 0
802	ErrorF("I830CopyPackedData: (%d,%d) (%d,%d)\n"
803	       "srcPitch: %d, dstPitch: %d\n", top, left, h, w,
804	       srcPitch, dstPitch);
805#endif
806
807	src = buf + (top * srcPitch) + (left << 1);
808
809	if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf))
810		return FALSE;
811
812	dst_base = adaptor_priv->buf->virtual;
813
814	dst = dst_base + adaptor_priv->YBufOffset;
815
816	switch (adaptor_priv->rotation) {
817	case RR_Rotate_0:
818		w <<= 1;
819		for (i = 0; i < h; i++) {
820			memcpy(dst, src, w);
821			src += srcPitch;
822			dst += dstPitch;
823		}
824		break;
825	case RR_Rotate_90:
826		h <<= 1;
827		for (i = 0; i < h; i += 2) {
828			s = src;
829			for (j = 0; j < w; j++) {
830				/* Copy Y */
831				dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++;
832				(void)*s++;
833			}
834			src += srcPitch;
835		}
836		h >>= 1;
837		src = buf + (top * srcPitch) + (left << 1);
838		for (i = 0; i < h; i += 2) {
839			for (j = 0; j < w; j += 2) {
840				/* Copy U */
841				dst[((i * 2) + 1) + ((w - j - 1) * dstPitch)] =
842				    src[(j * 2) + 1 + (i * srcPitch)];
843				dst[((i * 2) + 1) + ((w - j - 2) * dstPitch)] =
844				    src[(j * 2) + 1 + ((i + 1) * srcPitch)];
845				/* Copy V */
846				dst[((i * 2) + 3) + ((w - j - 1) * dstPitch)] =
847				    src[(j * 2) + 3 + (i * srcPitch)];
848				dst[((i * 2) + 3) + ((w - j - 2) * dstPitch)] =
849				    src[(j * 2) + 3 + ((i + 1) * srcPitch)];
850			}
851		}
852		break;
853	case RR_Rotate_180:
854		w <<= 1;
855		for (i = 0; i < h; i++) {
856			s = src;
857			for (j = 0; j < w; j += 4) {
858				dst[(w - j - 4) + ((h - i - 1) * dstPitch)] =
859				    *s++;
860				dst[(w - j - 3) + ((h - i - 1) * dstPitch)] =
861				    *s++;
862				dst[(w - j - 2) + ((h - i - 1) * dstPitch)] =
863				    *s++;
864				dst[(w - j - 1) + ((h - i - 1) * dstPitch)] =
865				    *s++;
866			}
867			src += srcPitch;
868		}
869		break;
870	case RR_Rotate_270:
871		h <<= 1;
872		for (i = 0; i < h; i += 2) {
873			s = src;
874			for (j = 0; j < w; j++) {
875				/* Copy Y */
876				dst[(h - i - 2) + (j * dstPitch)] = *s++;
877				(void)*s++;
878			}
879			src += srcPitch;
880		}
881		h >>= 1;
882		src = buf + (top * srcPitch) + (left << 1);
883		for (i = 0; i < h; i += 2) {
884			for (j = 0; j < w; j += 2) {
885				/* Copy U */
886				dst[(((h - i) * 2) - 3) + (j * dstPitch)] =
887				    src[(j * 2) + 1 + (i * srcPitch)];
888				dst[(((h - i) * 2) - 3) +
889				    ((j + 1) * dstPitch)] =
890				    src[(j * 2) + 1 + ((i + 1) * srcPitch)];
891				/* Copy V */
892				dst[(((h - i) * 2) - 1) + (j * dstPitch)] =
893				    src[(j * 2) + 3 + (i * srcPitch)];
894				dst[(((h - i) * 2) - 1) +
895				    ((j + 1) * dstPitch)] =
896				    src[(j * 2) + 3 + ((i + 1) * srcPitch)];
897			}
898		}
899		break;
900	}
901
902	drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf);
903	return TRUE;
904}
905
906static void intel_memcpy_plane(unsigned char *dst, unsigned char *src,
907			       int height, int width,
908			       int dstPitch, int srcPitch, Rotation rotation)
909{
910	int i, j = 0;
911	unsigned char *s;
912
913	switch (rotation) {
914	case RR_Rotate_0:
915		/* optimise for the case of no clipping */
916		if (srcPitch == dstPitch && srcPitch == width)
917			memcpy(dst, src, srcPitch * height);
918		else
919			for (i = 0; i < height; i++) {
920				memcpy(dst, src, width);
921				src += srcPitch;
922				dst += dstPitch;
923			}
924		break;
925	case RR_Rotate_90:
926		for (i = 0; i < height; i++) {
927			s = src;
928			for (j = 0; j < width; j++) {
929				dst[(i) + ((width - j - 1) * dstPitch)] = *s++;
930			}
931			src += srcPitch;
932		}
933		break;
934	case RR_Rotate_180:
935		for (i = 0; i < height; i++) {
936			s = src;
937			for (j = 0; j < width; j++) {
938				dst[(width - j - 1) +
939				    ((height - i - 1) * dstPitch)] = *s++;
940			}
941			src += srcPitch;
942		}
943		break;
944	case RR_Rotate_270:
945		for (i = 0; i < height; i++) {
946			s = src;
947			for (j = 0; j < width; j++) {
948				dst[(height - i - 1) + (j * dstPitch)] = *s++;
949			}
950			src += srcPitch;
951		}
952		break;
953	}
954}
955
956static Bool
957I830CopyPlanarData(intel_adaptor_private *adaptor_priv,
958		   unsigned char *buf, int srcPitch, int srcPitch2,
959		   int dstPitch, int dstPitch2,
960		   int srcH, int top, int left,
961		   int h, int w, int id)
962{
963	unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3;
964
965#if 0
966	ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n"
967	       "nlines %d, npixels %d, top %d, left %d\n",
968	       srcPitch, srcPitch2, dstPitch, h, w, top, left);
969#endif
970
971	/* Copy Y data */
972	src1 = buf + (top * srcPitch) + left;
973#if 0
974	ErrorF("src1 is %p, offset is %ld\n", src1,
975	       (unsigned long)src1 - (unsigned long)buf);
976#endif
977
978	if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf))
979		return FALSE;
980
981	dst_base = adaptor_priv->buf->virtual;
982
983	dst1 = dst_base + adaptor_priv->YBufOffset;
984
985	intel_memcpy_plane(dst1, src1, h, w, dstPitch2, srcPitch,
986			  adaptor_priv->rotation);
987
988	/* Copy V data for YV12, or U data for I420 */
989	src2 = buf +		/* start of YUV data */
990	    (srcH * srcPitch) +	/* move over Luma plane */
991	    ((top >> 1) * srcPitch2) +	/* move down from by top lines */
992	    (left >> 1);	/* move left by left pixels */
993
994#if 0
995	ErrorF("src2 is %p, offset is %ld\n", src2,
996	       (unsigned long)src2 - (unsigned long)buf);
997#endif
998	if (id == FOURCC_I420)
999		dst2 = dst_base + adaptor_priv->UBufOffset;
1000	else
1001		dst2 = dst_base + adaptor_priv->VBufOffset;
1002
1003	intel_memcpy_plane(dst2, src2, h / 2, w / 2,
1004			  dstPitch, srcPitch2, adaptor_priv->rotation);
1005
1006	/* Copy U data for YV12, or V data for I420 */
1007	src3 = buf +		/* start of YUV data */
1008	    (srcH * srcPitch) +	/* move over Luma plane */
1009	    ((srcH >> 1) * srcPitch2) +	/* move over Chroma plane */
1010	    ((top >> 1) * srcPitch2) +	/* move down from by top lines */
1011	    (left >> 1);	/* move left by left pixels */
1012#if 0
1013	ErrorF("src3 is %p, offset is %ld\n", src3,
1014	       (unsigned long)src3 - (unsigned long)buf);
1015#endif
1016	if (id == FOURCC_I420)
1017		dst3 = dst_base + adaptor_priv->VBufOffset;
1018	else
1019		dst3 = dst_base + adaptor_priv->UBufOffset;
1020
1021	intel_memcpy_plane(dst3, src3, h / 2, w / 2,
1022			  dstPitch, srcPitch2, adaptor_priv->rotation);
1023
1024	drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf);
1025	return TRUE;
1026}
1027
1028static void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
1029{
1030	dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
1031	dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
1032	if (dest->x1 >= dest->x2) {
1033		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
1034		return;
1035	}
1036
1037	dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1;
1038	dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2;
1039	if (dest->y1 >= dest->y2)
1040		dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
1041}
1042
1043static void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
1044{
1045	if (crtc->enabled) {
1046		crtc_box->x1 = crtc->x;
1047		crtc_box->x2 =
1048		    crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
1049		crtc_box->y1 = crtc->y;
1050		crtc_box->y2 =
1051		    crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
1052	} else
1053		crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
1054}
1055
1056static int intel_box_area(BoxPtr box)
1057{
1058	return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
1059}
1060
1061/*
1062 * Return the crtc covering 'box'. If two crtcs cover a portion of
1063 * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc
1064 * with greater coverage
1065 */
1066
1067xf86CrtcPtr
1068intel_covering_crtc(ScrnInfoPtr scrn,
1069		    BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret)
1070{
1071	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1072	xf86CrtcPtr crtc, best_crtc;
1073	int coverage, best_coverage;
1074	int c;
1075	BoxRec crtc_box, cover_box;
1076
1077	best_crtc = NULL;
1078	best_coverage = 0;
1079	crtc_box_ret->x1 = 0;
1080	crtc_box_ret->x2 = 0;
1081	crtc_box_ret->y1 = 0;
1082	crtc_box_ret->y2 = 0;
1083	for (c = 0; c < xf86_config->num_crtc; c++) {
1084		crtc = xf86_config->crtc[c];
1085
1086		/* If the CRTC is off, treat it as not covering */
1087		if (!intel_crtc_on(crtc))
1088			continue;
1089
1090		intel_crtc_box(crtc, &crtc_box);
1091		intel_box_intersect(&cover_box, &crtc_box, box);
1092		coverage = intel_box_area(&cover_box);
1093		if (coverage && crtc == desired) {
1094			*crtc_box_ret = crtc_box;
1095			return crtc;
1096		}
1097		if (coverage > best_coverage) {
1098			*crtc_box_ret = crtc_box;
1099			best_crtc = crtc;
1100			best_coverage = coverage;
1101		}
1102	}
1103	return best_crtc;
1104}
1105
1106static void
1107intel_update_dst_box_to_crtc_coords(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
1108				    BoxPtr dstBox)
1109{
1110	int tmp;
1111
1112	/* for overlay, we should take it from crtc's screen
1113	 * coordinate to current crtc's display mode.
1114	 * yeah, a bit confusing.
1115	 */
1116	switch (crtc->rotation & 0xf) {
1117	case RR_Rotate_0:
1118		dstBox->x1 -= crtc->x;
1119		dstBox->x2 -= crtc->x;
1120		dstBox->y1 -= crtc->y;
1121		dstBox->y2 -= crtc->y;
1122		break;
1123	case RR_Rotate_90:
1124		tmp = dstBox->x1;
1125		dstBox->x1 = dstBox->y1 - crtc->x;
1126		dstBox->y1 = scrn->virtualX - tmp - crtc->y;
1127		tmp = dstBox->x2;
1128		dstBox->x2 = dstBox->y2 - crtc->x;
1129		dstBox->y2 = scrn->virtualX - tmp - crtc->y;
1130		tmp = dstBox->y1;
1131		dstBox->y1 = dstBox->y2;
1132		dstBox->y2 = tmp;
1133		break;
1134	case RR_Rotate_180:
1135		tmp = dstBox->x1;
1136		dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x;
1137		dstBox->x2 = scrn->virtualX - tmp - crtc->x;
1138		tmp = dstBox->y1;
1139		dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y;
1140		dstBox->y2 = scrn->virtualY - tmp - crtc->y;
1141		break;
1142	case RR_Rotate_270:
1143		tmp = dstBox->x1;
1144		dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x;
1145		dstBox->y1 = tmp - crtc->y;
1146		tmp = dstBox->x2;
1147		dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x;
1148		dstBox->y2 = tmp - crtc->y;
1149		tmp = dstBox->x1;
1150		dstBox->x1 = dstBox->x2;
1151		dstBox->x2 = tmp;
1152		break;
1153	}
1154
1155	return;
1156}
1157
1158int is_planar_fourcc(int id)
1159{
1160	switch (id) {
1161	case FOURCC_YV12:
1162	case FOURCC_I420:
1163#ifdef INTEL_XVMC
1164	case FOURCC_XVMC:
1165#endif
1166		return 1;
1167	case FOURCC_UYVY:
1168	case FOURCC_YUY2:
1169		return 0;
1170	default:
1171		ErrorF("Unknown format 0x%x\n", id);
1172		return 0;
1173	}
1174}
1175
1176static int xvmc_passthrough(int id)
1177{
1178#ifdef INTEL_XVMC
1179	return id == FOURCC_XVMC;
1180#else
1181	return 0;
1182#endif
1183}
1184
1185static Bool
1186intel_display_overlay(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
1187		      int id, short width, short height,
1188		      int dstPitch, int dstPitch2,
1189		      BoxPtr dstBox, short src_w, short src_h, short drw_w,
1190		      short drw_h)
1191{
1192	intel_screen_private *intel = intel_get_screen_private(scrn);
1193	int tmp;
1194
1195	OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height,
1196		      dstPitch);
1197
1198	/*
1199	 * If the video isn't visible on any CRTC, turn it off
1200	 */
1201	if (!crtc) {
1202		intel_overlay_off(intel);
1203		return TRUE;
1204	}
1205
1206	intel_update_dst_box_to_crtc_coords(scrn, crtc, dstBox);
1207
1208	if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1209		tmp = width;
1210		width = height;
1211		height = tmp;
1212		tmp = drw_w;
1213		drw_w = drw_h;
1214		drw_h = tmp;
1215		tmp = src_w;
1216		src_w = src_h;
1217		src_h = tmp;
1218	}
1219
1220	return intel_overlay_put_image(intel, crtc, id,
1221					 width, height,
1222					 dstPitch, dstPitch2, dstBox,
1223					 src_w, src_h, drw_w, drw_h);
1224}
1225
1226static Bool
1227intel_clip_video_helper(ScrnInfoPtr scrn,
1228			intel_adaptor_private *adaptor_priv,
1229			xf86CrtcPtr * crtc_ret,
1230			BoxPtr dst,
1231			short src_x, short src_y,
1232			short drw_x, short drw_y,
1233			short src_w, short src_h,
1234			short drw_w, short drw_h,
1235			int id,
1236			int *top, int* left, int* npixels, int *nlines,
1237			RegionPtr reg, INT32 width, INT32 height)
1238{
1239	Bool ret;
1240	RegionRec crtc_region_local;
1241	RegionPtr crtc_region = reg;
1242	BoxRec crtc_box;
1243	INT32 x1, x2, y1, y2;
1244	xf86CrtcPtr crtc;
1245
1246	x1 = src_x;
1247	x2 = src_x + src_w;
1248	y1 = src_y;
1249	y2 = src_y + src_h;
1250
1251	dst->x1 = drw_x;
1252	dst->x2 = drw_x + drw_w;
1253	dst->y1 = drw_y;
1254	dst->y2 = drw_y + drw_h;
1255
1256	/*
1257	 * For overlay video, compute the relevant CRTC and
1258	 * clip video to that
1259	 */
1260	crtc = intel_covering_crtc(scrn, dst, adaptor_priv->desired_crtc,
1261				   &crtc_box);
1262
1263	/* For textured video, we don't actually want to clip at all. */
1264	if (crtc && !adaptor_priv->textured) {
1265		REGION_INIT(screen, &crtc_region_local, &crtc_box, 1);
1266		crtc_region = &crtc_region_local;
1267		REGION_INTERSECT(screen, crtc_region, crtc_region,
1268				 reg);
1269	}
1270	*crtc_ret = crtc;
1271
1272	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
1273				    crtc_region, width, height);
1274	if (crtc_region != reg)
1275		REGION_UNINIT(screen, &crtc_region_local);
1276
1277	*top = y1 >> 16;
1278	*left = (x1 >> 16) & ~1;
1279	*npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - *left;
1280	if (is_planar_fourcc(id)) {
1281		*top &= ~1;
1282		*nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - *top;
1283	} else
1284		*nlines = ((y2 + 0xffff) >> 16) - *top;
1285
1286	return ret;
1287}
1288
1289static void
1290intel_wait_for_scanline(ScrnInfoPtr scrn, PixmapPtr pixmap,
1291			xf86CrtcPtr crtc, RegionPtr clipBoxes)
1292{
1293	intel_screen_private *intel = intel_get_screen_private(scrn);
1294	pixman_box16_t box, crtc_box;
1295	int pipe, event;
1296	Bool full_height;
1297	int y1, y2;
1298
1299	pipe = -1;
1300	if (scrn->vtSema && pixmap_is_scanout(pixmap))
1301		pipe = intel_crtc_to_pipe(crtc);
1302	if (pipe < 0)
1303		return;
1304
1305	box = *REGION_EXTENTS(unused, clipBoxes);
1306
1307	if (crtc->transform_in_use)
1308		pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
1309
1310	/* We could presume the clip was correctly computed... */
1311	intel_crtc_box(crtc, &crtc_box);
1312	intel_box_intersect(&box, &crtc_box, &box);
1313
1314	/*
1315	 * Make sure we don't wait for a scanline that will
1316	 * never occur
1317	 */
1318	y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
1319	y2 = (box.y2 <= crtc_box.y2) ?
1320		box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
1321	if (y2 <= y1)
1322		return;
1323
1324	full_height = FALSE;
1325	if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
1326		full_height = TRUE;
1327
1328	/*
1329	 * Pre-965 doesn't have SVBLANK, so we need a bit
1330	 * of extra time for the blitter to start up and
1331	 * do its job for a full height blit
1332	 */
1333	if (full_height && INTEL_INFO(intel)->gen < 040)
1334		y2 -= 2;
1335
1336	if (pipe == 0) {
1337		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
1338		event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
1339		if (full_height && INTEL_INFO(intel)->gen >= 040)
1340			event = MI_WAIT_FOR_PIPEA_SVBLANK;
1341	} else {
1342		pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB;
1343		event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
1344		if (full_height && INTEL_INFO(intel)->gen >= 040)
1345			event = MI_WAIT_FOR_PIPEB_SVBLANK;
1346	}
1347
1348	if (crtc->mode.Flags & V_INTERLACE) {
1349		/* DSL count field lines */
1350		y1 /= 2;
1351		y2 /= 2;
1352	}
1353
1354	BEGIN_BATCH(5);
1355	/* The documentation says that the LOAD_SCAN_LINES command
1356	 * always comes in pairs. Don't ask me why. */
1357	OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe);
1358	OUT_BATCH((y1 << 16) | (y2-1));
1359	OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe);
1360	OUT_BATCH((y1 << 16) | (y2-1));
1361	OUT_BATCH(MI_WAIT_FOR_EVENT | event);
1362	ADVANCE_BATCH();
1363}
1364
1365static Bool
1366intel_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
1367			 int alloc_size, int id, unsigned char *buf)
1368{
1369	intel_screen_private *intel = intel_get_screen_private(scrn);
1370
1371	/* Free the current buffer if we're going to have to reallocate */
1372	if (adaptor_priv->buf && adaptor_priv->buf->size < alloc_size)
1373		intel_free_video_buffers(adaptor_priv);
1374
1375	if (adaptor_priv->buf == NULL) {
1376		adaptor_priv->buf = drm_intel_bo_alloc(intel->bufmgr, "xv buffer",
1377						       alloc_size, 4096);
1378		if (adaptor_priv->buf == NULL)
1379			return FALSE;
1380
1381		adaptor_priv->reusable = TRUE;
1382	}
1383
1384	return TRUE;
1385}
1386
1387static void
1388intel_setup_dst_params(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, short width,
1389		       short height, int *dstPitch, int *dstPitch2, int *size,
1390		       int id)
1391{
1392	intel_screen_private *intel = intel_get_screen_private(scrn);
1393	int pitchAlign;
1394
1395	/* Only needs to be DWORD-aligned for textured on i915, but overlay has
1396	 * stricter requirements.
1397	 */
1398	if (adaptor_priv->textured) {
1399		pitchAlign = 4;
1400	} else {
1401		if (INTEL_INFO(intel)->gen >= 040)
1402			/* Actually the alignment is 64 bytes, too. But the
1403			 * stride must be at least 512 bytes. Take the easy fix
1404			 * and align on 512 bytes unconditionally. */
1405			pitchAlign = 512;
1406		else if (IS_I830(intel) || IS_845G(intel))
1407			/* Harsh, errata on these chipsets limit the stride to be
1408			 * a multiple of 256 bytes.
1409			 */
1410			pitchAlign = 256;
1411		else
1412			pitchAlign = 64;
1413	}
1414
1415#if INTEL_XVMC
1416	/* for i915 xvmc, hw requires 1kb aligned surfaces */
1417	if ((id == FOURCC_XVMC) && IS_GEN3(intel))
1418		pitchAlign = 1024;
1419#endif
1420
1421	/* Determine the desired destination pitch (representing the chroma's pitch,
1422	 * in the planar case.
1423	 */
1424	if (is_planar_fourcc(id)) {
1425		if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1426			*dstPitch = ALIGN((height / 2), pitchAlign);
1427			*dstPitch2 = ALIGN(height, pitchAlign);
1428			*size = *dstPitch * width * 3;
1429		} else {
1430			*dstPitch = ALIGN((width / 2), pitchAlign);
1431			*dstPitch2 = ALIGN(width, pitchAlign);
1432			*size = *dstPitch * height * 3;
1433		}
1434	} else {
1435		if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1436			*dstPitch = ALIGN((height << 1), pitchAlign);
1437			*size = *dstPitch * width;
1438		} else {
1439			*dstPitch = ALIGN((width << 1), pitchAlign);
1440			*size = *dstPitch * height;
1441		}
1442		*dstPitch2 = 0;
1443	}
1444#if 0
1445	ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, *dstPitch,
1446	       size);
1447#endif
1448
1449	adaptor_priv->YBufOffset = 0;
1450
1451	if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
1452		adaptor_priv->UBufOffset =
1453		    adaptor_priv->YBufOffset + (*dstPitch2 * width);
1454		adaptor_priv->VBufOffset =
1455		    adaptor_priv->UBufOffset + (*dstPitch * width / 2);
1456	} else {
1457		adaptor_priv->UBufOffset =
1458		    adaptor_priv->YBufOffset + (*dstPitch2 * height);
1459		adaptor_priv->VBufOffset =
1460		    adaptor_priv->UBufOffset + (*dstPitch * height / 2);
1461	}
1462}
1463
1464static Bool
1465intel_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
1466		     short width, short height, int *dstPitch, int *dstPitch2,
1467		     int top, int left, int npixels, int nlines,
1468		     int id, unsigned char *buf)
1469{
1470	int srcPitch = 0, srcPitch2 = 0;
1471	int size;
1472
1473	if (is_planar_fourcc(id)) {
1474		srcPitch = ALIGN(width, 0x4);
1475		srcPitch2 = ALIGN((width >> 1), 0x4);
1476	} else {
1477		srcPitch = width << 1;
1478	}
1479
1480	intel_setup_dst_params(scrn, adaptor_priv, width, height, dstPitch,
1481				dstPitch2, &size, id);
1482
1483	if (!intel_setup_video_buffer(scrn, adaptor_priv, size, id, buf))
1484		return FALSE;
1485
1486	/* copy data */
1487	if (is_planar_fourcc(id)) {
1488		return I830CopyPlanarData(adaptor_priv, buf, srcPitch, srcPitch2,
1489					  *dstPitch, *dstPitch2,
1490					  height, top, left, nlines,
1491					  npixels, id);
1492	} else {
1493		return I830CopyPackedData(adaptor_priv, buf, srcPitch, *dstPitch, top, left,
1494					  nlines, npixels);
1495	}
1496}
1497
1498/*
1499 * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h).
1500 * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h).
1501 * id is a fourcc code for the format of the video.
1502 * buf is the pointer to the source data in system memory.
1503 * width and height are the w/h of the source data.
1504 * If "sync" is TRUE, then we must be finished with *buf at the point of return
1505 * (which we always are).
1506 * clipBoxes is the clipping region in screen space.
1507 * data is a pointer to our port private.
1508 * drawable is some Drawable, which might not be the screen in the case of
1509 * compositing.  It's a new argument to the function in the 1.1 server.
1510 */
1511static int
1512I830PutImageTextured(ScrnInfoPtr scrn,
1513		     short src_x, short src_y,
1514		     short drw_x, short drw_y,
1515		     short src_w, short src_h,
1516		     short drw_w, short drw_h,
1517		     int id, unsigned char *buf,
1518		     short width, short height,
1519		     Bool sync, RegionPtr clipBoxes, pointer data,
1520		     DrawablePtr drawable)
1521{
1522	intel_screen_private *intel = intel_get_screen_private(scrn);
1523	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
1524	PixmapPtr pixmap = get_drawable_pixmap(drawable);
1525	int dstPitch, dstPitch2;
1526	BoxRec dstBox;
1527	xf86CrtcPtr crtc;
1528	int top, left, npixels, nlines;
1529
1530	if (!intel_pixmap_is_offscreen(pixmap))
1531		return BadAlloc;
1532
1533#if 0
1534	ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n"
1535	       "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x,
1536	       drw_y, drw_w, drw_h, width, height);
1537#endif
1538
1539	if (!intel_clip_video_helper(scrn,
1540				    adaptor_priv,
1541				    &crtc,
1542				    &dstBox,
1543				    src_x, src_y, drw_x, drw_y,
1544				    src_w, src_h, drw_w, drw_h,
1545				    id,
1546				    &top, &left, &npixels, &nlines, clipBoxes,
1547				    width, height))
1548		return Success;
1549
1550	if (xvmc_passthrough(id)) {
1551		uint32_t *gem_handle = (uint32_t *)buf;
1552		int size;
1553
1554		intel_setup_dst_params(scrn, adaptor_priv, width, height,
1555				&dstPitch, &dstPitch2, &size, id);
1556
1557		if (IS_I915G(intel) || IS_I915GM(intel)) {
1558			/* XXX: i915 is not support and needs some
1559			 * serious care.  grep for KMS in i915_hwmc.c */
1560			return BadAlloc;
1561		}
1562
1563		if (adaptor_priv->buf)
1564			drm_intel_bo_unreference(adaptor_priv->buf);
1565
1566		adaptor_priv->buf =
1567			drm_intel_bo_gem_create_from_name(intel->bufmgr,
1568							  "xvmc surface",
1569							  *gem_handle);
1570		if (adaptor_priv->buf == NULL)
1571			return BadAlloc;
1572
1573		adaptor_priv->reusable = FALSE;
1574	} else {
1575		if (!intel_copy_video_data(scrn, adaptor_priv, width, height,
1576					  &dstPitch, &dstPitch2,
1577					  top, left, npixels, nlines, id, buf))
1578			return BadAlloc;
1579	}
1580
1581	if (crtc && adaptor_priv->SyncToVblank != 0 && INTEL_INFO(intel)->gen < 060) {
1582		intel_wait_for_scanline(scrn, pixmap, crtc, clipBoxes);
1583	}
1584
1585	if (INTEL_INFO(intel)->gen >= 060) {
1586		Gen6DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes,
1587					 width, height, dstPitch, dstPitch2,
1588					 src_w, src_h,
1589					 drw_w, drw_h, pixmap);
1590	} else if (INTEL_INFO(intel)->gen >= 040) {
1591		I965DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes,
1592					 width, height, dstPitch, dstPitch2,
1593					 src_w, src_h,
1594					 drw_w, drw_h, pixmap);
1595	} else {
1596		I915DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes,
1597					 width, height, dstPitch, dstPitch2,
1598					 src_w, src_h, drw_w, drw_h,
1599					 pixmap);
1600	}
1601
1602	intel_get_screen_private(scrn)->needs_flush = TRUE;
1603	DamageDamageRegion(drawable, clipBoxes);
1604
1605	/* And make sure the WAIT_FOR_EVENT is queued before any
1606	 * modesetting/dpms operations on the pipe.
1607	 */
1608	intel_batch_submit(scrn);
1609
1610	return Success;
1611}
1612
1613static int
1614I830PutImageOverlay(ScrnInfoPtr scrn,
1615	     short src_x, short src_y,
1616	     short drw_x, short drw_y,
1617	     short src_w, short src_h,
1618	     short drw_w, short drw_h,
1619	     int id, unsigned char *buf,
1620	     short width, short height,
1621	     Bool sync, RegionPtr clipBoxes, pointer data,
1622	     DrawablePtr drawable)
1623{
1624	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
1625	int dstPitch, dstPitch2;
1626	BoxRec dstBox;
1627	xf86CrtcPtr crtc;
1628	int top, left, npixels, nlines;
1629
1630#if 0
1631	ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n"
1632	       "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x,
1633	       drw_y, drw_w, drw_h, width, height);
1634#endif
1635
1636	/* If dst width and height are less than 1/8th the src size, the
1637	 * src/dst scale factor becomes larger than 8 and doesn't fit in
1638	 * the scale register. */
1639	if (src_w >= (drw_w * 8))
1640		drw_w = src_w / 7;
1641
1642	if (src_h >= (drw_h * 8))
1643		drw_h = src_h / 7;
1644
1645	if (!intel_clip_video_helper(scrn,
1646				    adaptor_priv,
1647				    &crtc,
1648				    &dstBox,
1649				    src_x, src_y, drw_x, drw_y,
1650				    src_w, src_h, drw_w, drw_h,
1651				    id,
1652				    &top, &left, &npixels, &nlines, clipBoxes,
1653				    width, height))
1654		return Success;
1655
1656	/* overlay can't handle rotation natively, store it for the copy func */
1657	if (crtc)
1658		adaptor_priv->rotation = crtc->rotation;
1659	else {
1660		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1661			   "Fail to clip video to any crtc!\n");
1662		return Success;
1663	}
1664
1665	if (!intel_copy_video_data(scrn, adaptor_priv, width, height,
1666				  &dstPitch, &dstPitch2,
1667				  top, left, npixels, nlines, id, buf))
1668		return BadAlloc;
1669
1670	if (!intel_display_overlay
1671	    (scrn, crtc, id, width, height, dstPitch, dstPitch2,
1672	     &dstBox, src_w, src_h, drw_w, drw_h))
1673		return BadAlloc;
1674
1675	/* update cliplist */
1676	if (!REGION_EQUAL(scrn->pScreen, &adaptor_priv->clip, clipBoxes)) {
1677		REGION_COPY(scrn->pScreen, &adaptor_priv->clip, clipBoxes);
1678		xf86XVFillKeyHelperDrawable(drawable,
1679					    adaptor_priv->colorKey,
1680					    clipBoxes);
1681	}
1682
1683	adaptor_priv->videoStatus = CLIENT_VIDEO_ON;
1684
1685	return Success;
1686}
1687
1688static int
1689I830QueryImageAttributes(ScrnInfoPtr scrn,
1690			 int id,
1691			 unsigned short *w, unsigned short *h,
1692			 int *pitches, int *offsets)
1693{
1694	intel_screen_private *intel = intel_get_screen_private(scrn);
1695	int size, tmp;
1696
1697#if 0
1698	ErrorF("I830QueryImageAttributes: w is %d, h is %d\n", *w, *h);
1699#endif
1700
1701	if (IS_845G(intel) || IS_I830(intel)) {
1702		if (*w > IMAGE_MAX_WIDTH_LEGACY)
1703			*w = IMAGE_MAX_WIDTH_LEGACY;
1704		if (*h > IMAGE_MAX_HEIGHT_LEGACY)
1705			*h = IMAGE_MAX_HEIGHT_LEGACY;
1706	} else {
1707		if (*w > IMAGE_MAX_WIDTH)
1708			*w = IMAGE_MAX_WIDTH;
1709		if (*h > IMAGE_MAX_HEIGHT)
1710			*h = IMAGE_MAX_HEIGHT;
1711	}
1712
1713	*w = (*w + 1) & ~1;
1714	if (offsets)
1715		offsets[0] = 0;
1716
1717	switch (id) {
1718		/* IA44 is for XvMC only */
1719	case FOURCC_IA44:
1720	case FOURCC_AI44:
1721		if (pitches)
1722			pitches[0] = *w;
1723		size = *w * *h;
1724		break;
1725	case FOURCC_YV12:
1726	case FOURCC_I420:
1727		*h = (*h + 1) & ~1;
1728		size = (*w + 3) & ~3;
1729		if (pitches)
1730			pitches[0] = size;
1731		size *= *h;
1732		if (offsets)
1733			offsets[1] = size;
1734		tmp = ((*w >> 1) + 3) & ~3;
1735		if (pitches)
1736			pitches[1] = pitches[2] = tmp;
1737		tmp *= (*h >> 1);
1738		size += tmp;
1739		if (offsets)
1740			offsets[2] = size;
1741		size += tmp;
1742#if 0
1743		if (pitches)
1744			ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n",
1745			       pitches[0], pitches[1], pitches[2]);
1746		if (offsets)
1747			ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1],
1748			       offsets[2]);
1749		if (offsets)
1750			ErrorF("size is %d\n", size);
1751#endif
1752		break;
1753#ifdef INTEL_XVMC
1754	case FOURCC_XVMC:
1755		*h = (*h + 1) & ~1;
1756		size = sizeof(struct intel_xvmc_command);
1757		if (pitches)
1758			pitches[0] = size;
1759		break;
1760#endif
1761	case FOURCC_UYVY:
1762	case FOURCC_YUY2:
1763	default:
1764		size = *w << 1;
1765		if (pitches)
1766			pitches[0] = size;
1767		size *= *h;
1768		break;
1769	}
1770
1771	return size;
1772}
1773
1774void
1775intel_video_block_handler(intel_screen_private *intel)
1776{
1777	intel_adaptor_private *adaptor_priv;
1778
1779	/* no overlay */
1780	if (intel->adaptor == NULL)
1781		return;
1782
1783	adaptor_priv = intel_get_adaptor_private(intel);
1784	if (adaptor_priv->videoStatus & OFF_TIMER) {
1785		Time now = currentTime.milliseconds;
1786		if (adaptor_priv->offTime < now) {
1787			/* Turn off the overlay */
1788			intel_overlay_off(intel);
1789			intel_free_video_buffers(adaptor_priv);
1790			adaptor_priv->videoStatus = 0;
1791		}
1792	}
1793}
1794