sna_video.c revision 03b705cf
103b705cfSriastradh/*************************************************************************** 203b705cfSriastradh 303b705cfSriastradh Copyright 2000 Intel Corporation. All Rights Reserved. 403b705cfSriastradh 503b705cfSriastradh Permission is hereby granted, free of charge, to any person obtaining a 603b705cfSriastradh copy of this software and associated documentation files (the 703b705cfSriastradh "Software"), to deal in the Software without restriction, including 803b705cfSriastradh without limitation the rights to use, copy, modify, merge, publish, 903b705cfSriastradh distribute, sub license, and/or sell copies of the Software, and to 1003b705cfSriastradh permit persons to whom the Software is furnished to do so, subject to 1103b705cfSriastradh the following conditions: 1203b705cfSriastradh 1303b705cfSriastradh The above copyright notice and this permission notice (including the 1403b705cfSriastradh next paragraph) shall be included in all copies or substantial portions 1503b705cfSriastradh of the Software. 1603b705cfSriastradh 1703b705cfSriastradh THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1803b705cfSriastradh OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1903b705cfSriastradh MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2003b705cfSriastradh IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2103b705cfSriastradh DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2203b705cfSriastradh OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 2303b705cfSriastradh THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2403b705cfSriastradh 2503b705cfSriastradh **************************************************************************/ 2603b705cfSriastradh 2703b705cfSriastradh/* 2803b705cfSriastradh * i830_video.c: i830/i845 Xv driver. 2903b705cfSriastradh * 3003b705cfSriastradh * Copyright © 2002 by Alan Hourihane and David Dawes 3103b705cfSriastradh * 3203b705cfSriastradh * Authors: 3303b705cfSriastradh * Alan Hourihane <alanh@tungstengraphics.com> 3403b705cfSriastradh * David Dawes <dawes@xfree86.org> 3503b705cfSriastradh * 3603b705cfSriastradh * Derived from i810 Xv driver: 3703b705cfSriastradh * 3803b705cfSriastradh * Authors of i810 code: 3903b705cfSriastradh * Jonathan Bian <jonathan.bian@intel.com> 4003b705cfSriastradh * Offscreen Images: 4103b705cfSriastradh * Matt Sottek <matthew.j.sottek@intel.com> 4203b705cfSriastradh */ 4303b705cfSriastradh 4403b705cfSriastradh#ifdef HAVE_CONFIG_H 4503b705cfSriastradh#include "config.h" 4603b705cfSriastradh#endif 4703b705cfSriastradh 4803b705cfSriastradh#include <inttypes.h> 4903b705cfSriastradh#include <math.h> 5003b705cfSriastradh#include <string.h> 5103b705cfSriastradh#include <assert.h> 5203b705cfSriastradh#include <errno.h> 5303b705cfSriastradh 5403b705cfSriastradh#include <sys/mman.h> 5503b705cfSriastradh 5603b705cfSriastradh#include "sna.h" 5703b705cfSriastradh#include "sna_reg.h" 5803b705cfSriastradh#include "sna_video.h" 5903b705cfSriastradh 6003b705cfSriastradh#include "intel_options.h" 6103b705cfSriastradh 6203b705cfSriastradh#include <xf86xv.h> 6303b705cfSriastradh#include <X11/extensions/Xv.h> 6403b705cfSriastradh 6503b705cfSriastradh#ifdef SNA_XVMC 6603b705cfSriastradh#define _SNA_XVMC_SERVER_ 6703b705cfSriastradh#include "sna_video_hwmc.h" 6803b705cfSriastradh#else 6903b705cfSriastradhstatic inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr) 7003b705cfSriastradh{ 7103b705cfSriastradh} 7203b705cfSriastradh#endif 7303b705cfSriastradh 7403b705cfSriastradhvoid sna_video_free_buffers(struct sna_video *video) 7503b705cfSriastradh{ 7603b705cfSriastradh unsigned int i; 7703b705cfSriastradh 7803b705cfSriastradh for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) { 7903b705cfSriastradh if (video->old_buf[i]) { 8003b705cfSriastradh kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]); 8103b705cfSriastradh video->old_buf[i] = NULL; 8203b705cfSriastradh } 8303b705cfSriastradh } 8403b705cfSriastradh 8503b705cfSriastradh if (video->buf) { 8603b705cfSriastradh kgem_bo_destroy(&video->sna->kgem, video->buf); 8703b705cfSriastradh video->buf = NULL; 8803b705cfSriastradh } 8903b705cfSriastradh} 9003b705cfSriastradh 9103b705cfSriastradhstruct kgem_bo * 9203b705cfSriastradhsna_video_buffer(struct sna_video *video, 9303b705cfSriastradh struct sna_video_frame *frame) 9403b705cfSriastradh{ 9503b705cfSriastradh /* Free the current buffer if we're going to have to reallocate */ 9603b705cfSriastradh if (video->buf && __kgem_bo_size(video->buf) < frame->size) 9703b705cfSriastradh sna_video_free_buffers(video); 9803b705cfSriastradh 9903b705cfSriastradh if (video->buf == NULL) { 10003b705cfSriastradh if (video->tiled) { 10103b705cfSriastradh video->buf = kgem_create_2d(&video->sna->kgem, 10203b705cfSriastradh frame->width, frame->height, 32, 10303b705cfSriastradh I915_TILING_X, CREATE_EXACT); 10403b705cfSriastradh } else { 10503b705cfSriastradh video->buf = kgem_create_linear(&video->sna->kgem, frame->size, 10603b705cfSriastradh CREATE_GTT_MAP); 10703b705cfSriastradh } 10803b705cfSriastradh } 10903b705cfSriastradh 11003b705cfSriastradh return video->buf; 11103b705cfSriastradh} 11203b705cfSriastradh 11303b705cfSriastradhvoid sna_video_buffer_fini(struct sna_video *video) 11403b705cfSriastradh{ 11503b705cfSriastradh struct kgem_bo *bo; 11603b705cfSriastradh 11703b705cfSriastradh bo = video->old_buf[1]; 11803b705cfSriastradh video->old_buf[1] = video->old_buf[0]; 11903b705cfSriastradh video->old_buf[0] = video->buf; 12003b705cfSriastradh video->buf = bo; 12103b705cfSriastradh} 12203b705cfSriastradh 12303b705cfSriastradhbool 12403b705cfSriastradhsna_video_clip_helper(ScrnInfoPtr scrn, 12503b705cfSriastradh struct sna_video *video, 12603b705cfSriastradh struct sna_video_frame *frame, 12703b705cfSriastradh xf86CrtcPtr * crtc_ret, 12803b705cfSriastradh BoxPtr dst, 12903b705cfSriastradh short src_x, short src_y, 13003b705cfSriastradh short drw_x, short drw_y, 13103b705cfSriastradh short src_w, short src_h, 13203b705cfSriastradh short drw_w, short drw_h, 13303b705cfSriastradh RegionPtr reg) 13403b705cfSriastradh{ 13503b705cfSriastradh bool ret; 13603b705cfSriastradh RegionRec crtc_region_local; 13703b705cfSriastradh RegionPtr crtc_region = reg; 13803b705cfSriastradh INT32 x1, x2, y1, y2; 13903b705cfSriastradh xf86CrtcPtr crtc; 14003b705cfSriastradh 14103b705cfSriastradh x1 = src_x; 14203b705cfSriastradh x2 = src_x + src_w; 14303b705cfSriastradh y1 = src_y; 14403b705cfSriastradh y2 = src_y + src_h; 14503b705cfSriastradh 14603b705cfSriastradh dst->x1 = drw_x; 14703b705cfSriastradh dst->x2 = drw_x + drw_w; 14803b705cfSriastradh dst->y1 = drw_y; 14903b705cfSriastradh dst->y2 = drw_y + drw_h; 15003b705cfSriastradh 15103b705cfSriastradh /* 15203b705cfSriastradh * For overlay video, compute the relevant CRTC and 15303b705cfSriastradh * clip video to that 15403b705cfSriastradh */ 15503b705cfSriastradh crtc = sna_covering_crtc(scrn, dst, video->desired_crtc); 15603b705cfSriastradh 15703b705cfSriastradh /* For textured video, we don't actually want to clip at all. */ 15803b705cfSriastradh if (crtc && !video->textured) { 15903b705cfSriastradh crtc_region_local.extents = crtc->bounds; 16003b705cfSriastradh crtc_region_local.data = NULL; 16103b705cfSriastradh crtc_region = &crtc_region_local; 16203b705cfSriastradh RegionIntersect(crtc_region, crtc_region, reg); 16303b705cfSriastradh } 16403b705cfSriastradh *crtc_ret = crtc; 16503b705cfSriastradh 16603b705cfSriastradh ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2, 16703b705cfSriastradh crtc_region, frame->width, frame->height); 16803b705cfSriastradh if (crtc_region != reg) 16903b705cfSriastradh RegionUninit(crtc_region); 17003b705cfSriastradh 17103b705cfSriastradh frame->src.x1 = x1 >> 16; 17203b705cfSriastradh frame->src.y1 = y1 >> 16; 17303b705cfSriastradh frame->src.x2 = (x2 + 0xffff) >> 16; 17403b705cfSriastradh frame->src.y2 = (y2 + 0xffff) >> 16; 17503b705cfSriastradh 17603b705cfSriastradh frame->image.x1 = frame->src.x1 & ~1; 17703b705cfSriastradh frame->image.x2 = ALIGN(frame->src.x2, 2); 17803b705cfSriastradh if (is_planar_fourcc(frame->id)) { 17903b705cfSriastradh frame->image.y1 = frame->src.y1 & ~1; 18003b705cfSriastradh frame->image.y2 = ALIGN(frame->src.y2, 2); 18103b705cfSriastradh } else { 18203b705cfSriastradh frame->image.y1 = frame->src.y1; 18303b705cfSriastradh frame->image.y2 = frame->src.y2; 18403b705cfSriastradh } 18503b705cfSriastradh 18603b705cfSriastradh return ret; 18703b705cfSriastradh} 18803b705cfSriastradh 18903b705cfSriastradhvoid 19003b705cfSriastradhsna_video_frame_init(struct sna_video *video, 19103b705cfSriastradh int id, short width, short height, 19203b705cfSriastradh struct sna_video_frame *frame) 19303b705cfSriastradh{ 19403b705cfSriastradh int align; 19503b705cfSriastradh 19603b705cfSriastradh DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n", 19703b705cfSriastradh __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment)); 19803b705cfSriastradh assert(width && height); 19903b705cfSriastradh 20003b705cfSriastradh frame->bo = NULL; 20103b705cfSriastradh frame->id = id; 20203b705cfSriastradh frame->width = width; 20303b705cfSriastradh frame->height = height; 20403b705cfSriastradh 20503b705cfSriastradh align = video->alignment; 20603b705cfSriastradh#if SNA_XVMC 20703b705cfSriastradh /* for i915 xvmc, hw requires 1kb aligned surfaces */ 20803b705cfSriastradh if (id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024) 20903b705cfSriastradh align = 1024; 21003b705cfSriastradh#endif 21103b705cfSriastradh 21203b705cfSriastradh /* Determine the desired destination pitch (representing the 21303b705cfSriastradh * chroma's pitch in the planar case). 21403b705cfSriastradh */ 21503b705cfSriastradh if (is_planar_fourcc(id)) { 21603b705cfSriastradh assert((width & 1) == 0); 21703b705cfSriastradh assert((height & 1) == 0); 21803b705cfSriastradh if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 21903b705cfSriastradh frame->pitch[0] = ALIGN((height / 2), align); 22003b705cfSriastradh frame->pitch[1] = ALIGN(height, align); 22103b705cfSriastradh frame->size = width; 22203b705cfSriastradh } else { 22303b705cfSriastradh frame->pitch[0] = ALIGN((width / 2), align); 22403b705cfSriastradh frame->pitch[1] = ALIGN(width, align); 22503b705cfSriastradh frame->size = height; 22603b705cfSriastradh } 22703b705cfSriastradh frame->size *= frame->pitch[0] + frame->pitch[1]; 22803b705cfSriastradh 22903b705cfSriastradh if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 23003b705cfSriastradh frame->UBufOffset = (int)frame->pitch[1] * width; 23103b705cfSriastradh frame->VBufOffset = 23203b705cfSriastradh frame->UBufOffset + (int)frame->pitch[0] * width / 2; 23303b705cfSriastradh } else { 23403b705cfSriastradh frame->UBufOffset = (int)frame->pitch[1] * height; 23503b705cfSriastradh frame->VBufOffset = 23603b705cfSriastradh frame->UBufOffset + (int)frame->pitch[0] * height / 2; 23703b705cfSriastradh } 23803b705cfSriastradh } else { 23903b705cfSriastradh switch (frame->id) { 24003b705cfSriastradh case FOURCC_RGB888: 24103b705cfSriastradh if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 24203b705cfSriastradh frame->pitch[0] = ALIGN((height << 2), align); 24303b705cfSriastradh frame->size = (int)frame->pitch[0] * width; 24403b705cfSriastradh } else { 24503b705cfSriastradh frame->pitch[0] = ALIGN((width << 2), align); 24603b705cfSriastradh frame->size = (int)frame->pitch[0] * height; 24703b705cfSriastradh } 24803b705cfSriastradh frame->UBufOffset = frame->VBufOffset = 0; 24903b705cfSriastradh break; 25003b705cfSriastradh case FOURCC_RGB565: 25103b705cfSriastradh if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 25203b705cfSriastradh frame->pitch[0] = ALIGN((height << 1), align); 25303b705cfSriastradh frame->size = (int)frame->pitch[0] * width; 25403b705cfSriastradh } else { 25503b705cfSriastradh frame->pitch[0] = ALIGN((width << 1), align); 25603b705cfSriastradh frame->size = (int)frame->pitch[0] * height; 25703b705cfSriastradh } 25803b705cfSriastradh frame->UBufOffset = frame->VBufOffset = 0; 25903b705cfSriastradh break; 26003b705cfSriastradh 26103b705cfSriastradh default: 26203b705cfSriastradh if (video->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 26303b705cfSriastradh frame->pitch[0] = ALIGN((height << 1), align); 26403b705cfSriastradh frame->size = (int)frame->pitch[0] * width; 26503b705cfSriastradh } else { 26603b705cfSriastradh frame->pitch[0] = ALIGN((width << 1), align); 26703b705cfSriastradh frame->size = (int)frame->pitch[0] * height; 26803b705cfSriastradh } 26903b705cfSriastradh break; 27003b705cfSriastradh } 27103b705cfSriastradh frame->pitch[1] = 0; 27203b705cfSriastradh frame->UBufOffset = 0; 27303b705cfSriastradh frame->VBufOffset = 0; 27403b705cfSriastradh } 27503b705cfSriastradh 27603b705cfSriastradh assert(frame->size); 27703b705cfSriastradh} 27803b705cfSriastradh 27903b705cfSriastradhstatic void sna_memcpy_plane(struct sna_video *video, 28003b705cfSriastradh uint8_t *dst, const uint8_t *src, 28103b705cfSriastradh const struct sna_video_frame *frame, int sub) 28203b705cfSriastradh{ 28303b705cfSriastradh int dstPitch = frame->pitch[!sub], srcPitch; 28403b705cfSriastradh const uint8_t *s; 28503b705cfSriastradh int i, j = 0; 28603b705cfSriastradh int x, y, w, h; 28703b705cfSriastradh 28803b705cfSriastradh x = frame->image.x1; 28903b705cfSriastradh y = frame->image.y1; 29003b705cfSriastradh w = frame->image.x2 - frame->image.x1; 29103b705cfSriastradh h = frame->image.y2 - frame->image.y1; 29203b705cfSriastradh if (sub) { 29303b705cfSriastradh x >>= 1; w >>= 1; 29403b705cfSriastradh y >>= 1; h >>= 1; 29503b705cfSriastradh srcPitch = ALIGN((frame->width >> 1), 4); 29603b705cfSriastradh } else 29703b705cfSriastradh srcPitch = ALIGN(frame->width, 4); 29803b705cfSriastradh 29903b705cfSriastradh src += y * srcPitch + x; 30003b705cfSriastradh if (!video->textured) 30103b705cfSriastradh x = y = 0; 30203b705cfSriastradh 30303b705cfSriastradh switch (video->rotation) { 30403b705cfSriastradh case RR_Rotate_0: 30503b705cfSriastradh dst += y * dstPitch + x; 30603b705cfSriastradh if (srcPitch == dstPitch && srcPitch == w) 30703b705cfSriastradh memcpy(dst, src, srcPitch * h); 30803b705cfSriastradh else while (h--) { 30903b705cfSriastradh memcpy(dst, src, w); 31003b705cfSriastradh src += srcPitch; 31103b705cfSriastradh dst += dstPitch; 31203b705cfSriastradh } 31303b705cfSriastradh break; 31403b705cfSriastradh case RR_Rotate_90: 31503b705cfSriastradh for (i = 0; i < h; i++) { 31603b705cfSriastradh s = src; 31703b705cfSriastradh for (j = 0; j < w; j++) 31803b705cfSriastradh dst[i + ((x + w - j - 1) * dstPitch)] = *s++; 31903b705cfSriastradh src += srcPitch; 32003b705cfSriastradh } 32103b705cfSriastradh break; 32203b705cfSriastradh case RR_Rotate_180: 32303b705cfSriastradh for (i = 0; i < h; i++) { 32403b705cfSriastradh s = src; 32503b705cfSriastradh for (j = 0; j < w; j++) { 32603b705cfSriastradh dst[(x + w - j - 1) + 32703b705cfSriastradh ((h - i - 1) * dstPitch)] = *s++; 32803b705cfSriastradh } 32903b705cfSriastradh src += srcPitch; 33003b705cfSriastradh } 33103b705cfSriastradh break; 33203b705cfSriastradh case RR_Rotate_270: 33303b705cfSriastradh for (i = 0; i < h; i++) { 33403b705cfSriastradh s = src; 33503b705cfSriastradh for (j = 0; j < w; j++) { 33603b705cfSriastradh dst[(h - i - 1) + (x + j * dstPitch)] = *s++; 33703b705cfSriastradh } 33803b705cfSriastradh src += srcPitch; 33903b705cfSriastradh } 34003b705cfSriastradh break; 34103b705cfSriastradh } 34203b705cfSriastradh} 34303b705cfSriastradh 34403b705cfSriastradhstatic void 34503b705cfSriastradhsna_copy_planar_data(struct sna_video *video, 34603b705cfSriastradh const struct sna_video_frame *frame, 34703b705cfSriastradh const uint8_t *src, uint8_t *dst) 34803b705cfSriastradh{ 34903b705cfSriastradh uint8_t *d; 35003b705cfSriastradh 35103b705cfSriastradh sna_memcpy_plane(video, dst, src, frame, 0); 35203b705cfSriastradh src += frame->height * ALIGN(frame->width, 4); 35303b705cfSriastradh 35403b705cfSriastradh if (frame->id == FOURCC_I420) 35503b705cfSriastradh d = dst + frame->UBufOffset; 35603b705cfSriastradh else 35703b705cfSriastradh d = dst + frame->VBufOffset; 35803b705cfSriastradh sna_memcpy_plane(video, d, src, frame, 1); 35903b705cfSriastradh src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4); 36003b705cfSriastradh 36103b705cfSriastradh if (frame->id == FOURCC_I420) 36203b705cfSriastradh d = dst + frame->VBufOffset; 36303b705cfSriastradh else 36403b705cfSriastradh d = dst + frame->UBufOffset; 36503b705cfSriastradh sna_memcpy_plane(video, d, src, frame, 1); 36603b705cfSriastradh} 36703b705cfSriastradh 36803b705cfSriastradhstatic void 36903b705cfSriastradhsna_copy_packed_data(struct sna_video *video, 37003b705cfSriastradh const struct sna_video_frame *frame, 37103b705cfSriastradh const uint8_t *buf, 37203b705cfSriastradh uint8_t *dst) 37303b705cfSriastradh{ 37403b705cfSriastradh int pitch = frame->width << 1; 37503b705cfSriastradh const uint8_t *src, *s; 37603b705cfSriastradh int x, y, w, h; 37703b705cfSriastradh int i, j; 37803b705cfSriastradh 37903b705cfSriastradh if (video->textured) { 38003b705cfSriastradh /* XXX support copying cropped extents */ 38103b705cfSriastradh x = y = 0; 38203b705cfSriastradh w = frame->width; 38303b705cfSriastradh h = frame->height; 38403b705cfSriastradh } else { 38503b705cfSriastradh x = frame->image.x1; 38603b705cfSriastradh y = frame->image.y1; 38703b705cfSriastradh w = frame->image.x2 - frame->image.x1; 38803b705cfSriastradh h = frame->image.y2 - frame->image.y1; 38903b705cfSriastradh } 39003b705cfSriastradh 39103b705cfSriastradh src = buf + (y * pitch) + (x << 1); 39203b705cfSriastradh 39303b705cfSriastradh switch (video->rotation) { 39403b705cfSriastradh case RR_Rotate_0: 39503b705cfSriastradh w <<= 1; 39603b705cfSriastradh for (i = 0; i < h; i++) { 39703b705cfSriastradh memcpy(dst, src, w); 39803b705cfSriastradh src += pitch; 39903b705cfSriastradh dst += frame->pitch[0]; 40003b705cfSriastradh } 40103b705cfSriastradh break; 40203b705cfSriastradh case RR_Rotate_90: 40303b705cfSriastradh h <<= 1; 40403b705cfSriastradh for (i = 0; i < h; i += 2) { 40503b705cfSriastradh s = src; 40603b705cfSriastradh for (j = 0; j < w; j++) { 40703b705cfSriastradh /* Copy Y */ 40803b705cfSriastradh dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s; 40903b705cfSriastradh s += 2; 41003b705cfSriastradh } 41103b705cfSriastradh src += pitch; 41203b705cfSriastradh } 41303b705cfSriastradh h >>= 1; 41403b705cfSriastradh src = buf + (y * pitch) + (x << 1); 41503b705cfSriastradh for (i = 0; i < h; i += 2) { 41603b705cfSriastradh for (j = 0; j < w; j += 2) { 41703b705cfSriastradh /* Copy U */ 41803b705cfSriastradh dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 41903b705cfSriastradh dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 42003b705cfSriastradh /* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 42103b705cfSriastradh dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 42203b705cfSriastradh } 42303b705cfSriastradh } 42403b705cfSriastradh break; 42503b705cfSriastradh case RR_Rotate_180: 42603b705cfSriastradh w <<= 1; 42703b705cfSriastradh for (i = 0; i < h; i++) { 42803b705cfSriastradh s = src; 42903b705cfSriastradh for (j = 0; j < w; j += 4) { 43003b705cfSriastradh dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++; 43103b705cfSriastradh dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++; 43203b705cfSriastradh dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++; 43303b705cfSriastradh dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++; 43403b705cfSriastradh } 43503b705cfSriastradh src += pitch; 43603b705cfSriastradh } 43703b705cfSriastradh break; 43803b705cfSriastradh case RR_Rotate_270: 43903b705cfSriastradh h <<= 1; 44003b705cfSriastradh for (i = 0; i < h; i += 2) { 44103b705cfSriastradh s = src; 44203b705cfSriastradh for (j = 0; j < w; j++) { 44303b705cfSriastradh /* Copy Y */ 44403b705cfSriastradh dst[(h - i - 2) + (j * frame->pitch[0])] = *s; 44503b705cfSriastradh s += 2; 44603b705cfSriastradh } 44703b705cfSriastradh src += pitch; 44803b705cfSriastradh } 44903b705cfSriastradh h >>= 1; 45003b705cfSriastradh src = buf + (y * pitch) + (x << 1); 45103b705cfSriastradh for (i = 0; i < h; i += 2) { 45203b705cfSriastradh for (j = 0; j < w; j += 2) { 45303b705cfSriastradh /* Copy U */ 45403b705cfSriastradh dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 45503b705cfSriastradh dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 45603b705cfSriastradh /* Copy V */ 45703b705cfSriastradh dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 45803b705cfSriastradh dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 45903b705cfSriastradh } 46003b705cfSriastradh } 46103b705cfSriastradh break; 46203b705cfSriastradh } 46303b705cfSriastradh} 46403b705cfSriastradh 46503b705cfSriastradhbool 46603b705cfSriastradhsna_video_copy_data(struct sna_video *video, 46703b705cfSriastradh struct sna_video_frame *frame, 46803b705cfSriastradh const uint8_t *buf) 46903b705cfSriastradh{ 47003b705cfSriastradh uint8_t *dst; 47103b705cfSriastradh 47203b705cfSriastradh DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n", 47303b705cfSriastradh __FUNCTION__, frame->bo ? frame->bo->handle : 0, 47403b705cfSriastradh frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1], 47503b705cfSriastradh video->rotation, video->textured)); 47603b705cfSriastradh DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n", 47703b705cfSriastradh __FUNCTION__, 47803b705cfSriastradh frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2, 47903b705cfSriastradh frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2)); 48003b705cfSriastradh assert(frame->width && frame->height); 48103b705cfSriastradh assert(frame->size); 48203b705cfSriastradh 48303b705cfSriastradh /* In the common case, we can simply the upload in a single pwrite */ 48403b705cfSriastradh if (video->rotation == RR_Rotate_0 && !video->tiled) { 48503b705cfSriastradh DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n", 48603b705cfSriastradh __FUNCTION__, is_planar_fourcc(frame->id))); 48703b705cfSriastradh if (is_planar_fourcc(frame->id)) { 48803b705cfSriastradh int w = frame->image.x2 - frame->image.x1; 48903b705cfSriastradh int h = frame->image.y2 - frame->image.y1; 49003b705cfSriastradh if (ALIGN(h, 2) == frame->height && 49103b705cfSriastradh ALIGN(w >> 1, 4) == frame->pitch[0] && 49203b705cfSriastradh ALIGN(w, 4) == frame->pitch[1]) { 49303b705cfSriastradh if (frame->bo) { 49403b705cfSriastradh kgem_bo_write(&video->sna->kgem, frame->bo, 49503b705cfSriastradh buf, frame->size); 49603b705cfSriastradh } else { 49703b705cfSriastradh frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 49803b705cfSriastradh KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 49903b705cfSriastradh (void **)&dst); 50003b705cfSriastradh if (frame->bo == NULL) 50103b705cfSriastradh return false; 50203b705cfSriastradh 50303b705cfSriastradh memcpy(dst, buf, frame->size); 50403b705cfSriastradh } 50503b705cfSriastradh if (frame->id != FOURCC_I420) { 50603b705cfSriastradh uint32_t tmp; 50703b705cfSriastradh tmp = frame->VBufOffset; 50803b705cfSriastradh frame->VBufOffset = frame->UBufOffset; 50903b705cfSriastradh frame->UBufOffset = tmp; 51003b705cfSriastradh } 51103b705cfSriastradh return true; 51203b705cfSriastradh } 51303b705cfSriastradh } else { 51403b705cfSriastradh if (frame->width*2 == frame->pitch[0]) { 51503b705cfSriastradh if (frame->bo) { 51603b705cfSriastradh kgem_bo_write(&video->sna->kgem, frame->bo, 51703b705cfSriastradh buf + (2U*frame->image.y1 * frame->width) + (frame->image.x1 << 1), 51803b705cfSriastradh 2U*(frame->image.y2-frame->image.y1)*frame->width); 51903b705cfSriastradh } else { 52003b705cfSriastradh frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 52103b705cfSriastradh KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 52203b705cfSriastradh (void **)&dst); 52303b705cfSriastradh if (frame->bo == NULL) 52403b705cfSriastradh return false; 52503b705cfSriastradh 52603b705cfSriastradh memcpy(dst, 52703b705cfSriastradh buf + (frame->image.y1 * frame->width*2) + (frame->image.x1 << 1), 52803b705cfSriastradh 2U*(frame->image.y2-frame->image.y1)*frame->width); 52903b705cfSriastradh } 53003b705cfSriastradh return true; 53103b705cfSriastradh } 53203b705cfSriastradh } 53303b705cfSriastradh 53403b705cfSriastradh DBG(("%s: source cropped, fallback\n", __FUNCTION__)); 53503b705cfSriastradh } 53603b705cfSriastradh 53703b705cfSriastradh /* copy data, must use GTT so that we keep the overlay uncached */ 53803b705cfSriastradh if (frame->bo) { 53903b705cfSriastradh dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo); 54003b705cfSriastradh if (dst == NULL) 54103b705cfSriastradh return false; 54203b705cfSriastradh } else { 54303b705cfSriastradh frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 54403b705cfSriastradh KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 54503b705cfSriastradh (void **)&dst); 54603b705cfSriastradh if (frame->bo == NULL) 54703b705cfSriastradh return false; 54803b705cfSriastradh } 54903b705cfSriastradh 55003b705cfSriastradh if (is_planar_fourcc(frame->id)) 55103b705cfSriastradh sna_copy_planar_data(video, frame, buf, dst); 55203b705cfSriastradh else 55303b705cfSriastradh sna_copy_packed_data(video, frame, buf, dst); 55403b705cfSriastradh 55503b705cfSriastradh return true; 55603b705cfSriastradh} 55703b705cfSriastradh 55803b705cfSriastradhXvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna) 55903b705cfSriastradh{ 56003b705cfSriastradh XvAdaptorPtr new_adaptors; 56103b705cfSriastradh 56203b705cfSriastradh new_adaptors = realloc(sna->xv.adaptors, 56303b705cfSriastradh (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec)); 56403b705cfSriastradh if (new_adaptors == NULL) 56503b705cfSriastradh return NULL; 56603b705cfSriastradh 56703b705cfSriastradh if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) { 56803b705cfSriastradh XvAdaptorPtr adaptor = new_adaptors; 56903b705cfSriastradh int i = sna->xv.num_adaptors, j; 57003b705cfSriastradh while (i--) { 57103b705cfSriastradh for (j = 0; j < adaptor->nPorts; j++) 57203b705cfSriastradh adaptor->pPorts[j].pAdaptor = adaptor; 57303b705cfSriastradh adaptor++; 57403b705cfSriastradh } 57503b705cfSriastradh } 57603b705cfSriastradh 57703b705cfSriastradh sna->xv.adaptors = new_adaptors; 57803b705cfSriastradh return &sna->xv.adaptors[sna->xv.num_adaptors++]; 57903b705cfSriastradh} 58003b705cfSriastradh 58103b705cfSriastradhint 58203b705cfSriastradhsna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out) 58303b705cfSriastradh{ 58403b705cfSriastradh *out = in; 58503b705cfSriastradh return Success; 58603b705cfSriastradh} 58703b705cfSriastradh 58803b705cfSriastradhint 58903b705cfSriastradhsna_xv_free_port(XvPortPtr port) 59003b705cfSriastradh{ 59103b705cfSriastradh return Success; 59203b705cfSriastradh} 59303b705cfSriastradh 59403b705cfSriastradhint 59503b705cfSriastradhsna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats) 59603b705cfSriastradh{ 59703b705cfSriastradh XvFormatPtr out = formats; 59803b705cfSriastradh int count = 0; 59903b705cfSriastradh 60003b705cfSriastradh while (num_formats--) { 60103b705cfSriastradh int num_visuals = screen->numVisuals; 60203b705cfSriastradh VisualPtr v = screen->visuals; 60303b705cfSriastradh 60403b705cfSriastradh while (num_visuals--) { 60503b705cfSriastradh if (v->class == TrueColor && 60603b705cfSriastradh v->nplanes == formats->depth) { 60703b705cfSriastradh int tmp = out[count].depth; 60803b705cfSriastradh out[count].depth = formats->depth; 60903b705cfSriastradh out[count].visual = v->vid; 61003b705cfSriastradh formats->depth = tmp; 61103b705cfSriastradh count++; 61203b705cfSriastradh break; 61303b705cfSriastradh } 61403b705cfSriastradh v++; 61503b705cfSriastradh } 61603b705cfSriastradh 61703b705cfSriastradh formats++; 61803b705cfSriastradh } 61903b705cfSriastradh 62003b705cfSriastradh return count; 62103b705cfSriastradh} 62203b705cfSriastradh 62303b705cfSriastradhstatic int 62403b705cfSriastradhsna_xv_query_adaptors(ScreenPtr screen, 62503b705cfSriastradh XvAdaptorPtr *adaptors, 62603b705cfSriastradh int *num_adaptors) 62703b705cfSriastradh{ 62803b705cfSriastradh struct sna *sna = to_sna_from_screen(screen); 62903b705cfSriastradh 63003b705cfSriastradh *num_adaptors = sna->xv.num_adaptors; 63103b705cfSriastradh *adaptors = sna->xv.adaptors; 63203b705cfSriastradh return Success; 63303b705cfSriastradh} 63403b705cfSriastradh 63503b705cfSriastradhstatic Bool 63603b705cfSriastradhsna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL) 63703b705cfSriastradh{ 63803b705cfSriastradh struct sna *sna = to_sna_from_screen(screen); 63903b705cfSriastradh int i; 64003b705cfSriastradh 64103b705cfSriastradh for (i = 0; i < sna->xv.num_adaptors; i++) { 64203b705cfSriastradh free(sna->xv.adaptors[i].pPorts->devPriv.ptr); 64303b705cfSriastradh free(sna->xv.adaptors[i].pPorts); 64403b705cfSriastradh free(sna->xv.adaptors[i].pEncodings); 64503b705cfSriastradh } 64603b705cfSriastradh free(sna->xv.adaptors); 64703b705cfSriastradh 64803b705cfSriastradh sna->xv.adaptors = NULL; 64903b705cfSriastradh sna->xv.num_adaptors = 0; 65003b705cfSriastradh 65103b705cfSriastradh return TRUE; 65203b705cfSriastradh} 65303b705cfSriastradh 65403b705cfSriastradhvoid sna_video_init(struct sna *sna, ScreenPtr screen) 65503b705cfSriastradh{ 65603b705cfSriastradh XvScreenPtr xv; 65703b705cfSriastradh 65803b705cfSriastradh if (noXvExtension) 65903b705cfSriastradh return; 66003b705cfSriastradh 66103b705cfSriastradh if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) { 66203b705cfSriastradh XF86VideoAdaptorPtr *adaptors = NULL; 66303b705cfSriastradh int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors); 66403b705cfSriastradh if (num_adaptors) 66503b705cfSriastradh xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 66603b705cfSriastradh "Ignoring generic xf86XV adaptors"); 66703b705cfSriastradh free(adaptors); 66803b705cfSriastradh } 66903b705cfSriastradh 67003b705cfSriastradh if (XvScreenInit(screen) != Success) 67103b705cfSriastradh return; 67203b705cfSriastradh 67303b705cfSriastradh xv = to_xv(screen); 67403b705cfSriastradh xv->ddCloseScreen = sna_xv_close_screen; 67503b705cfSriastradh xv->ddQueryAdaptors = sna_xv_query_adaptors; 67603b705cfSriastradh 67703b705cfSriastradh sna_video_textured_setup(sna, screen); 67803b705cfSriastradh sna_video_sprite_setup(sna, screen); 67903b705cfSriastradh sna_video_overlay_setup(sna, screen); 68003b705cfSriastradh 68103b705cfSriastradh if (sna->xv.num_adaptors >= 2 && 68203b705cfSriastradh xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) { 68303b705cfSriastradh XvAdaptorRec tmp; 68403b705cfSriastradh 68503b705cfSriastradh tmp = sna->xv.adaptors[0]; 68603b705cfSriastradh sna->xv.adaptors[0] = sna->xv.adaptors[1]; 68703b705cfSriastradh sna->xv.adaptors[1] = tmp; 68803b705cfSriastradh } 68903b705cfSriastradh 69003b705cfSriastradh xv->nAdaptors = sna->xv.num_adaptors; 69103b705cfSriastradh xv->pAdaptors = sna->xv.adaptors; 69203b705cfSriastradh 69303b705cfSriastradh sna_video_xvmc_setup(sna, screen); 69403b705cfSriastradh} 69503b705cfSriastradh 69603b705cfSriastradhvoid sna_video_destroy_window(WindowPtr win) 69703b705cfSriastradh{ 69803b705cfSriastradh XvPortPtr port; 69903b705cfSriastradh 70003b705cfSriastradh port = sna_window_get_port(win); 70103b705cfSriastradh if (port) 70203b705cfSriastradh port->pAdaptor->ddStopVideo(NULL, port, &win->drawable); 70303b705cfSriastradh assert(sna_window_get_port(win) == NULL); 70403b705cfSriastradh} 705