summaryrefslogtreecommitdiff
path: root/Source/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c')
-rwxr-xr-xSource/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c b/Source/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c
new file mode 100755
index 0000000..747f14c
--- /dev/null
+++ b/Source/DirectFB/gfxdrivers/nvidia/nvidia_overlay.c
@@ -0,0 +1,566 @@
+/*
+ (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 Oliver Schwartz <Oliver.Schwartz@gmx.de> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <core/coredefs.h>
+#include <core/surface.h>
+#include <core/gfxcard.h>
+
+#include <core/layers.h>
+#include <core/layer_context.h>
+#include <core/layer_control.h>
+#include <core/layer_region.h>
+#include <core/layers_internal.h>
+
+#include <gfx/convert.h>
+
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+
+#include "nvidia.h"
+#include "nvidia_regs.h"
+#include "nvidia_accel.h"
+
+
+typedef struct {
+ CoreLayerRegionConfig config;
+ CoreSurface *videoSurface;
+ CoreSurfaceBufferLock *lock;
+
+ short brightness;
+ short contrast;
+ short hue;
+ short saturation;
+ int field;
+
+ struct {
+ u32 BUFFER;
+ u32 STOP;
+ u32 UVBASE_0;
+ u32 UVBASE_1;
+ u32 UVOFFSET_0;
+ u32 UVOFFSET_1;
+ u32 BASE_0;
+ u32 BASE_1;
+ u32 OFFSET_0;
+ u32 OFFSET_1;
+ u32 SIZE_IN_0;
+ u32 SIZE_IN_1;
+ u32 POINT_IN_0;
+ u32 POINT_IN_1;
+ u32 DS_DX_0;
+ u32 DS_DX_1;
+ u32 DT_DY_0;
+ u32 DT_DY_1;
+ u32 POINT_OUT_0;
+ u32 POINT_OUT_1;
+ u32 SIZE_OUT_0;
+ u32 SIZE_OUT_1;
+ u32 FORMAT_0;
+ u32 FORMAT_1;
+ } regs;
+} NVidiaOverlayLayerData;
+
+static void ov0_set_regs ( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfigFlags flags );
+static void ov0_calc_regs ( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags flags );
+static void ov0_set_colorkey( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfig *config );
+static void ov0_set_csc ( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0 );
+
+#define OV0_SUPPORTED_OPTIONS \
+ ( DLOP_DST_COLORKEY | DLOP_DEINTERLACING )
+
+/**********************/
+
+
+
+static int
+ov0LayerDataSize( void )
+{
+ return sizeof(NVidiaOverlayLayerData);
+}
+
+static DFBResult
+ov0InitLayer( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ DFBDisplayLayerDescription *description,
+ DFBDisplayLayerConfig *config,
+ DFBColorAdjustment *adjustment )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ NVidiaOverlayLayerData *nvov0 = (NVidiaOverlayLayerData*) layer_data;
+
+ /* set capabilities and type */
+ description->caps = DLCAPS_SURFACE | DLCAPS_SCREEN_LOCATION |
+ DLCAPS_BRIGHTNESS | DLCAPS_CONTRAST |
+ DLCAPS_SATURATION | DLCAPS_HUE |
+ DLCAPS_DST_COLORKEY | DLCAPS_DEINTERLACING;
+ description->type = DLTF_VIDEO | DLTF_STILL_PICTURE;
+
+ /* set name */
+ snprintf( description->name,
+ DFB_DISPLAY_LAYER_DESC_NAME_LENGTH, "NVidia 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 | DCAF_HUE;
+ adjustment->brightness = 0x8000;
+ adjustment->contrast = 0x8000;
+ adjustment->saturation = 0x8000;
+ adjustment->hue = 0x8000;
+
+ /* reset overlay */
+ nvov0->brightness = 0;
+ nvov0->contrast = 4096;
+ nvov0->hue = 0;
+ nvov0->saturation = 4096;
+ ov0_set_csc( nvdrv, nvov0 );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0Remove( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ volatile u8 *mmio = nvdrv->mmio_base;
+
+ /* disable overlay */
+ nv_out32( mmio, PVIDEO_STOP, PVIDEO_STOP_OVERLAY_ACTIVE |
+ PVIDEO_STOP_METHOD_IMMEDIATELY );
+ nv_out32( mmio, PVIDEO_BUFFER, 0 );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0TestRegion(CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags *failed )
+{
+ NVidiaDriverData *nvdrv = driver_data;
+ NVidiaDeviceData *nvdev = nvdrv->device_data;
+ CoreLayerRegionConfigFlags fail = CLRCF_NONE;
+
+
+ /* check for unsupported options */
+ if (config->options & ~OV0_SUPPORTED_OPTIONS)
+ fail |= CLRCF_OPTIONS;
+
+ /* check buffermode */
+ switch (config->buffermode) {
+ case DLBM_FRONTONLY:
+ case DLBM_BACKSYSTEM:
+ case DLBM_BACKVIDEO:
+ case DLBM_TRIPLE:
+ break;
+
+ default:
+ fail |= CLRCF_BUFFERMODE;
+ break;
+ }
+
+ /* check pixel format */
+ switch (config->format) {
+ case DSPF_YUY2:
+ case DSPF_UYVY:
+ break;
+
+ case DSPF_NV12:
+ /*case DSPF_NV21:*/
+ if (nvdev->arch < NV_ARCH_30)
+ fail |= CLRCF_FORMAT;
+ break;
+
+ default:
+ fail |= CLRCF_FORMAT;
+ break;
+ }
+
+ /* check width */
+ if (config->width > 2046 || config->width < 1)
+ fail |= CLRCF_WIDTH;
+
+ /* check height */
+ if (config->height > 2046 || config->height < 1)
+ fail |= CLRCF_HEIGHT;
+
+ /* write back failing fields */
+ if (failed)
+ *failed = fail;
+
+ /* return failure if any field failed */
+ if (fail)
+ return DFB_UNSUPPORTED;
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0SetRegion( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags updated,
+ CoreSurface *surface,
+ CorePalette *palette,
+ CoreSurfaceBufferLock *lock )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ NVidiaOverlayLayerData *nvov0 = (NVidiaOverlayLayerData*) layer_data;
+
+ /* remember configuration */
+ nvov0->config = *config;
+
+ nvov0->videoSurface = surface;
+ nvov0->lock = lock;
+
+ /* set configuration */
+ if (updated & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_FORMAT |
+ CLRCF_SOURCE | CLRCF_DEST | CLRCF_OPTIONS | CLRCF_OPACITY))
+ {
+ ov0_calc_regs( nvdrv, nvov0, config, updated );
+ ov0_set_regs( nvdrv, nvov0, updated );
+ }
+
+ /* set destination colorkey */
+ if (updated & CLRCF_DSTKEY)
+ ov0_set_colorkey( nvdrv, nvov0, config );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0FlipRegion ( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data,
+ CoreSurface *surface,
+ DFBSurfaceFlipFlags flags,
+ CoreSurfaceBufferLock *lock )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ NVidiaOverlayLayerData *nvov0 = (NVidiaOverlayLayerData*) layer_data;
+
+ nvov0->videoSurface = surface;
+ nvov0->lock = lock;
+
+ dfb_surface_flip( nvov0->videoSurface, false );
+
+ ov0_calc_regs( nvdrv, nvov0, &nvov0->config, CLRCF_SURFACE );
+ ov0_set_regs( nvdrv, nvov0, CLRCF_SURFACE );
+
+ if (flags & DSFLIP_WAIT)
+ dfb_layer_wait_vsync( layer );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0SetColorAdjustment( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ DFBColorAdjustment *adj )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ NVidiaOverlayLayerData *nvov0 = (NVidiaOverlayLayerData*) layer_data;
+
+ if (adj->flags & DCAF_BRIGHTNESS) {
+ nvov0->brightness = (adj->brightness >> 8) - 128;
+ D_DEBUG( "DirectFB/NVidia/Overlay: brightness=%i\n", nvov0->brightness );
+ }
+
+ if (adj->flags & DCAF_CONTRAST) {
+ nvov0->contrast = 8191 - (adj->contrast >> 3); /* contrast inverted ?! */
+ D_DEBUG( "DirectFB/NVidia/Overlay: contrast=%i\n", nvov0->contrast );
+ }
+
+ if (adj->flags & DCAF_SATURATION) {
+ nvov0->saturation = adj->saturation >> 3;
+ D_DEBUG( "DirectFB/NVidia/Overlay: saturation=%i\n", nvov0->saturation );
+ }
+
+ if (adj->flags & DCAF_HUE) {
+ nvov0->hue = (adj->hue / 182 - 180) % 360;
+ D_DEBUG( "DirectFB/NVidia/Overlay: hue=%i\n", nvov0->hue );
+ }
+
+ ov0_set_csc( nvdrv, nvov0 );
+
+ return DFB_OK;
+}
+
+static DFBResult
+ov0SetInputField( CoreLayer *layer,
+ void *driver_data,
+ void *layer_data,
+ void *region_data,
+ int field )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) driver_data;
+ NVidiaOverlayLayerData *nvov0 = (NVidiaOverlayLayerData*) layer_data;
+
+ nvov0->field = field;
+ nvov0->regs.BUFFER = 1 << (field << 2);
+
+ nv_out32( nvdrv->mmio_base, PVIDEO_BUFFER, nvov0->regs.BUFFER );
+
+ return DFB_OK;
+}
+
+DisplayLayerFuncs nvidiaOverlayFuncs = {
+ .LayerDataSize = ov0LayerDataSize,
+ .InitLayer = ov0InitLayer,
+ .SetRegion = ov0SetRegion,
+ .RemoveRegion = ov0Remove,
+ .TestRegion = ov0TestRegion,
+ .FlipRegion = ov0FlipRegion,
+ .SetColorAdjustment = ov0SetColorAdjustment,
+ .SetInputField = ov0SetInputField,
+};
+
+
+/* internal */
+
+static void ov0_set_regs( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfigFlags flags )
+{
+ volatile u8 *mmio = nvdrv->mmio_base;
+
+ if (flags & CLRCF_SURFACE) {
+ if (DFB_PLANAR_PIXELFORMAT(nvov0->config.format)) {
+ nv_out32( mmio, PVIDEO_UVBASE_0, nvov0->regs.UVBASE_0 );
+ nv_out32( mmio, PVIDEO_UVBASE_1, nvov0->regs.UVBASE_1 );
+ nv_out32( mmio, PVIDEO_UVOFFSET_0, nvov0->regs.UVOFFSET_0 );
+ nv_out32( mmio, PVIDEO_UVOFFSET_1, nvov0->regs.UVOFFSET_1 );
+ }
+ nv_out32( mmio, PVIDEO_BASE_0, nvov0->regs.BASE_0 );
+ nv_out32( mmio, PVIDEO_BASE_1, nvov0->regs.BASE_1 );
+ nv_out32( mmio, PVIDEO_OFFSET_0, nvov0->regs.OFFSET_0 );
+ nv_out32( mmio, PVIDEO_OFFSET_1, nvov0->regs.OFFSET_1 );
+ }
+ if (flags & (CLRCF_WIDTH | CLRCF_HEIGHT | CLRCF_OPTIONS)) {
+ nv_out32( mmio, PVIDEO_SIZE_IN_0, nvov0->regs.SIZE_IN_0 );
+ nv_out32( mmio, PVIDEO_SIZE_IN_1, nvov0->regs.SIZE_IN_1 );
+ }
+ if (flags & (CLRCF_SOURCE | CLRCF_DEST | CLRCF_OPTIONS)) {
+ nv_out32( mmio, PVIDEO_POINT_IN_0, nvov0->regs.POINT_IN_0 );
+ nv_out32( mmio, PVIDEO_POINT_IN_1, nvov0->regs.POINT_IN_1 );
+ nv_out32( mmio, PVIDEO_DS_DX_0, nvov0->regs.DS_DX_0 );
+ nv_out32( mmio, PVIDEO_DS_DX_1, nvov0->regs.DS_DX_1 );
+ nv_out32( mmio, PVIDEO_DT_DY_0, nvov0->regs.DT_DY_0 );
+ nv_out32( mmio, PVIDEO_DT_DY_1, nvov0->regs.DT_DY_1 );
+ }
+ if (flags & CLRCF_DEST) {
+ nv_out32( mmio, PVIDEO_POINT_OUT_0, nvov0->regs.POINT_OUT_0 );
+ nv_out32( mmio, PVIDEO_POINT_OUT_1, nvov0->regs.POINT_OUT_1 );
+ nv_out32( mmio, PVIDEO_SIZE_OUT_0, nvov0->regs.SIZE_OUT_0 );
+ nv_out32( mmio, PVIDEO_SIZE_OUT_1, nvov0->regs.SIZE_OUT_1 );
+ }
+ if (flags & (CLRCF_FORMAT | CLRCF_SURFACE | CLRCF_OPTIONS)) {
+ nv_out32( mmio, PVIDEO_FORMAT_0, nvov0->regs.FORMAT_0 );
+ nv_out32( mmio, PVIDEO_FORMAT_1, nvov0->regs.FORMAT_1 );
+ }
+ nv_out32( mmio, PVIDEO_BUFFER, nvov0->regs.BUFFER );
+ nv_out32( mmio, PVIDEO_STOP, nvov0->regs.STOP );
+}
+
+static void
+ov0_calc_regs( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfig *config,
+ CoreLayerRegionConfigFlags flags )
+{
+ NVidiaDeviceData *nvdev = nvdrv->device_data;
+
+ if (flags & (CLRCF_WIDTH | CLRCF_HEIGHT |
+ CLRCF_SOURCE | CLRCF_DEST | CLRCF_OPTIONS)) {
+ int width = config->width;
+ int height = config->height;
+ DFBRectangle source = config->source;
+ DFBRectangle dest = config->dest;
+
+ source.x <<= 4;
+ source.y <<= 4;
+
+ if (dest.x < 0) {
+ source.x -= (dest.x * source.w << 4) / dest.w;
+ source.w += dest.x * source.w / dest.w;
+ dest.w += dest.x;
+ dest.x = 0;
+ }
+
+ if (dest.y < 0) {
+ source.y -= (dest.y * source.h << 4) / dest.h;
+ source.h += dest.y * source.h / dest.h;
+ dest.h += dest.y;
+ dest.y = 0;
+ }
+
+ if (config->options & DLOP_DEINTERLACING) {
+ height /= 2;
+ source.y /= 2;
+ source.h /= 2;
+ }
+
+ if (source.w < 1 || source.h < 1 || dest.w < 1 || dest.h < 1) {
+ nvov0->regs.STOP = PVIDEO_STOP_OVERLAY_ACTIVE |
+ PVIDEO_STOP_METHOD_NORMALLY;
+ return;
+ }
+
+ nvov0->regs.SIZE_IN_0 =
+ nvov0->regs.SIZE_IN_1 = ((height << 16) & PVIDEO_SIZE_IN_HEIGHT_MSK) |
+ ( width & PVIDEO_SIZE_IN_WIDTH_MSK);
+ nvov0->regs.POINT_IN_0 =
+ nvov0->regs.POINT_IN_1 = ((source.y << 16) & PVIDEO_POINT_IN_T_MSK) |
+ ( source.x & PVIDEO_POINT_IN_S_MSK);
+ nvov0->regs.DS_DX_0 =
+ nvov0->regs.DS_DX_1 = (source.w << 20) / dest.w;
+ nvov0->regs.DT_DY_0 =
+ nvov0->regs.DT_DY_1 = (source.h << 20) / dest.h;
+ nvov0->regs.POINT_OUT_0 =
+ nvov0->regs.POINT_OUT_1 = ((dest.y << 16) & PVIDEO_POINT_OUT_Y_MSK) |
+ ( dest.x & PVIDEO_POINT_OUT_X_MSK);
+ nvov0->regs.SIZE_OUT_0 =
+ nvov0->regs.SIZE_OUT_1 = ((dest.h << 16) & PVIDEO_SIZE_OUT_HEIGHT_MSK) |
+ ( dest.w & PVIDEO_SIZE_OUT_WIDTH_MSK);
+ }
+
+ if (flags & (CLRCF_SURFACE | CLRCF_FORMAT | CLRCF_OPTIONS)) {
+ CoreSurfaceBufferLock *lock = nvov0->lock;
+ u32 format;
+
+ if (config->options & DLOP_DEINTERLACING)
+ format = (lock->pitch*2) & PVIDEO_FORMAT_PITCH_MSK;
+ else
+ format = lock->pitch & PVIDEO_FORMAT_PITCH_MSK;
+
+ if (DFB_PLANAR_PIXELFORMAT(config->format))
+ format |= PVIDEO_FORMAT_PLANAR_NV;
+
+ if (config->format == DSPF_UYVY)
+ format |= PVIDEO_FORMAT_COLOR_YB8CR8YA8CB8;
+ else
+ format |= PVIDEO_FORMAT_COLOR_CR8YB8CB8YA8;
+
+ if (config->options & DLOP_DST_COLORKEY)
+ format |= PVIDEO_FORMAT_DISPLAY_COLOR_KEY_EQUAL;
+
+ /* Use Buffer 0 for Odd field */
+ nvov0->regs.OFFSET_0 = (nvdev->fb_offset + lock->offset) & PVIDEO_OFFSET_MSK;
+ /* Use Buffer 1 for Even field */
+ nvov0->regs.OFFSET_1 = nvov0->regs.OFFSET_0 + lock->pitch;
+ if (DFB_PLANAR_PIXELFORMAT(config->format)) {
+ CoreSurface *surface = nvov0->videoSurface;
+ nvov0->regs.UVOFFSET_0 = (nvov0->regs.OFFSET_0 +
+ lock->pitch * surface->config.size.h) & PVIDEO_UVOFFSET_MSK;
+ nvov0->regs.UVOFFSET_1 = nvov0->regs.UVOFFSET_0 + lock->pitch;
+ }
+ nvov0->regs.FORMAT_0 =
+ nvov0->regs.FORMAT_1 = format;
+ }
+
+ nvov0->regs.BUFFER = 1 << (nvov0->field << 2);
+ nvov0->regs.STOP = (config->opacity)
+ ? PVIDEO_STOP_OVERLAY_INACTIVE
+ : PVIDEO_STOP_OVERLAY_ACTIVE;
+ nvov0->regs.STOP |= PVIDEO_STOP_METHOD_NORMALLY;
+}
+
+static void
+ov0_set_colorkey( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0,
+ CoreLayerRegionConfig *config )
+{
+ u32 key;
+
+ key = dfb_color_to_pixel( dfb_primary_layer_pixelformat(),
+ config->dst_key.r,
+ config->dst_key.g,
+ config->dst_key.b );
+
+ nv_out32( nvdrv->mmio_base, PVIDEO_COLOR_KEY, key );
+}
+
+static void
+ov0_set_csc( NVidiaDriverData *nvdrv,
+ NVidiaOverlayLayerData *nvov0 )
+{
+ volatile u8 *mmio = nvdrv->mmio_base;
+ s32 satSine;
+ s32 satCosine;
+ double angle;
+
+ angle = (double) nvov0->hue * M_PI / 180.0;
+ satSine = nvov0->saturation * sin(angle);
+ if (satSine < -1024)
+ satSine = -1024;
+ satCosine = nvov0->saturation * cos(angle);
+ if (satCosine < -1024)
+ satCosine = -1024;
+
+ nv_out32( mmio, PVIDEO_LUMINANCE_0, (nvov0->brightness << 16) |
+ (nvov0->contrast & 0xffff) );
+ nv_out32( mmio, PVIDEO_LUMINANCE_1, (nvov0->brightness << 16) |
+ (nvov0->contrast & 0xffff) );
+ nv_out32( mmio, PVIDEO_CHROMINANCE_0, (satSine << 16) |
+ (satCosine & 0xffff) );
+ nv_out32( mmio, PVIDEO_CHROMINANCE_1, (satSine << 16) |
+ (satCosine & 0xffff) );
+}
+