diff options
Diffstat (limited to 'src/intel_sprite.c')
-rw-r--r-- | src/intel_sprite.c | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/src/intel_sprite.c b/src/intel_sprite.c new file mode 100644 index 00000000..c6fe7579 --- /dev/null +++ b/src/intel_sprite.c @@ -0,0 +1,439 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> +#include <math.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <xf86drmMode.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86PciInfo.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "regionstr.h" +#include "randrstr.h" +#include "windowstr.h" +#include "damage.h" +#include "intel.h" +#include "intel_video.h" +#include "i830_reg.h" +#include "xf86xv.h" +#include <X11/extensions/Xv.h> +#include "dixstruct.h" +#include "fourcc.h" + +#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 intel_sprite_stop(ScrnInfoPtr scrn, pointer data, Bool shutdown) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + intel_adaptor_private *adaptor_priv = intel_get_sprite_adaptor_private(intel); + int ret; + + ret = drmModeSetPlane(intel->drmSubFD, adaptor_priv->plane_id, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0); + if (ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to disable plane\n"); +} + +static int intel_sprite_set_attr(ScrnInfoPtr scrn, Atom attribute, INT32 value, + pointer data) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + intel_adaptor_private *adaptor_priv = intel_get_sprite_adaptor_private(intel); + + if (attribute == xvColorKey) { + adaptor_priv->colorKeyChanged = TRUE; + adaptor_priv->colorKey = value; + ErrorF("COLORKEY = %d\n", value); + } else + return BadMatch; + + return Success; +} + +static int intel_sprite_get_attr(ScrnInfoPtr scrn, Atom attribute, INT32 *value, + pointer data) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + intel_adaptor_private *adaptor_priv = intel_get_sprite_adaptor_private(intel); + + if (attribute == xvColorKey) + *value = adaptor_priv->colorKey; + else + return BadMatch; + + return Success; +} + +static void intel_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 Bool intel_plane_moved(intel_adaptor_private *adaptor_priv, + BoxRec *new_location) +{ + uint32_t new_w = new_location->x2 - new_location->x1; + uint32_t new_h = new_location->y2 - new_location->y1; + + if (adaptor_priv->crtc_x != new_location->x1 || + adaptor_priv->crtc_y != new_location->y1 || + adaptor_priv->crtc_w != new_w || + adaptor_priv->crtc_h != new_h) + return TRUE; + return FALSE; +} + +static Bool intel_source_changed(intel_adaptor_private *adaptor_priv, + int src_x, int src_y, int src_w, int src_h) +{ + if (adaptor_priv->src_x != src_x || + adaptor_priv->src_y != src_y || + adaptor_priv->src_w != src_w || + adaptor_priv->src_h != src_h) + return TRUE; + return FALSE; +} + +static int intel_sprite_put(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 clipBoxes, pointer data, + DrawablePtr drawable) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + intel_adaptor_private *adaptor_priv = intel_get_sprite_adaptor_private(intel); + dri_bo *new_frame; + unsigned char *src, *dst, *dst_base; + int i; + xf86CrtcPtr crtc; + BoxRec dst_box; + int ret, top, left, lines, pixel_width; + int crtc_x, crtc_y; + unsigned long crtc_w, crtc_h; + int plane_id; + uint32_t fb_id, crtc_id; + Bool plane_updated = FALSE; + uint32_t pixel_format; + uint32_t pitches[4], offsets[4]; + + ret = intel_clip_video_helper(scrn, adaptor_priv, &crtc, &dst_box, + src_x, src_y, drw_x, drw_y, + src_w, src_h, drw_w, drw_h, + id, &top, &left, &pixel_width, &lines, + clipBoxes, width, height); + if (!ret) + return Success; + + crtc_id = intel_crtc_id(crtc); + + /* Make output coords CRTC relative */ + crtc_x = dst_box.x1 - crtc->x; + crtc_y = dst_box.y1 - crtc->y; + crtc_w = dst_box.x2 - dst_box.x1; + crtc_h = dst_box.y2 - dst_box.y1; + + plane_id = intel_crtc_to_sprite(crtc); + if (!plane_id) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "no planes available for crtc\n"); + return Success; + } + + new_frame = adaptor_priv->buf; + + if (adaptor_priv->plane_id != plane_id || + adaptor_priv->colorKeyChanged) { + struct drm_intel_set_sprite_destkey set; + + set.plane_id = plane_id; + set.value = adaptor_priv->colorKey; + ret = drmCommandWrite(intel->drmSubFD, + DRM_I915_SET_SPRITE_DESTKEY, &set, + sizeof(set)); + if (ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to update color key\n"); + adaptor_priv->colorKeyChanged = FALSE; + } + + /* Re-alloc if source size changed */ + if (new_frame && + intel_source_changed(adaptor_priv, top, left, pixel_width, lines)) { + drm_intel_bo_unreference(new_frame); + new_frame = NULL; + } + + if (!new_frame) { + uint32_t tiling_mode = I915_TILING_X; + unsigned long alloc_pitch; + + memset(offsets, 0, sizeof(offsets)); + + switch (id) { + case FOURCC_UYVY: + pixel_format = V4L2_PIX_FMT_UYVY; + break; + case FOURCC_YUY2: + default: + pixel_format = V4L2_PIX_FMT_YUYV; + break; + } + + new_frame = drm_intel_bo_alloc_tiled(intel->bufmgr, + "sprite buffer", + pixel_width, lines, + drawable->bitsPerPixel / 8, + &tiling_mode, &alloc_pitch, + BO_ALLOC_FOR_RENDER); + if (!new_frame) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to create bo for video data: %s\n", + strerror(errno)); + return BadAlloc; + } + adaptor_priv->reusable = TRUE; + adaptor_priv->buf = new_frame; + adaptor_priv->pitch = alloc_pitch; + ErrorF("allocated new frame, %dx%d, pitch %ld\n", pixel_width, + lines, alloc_pitch); + + pitches[0] = adaptor_priv->pitch; + + ret = drmModeAddFB2(intel->drmSubFD, pixel_width, lines, + pixel_format, new_frame->handle, + pitches, offsets, &fb_id); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to add fb (depth %d, bpp %d) " + "for video data: %s\n", + drawable->depth, drawable->bitsPerPixel, + strerror(errno)); + return BadAlloc; + } + adaptor_priv->fb_id = fb_id; + plane_updated = TRUE; + } + + if (intel_plane_moved(adaptor_priv, &dst_box) || + intel_source_changed(adaptor_priv, top, left, pixel_width, lines) || + adaptor_priv->crtc_id != crtc_id || + adaptor_priv->plane_id != plane_id) { + plane_updated = TRUE; + adaptor_priv->crtc_x = crtc_x; + adaptor_priv->crtc_y = crtc_y; + adaptor_priv->crtc_w = crtc_w; + adaptor_priv->crtc_h = crtc_h; + adaptor_priv->src_x = top; + adaptor_priv->src_y = left; + adaptor_priv->src_w = pixel_width; + adaptor_priv->src_h = lines; + /* Must have switched CRTCs, disable the old one */ + if (plane_id != adaptor_priv->plane_id) + drmModeSetPlane(intel->drmSubFD, adaptor_priv->plane_id, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + adaptor_priv->crtc_id = crtc_id; + adaptor_priv->plane_id = plane_id; + } + + if (drm_intel_gem_bo_map_gtt(new_frame)) + return BadAlloc; + + dst_base = new_frame->virtual; + dst = dst_base + adaptor_priv->YBufOffset; + + src = buf + (top * (width * 2)) + (left << 1); + + for (i = 0; i < height; i++) { + memcpy(dst, src, width * 2); + src += width * 2; + dst += adaptor_priv->pitch; + } + + drm_intel_gem_bo_unmap_gtt(new_frame); + + /* update cliplist */ + if (!REGION_EQUAL(scrn->pScreen, &adaptor_priv->clip, clipBoxes)) { + REGION_COPY(scrn->pScreen, &adaptor_priv->clip, clipBoxes); + xf86XVFillKeyHelperDrawable(drawable, adaptor_priv->colorKey, + clipBoxes); + } + + if (plane_updated) { + ret = drmModeSetPlane(intel->drmSubFD, plane_id, + crtc_id, adaptor_priv->fb_id, + crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, pixel_width, lines); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "failed to enable plane for video data: %s\n", + strerror(errno)); + return BadAlloc; + } + } + + return Success; +} + +static int intel_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; +} + +XF86VideoAdaptorPtr intel_setup_sprite(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86Screens[screen->myNum]; + intel_screen_private *intel = intel_get_screen_private(scrn); + XF86VideoAdaptorPtr adapt; + intel_adaptor_private *adaptor_priv; + drmModePlaneRes *plane_resources; + drmModePlane *planes; + + adapt = calloc(1, sizeof(XF86VideoAdaptorRec) + + sizeof(intel_adaptor_private) + sizeof(DevUnion)); + if (!adapt) + goto err; + + plane_resources = drmModeGetPlaneResources(intel->drmSubFD); + if (!plane_resources) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, "No sprite support\n"); + goto err_free_adaptor; + } + + planes = calloc(plane_resources->count_planes, sizeof(*planes)); + if (!planes) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Out of memory in %s\n", + __func__); + goto err_free_res; + } + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ; + adapt->name = "Intel(R) Video Sprite"; + adapt->nEncodings = ARRAY_SIZE(xv_dummy_encoding); + adapt->pEncodings = xnfalloc(sizeof(xv_dummy_encoding)); + memcpy(adapt->pEncodings, xv_dummy_encoding, sizeof(xv_dummy_encoding)); + adapt->nFormats = ARRAY_SIZE(xv_formats); + adapt->pFormats = xv_formats; + adapt->nPorts = 1; + adapt->pPortPrivates = (DevUnion *) (&adapt[1]); + + adaptor_priv = (intel_adaptor_private *)&adapt->pPortPrivates[1]; + adapt->pPortPrivates[0].ptr = (pointer) (adaptor_priv); + + adapt->nAttributes = ARRAY_SIZE(attribs); + adapt->pAttributes = attribs; + + adapt->nImages = ARRAY_SIZE(xv_images); + adapt->pImages = xv_images; + + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = intel_sprite_stop; + adapt->SetPortAttribute = intel_sprite_set_attr; + adapt->GetPortAttribute = intel_sprite_get_attr; + adapt->QueryBestSize = intel_sprite_best_size; + adapt->PutImage = intel_sprite_put; + adapt->QueryImageAttributes = intel_sprite_query_attrs; + + adaptor_priv->textured = FALSE; + adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1); + adaptor_priv->brightness = -19; /* (255/219) * -16 */ + adaptor_priv->contrast = 75; /* 255/219 * 64 */ + adaptor_priv->saturation = 146; /* 128/112 * 128 */ + adaptor_priv->desired_crtc = NULL; + adaptor_priv->buf = NULL; + adaptor_priv->old_buf[0] = NULL; + adaptor_priv->old_buf[1] = NULL; + adaptor_priv->gamma5 = 0xc0c0c0; + adaptor_priv->gamma4 = 0x808080; + adaptor_priv->gamma3 = 0x404040; + adaptor_priv->gamma2 = 0x202020; + adaptor_priv->gamma1 = 0x101010; + adaptor_priv->gamma0 = 0x080808; + adaptor_priv->planes = planes; + + adaptor_priv->rotation = RR_Rotate_0; + + /* gotta uninit this someplace */ + REGION_NULL(screen, &adaptor_priv->clip); + + intel->sprite_adaptor = adapt; + + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + + free(plane_resources); + + return adapt; + +err_free_res: + free(plane_resources); +err_free_adaptor: + free(adapt); +err: + return NULL; +} |