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