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