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
63#ifdef SNA_XVMC
64#define _SNA_XVMC_SERVER_
65#include "sna_video_hwmc.h"
66#else
67static inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr)
68{
69	DBG(("%s: XvMC not compiled in\n", __FUNCTION__));
70}
71#endif
72
73void sna_video_free_buffers(struct sna_video *video)
74{
75	unsigned int i;
76
77	for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) {
78		if (video->old_buf[i]) {
79			kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]);
80			video->old_buf[i] = NULL;
81		}
82	}
83
84	if (video->buf) {
85		kgem_bo_destroy(&video->sna->kgem, video->buf);
86		video->buf = NULL;
87	}
88}
89
90struct kgem_bo *
91sna_video_buffer(struct sna_video *video,
92		 struct sna_video_frame *frame)
93{
94	/* Free the current buffer if we're going to have to reallocate */
95	if (video->buf && __kgem_bo_size(video->buf) < frame->size)
96		sna_video_free_buffers(video);
97
98	if (video->buf && video->buf->scanout) {
99		if (frame->width != video->width ||
100		    frame->height != video->height ||
101		    frame->id != video->format)
102			sna_video_free_buffers(video);
103	}
104
105	if (video->buf == NULL) {
106		if (video->tiled) {
107			video->buf = kgem_create_2d(&video->sna->kgem,
108						    frame->width, frame->height, 32,
109						    I915_TILING_X, CREATE_EXACT);
110		} else {
111			video->buf = kgem_create_linear(&video->sna->kgem, frame->size,
112							CREATE_GTT_MAP);
113		}
114	}
115
116	video->width  = frame->width;
117	video->height = frame->height;
118	video->format = frame->id;
119
120	return video->buf;
121}
122
123void sna_video_buffer_fini(struct sna_video *video)
124{
125	struct kgem_bo *bo;
126
127	bo = video->old_buf[1];
128	video->old_buf[1] = video->old_buf[0];
129	video->old_buf[0] = video->buf;
130	video->buf = bo;
131}
132
133bool
134sna_video_clip_helper(struct sna_video *video,
135		      struct sna_video_frame *frame,
136		      xf86CrtcPtr *crtc_ret,
137		      BoxPtr dst,
138		      short src_x, short src_y,
139		      short drw_x, short drw_y,
140		      short src_w, short src_h,
141		      short drw_w, short drw_h,
142		      RegionPtr reg)
143{
144	bool ret;
145	RegionRec crtc_region_local;
146	RegionPtr crtc_region = reg;
147	INT32 x1, x2, y1, y2;
148	xf86CrtcPtr crtc;
149
150	x1 = src_x;
151	x2 = src_x + src_w;
152	y1 = src_y;
153	y2 = src_y + src_h;
154
155	dst->x1 = drw_x;
156	dst->x2 = drw_x + drw_w;
157	dst->y1 = drw_y;
158	dst->y2 = drw_y + drw_h;
159
160	/*
161	 * For overlay video, compute the relevant CRTC and
162	 * clip video to that
163	 */
164	crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc);
165
166	/* For textured video, we don't actually want to clip at all. */
167	if (crtc && !video->textured) {
168		crtc_region_local.extents = crtc->bounds;
169		crtc_region_local.data = NULL;
170		crtc_region = &crtc_region_local;
171		RegionIntersect(crtc_region, crtc_region, reg);
172	}
173	*crtc_ret = crtc;
174
175	ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2,
176				    crtc_region, frame->width, frame->height);
177	if (crtc_region != reg)
178		RegionUninit(crtc_region);
179
180	frame->src.x1 = x1 >> 16;
181	frame->src.y1 = y1 >> 16;
182	frame->src.x2 = (x2 + 0xffff) >> 16;
183	frame->src.y2 = (y2 + 0xffff) >> 16;
184
185	frame->image.x1 = frame->src.x1 & ~1;
186	frame->image.x2 = ALIGN(frame->src.x2, 2);
187	if (is_planar_fourcc(frame->id)) {
188		frame->image.y1 = frame->src.y1 & ~1;
189		frame->image.y2 = ALIGN(frame->src.y2, 2);
190	} else {
191		frame->image.y1 = frame->src.y1;
192		frame->image.y2 = frame->src.y2;
193	}
194
195	return ret;
196}
197
198void
199sna_video_frame_init(struct sna_video *video,
200		     int id, short width, short height,
201		     struct sna_video_frame *frame)
202{
203	DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n",
204	     __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment));
205	assert(width && height);
206
207	frame->bo = NULL;
208	frame->id = id;
209	frame->width = width;
210	frame->height = height;
211	frame->rotation = 0;
212}
213
214void
215sna_video_frame_set_rotation(struct sna_video *video,
216			     struct sna_video_frame *frame,
217			     Rotation rotation)
218{
219	unsigned width = frame->width;
220	unsigned height = frame->height;
221	unsigned align;
222
223	DBG(("%s: rotation=%d\n", __FUNCTION__, rotation));
224	frame->rotation = rotation;
225
226	align = video->alignment;
227#if SNA_XVMC
228	/* for i915 xvmc, hw requires 1kb aligned surfaces */
229	if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024)
230		align = 1024;
231#endif
232
233	/* Determine the desired destination pitch (representing the
234	 * chroma's pitch in the planar case).
235	 */
236	if (is_planar_fourcc(frame->id)) {
237		assert((width & 1) == 0);
238		assert((height & 1) == 0);
239		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
240			frame->pitch[0] = ALIGN((height / 2), align);
241			frame->pitch[1] = ALIGN(height, align);
242			frame->size = width;
243		} else {
244			frame->pitch[0] = ALIGN((width / 2), align);
245			frame->pitch[1] = ALIGN(width, align);
246			frame->size = height;
247		}
248		frame->size *= frame->pitch[0] + frame->pitch[1];
249
250		if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
251			frame->UBufOffset = (int)frame->pitch[1] * width;
252			frame->VBufOffset =
253				frame->UBufOffset + (int)frame->pitch[0] * width / 2;
254		} else {
255			frame->UBufOffset = (int)frame->pitch[1] * height;
256			frame->VBufOffset =
257				frame->UBufOffset + (int)frame->pitch[0] * height / 2;
258		}
259	} else {
260		switch (frame->id) {
261		case FOURCC_RGB888:
262			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
263				frame->pitch[0] = ALIGN((height << 2), align);
264				frame->size = (int)frame->pitch[0] * width;
265			} else {
266				frame->pitch[0] = ALIGN((width << 2), align);
267				frame->size = (int)frame->pitch[0] * height;
268			}
269			frame->UBufOffset = frame->VBufOffset = 0;
270			break;
271		case FOURCC_RGB565:
272			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
273				frame->pitch[0] = ALIGN((height << 1), align);
274				frame->size = (int)frame->pitch[0] * width;
275			} else {
276				frame->pitch[0] = ALIGN((width << 1), align);
277				frame->size = (int)frame->pitch[0] * height;
278			}
279			frame->UBufOffset = frame->VBufOffset = 0;
280			break;
281
282		default:
283			if (rotation & (RR_Rotate_90 | RR_Rotate_270)) {
284				frame->pitch[0] = ALIGN((height << 1), align);
285				frame->size = (int)frame->pitch[0] * width;
286			} else {
287				frame->pitch[0] = ALIGN((width << 1), align);
288				frame->size = (int)frame->pitch[0] * height;
289			}
290			break;
291		}
292		frame->pitch[1] = 0;
293		frame->UBufOffset = 0;
294		frame->VBufOffset = 0;
295	}
296
297	assert(frame->size);
298}
299
300static void sna_memcpy_plane(struct sna_video *video,
301			     uint8_t *dst, const uint8_t *src,
302			     const struct sna_video_frame *frame, int sub)
303{
304	int dstPitch = frame->pitch[!sub], srcPitch;
305	const uint8_t *s;
306	int i, j = 0;
307	int x, y, w, h;
308
309	x = frame->image.x1;
310	y = frame->image.y1;
311	w = frame->image.x2 - frame->image.x1;
312	h = frame->image.y2 - frame->image.y1;
313	if (sub) {
314		x >>= 1; w >>= 1;
315		y >>= 1; h >>= 1;
316		srcPitch = ALIGN((frame->width >> 1), 4);
317	} else
318		srcPitch = ALIGN(frame->width, 4);
319
320	src += y * srcPitch + x;
321	if (!video->textured)
322		x = y = 0;
323
324	switch (frame->rotation) {
325	case RR_Rotate_0:
326		dst += y * dstPitch + x;
327		if (srcPitch == dstPitch && srcPitch == w)
328			memcpy(dst, src, srcPitch * h);
329		else while (h--) {
330			memcpy(dst, src, w);
331			src += srcPitch;
332			dst += dstPitch;
333		}
334		break;
335	case RR_Rotate_90:
336		for (i = 0; i < h; i++) {
337			s = src;
338			for (j = 0; j < w; j++)
339				dst[i + ((x + w - j - 1) * dstPitch)] = *s++;
340			src += srcPitch;
341		}
342		break;
343	case RR_Rotate_180:
344		for (i = 0; i < h; i++) {
345			s = src;
346			for (j = 0; j < w; j++) {
347				dst[(x + w - j - 1) +
348				    ((h - i - 1) * dstPitch)] = *s++;
349			}
350			src += srcPitch;
351		}
352		break;
353	case RR_Rotate_270:
354		for (i = 0; i < h; i++) {
355			s = src;
356			for (j = 0; j < w; j++) {
357				dst[(h - i - 1) + (x + j * dstPitch)] = *s++;
358			}
359			src += srcPitch;
360		}
361		break;
362	}
363}
364
365static void
366sna_copy_planar_data(struct sna_video *video,
367		     const struct sna_video_frame *frame,
368		     const uint8_t *src, uint8_t *dst)
369{
370	uint8_t *d;
371
372	sna_memcpy_plane(video, dst, src, frame, 0);
373	src += frame->height * ALIGN(frame->width, 4);
374
375	if (frame->id == FOURCC_I420)
376		d = dst + frame->UBufOffset;
377	else
378		d = dst + frame->VBufOffset;
379	sna_memcpy_plane(video, d, src, frame, 1);
380	src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4);
381
382	if (frame->id == FOURCC_I420)
383		d = dst + frame->VBufOffset;
384	else
385		d = dst + frame->UBufOffset;
386	sna_memcpy_plane(video, d, src, frame, 1);
387}
388
389static void
390sna_copy_packed_data(struct sna_video *video,
391		     const struct sna_video_frame *frame,
392		     const uint8_t *buf,
393		     uint8_t *dst)
394{
395	int pitch = frame->width << 1;
396	const uint8_t *src, *s;
397	int x, y, w, h;
398	int i, j;
399
400	if (video->textured) {
401		/* XXX support copying cropped extents */
402		x = y = 0;
403		w = frame->width;
404		h = frame->height;
405	} else {
406		x = frame->image.x1;
407		y = frame->image.y1;
408		w = frame->image.x2 - frame->image.x1;
409		h = frame->image.y2 - frame->image.y1;
410	}
411
412	src = buf + (y * pitch) + (x << 1);
413
414	switch (frame->rotation) {
415	case RR_Rotate_0:
416		w <<= 1;
417		for (i = 0; i < h; i++) {
418			memcpy(dst, src, w);
419			src += pitch;
420			dst += frame->pitch[0];
421		}
422		break;
423	case RR_Rotate_90:
424		h <<= 1;
425		for (i = 0; i < h; i += 2) {
426			s = src;
427			for (j = 0; j < w; j++) {
428				/* Copy Y */
429				dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s;
430				s += 2;
431			}
432			src += pitch;
433		}
434		h >>= 1;
435		src = buf + (y * pitch) + (x << 1);
436		for (i = 0; i < h; i += 2) {
437			for (j = 0; j < w; j += 2) {
438				/* Copy U */
439				dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
440				dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
441				/* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
442				dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
443			}
444		}
445		break;
446	case RR_Rotate_180:
447		w <<= 1;
448		for (i = 0; i < h; i++) {
449			s = src;
450			for (j = 0; j < w; j += 4) {
451				dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++;
452				dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++;
453				dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++;
454				dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++;
455			}
456			src += pitch;
457		}
458		break;
459	case RR_Rotate_270:
460		h <<= 1;
461		for (i = 0; i < h; i += 2) {
462			s = src;
463			for (j = 0; j < w; j++) {
464				/* Copy Y */
465				dst[(h - i - 2) + (j * frame->pitch[0])] = *s;
466				s += 2;
467			}
468			src += pitch;
469		}
470		h >>= 1;
471		src = buf + (y * pitch) + (x << 1);
472		for (i = 0; i < h; i += 2) {
473			for (j = 0; j < w; j += 2) {
474				/* Copy U */
475				dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)];
476				dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)];
477				/* Copy V */
478				dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)];
479				dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)];
480			}
481		}
482		break;
483	}
484}
485
486bool
487sna_video_copy_data(struct sna_video *video,
488		    struct sna_video_frame *frame,
489		    const uint8_t *buf)
490{
491	uint8_t *dst;
492
493	DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n",
494	     __FUNCTION__, frame->bo ? frame->bo->handle : 0,
495	     frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1],
496	     frame->rotation, video->textured));
497	DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n",
498	     __FUNCTION__,
499	     frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2,
500	     frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2));
501	assert(frame->width && frame->height);
502	assert(frame->rotation);
503	assert(frame->size);
504
505	/* In the common case, we can simply the upload in a single pwrite */
506	if (frame->rotation == RR_Rotate_0 && !video->tiled) {
507		DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n",
508		     __FUNCTION__, is_planar_fourcc(frame->id)));
509		if (is_planar_fourcc(frame->id)) {
510			int w = frame->image.x2 - frame->image.x1;
511			int h = frame->image.y2 - frame->image.y1;
512			if (ALIGN(h, 2) == frame->height &&
513			    ALIGN(w >> 1, 4) == frame->pitch[0] &&
514			    ALIGN(w, 4) == frame->pitch[1]) {
515				if (frame->bo) {
516					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
517							   buf, frame->size))
518						goto use_gtt;
519				} else {
520					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
521								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
522								       (void **)&dst);
523					if (frame->bo == NULL)
524						return false;
525
526					memcpy(dst, buf, frame->size);
527				}
528				if (frame->id != FOURCC_I420) {
529					uint32_t tmp;
530					tmp = frame->VBufOffset;
531					frame->VBufOffset = frame->UBufOffset;
532					frame->UBufOffset = tmp;
533				}
534				return true;
535			}
536		} else {
537			int x, y, w, h;
538
539			if (video->textured) {
540				/* XXX support copying cropped extents */
541				x = y = 0;
542				w = frame->width;
543				h = frame->height;
544			} else {
545				x = frame->image.x1;
546				y = frame->image.y1;
547				w = frame->image.x2 - frame->image.x1;
548				h = frame->image.y2 - frame->image.y1;
549			}
550
551			if (w*2 == frame->pitch[0]) {
552				buf += (2U*y * frame->width) + (x << 1);
553				if (frame->bo) {
554					if (!kgem_bo_write(&video->sna->kgem, frame->bo,
555							   buf, 2U*h*frame->width))
556						goto use_gtt;
557				} else {
558					frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
559								       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
560								       (void **)&dst);
561					if (frame->bo == NULL)
562						return false;
563
564					memcpy(dst, buf, 2U*h*frame->width);
565				}
566				return true;
567			}
568		}
569
570		DBG(("%s: source cropped, fallback\n", __FUNCTION__));
571	}
572
573use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
574	if (frame->bo) {
575		dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo);
576		if (dst == NULL)
577			return false;
578	} else {
579		frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size,
580					       KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE,
581					       (void **)&dst);
582		if (frame->bo == NULL)
583			return false;
584	}
585
586	if (is_planar_fourcc(frame->id))
587		sna_copy_planar_data(video, frame, buf, dst);
588	else
589		sna_copy_packed_data(video, frame, buf, dst);
590
591	return true;
592}
593
594XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
595{
596	XvAdaptorPtr new_adaptors;
597
598	new_adaptors = realloc(sna->xv.adaptors,
599			       (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec));
600	if (new_adaptors == NULL)
601		return NULL;
602
603	if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) {
604		XvAdaptorPtr adaptor = new_adaptors;
605		int i = sna->xv.num_adaptors, j;
606		while (i--) {
607			for (j = 0; j < adaptor->nPorts; j++)
608				adaptor->pPorts[j].pAdaptor = adaptor;
609			adaptor++;
610		}
611	}
612
613	sna->xv.adaptors = new_adaptors;
614	return &sna->xv.adaptors[sna->xv.num_adaptors++];
615}
616
617int
618sna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out)
619{
620	*out = in;
621	return Success;
622}
623
624int
625sna_xv_free_port(XvPortPtr port)
626{
627	return Success;
628}
629
630int
631sna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats)
632{
633	XvFormatPtr out = formats;
634	int count = 0;
635
636	while (num_formats--) {
637		int num_visuals = screen->numVisuals;
638		VisualPtr v = screen->visuals;
639
640		while (num_visuals--) {
641			if (v->class == TrueColor &&
642			    v->nplanes == formats->depth) {
643				int tmp = out[count].depth;
644				out[count].depth = formats->depth;
645				out[count].visual = v->vid;
646				formats->depth = tmp;
647				count++;
648				break;
649			}
650			v++;
651		}
652
653		formats++;
654	}
655
656	return count;
657}
658
659#if XORG_XV_VERSION < 2
660static int
661sna_xv_query_adaptors(ScreenPtr screen,
662		      XvAdaptorPtr *adaptors,
663		      int *num_adaptors)
664{
665	struct sna *sna = to_sna_from_screen(screen);
666
667	*num_adaptors = sna->xv.num_adaptors;
668	*adaptors = sna->xv.adaptors;
669	return Success;
670}
671
672static Bool
673sna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL)
674{
675	struct sna *sna = to_sna_from_screen(screen);
676	sna_video_close(sna);
677	return TRUE;
678}
679#endif
680
681void sna_video_init(struct sna *sna, ScreenPtr screen)
682{
683	XvScreenPtr xv;
684
685	if (noXvExtension)
686		return;
687
688	if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) {
689		XF86VideoAdaptorPtr *adaptors = NULL;
690		int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors);
691		if (num_adaptors)
692			xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
693				   "Ignoring generic xf86XV adaptors");
694		free(adaptors);
695	}
696
697	if (XvScreenInit(screen) != Success)
698		return;
699
700	xv = to_xv(screen);
701#if XORG_XV_VERSION < 2
702	xv->ddCloseScreen = sna_xv_close_screen;
703	xv->ddQueryAdaptors = sna_xv_query_adaptors;
704#endif
705
706	sna_video_textured_setup(sna, screen);
707	sna_video_sprite_setup(sna, screen);
708	sna_video_overlay_setup(sna, screen);
709
710	if (sna->xv.num_adaptors >= 2 &&
711	    xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) {
712		XvAdaptorRec tmp;
713
714		tmp = sna->xv.adaptors[0];
715		sna->xv.adaptors[0] = sna->xv.adaptors[1];
716		sna->xv.adaptors[1] = tmp;
717	}
718
719	xv->nAdaptors = sna->xv.num_adaptors;
720	xv->pAdaptors = sna->xv.adaptors;
721
722	sna_video_xvmc_setup(sna, screen);
723}
724
725void sna_video_destroy_window(WindowPtr win)
726{
727	XvPortPtr port;
728
729	port = sna_window_get_port(win);
730	if (port) {
731#if XORG_XV_VERSION < 2
732		port->pAdaptor->ddStopVideo(NULL, port, &win->drawable);
733#else
734		port->pAdaptor->ddStopVideo(port, &win->drawable);
735#endif
736	}
737	assert(sna_window_get_port(win) == NULL);
738}
739
740void sna_video_close(struct sna *sna)
741{
742	int i;
743
744	for (i = 0; i < sna->xv.num_adaptors; i++) {
745		free(sna->xv.adaptors[i].pPorts->devPriv.ptr);
746		free(sna->xv.adaptors[i].pPorts);
747		free(sna->xv.adaptors[i].pEncodings);
748	}
749	free(sna->xv.adaptors);
750
751	sna->xv.adaptors = NULL;
752	sna->xv.num_adaptors = 0;
753}
754