From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/gfxdrivers/i810/i810_overlay.c | 598 +++++++++++++++++++++++++ 1 file changed, 598 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/i810/i810_overlay.c (limited to 'Source/DirectFB/gfxdrivers/i810/i810_overlay.c') diff --git a/Source/DirectFB/gfxdrivers/i810/i810_overlay.c b/Source/DirectFB/gfxdrivers/i810/i810_overlay.c new file mode 100755 index 0000000..ccb0ffc --- /dev/null +++ b/Source/DirectFB/gfxdrivers/i810/i810_overlay.c @@ -0,0 +1,598 @@ +/* + i810_overlay.c -- Video Overlay Support (based partly from + XFree86 i810_video.c) + + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Antonino Daplas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include + +#include + +#include /* FIXME: Needs to be included before dfb_types.h to work around a type clash with asm/types.h */ + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "i810.h" + + +/* + * OV0CMD - Overlay Command Register + */ +#define VERTICAL_CHROMINANCE_FILTER 0x70000000 +#define VC_SCALING_OFF 0x00000000 +#define VC_LINE_REPLICATION 0x10000000 +#define VC_UP_INTERPOLATION 0x20000000 +#define VC_PIXEL_DROPPING 0x50000000 +#define VC_DOWN_INTERPOLATION 0x60000000 +#define VERTICAL_LUMINANCE_FILTER 0x0E000000 +#define VL_SCALING_OFF 0x00000000 +#define VL_LINE_REPLICATION 0x02000000 +#define VL_UP_INTERPOLATION 0x04000000 +#define VL_PIXEL_DROPPING 0x0A000000 +#define VL_DOWN_INTERPOLATION 0x0C000000 +#define HORIZONTAL_CHROMINANCE_FILTER 0x01C00000 +#define HC_SCALING_OFF 0x00000000 +#define HC_LINE_REPLICATION 0x00400000 +#define HC_UP_INTERPOLATION 0x00800000 +#define HC_PIXEL_DROPPING 0x01400000 +#define HC_DOWN_INTERPOLATION 0x01800000 +#define HORIZONTAL_LUMINANCE_FILTER 0x00380000 +#define HL_SCALING_OFF 0x00000000 +#define HL_LINE_REPLICATION 0x00080000 +#define HL_UP_INTERPOLATION 0x00100000 +#define HL_PIXEL_DROPPING 0x00280000 +#define HL_DOWN_INTERPOLATION 0x00300000 + +#define Y_ADJUST 0x00010000 +#define OV_BYTE_ORDER 0x0000C000 +#define UV_SWAP 0x00004000 +#define Y_SWAP 0x00008000 +#define Y_AND_UV_SWAP 0x0000C000 +#define SOURCE_FORMAT 0x00003C00 +#define RGB_555 0x00000800 +#define RGB_565 0x00000C00 +#define YUV_422 0x00002000 +#define YUV_411 0x00002400 +#define YUV_420 0x00003000 +#define YUV_410 0x00003800 +#define FIELD_MODE 0x00000020 +#define FRAME_MODE 0x00000000 +#define BUFFER_AND_FIELD 0x00000006 +#define BUFFER0_FIELD0 0x00000000 +#define BUFFER1_FIELD0 0x00000004 +#define OVERLAY_ENABLE 0x00000001 + +#define UV_VERT_BUF1 0x02 +#define UV_VERT_BUF0 0x04 + +#define SRC_CONSTANT_ALPHA_BLEND 1 << 31 +#define MINUV_SCALE 0x1 + +#define I810FB_IOC_UPDATEOVERLAY _IOW ('F', 0xF7, struct i810_ovl_regs) +#define I810FB_IOC_UPDATEOVERLAYCMD _IOW ('F', 0xF6, int) + +extern u32 i810_wait_for_space(I810DriverData *i810drv, + I810DeviceData *i810dev, + u32 space ); + +#define I810_OVERLAY_SUPPORTED_OPTIONS (DLOP_DST_COLORKEY | DLOP_DEINTERLACING) + +static void ovl_calc_regs (I810DriverData *i810drv, + I810OverlayLayerData *i810ovl, + CoreLayer *layer, + CoreSurface *surface, + CoreLayerRegionConfig *config, + CoreSurfaceBufferLock *lock ); + +static void update_overlay(I810DriverData *i810drv, + I810DeviceData *i810dev) +{ + i810_writel(i810drv->mmio_base, OV0ADDR, i810dev->ovl_mem.physical); +} + +void +i810ovlOnOff( I810DriverData *idrv, + I810DeviceData *idev, + bool on ) +{ + if (on) + idrv->oregs->ov0cmd |= 1; + else + idrv->oregs->ov0cmd &= ~1; + + update_overlay( idrv, idev ); +} + +static int +ovlLayerDataSize( void ) +{ + return sizeof(I810OverlayLayerData); +} + +static DFBResult +ovlInitLayer( + CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBDisplayLayerDescription *description, + DFBDisplayLayerConfig *config, + DFBColorAdjustment *adjustment ) +{ + I810OverlayLayerData *i810ovl = (I810OverlayLayerData *) layer_data; + I810DriverData *idrv = driver_data; + I810DeviceData *idev = idrv->idev; + + idev->iovl = i810ovl; + + idrv->oregs = (volatile struct i810_ovl_regs*) idrv->ovl_base; + + memset( (void*) idrv->oregs, 0, sizeof(struct i810_ovl_regs) ); + + /* set_capabilities */ + description->caps = DLCAPS_SURFACE | DLCAPS_SCREEN_LOCATION | + DLCAPS_BRIGHTNESS | DLCAPS_CONTRAST | DLCAPS_SATURATION | + DLCAPS_DST_COLORKEY | DLCAPS_OPACITY | DLCAPS_DEINTERLACING; + + description->type = DLTF_GRAPHICS | DLTF_VIDEO | DLTF_STILL_PICTURE; + /* set name */ + snprintf( description->name, + DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "Intel 810/815 Overlay" ); + + /* fill out the default configuration */ + config->flags = DLCONF_WIDTH | DLCONF_HEIGHT | + DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE | DLCONF_OPTIONS; + config->width = 640; + config->height = 480; + config->pixelformat = DSPF_YUY2; + config->buffermode = DLBM_FRONTONLY; + config->options = DLOP_NONE; + + /* fill out default color adjustment, + only fields set in flags will be accepted from applications */ + adjustment->flags = DCAF_BRIGHTNESS | DCAF_CONTRAST | DCAF_SATURATION; + adjustment->brightness = 0x8000; + adjustment->contrast = 0x8000; + adjustment->saturation = 0x8000; + + idrv->oregs->yrgb_vph = 0; + idrv->oregs->uv_vph = 0; + idrv->oregs->horz_ph = 0; + idrv->oregs->init_ph = 0; + idrv->oregs->dwinpos = 0; + idrv->oregs->dwinsz = (640 << 16) | 480; + idrv->oregs->swid = 640 | (640 << 15); + idrv->oregs->swidqw = (640 >> 3) | (640 << 12); + idrv->oregs->sheight = 480 | (480 << 15); + idrv->oregs->yrgbscale = 0x80004000; /* scale factor 1 */ + idrv->oregs->uvscale = 0x80004000; /* scale factor 1 */ + idrv->oregs->ov0clrc0 = 0x4000; /* brightness: 0 contrast: 1.0 */ + idrv->oregs->ov0clrc1 = 0x80; /* saturation: bypass */ + + idrv->oregs->sclrkvh = 0; + idrv->oregs->sclrkvl = 0; + idrv->oregs->sclrkm = 0; /* source color key disable */ + idrv->oregs->ov0conf = 0; /* two 720 pixel line buffers */ + + idrv->oregs->ov0cmd = VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | YUV_420; + + update_overlay( idrv, idev ); + + /* + * FIXME: If the fence registers are enabled, then the buffer pointers + * require specific alignment. This is a problem with planar formats + * which have separate pointers for each of the U and V planes. Packed + * formats should not be a problem. + */ + i810ovl->planar_bug = 0; + if (i810_readl(idrv->mmio_base, FENCE) & 1) + i810ovl->planar_bug = 1; + + return DFB_OK; +} + +static DFBResult +ovlTestRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags *failed ) +{ + DFBDisplayLayerConfigFlags fail = 0; + I810OverlayLayerData *i810ovl = (I810OverlayLayerData *) layer_data; + + if (config->options & ~I810_OVERLAY_SUPPORTED_OPTIONS) + fail |= DLCONF_OPTIONS; + + switch (config->format) { + case DSPF_I420: + case DSPF_YV12: + case DSPF_YUY2: + case DSPF_UYVY: + break; + default: + fail |= DLCONF_PIXELFORMAT; + } + if (i810ovl->planar_bug && (config->format == DSPF_I420 || + config->format == DSPF_YV12 )) { + D_DEBUG("Sorry, planar formats will not work when memory tiling " + "is enabled\n"); + fail |= DLCONF_PIXELFORMAT; + } + + if (config->width > 1440 || config->width < 1) + fail |= DLCONF_WIDTH; + + if (config->height > 1023 || config->height < 1) + fail |= DLCONF_HEIGHT; + + if (failed) + *failed = fail; + + if (fail) + return DFB_UNSUPPORTED; + + return DFB_OK; +} + +static DFBResult +ovlSetRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreLayerRegionConfig *config, + CoreLayerRegionConfigFlags updated, + CoreSurface *surface, + CorePalette *palette, + CoreSurfaceBufferLock *lock) +{ + I810DriverData *i810drv = (I810DriverData *) driver_data; + I810OverlayLayerData *i810ovl = (I810OverlayLayerData *) layer_data; + + i810ovl->config = *config; + + ovl_calc_regs (i810drv, i810ovl, layer, surface, config, lock); + update_overlay(i810drv, i810drv->idev); + + i810ovlOnOff(i810drv, i810drv->idev, 1); + + return DFB_OK; +} + +static DFBResult +ovlRemoveRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data ) +{ + I810DriverData *i810drv = (I810DriverData *) driver_data; + + /* disable overlay */ + i810ovlOnOff( i810drv, i810drv->idev, 0 ); + + return DFB_OK; +} + +static DFBResult +ovlFlipRegion( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + CoreSurface *surface, + DFBSurfaceFlipFlags flags, + CoreSurfaceBufferLock *lock ) +{ + I810DriverData *i810drv = (I810DriverData *) driver_data; + I810OverlayLayerData *i810ovl = (I810OverlayLayerData *) layer_data; + u32 current_buffer; + + dfb_surface_flip( surface, false ); + + /* select buffer */ + current_buffer = (i810drv->oregs->ov0cmd & 4) >> 2; + + if (current_buffer) { + i810drv->oregs->ov0cmd &= ~4; + } + else { + i810drv->oregs->ov0cmd |= 4; + } + + ovl_calc_regs (i810drv, i810ovl, layer, surface, &i810ovl->config, lock); + update_overlay(i810drv, i810drv->idev); + + if (flags & DSFLIP_WAIT) + dfb_screen_wait_vsync( dfb_screens_at( DSCID_PRIMARY ) ); + + return DFB_OK; +} + +static DFBResult +ovlSetColorAdjustment( CoreLayer *layer, + void *driver_data, + void *layer_data, + DFBColorAdjustment *adj ) +{ + I810DriverData *i810drv = (I810DriverData*) driver_data; + + i810drv->oregs->ov0clrc0 = (((adj->brightness >> 8) - 128) & 0xFF) | + ((adj->contrast >> 9) << 8); + i810drv->oregs->ov0clrc1 = (adj->saturation >> 8) & 0xFF; + + update_overlay(i810drv, i810drv->idev); + return DFB_OK; +} + +static DFBResult +ovlSetInputField( CoreLayer *layer, + void *driver_data, + void *layer_data, + void *region_data, + int field ) +{ + I810DriverData *i810drv = (I810DriverData*) driver_data; + + i810drv->oregs->ov0cmd &= ~2; + i810drv->oregs->ov0cmd |= (field) ? 2 : 0; + + update_overlay(i810drv, i810drv->idev); + return DFB_OK; +} + +DisplayLayerFuncs i810OverlayFuncs = { + .LayerDataSize = ovlLayerDataSize, + .InitLayer = ovlInitLayer, + .TestRegion = ovlTestRegion, + .SetRegion = ovlSetRegion, + .RemoveRegion = ovlRemoveRegion, + .FlipRegion = ovlFlipRegion, + .SetColorAdjustment = ovlSetColorAdjustment, + .SetInputField = ovlSetInputField, +}; + + +static void ovl_calc_regs (I810DriverData *i810drv, + I810OverlayLayerData *i810ovl, + CoreLayer *layer, + CoreSurface *surface, + CoreLayerRegionConfig *config, + CoreSurfaceBufferLock *lock ) +{ + u32 swidth = 0, y_offset, v_offset = 0, u_offset = 0; + u32 drw_w, src_w, drw_h, src_h, xscaleInt, xscaleFract, yscaleInt; + u32 xscaleFractUV = 0, xscaleIntUV, yscaleIntUV = 0, yscaleFract, yscaleFractUV = 0; + + DFBSurfacePixelFormat primary_format; + + drw_w = config->dest.w; + drw_h = config->dest.h; + src_w = surface->config.size.w; + src_h = surface->config.size.h; + + if (config->options & DLOP_DEINTERLACING) + src_h >>= 1; + + /* reset command register except the enable bit and buffer select bits */ + i810drv->oregs->ov0cmd &= 7; + + /* Set source dimension in bytes */ + switch (surface->config.format) { + case DSPF_I420: + case DSPF_YV12: + swidth = (src_w + 7) & ~7; + i810drv->oregs->swid = (swidth << 15) | swidth; + i810drv->oregs->swidqw = (swidth << 12) | (swidth >> 3); + break; + case DSPF_UYVY: + case DSPF_YUY2: + swidth = ((src_w + 3) & ~3) << 1; + i810drv->oregs->swid = swidth; + i810drv->oregs->swidqw = swidth >> 3; + break; + default: + break; + } + i810drv->oregs->sheight = src_h | (src_h << 15); + + /* select buffer size */ + if (swidth > 720) + i810drv->oregs->ov0conf = 1; + else + i810drv->oregs->ov0conf = 0; + + /* set dest window position and dimension */ + i810drv->oregs->dwinpos = (config->dest.y << 16) | config->dest.x; + i810drv->oregs->dwinsz = (drw_h << 16) | drw_w; + + /* Set buffer pointers */ + y_offset = (dfb_gfxcard_memory_physical(NULL, lock->offset)); + + switch (surface->config.format) { + case DSPF_I420: + u_offset = y_offset + surface->config.size.h * lock->pitch; + v_offset = u_offset + ((surface->config.size.h >> 1) * (lock->pitch >> 1)); + break; + case DSPF_YV12: + v_offset = y_offset + surface->config.size.h * lock->pitch; + u_offset = v_offset + ((surface->config.size.h >> 1) * (lock->pitch >> 1)); + break; + default: + break; + } + + if (i810drv->oregs->ov0cmd & 4) { + i810drv->oregs->obuf_1y = y_offset; + i810drv->oregs->obuf_1v = v_offset; + i810drv->oregs->obuf_1u = u_offset; + } + else { + i810drv->oregs->obuf_0y = y_offset; + i810drv->oregs->obuf_0v = v_offset; + i810drv->oregs->obuf_0u = u_offset; + } + + /* set scaling */ + i810drv->oregs->yrgbscale = 0x80004000; + i810drv->oregs->uvscale = 0x80004000; + + i810drv->oregs->ov0cmd |= VC_UP_INTERPOLATION | HC_UP_INTERPOLATION | Y_ADJUST | FRAME_MODE; + + if (config->options & DLOP_DEINTERLACING) + i810drv->oregs->ov0cmd |= FIELD_MODE; + + if ((drw_w != src_w) || (drw_h != src_h)) + { + xscaleInt = (src_w / drw_w) & 0x3; + xscaleFract = (src_w << 12) / drw_w; + yscaleInt = (src_h / drw_h) & 0x3; + yscaleFract = (src_h << 12) / drw_h; + + i810drv->oregs->yrgbscale = (xscaleInt << 15) | + ((xscaleFract & 0xFFF) << 3) | + (yscaleInt) | + ((yscaleFract & 0xFFF) << 20); + + if (drw_w > src_w) + { + i810drv->oregs->ov0cmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + i810drv->oregs->ov0cmd &= ~HORIZONTAL_LUMINANCE_FILTER; + i810drv->oregs->ov0cmd |= (HC_UP_INTERPOLATION | HL_UP_INTERPOLATION); + } + + if (drw_h > src_h) + { + i810drv->oregs->ov0cmd &= ~VERTICAL_CHROMINANCE_FILTER; + i810drv->oregs->ov0cmd &= ~VERTICAL_LUMINANCE_FILTER; + i810drv->oregs->ov0cmd |= (VC_UP_INTERPOLATION | VL_UP_INTERPOLATION); + } + + if (drw_w < src_w) + { + i810drv->oregs->ov0cmd &= ~HORIZONTAL_CHROMINANCE_FILTER; + i810drv->oregs->ov0cmd &= ~HORIZONTAL_LUMINANCE_FILTER; + i810drv->oregs->ov0cmd |= (HC_DOWN_INTERPOLATION | HL_DOWN_INTERPOLATION); + } + + if (drw_h < src_h) + { + i810drv->oregs->ov0cmd &= ~VERTICAL_CHROMINANCE_FILTER; + i810drv->oregs->ov0cmd &= ~VERTICAL_LUMINANCE_FILTER; + i810drv->oregs->ov0cmd |= (VC_DOWN_INTERPOLATION | VL_DOWN_INTERPOLATION); + } + + if (xscaleFract) + { + xscaleFractUV = xscaleFract >> MINUV_SCALE; + i810drv->oregs->ov0cmd &= ~HC_DOWN_INTERPOLATION; + i810drv->oregs->ov0cmd |= HC_UP_INTERPOLATION; + } + + if (xscaleInt) + { + xscaleIntUV = xscaleInt >> MINUV_SCALE; + if (xscaleIntUV) + { + i810drv->oregs->ov0cmd &= ~HC_UP_INTERPOLATION; + } + } + + if (yscaleFract) + { + yscaleFractUV = yscaleFract >> MINUV_SCALE; + i810drv->oregs->ov0cmd &= ~VC_DOWN_INTERPOLATION; + i810drv->oregs->ov0cmd |= VC_UP_INTERPOLATION; + } + + if (yscaleInt) + { + yscaleIntUV = yscaleInt >> MINUV_SCALE; + if (yscaleIntUV) + { + i810drv->oregs->ov0cmd &= ~VC_UP_INTERPOLATION; + i810drv->oregs->ov0cmd |= VC_DOWN_INTERPOLATION; + } + } + + i810drv->oregs->uvscale = yscaleIntUV | ((xscaleFractUV & 0xFFF) << 3) | + ((yscaleFractUV & 0xFFF) << 20); + } + + switch(surface->config.format) { + case DSPF_YV12: + case DSPF_I420: + /* set UV vertical phase to -0.25 */ + i810drv->oregs->uv_vph = 0x30003000; + i810drv->oregs->init_ph = UV_VERT_BUF0 | UV_VERT_BUF1; + i810drv->oregs->ov0stride = (lock->pitch) | (lock->pitch << 15); + i810drv->oregs->ov0cmd &= ~SOURCE_FORMAT; + i810drv->oregs->ov0cmd |= YUV_420; + break; + case DSPF_UYVY: + case DSPF_YUY2: + i810drv->oregs->uv_vph = 0; + i810drv->oregs->init_ph = 0; + i810drv->oregs->ov0stride = lock->pitch; + i810drv->oregs->ov0cmd &= ~SOURCE_FORMAT; + i810drv->oregs->ov0cmd |= YUV_422; + i810drv->oregs->ov0cmd &= ~OV_BYTE_ORDER; + if (surface->config.format == DSPF_UYVY) + i810drv->oregs->ov0cmd |= Y_SWAP; + break; + default: + D_BUG("unexpected pixelformat"); + break; + } + + /* Set alpha window */ + i810drv->oregs->awinpos = i810drv->oregs->dwinpos; + i810drv->oregs->awinsz = i810drv->oregs->dwinsz; + + + /* + * Destination color keying. + */ + + primary_format = dfb_primary_layer_pixelformat(); + + i810drv->oregs->dclrkv = dfb_color_to_pixel( primary_format, + config->dst_key.r, + config->dst_key.g, + config->dst_key.b ); + + i810drv->oregs->dclrkm = (1 << DFB_COLOR_BITS_PER_PIXEL( primary_format )) - 1; + + if (config->options & DLOP_DST_COLORKEY) + i810drv->oregs->dclrkm |= 0x80000000; +} -- cgit