summaryrefslogtreecommitdiff
path: root/Source/DirectFB/gfxdrivers/nvidia/nvidia_3d.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/gfxdrivers/nvidia/nvidia_3d.c')
-rwxr-xr-xSource/DirectFB/gfxdrivers/nvidia/nvidia_3d.c522
1 files changed, 522 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/nvidia/nvidia_3d.c b/Source/DirectFB/gfxdrivers/nvidia/nvidia_3d.c
new file mode 100755
index 0000000..ae8dffc
--- /dev/null
+++ b/Source/DirectFB/gfxdrivers/nvidia/nvidia_3d.c
@@ -0,0 +1,522 @@
+/*
+ Copyright (C) 2004-2006 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 <directfb.h>
+
+#include <direct/messages.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+
+#include <core/coredefs.h>
+#include <core/coretypes.h>
+
+#include <core/gfxcard.h>
+#include <core/surface.h>
+
+#include <gfx/convert.h>
+
+#include "nvidia.h"
+#include "nvidia_regs.h"
+#include "nvidia_accel.h"
+#include "nvidia_3d.h"
+
+
+static __inline__ u32
+f2d( float f ) {
+ union {
+ float f;
+ u32 d;
+ } t;
+ t.f = f;
+ return t.d;
+}
+
+#define nv_setstate3d( state3d ) { \
+ if ((state3d)->modified) { \
+ nv_begin( SUBC_TEXTRIANGLE, TXTRI_COLOR_KEY, 7 ); \
+ nv_outr( (state3d)->colorkey ); \
+ nv_outr( (state3d)->offset ); \
+ nv_outr( (state3d)->format ); \
+ nv_outr( (state3d)->filter ); \
+ nv_outr( (state3d)->blend ); \
+ nv_outr( (state3d)->control ); \
+ nv_outr( (state3d)->fog ); \
+ \
+ (state3d)->modified = false; \
+ } \
+}
+
+#define nv_putvertex( i, x, y, z, w, col, spc, s, t ) { \
+ nv_begin( SUBC_TEXTRIANGLE, TXTRI_VERTEX0+(i)*32, 8 ); \
+ nv_outr( f2d( x ) ); \
+ nv_outr( f2d( y ) ); \
+ nv_outr( f2d( z ) ); \
+ nv_outr( f2d( w ) ); \
+ nv_outr( col ); \
+ nv_outr( spc ); \
+ nv_outr( f2d( s ) ); \
+ nv_outr( f2d( t ) ); \
+}
+
+#define nv_emit_vertices( i, v0, v1, v2, v3, v4, v5, v6, v7 ) { \
+ nv_begin( SUBC_TEXTRIANGLE, TXTRI_PRIMITIVE0+(i)*4, 1 ); \
+ nv_outr( ((v7) << 28) | ((v6) << 24) | \
+ ((v5) << 20) | ((v4) << 16) | \
+ ((v3) << 12) | ((v2) << 8) | \
+ ((v1) << 4) | (v0) ); \
+}
+
+
+static void nv_load_texture( NVidiaDriverData *nvdrv, NVidiaDeviceData *nvdev );
+
+
+#define M_TRANSFORM(x, y, retx, rety, m) { \
+ float _x, _y; \
+ _x = ((x) * (m)[0] + (y) * (m)[1] + (m)[2]) / 65536.f; \
+ _y = ((x) * (m)[3] + (y) * (m)[4] + (m)[5]) / 65536.f; \
+ retx = _x; \
+ rety = _y; \
+}
+
+
+bool nvFillRectangle3D( void *drv, void *dev, DFBRectangle *rect )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv;
+ NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev;
+ float x1, y1;
+ float x2, y2;
+
+ x1 = rect->x; x2 = rect->x+rect->w;
+ y1 = rect->y; y2 = rect->y+rect->h;
+
+ nv_setstate3d( &nvdev->state3d[0] );
+
+ if (nvdev->matrix) {
+ float x, y;
+
+ M_TRANSFORM( x1, y1, x, y, nvdev->matrix );
+ nv_putvertex( 0, x, y, 0, 1, nvdev->color3d, 0, 0, 0 );
+ M_TRANSFORM( x2, y1, x, y, nvdev->matrix );
+ nv_putvertex( 1, x, y, 0, 1, nvdev->color3d, 0, 0, 0 );
+ M_TRANSFORM( x2, y2, x, y, nvdev->matrix );
+ nv_putvertex( 2, x, y, 0, 1, nvdev->color3d, 0, 0, 0 );
+ M_TRANSFORM( x1, y2, x, y, nvdev->matrix );
+ nv_putvertex( 3, x, y, 0, 1, nvdev->color3d, 0, 0, 0 );
+ }
+ else {
+ nv_putvertex( 0, x1, y1, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 1, x2, y1, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 2, x2, y2, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 3, x1, y2, 0, 1, nvdev->color3d, 0, 0, 0 );
+ }
+
+ nv_emit_vertices( 0, 0, 1, 2, 0, 2, 3, 0, 0 );
+
+ return true;
+}
+
+bool nvFillTriangle3D( void *drv, void *dev, DFBTriangle *tri )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv;
+ NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev;
+ float x1, y1;
+ float x2, y2;
+ float x3, y3;
+
+ x1 = tri->x1; x2 = tri->x2; x3 = tri->x3;
+ y1 = tri->y1; y2 = tri->y2; y3 = tri->y3;
+ if (nvdev->matrix) {
+ M_TRANSFORM( x1, y1, x1, y1, nvdev->matrix );
+ M_TRANSFORM( x2, y2, x2, y2, nvdev->matrix );
+ M_TRANSFORM( x3, y3, x3, y3, nvdev->matrix );
+ }
+
+ nv_setstate3d( &nvdev->state3d[0] );
+
+ nv_putvertex( 0, x1, y1, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 1, x2, y2, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 2, x3, y3, 0, 1, nvdev->color3d, 0, 0, 0 );
+
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+
+ return true;
+}
+
+bool nvDrawRectangle3D( void *drv, void *dev, DFBRectangle *rect )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv;
+ NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev;
+ DFBRegion r[4];
+ int i;
+
+ if (nvdev->matrix) {
+ DFBRegion line;
+
+ /* top */
+ line = (DFBRegion) { rect->x, rect->y, rect->x+rect->w, rect->y };
+ nvDrawLine3D( drv, dev, &line );
+ /* right */
+ line = (DFBRegion) { rect->x+rect->w, rect->y, rect->x+rect->w, rect->y+rect->h };
+ nvDrawLine3D( drv, dev, &line );
+ /* bottom */
+ line = (DFBRegion) { rect->x, rect->y+rect->h, rect->x+rect->w, rect->y+rect->h };
+ nvDrawLine3D( drv, dev, &line );
+ /* left */
+ line = (DFBRegion) { rect->x, rect->y, rect->x, rect->y+rect->h };
+ nvDrawLine3D( drv, dev, &line );
+
+ return true;
+ }
+
+ /* top */
+ r[0].x1 = rect->x;
+ r[0].y1 = rect->y;
+ r[0].x2 = rect->x + rect->w;
+ r[0].y2 = rect->y + 1;
+
+ /* right */
+ r[1].x1 = rect->x + rect->w - 1;
+ r[1].y1 = rect->y + 1;
+ r[1].x2 = rect->x + rect->w;
+ r[1].y2 = rect->y + rect->h - 1;
+
+ /* bottom */
+ r[2].x1 = rect->x;
+ r[2].y1 = rect->y + rect->h - 1;
+ r[2].x2 = rect->x + rect->w;
+ r[2].y2 = rect->y + rect->h;
+
+ /* left */
+ r[3].x1 = rect->x;
+ r[3].y1 = rect->y + 1;
+ r[3].x2 = rect->x + 1;
+ r[3].y2 = rect->y + rect->h - 1;
+
+ nv_setstate3d( &nvdev->state3d[0] );
+
+ for (i = 0; i < 4; i++) {
+ nv_putvertex( 0, r[i].x1, r[i].y1, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 1, r[i].x2, r[i].y1, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 2, r[i].x2, r[i].y2, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 3, r[i].x1, r[i].y2, 0, 1, nvdev->color3d, 0, 0, 0 );
+
+ nv_emit_vertices( 0, 0, 1, 2, 0, 2, 3, 0, 0 );
+ }
+
+ return true;
+}
+
+bool nvDrawLine3D( void *drv, void *dev, DFBRegion *line )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv;
+ NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev;
+ float xinc, yinc;
+ float x1, y1;
+ float x2, y2;
+ float dx, dy;
+
+ x1 = line->x1; x2 = line->x2;
+ y1 = line->y1; y2 = line->y2;
+ if (nvdev->matrix) {
+ M_TRANSFORM( x1, y1, x1, y1, nvdev->matrix );
+ M_TRANSFORM( x2, y2, x2, y2, nvdev->matrix );
+
+ dx = fabs(x2 - x1);
+ dy = fabs(y2 - y1);
+ }
+ else {
+ dx = abs(line->x2 - line->x1);
+ dy = abs(line->y2 - line->y1);
+ }
+
+ if (dx > dy) { /* more horizontal */
+ xinc = 0.0;
+ yinc = 0.5;
+ } else { /* more vertical */
+ xinc = 0.5;
+ yinc = 0.0;
+ }
+
+ nv_setstate3d( &nvdev->state3d[0] );
+
+ nv_putvertex( 0, x1 - xinc, y1 - yinc, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 1, x1 + xinc, y1 + yinc, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 2, x2 + xinc, y2 + yinc, 0, 1, nvdev->color3d, 0, 0, 0 );
+ nv_putvertex( 3, x2 - xinc, y2 - yinc, 0, 1, nvdev->color3d, 0, 0, 0 );
+
+ nv_emit_vertices( 0, 2, 0, 1, 3, 0, 2, 0, 0 );
+
+ return true;
+}
+
+bool nvTextureTriangles( void *drv, void *dev, DFBVertex *ve,
+ int num, DFBTriangleFormation formation )
+{
+ NVidiaDriverData *nvdrv = (NVidiaDriverData*) drv;
+ NVidiaDeviceData *nvdev = (NVidiaDeviceData*) dev;
+ float s_scale;
+ float t_scale;
+ int i;
+
+ /* load source texture into texture buffer */
+ nv_load_texture( nvdrv, nvdev );
+
+ s_scale = (float)nvdev->src_width /
+ (float)(1 << ((nvdev->state3d[1].format >> 16) & 0xF));
+ t_scale = (float)nvdev->src_height /
+ (float)(1 << ((nvdev->state3d[1].format >> 20) & 0xF));
+
+ for (i = 0; i < num; i++) {
+ if (nvdev->matrix)
+ M_TRANSFORM( ve[i].x, ve[i].y, ve[i].x, ve[i].y, nvdev->matrix );
+ ve[i].x += 0.5;
+ ve[i].y += 0.5;
+ ve[i].s *= s_scale;
+ ve[i].t *= t_scale;
+ }
+
+ nv_setstate3d( &nvdev->state3d[1] );
+
+ switch (formation) {
+ case DTTF_LIST:
+ for (i = 0; i < num; i += 3) {
+ nv_putvertex( 0, ve[i].x, ve[i].y, ve[i].z, ve[i].w,
+ nvdev->color3d, 0, ve[i].s, ve[i].t );
+ nv_putvertex( 1, ve[i+1].x, ve[i+1].y, ve[i+1].z, ve[i+1].w,
+ nvdev->color3d, 0, ve[i+1].s, ve[i+1].t );
+ nv_putvertex( 2, ve[i+2].x, ve[i+2].y, ve[i+2].z, ve[i+2].w,
+ nvdev->color3d, 0, ve[i+2].s, ve[i+2].t );
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+ }
+ break;
+
+ case DTTF_STRIP:
+ nv_putvertex( 0, ve[0].x, ve[0].y, ve[0].z, ve[0].w,
+ nvdev->color3d, 0, ve[0].s, ve[0].t );
+ nv_putvertex( 1, ve[1].x, ve[1].y, ve[1].z, ve[1].w,
+ nvdev->color3d, 0, ve[1].s, ve[1].t );
+ nv_putvertex( 2, ve[2].x, ve[2].y, ve[2].z, ve[2].w,
+ nvdev->color3d, 0, ve[2].s, ve[2].t );
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+
+ for (i = 3; i < num; i++) {
+ nv_putvertex( 0, ve[i-2].x, ve[i-2].y, ve[i-2].z, ve[i-2].w,
+ nvdev->color3d, 0, ve[i-2].s, ve[i-2].t );
+ nv_putvertex( 1, ve[i-1].x, ve[i-1].y, ve[i-1].z, ve[i-1].w,
+ nvdev->color3d, 0, ve[i-1].s, ve[i-1].t );
+ nv_putvertex( 2, ve[i].x, ve[i].y, ve[i].z, ve[i].w,
+ nvdev->color3d, 0, ve[i].s, ve[i].t );
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+ }
+ break;
+
+ case DTTF_FAN:
+ nv_putvertex( 0, ve[0].x, ve[0].y, ve[0].z, ve[0].w,
+ nvdev->color3d, 0, ve[0].s, ve[0].t );
+ nv_putvertex( 1, ve[1].x, ve[1].y, ve[1].z, ve[1].w,
+ nvdev->color3d, 0, ve[1].s, ve[1].t );
+ nv_putvertex( 2, ve[2].x, ve[2].y, ve[2].z, ve[2].w,
+ nvdev->color3d, 0, ve[2].s, ve[2].t );
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+
+ for (i = 3; i < num; i++) {
+ nv_putvertex( 0, ve[0].x, ve[0].y, ve[0].z, ve[0].w,
+ nvdev->color3d, 0, ve[0].s, ve[0].t );
+ nv_putvertex( 1, ve[i-1].x, ve[i-1].y, ve[i-1].z, ve[i-1].w,
+ nvdev->color3d, 0, ve[i-1].s, ve[i-1].t );
+ nv_putvertex( 2, ve[i].x, ve[i].y, ve[i].z, ve[i].w,
+ nvdev->color3d, 0, ve[i].s, ve[i].t );
+ nv_emit_vertices( 0, 0, 1, 2, 0, 0, 0, 0, 0 );
+ }
+ break;
+
+ default:
+ D_BUG( "unexpected triangle formation" );
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Surface to Texture conversion routines.
+ */
+
+#define VINC 0xAAAAAAAC
+#define VMASK 0x55555555
+#define UINC 0x55555558
+#define UMASK 0xAAAAAAAA
+
+static inline void
+a8_to_tex( u32 *dst, u8 *src, int pitch, int width, int height )
+{
+ u32 u, v;
+ int i;
+
+ for (v = 0; height--; v = (v + VINC) & VMASK) {
+ for (i = 0, u = 0; i < width; i += 2, u = (u + UINC) & UMASK) {
+#ifdef WORDS_BIGENDIAN
+ dst[(u|v)/4] = ((src[i+0] & 0xF0) << 24) |
+ ((src[i+1] & 0xF0) << 8) |
+ 0x0FFF0FFF;
+#else
+ dst[(u|v)/4] = ((src[i+0] & 0xF0) << 8) |
+ ((src[i+1] & 0xF0) << 24) |
+ 0x0FFF0FFF;
+#endif
+ }
+
+ if (width & 1) {
+ u = (u + UINC) & UMASK;
+ dst[(u|v)/4] = ((src[width-1] & 0xF0) << 8) | 0x0FFF;
+ }
+
+ src += pitch;
+ }
+}
+
+static inline void
+rgb16_to_tex( u32 *dst, u8 *src, int pitch, int width, int height )
+{
+ u32 u, v;
+ int i;
+
+ for (v = 0; height--; v = (v + VINC) & VMASK) {
+ for (i = 0, u = 0; i < width/2; i++, u = (u + UINC) & UMASK)
+ dst[(u|v)/4] = ((u32*) src)[i];
+
+ if (width & 1) {
+ u = (u + UINC) & UMASK;
+ dst[(u|v)/4] = ((u16*) src)[width-1];
+ }
+
+ src += pitch;
+ }
+}
+
+static inline void
+rgb32_to_tex( u32 *dst, u8 *src, int pitch, int width, int height )
+{
+ u32 u, v;
+ int i;
+
+ for (v = 0; height--; v = (v + VINC) & VMASK) {
+ for (i = 0, u = 0; i < width; i += 2, u = (u + UINC) & UMASK) {
+ register u32 pix0, pix1;
+ pix0 = ((u32*) src)[i];
+ pix0 = RGB32_TO_RGB16( pix0 );
+ pix1 = ((u32*) src)[i+1];
+ pix1 = RGB32_TO_RGB16( pix1 );
+#ifdef WORDS_BIGENDIAN
+ dst[(u|v)/4] = (pix0 << 16) | pix1;
+#else
+ dst[(u|v)/4] = pix0 | (pix1 << 16);
+#endif
+ }
+
+ if (width & 1) {
+ u = (u + UINC) & UMASK;
+ dst[(u|v)/4] = RGB32_TO_RGB16( ((u32*) src)[width-1] );
+ }
+
+ src += pitch;
+ }
+}
+
+static inline void
+argb_to_tex( u32 *dst, u8 *src, int pitch, int width, int height )
+{
+ u32 u, v;
+ int i;
+
+ for (v = 0; height--; v = (v + VINC) & VMASK) {
+ for (i = 0, u = 0; i < width; i += 2, u = (u + UINC) & UMASK) {
+ register u32 pix0, pix1;
+ pix0 = ((u32*) src)[i];
+ pix0 = ARGB_TO_ARGB4444( pix0 );
+ pix1 = ((u32*) src)[i+1];
+ pix1 = ARGB_TO_ARGB4444( pix1 );
+#ifdef WORDS_BIGENDIAN
+ dst[(u|v)/4] = (pix0 << 16) | pix1;
+#else
+ dst[(u|v)/4] = pix0 | (pix1 << 16);
+#endif
+ }
+
+ if (width & 1) {
+ u = (u + UINC) & UMASK;
+ dst[(u|v)/4] = ARGB_TO_ARGB4444( ((u32*) src)[width-1] );
+ }
+
+ src += pitch;
+ }
+}
+
+static void nv_load_texture( NVidiaDriverData *nvdrv,
+ NVidiaDeviceData *nvdev )
+{
+ CoreSurfaceBuffer *buffer = nvdev->src_texture;
+ u32 *dst;
+
+ dst = dfb_gfxcard_memory_virtual( nvdrv->device, nvdev->buf_offset[1] );
+
+#if 0
+ if (nvdev->src_interlaced) {
+ if (surface->caps & DSCAPS_SEPARATED) {
+ if (surface->field)
+ field_offset = nvdev->src_height * src_pitch;
+ } else {
+ if (surface->field)
+ field_offset = src_pitch;
+ src_pitch *= 2;
+ }
+ }
+#endif
+
+ switch (buffer->format) {
+ case DSPF_A8:
+ a8_to_tex( dst, nvdev->src_lock->addr, nvdev->src_lock->pitch,
+ nvdev->src_width, nvdev->src_height );
+ break;
+ case DSPF_ARGB1555:
+ case DSPF_RGB16:
+ rgb16_to_tex( dst, nvdev->src_lock->addr, nvdev->src_lock->pitch,
+ nvdev->src_width, nvdev->src_height );
+ break;
+ case DSPF_RGB32:
+ rgb32_to_tex( dst, nvdev->src_lock->addr, nvdev->src_lock->pitch,
+ nvdev->src_width, nvdev->src_height );
+ break;
+ case DSPF_ARGB:
+ argb_to_tex( dst, nvdev->src_lock->addr, nvdev->src_lock->pitch,
+ nvdev->src_width, nvdev->src_height );
+ break;
+ default:
+ D_BUG( "unexpected pixelformat" );
+ break;
+ }
+}
+