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