1428d7b3dSmrg/***************************************************************************
2428d7b3dSmrg
3428d7b3dSmrg Copyright 2000 Intel Corporation.  All Rights Reserved.
4428d7b3dSmrg
5428d7b3dSmrg Permission is hereby granted, free of charge, to any person obtaining a
6428d7b3dSmrg copy of this software and associated documentation files (the
7428d7b3dSmrg "Software"), to deal in the Software without restriction, including
8428d7b3dSmrg without limitation the rights to use, copy, modify, merge, publish,
9428d7b3dSmrg distribute, sub license, and/or sell copies of the Software, and to
10428d7b3dSmrg permit persons to whom the Software is furnished to do so, subject to
11428d7b3dSmrg the following conditions:
12428d7b3dSmrg
13428d7b3dSmrg The above copyright notice and this permission notice (including the
14428d7b3dSmrg next paragraph) shall be included in all copies or substantial portions
15428d7b3dSmrg of the Software.
16428d7b3dSmrg
17428d7b3dSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18428d7b3dSmrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19428d7b3dSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20428d7b3dSmrg IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21428d7b3dSmrg DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22428d7b3dSmrg OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23428d7b3dSmrg THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24428d7b3dSmrg
25428d7b3dSmrg **************************************************************************/
26428d7b3dSmrg
27428d7b3dSmrg/*
28428d7b3dSmrg * i830_video.c: i830/i845 Xv driver.
29428d7b3dSmrg *
30428d7b3dSmrg * Copyright © 2002 by Alan Hourihane and David Dawes
31428d7b3dSmrg *
32428d7b3dSmrg * Authors:
33428d7b3dSmrg *	Alan Hourihane <alanh@tungstengraphics.com>
34428d7b3dSmrg *	David Dawes <dawes@xfree86.org>
35428d7b3dSmrg *
36428d7b3dSmrg * Derived from i810 Xv driver:
37428d7b3dSmrg *
38428d7b3dSmrg * Authors of i810 code:
39428d7b3dSmrg *	Jonathan Bian <jonathan.bian@intel.com>
40428d7b3dSmrg *      Offscreen Images:
41428d7b3dSmrg *        Matt Sottek <matthew.j.sottek@intel.com>
42428d7b3dSmrg */
43428d7b3dSmrg
44428d7b3dSmrg#ifdef HAVE_CONFIG_H
45428d7b3dSmrg#include "config.h"
46428d7b3dSmrg#endif
47428d7b3dSmrg
48428d7b3dSmrg#include <inttypes.h>
49428d7b3dSmrg#include <math.h>
50428d7b3dSmrg#include <string.h>
51428d7b3dSmrg#include <errno.h>
52428d7b3dSmrg
53428d7b3dSmrg#include <sys/mman.h>
54428d7b3dSmrg
55428d7b3dSmrg#include "sna.h"
56428d7b3dSmrg#include "sna_reg.h"
57428d7b3dSmrg#include "sna_video.h"
58428d7b3dSmrg
59428d7b3dSmrg#include "intel_options.h"
60428d7b3dSmrg
61428d7b3dSmrg#include <xf86xv.h>
62428d7b3dSmrg
63428d7b3dSmrg#ifdef SNA_XVMC
64428d7b3dSmrg#define _SNA_XVMC_SERVER_
65428d7b3dSmrg#include "sna_video_hwmc.h"
66428d7b3dSmrg#else
67428d7b3dSmrgstatic inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr)
68428d7b3dSmrg{
69428d7b3dSmrg	DBG(("%s: XvMC not compiled in\n", __FUNCTION__));
70428d7b3dSmrg}
71428d7b3dSmrg#endif
72428d7b3dSmrg
73428d7b3dSmrgvoid sna_video_free_buffers(struct sna_video *video)
74428d7b3dSmrg{
75428d7b3dSmrg	unsigned int i;
76428d7b3dSmrg
77428d7b3dSmrg	for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
78428d7b3dSmrg		if (video->old_buf[i]) {
79428d7b3dSmrg			kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]);
80428d7b3dSmrg			video->old_buf[i] = NULL;
81428d7b3dSmrg		}
82428d7b3dSmrg	}
83428d7b3dSmrg
84428d7b3dSmrg	if (video->buf) {
85428d7b3dSmrg		kgem_bo_destroy(&video->sna->kgem, video->buf);
86428d7b3dSmrg		video->buf = NULL;
87428d7b3dSmrg	}
88428d7b3dSmrg}
89428d7b3dSmrg
90428d7b3dSmrgstruct kgem_bo *
91428d7b3dSmrgsna_video_buffer(struct sna_video *video,
92428d7b3dSmrg		 struct sna_video_frame *frame)
93428d7b3dSmrg{
94428d7b3dSmrg	/* Free the current buffer if we're going to have to reallocate */
95428d7b3dSmrg	if (video->buf && __kgem_bo_size(video->buf) < frame->size)
96428d7b3dSmrg		sna_video_free_buffers(video);
97428d7b3dSmrg
98428d7b3dSmrg	if (video->buf && video->buf->scanout) {
99428d7b3dSmrg		if (frame->width != video->width ||
100428d7b3dSmrg		    frame->height != video->height ||
101428d7b3dSmrg		    frame->id != video->format)
102428d7b3dSmrg			sna_video_free_buffers(video);
103428d7b3dSmrg	}
104428d7b3dSmrg
105428d7b3dSmrg	if (video->buf == NULL) {
106428d7b3dSmrg		if (video->tiled) {
107428d7b3dSmrg			video->buf = kgem_create_2d(&video->sna->kgem,
108428d7b3dSmrg						    frame->width, frame->height, 32,
109428d7b3dSmrg						    I915_TILING_X, CREATE_EXACT);
110428d7b3dSmrg		} else {
111428d7b3dSmrg			video->buf = kgem_create_linear(&video->sna->kgem, frame->size,
112428d7b3dSmrg							CREATE_GTT_MAP);
113428d7b3dSmrg		}
114428d7b3dSmrg	}
115428d7b3dSmrg
116428d7b3dSmrg	video->width  = frame->width;
117428d7b3dSmrg	video->height = frame->height;
118428d7b3dSmrg	video->format = frame->id;
119428d7b3dSmrg
120428d7b3dSmrg	return video->buf;
121428d7b3dSmrg}
122428d7b3dSmrg
123428d7b3dSmrgvoid sna_video_buffer_fini(struct sna_video *video)
124428d7b3dSmrg{
125428d7b3dSmrg	struct kgem_bo *bo;
126428d7b3dSmrg
127428d7b3dSmrg	bo = video->old_buf[1];
128428d7b3dSmrg	video->old_buf[1] = video->old_buf[0];
129428d7b3dSmrg	video->old_buf[0] = video->buf;
130428d7b3dSmrg	video->buf = bo;
131428d7b3dSmrg}
132428d7b3dSmrg
133428d7b3dSmrgbool
134428d7b3dSmrgsna_video_clip_helper(struct sna_video *video,
135428d7b3dSmrg		      struct sna_video_frame *frame,
136428d7b3dSmrg		      xf86CrtcPtr *crtc_ret,
137428d7b3dSmrg		      BoxPtr dst,
138428d7b3dSmrg		      short src_x, short src_y,
139428d7b3dSmrg		      short drw_x, short drw_y,
140428d7b3dSmrg		      short src_w, short src_h,
141428d7b3dSmrg		      short drw_w, short drw_h,
142428d7b3dSmrg		      RegionPtr reg)
143428d7b3dSmrg{
144428d7b3dSmrg	bool ret;
145428d7b3dSmrg	RegionRec crtc_region_local;
146428d7b3dSmrg	RegionPtr crtc_region = reg;
147428d7b3dSmrg	INT32 x1, x2, y1, y2;
148428d7b3dSmrg	xf86CrtcPtr crtc;
149428d7b3dSmrg
150428d7b3dSmrg	x1 = src_x;
151428d7b3dSmrg	x2 = src_x + src_w;
152428d7b3dSmrg	y1 = src_y;
153428d7b3dSmrg	y2 = src_y + src_h;
154428d7b3dSmrg
155428d7b3dSmrg	dst->x1 = drw_x;
156428d7b3dSmrg	dst->x2 = drw_x + drw_w;
157428d7b3dSmrg	dst->y1 = drw_y;
158428d7b3dSmrg	dst->y2 = drw_y + drw_h;
159428d7b3dSmrg
160428d7b3dSmrg	/*
161428d7b3dSmrg	 * For overlay video, compute the relevant CRTC and
162428d7b3dSmrg	 * clip video to that
163428d7b3dSmrg	 */
164428d7b3dSmrg	crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc);
165428d7b3dSmrg
166428d7b3dSmrg	/* For textured video, we don't actually want to clip at all. */
167428d7b3dSmrg	if (crtc && !video->textured) {
168428d7b3dSmrg		crtc_region_local.extents = crtc->bounds;
169428d7b3dSmrg		crtc_region_local.data = NULL;
170428d7b3dSmrg		crtc_region = &crtc_region_local;
171428d7b3dSmrg		RegionIntersect(crtc_region, crtc_region, reg);
172428d7b3dSmrg	}
173428d7b3dSmrg	*crtc_ret = crtc;
174428d7b3dSmrg
175428d7b3dSmrg	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
176428d7b3dSmrg				    crtc_region, frame->width, frame->height);
177428d7b3dSmrg	if (crtc_region != reg)
178428d7b3dSmrg		RegionUninit(crtc_region);
179428d7b3dSmrg
180428d7b3dSmrg	frame->src.x1 = x1 >> 16;
181428d7b3dSmrg	frame->src.y1 = y1 >> 16;
182428d7b3dSmrg	frame->src.x2 = (x2 + 0xffff) >> 16;
183428d7b3dSmrg	frame->src.y2 = (y2 + 0xffff) >> 16;
184428d7b3dSmrg
185428d7b3dSmrg	frame->image.x1 = frame->src.x1 & ~1;
186428d7b3dSmrg	frame->image.x2 = ALIGN(frame->src.x2, 2);
187428d7b3dSmrg	if (is_planar_fourcc(frame->id)) {
188428d7b3dSmrg		frame->image.y1 = frame->src.y1 & ~1;
189428d7b3dSmrg		frame->image.y2 = ALIGN(frame->src.y2, 2);
190428d7b3dSmrg	} else {
191428d7b3dSmrg		frame->image.y1 = frame->src.y1;
192428d7b3dSmrg		frame->image.y2 = frame->src.y2;
193428d7b3dSmrg	}
194428d7b3dSmrg
195428d7b3dSmrg	return ret;
196428d7b3dSmrg}
197428d7b3dSmrg
198428d7b3dSmrgvoid
199428d7b3dSmrgsna_video_frame_init(struct sna_video *video,
200428d7b3dSmrg		     int id, short width, short height,
201428d7b3dSmrg		     struct sna_video_frame *frame)
202428d7b3dSmrg{
203428d7b3dSmrg	DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n",
204428d7b3dSmrg	     __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment));
205428d7b3dSmrg	assert(width && height);
206428d7b3dSmrg
207428d7b3dSmrg	frame->bo = NULL;
208428d7b3dSmrg	frame->id = id;
209428d7b3dSmrg	frame->width = width;
210428d7b3dSmrg	frame->height = height;
211428d7b3dSmrg	frame->rotation = 0;
212428d7b3dSmrg}
213428d7b3dSmrg
214428d7b3dSmrgvoid
215428d7b3dSmrgsna_video_frame_set_rotation(struct sna_video *video,
216428d7b3dSmrg			     struct sna_video_frame *frame,
217428d7b3dSmrg			     Rotation rotation)
218428d7b3dSmrg{
219428d7b3dSmrg	unsigned width = frame->width;
220428d7b3dSmrg	unsigned height = frame->height;
221428d7b3dSmrg	unsigned align;
222428d7b3dSmrg
223428d7b3dSmrg	DBG(("%s: rotation=%d\n", __FUNCTION__, rotation));
224428d7b3dSmrg	frame->rotation = rotation;
225428d7b3dSmrg
226428d7b3dSmrg	align = video->alignment;
227428d7b3dSmrg#if SNA_XVMC
228428d7b3dSmrg	/* for i915 xvmc, hw requires 1kb aligned surfaces */
229428d7b3dSmrg	if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024)
230428d7b3dSmrg		align = 1024;
231428d7b3dSmrg#endif
232428d7b3dSmrg
233428d7b3dSmrg	/* Determine the desired destination pitch (representing the
234428d7b3dSmrg	 * chroma's pitch in the planar case).
235428d7b3dSmrg	 */
236428d7b3dSmrg	if (is_planar_fourcc(frame->id)) {
237428d7b3dSmrg		assert((width & 1) == 0);
238428d7b3dSmrg		assert((height & 1) == 0);
239428d7b3dSmrg		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
240428d7b3dSmrg			frame->pitch[0] = ALIGN((height / 2), align);
241428d7b3dSmrg			frame->pitch[1] = ALIGN(height, align);
242428d7b3dSmrg			frame->size = width;
243428d7b3dSmrg		} else {
244428d7b3dSmrg			frame->pitch[0] = ALIGN((width / 2), align);
245428d7b3dSmrg			frame->pitch[1] = ALIGN(width, align);
246428d7b3dSmrg			frame->size = height;
247428d7b3dSmrg		}
248428d7b3dSmrg		frame->size *= frame->pitch[0] + frame->pitch[1];
249428d7b3dSmrg
250428d7b3dSmrg		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
251428d7b3dSmrg			frame->UBufOffset = (int)frame->pitch[1] * width;
252428d7b3dSmrg			frame->VBufOffset =
253428d7b3dSmrg				frame->UBufOffset + (int)frame->pitch[0] * width / 2;
254428d7b3dSmrg		} else {
255428d7b3dSmrg			frame->UBufOffset = (int)frame->pitch[1] * height;
256428d7b3dSmrg			frame->VBufOffset =
257428d7b3dSmrg				frame->UBufOffset + (int)frame->pitch[0] * height / 2;
258428d7b3dSmrg		}
259428d7b3dSmrg	} else {
260428d7b3dSmrg		switch (frame->id) {
261428d7b3dSmrg		case FOURCC_RGB888:
262428d7b3dSmrg			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
263428d7b3dSmrg				frame->pitch[0] = ALIGN((height << 2), align);
264428d7b3dSmrg				frame->size = (int)frame->pitch[0] * width;
265428d7b3dSmrg			} else {
266428d7b3dSmrg				frame->pitch[0] = ALIGN((width << 2), align);
267428d7b3dSmrg				frame->size = (int)frame->pitch[0] * height;
268428d7b3dSmrg			}
269428d7b3dSmrg			frame->UBufOffset = frame->VBufOffset = 0;
270428d7b3dSmrg			break;
271428d7b3dSmrg		case FOURCC_RGB565:
272428d7b3dSmrg			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
273428d7b3dSmrg				frame->pitch[0] = ALIGN((height << 1), align);
274428d7b3dSmrg				frame->size = (int)frame->pitch[0] * width;
275428d7b3dSmrg			} else {
276428d7b3dSmrg				frame->pitch[0] = ALIGN((width << 1), align);
277428d7b3dSmrg				frame->size = (int)frame->pitch[0] * height;
278428d7b3dSmrg			}
279428d7b3dSmrg			frame->UBufOffset = frame->VBufOffset = 0;
280428d7b3dSmrg			break;
281428d7b3dSmrg
282428d7b3dSmrg		default:
283428d7b3dSmrg			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
284428d7b3dSmrg				frame->pitch[0] = ALIGN((height << 1), align);
285428d7b3dSmrg				frame->size = (int)frame->pitch[0] * width;
286428d7b3dSmrg			} else {
287428d7b3dSmrg				frame->pitch[0] = ALIGN((width << 1), align);
288428d7b3dSmrg				frame->size = (int)frame->pitch[0] * height;
289428d7b3dSmrg			}
290428d7b3dSmrg			break;
291428d7b3dSmrg		}
292428d7b3dSmrg		frame->pitch[1] = 0;
293428d7b3dSmrg		frame->UBufOffset = 0;
294428d7b3dSmrg		frame->VBufOffset = 0;
295428d7b3dSmrg	}
296428d7b3dSmrg
297428d7b3dSmrg	assert(frame->size);
298428d7b3dSmrg}
299428d7b3dSmrg
300428d7b3dSmrgstatic void sna_memcpy_plane(struct sna_video *video,
301428d7b3dSmrg			     uint8_t *dst, const uint8_t *src,
302428d7b3dSmrg			     const struct sna_video_frame *frame, int sub)
303428d7b3dSmrg{
304428d7b3dSmrg	int dstPitch = frame->pitch[!sub], srcPitch;
305428d7b3dSmrg	const uint8_t *s;
306428d7b3dSmrg	int i, j = 0;
307428d7b3dSmrg	int x, y, w, h;
308428d7b3dSmrg
309428d7b3dSmrg	x = frame->image.x1;
310428d7b3dSmrg	y = frame->image.y1;
311428d7b3dSmrg	w = frame->image.x2 - frame->image.x1;
312428d7b3dSmrg	h = frame->image.y2 - frame->image.y1;
313428d7b3dSmrg	if (sub) {
314428d7b3dSmrg		x >>= 1; w >>= 1;
315428d7b3dSmrg		y >>= 1; h >>= 1;
316428d7b3dSmrg		srcPitch = ALIGN((frame->width >> 1), 4);
317428d7b3dSmrg	} else
318428d7b3dSmrg		srcPitch = ALIGN(frame->width, 4);
319428d7b3dSmrg
320428d7b3dSmrg	src += y * srcPitch + x;
321428d7b3dSmrg	if (!video->textured)
322428d7b3dSmrg		x = y = 0;
323428d7b3dSmrg
324428d7b3dSmrg	switch (frame->rotation) {
325428d7b3dSmrg	case RR_Rotate_0:
326428d7b3dSmrg		dst += y * dstPitch + x;
327428d7b3dSmrg		if (srcPitch == dstPitch && srcPitch == w)
328428d7b3dSmrg			memcpy(dst, src, srcPitch * h);
329428d7b3dSmrg		else while (h--) {
330428d7b3dSmrg			memcpy(dst, src, w);
331428d7b3dSmrg			src += srcPitch;
332428d7b3dSmrg			dst += dstPitch;
333428d7b3dSmrg		}
334428d7b3dSmrg		break;
335428d7b3dSmrg	case RR_Rotate_90:
336428d7b3dSmrg		for (i = 0; i < h; i++) {
337428d7b3dSmrg			s = src;
338428d7b3dSmrg			for (j = 0; j < w; j++)
339428d7b3dSmrg				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
340428d7b3dSmrg			src += srcPitch;
341428d7b3dSmrg		}
342428d7b3dSmrg		break;
343428d7b3dSmrg	case RR_Rotate_180:
344428d7b3dSmrg		for (i = 0; i < h; i++) {
345428d7b3dSmrg			s = src;
346428d7b3dSmrg			for (j = 0; j < w; j++) {
347428d7b3dSmrg				dst[(x + w - j - 1) +
348428d7b3dSmrg				    ((h - i - 1) * dstPitch)] = *s++;
349428d7b3dSmrg			}
350428d7b3dSmrg			src += srcPitch;
351428d7b3dSmrg		}
352428d7b3dSmrg		break;
353428d7b3dSmrg	case RR_Rotate_270:
354428d7b3dSmrg		for (i = 0; i < h; i++) {
355428d7b3dSmrg			s = src;
356428d7b3dSmrg			for (j = 0; j < w; j++) {
357428d7b3dSmrg				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
358428d7b3dSmrg			}
359428d7b3dSmrg			src += srcPitch;
360428d7b3dSmrg		}
361428d7b3dSmrg		break;
362428d7b3dSmrg	}
363428d7b3dSmrg}
364428d7b3dSmrg
365428d7b3dSmrgstatic void
366428d7b3dSmrgsna_copy_planar_data(struct sna_video *video,
367428d7b3dSmrg		     const struct sna_video_frame *frame,
368428d7b3dSmrg		     const uint8_t *src, uint8_t *dst)
369428d7b3dSmrg{
370428d7b3dSmrg	uint8_t *d;
371428d7b3dSmrg
372428d7b3dSmrg	sna_memcpy_plane(video, dst, src, frame, 0);
373428d7b3dSmrg	src += frame->height * ALIGN(frame->width, 4);
374428d7b3dSmrg
375428d7b3dSmrg	if (frame->id == FOURCC_I420)
376428d7b3dSmrg		d = dst + frame->UBufOffset;
377428d7b3dSmrg	else
378428d7b3dSmrg		d = dst + frame->VBufOffset;
379428d7b3dSmrg	sna_memcpy_plane(video, d, src, frame, 1);
380428d7b3dSmrg	src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4);
381428d7b3dSmrg
382428d7b3dSmrg	if (frame->id == FOURCC_I420)
383428d7b3dSmrg		d = dst + frame->VBufOffset;
384428d7b3dSmrg	else
385428d7b3dSmrg		d = dst + frame->UBufOffset;
386428d7b3dSmrg	sna_memcpy_plane(video, d, src, frame, 1);
387428d7b3dSmrg}
388428d7b3dSmrg
389428d7b3dSmrgstatic void
390428d7b3dSmrgsna_copy_packed_data(struct sna_video *video,
391428d7b3dSmrg		     const struct sna_video_frame *frame,
392428d7b3dSmrg		     const uint8_t *buf,
393428d7b3dSmrg		     uint8_t *dst)
394428d7b3dSmrg{
395428d7b3dSmrg	int pitch = frame->width << 1;
396428d7b3dSmrg	const uint8_t *src, *s;
397428d7b3dSmrg	int x, y, w, h;
398428d7b3dSmrg	int i, j;
399428d7b3dSmrg
400428d7b3dSmrg	if (video->textured) {
401428d7b3dSmrg		/* XXX support copying cropped extents */
402428d7b3dSmrg		x = y = 0;
403428d7b3dSmrg		w = frame->width;
404428d7b3dSmrg		h = frame->height;
405428d7b3dSmrg	} else {
406428d7b3dSmrg		x = frame->image.x1;
407428d7b3dSmrg		y = frame->image.y1;
408428d7b3dSmrg		w = frame->image.x2 - frame->image.x1;
409428d7b3dSmrg		h = frame->image.y2 - frame->image.y1;
410428d7b3dSmrg	}
411428d7b3dSmrg
412428d7b3dSmrg	src = buf + (y * pitch) + (x << 1);
413428d7b3dSmrg
414428d7b3dSmrg	switch (frame->rotation) {
415428d7b3dSmrg	case RR_Rotate_0:
416428d7b3dSmrg		w <<= 1;
417428d7b3dSmrg		for (i = 0; i < h; i++) {
418428d7b3dSmrg			memcpy(dst, src, w);
419428d7b3dSmrg			src += pitch;
420428d7b3dSmrg			dst += frame->pitch[0];
421428d7b3dSmrg		}
422428d7b3dSmrg		break;
423428d7b3dSmrg	case RR_Rotate_90:
424428d7b3dSmrg		h <<= 1;
425428d7b3dSmrg		for (i = 0; i < h; i += 2) {
426428d7b3dSmrg			s = src;
427428d7b3dSmrg			for (j = 0; j < w; j++) {
428428d7b3dSmrg				/* Copy Y */
429428d7b3dSmrg				dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s;
430428d7b3dSmrg				s += 2;
431428d7b3dSmrg			}
432428d7b3dSmrg			src += pitch;
433428d7b3dSmrg		}
434428d7b3dSmrg		h >>= 1;
435428d7b3dSmrg		src = buf + (y * pitch) + (x << 1);
436428d7b3dSmrg		for (i = 0; i < h; i += 2) {
437428d7b3dSmrg			for (j = 0; j < w; j += 2) {
438428d7b3dSmrg				/* Copy U */
439428d7b3dSmrg				dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
440428d7b3dSmrg				dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
441428d7b3dSmrg				/* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
442428d7b3dSmrg				dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
443428d7b3dSmrg			}
444428d7b3dSmrg		}
445428d7b3dSmrg		break;
446428d7b3dSmrg	case RR_Rotate_180:
447428d7b3dSmrg		w <<= 1;
448428d7b3dSmrg		for (i = 0; i < h; i++) {
449428d7b3dSmrg			s = src;
450428d7b3dSmrg			for (j = 0; j < w; j += 4) {
451428d7b3dSmrg				dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++;
452428d7b3dSmrg				dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++;
453428d7b3dSmrg				dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++;
454428d7b3dSmrg				dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++;
455428d7b3dSmrg			}
456428d7b3dSmrg			src += pitch;
457428d7b3dSmrg		}
458428d7b3dSmrg		break;
459428d7b3dSmrg	case RR_Rotate_270:
460428d7b3dSmrg		h <<= 1;
461428d7b3dSmrg		for (i = 0; i < h; i += 2) {
462428d7b3dSmrg			s = src;
463428d7b3dSmrg			for (j = 0; j < w; j++) {
464428d7b3dSmrg				/* Copy Y */
465428d7b3dSmrg				dst[(h - i - 2) + (j * frame->pitch[0])] = *s;
466428d7b3dSmrg				s += 2;
467428d7b3dSmrg			}
468428d7b3dSmrg			src += pitch;
469428d7b3dSmrg		}
470428d7b3dSmrg		h >>= 1;
471428d7b3dSmrg		src = buf + (y * pitch) + (x << 1);
472428d7b3dSmrg		for (i = 0; i < h; i += 2) {
473428d7b3dSmrg			for (j = 0; j < w; j += 2) {
474428d7b3dSmrg				/* Copy U */
475428d7b3dSmrg				dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
476428d7b3dSmrg				dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
477428d7b3dSmrg				/* Copy V */
478428d7b3dSmrg				dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
479428d7b3dSmrg				dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
480428d7b3dSmrg			}
481428d7b3dSmrg		}
482428d7b3dSmrg		break;
483428d7b3dSmrg	}
484428d7b3dSmrg}
485428d7b3dSmrg
486428d7b3dSmrgbool
487428d7b3dSmrgsna_video_copy_data(struct sna_video *video,
488428d7b3dSmrg		    struct sna_video_frame *frame,
489428d7b3dSmrg		    const uint8_t *buf)
490428d7b3dSmrg{
491428d7b3dSmrg	uint8_t *dst;
492428d7b3dSmrg
493428d7b3dSmrg	DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n",
494428d7b3dSmrg	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
495428d7b3dSmrg	     frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1],
496428d7b3dSmrg	     frame->rotation, video->textured));
497428d7b3dSmrg	DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n",
498428d7b3dSmrg	     __FUNCTION__,
499428d7b3dSmrg	     frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2,
500428d7b3dSmrg	     frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2));
501428d7b3dSmrg	assert(frame->width && frame->height);
502428d7b3dSmrg	assert(frame->rotation);
503428d7b3dSmrg	assert(frame->size);
504428d7b3dSmrg
505428d7b3dSmrg	/* In the common case, we can simply the upload in a single pwrite */
506428d7b3dSmrg	if (frame->rotation == RR_Rotate_0 && !video->tiled) {
507428d7b3dSmrg		DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n",
508428d7b3dSmrg		     __FUNCTION__, is_planar_fourcc(frame->id)));
509428d7b3dSmrg		if (is_planar_fourcc(frame->id)) {
510428d7b3dSmrg			int w = frame->image.x2 - frame->image.x1;
511428d7b3dSmrg			int h = frame->image.y2 - frame->image.y1;
512428d7b3dSmrg			if (ALIGN(h, 2) == frame->height &&
513428d7b3dSmrg			    ALIGN(w >> 1, 4) == frame->pitch[0] &&
514428d7b3dSmrg			    ALIGN(w, 4) == frame->pitch[1]) {
515428d7b3dSmrg				if (frame->bo) {
516428d7b3dSmrg					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
517428d7b3dSmrg							   buf, frame->size))
518428d7b3dSmrg						goto use_gtt;
519428d7b3dSmrg				} else {
520428d7b3dSmrg					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
521428d7b3dSmrg								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
522428d7b3dSmrg								       (void **)&dst);
523428d7b3dSmrg					if (frame->bo == NULL)
524428d7b3dSmrg						return false;
525428d7b3dSmrg
526428d7b3dSmrg					memcpy(dst, buf, frame->size);
527428d7b3dSmrg				}
528428d7b3dSmrg				if (frame->id != FOURCC_I420) {
529428d7b3dSmrg					uint32_t tmp;
530428d7b3dSmrg					tmp = frame->VBufOffset;
531428d7b3dSmrg					frame->VBufOffset = frame->UBufOffset;
532428d7b3dSmrg					frame->UBufOffset = tmp;
533428d7b3dSmrg				}
534428d7b3dSmrg				return true;
535428d7b3dSmrg			}
536428d7b3dSmrg		} else {
537428d7b3dSmrg			int x, y, w, h;
538428d7b3dSmrg
539428d7b3dSmrg			if (video->textured) {
540428d7b3dSmrg				/* XXX support copying cropped extents */
541428d7b3dSmrg				x = y = 0;
542428d7b3dSmrg				w = frame->width;
543428d7b3dSmrg				h = frame->height;
544428d7b3dSmrg			} else {
545428d7b3dSmrg				x = frame->image.x1;
546428d7b3dSmrg				y = frame->image.y1;
547428d7b3dSmrg				w = frame->image.x2 - frame->image.x1;
548428d7b3dSmrg				h = frame->image.y2 - frame->image.y1;
549428d7b3dSmrg			}
550428d7b3dSmrg
551428d7b3dSmrg			if (w*2 == frame->pitch[0]) {
552428d7b3dSmrg				buf += (2U*y * frame->width) + (x << 1);
553428d7b3dSmrg				if (frame->bo) {
554428d7b3dSmrg					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
555428d7b3dSmrg							   buf, 2U*h*frame->width))
556428d7b3dSmrg						goto use_gtt;
557428d7b3dSmrg				} else {
558428d7b3dSmrg					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
559428d7b3dSmrg								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
560428d7b3dSmrg								       (void **)&dst);
561428d7b3dSmrg					if (frame->bo == NULL)
562428d7b3dSmrg						return false;
563428d7b3dSmrg
564428d7b3dSmrg					memcpy(dst, buf, 2U*h*frame->width);
565428d7b3dSmrg				}
566428d7b3dSmrg				return true;
567428d7b3dSmrg			}
568428d7b3dSmrg		}
569428d7b3dSmrg
570428d7b3dSmrg		DBG(("%s: source cropped, fallback\n", __FUNCTION__));
571428d7b3dSmrg	}
572428d7b3dSmrg
573428d7b3dSmrguse_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
574428d7b3dSmrg	if (frame->bo) {
575428d7b3dSmrg		dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo);
576428d7b3dSmrg		if (dst == NULL)
577428d7b3dSmrg			return false;
578428d7b3dSmrg	} else {
579428d7b3dSmrg		frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
580428d7b3dSmrg					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
581428d7b3dSmrg					       (void **)&dst);
582428d7b3dSmrg		if (frame->bo == NULL)
583428d7b3dSmrg			return false;
584428d7b3dSmrg	}
585428d7b3dSmrg
586428d7b3dSmrg	if (is_planar_fourcc(frame->id))
587428d7b3dSmrg		sna_copy_planar_data(video, frame, buf, dst);
588428d7b3dSmrg	else
589428d7b3dSmrg		sna_copy_packed_data(video, frame, buf, dst);
590428d7b3dSmrg
591428d7b3dSmrg	return true;
592428d7b3dSmrg}
593428d7b3dSmrg
594428d7b3dSmrgXvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
595428d7b3dSmrg{
596428d7b3dSmrg	XvAdaptorPtr new_adaptors;
597428d7b3dSmrg
598428d7b3dSmrg	new_adaptors = realloc(sna->xv.adaptors,
599428d7b3dSmrg			       (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec));
600428d7b3dSmrg	if (new_adaptors == NULL)
601428d7b3dSmrg		return NULL;
602428d7b3dSmrg
603428d7b3dSmrg	if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) {
604428d7b3dSmrg		XvAdaptorPtr adaptor = new_adaptors;
605428d7b3dSmrg		int i = sna->xv.num_adaptors, j;
606428d7b3dSmrg		while (i--) {
607428d7b3dSmrg			for (j = 0; j < adaptor->nPorts; j++)
608428d7b3dSmrg				adaptor->pPorts[j].pAdaptor = adaptor;
609428d7b3dSmrg			adaptor++;
610428d7b3dSmrg		}
611428d7b3dSmrg	}
612428d7b3dSmrg
613428d7b3dSmrg	sna->xv.adaptors = new_adaptors;
614428d7b3dSmrg	return &sna->xv.adaptors[sna->xv.num_adaptors++];
615428d7b3dSmrg}
616428d7b3dSmrg
617428d7b3dSmrgint
618428d7b3dSmrgsna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out)
619428d7b3dSmrg{
620428d7b3dSmrg	*out = in;
621428d7b3dSmrg	return Success;
622428d7b3dSmrg}
623428d7b3dSmrg
624428d7b3dSmrgint
625428d7b3dSmrgsna_xv_free_port(XvPortPtr port)
626428d7b3dSmrg{
627428d7b3dSmrg	return Success;
628428d7b3dSmrg}
629428d7b3dSmrg
630428d7b3dSmrgint
631428d7b3dSmrgsna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats)
632428d7b3dSmrg{
633428d7b3dSmrg	XvFormatPtr out = formats;
634428d7b3dSmrg	int count = 0;
635428d7b3dSmrg
636428d7b3dSmrg	while (num_formats--) {
637428d7b3dSmrg		int num_visuals = screen->numVisuals;
638428d7b3dSmrg		VisualPtr v = screen->visuals;
639428d7b3dSmrg
640428d7b3dSmrg		while (num_visuals--) {
641428d7b3dSmrg			if (v->class == TrueColor &&
642428d7b3dSmrg			    v->nplanes == formats->depth) {
643428d7b3dSmrg				int tmp = out[count].depth;
644428d7b3dSmrg				out[count].depth = formats->depth;
645428d7b3dSmrg				out[count].visual = v->vid;
646428d7b3dSmrg				formats->depth = tmp;
647428d7b3dSmrg				count++;
648428d7b3dSmrg				break;
649428d7b3dSmrg			}
650428d7b3dSmrg			v++;
651428d7b3dSmrg		}
652428d7b3dSmrg
653428d7b3dSmrg		formats++;
654428d7b3dSmrg	}
655428d7b3dSmrg
656428d7b3dSmrg	return count;
657428d7b3dSmrg}
658428d7b3dSmrg
659428d7b3dSmrg#if XORG_XV_VERSION < 2
660428d7b3dSmrgstatic int
661428d7b3dSmrgsna_xv_query_adaptors(ScreenPtr screen,
662428d7b3dSmrg		      XvAdaptorPtr *adaptors,
663428d7b3dSmrg		      int *num_adaptors)
664428d7b3dSmrg{
665428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
666428d7b3dSmrg
667428d7b3dSmrg	*num_adaptors = sna->xv.num_adaptors;
668428d7b3dSmrg	*adaptors = sna->xv.adaptors;
669428d7b3dSmrg	return Success;
670428d7b3dSmrg}
671428d7b3dSmrg
672428d7b3dSmrgstatic Bool
673428d7b3dSmrgsna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL)
674428d7b3dSmrg{
675428d7b3dSmrg	struct sna *sna = to_sna_from_screen(screen);
676428d7b3dSmrg	sna_video_close(sna);
677428d7b3dSmrg	return TRUE;
678428d7b3dSmrg}
679428d7b3dSmrg#endif
680428d7b3dSmrg
681428d7b3dSmrgvoid sna_video_init(struct sna *sna, ScreenPtr screen)
682428d7b3dSmrg{
683428d7b3dSmrg	XvScreenPtr xv;
684428d7b3dSmrg
685428d7b3dSmrg	if (noXvExtension)
686428d7b3dSmrg		return;
687428d7b3dSmrg
688428d7b3dSmrg	if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) {
689428d7b3dSmrg		XF86VideoAdaptorPtr *adaptors = NULL;
690428d7b3dSmrg		int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
691428d7b3dSmrg		if (num_adaptors)
692428d7b3dSmrg			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
693428d7b3dSmrg				   "Ignoring generic xf86XV adaptors");
694428d7b3dSmrg		free(adaptors);
695428d7b3dSmrg	}
696428d7b3dSmrg
697428d7b3dSmrg	if (XvScreenInit(screen) != Success)
698428d7b3dSmrg		return;
699428d7b3dSmrg
700428d7b3dSmrg	xv = to_xv(screen);
701428d7b3dSmrg#if XORG_XV_VERSION < 2
702428d7b3dSmrg	xv->ddCloseScreen = sna_xv_close_screen;
703428d7b3dSmrg	xv->ddQueryAdaptors = sna_xv_query_adaptors;
704428d7b3dSmrg#endif
705428d7b3dSmrg
706428d7b3dSmrg	sna_video_textured_setup(sna, screen);
707428d7b3dSmrg	sna_video_sprite_setup(sna, screen);
708428d7b3dSmrg	sna_video_overlay_setup(sna, screen);
709428d7b3dSmrg
710428d7b3dSmrg	if (sna->xv.num_adaptors >= 2 &&
711428d7b3dSmrg	    xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) {
712428d7b3dSmrg		XvAdaptorRec tmp;
713428d7b3dSmrg
714428d7b3dSmrg		tmp = sna->xv.adaptors[0];
715428d7b3dSmrg		sna->xv.adaptors[0] = sna->xv.adaptors[1];
716428d7b3dSmrg		sna->xv.adaptors[1] = tmp;
717428d7b3dSmrg	}
718428d7b3dSmrg
719428d7b3dSmrg	xv->nAdaptors = sna->xv.num_adaptors;
720428d7b3dSmrg	xv->pAdaptors = sna->xv.adaptors;
721428d7b3dSmrg
722428d7b3dSmrg	sna_video_xvmc_setup(sna, screen);
723428d7b3dSmrg}
724428d7b3dSmrg
725428d7b3dSmrgvoid sna_video_destroy_window(WindowPtr win)
726428d7b3dSmrg{
727428d7b3dSmrg	XvPortPtr port;
728428d7b3dSmrg
729428d7b3dSmrg	port = sna_window_get_port(win);
730428d7b3dSmrg	if (port) {
731428d7b3dSmrg#if XORG_XV_VERSION < 2
732428d7b3dSmrg		port->pAdaptor->ddStopVideo(NULL, port, &win->drawable);
733428d7b3dSmrg#else
734428d7b3dSmrg		port->pAdaptor->ddStopVideo(port, &win->drawable);
735428d7b3dSmrg#endif
736428d7b3dSmrg	}
737428d7b3dSmrg	assert(sna_window_get_port(win) == NULL);
738428d7b3dSmrg}
739428d7b3dSmrg
740428d7b3dSmrgvoid sna_video_close(struct sna *sna)
741428d7b3dSmrg{
742428d7b3dSmrg	int i;
743428d7b3dSmrg
744428d7b3dSmrg	for (i = 0; i < sna->xv.num_adaptors; i++) {
745428d7b3dSmrg		free(sna->xv.adaptors[i].pPorts->devPriv.ptr);
746428d7b3dSmrg		free(sna->xv.adaptors[i].pPorts);
747428d7b3dSmrg		free(sna->xv.adaptors[i].pEncodings);
748428d7b3dSmrg	}
749428d7b3dSmrg	free(sna->xv.adaptors);
750428d7b3dSmrg
751428d7b3dSmrg	sna->xv.adaptors = NULL;
752428d7b3dSmrg	sna->xv.num_adaptors = 0;
753428d7b3dSmrg}
754