diff options
Diffstat (limited to 'Source/DirectFB/gfxdrivers/radeon/r300_3d.c')
-rwxr-xr-x | Source/DirectFB/gfxdrivers/radeon/r300_3d.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/Source/DirectFB/gfxdrivers/radeon/r300_3d.c b/Source/DirectFB/gfxdrivers/radeon/r300_3d.c new file mode 100755 index 0000000..c8a1b8c --- /dev/null +++ b/Source/DirectFB/gfxdrivers/radeon/r300_3d.c @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2006 Claudio Ciccani <klan@users.sf.net> + * + * Graphics driver for ATI Radeon cards written by + * 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 <string.h> +#include <unistd.h> + +#include <dfb_types.h> +#include <directfb.h> + +#include <direct/types.h> +#include <direct/messages.h> +#include <direct/util.h> + +#include <core/coredefs.h> +#include <core/coretypes.h> +#include <core/state.h> +#include <core/gfxcard.h> + +#include "radeon.h" +#include "radeon_regs.h" +#include "radeon_mmio.h" +#include "radeon_state.h" +#include "radeon_3d.h" + + +#define EMIT_VERTICES( rdrv, rdev, mmio ) { \ + u32 *_v = (rdev)->vb; \ + u32 _s = (rdev)->vb_size; \ + radeon_waitfifo( rdrv, rdev, 1 ); \ + radeon_out32( mmio, SE_VF_CNTL, rdev->vb_type | VF_PRIM_WALK_DATA | \ + (rdev->vb_count << VF_NUM_VERTICES_SHIFT) ); \ + do { \ + u32 _n = MIN(_s, 64); \ + _s -= _n; \ + radeon_waitfifo( rdrv, rdev, _n ); \ + while (_n--) \ + radeon_out32( mmio, SE_PORT_DATA0, *_v++ ); \ + } while (_s); \ + radeon_waitfifo( rdrv, rdev, 2 ); \ + radeon_out32( mmio, R300_RB3D_DSTCACHE_CTLSTAT, 0xa ); \ + radeon_out32( mmio, 0x4f18, 0x3 ); \ +} + +static void +r300_flush_vb( RadeonDriverData *rdrv, RadeonDeviceData *rdev ) +{ + volatile u8 *mmio = rdrv->mmio_base; + + EMIT_VERTICES( rdrv, rdev, mmio ); + + if (DFB_PLANAR_PIXELFORMAT(rdev->dst_format)) { + DFBRegion clip; + int i; + + for (i = 0; i < rdev->vb_size; i += 8) { + rdev->vb[i+0] = f2d(d2f(rdev->vb[i+0])*0.5f); + rdev->vb[i+1] = f2d(d2f(rdev->vb[i+1])*0.5f); + } + + clip.x1 = rdev->clip.x1 >> 1; + clip.y1 = rdev->clip.y1 >> 1; + clip.x2 = rdev->clip.x2 >> 1; + clip.y2 = rdev->clip.y2 >> 1; + + /* Prepare Cb plane */ + radeon_waitfifo( rdrv, rdev, 5 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset_cb ); + radeon_out32( mmio, R300_RB3D_COLORPITCH0, (rdev->dst_pitch>>1) | + R300_COLOR_FORMAT_RGB8 ); + radeon_out32( mmio, R300_TX_SIZE_0, ((rdev->src_width/2 -1) << R300_TX_WIDTH_SHIFT) | + ((rdev->src_height/2-1) << R300_TX_HEIGHT_SHIFT) | + R300_TX_SIZE_TXPITCH_EN ); + radeon_out32( mmio, R300_TX_PITCH_0, (rdev->src_pitch>>1) - 8 ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset_cb ); + r300_set_clip3d( rdrv, rdev, &clip ); + + /* Fill Cb plane */ + EMIT_VERTICES( rdrv, rdev, mmio ); + + /* Prepare Cr plane */ + radeon_waitfifo( rdrv, rdev, 2 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset_cr ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset_cr ); + + /* Fill Cr plane */ + EMIT_VERTICES( rdrv, rdev, mmio ); + + /* Reset */ + radeon_waitfifo( rdrv, rdev, 5 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset ); + radeon_out32( mmio, R300_RB3D_COLORPITCH0, rdev->dst_pitch | + R300_COLOR_FORMAT_RGB8 ); + radeon_out32( mmio, R300_TX_SIZE_0, ((rdev->src_width -1) << R300_TX_WIDTH_SHIFT) | + ((rdev->src_height-1) << R300_TX_HEIGHT_SHIFT) | + R300_TX_SIZE_TXPITCH_EN ); + radeon_out32( mmio, R300_TX_PITCH_0, rdev->src_pitch - 8 ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset ); + r300_set_clip3d( rdrv, rdev, &rdev->clip ); + } + + rdev->vb_size = 0; + rdev->vb_count = 0; +} + +static inline u32* +r300_init_vb( RadeonDriverData *rdrv, RadeonDeviceData *rdev, u32 type, u32 count, u32 size ) +{ + u32 *vb; + + if ((rdev->vb_size && rdev->vb_type != type) || + rdev->vb_size+size > D_ARRAY_SIZE(rdev->vb)) + r300_flush_vb( rdrv, rdev ); + + vb = &rdev->vb[rdev->vb_size]; + rdev->vb_type = type; + rdev->vb_size += size; + rdev->vb_count += count; + + return vb; +} + + +#define VTX(v, x, y, c) \ + *(v)++ = f2d(x); \ + *(v)++ = f2d(y); \ + *(v)++ = f2d(0); \ + *(v)++ = f2d(1); \ + *(v)++ = f2d(c[0]); \ + *(v)++ = f2d(c[1]); \ + *(v)++ = f2d(c[2]); \ + *(v)++ = f2d(c[3]) + +bool r300FillRectangle3D( void *drv, void *dev, DFBRectangle *rect ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + float x1, y1; + float x2, y2; + u32 *v; + + if (rect->w == 1 && rect->h == 1) { + x1 = rect->x+1; y1 = rect->y+1; + if (rdev->matrix) + RADEON_TRANSFORM( x1, y1, x1, y1, rdev->matrix, rdev->affine_matrix ); + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_POINT_LIST, 1, 8 ); + VTX( v, x1, y1, rdev->color ); + + return true; + } + + x1 = rect->x; y1 = rect->y; + x2 = rect->x+rect->w; y2 = rect->y+rect->h; + if (rdev->matrix) { + float x, y; + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_QUAD_LIST, 4, 32 ); + RADEON_TRANSFORM( x1, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x2, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x2, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x1, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + } + else { + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_QUAD_LIST, 4, 32 ); + VTX( v, x1, y1, rdev->color ); + VTX( v, x2, y1, rdev->color ); + VTX( v, x2, y2, rdev->color ); + VTX( v, x1, y2, rdev->color ); + } + + return true; +} + +bool r300FillTriangle( void *drv, void *dev, DFBTriangle *tri ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + float x1, y1; + float x2, y2; + float x3, y3; + u32 *v; + + x1 = tri->x1; y1 = tri->y1; + x2 = tri->x2; y2 = tri->y2; + x3 = tri->x3; y3 = tri->y3; + if (rdev->matrix) { + RADEON_TRANSFORM( x1, y1, x1, y1, rdev->matrix, rdev->affine_matrix ); + RADEON_TRANSFORM( x2, y2, x2, y2, rdev->matrix, rdev->affine_matrix ); + RADEON_TRANSFORM( x3, y3, x3, y3, rdev->matrix, rdev->affine_matrix ); + } + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_TRIANGLE_LIST, 3, 24 ); + VTX( v, x1, y1, rdev->color ); + VTX( v, x2, y2, rdev->color ); + VTX( v, x3, y3, rdev->color ); + + return true; +} + +bool r300DrawRectangle3D( void *drv, void *dev, DFBRectangle *rect ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + float x1, y1; + float x2, y2; + u32 *v; + + x1 = rect->x; y1 = rect->y; + x2 = rect->x+rect->w; y2 = rect->y+rect->h; + if (rdev->matrix) { + float x, y; + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_LINE_LOOP, 4, 32 ); + RADEON_TRANSFORM( x1, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x2, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x2, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + RADEON_TRANSFORM( x1, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, rdev->color ); + } + else { + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_LINE_LOOP, 4, 32 ); + VTX( v, x1, y1, rdev->color ); + VTX( v, x2, y1, rdev->color ); + VTX( v, x2, y2, rdev->color ); + VTX( v, x1, y2, rdev->color ); + } + + return true; +} + +bool r300DrawLine3D( void *drv, void *dev, DFBRegion *line ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + float x1, y1; + float x2, y2; + u32 *v; + + x1 = line->x1; y1 = line->y1; + x2 = line->x2; y2 = line->y2; + if (rdev->matrix) { + RADEON_TRANSFORM( x1, y1, x1, y1, rdev->matrix, rdev->affine_matrix ); + RADEON_TRANSFORM( x2, y2, x2, y2, rdev->matrix, rdev->affine_matrix ); + } + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_LINE_LIST, 2, 16 ); + VTX( v, x1, y1, rdev->color ); + VTX( v, x2, y2, rdev->color ); + + return true; +} + +#undef VTX +#define VTX( v, x, y, s, t ) \ + *(v)++ = f2d(x); \ + *(v)++ = f2d(y); \ + *(v)++ = f2d(0); \ + *(v)++ = f2d(1); \ + *(v)++ = f2d(s); \ + *(v)++ = f2d(t); \ + *(v)++ = f2d(0); \ + *(v)++ = f2d(1) + +bool r300Blit3D( void *drv, void *dev, DFBRectangle *sr, int dx, int dy ) +{ + DFBRectangle dr = { dx, dy, sr->w, sr->h }; + + return r300StretchBlit( drv, dev, sr, &dr ); +} + +bool r300StretchBlit( void *drv, void *dev, DFBRectangle *sr, DFBRectangle *dr ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + float x1, y1; + float x2, y2; + float s1, t1; + float s2, t2; + u32 *v; + + if (rdev->blittingflags & DSBLIT_DEINTERLACE) { + sr->y /= 2; + sr->h /= 2; + } + + s1 = (float)sr->x / rdev->src_width; t1 = (float)sr->y / rdev->src_height; + s2 = (float)(sr->x+sr->w) / rdev->src_width; t2 = (float)(sr->y+sr->h) / rdev->src_height; + if (rdev->blittingflags & DSBLIT_ROTATE180) { + float tmp; + tmp = s2; s2 = s1; s1 = tmp; + tmp = t2; t2 = t1; t1 = tmp; + } + + x1 = dr->x; y1 = dr->y; + x2 = dr->x+dr->w; y2 = dr->y+dr->h; + if (rdev->matrix) { + float x, y; + + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_QUAD_LIST, 4, 32 ); + RADEON_TRANSFORM( x1, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, s1, t1 ); + RADEON_TRANSFORM( x2, y1, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, s2, t1 ); + RADEON_TRANSFORM( x2, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, s2, t2 ); + RADEON_TRANSFORM( x1, y2, x, y, rdev->matrix, rdev->affine_matrix ); + VTX( v, x, y, s1, t2 ); + } + else { + v = r300_init_vb( rdrv, rdev, VF_PRIM_TYPE_QUAD_LIST, 4, 32 ); + VTX( v, x1, y1, s1, t1 ); + VTX( v, x2, y1, s2, t1 ); + VTX( v, x2, y2, s2, t2 ); + VTX( v, x1, y2, s1, t2 ); + } + + return true; +} + +static void +r300DoTextureTriangles( RadeonDriverData *rdrv, RadeonDeviceData *rdev, + DFBVertex *ve, int num, u32 primitive ) +{ + volatile u8 *mmio = rdrv->mmio_base; + int i; + + radeon_waitfifo( rdrv, rdev, 1 ); + + radeon_out32( mmio, SE_VF_CNTL, primitive | VF_PRIM_WALK_DATA | + (num << VF_NUM_VERTICES_SHIFT) ); + + for (; num >= 8; num -= 8) { + radeon_waitfifo( rdrv, rdev, 64 ); + for (i = 0; i < 8; i++) { + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].x) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].y) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].z) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(1) ); // FIXME + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].s) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].t) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(0) ); // r + radeon_out32( mmio, SE_PORT_DATA0, f2d(1) ); // q + } + ve += 8; + } + + if (num > 0) { + radeon_waitfifo( rdrv, rdev, num*8 ); + for (i = 0; i < num; i++) { + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].x) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].y) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].z) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(1) ); // FIXME + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].s) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(ve[i].t) ); + radeon_out32( mmio, SE_PORT_DATA0, f2d(0) ); // r + radeon_out32( mmio, SE_PORT_DATA0, f2d(1) ); // q + } + } + + radeon_waitfifo( rdrv, rdev, 2 ); + radeon_out32( mmio, R300_RB3D_DSTCACHE_CTLSTAT, 0xa ); + radeon_out32( mmio, 0x4f18, 0x3 ); +} + +bool r300TextureTriangles( void *drv, void *dev, DFBVertex *ve, + int num, DFBTriangleFormation formation ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + u32 prim = 0; + int i; + + if (num > 65535) { + D_WARN( "R300 supports maximum 65535 vertices" ); + return false; + } + + switch (formation) { + case DTTF_LIST: + prim = VF_PRIM_TYPE_TRIANGLE_LIST; + break; + case DTTF_STRIP: + prim = VF_PRIM_TYPE_TRIANGLE_STRIP; + break; + case DTTF_FAN: + prim = VF_PRIM_TYPE_TRIANGLE_FAN; + break; + default: + D_BUG( "unexpected triangle formation" ); + return false; + } + + if (rdev->matrix) { + for (i = 0; i < num; i++) + RADEON_TRANSFORM( ve[i].x, ve[i].y, ve[i].x, ve[i].y, rdev->matrix, rdev->affine_matrix ); + } + + r300DoTextureTriangles( rdrv, rdev, ve, num, prim ); + + if (DFB_PLANAR_PIXELFORMAT(rdev->dst_format)) { + volatile u8 *mmio = rdrv->mmio_base; + DFBRegion clip; + int i; + + /* Scale coordinates */ + for (i = 0; i < num; i++) { + ve[i].x *= 0.5; + ve[i].y *= 0.5; + } + clip.x1 = rdev->clip.x1 >> 1; + clip.y1 = rdev->clip.y1 >> 1; + clip.x2 = rdev->clip.x2 >> 1; + clip.y2 = rdev->clip.y2 >> 1; + + /* Prepare Cb plane */ + radeon_waitfifo( rdrv, rdev, 5 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset_cb ); + radeon_out32( mmio, R300_RB3D_COLORPITCH0, (rdev->dst_pitch>>1) | + R300_COLOR_FORMAT_RGB8 ); + radeon_out32( mmio, R300_TX_SIZE_0, ((rdev->src_width/2 -1) << R300_TX_WIDTH_SHIFT) | + ((rdev->src_height/2-1) << R300_TX_HEIGHT_SHIFT) | + R300_TX_SIZE_TXPITCH_EN ); + radeon_out32( mmio, R300_TX_PITCH_0, (rdev->src_pitch>>1) - 8 ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset_cb ); + r300_set_clip3d( rdrv, rdev, &clip ); + + /* Blit Cb plane */ + r300DoTextureTriangles( rdrv, rdev, ve, num, prim ); + + /* Prepare Cr plane */ + radeon_waitfifo( rdrv, rdev, 2 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset_cr ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset_cr ); + + /* Blit Cr plane */ + r300DoTextureTriangles( rdrv, rdev, ve, num, prim ); + + /* Reset */ + radeon_waitfifo( rdrv, rdev, 5 ); + radeon_out32( mmio, R300_RB3D_COLOROFFSET0, rdev->dst_offset ); + radeon_out32( mmio, R300_RB3D_COLORPITCH0, rdev->dst_pitch | + R300_COLOR_FORMAT_RGB8 ); + radeon_out32( mmio, R300_TX_SIZE_0, ((rdev->src_width -1) << R300_TX_WIDTH_SHIFT) | + ((rdev->src_height-1) << R300_TX_HEIGHT_SHIFT) | + R300_TX_SIZE_TXPITCH_EN ); + radeon_out32( mmio, R300_TX_PITCH_0, rdev->src_pitch - 8 ); + radeon_out32( mmio, R300_TX_OFFSET_0, rdev->src_offset ); + r300_set_clip3d( rdrv, rdev, &rdev->clip ); + } + + return true; +} + +void r300EmitCommands3D( void *drv, void *dev ) +{ + RadeonDriverData *rdrv = (RadeonDriverData*) drv; + RadeonDeviceData *rdev = (RadeonDeviceData*) dev; + + if (rdev->vb_count) + r300_flush_vb( rdrv, rdev ); +} |