summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-03-28 18:59:26 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2012-03-28 22:53:17 +0100
commit6142232fa0feeb39412cda85ca727cc770eaa042 (patch)
treeb80821243df9b076b0dddf4c322a43d54c32f220
parentae8aa172a7330439a8e6dda41f5e33eb257a139b (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.am1
-rw-r--r--src/sna/sna.h1
-rw-r--r--src/sna/sna_display.c39
-rw-r--r--src/sna/sna_video.c18
-rw-r--r--src/sna/sna_video.h9
-rw-r--r--src/sna/sna_video_sprite.c434
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;
+}