sna_video.c revision 03b705cf
103b705cfSriastradh/***************************************************************************
203b705cfSriastradh
303b705cfSriastradh Copyright 2000 Intel Corporation.  All Rights Reserved.
403b705cfSriastradh
503b705cfSriastradh Permission is hereby granted, free of charge, to any person obtaining a
603b705cfSriastradh copy of this software and associated documentation files (the
703b705cfSriastradh "Software"), to deal in the Software without restriction, including
803b705cfSriastradh without limitation the rights to use, copy, modify, merge, publish,
903b705cfSriastradh distribute, sub license, and/or sell copies of the Software, and to
1003b705cfSriastradh permit persons to whom the Software is furnished to do so, subject to
1103b705cfSriastradh the following conditions:
1203b705cfSriastradh
1303b705cfSriastradh The above copyright notice and this permission notice (including the
1403b705cfSriastradh next paragraph) shall be included in all copies or substantial portions
1503b705cfSriastradh of the Software.
1603b705cfSriastradh
1703b705cfSriastradh THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1803b705cfSriastradh OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1903b705cfSriastradh MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2003b705cfSriastradh IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
2103b705cfSriastradh DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
2203b705cfSriastradh OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
2303b705cfSriastradh THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2403b705cfSriastradh
2503b705cfSriastradh **************************************************************************/
2603b705cfSriastradh
2703b705cfSriastradh/*
2803b705cfSriastradh * i830_video.c: i830/i845 Xv driver.
2903b705cfSriastradh *
3003b705cfSriastradh * Copyright © 2002 by Alan Hourihane and David Dawes
3103b705cfSriastradh *
3203b705cfSriastradh * Authors:
3303b705cfSriastradh *	Alan Hourihane <alanh@tungstengraphics.com>
3403b705cfSriastradh *	David Dawes <dawes@xfree86.org>
3503b705cfSriastradh *
3603b705cfSriastradh * Derived from i810 Xv driver:
3703b705cfSriastradh *
3803b705cfSriastradh * Authors of i810 code:
3903b705cfSriastradh *	Jonathan Bian <jonathan.bian@intel.com>
4003b705cfSriastradh *      Offscreen Images:
4103b705cfSriastradh *        Matt Sottek <matthew.j.sottek@intel.com>
4203b705cfSriastradh */
4303b705cfSriastradh
4403b705cfSriastradh#ifdef HAVE_CONFIG_H
4503b705cfSriastradh#include "config.h"
4603b705cfSriastradh#endif
4703b705cfSriastradh
4803b705cfSriastradh#include <inttypes.h>
4903b705cfSriastradh#include <math.h>
5003b705cfSriastradh#include <string.h>
5103b705cfSriastradh#include <assert.h>
5203b705cfSriastradh#include <errno.h>
5303b705cfSriastradh
5403b705cfSriastradh#include <sys/mman.h>
5503b705cfSriastradh
5603b705cfSriastradh#include "sna.h"
5703b705cfSriastradh#include "sna_reg.h"
5803b705cfSriastradh#include "sna_video.h"
5903b705cfSriastradh
6003b705cfSriastradh#include "intel_options.h"
6103b705cfSriastradh
6203b705cfSriastradh#include <xf86xv.h>
6303b705cfSriastradh#include <X11/extensions/Xv.h>
6403b705cfSriastradh
6503b705cfSriastradh#ifdef SNA_XVMC
6603b705cfSriastradh#define _SNA_XVMC_SERVER_
6703b705cfSriastradh#include "sna_video_hwmc.h"
6803b705cfSriastradh#else
6903b705cfSriastradhstatic inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr)
7003b705cfSriastradh{
7103b705cfSriastradh}
7203b705cfSriastradh#endif
7303b705cfSriastradh
7403b705cfSriastradhvoid sna_video_free_buffers(struct sna_video *video)
7503b705cfSriastradh{
7603b705cfSriastradh	unsigned int i;
7703b705cfSriastradh
7803b705cfSriastradh	for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
7903b705cfSriastradh		if (video->old_buf[i]) {
8003b705cfSriastradh			kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]);
8103b705cfSriastradh			video->old_buf[i] = NULL;
8203b705cfSriastradh		}
8303b705cfSriastradh	}
8403b705cfSriastradh
8503b705cfSriastradh	if (video->buf) {
8603b705cfSriastradh		kgem_bo_destroy(&video->sna->kgem, video->buf);
8703b705cfSriastradh		video->buf = NULL;
8803b705cfSriastradh	}
8903b705cfSriastradh}
9003b705cfSriastradh
9103b705cfSriastradhstruct kgem_bo *
9203b705cfSriastradhsna_video_buffer(struct sna_video *video,
9303b705cfSriastradh		 struct sna_video_frame *frame)
9403b705cfSriastradh{
9503b705cfSriastradh	/* Free the current buffer if we're going to have to reallocate */
9603b705cfSriastradh	if (video->buf && __kgem_bo_size(video->buf) < frame->size)
9703b705cfSriastradh		sna_video_free_buffers(video);
9803b705cfSriastradh
9903b705cfSriastradh	if (video->buf == NULL) {
10003b705cfSriastradh		if (video->tiled) {
10103b705cfSriastradh			video->buf = kgem_create_2d(&video->sna->kgem,
10203b705cfSriastradh						    frame->width, frame->height, 32,
10303b705cfSriastradh						    I915_TILING_X, CREATE_EXACT);
10403b705cfSriastradh		} else {
10503b705cfSriastradh			video->buf = kgem_create_linear(&video->sna->kgem, frame->size,
10603b705cfSriastradh							CREATE_GTT_MAP);
10703b705cfSriastradh		}
10803b705cfSriastradh	}
10903b705cfSriastradh
11003b705cfSriastradh	return video->buf;
11103b705cfSriastradh}
11203b705cfSriastradh
11303b705cfSriastradhvoid sna_video_buffer_fini(struct sna_video *video)
11403b705cfSriastradh{
11503b705cfSriastradh	struct kgem_bo *bo;
11603b705cfSriastradh
11703b705cfSriastradh	bo = video->old_buf[1];
11803b705cfSriastradh	video->old_buf[1] = video->old_buf[0];
11903b705cfSriastradh	video->old_buf[0] = video->buf;
12003b705cfSriastradh	video->buf = bo;
12103b705cfSriastradh}
12203b705cfSriastradh
12303b705cfSriastradhbool
12403b705cfSriastradhsna_video_clip_helper(ScrnInfoPtr scrn,
12503b705cfSriastradh		      struct sna_video *video,
12603b705cfSriastradh		      struct sna_video_frame *frame,
12703b705cfSriastradh		      xf86CrtcPtr * crtc_ret,
12803b705cfSriastradh		      BoxPtr dst,
12903b705cfSriastradh		      short src_x, short src_y,
13003b705cfSriastradh		      short drw_x, short drw_y,
13103b705cfSriastradh		      short src_w, short src_h,
13203b705cfSriastradh		      short drw_w, short drw_h,
13303b705cfSriastradh		      RegionPtr reg)
13403b705cfSriastradh{
13503b705cfSriastradh	bool ret;
13603b705cfSriastradh	RegionRec crtc_region_local;
13703b705cfSriastradh	RegionPtr crtc_region = reg;
13803b705cfSriastradh	INT32 x1, x2, y1, y2;
13903b705cfSriastradh	xf86CrtcPtr crtc;
14003b705cfSriastradh
14103b705cfSriastradh	x1 = src_x;
14203b705cfSriastradh	x2 = src_x + src_w;
14303b705cfSriastradh	y1 = src_y;
14403b705cfSriastradh	y2 = src_y + src_h;
14503b705cfSriastradh
14603b705cfSriastradh	dst->x1 = drw_x;
14703b705cfSriastradh	dst->x2 = drw_x + drw_w;
14803b705cfSriastradh	dst->y1 = drw_y;
14903b705cfSriastradh	dst->y2 = drw_y + drw_h;
15003b705cfSriastradh
15103b705cfSriastradh	/*
15203b705cfSriastradh	 * For overlay video, compute the relevant CRTC and
15303b705cfSriastradh	 * clip video to that
15403b705cfSriastradh	 */
15503b705cfSriastradh	crtc = sna_covering_crtc(scrn, dst, video->desired_crtc);
15603b705cfSriastradh
15703b705cfSriastradh	/* For textured video, we don't actually want to clip at all. */
15803b705cfSriastradh	if (crtc && !video->textured) {
15903b705cfSriastradh		crtc_region_local.extents = crtc->bounds;
16003b705cfSriastradh		crtc_region_local.data = NULL;
16103b705cfSriastradh		crtc_region = &crtc_region_local;
16203b705cfSriastradh		RegionIntersect(crtc_region, crtc_region, reg);
16303b705cfSriastradh	}
16403b705cfSriastradh	*crtc_ret = crtc;
16503b705cfSriastradh
16603b705cfSriastradh	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
16703b705cfSriastradh				    crtc_region, frame->width, frame->height);
16803b705cfSriastradh	if (crtc_region != reg)
16903b705cfSriastradh		RegionUninit(crtc_region);
17003b705cfSriastradh
17103b705cfSriastradh	frame->src.x1 = x1 >> 16;
17203b705cfSriastradh	frame->src.y1 = y1 >> 16;
17303b705cfSriastradh	frame->src.x2 = (x2 + 0xffff) >> 16;
17403b705cfSriastradh	frame->src.y2 = (y2 + 0xffff) >> 16;
17503b705cfSriastradh
17603b705cfSriastradh	frame->image.x1 = frame->src.x1 & ~1;
17703b705cfSriastradh	frame->image.x2 = ALIGN(frame->src.x2, 2);
17803b705cfSriastradh	if (is_planar_fourcc(frame->id)) {
17903b705cfSriastradh		frame->image.y1 = frame->src.y1 & ~1;
18003b705cfSriastradh		frame->image.y2 = ALIGN(frame->src.y2, 2);
18103b705cfSriastradh	} else {
18203b705cfSriastradh		frame->image.y1 = frame->src.y1;
18303b705cfSriastradh		frame->image.y2 = frame->src.y2;
18403b705cfSriastradh	}
18503b705cfSriastradh
18603b705cfSriastradh	return ret;
18703b705cfSriastradh}
18803b705cfSriastradh
18903b705cfSriastradhvoid
19003b705cfSriastradhsna_video_frame_init(struct sna_video *video,
19103b705cfSriastradh		     int id, short width, short height,
19203b705cfSriastradh		     struct sna_video_frame *frame)
19303b705cfSriastradh{
19403b705cfSriastradh	int align;
19503b705cfSriastradh
19603b705cfSriastradh	DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n",
19703b705cfSriastradh	     __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment));
19803b705cfSriastradh	assert(width && height);
19903b705cfSriastradh
20003b705cfSriastradh	frame->bo = NULL;
20103b705cfSriastradh	frame->id = id;
20203b705cfSriastradh	frame->width = width;
20303b705cfSriastradh	frame->height = height;
20403b705cfSriastradh
20503b705cfSriastradh	align = video->alignment;
20603b705cfSriastradh#if SNA_XVMC
20703b705cfSriastradh	/* for i915 xvmc, hw requires 1kb aligned surfaces */
20803b705cfSriastradh	if (id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024)
20903b705cfSriastradh		align = 1024;
21003b705cfSriastradh#endif
21103b705cfSriastradh
21203b705cfSriastradh	/* Determine the desired destination pitch (representing the
21303b705cfSriastradh	 * chroma's pitch in the planar case).
21403b705cfSriastradh	 */
21503b705cfSriastradh	if (is_planar_fourcc(id)) {
21603b705cfSriastradh		assert((width & 1) == 0);
21703b705cfSriastradh		assert((height & 1) == 0);
21803b705cfSriastradh		if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
21903b705cfSriastradh			frame->pitch[0] = ALIGN((height / 2), align);
22003b705cfSriastradh			frame->pitch[1] = ALIGN(height, align);
22103b705cfSriastradh			frame->size = width;
22203b705cfSriastradh		} else {
22303b705cfSriastradh			frame->pitch[0] = ALIGN((width / 2), align);
22403b705cfSriastradh			frame->pitch[1] = ALIGN(width, align);
22503b705cfSriastradh			frame->size = height;
22603b705cfSriastradh		}
22703b705cfSriastradh		frame->size *= frame->pitch[0] + frame->pitch[1];
22803b705cfSriastradh
22903b705cfSriastradh		if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
23003b705cfSriastradh			frame->UBufOffset = (int)frame->pitch[1] * width;
23103b705cfSriastradh			frame->VBufOffset =
23203b705cfSriastradh				frame->UBufOffset + (int)frame->pitch[0] * width / 2;
23303b705cfSriastradh		} else {
23403b705cfSriastradh			frame->UBufOffset = (int)frame->pitch[1] * height;
23503b705cfSriastradh			frame->VBufOffset =
23603b705cfSriastradh				frame->UBufOffset + (int)frame->pitch[0] * height / 2;
23703b705cfSriastradh		}
23803b705cfSriastradh	} else {
23903b705cfSriastradh		switch (frame->id) {
24003b705cfSriastradh		case FOURCC_RGB888:
24103b705cfSriastradh			if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
24203b705cfSriastradh				frame->pitch[0] = ALIGN((height << 2), align);
24303b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
24403b705cfSriastradh			} else {
24503b705cfSriastradh				frame->pitch[0] = ALIGN((width << 2), align);
24603b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
24703b705cfSriastradh			}
24803b705cfSriastradh			frame->UBufOffset = frame->VBufOffset = 0;
24903b705cfSriastradh			break;
25003b705cfSriastradh		case FOURCC_RGB565:
25103b705cfSriastradh			if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
25203b705cfSriastradh				frame->pitch[0] = ALIGN((height << 1), align);
25303b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
25403b705cfSriastradh			} else {
25503b705cfSriastradh				frame->pitch[0] = ALIGN((width << 1), align);
25603b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
25703b705cfSriastradh			}
25803b705cfSriastradh			frame->UBufOffset = frame->VBufOffset = 0;
25903b705cfSriastradh			break;
26003b705cfSriastradh
26103b705cfSriastradh		default:
26203b705cfSriastradh			if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
26303b705cfSriastradh				frame->pitch[0] = ALIGN((height << 1), align);
26403b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
26503b705cfSriastradh			} else {
26603b705cfSriastradh				frame->pitch[0] = ALIGN((width << 1), align);
26703b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
26803b705cfSriastradh			}
26903b705cfSriastradh			break;
27003b705cfSriastradh		}
27103b705cfSriastradh		frame->pitch[1] = 0;
27203b705cfSriastradh		frame->UBufOffset = 0;
27303b705cfSriastradh		frame->VBufOffset = 0;
27403b705cfSriastradh	}
27503b705cfSriastradh
27603b705cfSriastradh	assert(frame->size);
27703b705cfSriastradh}
27803b705cfSriastradh
27903b705cfSriastradhstatic void sna_memcpy_plane(struct sna_video *video,
28003b705cfSriastradh			     uint8_t *dst, const uint8_t *src,
28103b705cfSriastradh			     const struct sna_video_frame *frame, int sub)
28203b705cfSriastradh{
28303b705cfSriastradh	int dstPitch = frame->pitch[!sub], srcPitch;
28403b705cfSriastradh	const uint8_t *s;
28503b705cfSriastradh	int i, j = 0;
28603b705cfSriastradh	int x, y, w, h;
28703b705cfSriastradh
28803b705cfSriastradh	x = frame->image.x1;
28903b705cfSriastradh	y = frame->image.y1;
29003b705cfSriastradh	w = frame->image.x2 - frame->image.x1;
29103b705cfSriastradh	h = frame->image.y2 - frame->image.y1;
29203b705cfSriastradh	if (sub) {
29303b705cfSriastradh		x >>= 1; w >>= 1;
29403b705cfSriastradh		y >>= 1; h >>= 1;
29503b705cfSriastradh		srcPitch = ALIGN((frame->width >> 1), 4);
29603b705cfSriastradh	} else
29703b705cfSriastradh		srcPitch = ALIGN(frame->width, 4);
29803b705cfSriastradh
29903b705cfSriastradh	src += y * srcPitch + x;
30003b705cfSriastradh	if (!video->textured)
30103b705cfSriastradh		x = y = 0;
30203b705cfSriastradh
30303b705cfSriastradh	switch (video->rotation) {
30403b705cfSriastradh	case RR_Rotate_0:
30503b705cfSriastradh		dst += y * dstPitch + x;
30603b705cfSriastradh		if (srcPitch == dstPitch && srcPitch == w)
30703b705cfSriastradh			memcpy(dst, src, srcPitch * h);
30803b705cfSriastradh		else while (h--) {
30903b705cfSriastradh			memcpy(dst, src, w);
31003b705cfSriastradh			src += srcPitch;
31103b705cfSriastradh			dst += dstPitch;
31203b705cfSriastradh		}
31303b705cfSriastradh		break;
31403b705cfSriastradh	case RR_Rotate_90:
31503b705cfSriastradh		for (i = 0; i < h; i++) {
31603b705cfSriastradh			s = src;
31703b705cfSriastradh			for (j = 0; j < w; j++)
31803b705cfSriastradh				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
31903b705cfSriastradh			src += srcPitch;
32003b705cfSriastradh		}
32103b705cfSriastradh		break;
32203b705cfSriastradh	case RR_Rotate_180:
32303b705cfSriastradh		for (i = 0; i < h; i++) {
32403b705cfSriastradh			s = src;
32503b705cfSriastradh			for (j = 0; j < w; j++) {
32603b705cfSriastradh				dst[(x + w - j - 1) +
32703b705cfSriastradh				    ((h - i - 1) * dstPitch)] = *s++;
32803b705cfSriastradh			}
32903b705cfSriastradh			src += srcPitch;
33003b705cfSriastradh		}
33103b705cfSriastradh		break;
33203b705cfSriastradh	case RR_Rotate_270:
33303b705cfSriastradh		for (i = 0; i < h; i++) {
33403b705cfSriastradh			s = src;
33503b705cfSriastradh			for (j = 0; j < w; j++) {
33603b705cfSriastradh				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
33703b705cfSriastradh			}
33803b705cfSriastradh			src += srcPitch;
33903b705cfSriastradh		}
34003b705cfSriastradh		break;
34103b705cfSriastradh	}
34203b705cfSriastradh}
34303b705cfSriastradh
34403b705cfSriastradhstatic void
34503b705cfSriastradhsna_copy_planar_data(struct sna_video *video,
34603b705cfSriastradh		     const struct sna_video_frame *frame,
34703b705cfSriastradh		     const uint8_t *src, uint8_t *dst)
34803b705cfSriastradh{
34903b705cfSriastradh	uint8_t *d;
35003b705cfSriastradh
35103b705cfSriastradh	sna_memcpy_plane(video, dst, src, frame, 0);
35203b705cfSriastradh	src += frame->height * ALIGN(frame->width, 4);
35303b705cfSriastradh
35403b705cfSriastradh	if (frame->id == FOURCC_I420)
35503b705cfSriastradh		d = dst + frame->UBufOffset;
35603b705cfSriastradh	else
35703b705cfSriastradh		d = dst + frame->VBufOffset;
35803b705cfSriastradh	sna_memcpy_plane(video, d, src, frame, 1);
35903b705cfSriastradh	src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4);
36003b705cfSriastradh
36103b705cfSriastradh	if (frame->id == FOURCC_I420)
36203b705cfSriastradh		d = dst + frame->VBufOffset;
36303b705cfSriastradh	else
36403b705cfSriastradh		d = dst + frame->UBufOffset;
36503b705cfSriastradh	sna_memcpy_plane(video, d, src, frame, 1);
36603b705cfSriastradh}
36703b705cfSriastradh
36803b705cfSriastradhstatic void
36903b705cfSriastradhsna_copy_packed_data(struct sna_video *video,
37003b705cfSriastradh		     const struct sna_video_frame *frame,
37103b705cfSriastradh		     const uint8_t *buf,
37203b705cfSriastradh		     uint8_t *dst)
37303b705cfSriastradh{
37403b705cfSriastradh	int pitch = frame->width << 1;
37503b705cfSriastradh	const uint8_t *src, *s;
37603b705cfSriastradh	int x, y, w, h;
37703b705cfSriastradh	int i, j;
37803b705cfSriastradh
37903b705cfSriastradh	if (video->textured) {
38003b705cfSriastradh		/* XXX support copying cropped extents */
38103b705cfSriastradh		x = y = 0;
38203b705cfSriastradh		w = frame->width;
38303b705cfSriastradh		h = frame->height;
38403b705cfSriastradh	} else {
38503b705cfSriastradh		x = frame->image.x1;
38603b705cfSriastradh		y = frame->image.y1;
38703b705cfSriastradh		w = frame->image.x2 - frame->image.x1;
38803b705cfSriastradh		h = frame->image.y2 - frame->image.y1;
38903b705cfSriastradh	}
39003b705cfSriastradh
39103b705cfSriastradh	src = buf + (y * pitch) + (x << 1);
39203b705cfSriastradh
39303b705cfSriastradh	switch (video->rotation) {
39403b705cfSriastradh	case RR_Rotate_0:
39503b705cfSriastradh		w <<= 1;
39603b705cfSriastradh		for (i = 0; i < h; i++) {
39703b705cfSriastradh			memcpy(dst, src, w);
39803b705cfSriastradh			src += pitch;
39903b705cfSriastradh			dst += frame->pitch[0];
40003b705cfSriastradh		}
40103b705cfSriastradh		break;
40203b705cfSriastradh	case RR_Rotate_90:
40303b705cfSriastradh		h <<= 1;
40403b705cfSriastradh		for (i = 0; i < h; i += 2) {
40503b705cfSriastradh			s = src;
40603b705cfSriastradh			for (j = 0; j < w; j++) {
40703b705cfSriastradh				/* Copy Y */
40803b705cfSriastradh				dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s;
40903b705cfSriastradh				s += 2;
41003b705cfSriastradh			}
41103b705cfSriastradh			src += pitch;
41203b705cfSriastradh		}
41303b705cfSriastradh		h >>= 1;
41403b705cfSriastradh		src = buf + (y * pitch) + (x << 1);
41503b705cfSriastradh		for (i = 0; i < h; i += 2) {
41603b705cfSriastradh			for (j = 0; j < w; j += 2) {
41703b705cfSriastradh				/* Copy U */
41803b705cfSriastradh				dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
41903b705cfSriastradh				dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
42003b705cfSriastradh				/* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
42103b705cfSriastradh				dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
42203b705cfSriastradh			}
42303b705cfSriastradh		}
42403b705cfSriastradh		break;
42503b705cfSriastradh	case RR_Rotate_180:
42603b705cfSriastradh		w <<= 1;
42703b705cfSriastradh		for (i = 0; i < h; i++) {
42803b705cfSriastradh			s = src;
42903b705cfSriastradh			for (j = 0; j < w; j += 4) {
43003b705cfSriastradh				dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++;
43103b705cfSriastradh				dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++;
43203b705cfSriastradh				dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++;
43303b705cfSriastradh				dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++;
43403b705cfSriastradh			}
43503b705cfSriastradh			src += pitch;
43603b705cfSriastradh		}
43703b705cfSriastradh		break;
43803b705cfSriastradh	case RR_Rotate_270:
43903b705cfSriastradh		h <<= 1;
44003b705cfSriastradh		for (i = 0; i < h; i += 2) {
44103b705cfSriastradh			s = src;
44203b705cfSriastradh			for (j = 0; j < w; j++) {
44303b705cfSriastradh				/* Copy Y */
44403b705cfSriastradh				dst[(h - i - 2) + (j * frame->pitch[0])] = *s;
44503b705cfSriastradh				s += 2;
44603b705cfSriastradh			}
44703b705cfSriastradh			src += pitch;
44803b705cfSriastradh		}
44903b705cfSriastradh		h >>= 1;
45003b705cfSriastradh		src = buf + (y * pitch) + (x << 1);
45103b705cfSriastradh		for (i = 0; i < h; i += 2) {
45203b705cfSriastradh			for (j = 0; j < w; j += 2) {
45303b705cfSriastradh				/* Copy U */
45403b705cfSriastradh				dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
45503b705cfSriastradh				dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
45603b705cfSriastradh				/* Copy V */
45703b705cfSriastradh				dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
45803b705cfSriastradh				dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
45903b705cfSriastradh			}
46003b705cfSriastradh		}
46103b705cfSriastradh		break;
46203b705cfSriastradh	}
46303b705cfSriastradh}
46403b705cfSriastradh
46503b705cfSriastradhbool
46603b705cfSriastradhsna_video_copy_data(struct sna_video *video,
46703b705cfSriastradh		    struct sna_video_frame *frame,
46803b705cfSriastradh		    const uint8_t *buf)
46903b705cfSriastradh{
47003b705cfSriastradh	uint8_t *dst;
47103b705cfSriastradh
47203b705cfSriastradh	DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n",
47303b705cfSriastradh	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
47403b705cfSriastradh	     frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1],
47503b705cfSriastradh	     video->rotation, video->textured));
47603b705cfSriastradh	DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n",
47703b705cfSriastradh	     __FUNCTION__,
47803b705cfSriastradh	     frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2,
47903b705cfSriastradh	     frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2));
48003b705cfSriastradh	assert(frame->width && frame->height);
48103b705cfSriastradh	assert(frame->size);
48203b705cfSriastradh
48303b705cfSriastradh	/* In the common case, we can simply the upload in a single pwrite */
48403b705cfSriastradh	if (video->rotation == RR_Rotate_0 && !video->tiled) {
48503b705cfSriastradh		DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n",
48603b705cfSriastradh		     __FUNCTION__, is_planar_fourcc(frame->id)));
48703b705cfSriastradh		if (is_planar_fourcc(frame->id)) {
48803b705cfSriastradh			int w = frame->image.x2 - frame->image.x1;
48903b705cfSriastradh			int h = frame->image.y2 - frame->image.y1;
49003b705cfSriastradh			if (ALIGN(h, 2) == frame->height &&
49103b705cfSriastradh			    ALIGN(w >> 1, 4) == frame->pitch[0] &&
49203b705cfSriastradh			    ALIGN(w, 4) == frame->pitch[1]) {
49303b705cfSriastradh				if (frame->bo) {
49403b705cfSriastradh					kgem_bo_write(&video->sna->kgem, frame->bo,
49503b705cfSriastradh						      buf, frame->size);
49603b705cfSriastradh				} else {
49703b705cfSriastradh					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
49803b705cfSriastradh								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
49903b705cfSriastradh								       (void **)&dst);
50003b705cfSriastradh					if (frame->bo == NULL)
50103b705cfSriastradh						return false;
50203b705cfSriastradh
50303b705cfSriastradh					memcpy(dst, buf, frame->size);
50403b705cfSriastradh				}
50503b705cfSriastradh				if (frame->id != FOURCC_I420) {
50603b705cfSriastradh					uint32_t tmp;
50703b705cfSriastradh					tmp = frame->VBufOffset;
50803b705cfSriastradh					frame->VBufOffset = frame->UBufOffset;
50903b705cfSriastradh					frame->UBufOffset = tmp;
51003b705cfSriastradh				}
51103b705cfSriastradh				return true;
51203b705cfSriastradh			}
51303b705cfSriastradh		} else {
51403b705cfSriastradh			if (frame->width*2 == frame->pitch[0]) {
51503b705cfSriastradh				if (frame->bo) {
51603b705cfSriastradh					kgem_bo_write(&video->sna->kgem, frame->bo,
51703b705cfSriastradh						      buf + (2U*frame->image.y1 * frame->width) + (frame->image.x1 << 1),
51803b705cfSriastradh						      2U*(frame->image.y2-frame->image.y1)*frame->width);
51903b705cfSriastradh				} else {
52003b705cfSriastradh					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
52103b705cfSriastradh								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
52203b705cfSriastradh								       (void **)&dst);
52303b705cfSriastradh					if (frame->bo == NULL)
52403b705cfSriastradh						return false;
52503b705cfSriastradh
52603b705cfSriastradh					memcpy(dst,
52703b705cfSriastradh					       buf + (frame->image.y1 * frame->width*2) + (frame->image.x1 << 1),
52803b705cfSriastradh					       2U*(frame->image.y2-frame->image.y1)*frame->width);
52903b705cfSriastradh				}
53003b705cfSriastradh				return true;
53103b705cfSriastradh			}
53203b705cfSriastradh		}
53303b705cfSriastradh
53403b705cfSriastradh		DBG(("%s: source cropped, fallback\n", __FUNCTION__));
53503b705cfSriastradh	}
53603b705cfSriastradh
53703b705cfSriastradh	/* copy data, must use GTT so that we keep the overlay uncached */
53803b705cfSriastradh	if (frame->bo) {
53903b705cfSriastradh		dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo);
54003b705cfSriastradh		if (dst == NULL)
54103b705cfSriastradh			return false;
54203b705cfSriastradh	} else {
54303b705cfSriastradh		frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
54403b705cfSriastradh					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
54503b705cfSriastradh					       (void **)&dst);
54603b705cfSriastradh		if (frame->bo == NULL)
54703b705cfSriastradh			return false;
54803b705cfSriastradh	}
54903b705cfSriastradh
55003b705cfSriastradh	if (is_planar_fourcc(frame->id))
55103b705cfSriastradh		sna_copy_planar_data(video, frame, buf, dst);
55203b705cfSriastradh	else
55303b705cfSriastradh		sna_copy_packed_data(video, frame, buf, dst);
55403b705cfSriastradh
55503b705cfSriastradh	return true;
55603b705cfSriastradh}
55703b705cfSriastradh
55803b705cfSriastradhXvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
55903b705cfSriastradh{
56003b705cfSriastradh	XvAdaptorPtr new_adaptors;
56103b705cfSriastradh
56203b705cfSriastradh	new_adaptors = realloc(sna->xv.adaptors,
56303b705cfSriastradh			       (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec));
56403b705cfSriastradh	if (new_adaptors == NULL)
56503b705cfSriastradh		return NULL;
56603b705cfSriastradh
56703b705cfSriastradh	if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) {
56803b705cfSriastradh		XvAdaptorPtr adaptor = new_adaptors;
56903b705cfSriastradh		int i = sna->xv.num_adaptors, j;
57003b705cfSriastradh		while (i--) {
57103b705cfSriastradh			for (j = 0; j < adaptor->nPorts; j++)
57203b705cfSriastradh				adaptor->pPorts[j].pAdaptor = adaptor;
57303b705cfSriastradh			adaptor++;
57403b705cfSriastradh		}
57503b705cfSriastradh	}
57603b705cfSriastradh
57703b705cfSriastradh	sna->xv.adaptors = new_adaptors;
57803b705cfSriastradh	return &sna->xv.adaptors[sna->xv.num_adaptors++];
57903b705cfSriastradh}
58003b705cfSriastradh
58103b705cfSriastradhint
58203b705cfSriastradhsna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out)
58303b705cfSriastradh{
58403b705cfSriastradh	*out = in;
58503b705cfSriastradh	return Success;
58603b705cfSriastradh}
58703b705cfSriastradh
58803b705cfSriastradhint
58903b705cfSriastradhsna_xv_free_port(XvPortPtr port)
59003b705cfSriastradh{
59103b705cfSriastradh	return Success;
59203b705cfSriastradh}
59303b705cfSriastradh
59403b705cfSriastradhint
59503b705cfSriastradhsna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats)
59603b705cfSriastradh{
59703b705cfSriastradh	XvFormatPtr out = formats;
59803b705cfSriastradh	int count = 0;
59903b705cfSriastradh
60003b705cfSriastradh	while (num_formats--) {
60103b705cfSriastradh		int num_visuals = screen->numVisuals;
60203b705cfSriastradh		VisualPtr v = screen->visuals;
60303b705cfSriastradh
60403b705cfSriastradh		while (num_visuals--) {
60503b705cfSriastradh			if (v->class == TrueColor &&
60603b705cfSriastradh			    v->nplanes == formats->depth) {
60703b705cfSriastradh				int tmp = out[count].depth;
60803b705cfSriastradh				out[count].depth = formats->depth;
60903b705cfSriastradh				out[count].visual = v->vid;
61003b705cfSriastradh				formats->depth = tmp;
61103b705cfSriastradh				count++;
61203b705cfSriastradh				break;
61303b705cfSriastradh			}
61403b705cfSriastradh			v++;
61503b705cfSriastradh		}
61603b705cfSriastradh
61703b705cfSriastradh		formats++;
61803b705cfSriastradh	}
61903b705cfSriastradh
62003b705cfSriastradh	return count;
62103b705cfSriastradh}
62203b705cfSriastradh
62303b705cfSriastradhstatic int
62403b705cfSriastradhsna_xv_query_adaptors(ScreenPtr screen,
62503b705cfSriastradh		      XvAdaptorPtr *adaptors,
62603b705cfSriastradh		      int *num_adaptors)
62703b705cfSriastradh{
62803b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
62903b705cfSriastradh
63003b705cfSriastradh	*num_adaptors = sna->xv.num_adaptors;
63103b705cfSriastradh	*adaptors = sna->xv.adaptors;
63203b705cfSriastradh	return Success;
63303b705cfSriastradh}
63403b705cfSriastradh
63503b705cfSriastradhstatic Bool
63603b705cfSriastradhsna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL)
63703b705cfSriastradh{
63803b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
63903b705cfSriastradh	int i;
64003b705cfSriastradh
64103b705cfSriastradh	for (i = 0; i < sna->xv.num_adaptors; i++) {
64203b705cfSriastradh		free(sna->xv.adaptors[i].pPorts->devPriv.ptr);
64303b705cfSriastradh		free(sna->xv.adaptors[i].pPorts);
64403b705cfSriastradh		free(sna->xv.adaptors[i].pEncodings);
64503b705cfSriastradh	}
64603b705cfSriastradh	free(sna->xv.adaptors);
64703b705cfSriastradh
64803b705cfSriastradh	sna->xv.adaptors = NULL;
64903b705cfSriastradh	sna->xv.num_adaptors = 0;
65003b705cfSriastradh
65103b705cfSriastradh	return TRUE;
65203b705cfSriastradh}
65303b705cfSriastradh
65403b705cfSriastradhvoid sna_video_init(struct sna *sna, ScreenPtr screen)
65503b705cfSriastradh{
65603b705cfSriastradh	XvScreenPtr xv;
65703b705cfSriastradh
65803b705cfSriastradh	if (noXvExtension)
65903b705cfSriastradh		return;
66003b705cfSriastradh
66103b705cfSriastradh	if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) {
66203b705cfSriastradh		XF86VideoAdaptorPtr *adaptors = NULL;
66303b705cfSriastradh		int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
66403b705cfSriastradh		if (num_adaptors)
66503b705cfSriastradh			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
66603b705cfSriastradh				   "Ignoring generic xf86XV adaptors");
66703b705cfSriastradh		free(adaptors);
66803b705cfSriastradh	}
66903b705cfSriastradh
67003b705cfSriastradh	if (XvScreenInit(screen) != Success)
67103b705cfSriastradh		return;
67203b705cfSriastradh
67303b705cfSriastradh	xv = to_xv(screen);
67403b705cfSriastradh	xv->ddCloseScreen = sna_xv_close_screen;
67503b705cfSriastradh	xv->ddQueryAdaptors = sna_xv_query_adaptors;
67603b705cfSriastradh
67703b705cfSriastradh	sna_video_textured_setup(sna, screen);
67803b705cfSriastradh	sna_video_sprite_setup(sna, screen);
67903b705cfSriastradh	sna_video_overlay_setup(sna, screen);
68003b705cfSriastradh
68103b705cfSriastradh	if (sna->xv.num_adaptors >= 2 &&
68203b705cfSriastradh	    xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) {
68303b705cfSriastradh		XvAdaptorRec tmp;
68403b705cfSriastradh
68503b705cfSriastradh		tmp = sna->xv.adaptors[0];
68603b705cfSriastradh		sna->xv.adaptors[0] = sna->xv.adaptors[1];
68703b705cfSriastradh		sna->xv.adaptors[1] = tmp;
68803b705cfSriastradh	}
68903b705cfSriastradh
69003b705cfSriastradh	xv->nAdaptors = sna->xv.num_adaptors;
69103b705cfSriastradh	xv->pAdaptors = sna->xv.adaptors;
69203b705cfSriastradh
69303b705cfSriastradh	sna_video_xvmc_setup(sna, screen);
69403b705cfSriastradh}
69503b705cfSriastradh
69603b705cfSriastradhvoid sna_video_destroy_window(WindowPtr win)
69703b705cfSriastradh{
69803b705cfSriastradh	XvPortPtr port;
69903b705cfSriastradh
70003b705cfSriastradh	port = sna_window_get_port(win);
70103b705cfSriastradh	if (port)
70203b705cfSriastradh		port->pAdaptor->ddStopVideo(NULL, port, &win->drawable);
70303b705cfSriastradh	assert(sna_window_get_port(win) == NULL);
70403b705cfSriastradh}
705