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