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