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(scrn->pScreen, &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	clip.extents.x1 = draw->x + drw_x;
478	clip.extents.y1 = draw->y + drw_y;
479	clip.extents.x2 = clip.extents.x1 + drw_w;
480	clip.extents.y2 = clip.extents.y1 + drw_h;
481	clip.data = NULL;
482
483	DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
484	if (!video->AlwaysOnTop)
485		RegionIntersect(&clip, &clip, gc->pCompositeClip);
486	if (box_empty(&clip.extents))
487		goto invisible;
488
489	DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n",
490	     __FUNCTION__,
491	     src_x, src_y, src_w, src_h,
492	     drw_x, drw_y, drw_w, drw_h,
493	     format->id, width, height, sync));
494
495	DBG(("%s: region %d:(%d, %d), (%d, %d)\n", __FUNCTION__,
496	     region_num_rects(&clip),
497	     clip.extents.x1, clip.extents.y1,
498	     clip.extents.x2, clip.extents.y2));
499
500	sna_video_frame_init(video, format->id, width, height, &frame);
501
502	if (!sna_video_clip_helper(video, &frame, &crtc, &dstBox,
503				   src_x, src_y, draw->x + drw_x, draw->y + drw_y,
504				   src_w, src_h, drw_w, drw_h,
505				   &clip))
506		goto invisible;
507
508	if (!crtc)
509		goto invisible;
510
511	/* overlay can't handle rotation natively, store it for the copy func */
512	sna_video_frame_set_rotation(video, &frame, crtc->rotation);
513
514	if (xvmc_passthrough(format->id)) {
515		DBG(("%s: using passthough, name=%d\n",
516		     __FUNCTION__, *(uint32_t *)buf));
517
518		if (*(uint32_t*)buf == 0)
519			goto invisible;
520
521		frame.bo = kgem_create_for_name(&sna->kgem, *(uint32_t*)buf);
522		if (frame.bo == NULL) {
523			DBG(("%s: failed to open bo\n", __FUNCTION__));
524			return BadAlloc;
525		}
526
527		if (kgem_bo_size(frame.bo) < frame.size) {
528			DBG(("%s: bo size=%d, expected=%d\n",
529			     __FUNCTION__, kgem_bo_size(frame.bo), frame.size));
530			kgem_bo_destroy(&sna->kgem, frame.bo);
531			return BadAlloc;
532		}
533
534		frame.image.x1 = 0;
535		frame.image.y1 = 0;
536		frame.image.x2 = frame.width;
537		frame.image.y2 = frame.height;
538	} else {
539		frame.bo = sna_video_buffer(video, &frame);
540		if (frame.bo == NULL) {
541			DBG(("%s: failed to allocate video bo\n", __FUNCTION__));
542			return BadAlloc;
543		}
544
545		if (!sna_video_copy_data(video, &frame, buf)) {
546			DBG(("%s: failed to copy video data\n", __FUNCTION__));
547			return BadAlloc;
548		}
549	}
550
551	ret = Success;
552	if (sna_video_overlay_show
553	    (sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
554		//xf86XVFillKeyHelperDrawable(draw, video->color_key, &clip);
555		if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
556		    sna_blt_fill_boxes(sna, GXcopy,
557				       __sna_pixmap_get_bo(sna->front),
558				       sna->front->drawable.bitsPerPixel,
559				       video->color_key,
560				       region_rects(&clip),
561				       region_num_rects(&clip)))
562			RegionCopy(&video->clip, &clip);
563		sna_window_set_port((WindowPtr)draw, port);
564	} else {
565		DBG(("%s: failed to show video frame\n", __FUNCTION__));
566		ret = BadAlloc;
567	}
568
569	frame.bo->domain = DOMAIN_NONE;
570	if (xvmc_passthrough(format->id))
571		kgem_bo_destroy(&sna->kgem, frame.bo);
572	else
573		sna_video_buffer_fini(video);
574
575	return ret;
576
577invisible:
578	/*
579	 * If the video isn't visible on any CRTC, turn it off
580	 */
581#if XORG_XV_VERSION < 2
582	sna_video_overlay_stop(client, port, draw);
583#else
584	sna_video_overlay_stop(port, draw);
585#endif
586	return Success;
587}
588
589static int
590sna_video_overlay_query(ddQueryImageAttributes_ARGS)
591{
592	struct sna_video *video = port->devPriv.ptr;
593	struct sna_video_frame frame;
594	struct sna *sna = video->sna;
595	int size, tmp;
596
597	DBG(("%s: w is %d, h is %d\n", __FUNCTION__, *w, *h));
598
599	if (sna->kgem.gen < 021) {
600		if (*w > IMAGE_MAX_WIDTH_LEGACY)
601			*w = IMAGE_MAX_WIDTH_LEGACY;
602		if (*h > IMAGE_MAX_HEIGHT_LEGACY)
603			*h = IMAGE_MAX_HEIGHT_LEGACY;
604	} else {
605		if (*w > IMAGE_MAX_WIDTH)
606			*w = IMAGE_MAX_WIDTH;
607		if (*h > IMAGE_MAX_HEIGHT)
608			*h = IMAGE_MAX_HEIGHT;
609	}
610
611	*w = (*w + 1) & ~1;
612	if (offsets)
613		offsets[0] = 0;
614
615	switch (format->id) {
616	case FOURCC_XVMC:
617		*h = (*h + 1) & ~1;
618		sna_video_frame_init(video, format->id, *w, *h, &frame);
619		sna_video_frame_set_rotation(video, &frame, RR_Rotate_0);
620		size = sizeof(uint32_t);
621		if (pitches) {
622			pitches[0] = frame.pitch[1];
623			pitches[1] = frame.pitch[0];
624			pitches[2] = frame.pitch[0];
625		}
626		if (offsets) {
627			offsets[1] = frame.UBufOffset;
628			offsets[2] = frame.VBufOffset;
629		}
630		break;
631
632		/* IA44 is for XvMC only */
633	case FOURCC_IA44:
634	case FOURCC_AI44:
635		if (pitches)
636			pitches[0] = *w;
637		size = *w * *h;
638		break;
639	case FOURCC_YV12:
640	case FOURCC_I420:
641		*h = (*h + 1) & ~1;
642		size = (*w + 3) & ~3;
643		if (pitches)
644			pitches[0] = size;
645		size *= *h;
646		if (offsets)
647			offsets[1] = size;
648		tmp = ((*w >> 1) + 3) & ~3;
649		if (pitches)
650			pitches[1] = pitches[2] = tmp;
651		tmp *= (*h >> 1);
652		size += tmp;
653		if (offsets)
654			offsets[2] = size;
655		size += tmp;
656#if 0
657		if (pitches)
658			ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n",
659			       pitches[0], pitches[1], pitches[2]);
660		if (offsets)
661			ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1],
662			       offsets[2]);
663		if (offsets)
664			ErrorF("size is %d\n", size);
665#endif
666		break;
667	case FOURCC_UYVY:
668	case FOURCC_YUY2:
669	default:
670		size = *w << 1;
671		if (pitches)
672			pitches[0] = size;
673		size *= *h;
674		break;
675	}
676
677	return size;
678}
679
680static int sna_video_overlay_color_key(struct sna *sna)
681{
682	ScrnInfoPtr scrn = sna->scrn;
683	int color_key;
684
685	if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY,
686				 &color_key)) {
687	} else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY,
688					&color_key)) {
689	} else {
690		color_key =
691		    (1 << scrn->offset.red) |
692		    (1 << scrn->offset.green) |
693		    (((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue);
694	}
695
696	return color_key & ((1 << scrn->depth) - 1);
697}
698
699void sna_video_overlay_setup(struct sna *sna, ScreenPtr screen)
700{
701	XvAdaptorPtr adaptor;
702	struct sna_video *video;
703	XvPortPtr port;
704
705	if (sna->flags & SNA_IS_HOSTED)
706		return;
707
708	if (!sna_has_overlay(sna))
709		return;
710
711	DBG(("%s()\n", __FUNCTION__));
712
713	adaptor = sna_xv_adaptor_alloc(sna);
714	if (adaptor == NULL)
715		return;
716
717	video = calloc(1, sizeof(*video));
718	port = calloc(1, sizeof(*port));
719	if (video == NULL || port == NULL) {
720		free(video);
721		free(port);
722		sna->xv.num_adaptors--;
723		return;
724	}
725
726	adaptor->type = XvInputMask | XvImageMask;
727	adaptor->pScreen = screen;
728	adaptor->name = (char *)"Intel(R) Video Overlay";
729	adaptor->nEncodings = 1;
730	adaptor->pEncodings = xnfalloc(sizeof(XvEncodingRec));
731	adaptor->pEncodings[0].id = 0;
732	adaptor->pEncodings[0].pScreen = screen;
733	adaptor->pEncodings[0].name = (char *)"XV_IMAGE";
734	adaptor->pEncodings[0].width = sna->kgem.gen < 021 ? IMAGE_MAX_WIDTH_LEGACY : IMAGE_MAX_WIDTH;
735	adaptor->pEncodings[0].height = sna->kgem.gen < 021 ? IMAGE_MAX_HEIGHT_LEGACY : IMAGE_MAX_HEIGHT;
736	adaptor->pEncodings[0].rate.numerator = 1;
737	adaptor->pEncodings[0].rate.denominator = 1;
738	adaptor->pFormats = Formats;
739	adaptor->nFormats = sna_xv_fixup_formats(screen, Formats,
740						 ARRAY_SIZE(Formats));
741	adaptor->nAttributes = NUM_ATTRIBUTES;
742	if (HAS_GAMMA(sna))
743		adaptor->nAttributes += GAMMA_ATTRIBUTES;
744	adaptor->pAttributes = (XvAttributeRec *)Attributes;
745	adaptor->nImages = ARRAY_SIZE(Images);
746	adaptor->pImages = (XvImageRec *)Images;
747#if XORG_XV_VERSION < 2
748	adaptor->ddAllocatePort = sna_xv_alloc_port;
749	adaptor->ddFreePort = sna_xv_free_port;
750#endif
751	adaptor->ddPutVideo = NULL;
752	adaptor->ddPutStill = NULL;
753	adaptor->ddGetVideo = NULL;
754	adaptor->ddGetStill = NULL;
755	adaptor->ddStopVideo = sna_video_overlay_stop;
756	adaptor->ddSetPortAttribute = sna_video_overlay_set_attribute;
757	adaptor->ddGetPortAttribute = sna_video_overlay_get_attribute;
758	adaptor->ddQueryBestSize = sna_video_overlay_best_size;
759	adaptor->ddPutImage = sna_video_overlay_put_image;
760	adaptor->ddQueryImageAttributes = sna_video_overlay_query;
761
762	adaptor->nPorts = 1;
763	adaptor->pPorts = port;
764	adaptor->base_id = port->id = FakeClientID(0);
765	AddResource(port->id, XvGetRTPort(), port);
766
767	port->pAdaptor = adaptor;
768	port->pNotify =  NULL;
769	port->pDraw =  NULL;
770	port->client =  NULL;
771	port->grab.client =  NULL;
772	port->time = currentTime;
773	port->devPriv.ptr = video;
774
775	video->sna = sna;
776	if (sna->kgem.gen >= 040)
777		/* Actually the alignment is 64 bytes, too. But the
778		 * stride must be at least 512 bytes. Take the easy fix
779		 * and align on 512 bytes unconditionally. */
780		video->alignment = 512;
781	else if (sna->kgem.gen < 021)
782		/* Harsh, errata on these chipsets limit the stride
783		 * to be a multiple of 256 bytes.
784		 */
785		video->alignment = 256;
786	else
787		video->alignment = 64;
788	video->color_key = sna_video_overlay_color_key(sna);
789	video->brightness = -19;	/* (255/219) * -16 */
790	video->contrast = 75;	/* 255/219 * 64 */
791	video->saturation = 146;	/* 128/112 * 128 */
792	video->desired_crtc = NULL;
793	video->gamma5 = 0xc0c0c0;
794	video->gamma4 = 0x808080;
795	video->gamma3 = 0x404040;
796	video->gamma2 = 0x202020;
797	video->gamma1 = 0x101010;
798	video->gamma0 = 0x080808;
799	RegionNull(&video->clip);
800
801	xvColorKey = MAKE_ATOM("XV_COLORKEY");
802	xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
803	xvContrast = MAKE_ATOM("XV_CONTRAST");
804	xvSaturation = MAKE_ATOM("XV_SATURATION");
805
806	/* Allow the pipe to be switched from pipe A to B when in clone mode */
807	xvPipe = MAKE_ATOM("XV_PIPE");
808	xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP");
809
810	if (HAS_GAMMA(sna)) {
811		xvGamma0 = MAKE_ATOM("XV_GAMMA0");
812		xvGamma1 = MAKE_ATOM("XV_GAMMA1");
813		xvGamma2 = MAKE_ATOM("XV_GAMMA2");
814		xvGamma3 = MAKE_ATOM("XV_GAMMA3");
815		xvGamma4 = MAKE_ATOM("XV_GAMMA4");
816		xvGamma5 = MAKE_ATOM("XV_GAMMA5");
817	}
818
819	sna_video_overlay_update_attrs(video);
820
821	DBG(("%s: '%s' initialized %d ports\n", __FUNCTION__, adaptor->name, adaptor->nPorts));
822}
823