diff options
Diffstat (limited to 'src/uxa/intel_video.c')
-rw-r--r-- | src/uxa/intel_video.c | 1776 |
1 files changed, 1776 insertions, 0 deletions
diff --git a/src/uxa/intel_video.c b/src/uxa/intel_video.c new file mode 100644 index 00000000..c74b793b --- /dev/null +++ b/src/uxa/intel_video.c @@ -0,0 +1,1776 @@ +/*************************************************************************** + + Copyright 2000 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. + + **************************************************************************/ + +/* + * i830_video.c: i830/i845 Xv driver. + * + * Copyright © 2002 by Alan Hourihane and David Dawes + * + * Authors: + * Alan Hourihane <alanh@tungstengraphics.com> + * David Dawes <dawes@xfree86.org> + * + * Derived from i810 Xv driver: + * + * Authors of i810 code: + * Jonathan Bian <jonathan.bian@intel.com> + * Offscreen Images: + * Matt Sottek <matthew.j.sottek@intel.com> + */ + +/* + * XXX Could support more formats. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> +#include <math.h> +#include <string.h> +#include <assert.h> +#include <errno.h> + +#include "xf86.h" +#include "xf86_OSproc.h" +#include "compiler.h" +#include "xf86Pci.h" +#include "xf86fbman.h" +#include "xf86drm.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" + +#ifdef INTEL_XVMC +#define _INTEL_XVMC_SERVER_ +#include "intel_xvmc.h" +#endif + +#define OFF_DELAY 250 /* milliseconds */ + +#define OFF_TIMER 0x01 +#define CLIENT_VIDEO_ON 0x02 + +static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr); +static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr); +static void I830StopVideo(ScrnInfoPtr, pointer, Bool); +static int I830SetPortAttributeOverlay(ScrnInfoPtr, Atom, INT32, pointer); +static int I830SetPortAttributeTextured(ScrnInfoPtr, Atom, INT32, pointer); +static int I830GetPortAttribute(ScrnInfoPtr, Atom, INT32 *, pointer); +static void I830QueryBestSize(ScrnInfoPtr, Bool, + short, short, short, short, unsigned int *, + unsigned int *, pointer); +static int I830PutImageTextured(ScrnInfoPtr, short, short, short, short, short, short, + short, short, int, unsigned char *, short, short, + Bool, RegionPtr, pointer, DrawablePtr); +static int I830PutImageOverlay(ScrnInfoPtr, short, short, short, short, short, short, + short, short, int, unsigned char *, short, short, + Bool, RegionPtr, pointer, DrawablePtr); +static int I830QueryImageAttributes(ScrnInfoPtr, int, unsigned short *, + unsigned short *, int *, int *); + +#define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE) + +static Atom xvBrightness, xvContrast, xvSaturation, xvColorKey, xvPipe; +static Atom xvGamma0, xvGamma1, xvGamma2, xvGamma3, xvGamma4, xvGamma5; +static Atom xvSyncToVblank; + +/* Limits for the overlay/textured video source sizes. The documented hardware + * limits are 2048x2048 or better for overlay and both of our textured video + * implementations. Additionally, on the 830 and 845, larger sizes resulted in + * the card hanging, so we keep the limits lower there. + */ +#define IMAGE_MAX_WIDTH 2048 +#define IMAGE_MAX_HEIGHT 2048 +#define IMAGE_MAX_WIDTH_LEGACY 1024 +#define IMAGE_MAX_HEIGHT_LEGACY 1088 + +/* overlay debugging printf function */ +#if 0 +#define OVERLAY_DEBUG ErrorF +#else +#define OVERLAY_DEBUG if (0) ErrorF +#endif + +/* client libraries expect an encoding */ +static const XF86VideoEncodingRec DummyEncoding[1] = { + { + 0, + "XV_IMAGE", + IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT, + {1, 1} + } +}; + +#define NUM_FORMATS 3 + +static XF86VideoFormatRec Formats[NUM_FORMATS] = { + {15, TrueColor}, {16, TrueColor}, {24, TrueColor} +}; + +#define NUM_ATTRIBUTES 5 +static XF86AttributeRec Attributes[NUM_ATTRIBUTES] = { + {XvSettable | XvGettable, 0, (1 << 24) - 1, "XV_COLORKEY"}, + {XvSettable | XvGettable, -128, 127, "XV_BRIGHTNESS"}, + {XvSettable | XvGettable, 0, 255, "XV_CONTRAST"}, + {XvSettable | XvGettable, 0, 1023, "XV_SATURATION"}, + {XvSettable | XvGettable, -1, 1, "XV_PIPE"} +}; + +#define GAMMA_ATTRIBUTES 6 +static XF86AttributeRec GammaAttributes[GAMMA_ATTRIBUTES] = { + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA0"}, + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA1"}, + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA2"}, + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA3"}, + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA4"}, + {XvSettable | XvGettable, 0, 0xffffff, "XV_GAMMA5"} +}; + +#ifdef INTEL_XVMC +#define NUM_IMAGES 5 +#define XVMC_IMAGE 1 +#else +#define NUM_IMAGES 4 +#define XVMC_IMAGE 0 +#endif + +static XF86ImageRec Images[NUM_IMAGES] = { + XVIMAGE_YUY2, + XVIMAGE_YV12, + XVIMAGE_I420, + XVIMAGE_UYVY, +#ifdef INTEL_XVMC + { + /* + * Below, a dummy picture type that is used in XvPutImage only to do + * an overlay update. Introduced for the XvMC client lib. + * Defined to have a zero data size. + */ + FOURCC_XVMC, + XvYUV, + LSBFirst, + {'X', 'V', 'M', 'C', + 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0xAA, 0x00, + 0x38, 0x9B, 0x71}, + 12, + XvPlanar, + 3, + 0, 0, 0, 0, + 8, 8, 8, + 1, 2, 2, + 1, 2, 2, + {'Y', 'V', 'U', + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + XvTopToBottom}, +#endif +}; + +/* kernel modesetting overlay functions */ +static Bool intel_has_overlay(intel_screen_private *intel) +{ + struct drm_i915_getparam gp; + int has_overlay = 0; + int ret; + + gp.param = I915_PARAM_HAS_OVERLAY; + gp.value = &has_overlay; + ret = drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, sizeof(gp)); + + return ret == 0 && !! has_overlay; +} + +static Bool intel_overlay_update_attrs(intel_screen_private *intel) +{ + intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); + struct drm_intel_overlay_attrs attrs; + + attrs.flags = I915_OVERLAY_UPDATE_ATTRS; + attrs.brightness = adaptor_priv->brightness; + attrs.contrast = adaptor_priv->contrast; + attrs.saturation = adaptor_priv->saturation; + attrs.color_key = adaptor_priv->colorKey; + attrs.gamma0 = adaptor_priv->gamma0; + attrs.gamma1 = adaptor_priv->gamma1; + attrs.gamma2 = adaptor_priv->gamma2; + attrs.gamma3 = adaptor_priv->gamma3; + attrs.gamma4 = adaptor_priv->gamma4; + attrs.gamma5 = adaptor_priv->gamma5; + + return drmCommandWriteRead(intel->drmSubFD, DRM_I915_OVERLAY_ATTRS, + &attrs, sizeof(attrs)) == 0; +} + +static void intel_overlay_off(intel_screen_private *intel) +{ + struct drm_intel_overlay_put_image request; + int ret; + + request.flags = 0; + + ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, + &request, sizeof(request)); + (void) ret; +} + +static Bool +intel_overlay_put_image(intel_screen_private *intel, + xf86CrtcPtr crtc, + int id, short width, short height, + int dstPitch, int dstPitch2, + BoxPtr dstBox, short src_w, short src_h, short drw_w, + short drw_h) +{ + intel_adaptor_private *adaptor_priv = intel_get_adaptor_private(intel); + struct drm_intel_overlay_put_image request; + int ret; + int planar = is_planar_fourcc(id); + float scale; + dri_bo *tmp; + + request.flags = I915_OVERLAY_ENABLE; + + request.bo_handle = adaptor_priv->buf->handle; + if (planar) { + request.stride_Y = dstPitch2; + request.stride_UV = dstPitch; + } else { + request.stride_Y = dstPitch; + request.stride_UV = 0; + } + request.offset_Y = adaptor_priv->YBufOffset; + request.offset_U = adaptor_priv->UBufOffset; + request.offset_V = adaptor_priv->VBufOffset; + OVERLAY_DEBUG("off_Y: %i, off_U: %i, off_V: %i\n", request.offset_Y, + request.offset_U, request.offset_V); + + request.crtc_id = intel_crtc_id(crtc); + request.dst_x = dstBox->x1; + request.dst_y = dstBox->y1; + request.dst_width = dstBox->x2 - dstBox->x1; + request.dst_height = dstBox->y2 - dstBox->y1; + + request.src_width = width; + request.src_height = height; + /* adjust src dimensions */ + if (request.dst_height > 1) { + scale = ((float)request.dst_height - 1) / ((float)drw_h - 1); + request.src_scan_height = src_h * scale; + } else + request.src_scan_height = 1; + + if (request.dst_width > 1) { + scale = ((float)request.dst_width - 1) / ((float)drw_w - 1); + request.src_scan_width = src_w * scale; + } else + request.src_scan_width = 1; + + if (planar) { + request.flags |= I915_OVERLAY_YUV_PLANAR | I915_OVERLAY_YUV420; + } else { + request.flags |= I915_OVERLAY_YUV_PACKED | I915_OVERLAY_YUV422; + if (id == FOURCC_UYVY) + request.flags |= I915_OVERLAY_Y_SWAP; + } + + ret = drmCommandWrite(intel->drmSubFD, DRM_I915_OVERLAY_PUT_IMAGE, + &request, sizeof(request)); + if (ret) + return FALSE; + + if (!adaptor_priv->reusable) { + drm_intel_bo_unreference(adaptor_priv->buf); + adaptor_priv->buf = NULL; + adaptor_priv->reusable = TRUE; + } + + tmp = adaptor_priv->old_buf[1]; + adaptor_priv->old_buf[1] = adaptor_priv->old_buf[0]; + adaptor_priv->old_buf[0] = adaptor_priv->buf; + adaptor_priv->buf = tmp; + + return TRUE; +} + +void I830InitVideo(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + intel_screen_private *intel = intel_get_screen_private(scrn); + XF86VideoAdaptorPtr *adaptors = NULL, *newAdaptors = NULL; + XF86VideoAdaptorPtr overlayAdaptor = NULL, texturedAdaptor = NULL; + int num_adaptors = xf86XVListGenericAdaptors(scrn, &adaptors); + /* Give our adaptor list enough space for the overlay and/or texture video + * adaptors. + */ + newAdaptors = realloc(adaptors, + (num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr)); + if (newAdaptors == NULL) { + free(adaptors); + return; + } + adaptors = newAdaptors; + + /* Add the adaptors supported by our hardware. First, set up the atoms + * that will be used by both output adaptors. + */ + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + + /* Set up textured video if we can do it at this depth and we are on + * supported hardware. + */ + if (scrn->bitsPerPixel >= 16 && + INTEL_INFO(intel)->gen >= 030) { + texturedAdaptor = I830SetupImageVideoTextured(screen); + if (texturedAdaptor != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Set up textured video\n"); + } else { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to set up textured video\n"); + } + } + + /* Set up overlay video if it is available */ + intel->use_overlay = intel_has_overlay(intel); + if (intel->use_overlay) { + overlayAdaptor = I830SetupImageVideoOverlay(screen); + if (overlayAdaptor != NULL) { + xf86DrvMsg(scrn->scrnIndex, X_INFO, + "Set up overlay video\n"); + } else { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "Failed to set up overlay video\n"); + } + } + + if (overlayAdaptor && intel->XvPreferOverlay) + adaptors[num_adaptors++] = overlayAdaptor; + + if (texturedAdaptor) + adaptors[num_adaptors++] = texturedAdaptor; + + if (overlayAdaptor && !intel->XvPreferOverlay) + adaptors[num_adaptors++] = overlayAdaptor; + + if (num_adaptors) { + xf86XVScreenInit(screen, adaptors, num_adaptors); + } else { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Disabling Xv because no adaptors could be initialized.\n"); + intel->XvEnabled = FALSE; + } + +#ifdef INTEL_XVMC + if (texturedAdaptor) + intel_xvmc_adaptor_init(screen); +#endif + free(adaptors); +} + +static XF86VideoAdaptorPtr I830SetupImageVideoOverlay(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + intel_screen_private *intel = intel_get_screen_private(scrn); + XF86VideoAdaptorPtr adapt; + intel_adaptor_private *adaptor_priv; + XF86AttributePtr att; + + OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); + + if (!(adapt = calloc(1, + sizeof(XF86VideoAdaptorRec) + + sizeof(intel_adaptor_private) + + sizeof(DevUnion)))) + return NULL; + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = VIDEO_OVERLAID_IMAGES /*| VIDEO_CLIP_TO_VIEWPORT */ ; + adapt->name = "Intel(R) Video Overlay"; + adapt->nEncodings = 1; + adapt->pEncodings = xnfalloc(sizeof(DummyEncoding)); + memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding)); + if (IS_845G(intel) || IS_I830(intel)) { + adapt->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY; + adapt->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY; + } + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = 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 = NUM_ATTRIBUTES; + if (INTEL_INFO(intel)->gen >= 030) + adapt->nAttributes += GAMMA_ATTRIBUTES; /* has gamma */ + adapt->pAttributes = + xnfalloc(sizeof(XF86AttributeRec) * adapt->nAttributes); + /* Now copy the attributes */ + att = adapt->pAttributes; + memcpy((char *)att, (char *)Attributes, + sizeof(XF86AttributeRec) * NUM_ATTRIBUTES); + att += NUM_ATTRIBUTES; + if (INTEL_INFO(intel)->gen >= 030) { + memcpy((char *)att, (char *)GammaAttributes, + sizeof(XF86AttributeRec) * GAMMA_ATTRIBUTES); + } + adapt->nImages = NUM_IMAGES - XVMC_IMAGE; + + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = I830StopVideo; + adapt->SetPortAttribute = I830SetPortAttributeOverlay; + adapt->GetPortAttribute = I830GetPortAttribute; + adapt->QueryBestSize = I830QueryBestSize; + adapt->PutImage = I830PutImageOverlay; + adapt->QueryImageAttributes = I830QueryImageAttributes; + + adaptor_priv->textured = FALSE; + adaptor_priv->colorKey = intel->colorKey & ((1 << scrn->depth) - 1); + adaptor_priv->videoStatus = 0; + 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->rotation = RR_Rotate_0; + + /* gotta uninit this someplace */ + REGION_NULL(screen, &adaptor_priv->clip); + + intel->adaptor = adapt; + + xvColorKey = MAKE_ATOM("XV_COLORKEY"); + xvBrightness = MAKE_ATOM("XV_BRIGHTNESS"); + xvContrast = MAKE_ATOM("XV_CONTRAST"); + xvSaturation = MAKE_ATOM("XV_SATURATION"); + + /* Allow the pipe to be switched from pipe A to B when in clone mode */ + xvPipe = MAKE_ATOM("XV_PIPE"); + + if (INTEL_INFO(intel)->gen >= 030) { + xvGamma0 = MAKE_ATOM("XV_GAMMA0"); + xvGamma1 = MAKE_ATOM("XV_GAMMA1"); + xvGamma2 = MAKE_ATOM("XV_GAMMA2"); + xvGamma3 = MAKE_ATOM("XV_GAMMA3"); + xvGamma4 = MAKE_ATOM("XV_GAMMA4"); + xvGamma5 = MAKE_ATOM("XV_GAMMA5"); + } + + intel_overlay_update_attrs(intel); + + return adapt; +} + +static XF86VideoAdaptorPtr I830SetupImageVideoTextured(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + intel_screen_private *intel = intel_get_screen_private(scrn); + XF86VideoAdaptorPtr adapt; + intel_adaptor_private *adaptor_privs; + DevUnion *devUnions; + int nports = 16, i; + + OVERLAY_DEBUG("I830SetupImageVideoOverlay\n"); + + adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); + adaptor_privs = calloc(nports, sizeof(intel_adaptor_private)); + devUnions = calloc(nports, sizeof(DevUnion)); + if (adapt == NULL || adaptor_privs == NULL || devUnions == NULL) { + free(adapt); + free(adaptor_privs); + free(devUnions); + return NULL; + } + + adapt->type = XvWindowMask | XvInputMask | XvImageMask; + adapt->flags = 0; + adapt->name = "Intel(R) Textured Video"; + adapt->nEncodings = 1; + adapt->pEncodings = xnfalloc(sizeof(DummyEncoding)); + memcpy(adapt->pEncodings, DummyEncoding, sizeof(DummyEncoding)); + adapt->nFormats = NUM_FORMATS; + adapt->pFormats = Formats; + adapt->nPorts = nports; + adapt->pPortPrivates = devUnions; + adapt->nAttributes = 0; + adapt->pAttributes = NULL; + if (IS_I915G(intel) || IS_I915GM(intel)) + adapt->nImages = NUM_IMAGES - XVMC_IMAGE; + else + adapt->nImages = NUM_IMAGES; + + adapt->pImages = Images; + adapt->PutVideo = NULL; + adapt->PutStill = NULL; + adapt->GetVideo = NULL; + adapt->GetStill = NULL; + adapt->StopVideo = I830StopVideo; + adapt->SetPortAttribute = I830SetPortAttributeTextured; + adapt->GetPortAttribute = I830GetPortAttribute; + adapt->QueryBestSize = I830QueryBestSize; + adapt->PutImage = I830PutImageTextured; + adapt->QueryImageAttributes = I830QueryImageAttributes; + + for (i = 0; i < nports; i++) { + intel_adaptor_private *adaptor_priv = &adaptor_privs[i]; + + adaptor_priv->textured = TRUE; + adaptor_priv->videoStatus = 0; + adaptor_priv->buf = NULL; + adaptor_priv->old_buf[0] = NULL; + adaptor_priv->old_buf[1] = NULL; + + adaptor_priv->rotation = RR_Rotate_0; + adaptor_priv->SyncToVblank = 1; + + /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ + REGION_NULL(screen, &adaptor_priv->clip); + + adapt->pPortPrivates[i].ptr = (pointer) (adaptor_priv); + } + + xvSyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); + + return adapt; +} + +static void intel_free_video_buffers(intel_adaptor_private *adaptor_priv) +{ + int i; + + for (i = 0; i < 2; i++) { + if (adaptor_priv->old_buf[i]) { + drm_intel_bo_disable_reuse(adaptor_priv->old_buf[i]); + drm_intel_bo_unreference(adaptor_priv->old_buf[i]); + adaptor_priv->old_buf[i] = NULL; + } + } + + if (adaptor_priv->buf) { + drm_intel_bo_unreference(adaptor_priv->buf); + adaptor_priv->buf = NULL; + } +} + +static void I830StopVideo(ScrnInfoPtr scrn, pointer data, Bool shutdown) +{ + intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; + + if (adaptor_priv->textured) + return; + + OVERLAY_DEBUG("I830StopVideo\n"); + + REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip); + + if (shutdown) { + if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) + intel_overlay_off(intel_get_screen_private(scrn)); + + intel_free_video_buffers(adaptor_priv); + adaptor_priv->videoStatus = 0; + } else { + if (adaptor_priv->videoStatus & CLIENT_VIDEO_ON) { + adaptor_priv->videoStatus |= OFF_TIMER; + adaptor_priv->offTime = currentTime.milliseconds + OFF_DELAY; + } + } + +} + +static int +I830SetPortAttributeTextured(ScrnInfoPtr scrn, + Atom attribute, INT32 value, pointer data) +{ + intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; + + if (attribute == xvBrightness) { + if ((value < -128) || (value > 127)) + return BadValue; + adaptor_priv->brightness = value; + return Success; + } else if (attribute == xvContrast) { + if ((value < 0) || (value > 255)) + return BadValue; + adaptor_priv->contrast = value; + return Success; + } else if (attribute == xvSyncToVblank) { + if ((value < -1) || (value > 1)) + return BadValue; + adaptor_priv->SyncToVblank = value; + return Success; + } else { + return BadMatch; + } +} + +static int +I830SetPortAttributeOverlay(ScrnInfoPtr scrn, + Atom attribute, INT32 value, pointer data) +{ + intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; + intel_screen_private *intel = intel_get_screen_private(scrn); + + if (attribute == xvBrightness) { + if ((value < -128) || (value > 127)) + return BadValue; + adaptor_priv->brightness = value; + OVERLAY_DEBUG("BRIGHTNESS\n"); + } else if (attribute == xvContrast) { + if ((value < 0) || (value > 255)) + return BadValue; + adaptor_priv->contrast = value; + OVERLAY_DEBUG("CONTRAST\n"); + } else if (attribute == xvSaturation) { + if ((value < 0) || (value > 1023)) + return BadValue; + adaptor_priv->saturation = value; + } else if (attribute == xvPipe) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + if ((value < -1) || (value >= xf86_config->num_crtc)) + return BadValue; + if (value < 0) + adaptor_priv->desired_crtc = NULL; + else + adaptor_priv->desired_crtc = xf86_config->crtc[value]; + } else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma0 = value; + } else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma1 = value; + } else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma2 = value; + } else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma3 = value; + } else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma4 = value; + } else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) { + adaptor_priv->gamma5 = value; + } else if (attribute == xvColorKey) { + adaptor_priv->colorKey = value; + OVERLAY_DEBUG("COLORKEY\n"); + } else + return BadMatch; + + if ((attribute == xvGamma0 || + attribute == xvGamma1 || + attribute == xvGamma2 || + attribute == xvGamma3 || + attribute == xvGamma4 || + attribute == xvGamma5) && (INTEL_INFO(intel)->gen >= 030)) { + OVERLAY_DEBUG("GAMMA\n"); + } + + if (!intel_overlay_update_attrs(intel)) + return BadValue; + + if (attribute == xvColorKey) + REGION_EMPTY(scrn->pScreen, &adaptor_priv->clip); + + return Success; +} + +static int +I830GetPortAttribute(ScrnInfoPtr scrn, + Atom attribute, INT32 * value, pointer data) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; + + if (attribute == xvBrightness) { + *value = adaptor_priv->brightness; + } else if (attribute == xvContrast) { + *value = adaptor_priv->contrast; + } else if (attribute == xvSaturation) { + *value = adaptor_priv->saturation; + } else if (attribute == xvPipe) { + int c; + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + for (c = 0; c < xf86_config->num_crtc; c++) + if (xf86_config->crtc[c] == adaptor_priv->desired_crtc) + break; + if (c == xf86_config->num_crtc) + c = -1; + *value = c; + } else if (attribute == xvGamma0 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma0; + } else if (attribute == xvGamma1 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma1; + } else if (attribute == xvGamma2 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma2; + } else if (attribute == xvGamma3 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma3; + } else if (attribute == xvGamma4 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma4; + } else if (attribute == xvGamma5 && (INTEL_INFO(intel)->gen >= 030)) { + *value = adaptor_priv->gamma5; + } else if (attribute == xvColorKey) { + *value = adaptor_priv->colorKey; + } else if (attribute == xvSyncToVblank) { + *value = adaptor_priv->SyncToVblank; + } else + return BadMatch; + + return Success; +} + +static void +I830QueryBestSize(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) +{ + if (vid_w > (drw_w << 1)) + drw_w = vid_w >> 1; + if (vid_h > (drw_h << 1)) + drw_h = vid_h >> 1; + + *p_w = drw_w; + *p_h = drw_h; +} + +static Bool +I830CopyPackedData(intel_adaptor_private *adaptor_priv, + unsigned char *buf, + int srcPitch, int dstPitch, int top, int left, int h, int w) +{ + unsigned char *src, *dst, *dst_base; + int i, j; + unsigned char *s; + +#if 0 + ErrorF("I830CopyPackedData: (%d,%d) (%d,%d)\n" + "srcPitch: %d, dstPitch: %d\n", top, left, h, w, + srcPitch, dstPitch); +#endif + + src = buf + (top * srcPitch) + (left << 1); + + if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf)) + return FALSE; + + dst_base = adaptor_priv->buf->virtual; + + dst = dst_base + adaptor_priv->YBufOffset; + + switch (adaptor_priv->rotation) { + case RR_Rotate_0: + w <<= 1; + for (i = 0; i < h; i++) { + memcpy(dst, src, w); + src += srcPitch; + dst += dstPitch; + } + break; + case RR_Rotate_90: + h <<= 1; + for (i = 0; i < h; i += 2) { + s = src; + for (j = 0; j < w; j++) { + /* Copy Y */ + dst[(i + 0) + ((w - j - 1) * dstPitch)] = *s++; + (void)*s++; + } + src += srcPitch; + } + h >>= 1; + src = buf + (top * srcPitch) + (left << 1); + for (i = 0; i < h; i += 2) { + for (j = 0; j < w; j += 2) { + /* Copy U */ + dst[((i * 2) + 1) + ((w - j - 1) * dstPitch)] = + src[(j * 2) + 1 + (i * srcPitch)]; + dst[((i * 2) + 1) + ((w - j - 2) * dstPitch)] = + src[(j * 2) + 1 + ((i + 1) * srcPitch)]; + /* Copy V */ + dst[((i * 2) + 3) + ((w - j - 1) * dstPitch)] = + src[(j * 2) + 3 + (i * srcPitch)]; + dst[((i * 2) + 3) + ((w - j - 2) * dstPitch)] = + src[(j * 2) + 3 + ((i + 1) * srcPitch)]; + } + } + break; + case RR_Rotate_180: + w <<= 1; + for (i = 0; i < h; i++) { + s = src; + for (j = 0; j < w; j += 4) { + dst[(w - j - 4) + ((h - i - 1) * dstPitch)] = + *s++; + dst[(w - j - 3) + ((h - i - 1) * dstPitch)] = + *s++; + dst[(w - j - 2) + ((h - i - 1) * dstPitch)] = + *s++; + dst[(w - j - 1) + ((h - i - 1) * dstPitch)] = + *s++; + } + src += srcPitch; + } + break; + case RR_Rotate_270: + h <<= 1; + for (i = 0; i < h; i += 2) { + s = src; + for (j = 0; j < w; j++) { + /* Copy Y */ + dst[(h - i - 2) + (j * dstPitch)] = *s++; + (void)*s++; + } + src += srcPitch; + } + h >>= 1; + src = buf + (top * srcPitch) + (left << 1); + for (i = 0; i < h; i += 2) { + for (j = 0; j < w; j += 2) { + /* Copy U */ + dst[(((h - i) * 2) - 3) + (j * dstPitch)] = + src[(j * 2) + 1 + (i * srcPitch)]; + dst[(((h - i) * 2) - 3) + + ((j + 1) * dstPitch)] = + src[(j * 2) + 1 + ((i + 1) * srcPitch)]; + /* Copy V */ + dst[(((h - i) * 2) - 1) + (j * dstPitch)] = + src[(j * 2) + 3 + (i * srcPitch)]; + dst[(((h - i) * 2) - 1) + + ((j + 1) * dstPitch)] = + src[(j * 2) + 3 + ((i + 1) * srcPitch)]; + } + } + break; + } + + drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf); + return TRUE; +} + +static void intel_memcpy_plane(unsigned char *dst, unsigned char *src, + int height, int width, + int dstPitch, int srcPitch, Rotation rotation) +{ + int i, j = 0; + unsigned char *s; + + switch (rotation) { + case RR_Rotate_0: + /* optimise for the case of no clipping */ + if (srcPitch == dstPitch && srcPitch == width) + memcpy(dst, src, srcPitch * height); + else + for (i = 0; i < height; i++) { + memcpy(dst, src, width); + src += srcPitch; + dst += dstPitch; + } + break; + case RR_Rotate_90: + for (i = 0; i < height; i++) { + s = src; + for (j = 0; j < width; j++) { + dst[(i) + ((width - j - 1) * dstPitch)] = *s++; + } + src += srcPitch; + } + break; + case RR_Rotate_180: + for (i = 0; i < height; i++) { + s = src; + for (j = 0; j < width; j++) { + dst[(width - j - 1) + + ((height - i - 1) * dstPitch)] = *s++; + } + src += srcPitch; + } + break; + case RR_Rotate_270: + for (i = 0; i < height; i++) { + s = src; + for (j = 0; j < width; j++) { + dst[(height - i - 1) + (j * dstPitch)] = *s++; + } + src += srcPitch; + } + break; + } +} + +static Bool +I830CopyPlanarData(intel_adaptor_private *adaptor_priv, + unsigned char *buf, int srcPitch, int srcPitch2, + int dstPitch, int dstPitch2, + int srcH, int top, int left, + int h, int w, int id) +{ + unsigned char *src1, *src2, *src3, *dst_base, *dst1, *dst2, *dst3; + +#if 0 + ErrorF("I830CopyPlanarData: srcPitch %d, srcPitch %d, dstPitch %d\n" + "nlines %d, npixels %d, top %d, left %d\n", + srcPitch, srcPitch2, dstPitch, h, w, top, left); +#endif + + /* Copy Y data */ + src1 = buf + (top * srcPitch) + left; +#if 0 + ErrorF("src1 is %p, offset is %ld\n", src1, + (unsigned long)src1 - (unsigned long)buf); +#endif + + if (drm_intel_gem_bo_map_gtt(adaptor_priv->buf)) + return FALSE; + + dst_base = adaptor_priv->buf->virtual; + + dst1 = dst_base + adaptor_priv->YBufOffset; + + intel_memcpy_plane(dst1, src1, h, w, dstPitch2, srcPitch, + adaptor_priv->rotation); + + /* Copy V data for YV12, or U data for I420 */ + src2 = buf + /* start of YUV data */ + (srcH * srcPitch) + /* move over Luma plane */ + ((top >> 1) * srcPitch2) + /* move down from by top lines */ + (left >> 1); /* move left by left pixels */ + +#if 0 + ErrorF("src2 is %p, offset is %ld\n", src2, + (unsigned long)src2 - (unsigned long)buf); +#endif + if (id == FOURCC_I420) + dst2 = dst_base + adaptor_priv->UBufOffset; + else + dst2 = dst_base + adaptor_priv->VBufOffset; + + intel_memcpy_plane(dst2, src2, h / 2, w / 2, + dstPitch, srcPitch2, adaptor_priv->rotation); + + /* Copy U data for YV12, or V data for I420 */ + src3 = buf + /* start of YUV data */ + (srcH * srcPitch) + /* move over Luma plane */ + ((srcH >> 1) * srcPitch2) + /* move over Chroma plane */ + ((top >> 1) * srcPitch2) + /* move down from by top lines */ + (left >> 1); /* move left by left pixels */ +#if 0 + ErrorF("src3 is %p, offset is %ld\n", src3, + (unsigned long)src3 - (unsigned long)buf); +#endif + if (id == FOURCC_I420) + dst3 = dst_base + adaptor_priv->VBufOffset; + else + dst3 = dst_base + adaptor_priv->UBufOffset; + + intel_memcpy_plane(dst3, src3, h / 2, w / 2, + dstPitch, srcPitch2, adaptor_priv->rotation); + + drm_intel_gem_bo_unmap_gtt(adaptor_priv->buf); + return TRUE; +} + +static void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) +{ + dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; + dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; + dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; + dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; + if (dest->x1 >= dest->x2 || dest->y1 >= dest->y2) + dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; +} + +static void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) +{ + if (crtc->enabled) { + crtc_box->x1 = crtc->x; + crtc_box->x2 = + crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); + crtc_box->y1 = crtc->y; + crtc_box->y2 = + crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); + } else + crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; +} + +static int intel_box_area(BoxPtr box) +{ + return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); +} + +/* + * Return the crtc covering 'box'. If two crtcs cover a portion of + * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc + * with greater coverage + */ + +xf86CrtcPtr +intel_covering_crtc(ScrnInfoPtr scrn, + BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + xf86CrtcPtr crtc, best_crtc; + int coverage, best_coverage; + int c; + BoxRec crtc_box, cover_box; + + best_crtc = NULL; + best_coverage = 0; + crtc_box_ret->x1 = 0; + crtc_box_ret->x2 = 0; + crtc_box_ret->y1 = 0; + crtc_box_ret->y2 = 0; + for (c = 0; c < xf86_config->num_crtc; c++) { + crtc = xf86_config->crtc[c]; + + /* If the CRTC is off, treat it as not covering */ + if (!intel_crtc_on(crtc)) + continue; + + intel_crtc_box(crtc, &crtc_box); + intel_box_intersect(&cover_box, &crtc_box, box); + coverage = intel_box_area(&cover_box); + if (coverage && crtc == desired) { + *crtc_box_ret = crtc_box; + return crtc; + } + if (coverage > best_coverage) { + *crtc_box_ret = crtc_box; + best_crtc = crtc; + best_coverage = coverage; + } + } + return best_crtc; +} + +static void +intel_update_dst_box_to_crtc_coords(ScrnInfoPtr scrn, xf86CrtcPtr crtc, + BoxPtr dstBox) +{ + int tmp; + + /* for overlay, we should take it from crtc's screen + * coordinate to current crtc's display mode. + * yeah, a bit confusing. + */ + 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; + } + + return; +} + +int is_planar_fourcc(int id) +{ + switch (id) { + case FOURCC_YV12: + case FOURCC_I420: +#ifdef INTEL_XVMC + case FOURCC_XVMC: +#endif + return 1; + case FOURCC_UYVY: + case FOURCC_YUY2: + return 0; + default: + ErrorF("Unknown format 0x%x\n", id); + return 0; + } +} + +static int xvmc_passthrough(int id) +{ +#ifdef INTEL_XVMC + return id == FOURCC_XVMC; +#else + return 0; +#endif +} + +static Bool +intel_display_overlay(ScrnInfoPtr scrn, xf86CrtcPtr crtc, + int id, short width, short height, + int dstPitch, int dstPitch2, + BoxPtr dstBox, short src_w, short src_h, short drw_w, + short drw_h) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + int tmp; + + OVERLAY_DEBUG("I830DisplayVideo: %dx%d (pitch %d)\n", width, height, + dstPitch); + + /* + * If the video isn't visible on any CRTC, turn it off + */ + if (!crtc) { + intel_overlay_off(intel); + return TRUE; + } + + intel_update_dst_box_to_crtc_coords(scrn, crtc, dstBox); + + if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + tmp = width; + width = height; + height = tmp; + tmp = drw_w; + drw_w = drw_h; + drw_h = tmp; + tmp = src_w; + src_w = src_h; + src_h = tmp; + } + + return intel_overlay_put_image(intel, crtc, id, + width, height, + dstPitch, dstPitch2, dstBox, + src_w, src_h, drw_w, drw_h); +} + +static Bool +intel_clip_video_helper(ScrnInfoPtr scrn, + intel_adaptor_private *adaptor_priv, + xf86CrtcPtr * crtc_ret, + BoxPtr dst, + 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, + int *top, int* left, int* npixels, int *nlines, + RegionPtr reg, INT32 width, INT32 height) +{ + Bool ret; + RegionRec crtc_region_local; + RegionPtr crtc_region = reg; + BoxRec crtc_box; + INT32 x1, x2, y1, y2; + xf86CrtcPtr crtc; + + x1 = src_x; + x2 = src_x + src_w; + y1 = src_y; + y2 = src_y + src_h; + + dst->x1 = drw_x; + dst->x2 = drw_x + drw_w; + dst->y1 = drw_y; + dst->y2 = drw_y + drw_h; + + /* + * For overlay video, compute the relevant CRTC and + * clip video to that + */ + crtc = intel_covering_crtc(scrn, dst, adaptor_priv->desired_crtc, + &crtc_box); + + /* For textured video, we don't actually want to clip at all. */ + if (crtc && !adaptor_priv->textured) { + REGION_INIT(screen, &crtc_region_local, &crtc_box, 1); + crtc_region = &crtc_region_local; + REGION_INTERSECT(screen, crtc_region, crtc_region, + reg); + } + *crtc_ret = crtc; + + ret = xf86XVClipVideoHelper(dst, &x1, &x2, &y1, &y2, + crtc_region, width, height); + if (crtc_region != reg) + REGION_UNINIT(screen, &crtc_region_local); + + *top = y1 >> 16; + *left = (x1 >> 16) & ~1; + *npixels = ALIGN(((x2 + 0xffff) >> 16), 2) - *left; + if (is_planar_fourcc(id)) { + *top &= ~1; + *nlines = ALIGN(((y2 + 0xffff) >> 16), 2) - *top; + } else + *nlines = ((y2 + 0xffff) >> 16) - *top; + + return ret; +} + +static void +intel_wait_for_scanline(ScrnInfoPtr scrn, PixmapPtr pixmap, + xf86CrtcPtr crtc, RegionPtr clipBoxes) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + pixman_box16_t box, crtc_box; + int pipe, event; + Bool full_height; + int y1, y2; + + pipe = -1; + if (scrn->vtSema && pixmap_is_scanout(pixmap)) + pipe = intel_crtc_to_pipe(crtc); + if (pipe < 0) + return; + + box = *REGION_EXTENTS(unused, clipBoxes); + + if (crtc->transform_in_use) + pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box); + + /* We could presume the clip was correctly computed... */ + intel_crtc_box(crtc, &crtc_box); + intel_box_intersect(&box, &crtc_box, &box); + + /* + * Make sure we don't wait for a scanline that will + * never occur + */ + y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0; + y2 = (box.y2 <= crtc_box.y2) ? + box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1; + if (y2 <= y1) + return; + + full_height = FALSE; + if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1)) + full_height = TRUE; + + /* + * Pre-965 doesn't have SVBLANK, so we need a bit + * of extra time for the blitter to start up and + * do its job for a full height blit + */ + if (full_height && INTEL_INFO(intel)->gen < 040) + y2 -= 2; + + if (pipe == 0) { + pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; + event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; + if (full_height && INTEL_INFO(intel)->gen >= 040) + event = MI_WAIT_FOR_PIPEA_SVBLANK; + } else { + pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; + event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; + if (full_height && INTEL_INFO(intel)->gen >= 040) + event = MI_WAIT_FOR_PIPEB_SVBLANK; + } + + if (crtc->mode.Flags & V_INTERLACE) { + /* DSL count field lines */ + y1 /= 2; + y2 /= 2; + } + + BEGIN_BATCH(5); + /* The documentation says that the LOAD_SCAN_LINES command + * always comes in pairs. Don't ask me why. */ + OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); + OUT_BATCH((y1 << 16) | (y2-1)); + OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); + OUT_BATCH((y1 << 16) | (y2-1)); + OUT_BATCH(MI_WAIT_FOR_EVENT | event); + ADVANCE_BATCH(); +} + +static Bool +intel_setup_video_buffer(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, + int alloc_size, int id, unsigned char *buf) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + + /* Free the current buffer if we're going to have to reallocate */ + if (adaptor_priv->buf && adaptor_priv->buf->size < alloc_size) + intel_free_video_buffers(adaptor_priv); + + if (adaptor_priv->buf == NULL) { + adaptor_priv->buf = drm_intel_bo_alloc(intel->bufmgr, "xv buffer", + alloc_size, 4096); + if (adaptor_priv->buf == NULL) + return FALSE; + + adaptor_priv->reusable = TRUE; + } + + return TRUE; +} + +static void +intel_setup_dst_params(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, short width, + short height, int *dstPitch, int *dstPitch2, int *size, + int id) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + int pitchAlign; + + /* Only needs to be DWORD-aligned for textured on i915, but overlay has + * stricter requirements. + */ + if (adaptor_priv->textured) { + pitchAlign = 4; + } else { + if (INTEL_INFO(intel)->gen >= 040) + /* Actually the alignment is 64 bytes, too. But the + * stride must be at least 512 bytes. Take the easy fix + * and align on 512 bytes unconditionally. */ + pitchAlign = 512; + else if (IS_I830(intel) || IS_845G(intel)) + /* Harsh, errata on these chipsets limit the stride to be + * a multiple of 256 bytes. + */ + pitchAlign = 256; + else + pitchAlign = 64; + } + +#if INTEL_XVMC + /* for i915 xvmc, hw requires 1kb aligned surfaces */ + if ((id == FOURCC_XVMC) && IS_GEN3(intel)) + pitchAlign = 1024; +#endif + + /* Determine the desired destination pitch (representing the chroma's pitch, + * in the planar case. + */ + if (is_planar_fourcc(id)) { + if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + *dstPitch = ALIGN((height / 2), pitchAlign); + *dstPitch2 = ALIGN(height, pitchAlign); + *size = *dstPitch * width * 3; + } else { + *dstPitch = ALIGN((width / 2), pitchAlign); + *dstPitch2 = ALIGN(width, pitchAlign); + *size = *dstPitch * height * 3; + } + } else { + if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + *dstPitch = ALIGN((height << 1), pitchAlign); + *size = *dstPitch * width; + } else { + *dstPitch = ALIGN((width << 1), pitchAlign); + *size = *dstPitch * height; + } + *dstPitch2 = 0; + } +#if 0 + ErrorF("srcPitch: %d, dstPitch: %d, size: %d\n", srcPitch, *dstPitch, + size); +#endif + + adaptor_priv->YBufOffset = 0; + + if (adaptor_priv->rotation & (RR_Rotate_90 | RR_Rotate_270)) { + adaptor_priv->UBufOffset = + adaptor_priv->YBufOffset + (*dstPitch2 * width); + adaptor_priv->VBufOffset = + adaptor_priv->UBufOffset + (*dstPitch * width / 2); + } else { + adaptor_priv->UBufOffset = + adaptor_priv->YBufOffset + (*dstPitch2 * height); + adaptor_priv->VBufOffset = + adaptor_priv->UBufOffset + (*dstPitch * height / 2); + } +} + +static Bool +intel_copy_video_data(ScrnInfoPtr scrn, intel_adaptor_private *adaptor_priv, + short width, short height, int *dstPitch, int *dstPitch2, + int top, int left, int npixels, int nlines, + int id, unsigned char *buf) +{ + int srcPitch = 0, srcPitch2 = 0; + int size; + + if (is_planar_fourcc(id)) { + srcPitch = ALIGN(width, 0x4); + srcPitch2 = ALIGN((width >> 1), 0x4); + } else { + srcPitch = width << 1; + } + + intel_setup_dst_params(scrn, adaptor_priv, width, height, dstPitch, + dstPitch2, &size, id); + + if (!intel_setup_video_buffer(scrn, adaptor_priv, size, id, buf)) + return FALSE; + + /* copy data */ + if (is_planar_fourcc(id)) { + return I830CopyPlanarData(adaptor_priv, buf, srcPitch, srcPitch2, + *dstPitch, *dstPitch2, + height, top, left, nlines, + npixels, id); + } else { + return I830CopyPackedData(adaptor_priv, buf, srcPitch, *dstPitch, top, left, + nlines, npixels); + } +} + +/* + * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). + * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). + * id is a fourcc code for the format of the video. + * buf is the pointer to the source data in system memory. + * width and height are the w/h of the source data. + * If "sync" is TRUE, then we must be finished with *buf at the point of return + * (which we always are). + * clipBoxes is the clipping region in screen space. + * data is a pointer to our port private. + * drawable is some Drawable, which might not be the screen in the case of + * compositing. It's a new argument to the function in the 1.1 server. + */ +static int +I830PutImageTextured(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_adaptor_private *) data; + PixmapPtr pixmap = get_drawable_pixmap(drawable); + int dstPitch, dstPitch2; + BoxRec dstBox; + xf86CrtcPtr crtc; + int top, left, npixels, nlines; + + if (!intel_pixmap_is_offscreen(pixmap)) + return BadAlloc; + +#if 0 + ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" + "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, + drw_y, drw_w, drw_h, width, height); +#endif + + if (!intel_clip_video_helper(scrn, + adaptor_priv, + &crtc, + &dstBox, + src_x, src_y, drw_x, drw_y, + src_w, src_h, drw_w, drw_h, + id, + &top, &left, &npixels, &nlines, clipBoxes, + width, height)) + return Success; + + if (xvmc_passthrough(id)) { + uint32_t *gem_handle = (uint32_t *)buf; + int size; + + intel_setup_dst_params(scrn, adaptor_priv, width, height, + &dstPitch, &dstPitch2, &size, id); + + if (IS_I915G(intel) || IS_I915GM(intel)) { + /* XXX: i915 is not support and needs some + * serious care. grep for KMS in i915_hwmc.c */ + return BadAlloc; + } + + if (adaptor_priv->buf) + drm_intel_bo_unreference(adaptor_priv->buf); + + adaptor_priv->buf = + drm_intel_bo_gem_create_from_name(intel->bufmgr, + "xvmc surface", + *gem_handle); + if (adaptor_priv->buf == NULL) + return BadAlloc; + + adaptor_priv->reusable = FALSE; + } else { + if (!intel_copy_video_data(scrn, adaptor_priv, width, height, + &dstPitch, &dstPitch2, + top, left, npixels, nlines, id, buf)) + return BadAlloc; + } + + if (crtc && adaptor_priv->SyncToVblank != 0 && INTEL_INFO(intel)->gen < 060) { + intel_wait_for_scanline(scrn, pixmap, crtc, clipBoxes); + } + + if (INTEL_INFO(intel)->gen >= 060) { + Gen6DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, + width, height, dstPitch, dstPitch2, + src_w, src_h, + drw_w, drw_h, pixmap); + } else if (INTEL_INFO(intel)->gen >= 040) { + I965DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, + width, height, dstPitch, dstPitch2, + src_w, src_h, + drw_w, drw_h, pixmap); + } else { + I915DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, + width, height, dstPitch, dstPitch2, + src_w, src_h, drw_w, drw_h, + pixmap); + } + + intel_get_screen_private(scrn)->needs_flush = TRUE; + DamageDamageRegion(drawable, clipBoxes); + + /* And make sure the WAIT_FOR_EVENT is queued before any + * modesetting/dpms operations on the pipe. + */ + intel_batch_submit(scrn); + + return Success; +} + +static int +I830PutImageOverlay(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_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; + int dstPitch, dstPitch2; + BoxRec dstBox; + xf86CrtcPtr crtc; + int top, left, npixels, nlines; + +#if 0 + ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" + "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, + drw_y, drw_w, drw_h, width, height); +#endif + + /* If dst width and height are less than 1/8th the src size, the + * src/dst scale factor becomes larger than 8 and doesn't fit in + * the scale register. */ + if (src_w >= (drw_w * 8)) + drw_w = src_w / 7; + + if (src_h >= (drw_h * 8)) + drw_h = src_h / 7; + + if (!intel_clip_video_helper(scrn, + adaptor_priv, + &crtc, + &dstBox, + src_x, src_y, drw_x, drw_y, + src_w, src_h, drw_w, drw_h, + id, + &top, &left, &npixels, &nlines, clipBoxes, + width, height)) + return Success; + + /* overlay can't handle rotation natively, store it for the copy func */ + if (crtc) + adaptor_priv->rotation = crtc->rotation; + else { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Fail to clip video to any crtc!\n"); + return Success; + } + + if (!intel_copy_video_data(scrn, adaptor_priv, width, height, + &dstPitch, &dstPitch2, + top, left, npixels, nlines, id, buf)) + return BadAlloc; + + if (!intel_display_overlay + (scrn, crtc, id, width, height, dstPitch, dstPitch2, + &dstBox, src_w, src_h, drw_w, drw_h)) + return BadAlloc; + + /* 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); + } + + adaptor_priv->videoStatus = CLIENT_VIDEO_ON; + + return Success; +} + +static int +I830QueryImageAttributes(ScrnInfoPtr scrn, + int id, + unsigned short *w, unsigned short *h, + int *pitches, int *offsets) +{ + intel_screen_private *intel = intel_get_screen_private(scrn); + int size, tmp; + +#if 0 + ErrorF("I830QueryImageAttributes: w is %d, h is %d\n", *w, *h); +#endif + + if (IS_845G(intel) || IS_I830(intel)) { + if (*w > IMAGE_MAX_WIDTH_LEGACY) + *w = IMAGE_MAX_WIDTH_LEGACY; + if (*h > IMAGE_MAX_HEIGHT_LEGACY) + *h = IMAGE_MAX_HEIGHT_LEGACY; + } else { + 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) { + /* IA44 is for XvMC only */ + case FOURCC_IA44: + case FOURCC_AI44: + if (pitches) + pitches[0] = *w; + size = *w * *h; + break; + case FOURCC_YV12: + case FOURCC_I420: + *h = (*h + 1) & ~1; + size = (*w + 3) & ~3; + if (pitches) + pitches[0] = size; + size *= *h; + if (offsets) + offsets[1] = size; + tmp = ((*w >> 1) + 3) & ~3; + if (pitches) + pitches[1] = pitches[2] = tmp; + tmp *= (*h >> 1); + size += tmp; + if (offsets) + offsets[2] = size; + size += tmp; +#if 0 + if (pitches) + ErrorF("pitch 0 is %d, pitch 1 is %d, pitch 2 is %d\n", + pitches[0], pitches[1], pitches[2]); + if (offsets) + ErrorF("offset 1 is %d, offset 2 is %d\n", offsets[1], + offsets[2]); + if (offsets) + ErrorF("size is %d\n", size); +#endif + break; +#ifdef INTEL_XVMC + case FOURCC_XVMC: + *h = (*h + 1) & ~1; + size = sizeof(struct intel_xvmc_command); + if (pitches) + pitches[0] = size; + break; +#endif + case FOURCC_UYVY: + case FOURCC_YUY2: + default: + size = *w << 1; + if (pitches) + pitches[0] = size; + size *= *h; + break; + } + + return size; +} + +void +intel_video_block_handler(intel_screen_private *intel) +{ + intel_adaptor_private *adaptor_priv; + + /* no overlay */ + if (intel->adaptor == NULL) + return; + + adaptor_priv = intel_get_adaptor_private(intel); + if (adaptor_priv->videoStatus & OFF_TIMER) { + Time now = currentTime.milliseconds; + if (adaptor_priv->offTime < now) { + /* Turn off the overlay */ + intel_overlay_off(intel); + intel_free_video_buffers(adaptor_priv); + adaptor_priv->videoStatus = 0; + } + } +} |