1/***************************************************************************
2
3 Copyright 2000-2011 Intel Corporation.  All Rights Reserved.
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sub license, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice (including the
14 next paragraph) shall be included in all copies or substantial portions
15 of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
21 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
23 THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "sna.h"
32#include "sna_video.h"
33
34#include <xf86drm.h>
35#include <xf86xv.h>
36#include <X11/extensions/Xv.h>
37#include <fourcc.h>
38#include <i915_drm.h>
39
40#include "intel_options.h"
41
42#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
43
44#define HAS_GAMMA(sna) ((sna)->kgem.gen >= 030)
45
46static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe, xvAlwaysOnTop;
47static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
48
49/* Limits for the overlay/textured video source sizes.  The documented hardware
50 * limits are 2048x2048 or better for overlay and both of our textured video
51 * implementations.  Additionally, on the 830 and 845, larger sizes resulted in
52 * the card hanging, so we keep the limits lower there.
53 */
54#define IMAGE_MAX_WIDTH		2048
55#define IMAGE_MAX_HEIGHT	2048
56#define IMAGE_MAX_WIDTH_LEGACY	1024
57#define IMAGE_MAX_HEIGHT_LEGACY	1088
58
59static XvFormatRec Formats[] = { {15}, {16}, {24} };
60
61static const XvAttributeRec Attributes[] = {
62	{XvSettable | XvGettable, 0, (1 << 24) - 1, (char *)"XV_COLORKEY"},
63	{XvSettable | XvGettable, 0, 1, (char *)"XV_ALWAYS_ON_TOP"},
64	{XvSettable | XvGettable, -128, 127, (char *)"XV_BRIGHTNESS"},
65	{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"},
66	{XvSettable | XvGettable, 0, 1023, (char *)"XV_SATURATION"},
67	{XvSettable | XvGettable, -1, 1, (char *)"XV_PIPE"},
68#define NUM_ATTRIBUTES 6
69
70	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA0"},
71	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA1"},
72	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA2"},
73	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA3"},
74	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA4"},
75	{XvSettable | XvGettable, 0, 0xffffff, (char *)"XV_GAMMA5"}
76#define GAMMA_ATTRIBUTES 6
77};
78
79static const XvImageRec Images[] = {
80	XVIMAGE_YUY2,
81	XVIMAGE_YV12,
82	XVIMAGE_I420,
83	XVIMAGE_UYVY,
84	XVMC_YUV
85};
86
87/* kernel modesetting overlay functions */
88static bool sna_has_overlay(struct sna *sna)
89{
90	struct drm_i915_getparam gp;
91	int has_overlay = 0;
92	int ret;
93
94	VG_CLEAR(gp);
95	gp.param = I915_PARAM_HAS_OVERLAY;
96	gp.value = &has_overlay;
97	ret = drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp);
98	return ret == 0 && has_overlay;
99}
100
101static bool sna_video_overlay_update_attrs(struct sna_video *video)
102{
103	struct drm_intel_overlay_attrs attrs;
104
105	DBG(("%s()\n", __FUNCTION__));
106
107	attrs.flags = I915_OVERLAY_UPDATE_ATTRS;
108	attrs.brightness = video->brightness;
109	attrs.contrast = video->contrast;
110	attrs.saturation = video->saturation;
111	attrs.color_key = video->color_key;
112	attrs.gamma0 = video->gamma0;
113	attrs.gamma1 = video->gamma1;
114	attrs.gamma2 = video->gamma2;
115	attrs.gamma3 = video->gamma3;
116	attrs.gamma4 = video->gamma4;
117	attrs.gamma5 = video->gamma5;
118
119	if (video->AlwaysOnTop)
120		attrs.flags |= 1<<2;
121
122	return drmIoctl(video->sna->kgem.fd, DRM_IOCTL_I915_OVERLAY_ATTRS, &attrs) == 0;
123}
124
125static int sna_video_overlay_stop(ddStopVideo_ARGS)
126{
127	struct sna_video *video = port->devPriv.ptr;
128	struct sna *sna = video->sna;
129	struct drm_intel_overlay_put_image request;
130
131	DBG(("%s()\n", __FUNCTION__));
132
133	REGION_EMPTY(to_screen_from_sna(sna), &video->clip);
134
135	request.flags = 0;
136	(void)drmIoctl(sna->kgem.fd,
137		       DRM_IOCTL_I915_OVERLAY_PUT_IMAGE,
138		       &request);
139
140	if (video->bo[0])
141		kgem_bo_destroy(&sna->kgem, video->bo[0]);
142	video->bo[0] = NULL;
143
144	sna_video_free_buffers(video);
145	sna_window_set_port((WindowPtr)draw, NULL);
146	return Success;
147}
148
149static int
150sna_video_overlay_set_attribute(ddSetPortAttribute_ARGS)
151{
152	struct sna_video *video = port->devPriv.ptr;
153	struct sna *sna = video->sna;
154
155	DBG(("%s: set(%lx) to %d\n", __FUNCTION__, (long)attribute, (int)value));
156	if (attribute == xvBrightness) {
157		if ((value < -128) || (value > 127))
158			return BadValue;
159		DBG(("%s: BRIGHTNESS %d -> %d\n", __FUNCTION__,
160		     video->contrast, (int)value));
161		video->brightness = value;
162	} else if (attribute == xvContrast) {
163		if ((value < 0) || (value > 255))
164			return BadValue;
165		DBG(("%s: CONTRAST %d -> %d\n", __FUNCTION__,
166		     video->contrast, (int)value));
167		video->contrast = value;
168	} else if (attribute == xvSaturation) {
169		if ((value < 0) || (value > 1023))
170			return BadValue;
171		DBG(("%s: SATURATION %d -> %d\n", __FUNCTION__,
172		     video->saturation, (int)value));
173		video->saturation = value;
174	} else if (attribute == xvPipe) {
175		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
176		if ((value < -1) || (value >= xf86_config->num_crtc))
177			return BadValue;
178		if (value < 0)
179			video->desired_crtc = NULL;
180		else
181			video->desired_crtc = xf86_config->crtc[value];
182	} else if (attribute == xvAlwaysOnTop) {
183		DBG(("%s: ALWAYS_ON_TOP: %d -> %d\n", __FUNCTION__,
184		     video->AlwaysOnTop, !!value));
185		video->AlwaysOnTop = !!value;
186	} else if (attribute == xvGamma0 && HAS_GAMMA(sna)) {
187		video->gamma0 = value;
188	} else if (attribute == xvGamma1 && HAS_GAMMA(sna)) {
189		video->gamma1 = value;
190	} else if (attribute == xvGamma2 && HAS_GAMMA(sna)) {
191		video->gamma2 = value;
192	} else if (attribute == xvGamma3 && HAS_GAMMA(sna)) {
193		video->gamma3 = value;
194	} else if (attribute == xvGamma4 && HAS_GAMMA(sna)) {
195		video->gamma4 = value;
196	} else if (attribute == xvGamma5 && HAS_GAMMA(sna)) {
197		video->gamma5 = value;
198	} else if (attribute == xvColorKey) {
199		video->color_key = value;
200		RegionEmpty(&video->clip);
201		DBG(("COLORKEY\n"));
202	} else
203		return BadMatch;
204
205	if ((attribute == xvGamma0 ||
206	     attribute == xvGamma1 ||
207	     attribute == xvGamma2 ||
208	     attribute == xvGamma3 ||
209	     attribute == xvGamma4 ||
210	     attribute == xvGamma5) && HAS_GAMMA(sna)) {
211		DBG(("%s: GAMMA\n", __FUNCTION__));
212	}
213
214	if (!sna_video_overlay_update_attrs(video))
215		return BadValue;
216
217	return Success;
218}
219
220static int
221sna_video_overlay_get_attribute(ddGetPortAttribute_ARGS)
222{
223	struct sna_video *video = port->devPriv.ptr;
224	struct sna *sna = video->sna;
225
226	if (attribute == xvBrightness) {
227		*value = video->brightness;
228	} else if (attribute == xvContrast) {
229		*value = video->contrast;
230	} else if (attribute == xvSaturation) {
231		*value = video->saturation;
232	} else if (attribute == xvPipe) {
233		int c;
234		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(sna->scrn);
235		for (c = 0; c < xf86_config->num_crtc; c++)
236			if (xf86_config->crtc[c] == video->desired_crtc)
237				break;
238		if (c == xf86_config->num_crtc)
239			c = -1;
240		*value = c;
241	} else if (attribute == xvAlwaysOnTop) {
242		*value = video->AlwaysOnTop;
243	} else if (attribute == xvGamma0 && HAS_GAMMA(sna)) {
244		*value = video->gamma0;
245	} else if (attribute == xvGamma1 && HAS_GAMMA(sna)) {
246		*value = video->gamma1;
247	} else if (attribute == xvGamma2 && HAS_GAMMA(sna)) {
248		*value = video->gamma2;
249	} else if (attribute == xvGamma3 && HAS_GAMMA(sna)) {
250		*value = video->gamma3;
251	} else if (attribute == xvGamma4 && HAS_GAMMA(sna)) {
252		*value = video->gamma4;
253	} else if (attribute == xvGamma5 && HAS_GAMMA(sna)) {
254		*value = video->gamma5;
255	} else if (attribute == xvColorKey) {
256		*value = video->color_key;
257	} else
258		return BadMatch;
259
260	return Success;
261}
262
263static int
264sna_video_overlay_best_size(ddQueryBestSize_ARGS)
265{
266	struct sna_video *video = port->devPriv.ptr;
267	struct sna *sna = video->sna;
268	short max_w, max_h;
269
270	if (vid_w > (drw_w << 1) || vid_h > (drw_h << 1)){
271		drw_w = vid_w >> 1;
272		drw_h = vid_h >> 1;
273	}
274
275	if (sna->kgem.gen < 021) {
276		max_w = IMAGE_MAX_WIDTH_LEGACY;
277		max_h = IMAGE_MAX_HEIGHT_LEGACY;
278	} else {
279		max_w = IMAGE_MAX_WIDTH;
280		max_h = IMAGE_MAX_HEIGHT;
281	}
282
283	while (drw_w > max_w || drw_h > max_h) {
284		drw_w >>= 1;
285		drw_h >>= 1;
286	}
287
288	*p_w = drw_w;
289	*p_h = drw_h;
290	return Success;
291}
292
293static void
294update_dst_box_to_crtc_coords(struct sna *sna, xf86CrtcPtr crtc, BoxPtr dstBox)
295{
296	ScrnInfoPtr scrn = sna->scrn;
297	int tmp;
298
299	/* for overlay, we should take it from crtc's screen
300	 * coordinate to current crtc's display mode.
301	 * yeah, a bit confusing.
302	 */
303	switch (crtc->rotation & 0xf) {
304	case RR_Rotate_0:
305		dstBox->x1 -= crtc->x;
306		dstBox->x2 -= crtc->x;
307		dstBox->y1 -= crtc->y;
308		dstBox->y2 -= crtc->y;
309		break;
310	case RR_Rotate_90:
311		tmp = dstBox->x1;
312		dstBox->x1 = dstBox->y1 - crtc->x;
313		dstBox->y1 = scrn->virtualX - tmp - crtc->y;
314		tmp = dstBox->x2;
315		dstBox->x2 = dstBox->y2 - crtc->x;
316		dstBox->y2 = scrn->virtualX - tmp - crtc->y;
317		tmp = dstBox->y1;
318		dstBox->y1 = dstBox->y2;
319		dstBox->y2 = tmp;
320		break;
321	case RR_Rotate_180:
322		tmp = dstBox->x1;
323		dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x;
324		dstBox->x2 = scrn->virtualX - tmp - crtc->x;
325		tmp = dstBox->y1;
326		dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y;
327		dstBox->y2 = scrn->virtualY - tmp - crtc->y;
328		break;
329	case RR_Rotate_270:
330		tmp = dstBox->x1;
331		dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x;
332		dstBox->y1 = tmp - crtc->y;
333		tmp = dstBox->x2;
334		dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x;
335		dstBox->y2 = tmp - crtc->y;
336		tmp = dstBox->x1;
337		dstBox->x1 = dstBox->x2;
338		dstBox->x2 = tmp;
339		break;
340	}
341
342	return;
343}
344
345static bool
346sna_video_overlay_show(struct sna *sna,
347		       struct sna_video *video,
348		       struct sna_video_frame *frame,
349		       xf86CrtcPtr crtc,
350		       BoxPtr dstBox,
351		       short src_w, short src_h,
352		       short drw_w, short drw_h)
353{
354	struct drm_intel_overlay_put_image request;
355	bool planar = is_planar_fourcc(frame->id);
356	float scale;
357
358	DBG(("%s: src=(%dx%d), dst=(%dx%d)\n", __FUNCTION__,
359	     src_w, src_h, drw_w, drw_h));
360
361	update_dst_box_to_crtc_coords(sna, crtc, dstBox);
362	if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
363		int tmp;
364
365		tmp = frame->width;
366		frame->width = frame->height;
367		frame->height = tmp;
368
369		tmp = drw_w;
370		drw_w = drw_h;
371		drw_h = tmp;
372
373		tmp = src_w;
374		src_w = src_h;
375		src_h = tmp;
376	}
377
378	memset(&request, 0, sizeof(request));
379	request.flags = I915_OVERLAY_ENABLE;
380
381	request.bo_handle = frame->bo->handle;
382	if (planar) {
383		request.stride_Y = frame->pitch[1];
384		request.stride_UV = frame->pitch[0];
385	} else {
386		request.stride_Y = frame->pitch[0];
387		request.stride_UV = 0;
388	}
389	request.offset_Y = 0;
390	request.offset_U = frame->UBufOffset;
391	request.offset_V = frame->VBufOffset;
392	DBG(("%s: handle=%d, stride_Y=%d, stride_UV=%d, off_Y: %i, off_U: %i, off_V: %i\n",
393	     __FUNCTION__,
394	     request.bo_handle, request.stride_Y, request.stride_UV,
395	     request.offset_Y, request.offset_U, request.offset_V));
396
397	request.crtc_id = sna_crtc_id(crtc);
398	request.dst_x = dstBox->x1;
399	request.dst_y = dstBox->y1;
400	request.dst_width = dstBox->x2 - dstBox->x1;
401	request.dst_height = dstBox->y2 - dstBox->y1;
402
403	DBG(("%s: crtc=%d, dst=(%d, %d)x(%d, %d)\n",
404	     __FUNCTION__, request.crtc_id,
405	     request.dst_x, request.dst_y,
406	     request.dst_width, request.dst_height));
407
408	request.src_width = frame->width;
409	request.src_height = frame->height;
410	/* adjust src dimensions */
411	if (request.dst_height > 1) {
412		scale = ((float)request.dst_height - 1) / ((float)drw_h - 1);
413		request.src_scan_height = src_h * scale;
414	} else
415		request.src_scan_height = 1;
416
417	if (request.dst_width > 1) {
418		scale = ((float)request.dst_width - 1) / ((float)drw_w - 1);
419		request.src_scan_width = src_w * scale;
420	} else
421		request.src_scan_width = 1;
422
423	DBG(("%s: src=(%d, %d) scan=(%d, %d)\n",
424	     __FUNCTION__,
425	     request.src_width, request.src_height,
426	     request.src_scan_width, request.src_scan_height));
427
428	if (planar) {
429		request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420;
430	} else {
431		request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422;
432		if (frame->id == FOURCC_UYVY)
433			request.flags |= I915_OVERLAY_Y_SWAP;
434	}
435
436	DBG(("%s: flags=%x\n", __FUNCTION__, request.flags));
437
438	if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_OVERLAY_PUT_IMAGE, &request)) {
439		DBG(("%s: Putimage failed\n", __FUNCTION__));
440		return false;
441	}
442
443	if (video->bo[0] != frame->bo) {
444		if (video->bo[0])
445			kgem_bo_destroy(&sna->kgem, video->bo[0]);
446		video->bo[0] = kgem_bo_reference(frame->bo);
447	}
448
449	return true;
450}
451
452static int
453sna_video_overlay_put_image(ddPutImage_ARGS)
454{
455	struct sna_video *video = port->devPriv.ptr;
456	struct sna *sna = video->sna;
457	struct sna_video_frame frame;
458	xf86CrtcPtr crtc;
459	BoxRec dstBox;
460	RegionRec clip;
461	int ret;
462
463	DBG(("%s: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d), width %d, height %d\n",
464	     __FUNCTION__,
465	     src_x, src_y, src_w, src_h, drw_x,
466	     drw_y, drw_w, drw_h, width, height));
467
468	/* If dst width and height are less than 1/8th the src size, the
469	 * src/dst scale factor becomes larger than 8 and doesn't fit in
470	 * the scale register. */
471	if (src_w >= (drw_w * 8))
472		drw_w = src_w / 7;
473
474	if (src_h >= (drw_h * 8))
475		drw_h = src_h / 7;
476
477	init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
478
479	DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
480	if (!video->AlwaysOnTop) {
481		ValidateGC(draw, gc);
482		RegionIntersect(&clip, &clip, gc->pCompositeClip);
483	}
484	if (box_empty(&clip.extents))
485		goto invisible;
486
487	DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n",
488	     __FUNCTION__,
489	     src_x, src_y, src_w, src_h,
490	     drw_x, drw_y, drw_w, drw_h,
491	     format->id, width, height, sync));
492
493	DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__,
494	     region_num_rects(&clip),
495	     clip.extents.x1, clip.extents.y1,
496	     clip.extents.x2, clip.extents.y2));
497
498	sna_video_frame_init(video, format->id, width, height, &frame);
499
500	if (!sna_video_clip_helper(video, &frame, &crtc, &dstBox,
501				   src_x, src_y, draw->x + drw_x, draw->y + drw_y,
502				   src_w, src_h, drw_w, drw_h,
503				   &clip))
504		goto invisible;
505
506	if (!crtc)
507		goto invisible;
508
509	/* overlay can't handle rotation natively, store it for the copy func */
510	sna_video_frame_set_rotation(video, &frame, crtc->rotation);
511
512	if (xvmc_passthrough(format->id)) {
513		DBG(("%s: using passthough, name=%d\n",
514		     __FUNCTION__, *(uint32_t *)buf));
515
516		if (*(uint32_t*)buf == 0)
517			goto invisible;
518
519		frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf);
520		if (frame.bo == NULL) {
521			DBG(("%s: failed to open bo\n", __FUNCTION__));
522			return BadAlloc;
523		}
524
525		if (kgem_bo_size(frame.bo) < frame.size) {
526			DBG(("%s: bo size=%d, expected=%d\n",
527			     __FUNCTION__, kgem_bo_size(frame.bo), frame.size));
528			kgem_bo_destroy(&sna->kgem, frame.bo);
529			return BadAlloc;
530		}
531
532		frame.image.x1 = 0;
533		frame.image.y1 = 0;
534		frame.image.x2 = frame.width;
535		frame.image.y2 = frame.height;
536	} else {
537		frame.bo = sna_video_buffer(video, &frame);
538		if (frame.bo == NULL) {
539			DBG(("%s: failed to allocate video bo\n", __FUNCTION__));
540			return BadAlloc;
541		}
542
543		if (!sna_video_copy_data(video, &frame, buf)) {
544			DBG(("%s: failed to copy video data\n", __FUNCTION__));
545			return BadAlloc;
546		}
547	}
548
549	ret = Success;
550	if (sna_video_overlay_show
551	    (sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
552		sna_video_fill_colorkey(video, &clip);
553		sna_window_set_port((WindowPtr)draw, port);
554	} else {
555		DBG(("%s: failed to show video frame\n", __FUNCTION__));
556		ret = BadAlloc;
557	}
558
559	frame.bo->domain = DOMAIN_NONE;
560	if (xvmc_passthrough(format->id))
561		kgem_bo_destroy(&sna->kgem, frame.bo);
562	else
563		sna_video_buffer_fini(video);
564
565	return ret;
566
567invisible:
568	/*
569	 * If the video isn't visible on any CRTC, turn it off
570	 */
571#if XORG_XV_VERSION < 2
572	sna_video_overlay_stop(client, port, draw);
573#else
574	sna_video_overlay_stop(port, draw);
575#endif
576	return Success;
577}
578
579static int
580sna_video_overlay_query(ddQueryImageAttributes_ARGS)
581{
582	struct sna_video *video = port->devPriv.ptr;
583	struct sna_video_frame frame;
584	struct sna *sna = video->sna;
585	int size, tmp;
586
587	DBG(("%s: w is %d, h is %d\n", __FUNCTION__, *w, *h));
588
589	if (sna->kgem.gen < 021) {
590		if (*w > IMAGE_MAX_WIDTH_LEGACY)
591			*w = IMAGE_MAX_WIDTH_LEGACY;
592		if (*h > IMAGE_MAX_HEIGHT_LEGACY)
593			*h = IMAGE_MAX_HEIGHT_LEGACY;
594	} else {
595		if (*w > IMAGE_MAX_WIDTH)
596			*w = IMAGE_MAX_WIDTH;
597		if (*h > IMAGE_MAX_HEIGHT)
598			*h = IMAGE_MAX_HEIGHT;
599	}
600
601	*w = (*w + 1) & ~1;
602	if (offsets)
603		offsets[0] = 0;
604
605	switch (format->id) {
606	case FOURCC_XVMC:
607		*h = (*h + 1) & ~1;
608		sna_video_frame_init(video, format->id, *w, *h, &frame);
609		sna_video_frame_set_rotation(video, &frame, RR_Rotate_0);
610		size = sizeof(uint32_t);
611		if (pitches) {
612			pitches[0] = frame.pitch[1];
613			pitches[1] = frame.pitch[0];
614			pitches[2] = frame.pitch[0];
615		}
616		if (offsets) {
617			offsets[1] = frame.UBufOffset;
618			offsets[2] = frame.VBufOffset;
619		}
620		break;
621
622		/* IA44 is for XvMC only */
623	case FOURCC_IA44:
624	case FOURCC_AI44:
625		if (pitches)
626			pitches[0] = *w;
627		size = *w * *h;
628		break;
629	case FOURCC_YV12:
630	case FOURCC_I420:
631		*h = (*h + 1) & ~1;
632		size = (*w + 3) & ~3;
633		if (pitches)
634			pitches[0] = size;
635		size *= *h;
636		if (offsets)
637			offsets[1] = size;
638		tmp = ((*w >> 1) + 3) & ~3;
639		if (pitches)
640			pitches[1] = pitches[2] = tmp;
641		tmp *= (*h >> 1);
642		size += tmp;
643		if (offsets)
644			offsets[2] = size;
645		size += tmp;
646#if 0
647		if (pitches)
648			ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n",
649			       pitches[0], pitches[1], pitches[2]);
650		if (offsets)
651			ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1],
652			       offsets[2]);
653		if (offsets)
654			ErrorF("size is %d\n", size);
655#endif
656		break;
657	case FOURCC_UYVY:
658	case FOURCC_YUY2:
659	default:
660		size = *w << 1;
661		if (pitches)
662			pitches[0] = size;
663		size *= *h;
664		break;
665	}
666
667	return size;
668}
669
670static int sna_video_overlay_color_key(struct sna *sna)
671{
672	ScrnInfoPtr scrn = sna->scrn;
673	int color_key;
674
675	if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY,
676				 &color_key)) {
677	} else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY,
678					&color_key)) {
679	} else {
680		color_key =
681		    (1 << scrn->offset.red) |
682		    (1 << scrn->offset.green) |
683		    (((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue);
684	}
685
686	return color_key & ((1 << scrn->depth) - 1);
687}
688
689void sna_video_overlay_setup(struct sna *sna, ScreenPtr screen)
690{
691	XvAdaptorPtr adaptor;
692	struct sna_video *video;
693	XvPortPtr port;
694
695	if (sna->flags & SNA_IS_HOSTED)
696		return;
697
698	if (!sna_has_overlay(sna))
699		return;
700
701	DBG(("%s()\n", __FUNCTION__));
702
703	adaptor = sna_xv_adaptor_alloc(sna);
704	if (adaptor == NULL)
705		return;
706
707	video = calloc(1, sizeof(*video));
708	port = calloc(1, sizeof(*port));
709	if (video == NULL || port == NULL) {
710		free(video);
711		free(port);
712		sna->xv.num_adaptors--;
713		return;
714	}
715
716	adaptor->type = XvInputMask | XvImageMask;
717	adaptor->pScreen = screen;
718	adaptor->name = (char *)"Intel(R) Video Overlay";
719	adaptor->nEncodings = 1;
720	adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec));
721	adaptor->pEncodings[0].id = 0;
722	adaptor->pEncodings[0].pScreen = screen;
723	adaptor->pEncodings[0].name = (char *)"XV_IMAGE";
724	adaptor->pEncodings[0].width = sna->kgem.gen < 021 ? IMAGE_MAX_WIDTH_LEGACY : IMAGE_MAX_WIDTH;
725	adaptor->pEncodings[0].height = sna->kgem.gen < 021 ? IMAGE_MAX_HEIGHT_LEGACY : IMAGE_MAX_HEIGHT;
726	adaptor->pEncodings[0].rate.numerator = 1;
727	adaptor->pEncodings[0].rate.denominator = 1;
728	adaptor->pFormats = Formats;
729	adaptor->nFormats = sna_xv_fixup_formats(screen, Formats,
730						 ARRAY_SIZE(Formats));
731	adaptor->nAttributes = NUM_ATTRIBUTES;
732	if (HAS_GAMMA(sna))
733		adaptor->nAttributes += GAMMA_ATTRIBUTES;
734	adaptor->pAttributes = (XvAttributeRec *)Attributes;
735	adaptor->nImages = ARRAY_SIZE(Images);
736	adaptor->pImages = (XvImageRec *)Images;
737#if XORG_XV_VERSION < 2
738	adaptor->ddAllocatePort = sna_xv_alloc_port;
739	adaptor->ddFreePort = sna_xv_free_port;
740#endif
741	adaptor->ddPutVideo = NULL;
742	adaptor->ddPutStill = NULL;
743	adaptor->ddGetVideo = NULL;
744	adaptor->ddGetStill = NULL;
745	adaptor->ddStopVideo = sna_video_overlay_stop;
746	adaptor->ddSetPortAttribute = sna_video_overlay_set_attribute;
747	adaptor->ddGetPortAttribute = sna_video_overlay_get_attribute;
748	adaptor->ddQueryBestSize = sna_video_overlay_best_size;
749	adaptor->ddPutImage = sna_video_overlay_put_image;
750	adaptor->ddQueryImageAttributes = sna_video_overlay_query;
751
752	adaptor->nPorts = 1;
753	adaptor->pPorts = port;
754	adaptor->base_id = port->id = FakeClientID(0);
755	AddResource(port->id, XvGetRTPort(), port);
756
757	port->pAdaptor = adaptor;
758	port->pNotify =  NULL;
759	port->pDraw =  NULL;
760	port->client =  NULL;
761	port->grab.client =  NULL;
762	port->time = currentTime;
763	port->devPriv.ptr = video;
764
765	video->sna = sna;
766	if (sna->kgem.gen >= 040)
767		/* Actually the alignment is 64 bytes, too. But the
768		 * stride must be at least 512 bytes. Take the easy fix
769		 * and align on 512 bytes unconditionally. */
770		video->alignment = 512;
771	else if (sna->kgem.gen < 021)
772		/* Harsh, errata on these chipsets limit the stride
773		 * to be a multiple of 256 bytes.
774		 */
775		video->alignment = 256;
776	else
777		video->alignment = 64;
778	video->color_key = sna_video_overlay_color_key(sna);
779	video->brightness = -19;	/* (255/219) * -16 */
780	video->contrast = 75;	/* 255/219 * 64 */
781	video->saturation = 146;	/* 128/112 * 128 */
782	video->desired_crtc = NULL;
783	video->gamma5 = 0xc0c0c0;
784	video->gamma4 = 0x808080;
785	video->gamma3 = 0x404040;
786	video->gamma2 = 0x202020;
787	video->gamma1 = 0x101010;
788	video->gamma0 = 0x080808;
789	RegionNull(&video->clip);
790
791	xvColorKey = MAKE_ATOM("XV_COLORKEY");
792	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
793	xvContrast = MAKE_ATOM("XV_CONTRAST");
794	xvSaturation = MAKE_ATOM("XV_SATURATION");
795
796	/* Allow the pipe to be switched from pipe A to B when in clone mode */
797	xvPipe = MAKE_ATOM("XV_PIPE");
798	xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP");
799
800	if (HAS_GAMMA(sna)) {
801		xvGamma0 = MAKE_ATOM("XV_GAMMA0");
802		xvGamma1 = MAKE_ATOM("XV_GAMMA1");
803		xvGamma2 = MAKE_ATOM("XV_GAMMA2");
804		xvGamma3 = MAKE_ATOM("XV_GAMMA3");
805		xvGamma4 = MAKE_ATOM("XV_GAMMA4");
806		xvGamma5 = MAKE_ATOM("XV_GAMMA5");
807	}
808
809	sna_video_overlay_update_attrs(video);
810
811	DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts));
812}
813