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 <errno.h>
5203b705cfSriastradh
5303b705cfSriastradh#include <sys/mman.h>
5403b705cfSriastradh
5503b705cfSriastradh#include "sna.h"
5603b705cfSriastradh#include "sna_reg.h"
5703b705cfSriastradh#include "sna_video.h"
5803b705cfSriastradh
5903b705cfSriastradh#include "intel_options.h"
6003b705cfSriastradh
6103b705cfSriastradh#include <xf86xv.h>
62fe8aea9eSmrg#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
63fe8aea9eSmrg#include <sys/types.h>
64fe8aea9eSmrg#include <sys/endian.h>
65fe8aea9eSmrg#ifdef __OpenBSD__
66fe8aea9eSmrg#define bswap_32 swap32
67fe8aea9eSmrg#else
68fe8aea9eSmrg#define bswap_32 bswap32
69fe8aea9eSmrg#endif
70fe8aea9eSmrg#else
71fe8aea9eSmrg#include <byteswap.h>
72fe8aea9eSmrg#endif
7303b705cfSriastradh
7403b705cfSriastradh#ifdef SNA_XVMC
7503b705cfSriastradh#define _SNA_XVMC_SERVER_
7603b705cfSriastradh#include "sna_video_hwmc.h"
7703b705cfSriastradh#else
7803b705cfSriastradhstatic inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr)
7903b705cfSriastradh{
8042542f5fSchristos	DBG(("%s: XvMC not compiled in\n", __FUNCTION__));
8103b705cfSriastradh}
8203b705cfSriastradh#endif
8303b705cfSriastradh
8403b705cfSriastradhvoid sna_video_free_buffers(struct sna_video *video)
8503b705cfSriastradh{
8603b705cfSriastradh	unsigned int i;
8703b705cfSriastradh
8803b705cfSriastradh	for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
8903b705cfSriastradh		if (video->old_buf[i]) {
9003b705cfSriastradh			kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]);
9103b705cfSriastradh			video->old_buf[i] = NULL;
9203b705cfSriastradh		}
9303b705cfSriastradh	}
9403b705cfSriastradh
9503b705cfSriastradh	if (video->buf) {
9603b705cfSriastradh		kgem_bo_destroy(&video->sna->kgem, video->buf);
9703b705cfSriastradh		video->buf = NULL;
9803b705cfSriastradh	}
9903b705cfSriastradh}
10003b705cfSriastradh
10103b705cfSriastradhstruct kgem_bo *
10203b705cfSriastradhsna_video_buffer(struct sna_video *video,
10303b705cfSriastradh		 struct sna_video_frame *frame)
10403b705cfSriastradh{
10503b705cfSriastradh	/* Free the current buffer if we're going to have to reallocate */
10603b705cfSriastradh	if (video->buf && __kgem_bo_size(video->buf) < frame->size)
10703b705cfSriastradh		sna_video_free_buffers(video);
10803b705cfSriastradh
10942542f5fSchristos	if (video->buf && video->buf->scanout) {
11042542f5fSchristos		if (frame->width != video->width ||
11142542f5fSchristos		    frame->height != video->height ||
11242542f5fSchristos		    frame->id != video->format)
11342542f5fSchristos			sna_video_free_buffers(video);
11442542f5fSchristos	}
11542542f5fSchristos
11603b705cfSriastradh	if (video->buf == NULL) {
11703b705cfSriastradh		if (video->tiled) {
11803b705cfSriastradh			video->buf = kgem_create_2d(&video->sna->kgem,
11903b705cfSriastradh						    frame->width, frame->height, 32,
12003b705cfSriastradh						    I915_TILING_X, CREATE_EXACT);
12103b705cfSriastradh		} else {
12203b705cfSriastradh			video->buf = kgem_create_linear(&video->sna->kgem, frame->size,
12303b705cfSriastradh							CREATE_GTT_MAP);
12403b705cfSriastradh		}
12503b705cfSriastradh	}
12603b705cfSriastradh
12742542f5fSchristos	video->width  = frame->width;
12842542f5fSchristos	video->height = frame->height;
12942542f5fSchristos	video->format = frame->id;
13042542f5fSchristos
13103b705cfSriastradh	return video->buf;
13203b705cfSriastradh}
13303b705cfSriastradh
13403b705cfSriastradhvoid sna_video_buffer_fini(struct sna_video *video)
13503b705cfSriastradh{
13603b705cfSriastradh	struct kgem_bo *bo;
13703b705cfSriastradh
13803b705cfSriastradh	bo = video->old_buf[1];
13903b705cfSriastradh	video->old_buf[1] = video->old_buf[0];
14003b705cfSriastradh	video->old_buf[0] = video->buf;
14103b705cfSriastradh	video->buf = bo;
14203b705cfSriastradh}
14303b705cfSriastradh
14403b705cfSriastradhbool
14542542f5fSchristossna_video_clip_helper(struct sna_video *video,
14603b705cfSriastradh		      struct sna_video_frame *frame,
14742542f5fSchristos		      xf86CrtcPtr *crtc_ret,
14803b705cfSriastradh		      BoxPtr dst,
14903b705cfSriastradh		      short src_x, short src_y,
15003b705cfSriastradh		      short drw_x, short drw_y,
15103b705cfSriastradh		      short src_w, short src_h,
15203b705cfSriastradh		      short drw_w, short drw_h,
15303b705cfSriastradh		      RegionPtr reg)
15403b705cfSriastradh{
15503b705cfSriastradh	bool ret;
15603b705cfSriastradh	RegionRec crtc_region_local;
15703b705cfSriastradh	RegionPtr crtc_region = reg;
15803b705cfSriastradh	INT32 x1, x2, y1, y2;
15903b705cfSriastradh	xf86CrtcPtr crtc;
16003b705cfSriastradh
16103b705cfSriastradh	x1 = src_x;
16203b705cfSriastradh	x2 = src_x + src_w;
16303b705cfSriastradh	y1 = src_y;
16403b705cfSriastradh	y2 = src_y + src_h;
16503b705cfSriastradh
16603b705cfSriastradh	dst->x1 = drw_x;
16703b705cfSriastradh	dst->x2 = drw_x + drw_w;
16803b705cfSriastradh	dst->y1 = drw_y;
16903b705cfSriastradh	dst->y2 = drw_y + drw_h;
17003b705cfSriastradh
17103b705cfSriastradh	/*
17203b705cfSriastradh	 * For overlay video, compute the relevant CRTC and
17303b705cfSriastradh	 * clip video to that
17403b705cfSriastradh	 */
17542542f5fSchristos	crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc);
17603b705cfSriastradh
17703b705cfSriastradh	/* For textured video, we don't actually want to clip at all. */
17803b705cfSriastradh	if (crtc && !video->textured) {
17903b705cfSriastradh		crtc_region_local.extents = crtc->bounds;
18003b705cfSriastradh		crtc_region_local.data = NULL;
18103b705cfSriastradh		crtc_region = &crtc_region_local;
18203b705cfSriastradh		RegionIntersect(crtc_region, crtc_region, reg);
18303b705cfSriastradh	}
18403b705cfSriastradh	*crtc_ret = crtc;
18503b705cfSriastradh
18603b705cfSriastradh	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
18703b705cfSriastradh				    crtc_region, frame->width, frame->height);
18803b705cfSriastradh	if (crtc_region != reg)
18903b705cfSriastradh		RegionUninit(crtc_region);
19003b705cfSriastradh
19103b705cfSriastradh	frame->src.x1 = x1 >> 16;
19203b705cfSriastradh	frame->src.y1 = y1 >> 16;
19303b705cfSriastradh	frame->src.x2 = (x2 + 0xffff) >> 16;
19403b705cfSriastradh	frame->src.y2 = (y2 + 0xffff) >> 16;
19503b705cfSriastradh
19603b705cfSriastradh	frame->image.x1 = frame->src.x1 & ~1;
19703b705cfSriastradh	frame->image.x2 = ALIGN(frame->src.x2, 2);
19803b705cfSriastradh	if (is_planar_fourcc(frame->id)) {
19903b705cfSriastradh		frame->image.y1 = frame->src.y1 & ~1;
20003b705cfSriastradh		frame->image.y2 = ALIGN(frame->src.y2, 2);
20103b705cfSriastradh	} else {
20203b705cfSriastradh		frame->image.y1 = frame->src.y1;
20303b705cfSriastradh		frame->image.y2 = frame->src.y2;
20403b705cfSriastradh	}
20503b705cfSriastradh
20603b705cfSriastradh	return ret;
20703b705cfSriastradh}
20803b705cfSriastradh
20903b705cfSriastradhvoid
21003b705cfSriastradhsna_video_frame_init(struct sna_video *video,
21103b705cfSriastradh		     int id, short width, short height,
21203b705cfSriastradh		     struct sna_video_frame *frame)
21303b705cfSriastradh{
21403b705cfSriastradh	DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n",
21503b705cfSriastradh	     __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment));
21603b705cfSriastradh	assert(width && height);
21703b705cfSriastradh
21803b705cfSriastradh	frame->bo = NULL;
21903b705cfSriastradh	frame->id = id;
22003b705cfSriastradh	frame->width = width;
22103b705cfSriastradh	frame->height = height;
22242542f5fSchristos	frame->rotation = 0;
22342542f5fSchristos}
22442542f5fSchristos
22542542f5fSchristosvoid
22642542f5fSchristossna_video_frame_set_rotation(struct sna_video *video,
22742542f5fSchristos			     struct sna_video_frame *frame,
22842542f5fSchristos			     Rotation rotation)
22942542f5fSchristos{
23042542f5fSchristos	unsigned width = frame->width;
23142542f5fSchristos	unsigned height = frame->height;
23242542f5fSchristos	unsigned align;
23342542f5fSchristos
23442542f5fSchristos	DBG(("%s: rotation=%d\n", __FUNCTION__, rotation));
23542542f5fSchristos	frame->rotation = rotation;
23603b705cfSriastradh
23703b705cfSriastradh	align = video->alignment;
23803b705cfSriastradh#if SNA_XVMC
23903b705cfSriastradh	/* for i915 xvmc, hw requires 1kb aligned surfaces */
24042542f5fSchristos	if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024)
24103b705cfSriastradh		align = 1024;
24203b705cfSriastradh#endif
24303b705cfSriastradh
24403b705cfSriastradh	/* Determine the desired destination pitch (representing the
24503b705cfSriastradh	 * chroma's pitch in the planar case).
24603b705cfSriastradh	 */
247fe8aea9eSmrg	if (is_nv12_fourcc(frame->id)) {
248fe8aea9eSmrg		assert((width & 1) == 0);
249fe8aea9eSmrg		assert((height & 1) == 0);
250fe8aea9eSmrg		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
251fe8aea9eSmrg			frame->pitch[0] = ALIGN(height, align);
252fe8aea9eSmrg			frame->pitch[1] = ALIGN(height, align);
253fe8aea9eSmrg			frame->size = width * frame->pitch[1] +
254fe8aea9eSmrg				width / 2 * frame->pitch[0];
255fe8aea9eSmrg		} else {
256fe8aea9eSmrg			frame->pitch[0] = ALIGN(width, align);
257fe8aea9eSmrg			frame->pitch[1] = ALIGN(width, align);
258fe8aea9eSmrg			frame->size = height * frame->pitch[1] +
259fe8aea9eSmrg				height / 2 * frame->pitch[0];
260fe8aea9eSmrg		}
261fe8aea9eSmrg
262fe8aea9eSmrg		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
263fe8aea9eSmrg			frame->UBufOffset = (int)frame->pitch[1] * width;
264fe8aea9eSmrg			frame->VBufOffset = frame->UBufOffset;
265fe8aea9eSmrg		} else {
266fe8aea9eSmrg			frame->UBufOffset = (int)frame->pitch[1] * height;
267fe8aea9eSmrg			frame->VBufOffset = frame->UBufOffset;
268fe8aea9eSmrg		}
269fe8aea9eSmrg	} else if (is_planar_fourcc(frame->id)) {
27003b705cfSriastradh		assert((width & 1) == 0);
27103b705cfSriastradh		assert((height & 1) == 0);
27242542f5fSchristos		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
27303b705cfSriastradh			frame->pitch[0] = ALIGN((height / 2), align);
27403b705cfSriastradh			frame->pitch[1] = ALIGN(height, align);
27503b705cfSriastradh			frame->size = width;
27603b705cfSriastradh		} else {
27703b705cfSriastradh			frame->pitch[0] = ALIGN((width / 2), align);
27803b705cfSriastradh			frame->pitch[1] = ALIGN(width, align);
27903b705cfSriastradh			frame->size = height;
28003b705cfSriastradh		}
28103b705cfSriastradh		frame->size *= frame->pitch[0] + frame->pitch[1];
28203b705cfSriastradh
28342542f5fSchristos		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
28403b705cfSriastradh			frame->UBufOffset = (int)frame->pitch[1] * width;
28503b705cfSriastradh			frame->VBufOffset =
28603b705cfSriastradh				frame->UBufOffset + (int)frame->pitch[0] * width / 2;
28703b705cfSriastradh		} else {
28803b705cfSriastradh			frame->UBufOffset = (int)frame->pitch[1] * height;
28903b705cfSriastradh			frame->VBufOffset =
29003b705cfSriastradh				frame->UBufOffset + (int)frame->pitch[0] * height / 2;
29103b705cfSriastradh		}
29203b705cfSriastradh	} else {
29303b705cfSriastradh		switch (frame->id) {
29403b705cfSriastradh		case FOURCC_RGB888:
295fe8aea9eSmrg		case FOURCC_AYUV:
29642542f5fSchristos			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
29703b705cfSriastradh				frame->pitch[0] = ALIGN((height << 2), align);
29803b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
29903b705cfSriastradh			} else {
30003b705cfSriastradh				frame->pitch[0] = ALIGN((width << 2), align);
30103b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
30203b705cfSriastradh			}
30303b705cfSriastradh			frame->UBufOffset = frame->VBufOffset = 0;
30403b705cfSriastradh			break;
30503b705cfSriastradh		case FOURCC_RGB565:
30642542f5fSchristos			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
30703b705cfSriastradh				frame->pitch[0] = ALIGN((height << 1), align);
30803b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
30903b705cfSriastradh			} else {
31003b705cfSriastradh				frame->pitch[0] = ALIGN((width << 1), align);
31103b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
31203b705cfSriastradh			}
31303b705cfSriastradh			frame->UBufOffset = frame->VBufOffset = 0;
31403b705cfSriastradh			break;
31503b705cfSriastradh
31603b705cfSriastradh		default:
31742542f5fSchristos			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
31803b705cfSriastradh				frame->pitch[0] = ALIGN((height << 1), align);
31903b705cfSriastradh				frame->size = (int)frame->pitch[0] * width;
32003b705cfSriastradh			} else {
32103b705cfSriastradh				frame->pitch[0] = ALIGN((width << 1), align);
32203b705cfSriastradh				frame->size = (int)frame->pitch[0] * height;
32303b705cfSriastradh			}
32403b705cfSriastradh			break;
32503b705cfSriastradh		}
32603b705cfSriastradh		frame->pitch[1] = 0;
32703b705cfSriastradh		frame->UBufOffset = 0;
32803b705cfSriastradh		frame->VBufOffset = 0;
32903b705cfSriastradh	}
33003b705cfSriastradh
33103b705cfSriastradh	assert(frame->size);
33203b705cfSriastradh}
33303b705cfSriastradh
334fe8aea9eSmrgstatic void plane_dims(const struct sna_video_frame *frame, int sub,
335fe8aea9eSmrg		       int *x, int *y, int *w, int *h)
336fe8aea9eSmrg{
337fe8aea9eSmrg	*x = frame->image.x1;
338fe8aea9eSmrg	*y = frame->image.y1;
339fe8aea9eSmrg	*w = frame->image.x2 - frame->image.x1;
340fe8aea9eSmrg	*h = frame->image.y2 - frame->image.y1;
341fe8aea9eSmrg
342fe8aea9eSmrg	if (sub) {
343fe8aea9eSmrg		*x >>= 1; *w >>= 1;
344fe8aea9eSmrg		*y >>= 1; *h >>= 1;
345fe8aea9eSmrg	}
346fe8aea9eSmrg}
347fe8aea9eSmrg
348fe8aea9eSmrgstatic void sna_memcpy_cbcr_plane(struct sna_video *video,
349fe8aea9eSmrg				  uint16_t *dst, const uint16_t *src,
350fe8aea9eSmrg				  const struct sna_video_frame *frame)
351fe8aea9eSmrg{
352fe8aea9eSmrg	int dstPitch = frame->pitch[0] >> 1, srcPitch;
353fe8aea9eSmrg	const uint16_t *s;
354fe8aea9eSmrg	int i, j = 0;
355fe8aea9eSmrg	int x, y, w, h;
356fe8aea9eSmrg
357fe8aea9eSmrg	plane_dims(frame, 1, &x, &y, &w, &h);
358fe8aea9eSmrg
359fe8aea9eSmrg	srcPitch = ALIGN((frame->width >> 1), 2);
360fe8aea9eSmrg
361fe8aea9eSmrg	src += y * srcPitch + x;
362fe8aea9eSmrg	if (!video->textured)
363fe8aea9eSmrg		x = y = 0;
364fe8aea9eSmrg
365fe8aea9eSmrg	switch (frame->rotation) {
366fe8aea9eSmrg	case RR_Rotate_0:
367fe8aea9eSmrg		dst += y * dstPitch + x;
368fe8aea9eSmrg		if (srcPitch == dstPitch && srcPitch == w)
369fe8aea9eSmrg			memcpy(dst, src, (srcPitch * h) << 1);
370fe8aea9eSmrg		else while (h--) {
371fe8aea9eSmrg			memcpy(dst, src, w << 1);
372fe8aea9eSmrg			src += srcPitch;
373fe8aea9eSmrg			dst += dstPitch;
374fe8aea9eSmrg		}
375fe8aea9eSmrg		break;
376fe8aea9eSmrg	case RR_Rotate_90:
377fe8aea9eSmrg		for (i = 0; i < h; i++) {
378fe8aea9eSmrg			s = src;
379fe8aea9eSmrg			for (j = 0; j < w; j++)
380fe8aea9eSmrg				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
381fe8aea9eSmrg			src += srcPitch;
382fe8aea9eSmrg		}
383fe8aea9eSmrg		break;
384fe8aea9eSmrg	case RR_Rotate_180:
385fe8aea9eSmrg		for (i = 0; i < h; i++) {
386fe8aea9eSmrg			s = src;
387fe8aea9eSmrg			for (j = 0; j < w; j++) {
388fe8aea9eSmrg				dst[(x + w - j - 1) +
389fe8aea9eSmrg				    ((h - i - 1) * dstPitch)] = *s++;
390fe8aea9eSmrg			}
391fe8aea9eSmrg			src += srcPitch;
392fe8aea9eSmrg		}
393fe8aea9eSmrg		break;
394fe8aea9eSmrg	case RR_Rotate_270:
395fe8aea9eSmrg		for (i = 0; i < h; i++) {
396fe8aea9eSmrg			s = src;
397fe8aea9eSmrg			for (j = 0; j < w; j++) {
398fe8aea9eSmrg				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
399fe8aea9eSmrg			}
400fe8aea9eSmrg			src += srcPitch;
401fe8aea9eSmrg		}
402fe8aea9eSmrg		break;
403fe8aea9eSmrg	}
404fe8aea9eSmrg}
405fe8aea9eSmrg
40603b705cfSriastradhstatic void sna_memcpy_plane(struct sna_video *video,
40703b705cfSriastradh			     uint8_t *dst, const uint8_t *src,
40803b705cfSriastradh			     const struct sna_video_frame *frame, int sub)
40903b705cfSriastradh{
41003b705cfSriastradh	int dstPitch = frame->pitch[!sub], srcPitch;
41103b705cfSriastradh	const uint8_t *s;
41203b705cfSriastradh	int i, j = 0;
41303b705cfSriastradh	int x, y, w, h;
41403b705cfSriastradh
415fe8aea9eSmrg	plane_dims(frame, sub, &x, &y, &w, &h);
416fe8aea9eSmrg
417fe8aea9eSmrg	if (sub)
41803b705cfSriastradh		srcPitch = ALIGN((frame->width >> 1), 4);
419fe8aea9eSmrg	else
42003b705cfSriastradh		srcPitch = ALIGN(frame->width, 4);
42103b705cfSriastradh
42203b705cfSriastradh	src += y * srcPitch + x;
42303b705cfSriastradh	if (!video->textured)
42403b705cfSriastradh		x = y = 0;
42503b705cfSriastradh
42642542f5fSchristos	switch (frame->rotation) {
42703b705cfSriastradh	case RR_Rotate_0:
42803b705cfSriastradh		dst += y * dstPitch + x;
42903b705cfSriastradh		if (srcPitch == dstPitch && srcPitch == w)
43003b705cfSriastradh			memcpy(dst, src, srcPitch * h);
43103b705cfSriastradh		else while (h--) {
43203b705cfSriastradh			memcpy(dst, src, w);
43303b705cfSriastradh			src += srcPitch;
43403b705cfSriastradh			dst += dstPitch;
43503b705cfSriastradh		}
43603b705cfSriastradh		break;
43703b705cfSriastradh	case RR_Rotate_90:
43803b705cfSriastradh		for (i = 0; i < h; i++) {
43903b705cfSriastradh			s = src;
44003b705cfSriastradh			for (j = 0; j < w; j++)
44103b705cfSriastradh				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
44203b705cfSriastradh			src += srcPitch;
44303b705cfSriastradh		}
44403b705cfSriastradh		break;
44503b705cfSriastradh	case RR_Rotate_180:
44603b705cfSriastradh		for (i = 0; i < h; i++) {
44703b705cfSriastradh			s = src;
44803b705cfSriastradh			for (j = 0; j < w; j++) {
44903b705cfSriastradh				dst[(x + w - j - 1) +
45003b705cfSriastradh				    ((h - i - 1) * dstPitch)] = *s++;
45103b705cfSriastradh			}
45203b705cfSriastradh			src += srcPitch;
45303b705cfSriastradh		}
45403b705cfSriastradh		break;
45503b705cfSriastradh	case RR_Rotate_270:
45603b705cfSriastradh		for (i = 0; i < h; i++) {
45703b705cfSriastradh			s = src;
45803b705cfSriastradh			for (j = 0; j < w; j++) {
45903b705cfSriastradh				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
46003b705cfSriastradh			}
46103b705cfSriastradh			src += srcPitch;
46203b705cfSriastradh		}
46303b705cfSriastradh		break;
46403b705cfSriastradh	}
46503b705cfSriastradh}
46603b705cfSriastradh
467fe8aea9eSmrgstatic void
468fe8aea9eSmrgsna_copy_nv12_data(struct sna_video *video,
469fe8aea9eSmrg		   const struct sna_video_frame *frame,
470fe8aea9eSmrg		   const uint8_t *src, uint8_t *dst)
471fe8aea9eSmrg{
472fe8aea9eSmrg	sna_memcpy_plane(video, dst, src, frame, 0);
473fe8aea9eSmrg	src += frame->height * ALIGN(frame->width, 4);
474fe8aea9eSmrg	dst += frame->UBufOffset;
475fe8aea9eSmrg	sna_memcpy_cbcr_plane(video, (void*)dst, (void*)src, frame);
476fe8aea9eSmrg}
477fe8aea9eSmrg
47803b705cfSriastradhstatic void
47903b705cfSriastradhsna_copy_planar_data(struct sna_video *video,
48003b705cfSriastradh		     const struct sna_video_frame *frame,
48103b705cfSriastradh		     const uint8_t *src, uint8_t *dst)
48203b705cfSriastradh{
48303b705cfSriastradh	uint8_t *d;
48403b705cfSriastradh
48503b705cfSriastradh	sna_memcpy_plane(video, dst, src, frame, 0);
48603b705cfSriastradh	src += frame->height * ALIGN(frame->width, 4);
48703b705cfSriastradh
48803b705cfSriastradh	if (frame->id == FOURCC_I420)
48903b705cfSriastradh		d = dst + frame->UBufOffset;
49003b705cfSriastradh	else
49103b705cfSriastradh		d = dst + frame->VBufOffset;
49203b705cfSriastradh	sna_memcpy_plane(video, d, src, frame, 1);
49303b705cfSriastradh	src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4);
49403b705cfSriastradh
49503b705cfSriastradh	if (frame->id == FOURCC_I420)
49603b705cfSriastradh		d = dst + frame->VBufOffset;
49703b705cfSriastradh	else
49803b705cfSriastradh		d = dst + frame->UBufOffset;
49903b705cfSriastradh	sna_memcpy_plane(video, d, src, frame, 1);
50003b705cfSriastradh}
50103b705cfSriastradh
50203b705cfSriastradhstatic void
50303b705cfSriastradhsna_copy_packed_data(struct sna_video *video,
50403b705cfSriastradh		     const struct sna_video_frame *frame,
50503b705cfSriastradh		     const uint8_t *buf,
50603b705cfSriastradh		     uint8_t *dst)
50703b705cfSriastradh{
50803b705cfSriastradh	int pitch = frame->width << 1;
50903b705cfSriastradh	const uint8_t *src, *s;
51003b705cfSriastradh	int x, y, w, h;
51103b705cfSriastradh	int i, j;
51203b705cfSriastradh
51303b705cfSriastradh	if (video->textured) {
51403b705cfSriastradh		/* XXX support copying cropped extents */
51503b705cfSriastradh		x = y = 0;
51603b705cfSriastradh		w = frame->width;
51703b705cfSriastradh		h = frame->height;
51803b705cfSriastradh	} else {
51903b705cfSriastradh		x = frame->image.x1;
52003b705cfSriastradh		y = frame->image.y1;
52103b705cfSriastradh		w = frame->image.x2 - frame->image.x1;
52203b705cfSriastradh		h = frame->image.y2 - frame->image.y1;
52303b705cfSriastradh	}
52403b705cfSriastradh
52503b705cfSriastradh	src = buf + (y * pitch) + (x << 1);
52603b705cfSriastradh
52742542f5fSchristos	switch (frame->rotation) {
52803b705cfSriastradh	case RR_Rotate_0:
52903b705cfSriastradh		w <<= 1;
53003b705cfSriastradh		for (i = 0; i < h; i++) {
53103b705cfSriastradh			memcpy(dst, src, w);
53203b705cfSriastradh			src += pitch;
53303b705cfSriastradh			dst += frame->pitch[0];
53403b705cfSriastradh		}
53503b705cfSriastradh		break;
53603b705cfSriastradh	case RR_Rotate_90:
53703b705cfSriastradh		h <<= 1;
53803b705cfSriastradh		for (i = 0; i < h; i += 2) {
53903b705cfSriastradh			s = src;
54003b705cfSriastradh			for (j = 0; j < w; j++) {
54103b705cfSriastradh				/* Copy Y */
54203b705cfSriastradh				dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s;
54303b705cfSriastradh				s += 2;
54403b705cfSriastradh			}
54503b705cfSriastradh			src += pitch;
54603b705cfSriastradh		}
54703b705cfSriastradh		h >>= 1;
54803b705cfSriastradh		src = buf + (y * pitch) + (x << 1);
54903b705cfSriastradh		for (i = 0; i < h; i += 2) {
55003b705cfSriastradh			for (j = 0; j < w; j += 2) {
55103b705cfSriastradh				/* Copy U */
55203b705cfSriastradh				dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
55303b705cfSriastradh				dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
55403b705cfSriastradh				/* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
55503b705cfSriastradh				dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
55603b705cfSriastradh			}
55703b705cfSriastradh		}
55803b705cfSriastradh		break;
55903b705cfSriastradh	case RR_Rotate_180:
56003b705cfSriastradh		w <<= 1;
56103b705cfSriastradh		for (i = 0; i < h; i++) {
56203b705cfSriastradh			s = src;
56303b705cfSriastradh			for (j = 0; j < w; j += 4) {
56403b705cfSriastradh				dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++;
56503b705cfSriastradh				dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++;
56603b705cfSriastradh				dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++;
56703b705cfSriastradh				dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++;
56803b705cfSriastradh			}
56903b705cfSriastradh			src += pitch;
57003b705cfSriastradh		}
57103b705cfSriastradh		break;
57203b705cfSriastradh	case RR_Rotate_270:
57303b705cfSriastradh		h <<= 1;
57403b705cfSriastradh		for (i = 0; i < h; i += 2) {
57503b705cfSriastradh			s = src;
57603b705cfSriastradh			for (j = 0; j < w; j++) {
57703b705cfSriastradh				/* Copy Y */
57803b705cfSriastradh				dst[(h - i - 2) + (j * frame->pitch[0])] = *s;
57903b705cfSriastradh				s += 2;
58003b705cfSriastradh			}
58103b705cfSriastradh			src += pitch;
58203b705cfSriastradh		}
58303b705cfSriastradh		h >>= 1;
58403b705cfSriastradh		src = buf + (y * pitch) + (x << 1);
58503b705cfSriastradh		for (i = 0; i < h; i += 2) {
58603b705cfSriastradh			for (j = 0; j < w; j += 2) {
58703b705cfSriastradh				/* Copy U */
58803b705cfSriastradh				dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
58903b705cfSriastradh				dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
59003b705cfSriastradh				/* Copy V */
59103b705cfSriastradh				dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
59203b705cfSriastradh				dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
59303b705cfSriastradh			}
59403b705cfSriastradh		}
59503b705cfSriastradh		break;
59603b705cfSriastradh	}
59703b705cfSriastradh}
59803b705cfSriastradh
599fe8aea9eSmrgstatic void
600fe8aea9eSmrgsna_copy_ayuv_data(struct sna_video *video,
601fe8aea9eSmrg		   const struct sna_video_frame *frame,
602fe8aea9eSmrg		   const uint8_t *buf,
603fe8aea9eSmrg		   uint8_t *dst)
604fe8aea9eSmrg{
605fe8aea9eSmrg	int pitch = frame->width << 2;
606fe8aea9eSmrg	const uint32_t *src_dw;
607fe8aea9eSmrg	const uint8_t *src;
608fe8aea9eSmrg	uint32_t *dst_dw = (uint32_t *)dst;
609fe8aea9eSmrg	int x, y, w, h;
610fe8aea9eSmrg	int i, j;
611fe8aea9eSmrg
612fe8aea9eSmrg	if (video->textured) {
613fe8aea9eSmrg		/* XXX support copying cropped extents */
614fe8aea9eSmrg		x = y = 0;
615fe8aea9eSmrg		w = frame->width;
616fe8aea9eSmrg		h = frame->height;
617fe8aea9eSmrg	} else {
618fe8aea9eSmrg		x = frame->image.x1;
619fe8aea9eSmrg		y = frame->image.y1;
620fe8aea9eSmrg		w = frame->image.x2 - frame->image.x1;
621fe8aea9eSmrg		h = frame->image.y2 - frame->image.y1;
622fe8aea9eSmrg	}
623fe8aea9eSmrg
624fe8aea9eSmrg	src = buf + (y * pitch) + (x << 2);
625fe8aea9eSmrg	src_dw = (uint32_t *)src;
626fe8aea9eSmrg
627fe8aea9eSmrg	switch (frame->rotation) {
628fe8aea9eSmrg	case RR_Rotate_0:
629fe8aea9eSmrg		for (i = 0; i < h; i++) {
630fe8aea9eSmrg			for (j = 0; j < w; j++) {
631fe8aea9eSmrg				/*
632fe8aea9eSmrg				 * Have to reverse bytes order, because the only
633fe8aea9eSmrg				 * player which supports AYUV format currently is
634fe8aea9eSmrg				 * Gstreamer and it supports in bad way, even though
635fe8aea9eSmrg				 * spec says MSB:AYUV, we get the bytes opposite way.
636fe8aea9eSmrg				 */
637fe8aea9eSmrg				dst_dw[i * w + j] = bswap_32(src_dw[i * w + j]);
638fe8aea9eSmrg			}
639fe8aea9eSmrg		}
640fe8aea9eSmrg		break;
641fe8aea9eSmrg	case RR_Rotate_90:
642fe8aea9eSmrg		for (i = 0; i < h; i++) {
643fe8aea9eSmrg			for (j = 0; j < w; j++) {
644fe8aea9eSmrg				dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]);
645fe8aea9eSmrg			}
646fe8aea9eSmrg		}
647fe8aea9eSmrg		break;
648fe8aea9eSmrg	case RR_Rotate_180:
649fe8aea9eSmrg		for (i = 0; i < h; i++) {
650fe8aea9eSmrg			for (j = 0; j < w; j++) {
651fe8aea9eSmrg				dst_dw[(h - i - 1) * w + w - j - 1] = bswap_32(src_dw[i * w + j]);
652fe8aea9eSmrg			}
653fe8aea9eSmrg		}
654fe8aea9eSmrg		break;
655fe8aea9eSmrg	case RR_Rotate_270:
656fe8aea9eSmrg		for (i = 0; i < h; i++) {
657fe8aea9eSmrg			for (j = 0; j < w; j++) {
658fe8aea9eSmrg				dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]);
659fe8aea9eSmrg			}
660fe8aea9eSmrg		}
661fe8aea9eSmrg		break;
662fe8aea9eSmrg	}
663fe8aea9eSmrg}
664fe8aea9eSmrg
66503b705cfSriastradhbool
66603b705cfSriastradhsna_video_copy_data(struct sna_video *video,
66703b705cfSriastradh		    struct sna_video_frame *frame,
66803b705cfSriastradh		    const uint8_t *buf)
66903b705cfSriastradh{
67003b705cfSriastradh	uint8_t *dst;
67103b705cfSriastradh
67203b705cfSriastradh	DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n",
67303b705cfSriastradh	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
67403b705cfSriastradh	     frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1],
67542542f5fSchristos	     frame->rotation, video->textured));
67603b705cfSriastradh	DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n",
67703b705cfSriastradh	     __FUNCTION__,
67803b705cfSriastradh	     frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2,
67903b705cfSriastradh	     frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2));
68003b705cfSriastradh	assert(frame->width && frame->height);
68142542f5fSchristos	assert(frame->rotation);
68203b705cfSriastradh	assert(frame->size);
68303b705cfSriastradh
68403b705cfSriastradh	/* In the common case, we can simply the upload in a single pwrite */
685fe8aea9eSmrg	if (frame->rotation == RR_Rotate_0 && !video->tiled && !is_ayuv_fourcc(frame->id)) {
68603b705cfSriastradh		DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n",
68703b705cfSriastradh		     __FUNCTION__, is_planar_fourcc(frame->id)));
688fe8aea9eSmrg		if (is_nv12_fourcc(frame->id)) {
689fe8aea9eSmrg			int w = frame->image.x2 - frame->image.x1;
690fe8aea9eSmrg			int h = frame->image.y2 - frame->image.y1;
691fe8aea9eSmrg			if (ALIGN(h, 2) == frame->height &&
692fe8aea9eSmrg			    ALIGN(w, 4) == frame->pitch[0] &&
693fe8aea9eSmrg			    ALIGN(w, 4) == frame->pitch[1]) {
694fe8aea9eSmrg				if (frame->bo) {
695fe8aea9eSmrg					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
696fe8aea9eSmrg							   buf, frame->size))
697fe8aea9eSmrg						goto use_gtt;
698fe8aea9eSmrg				} else {
699fe8aea9eSmrg					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
700fe8aea9eSmrg								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
701fe8aea9eSmrg								       (void **)&dst);
702fe8aea9eSmrg					if (frame->bo == NULL)
703fe8aea9eSmrg						return false;
704fe8aea9eSmrg
705fe8aea9eSmrg					memcpy(dst, buf, frame->size);
706fe8aea9eSmrg				}
707fe8aea9eSmrg				return true;
708fe8aea9eSmrg			}
709fe8aea9eSmrg		} else if (is_planar_fourcc(frame->id)) {
71003b705cfSriastradh			int w = frame->image.x2 - frame->image.x1;
71103b705cfSriastradh			int h = frame->image.y2 - frame->image.y1;
71203b705cfSriastradh			if (ALIGN(h, 2) == frame->height &&
71303b705cfSriastradh			    ALIGN(w >> 1, 4) == frame->pitch[0] &&
71403b705cfSriastradh			    ALIGN(w, 4) == frame->pitch[1]) {
71503b705cfSriastradh				if (frame->bo) {
71642542f5fSchristos					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
71742542f5fSchristos							   buf, frame->size))
71842542f5fSchristos						goto use_gtt;
71903b705cfSriastradh				} else {
72003b705cfSriastradh					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
72103b705cfSriastradh								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
72203b705cfSriastradh								       (void **)&dst);
72303b705cfSriastradh					if (frame->bo == NULL)
72403b705cfSriastradh						return false;
72503b705cfSriastradh
72603b705cfSriastradh					memcpy(dst, buf, frame->size);
72703b705cfSriastradh				}
72803b705cfSriastradh				if (frame->id != FOURCC_I420) {
72903b705cfSriastradh					uint32_t tmp;
73003b705cfSriastradh					tmp = frame->VBufOffset;
73103b705cfSriastradh					frame->VBufOffset = frame->UBufOffset;
73203b705cfSriastradh					frame->UBufOffset = tmp;
73303b705cfSriastradh				}
73403b705cfSriastradh				return true;
73503b705cfSriastradh			}
73603b705cfSriastradh		} else {
73742542f5fSchristos			int x, y, w, h;
73842542f5fSchristos
73942542f5fSchristos			if (video->textured) {
74042542f5fSchristos				/* XXX support copying cropped extents */
74142542f5fSchristos				x = y = 0;
74242542f5fSchristos				w = frame->width;
74342542f5fSchristos				h = frame->height;
74442542f5fSchristos			} else {
74542542f5fSchristos				x = frame->image.x1;
74642542f5fSchristos				y = frame->image.y1;
74742542f5fSchristos				w = frame->image.x2 - frame->image.x1;
74842542f5fSchristos				h = frame->image.y2 - frame->image.y1;
74942542f5fSchristos			}
75042542f5fSchristos
75142542f5fSchristos			if (w*2 == frame->pitch[0]) {
75242542f5fSchristos				buf += (2U*y * frame->width) + (x << 1);
75303b705cfSriastradh				if (frame->bo) {
75442542f5fSchristos					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
75542542f5fSchristos							   buf, 2U*h*frame->width))
75642542f5fSchristos						goto use_gtt;
75703b705cfSriastradh				} else {
75803b705cfSriastradh					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
75903b705cfSriastradh								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
76003b705cfSriastradh								       (void **)&dst);
76103b705cfSriastradh					if (frame->bo == NULL)
76203b705cfSriastradh						return false;
76303b705cfSriastradh
76442542f5fSchristos					memcpy(dst, buf, 2U*h*frame->width);
76503b705cfSriastradh				}
76603b705cfSriastradh				return true;
76703b705cfSriastradh			}
76803b705cfSriastradh		}
76903b705cfSriastradh
77003b705cfSriastradh		DBG(("%s: source cropped, fallback\n", __FUNCTION__));
77103b705cfSriastradh	}
77203b705cfSriastradh
77342542f5fSchristosuse_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
77403b705cfSriastradh	if (frame->bo) {
77503b705cfSriastradh		dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo);
77603b705cfSriastradh		if (dst == NULL)
77703b705cfSriastradh			return false;
77803b705cfSriastradh	} else {
77903b705cfSriastradh		frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
78003b705cfSriastradh					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
78103b705cfSriastradh					       (void **)&dst);
78203b705cfSriastradh		if (frame->bo == NULL)
78303b705cfSriastradh			return false;
78403b705cfSriastradh	}
78503b705cfSriastradh
786fe8aea9eSmrg	if (is_nv12_fourcc(frame->id))
787fe8aea9eSmrg		sna_copy_nv12_data(video, frame, buf, dst);
788fe8aea9eSmrg	else if (is_planar_fourcc(frame->id))
78903b705cfSriastradh		sna_copy_planar_data(video, frame, buf, dst);
790fe8aea9eSmrg	else if (is_ayuv_fourcc(frame->id))
791fe8aea9eSmrg		sna_copy_ayuv_data(video, frame, buf, dst);
79203b705cfSriastradh	else
79303b705cfSriastradh		sna_copy_packed_data(video, frame, buf, dst);
79403b705cfSriastradh
79503b705cfSriastradh	return true;
79603b705cfSriastradh}
79703b705cfSriastradh
798fe8aea9eSmrgvoid sna_video_fill_colorkey(struct sna_video *video,
799fe8aea9eSmrg			     const RegionRec *clip)
800fe8aea9eSmrg{
801fe8aea9eSmrg	struct sna *sna = video->sna;
802fe8aea9eSmrg	PixmapPtr front = sna->front;
803fe8aea9eSmrg	struct kgem_bo *bo = __sna_pixmap_get_bo(front);
804fe8aea9eSmrg	uint8_t *dst, *tmp;
805fe8aea9eSmrg	int w, width;
806fe8aea9eSmrg
807fe8aea9eSmrg	if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip))
808fe8aea9eSmrg		return;
809fe8aea9eSmrg
810fe8aea9eSmrg	assert(bo);
811fe8aea9eSmrg	if (!wedged(sna) &&
812fe8aea9eSmrg	    sna_blt_fill_boxes(sna, GXcopy, bo,
813fe8aea9eSmrg			       front->drawable.bitsPerPixel,
814fe8aea9eSmrg			       video->color_key,
815fe8aea9eSmrg			       region_rects(clip),
816fe8aea9eSmrg			       region_num_rects(clip))) {
817fe8aea9eSmrg		RegionCopy(&video->clip, (RegionPtr)clip);
818fe8aea9eSmrg		return;
819fe8aea9eSmrg	}
820fe8aea9eSmrg
821fe8aea9eSmrg	dst = kgem_bo_map__gtt(&sna->kgem, bo);
822fe8aea9eSmrg	if (dst == NULL)
823fe8aea9eSmrg		return;
824fe8aea9eSmrg
825fe8aea9eSmrg	w = front->drawable.bitsPerPixel/8;
826fe8aea9eSmrg	width = (clip->extents.x2 - clip->extents.x1) * w;
827fe8aea9eSmrg	tmp = malloc(width);
828fe8aea9eSmrg	if (tmp == NULL)
829fe8aea9eSmrg		return;
830fe8aea9eSmrg
831fe8aea9eSmrg	memcpy(tmp, &video->color_key, w);
832fe8aea9eSmrg	while (2 * w < width) {
833fe8aea9eSmrg		memcpy(tmp + w, tmp, w);
834fe8aea9eSmrg		w *= 2;
835fe8aea9eSmrg	}
836fe8aea9eSmrg	if (w < width)
837fe8aea9eSmrg		memcpy(tmp + w, tmp, width - w);
838fe8aea9eSmrg
839fe8aea9eSmrg	if (sigtrap_get() == 0) {
840fe8aea9eSmrg		const BoxRec *box = region_rects(clip);
841fe8aea9eSmrg		int n = region_num_rects(clip);
842fe8aea9eSmrg
843fe8aea9eSmrg		w = front->drawable.bitsPerPixel/8;
844fe8aea9eSmrg		do {
845fe8aea9eSmrg			int y = box->y1;
846fe8aea9eSmrg			uint8_t *row = dst + y*bo->pitch + w*box->x1;
847fe8aea9eSmrg
848fe8aea9eSmrg			width = (box->x2 - box->x1) * w;
849fe8aea9eSmrg			while (y < box->y2) {
850fe8aea9eSmrg				memcpy(row, tmp, width);
851fe8aea9eSmrg				row += bo->pitch;
852fe8aea9eSmrg				y++;
853fe8aea9eSmrg			}
854fe8aea9eSmrg			box++;
855fe8aea9eSmrg		} while (--n);
856fe8aea9eSmrg		sigtrap_put();
857fe8aea9eSmrg
858fe8aea9eSmrg		RegionCopy(&video->clip, (RegionPtr)clip);
859fe8aea9eSmrg	}
860fe8aea9eSmrg
861fe8aea9eSmrg	free(tmp);
862fe8aea9eSmrg}
863fe8aea9eSmrg
86403b705cfSriastradhXvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
86503b705cfSriastradh{
86603b705cfSriastradh	XvAdaptorPtr new_adaptors;
86703b705cfSriastradh
86803b705cfSriastradh	new_adaptors = realloc(sna->xv.adaptors,
86903b705cfSriastradh			       (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec));
87003b705cfSriastradh	if (new_adaptors == NULL)
87103b705cfSriastradh		return NULL;
87203b705cfSriastradh
87303b705cfSriastradh	if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) {
87403b705cfSriastradh		XvAdaptorPtr adaptor = new_adaptors;
87503b705cfSriastradh		int i = sna->xv.num_adaptors, j;
87603b705cfSriastradh		while (i--) {
87703b705cfSriastradh			for (j = 0; j < adaptor->nPorts; j++)
87803b705cfSriastradh				adaptor->pPorts[j].pAdaptor = adaptor;
87903b705cfSriastradh			adaptor++;
88003b705cfSriastradh		}
88103b705cfSriastradh	}
88203b705cfSriastradh
88303b705cfSriastradh	sna->xv.adaptors = new_adaptors;
88403b705cfSriastradh	return &sna->xv.adaptors[sna->xv.num_adaptors++];
88503b705cfSriastradh}
88603b705cfSriastradh
88703b705cfSriastradhint
88803b705cfSriastradhsna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out)
88903b705cfSriastradh{
89003b705cfSriastradh	*out = in;
89103b705cfSriastradh	return Success;
89203b705cfSriastradh}
89303b705cfSriastradh
89403b705cfSriastradhint
89503b705cfSriastradhsna_xv_free_port(XvPortPtr port)
89603b705cfSriastradh{
89703b705cfSriastradh	return Success;
89803b705cfSriastradh}
89903b705cfSriastradh
90003b705cfSriastradhint
90103b705cfSriastradhsna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats)
90203b705cfSriastradh{
90303b705cfSriastradh	XvFormatPtr out = formats;
90403b705cfSriastradh	int count = 0;
90503b705cfSriastradh
90603b705cfSriastradh	while (num_formats--) {
90703b705cfSriastradh		int num_visuals = screen->numVisuals;
90803b705cfSriastradh		VisualPtr v = screen->visuals;
90903b705cfSriastradh
91003b705cfSriastradh		while (num_visuals--) {
91103b705cfSriastradh			if (v->class == TrueColor &&
91203b705cfSriastradh			    v->nplanes == formats->depth) {
91303b705cfSriastradh				int tmp = out[count].depth;
91403b705cfSriastradh				out[count].depth = formats->depth;
91503b705cfSriastradh				out[count].visual = v->vid;
91603b705cfSriastradh				formats->depth = tmp;
91703b705cfSriastradh				count++;
91803b705cfSriastradh				break;
91903b705cfSriastradh			}
92003b705cfSriastradh			v++;
92103b705cfSriastradh		}
92203b705cfSriastradh
92303b705cfSriastradh		formats++;
92403b705cfSriastradh	}
92503b705cfSriastradh
92603b705cfSriastradh	return count;
92703b705cfSriastradh}
92803b705cfSriastradh
92942542f5fSchristos#if XORG_XV_VERSION < 2
93003b705cfSriastradhstatic int
93103b705cfSriastradhsna_xv_query_adaptors(ScreenPtr screen,
93203b705cfSriastradh		      XvAdaptorPtr *adaptors,
93303b705cfSriastradh		      int *num_adaptors)
93403b705cfSriastradh{
93503b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
93603b705cfSriastradh
93703b705cfSriastradh	*num_adaptors = sna->xv.num_adaptors;
93803b705cfSriastradh	*adaptors = sna->xv.adaptors;
93903b705cfSriastradh	return Success;
94003b705cfSriastradh}
94103b705cfSriastradh
94203b705cfSriastradhstatic Bool
94303b705cfSriastradhsna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL)
94403b705cfSriastradh{
94503b705cfSriastradh	struct sna *sna = to_sna_from_screen(screen);
94642542f5fSchristos	sna_video_close(sna);
94703b705cfSriastradh	return TRUE;
94803b705cfSriastradh}
94942542f5fSchristos#endif
95003b705cfSriastradh
95103b705cfSriastradhvoid sna_video_init(struct sna *sna, ScreenPtr screen)
95203b705cfSriastradh{
95303b705cfSriastradh	XvScreenPtr xv;
95403b705cfSriastradh
95503b705cfSriastradh	if (noXvExtension)
95603b705cfSriastradh		return;
95703b705cfSriastradh
95803b705cfSriastradh	if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) {
95903b705cfSriastradh		XF86VideoAdaptorPtr *adaptors = NULL;
96003b705cfSriastradh		int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
96103b705cfSriastradh		if (num_adaptors)
96203b705cfSriastradh			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
96303b705cfSriastradh				   "Ignoring generic xf86XV adaptors");
96403b705cfSriastradh		free(adaptors);
96503b705cfSriastradh	}
96603b705cfSriastradh
96703b705cfSriastradh	if (XvScreenInit(screen) != Success)
96803b705cfSriastradh		return;
96903b705cfSriastradh
97003b705cfSriastradh	xv = to_xv(screen);
97142542f5fSchristos#if XORG_XV_VERSION < 2
97203b705cfSriastradh	xv->ddCloseScreen = sna_xv_close_screen;
97303b705cfSriastradh	xv->ddQueryAdaptors = sna_xv_query_adaptors;
97442542f5fSchristos#endif
97503b705cfSriastradh
97603b705cfSriastradh	sna_video_textured_setup(sna, screen);
97703b705cfSriastradh	sna_video_sprite_setup(sna, screen);
97803b705cfSriastradh	sna_video_overlay_setup(sna, screen);
97903b705cfSriastradh
98003b705cfSriastradh	if (sna->xv.num_adaptors >= 2 &&
98103b705cfSriastradh	    xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) {
98203b705cfSriastradh		XvAdaptorRec tmp;
98303b705cfSriastradh
98403b705cfSriastradh		tmp = sna->xv.adaptors[0];
98503b705cfSriastradh		sna->xv.adaptors[0] = sna->xv.adaptors[1];
98603b705cfSriastradh		sna->xv.adaptors[1] = tmp;
98703b705cfSriastradh	}
98803b705cfSriastradh
98903b705cfSriastradh	xv->nAdaptors = sna->xv.num_adaptors;
99003b705cfSriastradh	xv->pAdaptors = sna->xv.adaptors;
99103b705cfSriastradh
99203b705cfSriastradh	sna_video_xvmc_setup(sna, screen);
99303b705cfSriastradh}
99403b705cfSriastradh
99503b705cfSriastradhvoid sna_video_destroy_window(WindowPtr win)
99603b705cfSriastradh{
99703b705cfSriastradh	XvPortPtr port;
99803b705cfSriastradh
99903b705cfSriastradh	port = sna_window_get_port(win);
100042542f5fSchristos	if (port) {
100142542f5fSchristos#if XORG_XV_VERSION < 2
100203b705cfSriastradh		port->pAdaptor->ddStopVideo(NULL, port, &win->drawable);
100342542f5fSchristos#else
100442542f5fSchristos		port->pAdaptor->ddStopVideo(port, &win->drawable);
100542542f5fSchristos#endif
100642542f5fSchristos	}
100703b705cfSriastradh	assert(sna_window_get_port(win) == NULL);
100803b705cfSriastradh}
100942542f5fSchristos
101042542f5fSchristosvoid sna_video_close(struct sna *sna)
101142542f5fSchristos{
101242542f5fSchristos	int i;
101342542f5fSchristos
101442542f5fSchristos	for (i = 0; i < sna->xv.num_adaptors; i++) {
101542542f5fSchristos		free(sna->xv.adaptors[i].pPorts->devPriv.ptr);
101642542f5fSchristos		free(sna->xv.adaptors[i].pPorts);
101742542f5fSchristos		free(sna->xv.adaptors[i].pEncodings);
101842542f5fSchristos	}
101942542f5fSchristos	free(sna->xv.adaptors);
102042542f5fSchristos
102142542f5fSchristos	sna->xv.adaptors = NULL;
102242542f5fSchristos	sna->xv.num_adaptors = 0;
102342542f5fSchristos}
1024