113496ba1Ssnj/*************************************************************************** 213496ba1Ssnj 313496ba1Ssnj Copyright 2000 Intel Corporation. All Rights Reserved. 413496ba1Ssnj 513496ba1Ssnj Permission is hereby granted, free of charge, to any person obtaining a 613496ba1Ssnj copy of this software and associated documentation files (the 713496ba1Ssnj "Software"), to deal in the Software without restriction, including 813496ba1Ssnj without limitation the rights to use, copy, modify, merge, publish, 913496ba1Ssnj distribute, sub license, and/or sell copies of the Software, and to 1013496ba1Ssnj permit persons to whom the Software is furnished to do so, subject to 1113496ba1Ssnj the following conditions: 1213496ba1Ssnj 1313496ba1Ssnj The above copyright notice and this permission notice (including the 1413496ba1Ssnj next paragraph) shall be included in all copies or substantial portions 1513496ba1Ssnj of the Software. 1613496ba1Ssnj 1713496ba1Ssnj THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1813496ba1Ssnj OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1913496ba1Ssnj MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 2013496ba1Ssnj IN NO EVENT SHALL INTEL, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2113496ba1Ssnj DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2213496ba1Ssnj OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 2313496ba1Ssnj THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2413496ba1Ssnj 2513496ba1Ssnj **************************************************************************/ 2613496ba1Ssnj 2713496ba1Ssnj/* 2813496ba1Ssnj * i830_video.c: i830/i845 Xv driver. 2913496ba1Ssnj * 3013496ba1Ssnj * Copyright © 2002 by Alan Hourihane and David Dawes 3113496ba1Ssnj * 3213496ba1Ssnj * Authors: 3313496ba1Ssnj * Alan Hourihane <alanh@tungstengraphics.com> 3413496ba1Ssnj * David Dawes <dawes@xfree86.org> 3513496ba1Ssnj * 3613496ba1Ssnj * Derived from i810 Xv driver: 3713496ba1Ssnj * 3813496ba1Ssnj * Authors of i810 code: 3913496ba1Ssnj * Jonathan Bian <jonathan.bian@intel.com> 4013496ba1Ssnj * Offscreen Images: 4113496ba1Ssnj * Matt Sottek <matthew.j.sottek@intel.com> 4213496ba1Ssnj */ 4313496ba1Ssnj 4413496ba1Ssnj#ifdef HAVE_CONFIG_H 4513496ba1Ssnj#include "config.h" 4613496ba1Ssnj#endif 4713496ba1Ssnj 4813496ba1Ssnj#include <inttypes.h> 4913496ba1Ssnj#include <math.h> 5013496ba1Ssnj#include <string.h> 5113496ba1Ssnj#include <assert.h> 5213496ba1Ssnj#include <errno.h> 5313496ba1Ssnj 5413496ba1Ssnj#include "xorg-server.h" 5513496ba1Ssnj#include "xf86.h" 5613496ba1Ssnj#include "xf86_OSproc.h" 5713496ba1Ssnj#include "compiler.h" 5813496ba1Ssnj#include "xf86Pci.h" 5913496ba1Ssnj#include "xf86fbman.h" 6013496ba1Ssnj#include "xf86drm.h" 6113496ba1Ssnj#include "regionstr.h" 6213496ba1Ssnj#include "randrstr.h" 6313496ba1Ssnj#include "windowstr.h" 6413496ba1Ssnj#include "damage.h" 6513496ba1Ssnj#include "intel.h" 6613496ba1Ssnj#include "intel_uxa.h" 6713496ba1Ssnj#include "i830_reg.h" 6813496ba1Ssnj#include "xf86xv.h" 6913496ba1Ssnj#include <X11/extensions/Xv.h> 7013496ba1Ssnj#include "dixstruct.h" 7113496ba1Ssnj#include "fourcc.h" 7213496ba1Ssnj 7313496ba1Ssnj#ifdef INTEL_XVMC 7413496ba1Ssnj#define _INTEL_XVMC_SERVER_ 7513496ba1Ssnj#include "intel_xvmc.h" 7613496ba1Ssnj#endif 7713496ba1Ssnj 7813496ba1Ssnj/* overlay debugging printf function */ 7913496ba1Ssnj#if 0 8013496ba1Ssnj#define UXA_VIDEO_DEBUG ErrorF 8113496ba1Ssnj#else 8213496ba1Ssnj#define UXA_VIDEO_DEBUG if (0) ErrorF 8313496ba1Ssnj#endif 8413496ba1Ssnj 8513496ba1Ssnjstatic int intel_uxa_video_put_image_textured(ScrnInfoPtr, short, short, short, short, short, short, 8613496ba1Ssnj short, short, int, unsigned char *, short, short, 8713496ba1Ssnj Bool, RegionPtr, pointer, DrawablePtr); 8813496ba1Ssnj 8913496ba1Ssnjstatic int 9013496ba1Ssnjintel_uxa_video_set_port_attribute(ScrnInfoPtr scrn, 9113496ba1Ssnj Atom attribute, INT32 value, pointer data) 9213496ba1Ssnj{ 9313496ba1Ssnj intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 9413496ba1Ssnj 9513496ba1Ssnj if (attribute == intel_xv_Brightness) { 9613496ba1Ssnj if ((value < -128) || (value > 127)) 9713496ba1Ssnj return BadValue; 9813496ba1Ssnj adaptor_priv->brightness = value; 9913496ba1Ssnj return Success; 10013496ba1Ssnj } else if (attribute == intel_xv_Contrast) { 10113496ba1Ssnj if ((value < 0) || (value > 255)) 10213496ba1Ssnj return BadValue; 10313496ba1Ssnj adaptor_priv->contrast = value; 10413496ba1Ssnj return Success; 10513496ba1Ssnj } else if (attribute == intel_xv_SyncToVblank) { 10613496ba1Ssnj if ((value < -1) || (value > 1)) 10713496ba1Ssnj return BadValue; 10813496ba1Ssnj adaptor_priv->SyncToVblank = value; 10913496ba1Ssnj return Success; 11013496ba1Ssnj } else { 11113496ba1Ssnj return BadMatch; 11213496ba1Ssnj } 11313496ba1Ssnj} 11413496ba1Ssnj 11513496ba1Ssnj 11613496ba1Ssnjstatic int xvmc_passthrough(int id) 11713496ba1Ssnj{ 11813496ba1Ssnj#ifdef INTEL_XVMC 11913496ba1Ssnj return id == FOURCC_XVMC; 12013496ba1Ssnj#else 12113496ba1Ssnj return 0; 12213496ba1Ssnj#endif 12313496ba1Ssnj} 12413496ba1Ssnj 12513496ba1Ssnj 12613496ba1Ssnjstatic void 12713496ba1Ssnjintel_wait_for_scanline(ScrnInfoPtr scrn, PixmapPtr pixmap, 12813496ba1Ssnj xf86CrtcPtr crtc, RegionPtr clipBoxes) 12913496ba1Ssnj{ 13013496ba1Ssnj intel_screen_private *intel = intel_get_screen_private(scrn); 13113496ba1Ssnj pixman_box16_t box, crtc_box; 13213496ba1Ssnj int pipe, event; 13313496ba1Ssnj Bool full_height; 13413496ba1Ssnj int y1, y2; 13513496ba1Ssnj 13613496ba1Ssnj pipe = -1; 13713496ba1Ssnj if (scrn->vtSema && pixmap_is_scanout(pixmap)) 13813496ba1Ssnj pipe = intel_crtc_to_pipe(crtc); 13913496ba1Ssnj if (pipe < 0) 14013496ba1Ssnj return; 14113496ba1Ssnj 14213496ba1Ssnj box = *REGION_EXTENTS(unused, clipBoxes); 14313496ba1Ssnj 14413496ba1Ssnj if (crtc->transform_in_use) 14513496ba1Ssnj pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box); 14613496ba1Ssnj 14713496ba1Ssnj /* We could presume the clip was correctly computed... */ 14813496ba1Ssnj intel_crtc_box(crtc, &crtc_box); 14913496ba1Ssnj intel_box_intersect(&box, &crtc_box, &box); 15013496ba1Ssnj 15113496ba1Ssnj /* 15213496ba1Ssnj * Make sure we don't wait for a scanline that will 15313496ba1Ssnj * never occur 15413496ba1Ssnj */ 15513496ba1Ssnj y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0; 15613496ba1Ssnj y2 = (box.y2 <= crtc_box.y2) ? 15713496ba1Ssnj box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1; 15813496ba1Ssnj if (y2 <= y1) 15913496ba1Ssnj return; 16013496ba1Ssnj 16113496ba1Ssnj full_height = FALSE; 16213496ba1Ssnj if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1)) 16313496ba1Ssnj full_height = TRUE; 16413496ba1Ssnj 16513496ba1Ssnj /* 16613496ba1Ssnj * Pre-965 doesn't have SVBLANK, so we need a bit 16713496ba1Ssnj * of extra time for the blitter to start up and 16813496ba1Ssnj * do its job for a full height blit 16913496ba1Ssnj */ 17013496ba1Ssnj if (full_height && INTEL_INFO(intel)->gen < 040) 17113496ba1Ssnj y2 -= 2; 17213496ba1Ssnj 17313496ba1Ssnj if (pipe == 0) { 17413496ba1Ssnj pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA; 17513496ba1Ssnj event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 17613496ba1Ssnj if (full_height && INTEL_INFO(intel)->gen >= 040) 17713496ba1Ssnj event = MI_WAIT_FOR_PIPEA_SVBLANK; 17813496ba1Ssnj } else { 17913496ba1Ssnj pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEB; 18013496ba1Ssnj event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 18113496ba1Ssnj if (full_height && INTEL_INFO(intel)->gen >= 040) 18213496ba1Ssnj event = MI_WAIT_FOR_PIPEB_SVBLANK; 18313496ba1Ssnj } 18413496ba1Ssnj 18513496ba1Ssnj if (crtc->mode.Flags & V_INTERLACE) { 18613496ba1Ssnj /* DSL count field lines */ 18713496ba1Ssnj y1 /= 2; 18813496ba1Ssnj y2 /= 2; 18913496ba1Ssnj } 19013496ba1Ssnj 19113496ba1Ssnj BEGIN_BATCH(5); 19213496ba1Ssnj /* The documentation says that the LOAD_SCAN_LINES command 19313496ba1Ssnj * always comes in pairs. Don't ask me why. */ 19413496ba1Ssnj OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); 19513496ba1Ssnj OUT_BATCH((y1 << 16) | (y2-1)); 19613496ba1Ssnj OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | pipe); 19713496ba1Ssnj OUT_BATCH((y1 << 16) | (y2-1)); 19813496ba1Ssnj OUT_BATCH(MI_WAIT_FOR_EVENT | event); 19913496ba1Ssnj ADVANCE_BATCH(); 20013496ba1Ssnj} 20113496ba1Ssnj 20213496ba1Ssnj/* 20313496ba1Ssnj * The source rectangle of the video is defined by (src_x, src_y, src_w, src_h). 20413496ba1Ssnj * The dest rectangle of the video is defined by (drw_x, drw_y, drw_w, drw_h). 20513496ba1Ssnj * id is a fourcc code for the format of the video. 20613496ba1Ssnj * buf is the pointer to the source data in system memory. 20713496ba1Ssnj * width and height are the w/h of the source data. 20813496ba1Ssnj * If "sync" is TRUE, then we must be finished with *buf at the point of return 20913496ba1Ssnj * (which we always are). 21013496ba1Ssnj * clipBoxes is the clipping region in screen space. 21113496ba1Ssnj * data is a pointer to our port private. 21213496ba1Ssnj * drawable is some Drawable, which might not be the screen in the case of 21313496ba1Ssnj * compositing. It's a new argument to the function in the 1.1 server. 21413496ba1Ssnj */ 21513496ba1Ssnjstatic int 21613496ba1Ssnjintel_uxa_video_put_image_textured(ScrnInfoPtr scrn, 21713496ba1Ssnj short src_x, short src_y, 21813496ba1Ssnj short drw_x, short drw_y, 21913496ba1Ssnj short src_w, short src_h, 22013496ba1Ssnj short drw_w, short drw_h, 22113496ba1Ssnj int id, unsigned char *buf, 22213496ba1Ssnj short width, short height, 22313496ba1Ssnj Bool sync, RegionPtr clipBoxes, pointer data, 22413496ba1Ssnj DrawablePtr drawable) 22513496ba1Ssnj{ 22613496ba1Ssnj intel_screen_private *intel = intel_get_screen_private(scrn); 22713496ba1Ssnj intel_adaptor_private *adaptor_priv = (intel_adaptor_private *) data; 22813496ba1Ssnj PixmapPtr pixmap = get_drawable_pixmap(drawable); 22913496ba1Ssnj int dstPitch, dstPitch2; 23013496ba1Ssnj BoxRec dstBox; 23113496ba1Ssnj xf86CrtcPtr crtc; 23213496ba1Ssnj int top, left, npixels, nlines; 23313496ba1Ssnj 23413496ba1Ssnj if (!intel_uxa_pixmap_is_offscreen(pixmap)) 23513496ba1Ssnj return BadAlloc; 23613496ba1Ssnj 23713496ba1Ssnj#if 0 23813496ba1Ssnj ErrorF("I830PutImage: src: (%d,%d)(%d,%d), dst: (%d,%d)(%d,%d)\n" 23913496ba1Ssnj "width %d, height %d\n", src_x, src_y, src_w, src_h, drw_x, 24013496ba1Ssnj drw_y, drw_w, drw_h, width, height); 24113496ba1Ssnj#endif 24213496ba1Ssnj 24313496ba1Ssnj if (!intel_clip_video_helper(scrn, 24413496ba1Ssnj adaptor_priv, 24513496ba1Ssnj &crtc, 24613496ba1Ssnj &dstBox, 24713496ba1Ssnj src_x, src_y, drw_x, drw_y, 24813496ba1Ssnj src_w, src_h, drw_w, drw_h, 24913496ba1Ssnj id, 25013496ba1Ssnj &top, &left, &npixels, &nlines, clipBoxes, 25113496ba1Ssnj width, height)) 25213496ba1Ssnj return Success; 25313496ba1Ssnj 25413496ba1Ssnj if (xvmc_passthrough(id)) { 25513496ba1Ssnj uint32_t *gem_handle = (uint32_t *)buf; 25613496ba1Ssnj int size; 25713496ba1Ssnj 25813496ba1Ssnj intel_setup_dst_params(scrn, adaptor_priv, width, height, 25913496ba1Ssnj &dstPitch, &dstPitch2, &size, id); 26013496ba1Ssnj 26113496ba1Ssnj if (IS_I915G(intel) || IS_I915GM(intel)) { 26213496ba1Ssnj /* XXX: i915 is not support and needs some 26313496ba1Ssnj * serious care. grep for KMS in i915_hwmc.c */ 26413496ba1Ssnj return BadAlloc; 26513496ba1Ssnj } 26613496ba1Ssnj 26713496ba1Ssnj if (adaptor_priv->buf) 26813496ba1Ssnj drm_intel_bo_unreference(adaptor_priv->buf); 26913496ba1Ssnj 27013496ba1Ssnj adaptor_priv->buf = 27113496ba1Ssnj drm_intel_bo_gem_create_from_name(intel->bufmgr, 27213496ba1Ssnj "xvmc surface", 27313496ba1Ssnj *gem_handle); 27413496ba1Ssnj if (adaptor_priv->buf == NULL) 27513496ba1Ssnj return BadAlloc; 27613496ba1Ssnj 27713496ba1Ssnj adaptor_priv->reusable = FALSE; 27813496ba1Ssnj } else { 27913496ba1Ssnj if (!intel_video_copy_data(scrn, adaptor_priv, width, height, 28013496ba1Ssnj &dstPitch, &dstPitch2, 28113496ba1Ssnj top, left, npixels, nlines, id, buf)) 28213496ba1Ssnj return BadAlloc; 28313496ba1Ssnj } 28413496ba1Ssnj 28513496ba1Ssnj if (crtc && adaptor_priv->SyncToVblank != 0 && INTEL_INFO(intel)->gen < 060) { 28613496ba1Ssnj intel_wait_for_scanline(scrn, pixmap, crtc, clipBoxes); 28713496ba1Ssnj } 28813496ba1Ssnj 28913496ba1Ssnj if (INTEL_INFO(intel)->gen >= 060) { 29013496ba1Ssnj Gen6DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 29113496ba1Ssnj width, height, dstPitch, dstPitch2, 29213496ba1Ssnj src_w, src_h, 29313496ba1Ssnj drw_w, drw_h, pixmap); 29413496ba1Ssnj } else if (INTEL_INFO(intel)->gen >= 040) { 29513496ba1Ssnj I965DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 29613496ba1Ssnj width, height, dstPitch, dstPitch2, 29713496ba1Ssnj src_w, src_h, 29813496ba1Ssnj drw_w, drw_h, pixmap); 29913496ba1Ssnj } else { 30013496ba1Ssnj I915DisplayVideoTextured(scrn, adaptor_priv, id, clipBoxes, 30113496ba1Ssnj width, height, dstPitch, dstPitch2, 30213496ba1Ssnj src_w, src_h, drw_w, drw_h, 30313496ba1Ssnj pixmap); 30413496ba1Ssnj } 30513496ba1Ssnj 30613496ba1Ssnj intel_get_screen_private(scrn)->needs_flush = TRUE; 30713496ba1Ssnj DamageDamageRegion(drawable, clipBoxes); 30813496ba1Ssnj 30913496ba1Ssnj /* And make sure the WAIT_FOR_EVENT is queued before any 31013496ba1Ssnj * modesetting/dpms operations on the pipe. 31113496ba1Ssnj */ 31213496ba1Ssnj intel_batch_submit(scrn); 31313496ba1Ssnj 31413496ba1Ssnj return Success; 31513496ba1Ssnj} 31613496ba1Ssnj 31713496ba1SsnjXF86VideoAdaptorPtr intel_uxa_video_setup_image_textured(ScreenPtr screen) 31813496ba1Ssnj{ 31913496ba1Ssnj ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 32013496ba1Ssnj intel_screen_private *intel = intel_get_screen_private(scrn); 32113496ba1Ssnj XF86VideoAdaptorPtr adapt; 32213496ba1Ssnj intel_adaptor_private *adaptor_privs; 32313496ba1Ssnj DevUnion *devUnions; 32413496ba1Ssnj int nports = 16, i; 32513496ba1Ssnj 32613496ba1Ssnj UXA_VIDEO_DEBUG("intel_video_overlay_setup_image\n"); 32713496ba1Ssnj 32813496ba1Ssnj adapt = calloc(1, sizeof(XF86VideoAdaptorRec)); 32913496ba1Ssnj adaptor_privs = calloc(nports, sizeof(intel_adaptor_private)); 33013496ba1Ssnj devUnions = calloc(nports, sizeof(DevUnion)); 33113496ba1Ssnj if (adapt == NULL || adaptor_privs == NULL || devUnions == NULL) { 33213496ba1Ssnj free(adapt); 33313496ba1Ssnj free(adaptor_privs); 33413496ba1Ssnj free(devUnions); 33513496ba1Ssnj return NULL; 33613496ba1Ssnj } 33713496ba1Ssnj 33813496ba1Ssnj adapt->type = XvWindowMask | XvInputMask | XvImageMask; 33913496ba1Ssnj adapt->flags = 0; 34013496ba1Ssnj adapt->name = "Intel(R) Textured Video"; 34113496ba1Ssnj adapt->nEncodings = 1; 34213496ba1Ssnj adapt->pEncodings = xnfalloc(sizeof(intel_xv_dummy_encoding)); 34313496ba1Ssnj memcpy(adapt->pEncodings, intel_xv_dummy_encoding, sizeof(intel_xv_dummy_encoding)); 34413496ba1Ssnj adapt->nFormats = NUM_FORMATS; 34513496ba1Ssnj adapt->pFormats = intel_xv_formats; 34613496ba1Ssnj adapt->nPorts = nports; 34713496ba1Ssnj adapt->pPortPrivates = devUnions; 34813496ba1Ssnj adapt->nAttributes = 0; 34913496ba1Ssnj adapt->pAttributes = NULL; 35013496ba1Ssnj if (IS_I915G(intel) || IS_I915GM(intel)) 35113496ba1Ssnj adapt->nImages = NUM_IMAGES - XVMC_IMAGE; 35213496ba1Ssnj else 35313496ba1Ssnj adapt->nImages = NUM_IMAGES; 35413496ba1Ssnj 35513496ba1Ssnj adapt->pImages = intel_xv_images; 35613496ba1Ssnj adapt->PutVideo = NULL; 35713496ba1Ssnj adapt->PutStill = NULL; 35813496ba1Ssnj adapt->GetVideo = NULL; 35913496ba1Ssnj adapt->GetStill = NULL; 36013496ba1Ssnj adapt->StopVideo = intel_video_stop_video; 36113496ba1Ssnj adapt->SetPortAttribute = intel_uxa_video_set_port_attribute; 36213496ba1Ssnj adapt->GetPortAttribute = intel_video_get_port_attribute; 36313496ba1Ssnj adapt->QueryBestSize = intel_video_query_best_size; 36413496ba1Ssnj adapt->PutImage = intel_uxa_video_put_image_textured; 36513496ba1Ssnj adapt->QueryImageAttributes = intel_video_query_image_attributes; 36613496ba1Ssnj 36713496ba1Ssnj for (i = 0; i < nports; i++) { 36813496ba1Ssnj intel_adaptor_private *adaptor_priv = &adaptor_privs[i]; 36913496ba1Ssnj 37013496ba1Ssnj adaptor_priv->textured = TRUE; 37113496ba1Ssnj adaptor_priv->videoStatus = 0; 37213496ba1Ssnj adaptor_priv->buf = NULL; 37313496ba1Ssnj adaptor_priv->old_buf[0] = NULL; 37413496ba1Ssnj adaptor_priv->old_buf[1] = NULL; 37513496ba1Ssnj 37613496ba1Ssnj adaptor_priv->rotation = RR_Rotate_0; 37713496ba1Ssnj adaptor_priv->SyncToVblank = 1; 37813496ba1Ssnj 37913496ba1Ssnj /* gotta uninit this someplace, XXX: shouldn't be necessary for textured */ 38013496ba1Ssnj REGION_NULL(screen, &adaptor_priv->clip); 38113496ba1Ssnj 38213496ba1Ssnj adapt->pPortPrivates[i].ptr = (pointer) (adaptor_priv); 38313496ba1Ssnj } 38413496ba1Ssnj 38513496ba1Ssnj intel_xv_SyncToVblank = MAKE_ATOM("XV_SYNC_TO_VBLANK"); 38613496ba1Ssnj 38713496ba1Ssnj return adapt; 38813496ba1Ssnj} 389