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