summaryrefslogtreecommitdiff
path: root/Source/DirectFB/gfxdrivers/radeon/r300_3d.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/gfxdrivers/radeon/r300_3d.c')
-rwxr-xr-xSource/DirectFB/gfxdrivers/radeon/r300_3d.c492
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 );
+}