1
/***************************************************************************
3
Copyright 2000-2011 Intel Corporation. All Rights Reserved.
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:
13
The above copyright notice and this permission notice (including the
14
next paragraph) shall be included in all copies or substantial portions
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.
25
**************************************************************************/
32
#include "sna_video.h"
35
#include <X11/extensions/Xv.h>
39
#if DEBUG_VIDEO_OVERLAY
41
#define DBG(x) ErrorF x
44
#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
46
#define HAS_GAMMA(sna) ((sna)->kgem.gen >= 30)
48
static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe;
49
static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5;
50
static Atom xvSyncToVblank;
52
/* Limits for the overlay/textured video source sizes. The documented hardware
53
* limits are 2048x2048 or better for overlay and both of our textured video
54
* implementations. Additionally, on the 830 and 845, larger sizes resulted in
55
* the card hanging, so we keep the limits lower there.
57
#define IMAGE_MAX_WIDTH 2048
58
#define IMAGE_MAX_HEIGHT 2048
59
#define IMAGE_MAX_WIDTH_LEGACY 1024
60
#define IMAGE_MAX_HEIGHT_LEGACY 1088
62
/* client libraries expect an encoding */
63
static const XF86VideoEncodingRec DummyEncoding[1] = {
67
IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT,
74
static XF86VideoFormatRec Formats[NUM_FORMATS] = {
75
{15, TrueColor}, {16, TrueColor}, {24, TrueColor}
78
#define NUM_ATTRIBUTES 5
79
static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = {
80
{XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"},
81
{XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"},
82
{XvSettable | XvGettable, 0, 255, "XV_CONTRAST"},
83
{XvSettable | XvGettable, 0, 1023, "XV_SATURATION"},
84
{XvSettable | XvGettable, -1, 1, "XV_PIPE"}
87
#define GAMMA_ATTRIBUTES 6
88
static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = {
89
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"},
90
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"},
91
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"},
92
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"},
93
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"},
94
{XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"}
99
static XF86ImageRec Images[NUM_IMAGES] = {
106
/* kernel modesetting overlay functions */
107
static Bool sna_has_overlay(struct sna *sna)
109
struct drm_i915_getparam gp;
113
gp.param = I915_PARAM_HAS_OVERLAY;
114
gp.value = &has_overlay;
115
ret = drmCommandWriteRead(sna->kgem.fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
117
return !! has_overlay;
121
static Bool sna_video_overlay_update_attrs(struct sna *sna,
122
struct sna_video *video)
124
struct drm_intel_overlay_attrs attrs;
126
DBG(("%s()\n", __FUNCTION__));
128
attrs.flags = I915_OVERLAY_UPDATE_ATTRS;
129
attrs.brightness = video->brightness;
130
attrs.contrast = video->contrast;
131
attrs.saturation = video->saturation;
132
attrs.color_key = video->color_key;
133
attrs.gamma0 = video->gamma0;
134
attrs.gamma1 = video->gamma1;
135
attrs.gamma2 = video->gamma2;
136
attrs.gamma3 = video->gamma3;
137
attrs.gamma4 = video->gamma4;
138
attrs.gamma5 = video->gamma5;
140
return drmCommandWriteRead(sna->kgem.fd, DRM_I915_OVERLAY_ATTRS,
141
&attrs, sizeof(attrs)) == 0;
144
static void sna_video_overlay_off(struct sna *sna)
146
struct drm_intel_overlay_put_image request;
149
DBG(("%s()\n", __FUNCTION__));
153
ret = drmCommandWrite(sna->kgem.fd, DRM_I915_OVERLAY_PUT_IMAGE,
154
&request, sizeof(request));
158
static void sna_video_overlay_stop(ScrnInfoPtr scrn,
162
struct sna *sna = to_sna(scrn);
163
struct sna_video *video = data;
165
DBG(("%s()\n", __FUNCTION__));
167
REGION_EMPTY(scrn->pScreen, &video->clip);
172
sna_video_overlay_off(sna);
173
sna_video_free_buffers(sna, video);
177
sna_video_overlay_set_port_attribute(ScrnInfoPtr scrn,
178
Atom attribute, INT32 value, pointer data)
180
struct sna *sna = to_sna(scrn);
181
struct sna_video *video = data;
183
if (attribute == xvBrightness) {
184
if ((value < -128) || (value > 127))
186
DBG(("%s: BRIGHTNESS %d -> %d\n", __FUNCTION__,
187
video->contrast, (int)value));
188
video->brightness = value;
189
} else if (attribute == xvContrast) {
190
if ((value < 0) || (value > 255))
192
DBG(("%s: CONTRAST %d -> %d\n", __FUNCTION__,
193
video->contrast, (int)value));
194
video->contrast = value;
195
} else if (attribute == xvSaturation) {
196
if ((value < 0) || (value > 1023))
198
DBG(("%s: SATURATION %d -> %d\n", __FUNCTION__,
199
video->saturation, (int)value));
200
video->saturation = value;
201
} else if (attribute == xvPipe) {
202
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
203
if ((value < -1) || (value > xf86_config->num_crtc))
206
video->desired_crtc = NULL;
208
video->desired_crtc = xf86_config->crtc[value];
209
} else if (attribute == xvGamma0 && HAS_GAMMA(sna)) {
210
video->gamma0 = value;
211
} else if (attribute == xvGamma1 && HAS_GAMMA(sna)) {
212
video->gamma1 = value;
213
} else if (attribute == xvGamma2 && HAS_GAMMA(sna)) {
214
video->gamma2 = value;
215
} else if (attribute == xvGamma3 && HAS_GAMMA(sna)) {
216
video->gamma3 = value;
217
} else if (attribute == xvGamma4 && HAS_GAMMA(sna)) {
218
video->gamma4 = value;
219
} else if (attribute == xvGamma5 && HAS_GAMMA(sna)) {
220
video->gamma5 = value;
221
} else if (attribute == xvColorKey) {
222
video->color_key = value;
227
if ((attribute == xvGamma0 ||
228
attribute == xvGamma1 ||
229
attribute == xvGamma2 ||
230
attribute == xvGamma3 ||
231
attribute == xvGamma4 ||
232
attribute == xvGamma5) && HAS_GAMMA(sna)) {
233
DBG(("%s: GAMMA\n", __FUNCTION__));
236
if (!sna_video_overlay_update_attrs(sna, data))
239
if (attribute == xvColorKey)
240
REGION_EMPTY(scrn->pScreen, &video->clip);
246
sna_video_overlay_get_port_attribute(ScrnInfoPtr scrn,
247
Atom attribute, INT32 * value, pointer data)
249
struct sna *sna = to_sna(scrn);
250
struct sna_video *video = (struct sna_video *) data;
252
if (attribute == xvBrightness) {
253
*value = video->brightness;
254
} else if (attribute == xvContrast) {
255
*value = video->contrast;
256
} else if (attribute == xvSaturation) {
257
*value = video->saturation;
258
} else if (attribute == xvPipe) {
260
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
261
for (c = 0; c < xf86_config->num_crtc; c++)
262
if (xf86_config->crtc[c] == video->desired_crtc)
264
if (c == xf86_config->num_crtc)
267
} else if (attribute == xvGamma0 && HAS_GAMMA(sna)) {
268
*value = video->gamma0;
269
} else if (attribute == xvGamma1 && HAS_GAMMA(sna)) {
270
*value = video->gamma1;
271
} else if (attribute == xvGamma2 && HAS_GAMMA(sna)) {
272
*value = video->gamma2;
273
} else if (attribute == xvGamma3 && HAS_GAMMA(sna)) {
274
*value = video->gamma3;
275
} else if (attribute == xvGamma4 && HAS_GAMMA(sna)) {
276
*value = video->gamma4;
277
} else if (attribute == xvGamma5 && HAS_GAMMA(sna)) {
278
*value = video->gamma5;
279
} else if (attribute == xvColorKey) {
280
*value = video->color_key;
281
} else if (attribute == xvSyncToVblank) {
282
*value = video->SyncToVblank;
290
sna_video_overlay_query_best_size(ScrnInfoPtr scrn,
292
short vid_w, short vid_h,
293
short drw_w, short drw_h,
294
unsigned int *p_w, unsigned int *p_h, pointer data)
296
if (vid_w > (drw_w << 1))
298
if (vid_h > (drw_h << 1))
306
update_dst_box_to_crtc_coords(struct sna *sna, xf86CrtcPtr crtc, BoxPtr dstBox)
308
ScrnInfoPtr scrn = sna->scrn;
311
/* for overlay, we should take it from crtc's screen
312
* coordinate to current crtc's display mode.
313
* yeah, a bit confusing.
315
switch (crtc->rotation & 0xf) {
317
dstBox->x1 -= crtc->x;
318
dstBox->x2 -= crtc->x;
319
dstBox->y1 -= crtc->y;
320
dstBox->y2 -= crtc->y;
324
dstBox->x1 = dstBox->y1 - crtc->x;
325
dstBox->y1 = scrn->virtualX - tmp - crtc->y;
327
dstBox->x2 = dstBox->y2 - crtc->x;
328
dstBox->y2 = scrn->virtualX - tmp - crtc->y;
330
dstBox->y1 = dstBox->y2;
335
dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x;
336
dstBox->x2 = scrn->virtualX - tmp - crtc->x;
338
dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y;
339
dstBox->y2 = scrn->virtualY - tmp - crtc->y;
343
dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x;
344
dstBox->y1 = tmp - crtc->y;
346
dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x;
347
dstBox->y2 = tmp - crtc->y;
349
dstBox->x1 = dstBox->x2;
358
sna_video_overlay_show(struct sna *sna,
359
struct sna_video *video,
360
struct sna_video_frame *frame,
363
short src_w, short src_h,
364
short drw_w, short drw_h)
366
struct drm_intel_overlay_put_image request;
367
bool planar = is_planar_fourcc(frame->id);
370
DBG(("%s: src=(%dx%d), dst=(%dx%d)\n", __FUNCTION__,
371
src_w, src_h, drw_w, drw_h));
373
update_dst_box_to_crtc_coords(sna, crtc, dstBox);
374
if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
378
frame->width = frame->height;
390
memset(&request, 0, sizeof(request));
391
request.flags = I915_OVERLAY_ENABLE;
393
request.bo_handle = frame->bo->handle;
395
request.stride_Y = frame->pitch[1];
396
request.stride_UV = frame->pitch[0];
398
request.stride_Y = frame->pitch[0];
399
request.stride_UV = 0;
401
request.offset_Y = 0;
402
request.offset_U = frame->UBufOffset;
403
request.offset_V = frame->VBufOffset;
404
DBG(("%s: handle=%d, stride_Y=%d, stride_UV=%d, off_Y: %i, off_U: %i, off_V: %i\n",
406
request.bo_handle, request.stride_Y, request.stride_UV,
407
request.offset_Y, request.offset_U, request.offset_V));
409
request.crtc_id = sna_crtc_id(crtc);
410
request.dst_x = dstBox->x1;
411
request.dst_y = dstBox->y1;
412
request.dst_width = dstBox->x2 - dstBox->x1;
413
request.dst_height = dstBox->y2 - dstBox->y1;
415
DBG(("%s: crtc=%d, dst=(%d, %d)x(%d, %d)\n",
416
__FUNCTION__, request.crtc_id,
417
request.dst_x, request.dst_y,
418
request.dst_width, request.dst_height));
420
request.src_width = frame->width;
421
request.src_height = frame->height;
422
/* adjust src dimensions */
423
if (request.dst_height > 1) {
424
scale = ((float)request.dst_height - 1) / ((float)drw_h - 1);
425
request.src_scan_height = src_h * scale;
427
request.src_scan_height = 1;
429
if (request.dst_width > 1) {
430
scale = ((float)request.dst_width - 1) / ((float)drw_w - 1);
431
request.src_scan_width = src_w * scale;
433
request.src_scan_width = 1;
435
DBG(("%s: src=(%d, %d) scan=(%d, %d)\n",
437
request.src_width, request.src_height,
438
request.src_scan_width, request.src_scan_height));
441
request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420;
443
request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422;
444
if (frame->id == FOURCC_UYVY)
445
request.flags |= I915_OVERLAY_Y_SWAP;
448
DBG(("%s: flags=%x\n", __FUNCTION__, request.flags));
450
return drmCommandWrite(sna->kgem.fd, DRM_I915_OVERLAY_PUT_IMAGE,
451
&request, sizeof(request)) == 0;
455
sna_video_overlay_put_image(ScrnInfoPtr scrn,
456
short src_x, short src_y,
457
short drw_x, short drw_y,
458
short src_w, short src_h,
459
short drw_w, short drw_h,
460
int id, unsigned char *buf,
461
short width, short height,
462
Bool sync, RegionPtr clip, pointer data,
463
DrawablePtr drawable)
465
struct sna *sna = to_sna(scrn);
466
struct sna_video *video = data;
467
struct sna_video_frame frame;
470
int top, left, npixels, nlines;
472
DBG(("%s: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d), width %d, height %d\n",
474
src_x, src_y, src_w, src_h, drw_x,
475
drw_y, drw_w, drw_h, width, height));
477
/* If dst width and height are less than 1/8th the src size, the
478
* src/dst scale factor becomes larger than 8 and doesn't fit in
479
* the scale register. */
480
if (src_w >= (drw_w * 8))
483
if (src_h >= (drw_h * 8))
486
if (!sna_video_clip_helper(scrn,
490
src_x, src_y, drw_x, drw_y,
491
src_w, src_h, drw_w, drw_h,
493
&top, &left, &npixels, &nlines, clip,
499
* If the video isn't visible on any CRTC, turn it off
501
sna_video_overlay_off(sna);
505
sna_video_frame_init(sna, video, id, width, height, &frame);
507
/* overlay can't handle rotation natively, store it for the copy func */
508
video->rotation = crtc->rotation;
509
if (!sna_video_copy_data(sna, video, &frame,
510
top, left, npixels, nlines, buf)) {
511
DBG(("%s: failed to copy video data\n", __FUNCTION__));
515
if (!sna_video_overlay_show
516
(sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
517
DBG(("%s: failed to show video frame\n", __FUNCTION__));
521
sna_video_frame_fini(sna, video, &frame);
523
/* update cliplist */
524
if (!REGION_EQUAL(scrn->pScreen, &video->clip, clip)) {
525
REGION_COPY(scrn->pScreen, &video->clip, clip);
526
xf86XVFillKeyHelperDrawable(drawable, video->color_key, clip);
533
sna_video_overlay_query_video_attributes(ScrnInfoPtr scrn,
535
unsigned short *w, unsigned short *h,
536
int *pitches, int *offsets)
538
struct sna *sna = to_sna(scrn);
541
DBG(("%s: w is %d, h is %d\n", __FUNCTION__, *w, *h));
543
if (sna->kgem.gen < 21) {
544
if (*w > IMAGE_MAX_WIDTH_LEGACY)
545
*w = IMAGE_MAX_WIDTH_LEGACY;
546
if (*h > IMAGE_MAX_HEIGHT_LEGACY)
547
*h = IMAGE_MAX_HEIGHT_LEGACY;
549
if (*w > IMAGE_MAX_WIDTH)
550
*w = IMAGE_MAX_WIDTH;
551
if (*h > IMAGE_MAX_HEIGHT)
552
*h = IMAGE_MAX_HEIGHT;
560
/* IA44 is for XvMC only */
570
size = (*w + 3) & ~3;
576
tmp = ((*w >> 1) + 3) & ~3;
578
pitches[1] = pitches[2] = tmp;
586
ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n",
587
pitches[0], pitches[1], pitches[2]);
589
ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1],
592
ErrorF("size is %d\n", size);
608
static int sna_video_overlay_color_key(struct sna *sna)
610
ScrnInfoPtr scrn = sna->scrn;
613
if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY,
615
} else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY,
619
(1 << scrn->offset.red) |
620
(1 << scrn->offset.green) |
621
(((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue);
624
return color_key & ((1 << scrn->depth) - 1);
627
XF86VideoAdaptorPtr sna_video_overlay_setup(struct sna *sna,
630
XF86VideoAdaptorPtr adaptor;
631
struct sna_video *video;
632
XF86AttributePtr att;
634
if (!sna_has_overlay(sna)) {
635
xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
636
"Overlay video not supported on this hardware\n");
640
DBG(("%s()\n", __FUNCTION__));
642
if (!(adaptor = calloc(1,
643
sizeof(XF86VideoAdaptorRec) +
644
sizeof(struct sna_video) +
648
adaptor->type = XvWindowMask | XvInputMask | XvImageMask;
649
adaptor->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ;
650
adaptor->name = "Intel(R) Video Overlay";
651
adaptor->nEncodings = 1;
652
adaptor->pEncodings = xnfalloc(sizeof(DummyEncoding));
653
memcpy(adaptor->pEncodings, DummyEncoding, sizeof(DummyEncoding));
654
if (sna->kgem.gen < 21) {
655
adaptor->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY;
656
adaptor->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY;
658
adaptor->nFormats = NUM_FORMATS;
659
adaptor->pFormats = Formats;
661
adaptor->pPortPrivates = (DevUnion *)&adaptor[1];
663
video = (struct sna_video *)&adaptor->pPortPrivates[1];
665
adaptor->pPortPrivates[0].ptr = video;
666
adaptor->nAttributes = NUM_ATTRIBUTES;
668
adaptor->nAttributes += GAMMA_ATTRIBUTES;
669
adaptor->pAttributes =
670
xnfalloc(sizeof(XF86AttributeRec) * adaptor->nAttributes);
671
/* Now copy the attributes */
672
att = adaptor->pAttributes;
673
memcpy(att, Attributes, sizeof(XF86AttributeRec) * NUM_ATTRIBUTES);
674
att += NUM_ATTRIBUTES;
675
if (HAS_GAMMA(sna)) {
676
memcpy(att, GammaAttributes,
677
sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES);
678
att += GAMMA_ATTRIBUTES;
680
adaptor->nImages = NUM_IMAGES;
681
adaptor->pImages = Images;
682
adaptor->PutVideo = NULL;
683
adaptor->PutStill = NULL;
684
adaptor->GetVideo = NULL;
685
adaptor->GetStill = NULL;
686
adaptor->StopVideo = sna_video_overlay_stop;
687
adaptor->SetPortAttribute = sna_video_overlay_set_port_attribute;
688
adaptor->GetPortAttribute = sna_video_overlay_get_port_attribute;
689
adaptor->QueryBestSize = sna_video_overlay_query_best_size;
690
adaptor->PutImage = sna_video_overlay_put_image;
691
adaptor->QueryImageAttributes = sna_video_overlay_query_video_attributes;
693
video->textured = FALSE;
694
video->color_key = sna_video_overlay_color_key(sna);
695
video->brightness = -19; /* (255/219) * -16 */
696
video->contrast = 75; /* 255/219 * 64 */
697
video->saturation = 146; /* 128/112 * 128 */
698
video->desired_crtc = NULL;
699
video->gamma5 = 0xc0c0c0;
700
video->gamma4 = 0x808080;
701
video->gamma3 = 0x404040;
702
video->gamma2 = 0x202020;
703
video->gamma1 = 0x101010;
704
video->gamma0 = 0x080808;
706
video->rotation = RR_Rotate_0;
708
/* gotta uninit this someplace */
709
REGION_NULL(screen, &video->clip);
711
xvColorKey = MAKE_ATOM("XV_COLORKEY");
712
xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
713
xvContrast = MAKE_ATOM("XV_CONTRAST");
714
xvSaturation = MAKE_ATOM("XV_SATURATION");
716
/* Allow the pipe to be switched from pipe A to B when in clone mode */
717
xvPipe = MAKE_ATOM("XV_PIPE");
719
if (HAS_GAMMA(sna)) {
720
xvGamma0 = MAKE_ATOM("XV_GAMMA0");
721
xvGamma1 = MAKE_ATOM("XV_GAMMA1");
722
xvGamma2 = MAKE_ATOM("XV_GAMMA2");
723
xvGamma3 = MAKE_ATOM("XV_GAMMA3");
724
xvGamma4 = MAKE_ATOM("XV_GAMMA4");
725
xvGamma5 = MAKE_ATOM("XV_GAMMA5");
728
sna_video_overlay_update_attrs(sna, video);