diff options
Diffstat (limited to 'Source/DirectFB/gfxdrivers/nvidia/nvidia_2d.c')
-rwxr-xr-x | Source/DirectFB/gfxdrivers/nvidia/nvidia_2d.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/nvidia/nvidia_2d.c b/Source/DirectFB/gfxdrivers/nvidia/nvidia_2d.c new file mode 100755 index 0000000..63e1728 --- /dev/null +++ b/Source/DirectFB/gfxdrivers/nvidia/nvidia_2d.c @@ -0,0 +1,549 @@ +/* + (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 Denis Oliver Kropp <dok@directfb.org>, + Andreas Hundt <andi@fischlustig.de>, + Sven Neumann <neo@directfb.org>, + Ville Syrjälä <syrjala@sci.fi> 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 <directfb.h> + +#include <direct/messages.h> +#include <direct/memcpy.h> + +#include <core/coredefs.h> +#include <core/coretypes.h> + +#include <core/gfxcard.h> +#include <core/surface.h> + +#include "nvidia.h" +#include "nvidia_regs.h" +#include "nvidia_accel.h" +#include "nvidia_2d.h" + + +static void +nv_copy32( volatile u32 *dst, u8 *src, int n ) +{ + u32 *D = (u32*) dst; + u32 *S = (u32*) src; + +#ifdef ARCH_X86 + __asm__ __volatile__( + "rep; movsl" + : "=&D" (D), "=&S" (S) + : "c" (n), "0" (D), "1" (S) + : "memory" ); +#else + do { + *D++ = *S++; + } while (--n); +#endif +} + +static void +nv_copy16( volatile u32 *dst, u8 *src, int n ) +{ + u32 *D = (u32*) dst; + u16 *S = (u16*) src; + +#ifdef ARCH_X86 + __asm__ __volatile__( + "rep; movsl" + : "=&D" (D), "=&S" (S) + : "c" (n/2), "0" (D), "1" (S) + : "memory" ); +#else + for (; n > 1; n -= 2) { + *D++ = *((u32*)S); + S += 2; + } +#endif + + if (n & 1) + *D = *S; +} + +static inline bool +nv_clip_source( DFBRectangle *rect, u32 width, u32 height ) +{ + if (rect->x >= width || rect->y >= height) + return false; + + if (rect->x < 0) { + rect->w += rect->x; + rect->x = 0; + } + if (rect->y < 0) { + rect->h += rect->y; + rect->y = 0; + } + + rect->w = MIN( rect->w, width - rect->x ); + rect->h = MIN( rect->h, height - rect->y ); + + return (rect->w > 0 && rect->h > 0); +} + + +#define M_TRANSFORM(x, y, retx, rety, m) { \ + s32 _x, _y; \ + _x = ((s64)(x) * (m)[0] + (y) * (m)[1] + (m)[2] + 0x8000) >> 16; \ + _y = ((s64)(x) * (m)[3] + (y) * (m)[4] + (m)[5] + 0x8000) >> 16; \ + retx = _x; \ + rety = _y; \ +} + + +bool nvFillRectangle2D( void *drv, void *dev, DFBRectangle *rect ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + + if (nvdev->dst_422) { + rect->x /= 2; + rect->w = (rect->w+1) >> 1; + } + + if (nvdev->matrix) { + int x1 = rect->x, x2 = rect->x+rect->w; + int y1 = rect->y, y2 = rect->y+rect->h; + int x, y; + + nv_begin( SUBC_TRIANGLE, TRI_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_TRIANGLE, TRI_POINT0, 3 ); + M_TRANSFORM( x1, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x2, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x1, y2, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + + nv_begin( SUBC_TRIANGLE, TRI_POINT0, 3 ); + M_TRANSFORM( x2, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x2, y2, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x1, y2, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + } + else { + nv_begin( SUBC_RECTANGLE, RECT_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_RECTANGLE, RECT_TOP_LEFT, 2 ); + nv_outr( (rect->y << 16) | (rect->x & 0xFFFF) ); + nv_outr( (rect->h << 16) | (rect->w & 0xFFFF) ); + } + + return true; +} + +bool nvFillTriangle2D( void *drv, void *dev, DFBTriangle *tri ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + + if (nvdev->matrix) { + M_TRANSFORM( tri->x1, tri->y1, tri->x1, tri->y1, nvdev->matrix ); + M_TRANSFORM( tri->x2, tri->y3, tri->x2, tri->y2, nvdev->matrix ); + M_TRANSFORM( tri->x3, tri->y3, tri->x3, tri->y3, nvdev->matrix ); + } + + nv_begin( SUBC_TRIANGLE, TRI_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_TRIANGLE, TRI_POINT0, 3 ); + nv_outr( (tri->y1 << 16) | (tri->x1 & 0xFFFF) ); + nv_outr( (tri->y2 << 16) | (tri->x2 & 0xFFFF) ); + nv_outr( (tri->y3 << 16) | (tri->x3 & 0xFFFF) ); + + return true; +} + +bool nvDrawRectangle2D( void *drv, void *dev, DFBRectangle *rect ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + + if (nvdev->dst_422) { + rect->x /= 2; + rect->w = (rect->w+1) >> 1; + } + + if (nvdev->matrix) { + int x1 = rect->x, x2 = rect->x+rect->w; + int y1 = rect->y, y2 = rect->y+rect->h; + int x, y; + + nv_begin( SUBC_LINE, LINE_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_LINE, LINE_POINT0, 8 ); + /* top */ + M_TRANSFORM( x1, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x2, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + /* right */ + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x2, y2, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + /* bottom */ + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x1, y2, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + /* left */ + nv_outr( (y << 16) | (x & 0xFFFF) ); + M_TRANSFORM( x1, y1, x, y, nvdev->matrix ); + nv_outr( (y << 16) | (x & 0xFFFF) ); + } + else { + nv_begin( SUBC_RECTANGLE, RECT_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_RECTANGLE, RECT_TOP_LEFT, 8 ); + /* top */ + nv_outr( (rect->y << 16) | (rect->x & 0xFFFF) ); + nv_outr( (1 << 16) | (rect->w & 0xFFFF) ); + /* bottom */ + nv_outr( ((rect->y + rect->h - 1) << 16) | (rect->x & 0xFFFF) ); + nv_outr( (1 << 16) | (rect->w & 0xFFFF) ); + /* left */ + nv_outr( ((rect->y + 1) << 16) | (rect->x & 0xFFFF) ); + nv_outr( ((rect->h - 2) << 16) | 1 ); + /* right */ + nv_outr( ((rect->y + 1) << 16) | ((rect->x + rect->w - 1) & 0xFFFF) ); + nv_outr( ((rect->h - 2) << 16) | 1 ); + } + + return true; +} + +bool nvDrawLine2D( void *drv, void *dev, DFBRegion *line ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + + if (nvdev->matrix) { + M_TRANSFORM( line->x1, line->y1, line->x1, line->y1, nvdev->matrix ); + M_TRANSFORM( line->x2, line->y2, line->x2, line->y2, nvdev->matrix ); + } + + nv_begin( SUBC_LINE, LINE_COLOR, 1 ); + nv_outr( nvdev->color2d ); + + nv_begin( SUBC_LINE, LINE_POINT0, 2 ); + nv_outr( (line->y1 << 16) | (line->x1 & 0xFFFF) ); + nv_outr( (line->y2 << 16) | (line->x2 & 0xFFFF) ); + + return true; +} + +bool nvBlit( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + + if (nvdev->blittingflags & DSBLIT_DEINTERLACE || nvdev->matrix) { + DFBRectangle dr = { dx, dy, rect->w, rect->h }; + return nvStretchBlit( drv, dev, rect, &dr ); + } + + if (nvdev->dst_422) { + dx /= 2; + rect->x /= 2; + rect->w = (rect->w+1) >> 1; + } + + if (nvdev->blittingflags || nvdev->src_format != nvdev->dst_format) { + DFBRectangle *clip = &nvdev->clip; + u32 src_width = (nvdev->src_width + 1) & ~1; + u32 src_height = (nvdev->src_height + 1) & ~1; + u32 filter = 0; + + if (nvdev->dst_422) + src_width >>= 1; + + if (nvdev->arch > NV_ARCH_04) + filter = SCALER_IN_FORMAT_ORIGIN_CORNER | + SCALER_IN_FORMAT_FILTER_NEAREST; + + nv_begin( SUBC_SCALEDIMAGE, SCALER_COLOR_FORMAT, 1 ); + nv_outr( nvdev->scaler_format ); + + nv_begin( SUBC_SCALEDIMAGE, SCALER_CLIP_POINT, 6 ); + nv_outr( (clip->y << 16) | (clip->x & 0xFFFF) ); + nv_outr( (clip->h << 16) | (clip->w & 0xFFFF) ); + nv_outr( (dy << 16) | (dx & 0xFFFF) ); + nv_outr( (rect->h << 16) | (rect->w & 0xFFFF) ); + nv_outr( 0x100000 ); + nv_outr( 0x100000 ); + + nv_begin( SUBC_SCALEDIMAGE, SCALER_IN_SIZE, 4 ); + nv_outr( (src_height << 16) | (src_width & 0xFFFF) ); + nv_outr( (nvdev->src_pitch & 0xFFFF) | filter ); + nv_outr( nvdev->src_offset ); + nv_outr( (rect->y << 20) | ((rect->x<<4) & 0xFFFF) ); + } + else { + nv_begin( SUBC_SCREENBLT, BLIT_TOP_LEFT_SRC, 3 ); + nv_outr( (rect->y << 16) | (rect->x & 0xFFFF) ); + nv_outr( (dy << 16) | (dx & 0xFFFF) ); + nv_outr( (rect->h << 16) | (rect->w & 0xFFFF) ); + } + + return true; +} + +bool nvBlitFromCPU( void *drv, void *dev, DFBRectangle *rect, int dx, int dy ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + u8 *src = nvdev->src_address; + u32 src_w; + u32 src_h; + int w, h, n; + + if (nvdev->blittingflags & DSBLIT_DEINTERLACE || nvdev->matrix) { + DFBRectangle dr = { dx, dy, rect->x, rect->y }; + return nvStretchBlitFromCPU( drv, dev, rect, &dr ); + } + + if (!nv_clip_source( rect, nvdev->src_width, nvdev->src_height )) + return true; + + src_w = (DFB_BYTES_PER_PIXEL(nvdev->src_format) == 2) + ? ((rect->w + 1) & ~1) : rect->w; + src_h = rect->h; + + nv_begin( SUBC_IMAGEBLT, IBLIT_COLOR_FORMAT, 1 ); + nv_outr( nvdev->system_format ); + + nv_begin( SUBC_IMAGEBLT, IBLIT_POINT, 3 ); + nv_outr( (dy << 16) | (dx & 0xFFFF) ); + nv_outr( (rect->h << 16) | (rect->w & 0xFFFF) ); + nv_outr( (src_h << 16) | (src_w & 0xFFFF) ); + + n = nvdev->use_dma ? 256 : 128; + + switch (nvdev->src_format) { + case DSPF_ARGB1555: + case DSPF_RGB16: + src += rect->y * nvdev->src_pitch + rect->x * 2; + for (h = rect->h; h--;) { + u8 *s = src; + + for (w = rect->w; w >= n*2; w -= n*2) { + nv_begin( SUBC_IMAGEBLT, IBLIT_PIXEL0, n ); + direct_memcpy( (void*)nvdev->cmd_ptr, s, n*4 ); + s += n*4; + } + if (w > 0) { + nv_begin( SUBC_IMAGEBLT, IBLIT_PIXEL0, (w+1)>>1 ); + nv_copy16( nvdev->cmd_ptr, s, w ); + } + + src += nvdev->src_pitch; + } + break; + + default: + src += rect->y * nvdev->src_pitch + rect->x * 4; + for (h = rect->h; h--;) { + u8 *s = src; + + for (w = rect->w; w >= n; w -= n) { + nv_begin( SUBC_IMAGEBLT, IBLIT_PIXEL0, n ); + direct_memcpy( (void*)nvdev->cmd_ptr, s, n*4 ); + s += n*4; + } + if (w > 0) { + nv_begin( SUBC_IMAGEBLT, IBLIT_PIXEL0, w ); + nv_copy32( nvdev->cmd_ptr, s, w ); + } + + src += nvdev->src_pitch; + } + break; + } + + return true; +} + +bool nvStretchBlit( void *drv, void *dev, DFBRectangle *sr, DFBRectangle *dr ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + DFBRectangle *cr = &nvdev->clip; + u32 src_width = (nvdev->src_width + 1) & ~1; + u32 src_height = (nvdev->src_height + 1) & ~1; + + if (nvdev->dst_422) { + sr->x /= 2; + sr->w = (sr->w+1) >> 1; + dr->x /= 2; + dr->w = (dr->w+1) >> 1; + src_width >>= 1; + } + + if (nvdev->blittingflags & DSBLIT_DEINTERLACE) { + sr->y /= 2; + sr->h = (sr->h+1) / 2; + } + + if (nvdev->matrix) { + int x1, y1, x2, y2; + + if (!nvdev->matrix[0] || !nvdev->matrix[4]) + return true; + + M_TRANSFORM( dr->x, dr->y, x1, y1, nvdev->matrix ); + M_TRANSFORM( dr->x+dr->w, dr->y+dr->h, x2, y2, nvdev->matrix ); + + dr->x = x1; dr->w = x2-x1; + dr->y = y1; dr->h = y2-y1; + } + + nv_begin( SUBC_SCALEDIMAGE, SCALER_COLOR_FORMAT, 1 ); + nv_outr( nvdev->scaler_format ); + + nv_begin( SUBC_SCALEDIMAGE, SCALER_CLIP_POINT, 6 ); + nv_outr( (cr->y << 16) | (cr->x & 0xFFFF) ); + nv_outr( (cr->h << 16) | (cr->w & 0xFFFF) ); + nv_outr( (dr->y << 16) | (dr->x & 0xFFFF) ); + nv_outr( (dr->h << 16) | (dr->w & 0xFFFF) ); + nv_outr( (sr->w << 20) / dr->w ); + nv_outr( (sr->h << 20) / dr->h ); + + nv_begin( SUBC_SCALEDIMAGE, SCALER_IN_SIZE, 4 ); + nv_outr( (src_height << 16) | (src_width & 0xFFFF) ); + nv_outr( (nvdev->src_pitch & 0xFFFF) | nvdev->scaler_filter ); + nv_outr( nvdev->src_offset ); + nv_outr( (sr->y << 20) | ((sr->x << 4) & 0xFFFF) ); + + return true; +} + +bool nvStretchBlitFromCPU( void *drv, void *dev, + DFBRectangle *sr, DFBRectangle *dr ) +{ + NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv; + NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev; + DFBRectangle *cr = &nvdev->clip; + u8 *src = nvdev->src_address; + u32 src_w; + u32 src_h; + int w, h, n; + + if (!nv_clip_source( sr, nvdev->src_width, nvdev->src_height )) + return true; + + if (nvdev->blittingflags & DSBLIT_DEINTERLACE) { + sr->y /= 2; + sr->h /= 2; + } + + if (nvdev->matrix) { + int x1, y1, x2, y2; + + if (!nvdev->matrix[0] || !nvdev->matrix[4]) + return true; + + M_TRANSFORM( dr->x, dr->y, x1, y1, nvdev->matrix ); + M_TRANSFORM( dr->x+dr->w, dr->y+dr->h, x2, y2, nvdev->matrix ); + + dr->x = x1; dr->w = x2-x1; + dr->y = y1; dr->h = y2-y1; + } + + src_w = (DFB_BYTES_PER_PIXEL(nvdev->src_format) == 2) + ? ((sr->w + 1) & ~1) : sr->w; + src_h = sr->h; + + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_COLOR_FORMAT, 1 ); + nv_outr( nvdev->system_format ); + + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_IN_SIZE, 6 ); + nv_outr( (src_h << 16) | (src_w & 0xFFFF) ); + nv_outr( (dr->w << 20) / src_w ); + nv_outr( (dr->h << 20) / src_h ); + nv_outr( (cr->y << 16) | (cr->x & 0xFFFF) ); + nv_outr( (cr->h << 16) | (cr->w & 0xFFFF) ); + nv_outr( (dr->y << 20) | ((dr->x<<4) & 0xFFFF) ); + + n = nvdev->use_dma ? 256 : 128; + + switch (nvdev->src_format) { + case DSPF_ARGB1555: + case DSPF_RGB16: + src += sr->y * nvdev->src_pitch + sr->x * 2; + for (h = sr->h; h--;) { + u8 *s = src; + + for (w = sr->w; w >= n*2; w -= n*2) { + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_PIXEL0, n ); + direct_memcpy( (void*)nvdev->cmd_ptr, s, n*4 ); + s += n*4; + } + if (w > 0) { + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_PIXEL0, (w+1)>>1 ); + nv_copy16( nvdev->cmd_ptr, s, w ); + } + + src += nvdev->src_pitch; + } + break; + + default: + src += sr->y * nvdev->src_pitch + sr->x * 4; + for (h = sr->h; h--;) { + u8 *s= src; + + for (w = sr->w; w >= n; w -= n) { + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_PIXEL0, n ); + direct_memcpy( (void*)nvdev->cmd_ptr, s, n*4 ); + s += n*4; + } + if (w > 0) { + nv_begin( SUBC_STRETCHEDIMAGE, ISTRETCH_PIXEL0, w ); + nv_copy32( nvdev->cmd_ptr, s, w ); + } + + src += nvdev->src_pitch; + } + break; + } + + return true; +} + |