1/***************************************************************************
2
3 Copyright 2000 Intel Corporation.  All Rights Reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sub license, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice (including the
14 next paragraph) shall be included in all copies or substantial portions
15 of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23 THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27/*
28 * i830_video.c: i830/i845 Xv driver.
29 *
30 * Copyright © 2002 by Alan Hourihane and David Dawes
31 *
32 * Authors:
33 *	Alan Hourihane <alanh@tungstengraphics.com>
34 *	David Dawes <dawes@xfree86.org>
35 *
36 * Derived from i810 Xv driver:
37 *
38 * Authors of i810 code:
39 *	Jonathan Bian <jonathan.bian@intel.com>
40 *      Offscreen Images:
41 *        Matt Sottek <matthew.j.sottek@intel.com>
42 */
43
44#ifdef HAVE_CONFIG_H
45#include "config.h"
46#endif
47
48#include <inttypes.h>
49#include <math.h>
50#include <string.h>
51#include <errno.h>
52
53#include <sys/mman.h>
54
55#include "sna.h"
56#include "sna_reg.h"
57#include "sna_video.h"
58
59#include "intel_options.h"
60
61#include <xf86xv.h>
62#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
63#include <sys/types.h>
64#include <sys/endian.h>
65#ifdef __OpenBSD__
66#define bswap_32 swap32
67#else
68#define bswap_32 bswap32
69#endif
70#else
71#include <byteswap.h>
72#endif
73
74#ifdef SNA_XVMC
75#define _SNA_XVMC_SERVER_
76#include "sna_video_hwmc.h"
77#else
78static inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr)
79{
80	DBG(("%s: XvMC not compiled in\n", __FUNCTION__));
81}
82#endif
83
84void sna_video_free_buffers(struct sna_video *video)
85{
86	unsigned int i;
87
88	for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
89		if (video->old_buf[i]) {
90			kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]);
91			video->old_buf[i] = NULL;
92		}
93	}
94
95	if (video->buf) {
96		kgem_bo_destroy(&video->sna->kgem, video->buf);
97		video->buf = NULL;
98	}
99}
100
101struct kgem_bo *
102sna_video_buffer(struct sna_video *video,
103		 struct sna_video_frame *frame)
104{
105	/* Free the current buffer if we're going to have to reallocate */
106	if (video->buf && __kgem_bo_size(video->buf) < frame->size)
107		sna_video_free_buffers(video);
108
109	if (video->buf && video->buf->scanout) {
110		if (frame->width != video->width ||
111		    frame->height != video->height ||
112		    frame->id != video->format)
113			sna_video_free_buffers(video);
114	}
115
116	if (video->buf == NULL) {
117		if (video->tiled) {
118			video->buf = kgem_create_2d(&video->sna->kgem,
119						    frame->width, frame->height, 32,
120						    I915_TILING_X, CREATE_EXACT);
121		} else {
122			video->buf = kgem_create_linear(&video->sna->kgem, frame->size,
123							CREATE_GTT_MAP);
124		}
125	}
126
127	video->width  = frame->width;
128	video->height = frame->height;
129	video->format = frame->id;
130
131	return video->buf;
132}
133
134void sna_video_buffer_fini(struct sna_video *video)
135{
136	struct kgem_bo *bo;
137
138	bo = video->old_buf[1];
139	video->old_buf[1] = video->old_buf[0];
140	video->old_buf[0] = video->buf;
141	video->buf = bo;
142}
143
144bool
145sna_video_clip_helper(struct sna_video *video,
146		      struct sna_video_frame *frame,
147		      xf86CrtcPtr *crtc_ret,
148		      BoxPtr dst,
149		      short src_x, short src_y,
150		      short drw_x, short drw_y,
151		      short src_w, short src_h,
152		      short drw_w, short drw_h,
153		      RegionPtr reg)
154{
155	bool ret;
156	RegionRec crtc_region_local;
157	RegionPtr crtc_region = reg;
158	INT32 x1, x2, y1, y2;
159	xf86CrtcPtr crtc;
160
161	x1 = src_x;
162	x2 = src_x + src_w;
163	y1 = src_y;
164	y2 = src_y + src_h;
165
166	dst->x1 = drw_x;
167	dst->x2 = drw_x + drw_w;
168	dst->y1 = drw_y;
169	dst->y2 = drw_y + drw_h;
170
171	/*
172	 * For overlay video, compute the relevant CRTC and
173	 * clip video to that
174	 */
175	crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc);
176
177	/* For textured video, we don't actually want to clip at all. */
178	if (crtc && !video->textured) {
179		crtc_region_local.extents = crtc->bounds;
180		crtc_region_local.data = NULL;
181		crtc_region = &crtc_region_local;
182		RegionIntersect(crtc_region, crtc_region, reg);
183	}
184	*crtc_ret = crtc;
185
186	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
187				    crtc_region, frame->width, frame->height);
188	if (crtc_region != reg)
189		RegionUninit(crtc_region);
190
191	frame->src.x1 = x1 >> 16;
192	frame->src.y1 = y1 >> 16;
193	frame->src.x2 = (x2 + 0xffff) >> 16;
194	frame->src.y2 = (y2 + 0xffff) >> 16;
195
196	frame->image.x1 = frame->src.x1 & ~1;
197	frame->image.x2 = ALIGN(frame->src.x2, 2);
198	if (is_planar_fourcc(frame->id)) {
199		frame->image.y1 = frame->src.y1 & ~1;
200		frame->image.y2 = ALIGN(frame->src.y2, 2);
201	} else {
202		frame->image.y1 = frame->src.y1;
203		frame->image.y2 = frame->src.y2;
204	}
205
206	return ret;
207}
208
209void
210sna_video_frame_init(struct sna_video *video,
211		     int id, short width, short height,
212		     struct sna_video_frame *frame)
213{
214	DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n",
215	     __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment));
216	assert(width && height);
217
218	frame->bo = NULL;
219	frame->id = id;
220	frame->width = width;
221	frame->height = height;
222	frame->rotation = 0;
223}
224
225void
226sna_video_frame_set_rotation(struct sna_video *video,
227			     struct sna_video_frame *frame,
228			     Rotation rotation)
229{
230	unsigned width = frame->width;
231	unsigned height = frame->height;
232	unsigned align;
233
234	DBG(("%s: rotation=%d\n", __FUNCTION__, rotation));
235	frame->rotation = rotation;
236
237	align = video->alignment;
238#if SNA_XVMC
239	/* for i915 xvmc, hw requires 1kb aligned surfaces */
240	if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024)
241		align = 1024;
242#endif
243
244	/* Determine the desired destination pitch (representing the
245	 * chroma's pitch in the planar case).
246	 */
247	if (is_nv12_fourcc(frame->id)) {
248		assert((width & 1) == 0);
249		assert((height & 1) == 0);
250		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
251			frame->pitch[0] = ALIGN(height, align);
252			frame->pitch[1] = ALIGN(height, align);
253			frame->size = width * frame->pitch[1] +
254				width / 2 * frame->pitch[0];
255		} else {
256			frame->pitch[0] = ALIGN(width, align);
257			frame->pitch[1] = ALIGN(width, align);
258			frame->size = height * frame->pitch[1] +
259				height / 2 * frame->pitch[0];
260		}
261
262		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
263			frame->UBufOffset = (int)frame->pitch[1] * width;
264			frame->VBufOffset = frame->UBufOffset;
265		} else {
266			frame->UBufOffset = (int)frame->pitch[1] * height;
267			frame->VBufOffset = frame->UBufOffset;
268		}
269	} else if (is_planar_fourcc(frame->id)) {
270		assert((width & 1) == 0);
271		assert((height & 1) == 0);
272		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
273			frame->pitch[0] = ALIGN((height / 2), align);
274			frame->pitch[1] = ALIGN(height, align);
275			frame->size = width;
276		} else {
277			frame->pitch[0] = ALIGN((width / 2), align);
278			frame->pitch[1] = ALIGN(width, align);
279			frame->size = height;
280		}
281		frame->size *= frame->pitch[0] + frame->pitch[1];
282
283		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
284			frame->UBufOffset = (int)frame->pitch[1] * width;
285			frame->VBufOffset =
286				frame->UBufOffset + (int)frame->pitch[0] * width / 2;
287		} else {
288			frame->UBufOffset = (int)frame->pitch[1] * height;
289			frame->VBufOffset =
290				frame->UBufOffset + (int)frame->pitch[0] * height / 2;
291		}
292	} else {
293		switch (frame->id) {
294		case FOURCC_RGB888:
295		case FOURCC_AYUV:
296			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
297				frame->pitch[0] = ALIGN((height << 2), align);
298				frame->size = (int)frame->pitch[0] * width;
299			} else {
300				frame->pitch[0] = ALIGN((width << 2), align);
301				frame->size = (int)frame->pitch[0] * height;
302			}
303			frame->UBufOffset = frame->VBufOffset = 0;
304			break;
305		case FOURCC_RGB565:
306			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
307				frame->pitch[0] = ALIGN((height << 1), align);
308				frame->size = (int)frame->pitch[0] * width;
309			} else {
310				frame->pitch[0] = ALIGN((width << 1), align);
311				frame->size = (int)frame->pitch[0] * height;
312			}
313			frame->UBufOffset = frame->VBufOffset = 0;
314			break;
315
316		default:
317			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
318				frame->pitch[0] = ALIGN((height << 1), align);
319				frame->size = (int)frame->pitch[0] * width;
320			} else {
321				frame->pitch[0] = ALIGN((width << 1), align);
322				frame->size = (int)frame->pitch[0] * height;
323			}
324			break;
325		}
326		frame->pitch[1] = 0;
327		frame->UBufOffset = 0;
328		frame->VBufOffset = 0;
329	}
330
331	assert(frame->size);
332}
333
334static void plane_dims(const struct sna_video_frame *frame, int sub,
335		       int *x, int *y, int *w, int *h)
336{
337	*x = frame->image.x1;
338	*y = frame->image.y1;
339	*w = frame->image.x2 - frame->image.x1;
340	*h = frame->image.y2 - frame->image.y1;
341
342	if (sub) {
343		*x >>= 1; *w >>= 1;
344		*y >>= 1; *h >>= 1;
345	}
346}
347
348static void sna_memcpy_cbcr_plane(struct sna_video *video,
349				  uint16_t *dst, const uint16_t *src,
350				  const struct sna_video_frame *frame)
351{
352	int dstPitch = frame->pitch[0] >> 1, srcPitch;
353	const uint16_t *s;
354	int i, j = 0;
355	int x, y, w, h;
356
357	plane_dims(frame, 1, &x, &y, &w, &h);
358
359	srcPitch = ALIGN((frame->width >> 1), 2);
360
361	src += y * srcPitch + x;
362	if (!video->textured)
363		x = y = 0;
364
365	switch (frame->rotation) {
366	case RR_Rotate_0:
367		dst += y * dstPitch + x;
368		if (srcPitch == dstPitch && srcPitch == w)
369			memcpy(dst, src, (srcPitch * h) << 1);
370		else while (h--) {
371			memcpy(dst, src, w << 1);
372			src += srcPitch;
373			dst += dstPitch;
374		}
375		break;
376	case RR_Rotate_90:
377		for (i = 0; i < h; i++) {
378			s = src;
379			for (j = 0; j < w; j++)
380				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
381			src += srcPitch;
382		}
383		break;
384	case RR_Rotate_180:
385		for (i = 0; i < h; i++) {
386			s = src;
387			for (j = 0; j < w; j++) {
388				dst[(x + w - j - 1) +
389				    ((h - i - 1) * dstPitch)] = *s++;
390			}
391			src += srcPitch;
392		}
393		break;
394	case RR_Rotate_270:
395		for (i = 0; i < h; i++) {
396			s = src;
397			for (j = 0; j < w; j++) {
398				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
399			}
400			src += srcPitch;
401		}
402		break;
403	}
404}
405
406static void sna_memcpy_plane(struct sna_video *video,
407			     uint8_t *dst, const uint8_t *src,
408			     const struct sna_video_frame *frame, int sub)
409{
410	int dstPitch = frame->pitch[!sub], srcPitch;
411	const uint8_t *s;
412	int i, j = 0;
413	int x, y, w, h;
414
415	plane_dims(frame, sub, &x, &y, &w, &h);
416
417	if (sub)
418		srcPitch = ALIGN((frame->width >> 1), 4);
419	else
420		srcPitch = ALIGN(frame->width, 4);
421
422	src += y * srcPitch + x;
423	if (!video->textured)
424		x = y = 0;
425
426	switch (frame->rotation) {
427	case RR_Rotate_0:
428		dst += y * dstPitch + x;
429		if (srcPitch == dstPitch && srcPitch == w)
430			memcpy(dst, src, srcPitch * h);
431		else while (h--) {
432			memcpy(dst, src, w);
433			src += srcPitch;
434			dst += dstPitch;
435		}
436		break;
437	case RR_Rotate_90:
438		for (i = 0; i < h; i++) {
439			s = src;
440			for (j = 0; j < w; j++)
441				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
442			src += srcPitch;
443		}
444		break;
445	case RR_Rotate_180:
446		for (i = 0; i < h; i++) {
447			s = src;
448			for (j = 0; j < w; j++) {
449				dst[(x + w - j - 1) +
450				    ((h - i - 1) * dstPitch)] = *s++;
451			}
452			src += srcPitch;
453		}
454		break;
455	case RR_Rotate_270:
456		for (i = 0; i < h; i++) {
457			s = src;
458			for (j = 0; j < w; j++) {
459				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
460			}
461			src += srcPitch;
462		}
463		break;
464	}
465}
466
467static void
468sna_copy_nv12_data(struct sna_video *video,
469		   const struct sna_video_frame *frame,
470		   const uint8_t *src, uint8_t *dst)
471{
472	sna_memcpy_plane(video, dst, src, frame, 0);
473	src += frame->height * ALIGN(frame->width, 4);
474	dst += frame->UBufOffset;
475	sna_memcpy_cbcr_plane(video, (void*)dst, (void*)src, frame);
476}
477
478static void
479sna_copy_planar_data(struct sna_video *video,
480		     const struct sna_video_frame *frame,
481		     const uint8_t *src, uint8_t *dst)
482{
483	uint8_t *d;
484
485	sna_memcpy_plane(video, dst, src, frame, 0);
486	src += frame->height * ALIGN(frame->width, 4);
487
488	if (frame->id == FOURCC_I420)
489		d = dst + frame->UBufOffset;
490	else
491		d = dst + frame->VBufOffset;
492	sna_memcpy_plane(video, d, src, frame, 1);
493	src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4);
494
495	if (frame->id == FOURCC_I420)
496		d = dst + frame->VBufOffset;
497	else
498		d = dst + frame->UBufOffset;
499	sna_memcpy_plane(video, d, src, frame, 1);
500}
501
502static void
503sna_copy_packed_data(struct sna_video *video,
504		     const struct sna_video_frame *frame,
505		     const uint8_t *buf,
506		     uint8_t *dst)
507{
508	int pitch = frame->width << 1;
509	const uint8_t *src, *s;
510	int x, y, w, h;
511	int i, j;
512
513	if (video->textured) {
514		/* XXX support copying cropped extents */
515		x = y = 0;
516		w = frame->width;
517		h = frame->height;
518	} else {
519		x = frame->image.x1;
520		y = frame->image.y1;
521		w = frame->image.x2 - frame->image.x1;
522		h = frame->image.y2 - frame->image.y1;
523	}
524
525	src = buf + (y * pitch) + (x << 1);
526
527	switch (frame->rotation) {
528	case RR_Rotate_0:
529		w <<= 1;
530		for (i = 0; i < h; i++) {
531			memcpy(dst, src, w);
532			src += pitch;
533			dst += frame->pitch[0];
534		}
535		break;
536	case RR_Rotate_90:
537		h <<= 1;
538		for (i = 0; i < h; i += 2) {
539			s = src;
540			for (j = 0; j < w; j++) {
541				/* Copy Y */
542				dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s;
543				s += 2;
544			}
545			src += pitch;
546		}
547		h >>= 1;
548		src = buf + (y * pitch) + (x << 1);
549		for (i = 0; i < h; i += 2) {
550			for (j = 0; j < w; j += 2) {
551				/* Copy U */
552				dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
553				dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
554				/* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
555				dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
556			}
557		}
558		break;
559	case RR_Rotate_180:
560		w <<= 1;
561		for (i = 0; i < h; i++) {
562			s = src;
563			for (j = 0; j < w; j += 4) {
564				dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++;
565				dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++;
566				dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++;
567				dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++;
568			}
569			src += pitch;
570		}
571		break;
572	case RR_Rotate_270:
573		h <<= 1;
574		for (i = 0; i < h; i += 2) {
575			s = src;
576			for (j = 0; j < w; j++) {
577				/* Copy Y */
578				dst[(h - i - 2) + (j * frame->pitch[0])] = *s;
579				s += 2;
580			}
581			src += pitch;
582		}
583		h >>= 1;
584		src = buf + (y * pitch) + (x << 1);
585		for (i = 0; i < h; i += 2) {
586			for (j = 0; j < w; j += 2) {
587				/* Copy U */
588				dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
589				dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
590				/* Copy V */
591				dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
592				dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
593			}
594		}
595		break;
596	}
597}
598
599static void
600sna_copy_ayuv_data(struct sna_video *video,
601		   const struct sna_video_frame *frame,
602		   const uint8_t *buf,
603		   uint8_t *dst)
604{
605	int pitch = frame->width << 2;
606	const uint32_t *src_dw;
607	const uint8_t *src;
608	uint32_t *dst_dw = (uint32_t *)dst;
609	int x, y, w, h;
610	int i, j;
611
612	if (video->textured) {
613		/* XXX support copying cropped extents */
614		x = y = 0;
615		w = frame->width;
616		h = frame->height;
617	} else {
618		x = frame->image.x1;
619		y = frame->image.y1;
620		w = frame->image.x2 - frame->image.x1;
621		h = frame->image.y2 - frame->image.y1;
622	}
623
624	src = buf + (y * pitch) + (x << 2);
625	src_dw = (uint32_t *)src;
626
627	switch (frame->rotation) {
628	case RR_Rotate_0:
629		for (i = 0; i < h; i++) {
630			for (j = 0; j < w; j++) {
631				/*
632				 * Have to reverse bytes order, because the only
633				 * player which supports AYUV format currently is
634				 * Gstreamer and it supports in bad way, even though
635				 * spec says MSB:AYUV, we get the bytes opposite way.
636				 */
637				dst_dw[i * w + j] = bswap_32(src_dw[i * w + j]);
638			}
639		}
640		break;
641	case RR_Rotate_90:
642		for (i = 0; i < h; i++) {
643			for (j = 0; j < w; j++) {
644				dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]);
645			}
646		}
647		break;
648	case RR_Rotate_180:
649		for (i = 0; i < h; i++) {
650			for (j = 0; j < w; j++) {
651				dst_dw[(h - i - 1) * w + w - j - 1] = bswap_32(src_dw[i * w + j]);
652			}
653		}
654		break;
655	case RR_Rotate_270:
656		for (i = 0; i < h; i++) {
657			for (j = 0; j < w; j++) {
658				dst_dw[(w - j - 1) * h + i] = bswap_32(src_dw[i * w + j]);
659			}
660		}
661		break;
662	}
663}
664
665bool
666sna_video_copy_data(struct sna_video *video,
667		    struct sna_video_frame *frame,
668		    const uint8_t *buf)
669{
670	uint8_t *dst;
671
672	DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n",
673	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
674	     frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1],
675	     frame->rotation, video->textured));
676	DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n",
677	     __FUNCTION__,
678	     frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2,
679	     frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2));
680	assert(frame->width && frame->height);
681	assert(frame->rotation);
682	assert(frame->size);
683
684	/* In the common case, we can simply the upload in a single pwrite */
685	if (frame->rotation == RR_Rotate_0 && !video->tiled && !is_ayuv_fourcc(frame->id)) {
686		DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n",
687		     __FUNCTION__, is_planar_fourcc(frame->id)));
688		if (is_nv12_fourcc(frame->id)) {
689			int w = frame->image.x2 - frame->image.x1;
690			int h = frame->image.y2 - frame->image.y1;
691			if (ALIGN(h, 2) == frame->height &&
692			    ALIGN(w, 4) == frame->pitch[0] &&
693			    ALIGN(w, 4) == frame->pitch[1]) {
694				if (frame->bo) {
695					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
696							   buf, frame->size))
697						goto use_gtt;
698				} else {
699					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
700								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
701								       (void **)&dst);
702					if (frame->bo == NULL)
703						return false;
704
705					memcpy(dst, buf, frame->size);
706				}
707				return true;
708			}
709		} else if (is_planar_fourcc(frame->id)) {
710			int w = frame->image.x2 - frame->image.x1;
711			int h = frame->image.y2 - frame->image.y1;
712			if (ALIGN(h, 2) == frame->height &&
713			    ALIGN(w >> 1, 4) == frame->pitch[0] &&
714			    ALIGN(w, 4) == frame->pitch[1]) {
715				if (frame->bo) {
716					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
717							   buf, frame->size))
718						goto use_gtt;
719				} else {
720					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
721								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
722								       (void **)&dst);
723					if (frame->bo == NULL)
724						return false;
725
726					memcpy(dst, buf, frame->size);
727				}
728				if (frame->id != FOURCC_I420) {
729					uint32_t tmp;
730					tmp = frame->VBufOffset;
731					frame->VBufOffset = frame->UBufOffset;
732					frame->UBufOffset = tmp;
733				}
734				return true;
735			}
736		} else {
737			int x, y, w, h;
738
739			if (video->textured) {
740				/* XXX support copying cropped extents */
741				x = y = 0;
742				w = frame->width;
743				h = frame->height;
744			} else {
745				x = frame->image.x1;
746				y = frame->image.y1;
747				w = frame->image.x2 - frame->image.x1;
748				h = frame->image.y2 - frame->image.y1;
749			}
750
751			if (w*2 == frame->pitch[0]) {
752				buf += (2U*y * frame->width) + (x << 1);
753				if (frame->bo) {
754					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
755							   buf, 2U*h*frame->width))
756						goto use_gtt;
757				} else {
758					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
759								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
760								       (void **)&dst);
761					if (frame->bo == NULL)
762						return false;
763
764					memcpy(dst, buf, 2U*h*frame->width);
765				}
766				return true;
767			}
768		}
769
770		DBG(("%s: source cropped, fallback\n", __FUNCTION__));
771	}
772
773use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
774	if (frame->bo) {
775		dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo);
776		if (dst == NULL)
777			return false;
778	} else {
779		frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
780					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
781					       (void **)&dst);
782		if (frame->bo == NULL)
783			return false;
784	}
785
786	if (is_nv12_fourcc(frame->id))
787		sna_copy_nv12_data(video, frame, buf, dst);
788	else if (is_planar_fourcc(frame->id))
789		sna_copy_planar_data(video, frame, buf, dst);
790	else if (is_ayuv_fourcc(frame->id))
791		sna_copy_ayuv_data(video, frame, buf, dst);
792	else
793		sna_copy_packed_data(video, frame, buf, dst);
794
795	return true;
796}
797
798void sna_video_fill_colorkey(struct sna_video *video,
799			     const RegionRec *clip)
800{
801	struct sna *sna = video->sna;
802	PixmapPtr front = sna->front;
803	struct kgem_bo *bo = __sna_pixmap_get_bo(front);
804	uint8_t *dst, *tmp;
805	int w, width;
806
807	if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip))
808		return;
809
810	assert(bo);
811	if (!wedged(sna) &&
812	    sna_blt_fill_boxes(sna, GXcopy, bo,
813			       front->drawable.bitsPerPixel,
814			       video->color_key,
815			       region_rects(clip),
816			       region_num_rects(clip))) {
817		RegionCopy(&video->clip, (RegionPtr)clip);
818		return;
819	}
820
821	dst = kgem_bo_map__gtt(&sna->kgem, bo);
822	if (dst == NULL)
823		return;
824
825	w = front->drawable.bitsPerPixel/8;
826	width = (clip->extents.x2 - clip->extents.x1) * w;
827	tmp = malloc(width);
828	if (tmp == NULL)
829		return;
830
831	memcpy(tmp, &video->color_key, w);
832	while (2 * w < width) {
833		memcpy(tmp + w, tmp, w);
834		w *= 2;
835	}
836	if (w < width)
837		memcpy(tmp + w, tmp, width - w);
838
839	if (sigtrap_get() == 0) {
840		const BoxRec *box = region_rects(clip);
841		int n = region_num_rects(clip);
842
843		w = front->drawable.bitsPerPixel/8;
844		do {
845			int y = box->y1;
846			uint8_t *row = dst + y*bo->pitch + w*box->x1;
847
848			width = (box->x2 - box->x1) * w;
849			while (y < box->y2) {
850				memcpy(row, tmp, width);
851				row += bo->pitch;
852				y++;
853			}
854			box++;
855		} while (--n);
856		sigtrap_put();
857
858		RegionCopy(&video->clip, (RegionPtr)clip);
859	}
860
861	free(tmp);
862}
863
864XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
865{
866	XvAdaptorPtr new_adaptors;
867
868	new_adaptors = realloc(sna->xv.adaptors,
869			       (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec));
870	if (new_adaptors == NULL)
871		return NULL;
872
873	if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) {
874		XvAdaptorPtr adaptor = new_adaptors;
875		int i = sna->xv.num_adaptors, j;
876		while (i--) {
877			for (j = 0; j < adaptor->nPorts; j++)
878				adaptor->pPorts[j].pAdaptor = adaptor;
879			adaptor++;
880		}
881	}
882
883	sna->xv.adaptors = new_adaptors;
884	return &sna->xv.adaptors[sna->xv.num_adaptors++];
885}
886
887int
888sna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out)
889{
890	*out = in;
891	return Success;
892}
893
894int
895sna_xv_free_port(XvPortPtr port)
896{
897	return Success;
898}
899
900int
901sna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats)
902{
903	XvFormatPtr out = formats;
904	int count = 0;
905
906	while (num_formats--) {
907		int num_visuals = screen->numVisuals;
908		VisualPtr v = screen->visuals;
909
910		while (num_visuals--) {
911			if (v->class == TrueColor &&
912			    v->nplanes == formats->depth) {
913				int tmp = out[count].depth;
914				out[count].depth = formats->depth;
915				out[count].visual = v->vid;
916				formats->depth = tmp;
917				count++;
918				break;
919			}
920			v++;
921		}
922
923		formats++;
924	}
925
926	return count;
927}
928
929#if XORG_XV_VERSION < 2
930static int
931sna_xv_query_adaptors(ScreenPtr screen,
932		      XvAdaptorPtr *adaptors,
933		      int *num_adaptors)
934{
935	struct sna *sna = to_sna_from_screen(screen);
936
937	*num_adaptors = sna->xv.num_adaptors;
938	*adaptors = sna->xv.adaptors;
939	return Success;
940}
941
942static Bool
943sna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL)
944{
945	struct sna *sna = to_sna_from_screen(screen);
946	sna_video_close(sna);
947	return TRUE;
948}
949#endif
950
951void sna_video_init(struct sna *sna, ScreenPtr screen)
952{
953	XvScreenPtr xv;
954
955	if (noXvExtension)
956		return;
957
958	if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) {
959		XF86VideoAdaptorPtr *adaptors = NULL;
960		int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
961		if (num_adaptors)
962			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
963				   "Ignoring generic xf86XV adaptors");
964		free(adaptors);
965	}
966
967	if (XvScreenInit(screen) != Success)
968		return;
969
970	xv = to_xv(screen);
971#if XORG_XV_VERSION < 2
972	xv->ddCloseScreen = sna_xv_close_screen;
973	xv->ddQueryAdaptors = sna_xv_query_adaptors;
974#endif
975
976	sna_video_textured_setup(sna, screen);
977	sna_video_sprite_setup(sna, screen);
978	sna_video_overlay_setup(sna, screen);
979
980	if (sna->xv.num_adaptors >= 2 &&
981	    xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) {
982		XvAdaptorRec tmp;
983
984		tmp = sna->xv.adaptors[0];
985		sna->xv.adaptors[0] = sna->xv.adaptors[1];
986		sna->xv.adaptors[1] = tmp;
987	}
988
989	xv->nAdaptors = sna->xv.num_adaptors;
990	xv->pAdaptors = sna->xv.adaptors;
991
992	sna_video_xvmc_setup(sna, screen);
993}
994
995void sna_video_destroy_window(WindowPtr win)
996{
997	XvPortPtr port;
998
999	port = sna_window_get_port(win);
1000	if (port) {
1001#if XORG_XV_VERSION < 2
1002		port->pAdaptor->ddStopVideo(NULL, port, &win->drawable);
1003#else
1004		port->pAdaptor->ddStopVideo(port, &win->drawable);
1005#endif
1006	}
1007	assert(sna_window_get_port(win) == NULL);
1008}
1009
1010void sna_video_close(struct sna *sna)
1011{
1012	int i;
1013
1014	for (i = 0; i < sna->xv.num_adaptors; i++) {
1015		free(sna->xv.adaptors[i].pPorts->devPriv.ptr);
1016		free(sna->xv.adaptors[i].pPorts);
1017		free(sna->xv.adaptors[i].pEncodings);
1018	}
1019	free(sna->xv.adaptors);
1020
1021	sna->xv.adaptors = NULL;
1022	sna->xv.num_adaptors = 0;
1023}
1024