diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-28 18:59:26 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-03-28 22:53:17 +0100 |
commit | 6142232fa0feeb39412cda85ca727cc770eaa042 (patch) | |
tree | b80821243df9b076b0dddf4c322a43d54c32f220 | |
parent | ae8aa172a7330439a8e6dda41f5e33eb257a139b (diff) |
sna: Add video sprite support for ILK+
Based on the work by Jesse Barnes.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/Makefile.am | 1 | ||||
-rw-r--r-- | src/sna/sna.h | 1 | ||||
-rw-r--r-- | src/sna/sna_display.c | 39 | ||||
-rw-r--r-- | src/sna/sna_video.c | 18 | ||||
-rw-r--r-- | src/sna/sna_video.h | 9 | ||||
-rw-r--r-- | src/sna/sna_video_sprite.c | 434 |
6 files changed, 495 insertions, 7 deletions
diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am index 70afd532..911a857e 100644 --- a/src/sna/Makefile.am +++ b/src/sna/Makefile.am @@ -60,6 +60,7 @@ libsna_la_SOURCES = \ sna_video.c \ sna_video.h \ sna_video_overlay.c \ + sna_video_sprite.c \ sna_video_textured.c \ gen2_render.c \ gen2_render.h \ diff --git a/src/sna/sna.h b/src/sna/sna.h index 949c18ff..8ad8efc4 100644 --- a/src/sna/sna.h +++ b/src/sna/sna.h @@ -371,6 +371,7 @@ void sna_dri_close(struct sna *sna, ScreenPtr pScreen); extern Bool sna_crtc_on(xf86CrtcPtr crtc); int sna_crtc_to_pipe(xf86CrtcPtr crtc); +int sna_crtc_to_plane(xf86CrtcPtr crtc); CARD32 sna_format_for_depth(int depth); CARD32 sna_render_format_for_depth(int depth); diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index a5d69dd5..ecfe6702 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -60,6 +60,7 @@ struct sna_crtc { int num; int id; int pipe; + int plane; int active; struct list link; }; @@ -144,6 +145,12 @@ int sna_crtc_to_pipe(xf86CrtcPtr crtc) return sna_crtc->pipe; } +int sna_crtc_to_plane(xf86CrtcPtr crtc) +{ + struct sna_crtc *sna_crtc = crtc->driver_private; + return sna_crtc->plane; +} + static uint32_t gem_create(int fd, int size) { struct drm_i915_gem_create create; @@ -852,6 +859,37 @@ static const xf86CrtcFuncsRec sna_crtc_funcs = { .destroy = sna_crtc_destroy, }; +static uint32_t +sna_crtc_find_plane(struct sna *sna, int pipe) +{ + drmModePlaneRes *resources; + uint32_t id = 0; + int i; + + resources = drmModeGetPlaneResources(sna->kgem.fd); + if (!resources) { + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, + "failed to get plane resources: %s\n", + strerror(errno)); + return 0; + } + + for (i = 0; id == 0 && i < resources->count_planes; i++) { + drmModePlane *p; + + p = drmModeGetPlane(sna->kgem.fd, resources->planes[i]); + if (p) { + if (p->possible_crtcs & (1 << pipe)) + id = p->plane_id; + + drmModeFreePlane(p); + } + } + + free(resources); + return id; +} + static void sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num) { @@ -878,6 +916,7 @@ sna_crtc_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num) DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, &get_pipe); sna_crtc->pipe = get_pipe.pipe; + sna_crtc->plane = sna_crtc_find_plane(sna, sna_crtc->pipe); if (xf86IsEntityShared(scrn->entityList[0]) && scrn->confScreen->device->screen != sna_crtc->pipe) { diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c index 56cf260f..c80ccfb7 100644 --- a/src/sna/sna_video.c +++ b/src/sna/sna_video.c @@ -83,12 +83,17 @@ void sna_video_free_buffers(struct sna *sna, struct sna_video *video) for (i = 0; i < ARRAY_SIZE(video->old_buf); i++) { if (video->old_buf[i]) { + if (video->old_buf[i]->unique_id) + drmModeRmFB(sna->kgem.fd, + video->old_buf[i]->unique_id); kgem_bo_destroy(&sna->kgem, video->old_buf[i]); video->old_buf[i] = NULL; } } if (video->buf) { + if (video->buf->unique_id) + drmModeRmFB(sna->kgem.fd, video->buf->unique_id); kgem_bo_destroy(&sna->kgem, video->buf); video->buf = NULL; } @@ -440,6 +445,11 @@ sna_video_copy_data(struct sna *sna, if (frame->bo == NULL) return FALSE; + DBG(("%s: handle=%d, size=%dx%d, rotation=%d\n", + __FUNCTION__, frame->bo->handle, frame->width, frame->height, + video->rotation)); + DBG(("%s: top=%d, left=%d\n", __FUNCTION__, frame->top, frame->left)); + /* In the common case, we can simply the upload in a single pwrite */ if (video->rotation == RR_Rotate_0) { if (is_planar_fourcc(frame->id)) { @@ -472,8 +482,8 @@ sna_video_copy_data(struct sna *sna, } } - /* copy data */ - dst = kgem_bo_map(&sna->kgem, frame->bo); + /* copy data, must use GTT so that we keep the overlay uncached */ + dst = kgem_bo_map__gtt(&sna->kgem, frame->bo); if (dst == NULL) return FALSE; @@ -510,7 +520,9 @@ void sna_video_init(struct sna *sna, ScreenPtr screen) * supported hardware. */ textured = sna_video_textured_setup(sna, screen); - overlay = sna_video_overlay_setup(sna, screen); + overlay = sna_video_sprite_setup(sna, screen); + if (overlay == NULL) + overlay = sna_video_overlay_setup(sna, screen); if (overlay && prefer_overlay) adaptors[num_adaptors++] = overlay; diff --git a/src/sna/sna_video.h b/src/sna/sna_video.h index 47ddab0f..687fbe1a 100644 --- a/src/sna/sna_video.h +++ b/src/sna/sna_video.h @@ -51,6 +51,7 @@ struct sna_video { uint32_t gamma5; int color_key; + int color_key_changed; /** YUV data buffers */ struct kgem_bo *old_buf[2]; @@ -58,6 +59,7 @@ struct sna_video { Bool textured; Rotation rotation; + int plane; int SyncToVblank; /* -1: auto, 0: off, 1: on */ }; @@ -78,10 +80,9 @@ struct sna_video_frame { }; void sna_video_init(struct sna *sna, ScreenPtr screen); -XF86VideoAdaptorPtr sna_video_overlay_setup(struct sna *sna, - ScreenPtr screen); -XF86VideoAdaptorPtr sna_video_textured_setup(struct sna *sna, - ScreenPtr screen); +XF86VideoAdaptorPtr sna_video_overlay_setup(struct sna *sna, ScreenPtr screen); +XF86VideoAdaptorPtr sna_video_sprite_setup(struct sna *sna, ScreenPtr screen); +XF86VideoAdaptorPtr sna_video_textured_setup(struct sna *sna, ScreenPtr screen); #define FOURCC_XVMC (('C' << 24) + ('M' << 16) + ('V' << 8) + 'X') diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c new file mode 100644 index 00000000..82db1224 --- /dev/null +++ b/src/sna/sna_video_sprite.c @@ -0,0 +1,434 @@ +/*************************************************************************** + + Copyright 2000-2011 Intel Corporation. All Rights Reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sub license, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial portions + of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sna.h" +#include "sna_video.h" + +#include <xf86xv.h> +#include <X11/extensions/Xv.h> +#include <fourcc.h> +#include <drm_fourcc.h> +#include <i915_drm.h> + +#if DEBUG_VIDEO_OVERLAY +#undef DBG +#define DBG(x) ErrorF x +#endif + +#define IMAGE_MAX_WIDTH 2048 +#define IMAGE_MAX_HEIGHT 2048 + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvColorKey; + +static XF86VideoFormatRec xv_formats[] = { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; +static XF86ImageRec xv_images[] = { XVIMAGE_YUY2, XVIMAGE_UYVY, }; +static const XF86VideoEncodingRec xv_dummy_encoding[] = { + { 0, "XV_IMAGE", IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, {1, 1} } +}; +static XF86AttributeRec attribs[] = { + {XvSettable | XvGettable, 0, 0xffffff, "XV_COLORKEY"}, +}; + +static void sna_video_sprite_off(struct sna *sna, struct sna_video *video) +{ + if (video->plane == 0) + return; + + if (drmModeSetPlane(sna->kgem.fd, + video->plane, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0)) + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, + "failed to disable plane\n"); + + video->plane = 0; +} + +static void sna_video_sprite_stop(ScrnInfoPtr scrn, pointer data, Bool shutdown) +{ + return sna_video_sprite_off(to_sna(scrn), data); +} + +static int sna_video_sprite_set_attr(ScrnInfoPtr scrn, + Atom attribute, INT32 value, + pointer data) +{ + struct sna_video *video = data; + + if (attribute == xvColorKey) { + video->color_key_changed = TRUE; + video->color_key = value; + DBG(("COLORKEY = %d\n", value)); + } else + return BadMatch; + + return Success; +} + +static int sna_video_sprite_get_attr(ScrnInfoPtr scrn, + Atom attribute, INT32 *value, + pointer data) +{ + struct sna_video *video = data; + + if (attribute == xvColorKey) + *value = video->color_key; + else + return BadMatch; + + return Success; +} + +static void sna_video_sprite_best_size(ScrnInfoPtr scrn, Bool motion, + short vid_w, short vid_h, + short drw_w, short drw_h, + unsigned int *p_w, unsigned int *p_h, + pointer data) +{ + *p_w = vid_w; + *p_h = vid_h; +} + +static void +update_dst_box_to_crtc_coords(struct sna *sna, xf86CrtcPtr crtc, BoxPtr dstBox) +{ + ScrnInfoPtr scrn = sna->scrn; + int tmp; + + switch (crtc->rotation & 0xf) { + case RR_Rotate_0: + dstBox->x1 -= crtc->x; + dstBox->x2 -= crtc->x; + dstBox->y1 -= crtc->y; + dstBox->y2 -= crtc->y; + break; + + case RR_Rotate_90: + tmp = dstBox->x1; + dstBox->x1 = dstBox->y1 - crtc->x; + dstBox->y1 = scrn->virtualX - tmp - crtc->y; + tmp = dstBox->x2; + dstBox->x2 = dstBox->y2 - crtc->x; + dstBox->y2 = scrn->virtualX - tmp - crtc->y; + tmp = dstBox->y1; + dstBox->y1 = dstBox->y2; + dstBox->y2 = tmp; + break; + + case RR_Rotate_180: + tmp = dstBox->x1; + dstBox->x1 = scrn->virtualX - dstBox->x2 - crtc->x; + dstBox->x2 = scrn->virtualX - tmp - crtc->x; + tmp = dstBox->y1; + dstBox->y1 = scrn->virtualY - dstBox->y2 - crtc->y; + dstBox->y2 = scrn->virtualY - tmp - crtc->y; + break; + + case RR_Rotate_270: + tmp = dstBox->x1; + dstBox->x1 = scrn->virtualY - dstBox->y1 - crtc->x; + dstBox->y1 = tmp - crtc->y; + tmp = dstBox->x2; + dstBox->x2 = scrn->virtualY - dstBox->y2 - crtc->x; + dstBox->y2 = tmp - crtc->y; + tmp = dstBox->x1; + dstBox->x1 = dstBox->x2; + dstBox->x2 = tmp; + break; + } +} + +static Bool +sna_video_sprite_show(struct sna *sna, + struct sna_video *video, + struct sna_video_frame *frame, + xf86CrtcPtr crtc, + BoxPtr dstBox) +{ + int plane = sna_crtc_to_plane(crtc); + + update_dst_box_to_crtc_coords(sna, crtc, dstBox); + if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + int tmp = frame->width; + frame->width = frame->height; + frame->height = tmp; + } + +#if defined(DRM_I915_SET_SPRITE_DESTKEY) + if (video->color_key_changed || video->plane != plane) { + struct drm_intel_set_sprite_destkey set; + + DBG(("%s: updating color key: %x\n", + __FUNCTION__, video->color_key)); + + set.plane_id = plane; + set.value = video->color_key; + + if (drmCommandWrite(sna->kgem.fd, + DRM_I915_SET_SPRITE_DESTKEY, + &set, sizeof(set))) + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, + "failed to update color key\n"); + + video->color_key_changed = FALSE; + } +#endif + + if (frame->bo->unique_id == 0) { + uint32_t offsets[4], pitches[4], handles[4]; + uint32_t pixel_format; + + switch (frame->id) { + case FOURCC_UYVY: + pixel_format = DRM_FORMAT_UYVY; + break; + case FOURCC_YUY2: + default: + pixel_format = DRM_FORMAT_YUYV; + break; + } + + handles[0] = frame->bo->handle; + pitches[0] = frame->pitch[0]; + offsets[0] = 0; + + DBG(("%s: creating new fb for handle=%d\n", + __FUNCTION__, frame->bo->handle)); + + if (drmModeAddFB2(sna->kgem.fd, + frame->width, frame->height, pixel_format, + handles, pitches, offsets, + &frame->bo->unique_id, 0)) { + xf86DrvMsg(sna->scrn->scrnIndex, + X_ERROR, "failed to add fb\n"); + return false; + } + } + + DBG(("%s: updating plane=%d, handle=%d [fb %d], dst=(%d,%d)x(%d,%d)\n", + __FUNCTION__, plane, frame->bo->handle, frame->bo->unique_id, + dstBox->x1, dstBox->y1, + dstBox->x2 - dstBox->x1, dstBox->y2 - dstBox->y1)); + if (drmModeSetPlane(sna->kgem.fd, + plane, sna_crtc_id(crtc), frame->bo->unique_id, 0, + dstBox->x1, dstBox->y1, + dstBox->x2 - dstBox->x1, dstBox->y2 - dstBox->y1, + 0, 0, frame->width << 16, frame->height << 16)) + return false; + + video->plane = plane; + return true; +} + +static int sna_video_sprite_put_image(ScrnInfoPtr scrn, + short src_x, short src_y, + short drw_x, short drw_y, + short src_w, short src_h, + short drw_w, short drw_h, + int id, unsigned char *buf, + short width, short height, + Bool sync, RegionPtr clip, pointer data, + DrawablePtr drawable) +{ + struct sna *sna = to_sna(scrn); + struct sna_video *video = data; + struct sna_video_frame frame; + xf86CrtcPtr crtc; + BoxRec dst_box; + + sna_video_frame_init(sna, video, id, width, height, &frame); + + if (!sna_video_clip_helper(scrn, video, &frame, &crtc, &dst_box, + src_x, src_y, drw_x, drw_y, + src_w, src_h, drw_w, drw_h, + clip)) + return Success; + + if (!crtc || !sna_crtc_to_plane(crtc)) { + /* If the video isn't visible on any CRTC, turn it off */ + sna_video_sprite_off(sna, video); + return Success; + } + + /* sprites can't handle rotation natively, store it for the copy func */ + video->rotation = crtc->rotation; + + frame.bo = sna_video_buffer(sna, video, &frame); + if (frame.bo == NULL) { + DBG(("%s: failed to allocate video bo\n", __FUNCTION__)); + return BadAlloc; + } + + if (!sna_video_copy_data(sna, video, &frame, buf)) { + DBG(("%s: failed to copy video data\n", __FUNCTION__)); + return BadAlloc; + } + + if (!sna_video_sprite_show(sna, video, &frame, crtc, &dst_box)) { + DBG(("%s: failed to show video frame\n", __FUNCTION__)); + return BadAlloc; + } + + sna_video_buffer_fini(sna, video); + + if (!REGION_EQUAL(scrn->pScreen, &video->clip, clip)) { + REGION_COPY(scrn->pScreen, &video->clip, clip); + xf86XVFillKeyHelperDrawable(drawable, video->color_key, clip); + } + + return Success; +} + +static int sna_video_sprite_query_attrs(ScrnInfoPtr scrn, int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ + int size; + + if (*w > IMAGE_MAX_WIDTH) + *w = IMAGE_MAX_WIDTH; + if (*h > IMAGE_MAX_HEIGHT) + *h = IMAGE_MAX_HEIGHT; + + *w = (*w + 1) & ~1; + if (offsets) + offsets[0] = 0; + + switch (id) { + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +static int sna_video_sprite_color_key(struct sna *sna) +{ + ScrnInfoPtr scrn = sna->scrn; + int color_key; + + if (xf86GetOptValInteger(sna->Options, OPTION_VIDEO_KEY, + &color_key)) { + } else if (xf86GetOptValInteger(sna->Options, OPTION_COLOR_KEY, + &color_key)) { + } else { + color_key = + (1 << scrn->offset.red) | + (1 << scrn->offset.green) | + (((scrn->mask.blue >> scrn->offset.blue) - 1) << scrn->offset.blue); + } + + return color_key & ((1 << scrn->depth) - 1); +} + +XF86VideoAdaptorPtr sna_video_sprite_setup(struct sna *sna, + ScreenPtr screen) +{ + XF86VideoAdaptorPtr adaptor; + struct sna_video *video; + drmModePlaneRes *plane_resources; + + plane_resources = drmModeGetPlaneResources(sna->kgem.fd); + if (!plane_resources) + return NULL; + + adaptor = calloc(1, + sizeof(XF86VideoAdaptorRec) + + sizeof(struct sna_video) + + sizeof(DevUnion)); + if (!adaptor) { + free(plane_resources); + return NULL; + } + + adaptor->type = XvWindowMask | XvInputMask | XvImageMask; + adaptor->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ; + adaptor->name = "Intel(R) Video Sprite"; + adaptor->nEncodings = ARRAY_SIZE(xv_dummy_encoding); + adaptor->pEncodings = xnfalloc(sizeof(xv_dummy_encoding)); + memcpy(adaptor->pEncodings, xv_dummy_encoding, sizeof(xv_dummy_encoding)); + adaptor->nFormats = ARRAY_SIZE(xv_formats); + adaptor->pFormats = xv_formats; + adaptor->nPorts = 1; + adaptor->pPortPrivates = (DevUnion *)&adaptor[1]; + + video = (struct sna_video *)&adaptor->pPortPrivates[1]; + adaptor->pPortPrivates[0].ptr = video; + + adaptor->nAttributes = ARRAY_SIZE(attribs); + adaptor->pAttributes = attribs; + + adaptor->nImages = ARRAY_SIZE(xv_images); + adaptor->pImages = xv_images; + + adaptor->PutVideo = NULL; + adaptor->PutStill = NULL; + adaptor->GetVideo = NULL; + adaptor->GetStill = NULL; + adaptor->StopVideo = sna_video_sprite_stop; + adaptor->SetPortAttribute = sna_video_sprite_set_attr; + adaptor->GetPortAttribute = sna_video_sprite_get_attr; + adaptor->QueryBestSize = sna_video_sprite_best_size; + adaptor->PutImage = sna_video_sprite_put_image; + adaptor->QueryImageAttributes = sna_video_sprite_query_attrs; + + video->textured = FALSE; + video->color_key = sna_video_sprite_color_key(sna); + video->color_key_changed = TRUE; + video->brightness = -19; /* (255/219) * -16 */ + video->contrast = 75; /* 255/219 * 64 */ + video->saturation = 146; /* 128/112 * 128 */ + video->desired_crtc = NULL; + video->gamma5 = 0xc0c0c0; + video->gamma4 = 0x808080; + video->gamma3 = 0x404040; + video->gamma2 = 0x202020; + video->gamma1 = 0x101010; + video->gamma0 = 0x080808; + + video->rotation = RR_Rotate_0; + + REGION_NULL(screen, &video->clip); + + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + free(plane_resources); + + return adaptor; +} |