1428d7b3dSmrg/*************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrg Copyright 2000 Intel Corporation. All Rights Reserved. 4428d7b3dSmrg 5428d7b3dSmrg Permission is hereby granted, free of charge, to any person obtaining a 6428d7b3dSmrg copy of this software and associated documentation files (the 7428d7b3dSmrg "Software"), to deal in the Software without restriction, including 8428d7b3dSmrg without limitation the rights to use, copy, modify, merge, publish, 9428d7b3dSmrg distribute, sub license, and/or sell copies of the Software, and to 10428d7b3dSmrg permit persons to whom the Software is furnished to do so, subject to 11428d7b3dSmrg the following conditions: 12428d7b3dSmrg 13428d7b3dSmrg The above copyright notice and this permission notice (including the 14428d7b3dSmrg next paragraph) shall be included in all copies or substantial portions 15428d7b3dSmrg of the Software. 16428d7b3dSmrg 17428d7b3dSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18428d7b3dSmrg OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19428d7b3dSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20428d7b3dSmrg IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 21428d7b3dSmrg DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 22428d7b3dSmrg OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 23428d7b3dSmrg THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24428d7b3dSmrg 25428d7b3dSmrg **************************************************************************/ 26428d7b3dSmrg 27428d7b3dSmrg/* 28428d7b3dSmrg * i830_video.c: i830/i845 Xv driver. 29428d7b3dSmrg * 30428d7b3dSmrg * Copyright © 2002 by Alan Hourihane and David Dawes 31428d7b3dSmrg * 32428d7b3dSmrg * Authors: 33428d7b3dSmrg * Alan Hourihane <alanh@tungstengraphics.com> 34428d7b3dSmrg * David Dawes <dawes@xfree86.org> 35428d7b3dSmrg * 36428d7b3dSmrg * Derived from i810 Xv driver: 37428d7b3dSmrg * 38428d7b3dSmrg * Authors of i810 code: 39428d7b3dSmrg * Jonathan Bian <jonathan.bian@intel.com> 40428d7b3dSmrg * Offscreen Images: 41428d7b3dSmrg * Matt Sottek <matthew.j.sottek@intel.com> 42428d7b3dSmrg */ 43428d7b3dSmrg 44428d7b3dSmrg#ifdef HAVE_CONFIG_H 45428d7b3dSmrg#include "config.h" 46428d7b3dSmrg#endif 47428d7b3dSmrg 48428d7b3dSmrg#include <inttypes.h> 49428d7b3dSmrg#include <math.h> 50428d7b3dSmrg#include <string.h> 51428d7b3dSmrg#include <errno.h> 52428d7b3dSmrg 53428d7b3dSmrg#include <sys/mman.h> 54428d7b3dSmrg 55428d7b3dSmrg#include "sna.h" 56428d7b3dSmrg#include "sna_reg.h" 57428d7b3dSmrg#include "sna_video.h" 58428d7b3dSmrg 59428d7b3dSmrg#include "intel_options.h" 60428d7b3dSmrg 61428d7b3dSmrg#include <xf86xv.h> 62428d7b3dSmrg 63428d7b3dSmrg#ifdef SNA_XVMC 64428d7b3dSmrg#define _SNA_XVMC_SERVER_ 65428d7b3dSmrg#include "sna_video_hwmc.h" 66428d7b3dSmrg#else 67428d7b3dSmrgstatic inline void sna_video_xvmc_setup(struct sna *sna, ScreenPtr ptr) 68428d7b3dSmrg{ 69428d7b3dSmrg DBG(("%s: XvMC not compiled in\n", __FUNCTION__)); 70428d7b3dSmrg} 71428d7b3dSmrg#endif 72428d7b3dSmrg 73428d7b3dSmrgvoid sna_video_free_buffers(struct sna_video *video) 74428d7b3dSmrg{ 75428d7b3dSmrg unsigned int i; 76428d7b3dSmrg 77428d7b3dSmrg for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) { 78428d7b3dSmrg if (video->old_buf[i]) { 79428d7b3dSmrg kgem_bo_destroy(&video->sna->kgem, video->old_buf[i]); 80428d7b3dSmrg video->old_buf[i] = NULL; 81428d7b3dSmrg } 82428d7b3dSmrg } 83428d7b3dSmrg 84428d7b3dSmrg if (video->buf) { 85428d7b3dSmrg kgem_bo_destroy(&video->sna->kgem, video->buf); 86428d7b3dSmrg video->buf = NULL; 87428d7b3dSmrg } 88428d7b3dSmrg} 89428d7b3dSmrg 90428d7b3dSmrgstruct kgem_bo * 91428d7b3dSmrgsna_video_buffer(struct sna_video *video, 92428d7b3dSmrg struct sna_video_frame *frame) 93428d7b3dSmrg{ 94428d7b3dSmrg /* Free the current buffer if we're going to have to reallocate */ 95428d7b3dSmrg if (video->buf && __kgem_bo_size(video->buf) < frame->size) 96428d7b3dSmrg sna_video_free_buffers(video); 97428d7b3dSmrg 98428d7b3dSmrg if (video->buf && video->buf->scanout) { 99428d7b3dSmrg if (frame->width != video->width || 100428d7b3dSmrg frame->height != video->height || 101428d7b3dSmrg frame->id != video->format) 102428d7b3dSmrg sna_video_free_buffers(video); 103428d7b3dSmrg } 104428d7b3dSmrg 105428d7b3dSmrg if (video->buf == NULL) { 106428d7b3dSmrg if (video->tiled) { 107428d7b3dSmrg video->buf = kgem_create_2d(&video->sna->kgem, 108428d7b3dSmrg frame->width, frame->height, 32, 109428d7b3dSmrg I915_TILING_X, CREATE_EXACT); 110428d7b3dSmrg } else { 111428d7b3dSmrg video->buf = kgem_create_linear(&video->sna->kgem, frame->size, 112428d7b3dSmrg CREATE_GTT_MAP); 113428d7b3dSmrg } 114428d7b3dSmrg } 115428d7b3dSmrg 116428d7b3dSmrg video->width = frame->width; 117428d7b3dSmrg video->height = frame->height; 118428d7b3dSmrg video->format = frame->id; 119428d7b3dSmrg 120428d7b3dSmrg return video->buf; 121428d7b3dSmrg} 122428d7b3dSmrg 123428d7b3dSmrgvoid sna_video_buffer_fini(struct sna_video *video) 124428d7b3dSmrg{ 125428d7b3dSmrg struct kgem_bo *bo; 126428d7b3dSmrg 127428d7b3dSmrg bo = video->old_buf[1]; 128428d7b3dSmrg video->old_buf[1] = video->old_buf[0]; 129428d7b3dSmrg video->old_buf[0] = video->buf; 130428d7b3dSmrg video->buf = bo; 131428d7b3dSmrg} 132428d7b3dSmrg 133428d7b3dSmrgbool 134428d7b3dSmrgsna_video_clip_helper(struct sna_video *video, 135428d7b3dSmrg struct sna_video_frame *frame, 136428d7b3dSmrg xf86CrtcPtr *crtc_ret, 137428d7b3dSmrg BoxPtr dst, 138428d7b3dSmrg short src_x, short src_y, 139428d7b3dSmrg short drw_x, short drw_y, 140428d7b3dSmrg short src_w, short src_h, 141428d7b3dSmrg short drw_w, short drw_h, 142428d7b3dSmrg RegionPtr reg) 143428d7b3dSmrg{ 144428d7b3dSmrg bool ret; 145428d7b3dSmrg RegionRec crtc_region_local; 146428d7b3dSmrg RegionPtr crtc_region = reg; 147428d7b3dSmrg INT32 x1, x2, y1, y2; 148428d7b3dSmrg xf86CrtcPtr crtc; 149428d7b3dSmrg 150428d7b3dSmrg x1 = src_x; 151428d7b3dSmrg x2 = src_x + src_w; 152428d7b3dSmrg y1 = src_y; 153428d7b3dSmrg y2 = src_y + src_h; 154428d7b3dSmrg 155428d7b3dSmrg dst->x1 = drw_x; 156428d7b3dSmrg dst->x2 = drw_x + drw_w; 157428d7b3dSmrg dst->y1 = drw_y; 158428d7b3dSmrg dst->y2 = drw_y + drw_h; 159428d7b3dSmrg 160428d7b3dSmrg /* 161428d7b3dSmrg * For overlay video, compute the relevant CRTC and 162428d7b3dSmrg * clip video to that 163428d7b3dSmrg */ 164428d7b3dSmrg crtc = sna_covering_crtc(video->sna, dst, video->desired_crtc); 165428d7b3dSmrg 166428d7b3dSmrg /* For textured video, we don't actually want to clip at all. */ 167428d7b3dSmrg if (crtc && !video->textured) { 168428d7b3dSmrg crtc_region_local.extents = crtc->bounds; 169428d7b3dSmrg crtc_region_local.data = NULL; 170428d7b3dSmrg crtc_region = &crtc_region_local; 171428d7b3dSmrg RegionIntersect(crtc_region, crtc_region, reg); 172428d7b3dSmrg } 173428d7b3dSmrg *crtc_ret = crtc; 174428d7b3dSmrg 175428d7b3dSmrg ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2, 176428d7b3dSmrg crtc_region, frame->width, frame->height); 177428d7b3dSmrg if (crtc_region != reg) 178428d7b3dSmrg RegionUninit(crtc_region); 179428d7b3dSmrg 180428d7b3dSmrg frame->src.x1 = x1 >> 16; 181428d7b3dSmrg frame->src.y1 = y1 >> 16; 182428d7b3dSmrg frame->src.x2 = (x2 + 0xffff) >> 16; 183428d7b3dSmrg frame->src.y2 = (y2 + 0xffff) >> 16; 184428d7b3dSmrg 185428d7b3dSmrg frame->image.x1 = frame->src.x1 & ~1; 186428d7b3dSmrg frame->image.x2 = ALIGN(frame->src.x2, 2); 187428d7b3dSmrg if (is_planar_fourcc(frame->id)) { 188428d7b3dSmrg frame->image.y1 = frame->src.y1 & ~1; 189428d7b3dSmrg frame->image.y2 = ALIGN(frame->src.y2, 2); 190428d7b3dSmrg } else { 191428d7b3dSmrg frame->image.y1 = frame->src.y1; 192428d7b3dSmrg frame->image.y2 = frame->src.y2; 193428d7b3dSmrg } 194428d7b3dSmrg 195428d7b3dSmrg return ret; 196428d7b3dSmrg} 197428d7b3dSmrg 198428d7b3dSmrgvoid 199428d7b3dSmrgsna_video_frame_init(struct sna_video *video, 200428d7b3dSmrg int id, short width, short height, 201428d7b3dSmrg struct sna_video_frame *frame) 202428d7b3dSmrg{ 203428d7b3dSmrg DBG(("%s: id=%d [planar? %d], width=%d, height=%d, align=%d\n", 204428d7b3dSmrg __FUNCTION__, id, is_planar_fourcc(id), width, height, video->alignment)); 205428d7b3dSmrg assert(width && height); 206428d7b3dSmrg 207428d7b3dSmrg frame->bo = NULL; 208428d7b3dSmrg frame->id = id; 209428d7b3dSmrg frame->width = width; 210428d7b3dSmrg frame->height = height; 211428d7b3dSmrg frame->rotation = 0; 212428d7b3dSmrg} 213428d7b3dSmrg 214428d7b3dSmrgvoid 215428d7b3dSmrgsna_video_frame_set_rotation(struct sna_video *video, 216428d7b3dSmrg struct sna_video_frame *frame, 217428d7b3dSmrg Rotation rotation) 218428d7b3dSmrg{ 219428d7b3dSmrg unsigned width = frame->width; 220428d7b3dSmrg unsigned height = frame->height; 221428d7b3dSmrg unsigned align; 222428d7b3dSmrg 223428d7b3dSmrg DBG(("%s: rotation=%d\n", __FUNCTION__, rotation)); 224428d7b3dSmrg frame->rotation = rotation; 225428d7b3dSmrg 226428d7b3dSmrg align = video->alignment; 227428d7b3dSmrg#if SNA_XVMC 228428d7b3dSmrg /* for i915 xvmc, hw requires 1kb aligned surfaces */ 229428d7b3dSmrg if (frame->id == FOURCC_XVMC && video->sna->kgem.gen < 040 && align < 1024) 230428d7b3dSmrg align = 1024; 231428d7b3dSmrg#endif 232428d7b3dSmrg 233428d7b3dSmrg /* Determine the desired destination pitch (representing the 234428d7b3dSmrg * chroma's pitch in the planar case). 235428d7b3dSmrg */ 236428d7b3dSmrg if (is_planar_fourcc(frame->id)) { 237428d7b3dSmrg assert((width & 1) == 0); 238428d7b3dSmrg assert((height & 1) == 0); 239428d7b3dSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 240428d7b3dSmrg frame->pitch[0] = ALIGN((height / 2), align); 241428d7b3dSmrg frame->pitch[1] = ALIGN(height, align); 242428d7b3dSmrg frame->size = width; 243428d7b3dSmrg } else { 244428d7b3dSmrg frame->pitch[0] = ALIGN((width / 2), align); 245428d7b3dSmrg frame->pitch[1] = ALIGN(width, align); 246428d7b3dSmrg frame->size = height; 247428d7b3dSmrg } 248428d7b3dSmrg frame->size *= frame->pitch[0] + frame->pitch[1]; 249428d7b3dSmrg 250428d7b3dSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 251428d7b3dSmrg frame->UBufOffset = (int)frame->pitch[1] * width; 252428d7b3dSmrg frame->VBufOffset = 253428d7b3dSmrg frame->UBufOffset + (int)frame->pitch[0] * width / 2; 254428d7b3dSmrg } else { 255428d7b3dSmrg frame->UBufOffset = (int)frame->pitch[1] * height; 256428d7b3dSmrg frame->VBufOffset = 257428d7b3dSmrg frame->UBufOffset + (int)frame->pitch[0] * height / 2; 258428d7b3dSmrg } 259428d7b3dSmrg } else { 260428d7b3dSmrg switch (frame->id) { 261428d7b3dSmrg case FOURCC_RGB888: 262428d7b3dSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 263428d7b3dSmrg frame->pitch[0] = ALIGN((height << 2), align); 264428d7b3dSmrg frame->size = (int)frame->pitch[0] * width; 265428d7b3dSmrg } else { 266428d7b3dSmrg frame->pitch[0] = ALIGN((width << 2), align); 267428d7b3dSmrg frame->size = (int)frame->pitch[0] * height; 268428d7b3dSmrg } 269428d7b3dSmrg frame->UBufOffset = frame->VBufOffset = 0; 270428d7b3dSmrg break; 271428d7b3dSmrg case FOURCC_RGB565: 272428d7b3dSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 273428d7b3dSmrg frame->pitch[0] = ALIGN((height << 1), align); 274428d7b3dSmrg frame->size = (int)frame->pitch[0] * width; 275428d7b3dSmrg } else { 276428d7b3dSmrg frame->pitch[0] = ALIGN((width << 1), align); 277428d7b3dSmrg frame->size = (int)frame->pitch[0] * height; 278428d7b3dSmrg } 279428d7b3dSmrg frame->UBufOffset = frame->VBufOffset = 0; 280428d7b3dSmrg break; 281428d7b3dSmrg 282428d7b3dSmrg default: 283428d7b3dSmrg if (rotation & (RR_Rotate_90 | RR_Rotate_270)) { 284428d7b3dSmrg frame->pitch[0] = ALIGN((height << 1), align); 285428d7b3dSmrg frame->size = (int)frame->pitch[0] * width; 286428d7b3dSmrg } else { 287428d7b3dSmrg frame->pitch[0] = ALIGN((width << 1), align); 288428d7b3dSmrg frame->size = (int)frame->pitch[0] * height; 289428d7b3dSmrg } 290428d7b3dSmrg break; 291428d7b3dSmrg } 292428d7b3dSmrg frame->pitch[1] = 0; 293428d7b3dSmrg frame->UBufOffset = 0; 294428d7b3dSmrg frame->VBufOffset = 0; 295428d7b3dSmrg } 296428d7b3dSmrg 297428d7b3dSmrg assert(frame->size); 298428d7b3dSmrg} 299428d7b3dSmrg 300428d7b3dSmrgstatic void sna_memcpy_plane(struct sna_video *video, 301428d7b3dSmrg uint8_t *dst, const uint8_t *src, 302428d7b3dSmrg const struct sna_video_frame *frame, int sub) 303428d7b3dSmrg{ 304428d7b3dSmrg int dstPitch = frame->pitch[!sub], srcPitch; 305428d7b3dSmrg const uint8_t *s; 306428d7b3dSmrg int i, j = 0; 307428d7b3dSmrg int x, y, w, h; 308428d7b3dSmrg 309428d7b3dSmrg x = frame->image.x1; 310428d7b3dSmrg y = frame->image.y1; 311428d7b3dSmrg w = frame->image.x2 - frame->image.x1; 312428d7b3dSmrg h = frame->image.y2 - frame->image.y1; 313428d7b3dSmrg if (sub) { 314428d7b3dSmrg x >>= 1; w >>= 1; 315428d7b3dSmrg y >>= 1; h >>= 1; 316428d7b3dSmrg srcPitch = ALIGN((frame->width >> 1), 4); 317428d7b3dSmrg } else 318428d7b3dSmrg srcPitch = ALIGN(frame->width, 4); 319428d7b3dSmrg 320428d7b3dSmrg src += y * srcPitch + x; 321428d7b3dSmrg if (!video->textured) 322428d7b3dSmrg x = y = 0; 323428d7b3dSmrg 324428d7b3dSmrg switch (frame->rotation) { 325428d7b3dSmrg case RR_Rotate_0: 326428d7b3dSmrg dst += y * dstPitch + x; 327428d7b3dSmrg if (srcPitch == dstPitch && srcPitch == w) 328428d7b3dSmrg memcpy(dst, src, srcPitch * h); 329428d7b3dSmrg else while (h--) { 330428d7b3dSmrg memcpy(dst, src, w); 331428d7b3dSmrg src += srcPitch; 332428d7b3dSmrg dst += dstPitch; 333428d7b3dSmrg } 334428d7b3dSmrg break; 335428d7b3dSmrg case RR_Rotate_90: 336428d7b3dSmrg for (i = 0; i < h; i++) { 337428d7b3dSmrg s = src; 338428d7b3dSmrg for (j = 0; j < w; j++) 339428d7b3dSmrg dst[i + ((x + w - j - 1) * dstPitch)] = *s++; 340428d7b3dSmrg src += srcPitch; 341428d7b3dSmrg } 342428d7b3dSmrg break; 343428d7b3dSmrg case RR_Rotate_180: 344428d7b3dSmrg for (i = 0; i < h; i++) { 345428d7b3dSmrg s = src; 346428d7b3dSmrg for (j = 0; j < w; j++) { 347428d7b3dSmrg dst[(x + w - j - 1) + 348428d7b3dSmrg ((h - i - 1) * dstPitch)] = *s++; 349428d7b3dSmrg } 350428d7b3dSmrg src += srcPitch; 351428d7b3dSmrg } 352428d7b3dSmrg break; 353428d7b3dSmrg case RR_Rotate_270: 354428d7b3dSmrg for (i = 0; i < h; i++) { 355428d7b3dSmrg s = src; 356428d7b3dSmrg for (j = 0; j < w; j++) { 357428d7b3dSmrg dst[(h - i - 1) + (x + j * dstPitch)] = *s++; 358428d7b3dSmrg } 359428d7b3dSmrg src += srcPitch; 360428d7b3dSmrg } 361428d7b3dSmrg break; 362428d7b3dSmrg } 363428d7b3dSmrg} 364428d7b3dSmrg 365428d7b3dSmrgstatic void 366428d7b3dSmrgsna_copy_planar_data(struct sna_video *video, 367428d7b3dSmrg const struct sna_video_frame *frame, 368428d7b3dSmrg const uint8_t *src, uint8_t *dst) 369428d7b3dSmrg{ 370428d7b3dSmrg uint8_t *d; 371428d7b3dSmrg 372428d7b3dSmrg sna_memcpy_plane(video, dst, src, frame, 0); 373428d7b3dSmrg src += frame->height * ALIGN(frame->width, 4); 374428d7b3dSmrg 375428d7b3dSmrg if (frame->id == FOURCC_I420) 376428d7b3dSmrg d = dst + frame->UBufOffset; 377428d7b3dSmrg else 378428d7b3dSmrg d = dst + frame->VBufOffset; 379428d7b3dSmrg sna_memcpy_plane(video, d, src, frame, 1); 380428d7b3dSmrg src += (frame->height >> 1) * ALIGN(frame->width >> 1, 4); 381428d7b3dSmrg 382428d7b3dSmrg if (frame->id == FOURCC_I420) 383428d7b3dSmrg d = dst + frame->VBufOffset; 384428d7b3dSmrg else 385428d7b3dSmrg d = dst + frame->UBufOffset; 386428d7b3dSmrg sna_memcpy_plane(video, d, src, frame, 1); 387428d7b3dSmrg} 388428d7b3dSmrg 389428d7b3dSmrgstatic void 390428d7b3dSmrgsna_copy_packed_data(struct sna_video *video, 391428d7b3dSmrg const struct sna_video_frame *frame, 392428d7b3dSmrg const uint8_t *buf, 393428d7b3dSmrg uint8_t *dst) 394428d7b3dSmrg{ 395428d7b3dSmrg int pitch = frame->width << 1; 396428d7b3dSmrg const uint8_t *src, *s; 397428d7b3dSmrg int x, y, w, h; 398428d7b3dSmrg int i, j; 399428d7b3dSmrg 400428d7b3dSmrg if (video->textured) { 401428d7b3dSmrg /* XXX support copying cropped extents */ 402428d7b3dSmrg x = y = 0; 403428d7b3dSmrg w = frame->width; 404428d7b3dSmrg h = frame->height; 405428d7b3dSmrg } else { 406428d7b3dSmrg x = frame->image.x1; 407428d7b3dSmrg y = frame->image.y1; 408428d7b3dSmrg w = frame->image.x2 - frame->image.x1; 409428d7b3dSmrg h = frame->image.y2 - frame->image.y1; 410428d7b3dSmrg } 411428d7b3dSmrg 412428d7b3dSmrg src = buf + (y * pitch) + (x << 1); 413428d7b3dSmrg 414428d7b3dSmrg switch (frame->rotation) { 415428d7b3dSmrg case RR_Rotate_0: 416428d7b3dSmrg w <<= 1; 417428d7b3dSmrg for (i = 0; i < h; i++) { 418428d7b3dSmrg memcpy(dst, src, w); 419428d7b3dSmrg src += pitch; 420428d7b3dSmrg dst += frame->pitch[0]; 421428d7b3dSmrg } 422428d7b3dSmrg break; 423428d7b3dSmrg case RR_Rotate_90: 424428d7b3dSmrg h <<= 1; 425428d7b3dSmrg for (i = 0; i < h; i += 2) { 426428d7b3dSmrg s = src; 427428d7b3dSmrg for (j = 0; j < w; j++) { 428428d7b3dSmrg /* Copy Y */ 429428d7b3dSmrg dst[(i + 0) + ((w - j - 1) * frame->pitch[0])] = *s; 430428d7b3dSmrg s += 2; 431428d7b3dSmrg } 432428d7b3dSmrg src += pitch; 433428d7b3dSmrg } 434428d7b3dSmrg h >>= 1; 435428d7b3dSmrg src = buf + (y * pitch) + (x << 1); 436428d7b3dSmrg for (i = 0; i < h; i += 2) { 437428d7b3dSmrg for (j = 0; j < w; j += 2) { 438428d7b3dSmrg /* Copy U */ 439428d7b3dSmrg dst[((i * 2) + 1) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 440428d7b3dSmrg dst[((i * 2) + 1) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 441428d7b3dSmrg /* Copy V */ dst[((i * 2) + 3) + ((w - j - 1) * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 442428d7b3dSmrg dst[((i * 2) + 3) + ((w - j - 2) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 443428d7b3dSmrg } 444428d7b3dSmrg } 445428d7b3dSmrg break; 446428d7b3dSmrg case RR_Rotate_180: 447428d7b3dSmrg w <<= 1; 448428d7b3dSmrg for (i = 0; i < h; i++) { 449428d7b3dSmrg s = src; 450428d7b3dSmrg for (j = 0; j < w; j += 4) { 451428d7b3dSmrg dst[(w - j - 4) + ((h - i - 1) * frame->pitch[0])] = *s++; 452428d7b3dSmrg dst[(w - j - 3) + ((h - i - 1) * frame->pitch[0])] = *s++; 453428d7b3dSmrg dst[(w - j - 2) + ((h - i - 1) * frame->pitch[0])] = *s++; 454428d7b3dSmrg dst[(w - j - 1) + ((h - i - 1) * frame->pitch[0])] = *s++; 455428d7b3dSmrg } 456428d7b3dSmrg src += pitch; 457428d7b3dSmrg } 458428d7b3dSmrg break; 459428d7b3dSmrg case RR_Rotate_270: 460428d7b3dSmrg h <<= 1; 461428d7b3dSmrg for (i = 0; i < h; i += 2) { 462428d7b3dSmrg s = src; 463428d7b3dSmrg for (j = 0; j < w; j++) { 464428d7b3dSmrg /* Copy Y */ 465428d7b3dSmrg dst[(h - i - 2) + (j * frame->pitch[0])] = *s; 466428d7b3dSmrg s += 2; 467428d7b3dSmrg } 468428d7b3dSmrg src += pitch; 469428d7b3dSmrg } 470428d7b3dSmrg h >>= 1; 471428d7b3dSmrg src = buf + (y * pitch) + (x << 1); 472428d7b3dSmrg for (i = 0; i < h; i += 2) { 473428d7b3dSmrg for (j = 0; j < w; j += 2) { 474428d7b3dSmrg /* Copy U */ 475428d7b3dSmrg dst[(((h - i) * 2) - 3) + (j * frame->pitch[0])] = src[(j * 2) + 1 + (i * pitch)]; 476428d7b3dSmrg dst[(((h - i) * 2) - 3) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 1 + ((i + 1) * pitch)]; 477428d7b3dSmrg /* Copy V */ 478428d7b3dSmrg dst[(((h - i) * 2) - 1) + (j * frame->pitch[0])] = src[(j * 2) + 3 + (i * pitch)]; 479428d7b3dSmrg dst[(((h - i) * 2) - 1) + ((j + 1) * frame->pitch[0])] = src[(j * 2) + 3 + ((i + 1) * pitch)]; 480428d7b3dSmrg } 481428d7b3dSmrg } 482428d7b3dSmrg break; 483428d7b3dSmrg } 484428d7b3dSmrg} 485428d7b3dSmrg 486428d7b3dSmrgbool 487428d7b3dSmrgsna_video_copy_data(struct sna_video *video, 488428d7b3dSmrg struct sna_video_frame *frame, 489428d7b3dSmrg const uint8_t *buf) 490428d7b3dSmrg{ 491428d7b3dSmrg uint8_t *dst; 492428d7b3dSmrg 493428d7b3dSmrg DBG(("%s: handle=%d, size=%dx%d [%d], pitch=[%d,%d] rotation=%d, is-texture=%d\n", 494428d7b3dSmrg __FUNCTION__, frame->bo ? frame->bo->handle : 0, 495428d7b3dSmrg frame->width, frame->height, frame->size, frame->pitch[0], frame->pitch[1], 496428d7b3dSmrg frame->rotation, video->textured)); 497428d7b3dSmrg DBG(("%s: image=(%d, %d), (%d, %d), source=(%d, %d), (%d, %d)\n", 498428d7b3dSmrg __FUNCTION__, 499428d7b3dSmrg frame->image.x1, frame->image.y1, frame->image.x2, frame->image.y2, 500428d7b3dSmrg frame->src.x1, frame->src.y1, frame->src.x2, frame->src.y2)); 501428d7b3dSmrg assert(frame->width && frame->height); 502428d7b3dSmrg assert(frame->rotation); 503428d7b3dSmrg assert(frame->size); 504428d7b3dSmrg 505428d7b3dSmrg /* In the common case, we can simply the upload in a single pwrite */ 506428d7b3dSmrg if (frame->rotation == RR_Rotate_0 && !video->tiled) { 507428d7b3dSmrg DBG(("%s: unrotated, untiled fast paths: is-planar?=%d\n", 508428d7b3dSmrg __FUNCTION__, is_planar_fourcc(frame->id))); 509428d7b3dSmrg if (is_planar_fourcc(frame->id)) { 510428d7b3dSmrg int w = frame->image.x2 - frame->image.x1; 511428d7b3dSmrg int h = frame->image.y2 - frame->image.y1; 512428d7b3dSmrg if (ALIGN(h, 2) == frame->height && 513428d7b3dSmrg ALIGN(w >> 1, 4) == frame->pitch[0] && 514428d7b3dSmrg ALIGN(w, 4) == frame->pitch[1]) { 515428d7b3dSmrg if (frame->bo) { 516428d7b3dSmrg if (!kgem_bo_write(&video->sna->kgem, frame->bo, 517428d7b3dSmrg buf, frame->size)) 518428d7b3dSmrg goto use_gtt; 519428d7b3dSmrg } else { 520428d7b3dSmrg frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 521428d7b3dSmrg KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 522428d7b3dSmrg (void **)&dst); 523428d7b3dSmrg if (frame->bo == NULL) 524428d7b3dSmrg return false; 525428d7b3dSmrg 526428d7b3dSmrg memcpy(dst, buf, frame->size); 527428d7b3dSmrg } 528428d7b3dSmrg if (frame->id != FOURCC_I420) { 529428d7b3dSmrg uint32_t tmp; 530428d7b3dSmrg tmp = frame->VBufOffset; 531428d7b3dSmrg frame->VBufOffset = frame->UBufOffset; 532428d7b3dSmrg frame->UBufOffset = tmp; 533428d7b3dSmrg } 534428d7b3dSmrg return true; 535428d7b3dSmrg } 536428d7b3dSmrg } else { 537428d7b3dSmrg int x, y, w, h; 538428d7b3dSmrg 539428d7b3dSmrg if (video->textured) { 540428d7b3dSmrg /* XXX support copying cropped extents */ 541428d7b3dSmrg x = y = 0; 542428d7b3dSmrg w = frame->width; 543428d7b3dSmrg h = frame->height; 544428d7b3dSmrg } else { 545428d7b3dSmrg x = frame->image.x1; 546428d7b3dSmrg y = frame->image.y1; 547428d7b3dSmrg w = frame->image.x2 - frame->image.x1; 548428d7b3dSmrg h = frame->image.y2 - frame->image.y1; 549428d7b3dSmrg } 550428d7b3dSmrg 551428d7b3dSmrg if (w*2 == frame->pitch[0]) { 552428d7b3dSmrg buf += (2U*y * frame->width) + (x << 1); 553428d7b3dSmrg if (frame->bo) { 554428d7b3dSmrg if (!kgem_bo_write(&video->sna->kgem, frame->bo, 555428d7b3dSmrg buf, 2U*h*frame->width)) 556428d7b3dSmrg goto use_gtt; 557428d7b3dSmrg } else { 558428d7b3dSmrg frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 559428d7b3dSmrg KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 560428d7b3dSmrg (void **)&dst); 561428d7b3dSmrg if (frame->bo == NULL) 562428d7b3dSmrg return false; 563428d7b3dSmrg 564428d7b3dSmrg memcpy(dst, buf, 2U*h*frame->width); 565428d7b3dSmrg } 566428d7b3dSmrg return true; 567428d7b3dSmrg } 568428d7b3dSmrg } 569428d7b3dSmrg 570428d7b3dSmrg DBG(("%s: source cropped, fallback\n", __FUNCTION__)); 571428d7b3dSmrg } 572428d7b3dSmrg 573428d7b3dSmrguse_gtt: /* copy data, must use GTT so that we keep the overlay uncached */ 574428d7b3dSmrg if (frame->bo) { 575428d7b3dSmrg dst = kgem_bo_map__gtt(&video->sna->kgem, frame->bo); 576428d7b3dSmrg if (dst == NULL) 577428d7b3dSmrg return false; 578428d7b3dSmrg } else { 579428d7b3dSmrg frame->bo = kgem_create_buffer(&video->sna->kgem, frame->size, 580428d7b3dSmrg KGEM_BUFFER_WRITE | KGEM_BUFFER_WRITE_INPLACE, 581428d7b3dSmrg (void **)&dst); 582428d7b3dSmrg if (frame->bo == NULL) 583428d7b3dSmrg return false; 584428d7b3dSmrg } 585428d7b3dSmrg 586428d7b3dSmrg if (is_planar_fourcc(frame->id)) 587428d7b3dSmrg sna_copy_planar_data(video, frame, buf, dst); 588428d7b3dSmrg else 589428d7b3dSmrg sna_copy_packed_data(video, frame, buf, dst); 590428d7b3dSmrg 591428d7b3dSmrg return true; 592428d7b3dSmrg} 593428d7b3dSmrg 594428d7b3dSmrgXvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna) 595428d7b3dSmrg{ 596428d7b3dSmrg XvAdaptorPtr new_adaptors; 597428d7b3dSmrg 598428d7b3dSmrg new_adaptors = realloc(sna->xv.adaptors, 599428d7b3dSmrg (sna->xv.num_adaptors+1)*sizeof(XvAdaptorRec)); 600428d7b3dSmrg if (new_adaptors == NULL) 601428d7b3dSmrg return NULL; 602428d7b3dSmrg 603428d7b3dSmrg if (sna->xv.num_adaptors && new_adaptors != sna->xv.adaptors) { 604428d7b3dSmrg XvAdaptorPtr adaptor = new_adaptors; 605428d7b3dSmrg int i = sna->xv.num_adaptors, j; 606428d7b3dSmrg while (i--) { 607428d7b3dSmrg for (j = 0; j < adaptor->nPorts; j++) 608428d7b3dSmrg adaptor->pPorts[j].pAdaptor = adaptor; 609428d7b3dSmrg adaptor++; 610428d7b3dSmrg } 611428d7b3dSmrg } 612428d7b3dSmrg 613428d7b3dSmrg sna->xv.adaptors = new_adaptors; 614428d7b3dSmrg return &sna->xv.adaptors[sna->xv.num_adaptors++]; 615428d7b3dSmrg} 616428d7b3dSmrg 617428d7b3dSmrgint 618428d7b3dSmrgsna_xv_alloc_port(unsigned long port, XvPortPtr in, XvPortPtr *out) 619428d7b3dSmrg{ 620428d7b3dSmrg *out = in; 621428d7b3dSmrg return Success; 622428d7b3dSmrg} 623428d7b3dSmrg 624428d7b3dSmrgint 625428d7b3dSmrgsna_xv_free_port(XvPortPtr port) 626428d7b3dSmrg{ 627428d7b3dSmrg return Success; 628428d7b3dSmrg} 629428d7b3dSmrg 630428d7b3dSmrgint 631428d7b3dSmrgsna_xv_fixup_formats(ScreenPtr screen, XvFormatPtr formats, int num_formats) 632428d7b3dSmrg{ 633428d7b3dSmrg XvFormatPtr out = formats; 634428d7b3dSmrg int count = 0; 635428d7b3dSmrg 636428d7b3dSmrg while (num_formats--) { 637428d7b3dSmrg int num_visuals = screen->numVisuals; 638428d7b3dSmrg VisualPtr v = screen->visuals; 639428d7b3dSmrg 640428d7b3dSmrg while (num_visuals--) { 641428d7b3dSmrg if (v->class == TrueColor && 642428d7b3dSmrg v->nplanes == formats->depth) { 643428d7b3dSmrg int tmp = out[count].depth; 644428d7b3dSmrg out[count].depth = formats->depth; 645428d7b3dSmrg out[count].visual = v->vid; 646428d7b3dSmrg formats->depth = tmp; 647428d7b3dSmrg count++; 648428d7b3dSmrg break; 649428d7b3dSmrg } 650428d7b3dSmrg v++; 651428d7b3dSmrg } 652428d7b3dSmrg 653428d7b3dSmrg formats++; 654428d7b3dSmrg } 655428d7b3dSmrg 656428d7b3dSmrg return count; 657428d7b3dSmrg} 658428d7b3dSmrg 659428d7b3dSmrg#if XORG_XV_VERSION < 2 660428d7b3dSmrgstatic int 661428d7b3dSmrgsna_xv_query_adaptors(ScreenPtr screen, 662428d7b3dSmrg XvAdaptorPtr *adaptors, 663428d7b3dSmrg int *num_adaptors) 664428d7b3dSmrg{ 665428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 666428d7b3dSmrg 667428d7b3dSmrg *num_adaptors = sna->xv.num_adaptors; 668428d7b3dSmrg *adaptors = sna->xv.adaptors; 669428d7b3dSmrg return Success; 670428d7b3dSmrg} 671428d7b3dSmrg 672428d7b3dSmrgstatic Bool 673428d7b3dSmrgsna_xv_close_screen(CLOSE_SCREEN_ARGS_DECL) 674428d7b3dSmrg{ 675428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 676428d7b3dSmrg sna_video_close(sna); 677428d7b3dSmrg return TRUE; 678428d7b3dSmrg} 679428d7b3dSmrg#endif 680428d7b3dSmrg 681428d7b3dSmrgvoid sna_video_init(struct sna *sna, ScreenPtr screen) 682428d7b3dSmrg{ 683428d7b3dSmrg XvScreenPtr xv; 684428d7b3dSmrg 685428d7b3dSmrg if (noXvExtension) 686428d7b3dSmrg return; 687428d7b3dSmrg 688428d7b3dSmrg if (xf86LoaderCheckSymbol("xf86XVListGenericAdaptors")) { 689428d7b3dSmrg XF86VideoAdaptorPtr *adaptors = NULL; 690428d7b3dSmrg int num_adaptors = xf86XVListGenericAdaptors(sna->scrn, &adaptors); 691428d7b3dSmrg if (num_adaptors) 692428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 693428d7b3dSmrg "Ignoring generic xf86XV adaptors"); 694428d7b3dSmrg free(adaptors); 695428d7b3dSmrg } 696428d7b3dSmrg 697428d7b3dSmrg if (XvScreenInit(screen) != Success) 698428d7b3dSmrg return; 699428d7b3dSmrg 700428d7b3dSmrg xv = to_xv(screen); 701428d7b3dSmrg#if XORG_XV_VERSION < 2 702428d7b3dSmrg xv->ddCloseScreen = sna_xv_close_screen; 703428d7b3dSmrg xv->ddQueryAdaptors = sna_xv_query_adaptors; 704428d7b3dSmrg#endif 705428d7b3dSmrg 706428d7b3dSmrg sna_video_textured_setup(sna, screen); 707428d7b3dSmrg sna_video_sprite_setup(sna, screen); 708428d7b3dSmrg sna_video_overlay_setup(sna, screen); 709428d7b3dSmrg 710428d7b3dSmrg if (sna->xv.num_adaptors >= 2 && 711428d7b3dSmrg xf86ReturnOptValBool(sna->Options, OPTION_PREFER_OVERLAY, false)) { 712428d7b3dSmrg XvAdaptorRec tmp; 713428d7b3dSmrg 714428d7b3dSmrg tmp = sna->xv.adaptors[0]; 715428d7b3dSmrg sna->xv.adaptors[0] = sna->xv.adaptors[1]; 716428d7b3dSmrg sna->xv.adaptors[1] = tmp; 717428d7b3dSmrg } 718428d7b3dSmrg 719428d7b3dSmrg xv->nAdaptors = sna->xv.num_adaptors; 720428d7b3dSmrg xv->pAdaptors = sna->xv.adaptors; 721428d7b3dSmrg 722428d7b3dSmrg sna_video_xvmc_setup(sna, screen); 723428d7b3dSmrg} 724428d7b3dSmrg 725428d7b3dSmrgvoid sna_video_destroy_window(WindowPtr win) 726428d7b3dSmrg{ 727428d7b3dSmrg XvPortPtr port; 728428d7b3dSmrg 729428d7b3dSmrg port = sna_window_get_port(win); 730428d7b3dSmrg if (port) { 731428d7b3dSmrg#if XORG_XV_VERSION < 2 732428d7b3dSmrg port->pAdaptor->ddStopVideo(NULL, port, &win->drawable); 733428d7b3dSmrg#else 734428d7b3dSmrg port->pAdaptor->ddStopVideo(port, &win->drawable); 735428d7b3dSmrg#endif 736428d7b3dSmrg } 737428d7b3dSmrg assert(sna_window_get_port(win) == NULL); 738428d7b3dSmrg} 739428d7b3dSmrg 740428d7b3dSmrgvoid sna_video_close(struct sna *sna) 741428d7b3dSmrg{ 742428d7b3dSmrg int i; 743428d7b3dSmrg 744428d7b3dSmrg for (i = 0; i < sna->xv.num_adaptors; i++) { 745428d7b3dSmrg free(sna->xv.adaptors[i].pPorts->devPriv.ptr); 746428d7b3dSmrg free(sna->xv.adaptors[i].pPorts); 747428d7b3dSmrg free(sna->xv.adaptors[i].pEncodings); 748428d7b3dSmrg } 749428d7b3dSmrg free(sna->xv.adaptors); 750428d7b3dSmrg 751428d7b3dSmrg sna->xv.adaptors = NULL; 752428d7b3dSmrg sna->xv.num_adaptors = 0; 753428d7b3dSmrg} 754