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_uxa.h"
82#include "intel_video_overlay.h"
83
84Atom intel_xv_Brightness, intel_xv_Contrast, intel_xv_Saturation, intel_xv_ColorKey, intel_xv_Pipe;
85Atom intel_xv_Gamma0, intel_xv_Gamma1, intel_xv_Gamma2, intel_xv_Gamma3, intel_xv_Gamma4, intel_xv_Gamma5;
86Atom intel_xv_SyncToVblank;
87
88/* client libraries expect an encoding */
89const XF86VideoEncodingRec intel_xv_dummy_encoding[1] = {
90	{
91	 0,
92	 "XV_IMAGE",
93	 IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
94	 {1, 1}
95	 }
96};
97
98XF86VideoFormatRec intel_xv_formats[NUM_FORMATS] = {
99	{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
100};
101
102XF86AttributeRec intel_xv_attributes[NUM_ATTRIBUTES] = {
103	{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
104	{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
105	{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
106	{XvSettable | XvGettable, 0, 1023, "XV_SATURATION"},
107	{XvSettable | XvGettable, -1, 1, "XV_PIPE"}
108};
109
110#define GAMMA_ATTRIBUTES 6
111XF86AttributeRec intel_xv_gamma_attributes[GAMMA_ATTRIBUTES] = {
112	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"},
113	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"},
114	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
115	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"},
116	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"},
117	{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"}
118};
119
120#ifdef INTEL_XVMC
121#define NUM_IMAGES 5
122#define XVMC_IMAGE 1
123#else
124#define NUM_IMAGES 4
125#define XVMC_IMAGE 0
126#endif
127
128XF86ImageRec intel_xv_images[NUM_IMAGES] = {
129	XVIMAGE_YUY2,
130	XVIMAGE_YV12,
131	XVIMAGE_I420,
132	XVIMAGE_UYVY,
133#ifdef INTEL_XVMC
134	{
135	 /*
136	  * Below, a dummy picture type that is used in XvPutImage only to do
137	  * an overlay update. Introduced for the XvMC client lib.
138	  * Defined to have a zero data size.
139	  */
140	 FOURCC_XVMC,
141	 XvYUV,
142	 LSBFirst,
143	 {'X', 'V', 'M', 'C',
144	  0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00,
145	  0x38, 0x9B, 0x71},
146	 12,
147	 XvPlanar,
148	 3,
149	 0, 0, 0, 0,
150	 8, 8, 8,
151	 1, 2, 2,
152	 1, 2, 2,
153	 {'Y', 'V', 'U',
154	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155	  0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
156	 XvTopToBottom},
157#endif
158};
159
160void intel_video_init(ScreenPtr screen)
161{
162	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
163	intel_screen_private *intel = intel_get_screen_private(scrn);
164	XF86VideoAdaptorPtr *adaptors = NULL, *newAdaptors = NULL;
165	XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL;
166	int num_adaptors = xf86XVListGenericAdaptors(scrn, &adaptors);
167
168	/* Give our adaptor list enough space for the overlay and/or texture video
169	 * adaptors.
170	 */
171	newAdaptors = realloc(adaptors,
172			      (num_adaptors + 3) * sizeof(XF86VideoAdaptorPtr));
173
174	if (newAdaptors == NULL) {
175		free(adaptors);
176		return;
177	}
178	adaptors = newAdaptors;
179
180	/* Add the adaptors supported by our hardware.  First, set up the atoms
181	 * that will be used by both output adaptors.
182	 */
183	intel_xv_Brightness = MAKE_ATOM("XV_BRIGHTNESS");
184	intel_xv_Contrast = MAKE_ATOM("XV_CONTRAST");
185
186        /* Set up textured video if we can do it at this depth and we are on
187         * supported hardware.
188         */
189        if (!intel->force_fallback &&
190            scrn->bitsPerPixel >= 16 &&
191            INTEL_INFO(intel)->gen >= 030 &&
192            INTEL_INFO(intel)->gen < 0100) {
193                texturedAdaptor = intel_uxa_video_setup_image_textured(screen);
194                if (texturedAdaptor != NULL) {
195                        xf86DrvMsg(scrn->scrnIndex, X_INFO,
196                                   "Set up textured video\n");
197                } else {
198                        xf86DrvMsg(scrn->scrnIndex, X_ERROR,
199                                   "Failed to set up textured video\n");
200                }
201        }
202
203        overlayAdaptor = intel_video_overlay_setup_image(screen);
204
205        if (intel->use_overlay) {
206		if (overlayAdaptor != NULL) {
207			xf86DrvMsg(scrn->scrnIndex, X_INFO,
208				   "Set up overlay video\n");
209		} else {
210			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
211				   "Failed to set up overlay video\n");
212		}
213	}
214
215	if (overlayAdaptor && intel->XvPreferOverlay)
216		adaptors[num_adaptors++] = overlayAdaptor;
217
218	if (texturedAdaptor)
219		adaptors[num_adaptors++] = texturedAdaptor;
220
221	if (overlayAdaptor && !intel->XvPreferOverlay)
222		adaptors[num_adaptors++] = overlayAdaptor;
223
224	if (num_adaptors) {
225		xf86XVScreenInit(screen, adaptors, num_adaptors);
226	} else {
227		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
228			   "Disabling Xv because no adaptors could be initialized.\n");
229		intel->XvEnabled = FALSE;
230	}
231
232#ifdef INTEL_XVMC
233        if (texturedAdaptor)
234                intel_xvmc_adaptor_init(screen);
235#endif
236
237	free(adaptors);
238}
239
240void intel_free_video_buffers(intel_adaptor_private *adaptor_priv)
241{
242	int i;
243
244	for (i = 0; i < 2; i++) {
245		if (adaptor_priv->old_buf[i]) {
246			drm_intel_bo_disable_reuse(adaptor_priv->old_buf[i]);
247			drm_intel_bo_unreference(adaptor_priv->old_buf[i]);
248			adaptor_priv->old_buf[i] = NULL;
249		}
250	}
251
252	if (adaptor_priv->buf) {
253		drm_intel_bo_unreference(adaptor_priv->buf);
254		adaptor_priv->buf = NULL;
255	}
256}
257
258int
259intel_video_get_port_attribute(ScrnInfoPtr scrn,
260                               Atom attribute, INT32 * value, pointer data)
261{
262	intel_screen_private *intel = intel_get_screen_private(scrn);
263	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
264
265	if (attribute == intel_xv_Brightness) {
266		*value = adaptor_priv->brightness;
267	} else if (attribute == intel_xv_Contrast) {
268		*value = adaptor_priv->contrast;
269	} else if (attribute == intel_xv_Saturation) {
270		*value = adaptor_priv->saturation;
271	} else if (attribute == intel_xv_Pipe) {
272		int c;
273		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
274		for (c = 0; c < xf86_config->num_crtc; c++)
275			if (xf86_config->crtc[c] == adaptor_priv->desired_crtc)
276				break;
277		if (c == xf86_config->num_crtc)
278			c = -1;
279		*value = c;
280	} else if (attribute == intel_xv_Gamma0 && (INTEL_INFO(intel)->gen >= 030)) {
281		*value = adaptor_priv->gamma0;
282	} else if (attribute == intel_xv_Gamma1 && (INTEL_INFO(intel)->gen >= 030)) {
283		*value = adaptor_priv->gamma1;
284	} else if (attribute == intel_xv_Gamma2 && (INTEL_INFO(intel)->gen >= 030)) {
285		*value = adaptor_priv->gamma2;
286	} else if (attribute == intel_xv_Gamma3 && (INTEL_INFO(intel)->gen >= 030)) {
287		*value = adaptor_priv->gamma3;
288	} else if (attribute == intel_xv_Gamma4 && (INTEL_INFO(intel)->gen >= 030)) {
289		*value = adaptor_priv->gamma4;
290	} else if (attribute == intel_xv_Gamma5 && (INTEL_INFO(intel)->gen >= 030)) {
291		*value = adaptor_priv->gamma5;
292	} else if (attribute == intel_xv_ColorKey) {
293		*value = adaptor_priv->colorKey;
294	} else if (attribute == intel_xv_SyncToVblank) {
295		*value = adaptor_priv->SyncToVblank;
296	} else
297		return BadMatch;
298
299	return Success;
300}
301
302void
303intel_video_query_best_size(ScrnInfoPtr scrn,
304		  Bool motion,
305		  short vid_w, short vid_h,
306		  short drw_w, short drw_h,
307		  unsigned int *p_w, unsigned int *p_h, pointer data)
308{
309	if (vid_w > (drw_w << 1))
310		drw_w = vid_w >> 1;
311	if (vid_h > (drw_h << 1))
312		drw_h = vid_h >> 1;
313
314	*p_w = drw_w;
315	*p_h = drw_h;
316}
317
318static Bool
319intel_video_copy_packed_data(intel_adaptor_private *adaptor_priv,
320                                 unsigned char *buf,
321                                 int srcPitch, int dstPitch, int top, int left, int h, int w)
322{
323	unsigned char *src, *dst, *dst_base;
324	int i, j;
325	unsigned char *s;
326
327#if 0
328	ErrorF("intel_video_copy_packed_data: (%d,%d) (%d,%d)\n"
329	       "srcPitch: %d, dstPitch: %d\n", top, left, h, w,
330	       srcPitch, dstPitch);
331#endif
332
333	src = buf + (top * srcPitch) + (left << 1);
334
335	if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf))
336		return FALSE;
337
338	dst_base = adaptor_priv->buf->virtual;
339
340	dst = dst_base + adaptor_priv->YBufOffset;
341
342	switch (adaptor_priv->rotation) {
343	case RR_Rotate_0:
344		w <<= 1;
345		for (i = 0; i < h; i++) {
346			memcpy(dst, src, w);
347			src += srcPitch;
348			dst += dstPitch;
349		}
350		break;
351	case RR_Rotate_90:
352		h <<= 1;
353		for (i = 0; i < h; i += 2) {
354			s = src;
355			for (j = 0; j < w; j++) {
356				/* Copy Y */
357				dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++;
358				(void)*s++;
359			}
360			src += srcPitch;
361		}
362		h >>= 1;
363		src = buf + (top * srcPitch) + (left << 1);
364		for (i = 0; i < h; i += 2) {
365			for (j = 0; j < w; j += 2) {
366				/* Copy U */
367				dst[((i * 2) + 1) + ((w - j - 1) * dstPitch)] =
368				    src[(j * 2) + 1 + (i * srcPitch)];
369				dst[((i * 2) + 1) + ((w - j - 2) * dstPitch)] =
370				    src[(j * 2) + 1 + ((i + 1) * srcPitch)];
371				/* Copy V */
372				dst[((i * 2) + 3) + ((w - j - 1) * dstPitch)] =
373				    src[(j * 2) + 3 + (i * srcPitch)];
374				dst[((i * 2) + 3) + ((w - j - 2) * dstPitch)] =
375				    src[(j * 2) + 3 + ((i + 1) * srcPitch)];
376			}
377		}
378		break;
379	case RR_Rotate_180:
380		w <<= 1;
381		for (i = 0; i < h; i++) {
382			s = src;
383			for (j = 0; j < w; j += 4) {
384				dst[(w - j - 4) + ((h - i - 1) * dstPitch)] =
385				    *s++;
386				dst[(w - j - 3) + ((h - i - 1) * dstPitch)] =
387				    *s++;
388				dst[(w - j - 2) + ((h - i - 1) * dstPitch)] =
389				    *s++;
390				dst[(w - j - 1) + ((h - i - 1) * dstPitch)] =
391				    *s++;
392			}
393			src += srcPitch;
394		}
395		break;
396	case RR_Rotate_270:
397		h <<= 1;
398		for (i = 0; i < h; i += 2) {
399			s = src;
400			for (j = 0; j < w; j++) {
401				/* Copy Y */
402				dst[(h - i - 2) + (j * dstPitch)] = *s++;
403				(void)*s++;
404			}
405			src += srcPitch;
406		}
407		h >>= 1;
408		src = buf + (top * srcPitch) + (left << 1);
409		for (i = 0; i < h; i += 2) {
410			for (j = 0; j < w; j += 2) {
411				/* Copy U */
412				dst[(((h - i) * 2) - 3) + (j * dstPitch)] =
413				    src[(j * 2) + 1 + (i * srcPitch)];
414				dst[(((h - i) * 2) - 3) +
415				    ((j + 1) * dstPitch)] =
416				    src[(j * 2) + 1 + ((i + 1) * srcPitch)];
417				/* Copy V */
418				dst[(((h - i) * 2) - 1) + (j * dstPitch)] =
419				    src[(j * 2) + 3 + (i * srcPitch)];
420				dst[(((h - i) * 2) - 1) +
421				    ((j + 1) * dstPitch)] =
422				    src[(j * 2) + 3 + ((i + 1) * srcPitch)];
423			}
424		}
425		break;
426	}
427
428	drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf);
429	return TRUE;
430}
431
432static void intel_memcpy_plane(unsigned char *dst, unsigned char *src,
433			       int height, int width,
434			       int dstPitch, int srcPitch, Rotation rotation)
435{
436	int i, j = 0;
437	unsigned char *s;
438
439	switch (rotation) {
440	case RR_Rotate_0:
441		/* optimise for the case of no clipping */
442		if (srcPitch == dstPitch && srcPitch == width)
443			memcpy(dst, src, srcPitch * height);
444		else
445			for (i = 0; i < height; i++) {
446				memcpy(dst, src, width);
447				src += srcPitch;
448				dst += dstPitch;
449			}
450		break;
451	case RR_Rotate_90:
452		for (i = 0; i < height; i++) {
453			s = src;
454			for (j = 0; j < width; j++) {
455				dst[(i) + ((width - j - 1) * dstPitch)] = *s++;
456			}
457			src += srcPitch;
458		}
459		break;
460	case RR_Rotate_180:
461		for (i = 0; i < height; i++) {
462			s = src;
463			for (j = 0; j < width; j++) {
464				dst[(width - j - 1) +
465				    ((height - i - 1) * dstPitch)] = *s++;
466			}
467			src += srcPitch;
468		}
469		break;
470	case RR_Rotate_270:
471		for (i = 0; i < height; i++) {
472			s = src;
473			for (j = 0; j < width; j++) {
474				dst[(height - i - 1) + (j * dstPitch)] = *s++;
475			}
476			src += srcPitch;
477		}
478		break;
479	}
480}
481
482static Bool
483intel_video_copy_planar_data(intel_adaptor_private *adaptor_priv,
484		   unsigned char *buf, int srcPitch, int srcPitch2,
485		   int dstPitch, int dstPitch2,
486		   int srcH, int top, int left,
487		   int h, int w, int id)
488{
489	unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3;
490
491#if 0
492	ErrorF("intel_video_copy_planar_data: srcPitch %d, srcPitch %d, dstPitch %d\n"
493	       "nlines %d, npixels %d, top %d, left %d\n",
494	       srcPitch, srcPitch2, dstPitch, h, w, top, left);
495#endif
496
497	/* Copy Y data */
498	src1 = buf + (top * srcPitch) + left;
499#if 0
500	ErrorF("src1 is %p, offset is %ld\n", src1,
501	       (unsigned long)src1 - (unsigned long)buf);
502#endif
503
504	if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf))
505		return FALSE;
506
507	dst_base = adaptor_priv->buf->virtual;
508
509	dst1 = dst_base + adaptor_priv->YBufOffset;
510
511	intel_memcpy_plane(dst1, src1, h, w, dstPitch2, srcPitch,
512			  adaptor_priv->rotation);
513
514	/* Copy V data for YV12, or U data for I420 */
515	src2 = buf +		/* start of YUV data */
516	    (srcH * srcPitch) +	/* move over Luma plane */
517	    ((top >> 1) * srcPitch2) +	/* move down from by top lines */
518	    (left >> 1);	/* move left by left pixels */
519
520#if 0
521	ErrorF("src2 is %p, offset is %ld\n", src2,
522	       (unsigned long)src2 - (unsigned long)buf);
523#endif
524	if (id == FOURCC_I420)
525		dst2 = dst_base + adaptor_priv->UBufOffset;
526	else
527		dst2 = dst_base + adaptor_priv->VBufOffset;
528
529	intel_memcpy_plane(dst2, src2, h / 2, w / 2,
530			  dstPitch, srcPitch2, adaptor_priv->rotation);
531
532	/* Copy U data for YV12, or V data for I420 */
533	src3 = buf +		/* start of YUV data */
534	    (srcH * srcPitch) +	/* move over Luma plane */
535	    ((srcH >> 1) * srcPitch2) +	/* move over Chroma plane */
536	    ((top >> 1) * srcPitch2) +	/* move down from by top lines */
537	    (left >> 1);	/* move left by left pixels */
538#if 0
539	ErrorF("src3 is %p, offset is %ld\n", src3,
540	       (unsigned long)src3 - (unsigned long)buf);
541#endif
542	if (id == FOURCC_I420)
543		dst3 = dst_base + adaptor_priv->VBufOffset;
544	else
545		dst3 = dst_base + adaptor_priv->UBufOffset;
546
547	intel_memcpy_plane(dst3, src3, h / 2, w / 2,
548			  dstPitch, srcPitch2, adaptor_priv->rotation);
549
550	drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf);
551	return TRUE;
552}
553
554void
555intel_setup_dst_params(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, short width,
556		       short height, int *dstPitch, int *dstPitch2, int *size,
557		       int id)
558{
559	intel_screen_private *intel = intel_get_screen_private(scrn);
560	int pitchAlign;
561
562	/* Only needs to be DWORD-aligned for textured on i915, but overlay has
563	 * stricter requirements.
564	 */
565	if (adaptor_priv->textured) {
566		pitchAlign = 4;
567	} else {
568		if (INTEL_INFO(intel)->gen >= 040)
569			/* Actually the alignment is 64 bytes, too. But the
570			 * stride must be at least 512 bytes. Take the easy fix
571			 * and align on 512 bytes unconditionally. */
572			pitchAlign = 512;
573		else if (IS_I830(intel) || IS_845G(intel))
574			/* Harsh, errata on these chipsets limit the stride to be
575			 * a multiple of 256 bytes.
576			 */
577			pitchAlign = 256;
578		else
579			pitchAlign = 64;
580	}
581
582#if INTEL_XVMC
583	/* for i915 xvmc, hw requires 1kb aligned surfaces */
584	if ((id == FOURCC_XVMC) && IS_GEN3(intel))
585		pitchAlign = 1024;
586#endif
587
588	/* Determine the desired destination pitch (representing the chroma's pitch,
589	 * in the planar case.
590	 */
591	if (is_planar_fourcc(id)) {
592		if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
593			*dstPitch = ALIGN((height / 2), pitchAlign);
594			*dstPitch2 = ALIGN(height, pitchAlign);
595			*size = *dstPitch * width * 3;
596		} else {
597			*dstPitch = ALIGN((width / 2), pitchAlign);
598			*dstPitch2 = ALIGN(width, pitchAlign);
599			*size = *dstPitch * height * 3;
600		}
601	} else {
602		if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
603			*dstPitch = ALIGN((height << 1), pitchAlign);
604			*size = *dstPitch * width;
605		} else {
606			*dstPitch = ALIGN((width << 1), pitchAlign);
607			*size = *dstPitch * height;
608		}
609		*dstPitch2 = 0;
610	}
611#if 0
612	ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, *dstPitch,
613	       size);
614#endif
615
616	adaptor_priv->YBufOffset = 0;
617
618	if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
619		adaptor_priv->UBufOffset =
620		    adaptor_priv->YBufOffset + (*dstPitch2 * width);
621		adaptor_priv->VBufOffset =
622		    adaptor_priv->UBufOffset + (*dstPitch * width / 2);
623	} else {
624		adaptor_priv->UBufOffset =
625		    adaptor_priv->YBufOffset + (*dstPitch2 * height);
626		adaptor_priv->VBufOffset =
627		    adaptor_priv->UBufOffset + (*dstPitch * height / 2);
628	}
629}
630
631static Bool
632intel_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
633			 int alloc_size, int id, unsigned char *buf)
634{
635	intel_screen_private *intel = intel_get_screen_private(scrn);
636
637	/* Free the current buffer if we're going to have to reallocate */
638	if (adaptor_priv->buf && adaptor_priv->buf->size < alloc_size)
639		intel_free_video_buffers(adaptor_priv);
640
641	if (adaptor_priv->buf == NULL) {
642		adaptor_priv->buf = drm_intel_bo_alloc(intel->bufmgr, "xv buffer",
643						       alloc_size, 4096);
644		if (adaptor_priv->buf == NULL)
645			return FALSE;
646
647		adaptor_priv->reusable = TRUE;
648	}
649
650	return TRUE;
651}
652
653Bool
654intel_video_copy_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv,
655                      short width, short height, int *dstPitch, int *dstPitch2,
656                      int top, int left, int npixels, int nlines,
657                      int id, unsigned char *buf)
658{
659	int srcPitch = 0, srcPitch2 = 0;
660	int size;
661
662	if (is_planar_fourcc(id)) {
663		srcPitch = ALIGN(width, 0x4);
664		srcPitch2 = ALIGN((width >> 1), 0x4);
665	} else {
666		srcPitch = width << 1;
667	}
668
669	intel_setup_dst_params(scrn, adaptor_priv, width, height, dstPitch,
670				dstPitch2, &size, id);
671
672	if (!intel_setup_video_buffer(scrn, adaptor_priv, size, id, buf))
673		return FALSE;
674
675	/* copy data */
676	if (is_planar_fourcc(id)) {
677		return intel_video_copy_planar_data(adaptor_priv, buf, srcPitch, srcPitch2,
678					  *dstPitch, *dstPitch2,
679					  height, top, left, nlines,
680					  npixels, id);
681	} else {
682		return intel_video_copy_packed_data(adaptor_priv, buf, srcPitch, *dstPitch, top, left,
683					  nlines, npixels);
684	}
685}
686
687int is_planar_fourcc(int id)
688{
689	switch (id) {
690	case FOURCC_YV12:
691	case FOURCC_I420:
692#ifdef INTEL_XVMC
693	case FOURCC_XVMC:
694#endif
695		return 1;
696	case FOURCC_UYVY:
697	case FOURCC_YUY2:
698		return 0;
699	default:
700		ErrorF("Unknown format 0x%x\n", id);
701		return 0;
702	}
703}
704
705Bool
706intel_clip_video_helper(ScrnInfoPtr scrn,
707			intel_adaptor_private *adaptor_priv,
708			xf86CrtcPtr * crtc_ret,
709			BoxPtr dst,
710			short src_x, short src_y,
711			short drw_x, short drw_y,
712			short src_w, short src_h,
713			short drw_w, short drw_h,
714			int id,
715			int *top, int* left, int* npixels, int *nlines,
716			RegionPtr reg, INT32 width, INT32 height)
717{
718	Bool ret;
719	RegionRec crtc_region_local;
720	RegionPtr crtc_region = reg;
721	BoxRec crtc_box;
722	INT32 x1, x2, y1, y2;
723	xf86CrtcPtr crtc;
724
725	x1 = src_x;
726	x2 = src_x + src_w;
727	y1 = src_y;
728	y2 = src_y + src_h;
729
730	dst->x1 = drw_x;
731	dst->x2 = drw_x + drw_w;
732	dst->y1 = drw_y;
733	dst->y2 = drw_y + drw_h;
734
735	/*
736	 * For overlay video, compute the relevant CRTC and
737	 * clip video to that
738	 */
739	crtc = intel_covering_crtc(scrn, dst, adaptor_priv->desired_crtc,
740				   &crtc_box);
741
742	/* For textured video, we don't actually want to clip at all. */
743	if (crtc && !adaptor_priv->textured) {
744		REGION_INIT(screen, &crtc_region_local, &crtc_box, 1);
745		crtc_region = &crtc_region_local;
746		REGION_INTERSECT(screen, crtc_region, crtc_region,
747				 reg);
748	}
749	*crtc_ret = crtc;
750
751	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
752				    crtc_region, width, height);
753	if (crtc_region != reg)
754		REGION_UNINIT(screen, &crtc_region_local);
755
756	*top = y1 >> 16;
757	*left = (x1 >> 16) & ~1;
758	*npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - *left;
759	if (is_planar_fourcc(id)) {
760		*top &= ~1;
761		*nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - *top;
762	} else
763		*nlines = ((y2 + 0xffff) >> 16) - *top;
764
765	return ret;
766}
767
768int
769intel_video_query_image_attributes(ScrnInfoPtr scrn,
770                                   int id,
771                                   unsigned short *w, unsigned short *h,
772                                   int *pitches, int *offsets)
773{
774	intel_screen_private *intel = intel_get_screen_private(scrn);
775	int size, tmp;
776
777#if 0
778	ErrorF("intel_video_query_image_attributes: w is %d, h is %d\n", *w, *h);
779#endif
780
781	if (IS_845G(intel) || IS_I830(intel)) {
782		if (*w > IMAGE_MAX_WIDTH_LEGACY)
783			*w = IMAGE_MAX_WIDTH_LEGACY;
784		if (*h > IMAGE_MAX_HEIGHT_LEGACY)
785			*h = IMAGE_MAX_HEIGHT_LEGACY;
786	} else {
787		if (*w > IMAGE_MAX_WIDTH)
788			*w = IMAGE_MAX_WIDTH;
789		if (*h > IMAGE_MAX_HEIGHT)
790			*h = IMAGE_MAX_HEIGHT;
791	}
792
793	*w = (*w + 1) & ~1;
794	if (offsets)
795		offsets[0] = 0;
796
797	switch (id) {
798		/* IA44 is for XvMC only */
799	case FOURCC_IA44:
800	case FOURCC_AI44:
801		if (pitches)
802			pitches[0] = *w;
803		size = *w * *h;
804		break;
805	case FOURCC_YV12:
806	case FOURCC_I420:
807		*h = (*h + 1) & ~1;
808		size = (*w + 3) & ~3;
809		if (pitches)
810			pitches[0] = size;
811		size *= *h;
812		if (offsets)
813			offsets[1] = size;
814		tmp = ((*w >> 1) + 3) & ~3;
815		if (pitches)
816			pitches[1] = pitches[2] = tmp;
817		tmp *= (*h >> 1);
818		size += tmp;
819		if (offsets)
820			offsets[2] = size;
821		size += tmp;
822#if 0
823		if (pitches)
824			ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n",
825			       pitches[0], pitches[1], pitches[2]);
826		if (offsets)
827			ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1],
828			       offsets[2]);
829		if (offsets)
830			ErrorF("size is %d\n", size);
831#endif
832		break;
833#ifdef INTEL_XVMC
834	case FOURCC_XVMC:
835		*h = (*h + 1) & ~1;
836		size = sizeof(struct intel_xvmc_command);
837		if (pitches)
838			pitches[0] = size;
839		break;
840#endif
841	case FOURCC_UYVY:
842	case FOURCC_YUY2:
843	default:
844		size = *w << 1;
845		if (pitches)
846			pitches[0] = size;
847		size *= *h;
848		break;
849	}
850
851	return size;
852}
853
854void intel_video_stop_video(ScrnInfoPtr scrn, pointer data, Bool shutdown)
855{
856	intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data;
857
858	if (adaptor_priv->textured)
859		return;
860
861	REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip);
862
863	if (shutdown) {
864		if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON)
865			intel_video_overlay_off(intel_get_screen_private(scrn));
866
867		intel_free_video_buffers(adaptor_priv);
868		adaptor_priv->videoStatus = 0;
869	} else {
870		if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) {
871			adaptor_priv->videoStatus |= OFF_TIMER;
872			adaptor_priv->offTime = currentTime.milliseconds + OFF_DELAY;
873		}
874	}
875
876}
877
878void
879intel_video_block_handler(intel_screen_private *intel)
880{
881	intel_adaptor_private *adaptor_priv;
882
883	/* no overlay */
884	if (intel->adaptor == NULL)
885		return;
886
887	adaptor_priv = intel_get_adaptor_private(intel);
888	if (adaptor_priv->videoStatus & OFF_TIMER) {
889		Time now = currentTime.milliseconds;
890		if (adaptor_priv->offTime < now) {
891			/* Turn off the overlay */
892			intel_video_overlay_off(intel);
893			intel_free_video_buffers(adaptor_priv);
894			adaptor_priv->videoStatus = 0;
895		}
896	}
897}
898