103b705cfSriastradh/*************************************************************************** 203b705cfSriastradh 303b705cfSriastradh Copyright 2000-2011 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#ifdef HAVE_CONFIG_H 2803b705cfSriastradh#include "config.h" 2903b705cfSriastradh#endif 3003b705cfSriastradh 3103b705cfSriastradh#include "sna.h" 3203b705cfSriastradh#include "sna_video.h" 3303b705cfSriastradh 3403b705cfSriastradh#include "intel_options.h" 3503b705cfSriastradh 3603b705cfSriastradh#include <xf86drm.h> 3703b705cfSriastradh#include <xf86xv.h> 3842542f5fSchristos#include <xf86Crtc.h> 3903b705cfSriastradh#include <X11/extensions/Xv.h> 4003b705cfSriastradh#include <fourcc.h> 4103b705cfSriastradh#include <i915_drm.h> 4203b705cfSriastradh#include <errno.h> 4303b705cfSriastradh 4442542f5fSchristos#define fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) 4542542f5fSchristos#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */ 4642542f5fSchristos#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */ 4742542f5fSchristos#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ 4842542f5fSchristos#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */ 49fe8aea9eSmrg#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ 50fe8aea9eSmrg#define DRM_FORMAT_XYUV8888 fourcc_code('X', 'Y', 'U', 'V') /* [31:0] x:Y:U:V 8:8:8:8 little endian */ 51fe8aea9eSmrg 52fe8aea9eSmrg#define has_hw_scaling(sna, video) ((sna)->kgem.gen < 071 || \ 53fe8aea9eSmrg (sna)->kgem.gen >= 0110) 5442542f5fSchristos 5542542f5fSchristos#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane) 5642542f5fSchristosstruct local_mode_set_plane { 5742542f5fSchristos uint32_t plane_id; 5842542f5fSchristos uint32_t crtc_id; 5942542f5fSchristos uint32_t fb_id; /* fb object contains surface format type */ 6042542f5fSchristos uint32_t flags; 6142542f5fSchristos 6242542f5fSchristos /* Signed dest location allows it to be partially off screen */ 6342542f5fSchristos int32_t crtc_x, crtc_y; 6442542f5fSchristos uint32_t crtc_w, crtc_h; 6542542f5fSchristos 6642542f5fSchristos /* Source values are 16.16 fixed point */ 6742542f5fSchristos uint32_t src_x, src_y; 6842542f5fSchristos uint32_t src_h, src_w; 6942542f5fSchristos}; 7003b705cfSriastradh 7103b705cfSriastradh#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, true) 7203b705cfSriastradh 73fe8aea9eSmrgstatic Atom xvColorKey, xvAlwaysOnTop, xvSyncToVblank, xvColorspace; 74fe8aea9eSmrg 75fe8aea9eSmrgstatic XvFormatRec formats[] = { {8}, {15}, {16}, {24}, {30} }; 76fe8aea9eSmrgstatic const XvImageRec images[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 77fe8aea9eSmrg XVMC_RGB888 }; 78fe8aea9eSmrgstatic const XvImageRec images_rgb565[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 79fe8aea9eSmrg XVMC_RGB888, XVMC_RGB565 }; 80fe8aea9eSmrgstatic const XvImageRec images_nv12[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, 81fe8aea9eSmrg XVIMAGE_NV12, XVMC_RGB888, XVMC_RGB565 }; 82fe8aea9eSmrgstatic const XvImageRec images_ayuv[] = { XVIMAGE_AYUV, XVIMAGE_YUY2, XVIMAGE_UYVY, 83fe8aea9eSmrg XVIMAGE_NV12, XVMC_RGB888, XVMC_RGB565 }; 8403b705cfSriastradhstatic const XvAttributeRec attribs[] = { 85fe8aea9eSmrg { XvSettable | XvGettable, 0, 1, (char *)"XV_COLORSPACE" }, /* BT.601, BT.709 */ 8603b705cfSriastradh { XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_COLORKEY" }, 8742542f5fSchristos { XvSettable | XvGettable, 0, 1, (char *)"XV_ALWAYS_ON_TOP" }, 8803b705cfSriastradh}; 8903b705cfSriastradh 9042542f5fSchristosstatic int sna_video_sprite_stop(ddStopVideo_ARGS) 9103b705cfSriastradh{ 9203b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 9342542f5fSchristos struct local_mode_set_plane s; 9442542f5fSchristos xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn); 9542542f5fSchristos int i; 9603b705cfSriastradh 97fe8aea9eSmrg for (i = 0; i < video->sna->mode.num_real_crtc; i++) { 9842542f5fSchristos xf86CrtcPtr crtc = config->crtc[i]; 9942542f5fSchristos int pipe; 10003b705cfSriastradh 101fe8aea9eSmrg pipe = sna_crtc_pipe(crtc); 102fe8aea9eSmrg assert(pipe < ARRAY_SIZE(video->bo)); 10342542f5fSchristos if (video->bo[pipe] == NULL) 10442542f5fSchristos continue; 10542542f5fSchristos 10642542f5fSchristos memset(&s, 0, sizeof(s)); 107fe8aea9eSmrg s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 10842542f5fSchristos if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 10942542f5fSchristos xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 11042542f5fSchristos "failed to disable plane\n"); 11142542f5fSchristos 11242542f5fSchristos if (video->bo[pipe]) 11342542f5fSchristos kgem_bo_destroy(&video->sna->kgem, video->bo[pipe]); 11442542f5fSchristos video->bo[pipe] = NULL; 11542542f5fSchristos } 11603b705cfSriastradh 11703b705cfSriastradh sna_window_set_port((WindowPtr)draw, NULL); 11803b705cfSriastradh 11903b705cfSriastradh return Success; 12003b705cfSriastradh} 12103b705cfSriastradh 12242542f5fSchristosstatic int sna_video_sprite_set_attr(ddSetPortAttribute_ARGS) 12303b705cfSriastradh{ 12403b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 12503b705cfSriastradh 12603b705cfSriastradh if (attribute == xvColorKey) { 12742542f5fSchristos video->color_key_changed = ~0; 12803b705cfSriastradh video->color_key = value; 12942542f5fSchristos RegionEmpty(&video->clip); 13003b705cfSriastradh DBG(("COLORKEY = %ld\n", (long)value)); 131fe8aea9eSmrg } else if (attribute == xvColorspace) { 132fe8aea9eSmrg video->colorspace_changed = ~0; 133fe8aea9eSmrg video->colorspace = value; 134fe8aea9eSmrg DBG(("COLORSPACE = %ld\n", (long)value)); 13542542f5fSchristos } else if (attribute == xvSyncToVblank) { 13642542f5fSchristos DBG(("%s: SYNC_TO_VBLANK: %d -> %d\n", __FUNCTION__, 13742542f5fSchristos video->SyncToVblank, !!value)); 13842542f5fSchristos video->SyncToVblank = !!value; 13903b705cfSriastradh } else if (attribute == xvAlwaysOnTop) { 14003b705cfSriastradh DBG(("%s: ALWAYS_ON_TOP: %d -> %d\n", __FUNCTION__, 14103b705cfSriastradh video->AlwaysOnTop, !!value)); 14242542f5fSchristos video->color_key_changed = ~0; 14303b705cfSriastradh video->AlwaysOnTop = !!value; 14403b705cfSriastradh } else 14503b705cfSriastradh return BadMatch; 14603b705cfSriastradh 14703b705cfSriastradh return Success; 14803b705cfSriastradh} 14903b705cfSriastradh 15042542f5fSchristosstatic int sna_video_sprite_get_attr(ddGetPortAttribute_ARGS) 15103b705cfSriastradh{ 15203b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 15303b705cfSriastradh 15403b705cfSriastradh if (attribute == xvColorKey) 15503b705cfSriastradh *value = video->color_key; 156fe8aea9eSmrg else if (attribute == xvColorspace) 157fe8aea9eSmrg *value = video->colorspace; 15803b705cfSriastradh else if (attribute == xvAlwaysOnTop) 15903b705cfSriastradh *value = video->AlwaysOnTop; 16042542f5fSchristos else if (attribute == xvSyncToVblank) 16142542f5fSchristos *value = video->SyncToVblank; 16203b705cfSriastradh else 16303b705cfSriastradh return BadMatch; 16403b705cfSriastradh 16503b705cfSriastradh return Success; 16603b705cfSriastradh} 16703b705cfSriastradh 16842542f5fSchristosstatic int sna_video_sprite_best_size(ddQueryBestSize_ARGS) 16903b705cfSriastradh{ 17003b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 17103b705cfSriastradh struct sna *sna = video->sna; 17203b705cfSriastradh 173fe8aea9eSmrg if (!has_hw_scaling(sna, video) && !sna->render.video) { 17403b705cfSriastradh *p_w = vid_w; 17503b705cfSriastradh *p_h = vid_h; 17603b705cfSriastradh } else { 17703b705cfSriastradh *p_w = drw_w; 17803b705cfSriastradh *p_h = drw_h; 17903b705cfSriastradh } 18003b705cfSriastradh 18103b705cfSriastradh return Success; 18203b705cfSriastradh} 18303b705cfSriastradh 18403b705cfSriastradhstatic void 18503b705cfSriastradhupdate_dst_box_to_crtc_coords(struct sna *sna, xf86CrtcPtr crtc, BoxPtr dstBox) 18603b705cfSriastradh{ 18703b705cfSriastradh ScrnInfoPtr scrn = sna->scrn; 18803b705cfSriastradh int tmp; 18903b705cfSriastradh 19003b705cfSriastradh switch (crtc->rotation & 0xf) { 19103b705cfSriastradh case RR_Rotate_0: 19203b705cfSriastradh dstBox->x1 -= crtc->x; 19303b705cfSriastradh dstBox->x2 -= crtc->x; 19403b705cfSriastradh dstBox->y1 -= crtc->y; 19503b705cfSriastradh dstBox->y2 -= crtc->y; 19603b705cfSriastradh break; 19703b705cfSriastradh 19803b705cfSriastradh case RR_Rotate_90: 19903b705cfSriastradh tmp = dstBox->x1; 20003b705cfSriastradh dstBox->x1 = dstBox->y1 - crtc->x; 20103b705cfSriastradh dstBox->y1 = scrn->virtualX - tmp - crtc->y; 20203b705cfSriastradh tmp = dstBox->x2; 20303b705cfSriastradh dstBox->x2 = dstBox->y2 - crtc->x; 20403b705cfSriastradh dstBox->y2 = scrn->virtualX - tmp - crtc->y; 20503b705cfSriastradh tmp = dstBox->y1; 20603b705cfSriastradh dstBox->y1 = dstBox->y2; 20703b705cfSriastradh dstBox->y2 = tmp; 20803b705cfSriastradh break; 20903b705cfSriastradh 21003b705cfSriastradh case RR_Rotate_180: 21103b705cfSriastradh tmp = dstBox->x1; 21203b705cfSriastradh dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x; 21303b705cfSriastradh dstBox->x2 = scrn->virtualX - tmp - crtc->x; 21403b705cfSriastradh tmp = dstBox->y1; 21503b705cfSriastradh dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y; 21603b705cfSriastradh dstBox->y2 = scrn->virtualY - tmp - crtc->y; 21703b705cfSriastradh break; 21803b705cfSriastradh 21903b705cfSriastradh case RR_Rotate_270: 22003b705cfSriastradh tmp = dstBox->x1; 22103b705cfSriastradh dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x; 22203b705cfSriastradh dstBox->y1 = tmp - crtc->y; 22303b705cfSriastradh tmp = dstBox->x2; 22403b705cfSriastradh dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x; 22503b705cfSriastradh dstBox->y2 = tmp - crtc->y; 22603b705cfSriastradh tmp = dstBox->x1; 22703b705cfSriastradh dstBox->x1 = dstBox->x2; 22803b705cfSriastradh dstBox->x2 = tmp; 22903b705cfSriastradh break; 23003b705cfSriastradh } 23103b705cfSriastradh} 23203b705cfSriastradh 233fe8aea9eSmrgstatic uint32_t ckey_chan(uint32_t value, int weight) 234fe8aea9eSmrg{ 235fe8aea9eSmrg return value << 8 >> weight; 236fe8aea9eSmrg} 237fe8aea9eSmrg 238fe8aea9eSmrgstatic uint32_t ckey_value_chan(uint32_t value, uint32_t mask, 239fe8aea9eSmrg int offset, int weight) 240fe8aea9eSmrg{ 241fe8aea9eSmrg return ckey_chan((value & mask) >> offset, weight); 242fe8aea9eSmrg} 243fe8aea9eSmrg 244fe8aea9eSmrgstatic uint32_t ckey_value(struct sna *sna, 245fe8aea9eSmrg struct sna_video *video) 246fe8aea9eSmrg{ 247fe8aea9eSmrg ScrnInfoPtr scrn = sna->scrn; 248fe8aea9eSmrg uint32_t r, g ,b; 249fe8aea9eSmrg 250fe8aea9eSmrg if (scrn->depth == 8) { 251fe8aea9eSmrg r = g = b = video->color_key & 0xff; 252fe8aea9eSmrg } else { 253fe8aea9eSmrg r = ckey_value_chan(video->color_key, scrn->mask.red, 254fe8aea9eSmrg scrn->offset.red, scrn->weight.red); 255fe8aea9eSmrg g = ckey_value_chan(video->color_key, scrn->mask.green, 256fe8aea9eSmrg scrn->offset.green, scrn->weight.green); 257fe8aea9eSmrg b = ckey_value_chan(video->color_key, scrn->mask.blue, 258fe8aea9eSmrg scrn->offset.blue, scrn->weight.blue); 259fe8aea9eSmrg } 260fe8aea9eSmrg 261fe8aea9eSmrg return r << 16 | g << 8 | b; 262fe8aea9eSmrg} 263fe8aea9eSmrg 264fe8aea9eSmrgstatic uint32_t ckey_mask_chan(int weight) 265fe8aea9eSmrg{ 266fe8aea9eSmrg return ckey_chan((1 << weight) - 1, weight); 267fe8aea9eSmrg} 268fe8aea9eSmrg 269fe8aea9eSmrgstatic uint32_t ckey_mask(struct sna *sna) 270fe8aea9eSmrg{ 271fe8aea9eSmrg ScrnInfoPtr scrn = sna->scrn; 272fe8aea9eSmrg uint32_t r = ckey_mask_chan(scrn->weight.red); 273fe8aea9eSmrg uint32_t g = ckey_mask_chan(scrn->weight.green); 274fe8aea9eSmrg uint32_t b = ckey_mask_chan(scrn->weight.blue); 275fe8aea9eSmrg 276fe8aea9eSmrg return 0x7 << 24 | r << 16 | g << 8 | b; 277fe8aea9eSmrg} 278fe8aea9eSmrg 27903b705cfSriastradhstatic bool 28003b705cfSriastradhsna_video_sprite_show(struct sna *sna, 28103b705cfSriastradh struct sna_video *video, 28203b705cfSriastradh struct sna_video_frame *frame, 28303b705cfSriastradh xf86CrtcPtr crtc, 28403b705cfSriastradh BoxPtr dstBox) 28503b705cfSriastradh{ 28642542f5fSchristos struct local_mode_set_plane s; 287fe8aea9eSmrg int pipe = sna_crtc_pipe(crtc); 28842542f5fSchristos 28942542f5fSchristos /* XXX handle video spanning multiple CRTC */ 29003b705cfSriastradh 29103b705cfSriastradh VG_CLEAR(s); 292fe8aea9eSmrg s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 29303b705cfSriastradh 29442542f5fSchristos#define DRM_I915_SET_SPRITE_COLORKEY 0x2b 29542542f5fSchristos#define LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct local_intel_sprite_colorkey) 29642542f5fSchristos#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2) 29703b705cfSriastradh 29842542f5fSchristos if (video->color_key_changed & (1 << pipe) && video->has_color_key) { 29942542f5fSchristos struct local_intel_sprite_colorkey { 30042542f5fSchristos uint32_t plane_id; 30142542f5fSchristos uint32_t min_value; 30242542f5fSchristos uint32_t channel_mask; 30342542f5fSchristos uint32_t max_value; 30442542f5fSchristos uint32_t flags; 30542542f5fSchristos } set; 30603b705cfSriastradh 30703b705cfSriastradh DBG(("%s: updating color key: %x\n", 30803b705cfSriastradh __FUNCTION__, video->color_key)); 30903b705cfSriastradh 31003b705cfSriastradh set.plane_id = s.plane_id; 311fe8aea9eSmrg set.min_value = ckey_value(sna, video); 312fe8aea9eSmrg set.max_value = 0; /* not used for destkey */ 313fe8aea9eSmrg set.channel_mask = ckey_mask(sna); 31403b705cfSriastradh set.flags = 0; 31503b705cfSriastradh if (!video->AlwaysOnTop) 31642542f5fSchristos set.flags |= 1 << 1; /* COLORKEY_DESTINATION */ 31703b705cfSriastradh 31803b705cfSriastradh if (drmIoctl(sna->kgem.fd, 31942542f5fSchristos LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY, 32042542f5fSchristos &set)) { 321fe8aea9eSmrg memset(&s, 0, sizeof(s)); 322fe8aea9eSmrg s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 323fe8aea9eSmrg 324fe8aea9eSmrg /* try to disable the plane first */ 325fe8aea9eSmrg if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 326fe8aea9eSmrg xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 327fe8aea9eSmrg "failed to disable plane\n"); 328fe8aea9eSmrg 329fe8aea9eSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY, &set)) { 330fe8aea9eSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 331fe8aea9eSmrg "failed to update color key, disabling future updates\n"); 332fe8aea9eSmrg video->has_color_key = false; 333fe8aea9eSmrg } 33442542f5fSchristos } 33503b705cfSriastradh 33642542f5fSchristos video->color_key_changed &= ~(1 << pipe); 33703b705cfSriastradh } 33803b705cfSriastradh 339fe8aea9eSmrg if (video->colorspace_changed & (1 << pipe)) { 340fe8aea9eSmrg DBG(("%s: updating colorspace: %x\n", 341fe8aea9eSmrg __FUNCTION__, video->colorspace)); 342fe8aea9eSmrg 343fe8aea9eSmrg sna_crtc_set_sprite_colorspace(crtc, video->idx, 344fe8aea9eSmrg video->colorspace); 345fe8aea9eSmrg 346fe8aea9eSmrg video->colorspace_changed &= ~(1 << pipe); 347fe8aea9eSmrg } 34803b705cfSriastradh 34942542f5fSchristos update_dst_box_to_crtc_coords(sna, crtc, dstBox); 35042542f5fSchristos if (frame->rotation & (RR_Rotate_90 | RR_Rotate_270)) { 35142542f5fSchristos int tmp = frame->width; 35242542f5fSchristos frame->width = frame->height; 35342542f5fSchristos frame->height = tmp; 35442542f5fSchristos } 35542542f5fSchristos 35642542f5fSchristos if (frame->bo->delta == 0) { 35742542f5fSchristos struct local_mode_fb_cmd2 { 35842542f5fSchristos uint32_t fb_id; 35942542f5fSchristos uint32_t width, height; 36042542f5fSchristos uint32_t pixel_format; 36142542f5fSchristos uint32_t flags; 36242542f5fSchristos 36342542f5fSchristos uint32_t handles[4]; 36442542f5fSchristos uint32_t pitches[4]; /* pitch for each plane */ 36542542f5fSchristos uint32_t offsets[4]; /* offset of each plane */ 366fe8aea9eSmrg uint64_t modifiers[4]; 36742542f5fSchristos } f; 36842542f5fSchristos bool purged = true; 36942542f5fSchristos 37042542f5fSchristos memset(&f, 0, sizeof(f)); 37142542f5fSchristos f.width = frame->width; 37242542f5fSchristos f.height = frame->height; 373fe8aea9eSmrg f.flags = 1 << 1; /* +modifiers */ 374fe8aea9eSmrg 375fe8aea9eSmrg switch (frame->bo->tiling) { 376fe8aea9eSmrg case I915_TILING_NONE: 377fe8aea9eSmrg break; 378fe8aea9eSmrg case I915_TILING_X: 379fe8aea9eSmrg /* I915_FORMAT_MOD_X_TILED */ 380fe8aea9eSmrg f.modifiers[0] = (uint64_t)1 << 56 | 1; 381fe8aea9eSmrg break; 382fe8aea9eSmrg case I915_TILING_Y: 383fe8aea9eSmrg /* I915_FORMAT_MOD_X_TILED */ 384fe8aea9eSmrg f.modifiers[0] = (uint64_t)1 << 56 | 2; 385fe8aea9eSmrg break; 386fe8aea9eSmrg } 387fe8aea9eSmrg 388fe8aea9eSmrg if (is_nv12_fourcc(frame->id)) { 389fe8aea9eSmrg f.handles[0] = frame->bo->handle; 390fe8aea9eSmrg f.handles[1] = frame->bo->handle; 391fe8aea9eSmrg f.pitches[0] = frame->pitch[1]; 392fe8aea9eSmrg f.pitches[1] = frame->pitch[0]; 393fe8aea9eSmrg f.offsets[0] = 0; 394fe8aea9eSmrg f.offsets[1] = frame->UBufOffset; 395fe8aea9eSmrg } else { 396fe8aea9eSmrg f.handles[0] = frame->bo->handle; 397fe8aea9eSmrg f.pitches[0] = frame->pitch[0]; 398fe8aea9eSmrg } 39903b705cfSriastradh 40003b705cfSriastradh switch (frame->id) { 40103b705cfSriastradh case FOURCC_RGB565: 40242542f5fSchristos f.pixel_format = DRM_FORMAT_RGB565; 40342542f5fSchristos purged = sna->scrn->depth != 16; 40403b705cfSriastradh break; 40503b705cfSriastradh case FOURCC_RGB888: 40642542f5fSchristos f.pixel_format = DRM_FORMAT_XRGB8888; 40742542f5fSchristos purged = sna->scrn->depth != 24; 40803b705cfSriastradh break; 409fe8aea9eSmrg case FOURCC_NV12: 410fe8aea9eSmrg f.pixel_format = DRM_FORMAT_NV12; 411fe8aea9eSmrg break; 41203b705cfSriastradh case FOURCC_UYVY: 41342542f5fSchristos f.pixel_format = DRM_FORMAT_UYVY; 41403b705cfSriastradh break; 415fe8aea9eSmrg case FOURCC_AYUV: 416fe8aea9eSmrg /* i915 doesn't support alpha, so we use XYUV */ 417fe8aea9eSmrg f.pixel_format = DRM_FORMAT_XYUV8888; 418fe8aea9eSmrg break; 41903b705cfSriastradh case FOURCC_YUY2: 42003b705cfSriastradh default: 42142542f5fSchristos f.pixel_format = DRM_FORMAT_YUYV; 42203b705cfSriastradh break; 42303b705cfSriastradh } 42403b705cfSriastradh 42542542f5fSchristos DBG(("%s: creating new fb for handle=%d, width=%d, height=%d, stride=%d, format=%x\n", 42642542f5fSchristos __FUNCTION__, frame->bo->handle, frame->width, frame->height, 42742542f5fSchristos f.pitches[0], f.pixel_format)); 42803b705cfSriastradh 42942542f5fSchristos if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) { 43042542f5fSchristos ERR(("%s: ADDFB2 failed, errno=%d\n", __FUNCTION__, errno)); 43103b705cfSriastradh xf86DrvMsg(sna->scrn->scrnIndex, 43242542f5fSchristos X_ERROR, "failed to add fb, unable to update video\n"); 43303b705cfSriastradh return false; 43403b705cfSriastradh } 43503b705cfSriastradh 43642542f5fSchristos frame->bo->delta = f.fb_id; 43742542f5fSchristos 43803b705cfSriastradh frame->bo->scanout = true; 43942542f5fSchristos /* Don't allow the scanout to be cached if not suitable for front */ 44042542f5fSchristos frame->bo->purged = purged; 44103b705cfSriastradh } 44203b705cfSriastradh 44303b705cfSriastradh assert(frame->bo->scanout); 44403b705cfSriastradh assert(frame->bo->delta); 44503b705cfSriastradh 44603b705cfSriastradh s.crtc_id = sna_crtc_id(crtc); 44703b705cfSriastradh s.fb_id = frame->bo->delta; 44803b705cfSriastradh s.flags = 0; 44903b705cfSriastradh s.crtc_x = dstBox->x1; 45003b705cfSriastradh s.crtc_y = dstBox->y1; 45103b705cfSriastradh s.crtc_w = dstBox->x2 - dstBox->x1; 45203b705cfSriastradh s.crtc_h = dstBox->y2 - dstBox->y1; 45303b705cfSriastradh s.src_x = 0; 45403b705cfSriastradh s.src_y = 0; 45503b705cfSriastradh s.src_w = (frame->image.x2 - frame->image.x1) << 16; 45603b705cfSriastradh s.src_h = (frame->image.y2 - frame->image.y1) << 16; 45703b705cfSriastradh 45803b705cfSriastradh DBG(("%s: updating crtc=%d, plane=%d, handle=%d [fb %d], dst=(%d,%d)x(%d,%d), src=(%d,%d)x(%d,%d)\n", 45903b705cfSriastradh __FUNCTION__, s.crtc_id, s.plane_id, frame->bo->handle, s.fb_id, 46003b705cfSriastradh s.crtc_x, s.crtc_y, s.crtc_w, s.crtc_h, 46103b705cfSriastradh s.src_x >> 16, s.src_y >> 16, s.src_w >> 16, s.src_h >> 16)); 46203b705cfSriastradh 46342542f5fSchristos if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) { 46403b705cfSriastradh DBG(("SET_PLANE failed: ret=%d\n", errno)); 46542542f5fSchristos if (video->bo[pipe]) { 46642542f5fSchristos kgem_bo_destroy(&sna->kgem, video->bo[pipe]); 46742542f5fSchristos video->bo[pipe] = NULL; 46842542f5fSchristos } 46903b705cfSriastradh return false; 47003b705cfSriastradh } 47103b705cfSriastradh 472fe8aea9eSmrg __kgem_bo_clear_dirty(frame->bo); 47303b705cfSriastradh 47442542f5fSchristos if (video->bo[pipe]) 47542542f5fSchristos kgem_bo_destroy(&sna->kgem, video->bo[pipe]); 47642542f5fSchristos video->bo[pipe] = kgem_bo_reference(frame->bo); 47703b705cfSriastradh return true; 47803b705cfSriastradh} 47903b705cfSriastradh 480fe8aea9eSmrgstatic bool need_scaling(const struct sna_video_frame *frame, 481fe8aea9eSmrg const BoxRec *dst) 482fe8aea9eSmrg{ 483fe8aea9eSmrg /* SKL+ need the plane scaler even for unscaled NV12 */ 484fe8aea9eSmrg return frame->id == FOURCC_NV12 || 485fe8aea9eSmrg frame->src.x2 - frame->src.x1 != dst->x2 - dst->x1 || 486fe8aea9eSmrg frame->src.y2 - frame->src.y1 != dst->y2 - dst->y1; 487fe8aea9eSmrg} 488fe8aea9eSmrg 48942542f5fSchristosstatic int sna_video_sprite_put_image(ddPutImage_ARGS) 49003b705cfSriastradh{ 49103b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 49203b705cfSriastradh struct sna *sna = video->sna; 49342542f5fSchristos xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 49403b705cfSriastradh RegionRec clip; 495fe8aea9eSmrg BoxRec draw_extents; 49642542f5fSchristos int ret, i; 49703b705cfSriastradh 498fe8aea9eSmrg init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h); 499fe8aea9eSmrg draw_extents = clip.extents; 50003b705cfSriastradh 50103b705cfSriastradh DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop)); 502fe8aea9eSmrg if (!video->AlwaysOnTop) { 503fe8aea9eSmrg ValidateGC(draw, gc); 50403b705cfSriastradh RegionIntersect(&clip, &clip, gc->pCompositeClip); 505fe8aea9eSmrg } 50603b705cfSriastradh 50703b705cfSriastradh DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n", 50803b705cfSriastradh __FUNCTION__, 50903b705cfSriastradh src_x, src_y, src_w, src_h, 51003b705cfSriastradh drw_x, drw_y, drw_w, drw_h, 51103b705cfSriastradh format->id, width, height, sync)); 51203b705cfSriastradh 51303b705cfSriastradh DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__, 51442542f5fSchristos region_num_rects(&clip), 51503b705cfSriastradh clip.extents.x1, clip.extents.y1, 51603b705cfSriastradh clip.extents.x2, clip.extents.y2)); 51703b705cfSriastradh 51842542f5fSchristos if (RegionNil(&clip)) { 51942542f5fSchristos ret = Success; 52042542f5fSchristos goto err; 52142542f5fSchristos } 52203b705cfSriastradh 523fe8aea9eSmrg for (i = 0; i < video->sna->mode.num_real_crtc; i++) { 52442542f5fSchristos xf86CrtcPtr crtc = config->crtc[i]; 52542542f5fSchristos struct sna_video_frame frame; 526fe8aea9eSmrg const int pipe = sna_crtc_pipe(crtc); 527fe8aea9eSmrg bool hw_scaling = has_hw_scaling(sna, video); 52842542f5fSchristos INT32 x1, x2, y1, y2; 52942542f5fSchristos Rotation rotation; 530fe8aea9eSmrg RegionRec reg; 531fe8aea9eSmrg BoxRec dst; 532fe8aea9eSmrg bool cache_bo; 53303b705cfSriastradh 534fe8aea9eSmrgretry: 535fe8aea9eSmrg dst = draw_extents; 53642542f5fSchristos 53742542f5fSchristos sna_video_frame_init(video, format->id, width, height, &frame); 53842542f5fSchristos 53942542f5fSchristos reg.extents = crtc->bounds; 54042542f5fSchristos reg.data = NULL; 54142542f5fSchristos RegionIntersect(®, ®, &clip); 54242542f5fSchristos if (RegionNil(®)) { 54342542f5fSchristosoff: 544fe8aea9eSmrg assert(pipe < ARRAY_SIZE(video->bo)); 54542542f5fSchristos if (video->bo[pipe]) { 54642542f5fSchristos struct local_mode_set_plane s; 54742542f5fSchristos memset(&s, 0, sizeof(s)); 548fe8aea9eSmrg s.plane_id = sna_crtc_to_sprite(crtc, video->idx); 54942542f5fSchristos if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 55042542f5fSchristos xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR, 55142542f5fSchristos "failed to disable plane\n"); 55242542f5fSchristos video->bo[pipe] = NULL; 55342542f5fSchristos } 55442542f5fSchristos continue; 55542542f5fSchristos } 55603b705cfSriastradh 55742542f5fSchristos x1 = src_x; 55842542f5fSchristos x2 = src_x + src_w; 55942542f5fSchristos y1 = src_y; 56042542f5fSchristos y2 = src_y + src_h; 56142542f5fSchristos 56242542f5fSchristos ret = xf86XVClipVideoHelper(&dst, &x1, &x2, &y1, &y2, 56342542f5fSchristos ®, frame.width, frame.height); 56442542f5fSchristos RegionUninit(®); 56542542f5fSchristos if (!ret) 56642542f5fSchristos goto off; 56742542f5fSchristos 56842542f5fSchristos frame.src.x1 = x1 >> 16; 56942542f5fSchristos frame.src.y1 = y1 >> 16; 57042542f5fSchristos frame.src.x2 = (x2 + 0xffff) >> 16; 57142542f5fSchristos frame.src.y2 = (y2 + 0xffff) >> 16; 57242542f5fSchristos 57342542f5fSchristos frame.image.x1 = frame.src.x1 & ~1; 57442542f5fSchristos frame.image.x2 = ALIGN(frame.src.x2, 2); 57542542f5fSchristos if (is_planar_fourcc(frame.id)) { 57642542f5fSchristos frame.image.y1 = frame.src.y1 & ~1; 57742542f5fSchristos frame.image.y2 = ALIGN(frame.src.y2, 2); 57842542f5fSchristos } else { 57942542f5fSchristos frame.image.y1 = frame.src.y1; 58042542f5fSchristos frame.image.y2 = frame.src.y2; 58103b705cfSriastradh } 58203b705cfSriastradh 58342542f5fSchristos /* if sprite can't handle rotation natively, store it for the copy func */ 58442542f5fSchristos rotation = RR_Rotate_0; 585fe8aea9eSmrg if (!sna_crtc_set_sprite_rotation(crtc, video->idx, crtc->rotation)) { 586fe8aea9eSmrg sna_crtc_set_sprite_rotation(crtc, video->idx, RR_Rotate_0); 58742542f5fSchristos rotation = crtc->rotation; 58842542f5fSchristos } 58942542f5fSchristos sna_video_frame_set_rotation(video, &frame, rotation); 59042542f5fSchristos 59142542f5fSchristos if (xvmc_passthrough(format->id)) { 59242542f5fSchristos DBG(("%s: using passthough, name=%d\n", 59342542f5fSchristos __FUNCTION__, *(uint32_t *)buf)); 59442542f5fSchristos 59542542f5fSchristos if (*(uint32_t*)buf == 0) 59642542f5fSchristos goto err; 59742542f5fSchristos 59842542f5fSchristos frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf); 59942542f5fSchristos if (frame.bo == NULL) { 60042542f5fSchristos ret = BadAlloc; 60142542f5fSchristos goto err; 60242542f5fSchristos } 60342542f5fSchristos 60442542f5fSchristos if (kgem_bo_size(frame.bo) < frame.size) { 60542542f5fSchristos DBG(("%s: bo size=%d, expected=%d\n", 60642542f5fSchristos __FUNCTION__, kgem_bo_size(frame.bo), frame.size)); 60742542f5fSchristos kgem_bo_destroy(&sna->kgem, frame.bo); 60842542f5fSchristos ret = BadAlloc; 60942542f5fSchristos goto err; 61042542f5fSchristos } 61142542f5fSchristos 61242542f5fSchristos frame.image.x1 = 0; 61342542f5fSchristos frame.image.y1 = 0; 61442542f5fSchristos frame.image.x2 = frame.width; 61542542f5fSchristos frame.image.y2 = frame.height; 616fe8aea9eSmrg 617fe8aea9eSmrg cache_bo = false; 61842542f5fSchristos } else { 61942542f5fSchristos frame.bo = sna_video_buffer(video, &frame); 62042542f5fSchristos if (frame.bo == NULL) { 62142542f5fSchristos DBG(("%s: failed to allocate video bo\n", __FUNCTION__)); 62242542f5fSchristos ret = BadAlloc; 62342542f5fSchristos goto err; 62442542f5fSchristos } 62542542f5fSchristos 62642542f5fSchristos if (!sna_video_copy_data(video, &frame, buf)) { 62742542f5fSchristos DBG(("%s: failed to copy video data\n", __FUNCTION__)); 62842542f5fSchristos ret = BadAlloc; 62942542f5fSchristos goto err; 63042542f5fSchristos } 631fe8aea9eSmrg 632fe8aea9eSmrg cache_bo = true; 633fe8aea9eSmrg } 634fe8aea9eSmrg 635fe8aea9eSmrg if (!hw_scaling && sna->render.video && 636fe8aea9eSmrg need_scaling(&frame, &dst)) { 637fe8aea9eSmrg ScreenPtr screen = to_screen_from_sna(sna); 638fe8aea9eSmrg PixmapPtr scaled; 639fe8aea9eSmrg RegionRec r; 640fe8aea9eSmrg 641fe8aea9eSmrg r.extents.x1 = r.extents.y1 = 0; 642fe8aea9eSmrg r.extents.x2 = dst.x2 - dst.x1; 643fe8aea9eSmrg r.extents.y2 = dst.y2 - dst.y1; 644fe8aea9eSmrg r.data = NULL; 645fe8aea9eSmrg 646fe8aea9eSmrg DBG(("%s: scaling from (%d, %d) to (%d, %d)\n", 647fe8aea9eSmrg __FUNCTION__, 648fe8aea9eSmrg frame.src.x2 - frame.src.x1, 649fe8aea9eSmrg frame.src.y2 - frame.src.y1, 650fe8aea9eSmrg r.extents.x2, r.extents.y2)); 651fe8aea9eSmrg 652fe8aea9eSmrg scaled = screen->CreatePixmap(screen, 653fe8aea9eSmrg r.extents.x2, 654fe8aea9eSmrg r.extents.y2, 655fe8aea9eSmrg 24, 656fe8aea9eSmrg CREATE_PIXMAP_USAGE_SCRATCH); 657fe8aea9eSmrg if (scaled == NULL) { 658fe8aea9eSmrg ret = BadAlloc; 659fe8aea9eSmrg goto err; 660fe8aea9eSmrg } 661fe8aea9eSmrg 662fe8aea9eSmrg if (!sna->render.video(sna, video, &frame, &r, scaled)) { 663fe8aea9eSmrg screen->DestroyPixmap(scaled); 664fe8aea9eSmrg ret = BadAlloc; 665fe8aea9eSmrg goto err; 666fe8aea9eSmrg } 667fe8aea9eSmrg 668fe8aea9eSmrg if (cache_bo) 669fe8aea9eSmrg sna_video_buffer_fini(video); 670fe8aea9eSmrg else 671fe8aea9eSmrg kgem_bo_destroy(&sna->kgem, frame.bo); 672fe8aea9eSmrg 673fe8aea9eSmrg frame.bo = kgem_bo_reference(__sna_pixmap_get_bo(scaled)); 674fe8aea9eSmrg kgem_bo_submit(&sna->kgem, frame.bo); 675fe8aea9eSmrg 676fe8aea9eSmrg frame.id = FOURCC_RGB888; 677fe8aea9eSmrg frame.src = frame.image = r.extents; 678fe8aea9eSmrg frame.width = frame.image.x2; 679fe8aea9eSmrg frame.height = frame.image.y2; 680fe8aea9eSmrg frame.pitch[0] = frame.bo->pitch; 681fe8aea9eSmrg 682fe8aea9eSmrg screen->DestroyPixmap(scaled); 683fe8aea9eSmrg cache_bo = false; 68403b705cfSriastradh } 68503b705cfSriastradh 68642542f5fSchristos ret = Success; 68742542f5fSchristos if (!sna_video_sprite_show(sna, video, &frame, crtc, &dst)) { 68842542f5fSchristos DBG(("%s: failed to show video frame\n", __FUNCTION__)); 68942542f5fSchristos ret = BadAlloc; 69003b705cfSriastradh } 69103b705cfSriastradh 692fe8aea9eSmrg if (cache_bo) 69342542f5fSchristos sna_video_buffer_fini(video); 694fe8aea9eSmrg else 695fe8aea9eSmrg kgem_bo_destroy(&sna->kgem, frame.bo); 69642542f5fSchristos 697fe8aea9eSmrg if (ret != Success) { 698fe8aea9eSmrg /* retry with GPU scaling */ 699fe8aea9eSmrg if (hw_scaling) { 700fe8aea9eSmrg hw_scaling = false; 701fe8aea9eSmrg goto retry; 702fe8aea9eSmrg } 70342542f5fSchristos goto err; 704fe8aea9eSmrg } 70503b705cfSriastradh } 70603b705cfSriastradh 707fe8aea9eSmrg sna_video_fill_colorkey(video, &clip); 70842542f5fSchristos sna_window_set_port((WindowPtr)draw, port); 70903b705cfSriastradh 71042542f5fSchristos return Success; 71103b705cfSriastradh 71242542f5fSchristoserr: 71342542f5fSchristos#if XORG_XV_VERSION < 2 71442542f5fSchristos (void)sna_video_sprite_stop(client, port, draw); 71542542f5fSchristos#else 71642542f5fSchristos (void)sna_video_sprite_stop(port, draw); 71742542f5fSchristos#endif 71842542f5fSchristos return ret; 71903b705cfSriastradh} 72003b705cfSriastradh 72142542f5fSchristosstatic int sna_video_sprite_query(ddQueryImageAttributes_ARGS) 72203b705cfSriastradh{ 72303b705cfSriastradh struct sna_video *video = port->devPriv.ptr; 72403b705cfSriastradh struct sna_video_frame frame; 725fe8aea9eSmrg int size, tmp; 72603b705cfSriastradh 72742542f5fSchristos if (*w > video->sna->mode.max_crtc_width) 72842542f5fSchristos *w = video->sna->mode.max_crtc_width; 72942542f5fSchristos if (*h > video->sna->mode.max_crtc_height) 73042542f5fSchristos *h = video->sna->mode.max_crtc_height; 73103b705cfSriastradh 73203b705cfSriastradh if (offsets) 73303b705cfSriastradh offsets[0] = 0; 73403b705cfSriastradh 73503b705cfSriastradh switch (format->id) { 73603b705cfSriastradh case FOURCC_RGB888: 73703b705cfSriastradh case FOURCC_RGB565: 73842542f5fSchristos if (pitches) { 73942542f5fSchristos sna_video_frame_init(video, format->id, *w, *h, &frame); 74042542f5fSchristos sna_video_frame_set_rotation(video, &frame, RR_Rotate_0); 74103b705cfSriastradh pitches[0] = frame.pitch[0]; 74242542f5fSchristos } 74303b705cfSriastradh size = 4; 74403b705cfSriastradh break; 74503b705cfSriastradh 746fe8aea9eSmrg case FOURCC_NV12: 747fe8aea9eSmrg *h = (*h + 1) & ~1; 748fe8aea9eSmrg size = (*w + 3) & ~3; 749fe8aea9eSmrg if (pitches) 750fe8aea9eSmrg pitches[0] = size; 751fe8aea9eSmrg size *= *h; 752fe8aea9eSmrg if (offsets) 753fe8aea9eSmrg offsets[1] = size; 754fe8aea9eSmrg tmp = (*w + 3) & ~3; 755fe8aea9eSmrg if (pitches) 756fe8aea9eSmrg pitches[1] = tmp; 757fe8aea9eSmrg tmp *= (*h >> 1); 758fe8aea9eSmrg size += tmp; 759fe8aea9eSmrg break; 760fe8aea9eSmrg case FOURCC_AYUV: 761fe8aea9eSmrg tmp = *w << 2; 762fe8aea9eSmrg if (pitches) 763fe8aea9eSmrg pitches[0] = tmp; 764fe8aea9eSmrg size = *h * tmp; 765fe8aea9eSmrg break; 76603b705cfSriastradh default: 76703b705cfSriastradh *w = (*w + 1) & ~1; 76803b705cfSriastradh *h = (*h + 1) & ~1; 76903b705cfSriastradh 77003b705cfSriastradh size = *w << 1; 77103b705cfSriastradh if (pitches) 77203b705cfSriastradh pitches[0] = size; 77303b705cfSriastradh size *= *h; 77403b705cfSriastradh break; 77503b705cfSriastradh } 77603b705cfSriastradh 77703b705cfSriastradh return size; 77803b705cfSriastradh} 77903b705cfSriastradh 78003b705cfSriastradhstatic int sna_video_sprite_color_key(struct sna *sna) 78103b705cfSriastradh{ 78203b705cfSriastradh ScrnInfoPtr scrn = sna->scrn; 78303b705cfSriastradh int color_key; 78403b705cfSriastradh 78503b705cfSriastradh if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY, 78603b705cfSriastradh &color_key)) { 78703b705cfSriastradh } else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY, 78803b705cfSriastradh &color_key)) { 78903b705cfSriastradh } else { 79003b705cfSriastradh color_key = 79103b705cfSriastradh (1 << scrn->offset.red) | 79203b705cfSriastradh (1 << scrn->offset.green) | 79303b705cfSriastradh (((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue); 79403b705cfSriastradh } 79503b705cfSriastradh 79603b705cfSriastradh return color_key & ((1 << scrn->depth) - 1); 79703b705cfSriastradh} 79803b705cfSriastradh 799fe8aea9eSmrgstatic int sna_video_has_sprites(struct sna *sna) 80042542f5fSchristos{ 80142542f5fSchristos xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 802fe8aea9eSmrg unsigned min; 80342542f5fSchristos int i; 80442542f5fSchristos 80542542f5fSchristos DBG(("%s: num_crtc=%d\n", __FUNCTION__, sna->mode.num_real_crtc)); 80642542f5fSchristos 80742542f5fSchristos if (sna->mode.num_real_crtc == 0) 808fe8aea9eSmrg return 0; 80942542f5fSchristos 810fe8aea9eSmrg min = -1; 81142542f5fSchristos for (i = 0; i < sna->mode.num_real_crtc; i++) { 812fe8aea9eSmrg unsigned count = sna_crtc_count_sprites(config->crtc[i]); 813fe8aea9eSmrg DBG(("%s: %d sprites found on pipe %d\n", __FUNCTION__, 814fe8aea9eSmrg count, sna_crtc_pipe(config->crtc[i]))); 815fe8aea9eSmrg if (count < min) 816fe8aea9eSmrg min = count; 81742542f5fSchristos } 81842542f5fSchristos 819fe8aea9eSmrg DBG(("%s: min=%d\n", __FUNCTION__, min)); 820fe8aea9eSmrg return min; 82142542f5fSchristos} 82242542f5fSchristos 82303b705cfSriastradhvoid sna_video_sprite_setup(struct sna *sna, ScreenPtr screen) 82403b705cfSriastradh{ 82503b705cfSriastradh XvAdaptorPtr adaptor; 82603b705cfSriastradh struct sna_video *video; 82703b705cfSriastradh XvPortPtr port; 828fe8aea9eSmrg int count, i; 82903b705cfSriastradh 830fe8aea9eSmrg count = sna_video_has_sprites(sna); 831fe8aea9eSmrg if (!count) 83203b705cfSriastradh return; 83303b705cfSriastradh 83403b705cfSriastradh adaptor = sna_xv_adaptor_alloc(sna); 83503b705cfSriastradh if (!adaptor) 83603b705cfSriastradh return; 83703b705cfSriastradh 838fe8aea9eSmrg video = calloc(count, sizeof(*video)); 839fe8aea9eSmrg port = calloc(count, sizeof(*port)); 84003b705cfSriastradh if (video == NULL || port == NULL) { 84103b705cfSriastradh free(video); 84203b705cfSriastradh free(port); 84303b705cfSriastradh sna->xv.num_adaptors--; 84403b705cfSriastradh return; 84503b705cfSriastradh } 84603b705cfSriastradh 84703b705cfSriastradh adaptor->type = XvInputMask | XvImageMask; 84803b705cfSriastradh adaptor->pScreen = screen; 84903b705cfSriastradh adaptor->name = (char *)"Intel(R) Video Sprite"; 85003b705cfSriastradh adaptor->nEncodings = 1; 85103b705cfSriastradh adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec)); 85203b705cfSriastradh adaptor->pEncodings[0].id = 0; 85303b705cfSriastradh adaptor->pEncodings[0].pScreen = screen; 85403b705cfSriastradh adaptor->pEncodings[0].name = (char *)"XV_IMAGE"; 85542542f5fSchristos adaptor->pEncodings[0].width = sna->mode.max_crtc_width; 85642542f5fSchristos adaptor->pEncodings[0].height = sna->mode.max_crtc_height; 85703b705cfSriastradh adaptor->pEncodings[0].rate.numerator = 1; 85803b705cfSriastradh adaptor->pEncodings[0].rate.denominator = 1; 85903b705cfSriastradh adaptor->pFormats = formats; 86003b705cfSriastradh adaptor->nFormats = sna_xv_fixup_formats(screen, formats, 86103b705cfSriastradh ARRAY_SIZE(formats)); 86203b705cfSriastradh adaptor->nAttributes = ARRAY_SIZE(attribs); 86303b705cfSriastradh adaptor->pAttributes = (XvAttributeRec *)attribs; 864fe8aea9eSmrg 865fe8aea9eSmrg if (sna_has_sprite_format(sna, DRM_FORMAT_XYUV8888)) { 866fe8aea9eSmrg adaptor->pImages = (XvImageRec *)images_ayuv; 867fe8aea9eSmrg adaptor->nImages = ARRAY_SIZE(images_ayuv); 868fe8aea9eSmrg } else if (sna_has_sprite_format(sna, DRM_FORMAT_NV12)) { 869fe8aea9eSmrg adaptor->pImages = (XvImageRec *)images_nv12; 870fe8aea9eSmrg adaptor->nImages = ARRAY_SIZE(images_nv12); 871fe8aea9eSmrg } else if (sna_has_sprite_format(sna, DRM_FORMAT_RGB565)) { 872fe8aea9eSmrg adaptor->pImages = (XvImageRec *)images_rgb565; 873fe8aea9eSmrg adaptor->nImages = ARRAY_SIZE(images_rgb565); 874fe8aea9eSmrg } else { 875fe8aea9eSmrg adaptor->pImages = (XvImageRec *)images; 876fe8aea9eSmrg adaptor->nImages = ARRAY_SIZE(images); 877fe8aea9eSmrg } 87803b705cfSriastradh 87942542f5fSchristos#if XORG_XV_VERSION < 2 88003b705cfSriastradh adaptor->ddAllocatePort = sna_xv_alloc_port; 88103b705cfSriastradh adaptor->ddFreePort = sna_xv_free_port; 88242542f5fSchristos#endif 88303b705cfSriastradh adaptor->ddPutVideo = NULL; 88403b705cfSriastradh adaptor->ddPutStill = NULL; 88503b705cfSriastradh adaptor->ddGetVideo = NULL; 88603b705cfSriastradh adaptor->ddGetStill = NULL; 88703b705cfSriastradh adaptor->ddStopVideo = sna_video_sprite_stop; 88803b705cfSriastradh adaptor->ddSetPortAttribute = sna_video_sprite_set_attr; 88903b705cfSriastradh adaptor->ddGetPortAttribute = sna_video_sprite_get_attr; 89003b705cfSriastradh adaptor->ddQueryBestSize = sna_video_sprite_best_size; 89103b705cfSriastradh adaptor->ddPutImage = sna_video_sprite_put_image; 89203b705cfSriastradh adaptor->ddQueryImageAttributes = sna_video_sprite_query; 89303b705cfSriastradh 894fe8aea9eSmrg adaptor->nPorts = count; 89503b705cfSriastradh adaptor->pPorts = port; 89603b705cfSriastradh 897fe8aea9eSmrg for (i = 0; i < count; i++) { 898fe8aea9eSmrg port->id = FakeClientID(0); 899fe8aea9eSmrg AddResource(port->id, XvGetRTPort(), port); 900fe8aea9eSmrg port->pAdaptor = adaptor; 901fe8aea9eSmrg port->pNotify = NULL; 902fe8aea9eSmrg port->pDraw = NULL; 903fe8aea9eSmrg port->client = NULL; 904fe8aea9eSmrg port->grab.client = NULL; 905fe8aea9eSmrg port->time = currentTime; 906fe8aea9eSmrg port->devPriv.ptr = video; 907fe8aea9eSmrg 908fe8aea9eSmrg video->sna = sna; 909fe8aea9eSmrg video->idx = i; 910fe8aea9eSmrg video->alignment = 64; 911fe8aea9eSmrg video->color_key = sna_video_sprite_color_key(sna); 912fe8aea9eSmrg video->color_key_changed = ~0; 913fe8aea9eSmrg video->colorspace = 1; /* BT.709 */ 914fe8aea9eSmrg video->colorspace_changed = ~0; 915fe8aea9eSmrg video->has_color_key = true; 916fe8aea9eSmrg video->brightness = -19; /* (255/219) * -16 */ 917fe8aea9eSmrg video->contrast = 75; /* 255/219 * 64 */ 918fe8aea9eSmrg video->saturation = 146; /* 128/112 * 128 */ 919fe8aea9eSmrg video->desired_crtc = NULL; 920fe8aea9eSmrg video->gamma5 = 0xc0c0c0; 921fe8aea9eSmrg video->gamma4 = 0x808080; 922fe8aea9eSmrg video->gamma3 = 0x404040; 923fe8aea9eSmrg video->gamma2 = 0x202020; 924fe8aea9eSmrg video->gamma1 = 0x101010; 925fe8aea9eSmrg video->gamma0 = 0x080808; 926fe8aea9eSmrg RegionNull(&video->clip); 927fe8aea9eSmrg video->SyncToVblank = 1; 928fe8aea9eSmrg 929fe8aea9eSmrg port++; 930fe8aea9eSmrg video++; 931fe8aea9eSmrg } 932fe8aea9eSmrg adaptor->base_id = adaptor->pPorts[0].id; 93303b705cfSriastradh 93403b705cfSriastradh xvColorKey = MAKE_ATOM("XV_COLORKEY"); 935fe8aea9eSmrg xvColorspace = MAKE_ATOM("XV_COLORSPACE"); 93603b705cfSriastradh xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP"); 93742542f5fSchristos xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 93842542f5fSchristos 93942542f5fSchristos DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts)); 94003b705cfSriastradh} 941