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(&reg, &reg, &clip);
54242542f5fSchristos		if (RegionNil(&reg)) {
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					    &reg, frame.width, frame.height);
56442542f5fSchristos		RegionUninit(&reg);
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