2010-04-25 00:31:27 +00:00
/*
2009-02-09 21:15:56 +00:00
* Copyright ( C ) 2007 - 2009 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* This Program 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 General Public License for more details .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
2010-04-25 00:31:27 +00:00
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2009-02-09 21:15:56 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
2009-02-20 10:59:10 +00:00
// TODO: JIT Draw* (flags: depth, texture, color (+iip), scissor)
2009-02-15 02:27:51 +00:00
2011-02-19 03:36:30 +00:00
# include "stdafx.h"
2009-02-09 21:15:56 +00:00
# include "GSRasterizer.h"
2011-02-17 18:22:47 +00:00
# define THREAD_HEIGHT 5
GSRasterizer : : GSRasterizer ( IDrawScanline * ds )
2009-02-09 21:15:56 +00:00
: m_ds ( ds )
2011-03-29 14:07:48 +00:00
, m_id ( - 1 )
, m_threads ( - 1 )
2009-02-09 21:15:56 +00:00
{
2011-03-09 11:52:53 +00:00
m_edge . buff = ( GSVertexSW * ) vmalloc ( sizeof ( GSVertexSW ) * 2048 , false ) ;
2011-03-08 01:48:15 +00:00
m_edge . count = 0 ;
2011-03-29 14:07:48 +00:00
m_myscanline = ( uint8 * ) _aligned_malloc ( ( 2048 > > THREAD_HEIGHT ) + 16 , 64 ) ;
SetThreadId ( 0 , 1 ) ;
2009-02-09 21:15:56 +00:00
}
GSRasterizer : : ~ GSRasterizer ( )
{
2011-03-29 14:07:48 +00:00
_aligned_free ( m_myscanline ) ;
2011-03-09 11:52:53 +00:00
if ( m_edge . buff ! = NULL ) vmfree ( m_edge . buff , sizeof ( GSVertexSW ) * 2048 ) ;
2011-03-08 01:48:15 +00:00
2009-02-09 21:15:56 +00:00
delete m_ds ;
}
2011-02-19 09:05:15 +00:00
bool GSRasterizer : : IsOneOfMyScanlines ( int scanline ) const
2009-12-03 23:08:52 +00:00
{
2011-03-29 14:07:48 +00:00
return m_myscanline [ scanline > > THREAD_HEIGHT ] ! = 0 ;
2009-12-03 23:08:52 +00:00
}
2009-02-09 21:15:56 +00:00
void GSRasterizer : : Draw ( const GSRasterizerData * data )
{
2011-02-17 18:22:47 +00:00
m_ds - > BeginDraw ( data - > param ) ;
2009-02-09 21:15:56 +00:00
const GSVertexSW * vertices = data - > vertices ;
const int count = data - > count ;
2011-03-08 01:48:15 +00:00
m_scissor = data - > scissor ;
m_fscissor = GSVector4 ( data - > scissor ) ;
2009-02-09 21:15:56 +00:00
m_stats . Reset ( ) ;
2011-03-29 06:45:35 +00:00
uint64 start = __rdtsc ( ) ;
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
// NOTE: data->scissor_test with templated Draw* speeds up large point lists (ffxii videos), but do not seem to make any difference for others
2009-02-09 21:15:56 +00:00
switch ( data - > primclass )
{
case GS_POINT_CLASS :
m_stats . prims = count ;
2011-03-27 03:12:12 +00:00
if ( data - > scissor_test ) DrawPoint < true > ( vertices , count ) ;
else DrawPoint < false > ( vertices , count ) ;
2009-02-09 21:15:56 +00:00
break ;
case GS_LINE_CLASS :
ASSERT ( ! ( count & 1 ) ) ;
m_stats . prims = count / 2 ;
2011-03-08 01:48:15 +00:00
for ( int i = 0 ; i < count ; i + = 2 ) DrawLine ( & vertices [ i ] ) ;
2009-02-09 21:15:56 +00:00
break ;
case GS_TRIANGLE_CLASS :
ASSERT ( ! ( count % 3 ) ) ;
m_stats . prims = count / 3 ;
2011-03-08 01:48:15 +00:00
for ( int i = 0 ; i < count ; i + = 3 ) DrawTriangle ( & vertices [ i ] ) ;
2009-02-09 21:15:56 +00:00
break ;
case GS_SPRITE_CLASS :
ASSERT ( ! ( count & 1 ) ) ;
m_stats . prims = count / 2 ;
2011-03-08 01:48:15 +00:00
for ( int i = 0 ; i < count ; i + = 2 ) DrawSprite ( & vertices [ i ] ) ;
2009-02-09 21:15:56 +00:00
break ;
default :
__assume ( 0 ) ;
}
m_stats . ticks = __rdtsc ( ) - start ;
2011-02-17 03:24:37 +00:00
m_ds - > EndDraw ( m_stats , data - > frame ) ;
2009-02-09 21:15:56 +00:00
}
2011-03-29 14:07:48 +00:00
void GSRasterizer : : SetThreadId ( int id , int threads )
{
if ( m_id ! = id | | m_threads ! = threads )
{
m_id = id ;
m_threads = threads ;
if ( threads > 1 )
{
int row = 0 ;
while ( row < ( 2048 > > THREAD_HEIGHT ) )
{
for ( int i = 0 ; i < threads ; i + + , row + + )
{
m_myscanline [ row ] = i = = id ? 1 : 0 ;
}
}
}
else
{
memset ( m_myscanline , 1 , 2048 > > THREAD_HEIGHT ) ;
}
}
}
2009-02-09 21:15:56 +00:00
void GSRasterizer : : GetStats ( GSRasterizerStats & stats )
{
stats = m_stats ;
}
2011-03-27 03:12:12 +00:00
template < bool scissor_test >
void GSRasterizer : : DrawPoint ( const GSVertexSW * v , int count )
2009-02-09 21:15:56 +00:00
{
2011-03-27 03:12:12 +00:00
for ( ; count > 0 ; count - - , v + + )
2009-02-09 21:15:56 +00:00
{
2011-03-27 03:12:12 +00:00
GSVector4i p ( v - > p ) ;
if ( ! scissor_test | | m_scissor . left < = p . x & & p . x < m_scissor . right & & m_scissor . top < = p . y & & p . y < m_scissor . bottom )
2009-02-09 21:15:56 +00:00
{
2011-03-27 03:12:12 +00:00
if ( IsOneOfMyScanlines ( p . y ) )
{
m_stats . pixels + + ;
2011-03-08 01:48:15 +00:00
2011-03-27 03:12:12 +00:00
m_ds - > SetupPrim ( v , * v ) ;
2009-02-09 21:15:56 +00:00
2011-03-27 03:12:12 +00:00
m_ds - > DrawScanline ( 1 , p . x , p . y , * v ) ;
}
2009-02-09 21:15:56 +00:00
}
}
}
2011-03-08 01:48:15 +00:00
void GSRasterizer : : DrawLine ( const GSVertexSW * v )
2009-02-09 21:15:56 +00:00
{
GSVertexSW dv = v [ 1 ] - v [ 0 ] ;
GSVector4 dp = dv . p . abs ( ) ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
int i = ( dp < dp . yxwz ( ) ) . mask ( ) & 1 ; // |dx| <= |dy|
2011-02-16 03:19:36 +00:00
if ( m_ds - > IsEdge ( ) )
2009-03-09 01:42:56 +00:00
{
2011-03-08 01:48:15 +00:00
DrawEdge ( v [ 0 ] , v [ 1 ] , dv , i , 0 ) ;
DrawEdge ( v [ 0 ] , v [ 1 ] , dv , i , 1 ) ;
2011-03-12 22:10:58 +00:00
Flush ( v , GSVertexSW : : zero ( ) , true ) ;
2009-03-09 01:42:56 +00:00
return ;
}
2009-02-09 21:15:56 +00:00
GSVector4i dpi ( dp ) ;
if ( dpi . y = = 0 )
{
if ( dpi . x > 0 )
{
// shortcut for horizontal lines
GSVector4 mask = ( v [ 0 ] . p > v [ 1 ] . p ) . xxxx ( ) ;
GSVertexSW l , dl ;
2011-03-12 22:10:58 +00:00
l . p = v [ 0 ] . p . blend32 ( v [ 1 ] . p , mask ) ;
l . t = v [ 0 ] . t . blend32 ( v [ 1 ] . t , mask ) ;
l . c = v [ 0 ] . c . blend32 ( v [ 1 ] . c , mask ) ;
2009-02-09 21:15:56 +00:00
GSVector4 r ;
2011-03-12 22:10:58 +00:00
r = v [ 1 ] . p . blend32 ( v [ 0 ] . p , mask ) ;
2009-02-09 21:15:56 +00:00
GSVector4i p ( l . p ) ;
2011-03-08 01:48:15 +00:00
if ( m_scissor . top < = p . y & & p . y < m_scissor . bottom )
2009-02-09 21:15:56 +00:00
{
GSVertexSW dscan = dv / dv . p . xxxx ( ) ;
2011-12-03 21:04:46 +00:00
GSVector4 x0 = l . p . xxxx ( ) ;
GSVector4 y0 = l . p . yyyy ( ) ;
2009-02-09 21:15:56 +00:00
l . p = l . p . upl ( r ) . xyzw ( l . p ) ; // r.x => l.y
2011-12-03 21:04:46 +00:00
DrawTriangleSection ( p . y , p . y + 1 , l , dl , dscan , x0 , y0 ) ;
2009-02-24 20:12:46 +00:00
2011-03-09 11:52:53 +00:00
Flush ( v , dscan ) ;
2009-02-09 21:15:56 +00:00
}
}
return ;
}
2011-03-09 11:52:53 +00:00
int steps = dpi . v [ i ] ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
if ( steps > 0 )
{
GSVertexSW edge = v [ 0 ] ;
GSVertexSW dedge = dv / GSVector4 ( dp . v [ i ] ) ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
GSVertexSW * RESTRICT e = m_edge . buff ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
while ( 1 )
{
GSVector4i p ( edge . p ) ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
if ( m_scissor . left < = p . x & & p . x < m_scissor . right & & m_scissor . top < = p . y & & p . y < m_scissor . bottom )
{
if ( IsOneOfMyScanlines ( p . y ) )
{
2011-03-27 03:12:12 +00:00
AddScanline ( e , 1 , p . x , p . y , edge ) ;
2011-03-09 11:52:53 +00:00
e + + ;
}
}
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
if ( - - steps = = 0 ) break ;
edge + = dedge ;
}
m_edge . count = e - m_edge . buff ;
m_stats . pixels + = m_edge . count ;
2011-03-12 22:10:58 +00:00
Flush ( v , GSVertexSW : : zero ( ) ) ;
2009-02-09 21:15:56 +00:00
}
}
2011-03-29 06:45:35 +00:00
static const uint8 s_ysort [ 8 ] [ 4 ] =
2009-02-09 21:15:56 +00:00
{
2011-03-29 06:45:35 +00:00
{ 0 , 1 , 2 , 0 } , // y0 <= y1 <= y2
{ 1 , 0 , 2 , 0 } , // y1 < y0 <= y2
2009-02-09 21:15:56 +00:00
{ 0 , 0 , 0 , 0 } ,
2011-03-29 06:45:35 +00:00
{ 1 , 2 , 0 , 0 } , // y1 <= y2 < y0
{ 0 , 2 , 1 , 0 } , // y0 <= y2 < y1
2009-02-09 21:15:56 +00:00
{ 0 , 0 , 0 , 0 } ,
2011-03-29 06:45:35 +00:00
{ 2 , 0 , 1 , 0 } , // y2 < y0 <= y1
{ 2 , 1 , 0 , 0 } , // y2 < y1 < y0
2009-02-09 21:15:56 +00:00
} ;
2011-03-08 01:48:15 +00:00
void GSRasterizer : : DrawTriangle ( const GSVertexSW * vertices )
2009-02-09 21:15:56 +00:00
{
2011-03-27 15:46:32 +00:00
GSVertexSW v [ 3 ] ;
2011-03-08 01:48:15 +00:00
GSVertexSW dv [ 3 ] ;
2011-03-27 15:46:32 +00:00
GSVertexSW edge ;
GSVertexSW dedge ;
2011-03-08 01:48:15 +00:00
GSVertexSW dscan ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 y0011 = vertices [ 0 ] . p . yyyy ( vertices [ 1 ] . p ) ;
GSVector4 y1221 = vertices [ 1 ] . p . yyyy ( vertices [ 2 ] . p ) . xzzx ( ) ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
int mask = ( y0011 > y1221 ) . mask ( ) & 7 ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
v [ 0 ] = vertices [ s_ysort [ mask ] [ 0 ] ] ;
v [ 1 ] = vertices [ s_ysort [ mask ] [ 1 ] ] ;
v [ 2 ] = vertices [ s_ysort [ mask ] [ 2 ] ] ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
y0011 = v [ 0 ] . p . yyyy ( v [ 1 ] . p ) ;
y1221 = v [ 1 ] . p . yyyy ( v [ 2 ] . p ) . xzzx ( ) ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
int i = ( y0011 = = y1221 ) . mask ( ) & 7 ;
2009-02-09 21:15:56 +00:00
2011-11-25 23:48:59 +00:00
// if(i == 0) => y0 < y1 < y2
// if(i == 1) => y0 == y1 < y2
// if(i == 4) => y0 < y1 == y2
2011-03-29 06:45:35 +00:00
if ( i = = 7 ) return ; // y0 == y1 == y2
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 tbf = y0011 . xzxz ( y1221 ) . ceil ( ) ;
2011-03-12 22:10:58 +00:00
GSVector4 tbmax = tbf . max ( m_fscissor . ywyw ( ) ) ;
GSVector4 tbmin = tbf . min ( m_fscissor . ywyw ( ) ) ;
2011-03-08 01:48:15 +00:00
GSVector4i tb = GSVector4i ( tbmax . xzyw ( tbmin ) ) ;
dv [ 0 ] = v [ 1 ] - v [ 0 ] ;
dv [ 1 ] = v [ 2 ] - v [ 0 ] ;
dv [ 2 ] = v [ 2 ] - v [ 1 ] ;
2009-03-09 01:42:56 +00:00
2011-03-27 15:46:32 +00:00
GSVector4 cross = dv [ 0 ] . p * dv [ 1 ] . p . yxwz ( ) ;
cross = ( cross - cross . yxwz ( ) ) . yyyy ( ) ; // select the second component, the negated cross product
// the longest horizontal span would be cross.x / dv[1].p.y, but we don't need its actual value
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
int j = cross . upl ( cross = = GSVector4 : : zero ( ) ) . mask ( ) ;
2009-02-09 21:15:56 +00:00
2011-03-08 01:48:15 +00:00
if ( j & 2 ) return ;
2009-02-09 21:15:56 +00:00
2011-03-08 01:48:15 +00:00
j & = 1 ;
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
cross = cross . rcpnr ( ) ;
2011-03-29 06:45:35 +00:00
GSVector4 dxy01 = dv [ 0 ] . p . xyxy ( dv [ 1 ] . p ) ;
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 dx = dxy01 . xzxy ( dv [ 2 ] . p ) ;
GSVector4 dy = dxy01 . ywyx ( dv [ 2 ] . p ) ;
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 ddx [ 3 ] ;
2011-03-08 01:48:15 +00:00
2011-03-29 06:45:35 +00:00
ddx [ 0 ] = dx / dy ;
ddx [ 1 ] = ddx [ 0 ] . yxzw ( ) ;
ddx [ 2 ] = ddx [ 0 ] . xzyw ( ) ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 dxy01c = dxy01 * cross ;
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 _z = dxy01c * dv [ 1 ] . p . zzzz ( dv [ 0 ] . p ) ; // dx0 * z1, dy0 * z1, dx1 * z0, dy1 * z0
GSVector4 _f = dxy01c * dv [ 1 ] . p . wwww ( dv [ 0 ] . p ) ; // dx0 * f1, dy0 * f1, dx1 * f0, dy1 * f0
2009-02-09 21:15:56 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 _zf = _z . ywyw ( _f ) . hsub ( _z . zxzx ( _f ) ) ; // dy0 * z1 - dy1 * z0, dy0 * f1 - dy1 * f0, dx1 * z0 - dx0 * z1, dx1 * f0 - dx0 * f1
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
dscan . p = _zf . zwxy ( ) ; // dy0 * z1 - dy1 * z0, dy0 * f1 - dy1 * f0
dedge . p = _zf ; // dx1 * z0 - dx0 * z1, dx1 * f0 - dx0 * f1
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
GSVector4 _s = dxy01c * dv [ 1 ] . t . xxxx ( dv [ 0 ] . t ) ; // dx0 * s1, dy0 * s1, dx1 * s0, dy1 * s0
GSVector4 _t = dxy01c * dv [ 1 ] . t . yyyy ( dv [ 0 ] . t ) ; // dx0 * t1, dy0 * t1, dx1 * t0, dy1 * t0
GSVector4 _q = dxy01c * dv [ 1 ] . t . zzzz ( dv [ 0 ] . t ) ; // dx0 * q1, dy0 * q1, dx1 * q0, dy1 * q0
2011-03-27 15:46:32 +00:00
2011-03-29 06:45:35 +00:00
dscan . t = _s . ywyw ( _t ) . hsub ( _q . ywyw ( ) ) ; // dy0 * s1 - dy1 * s0, dy0 * t1 - dy1 * t0, dy0 * q1 - dy1 * q0
dedge . t = _s . zxzx ( _t ) . hsub ( _q . zxzx ( ) ) ; // dx1 * s0 - dx0 * s1, dx1 * t0 - dx0 * t1, dx1 * q0 - dx0 * q1
GSVector4 _r = dxy01c * dv [ 1 ] . c . xxxx ( dv [ 0 ] . c ) ; // dx0 * r1, dy0 * r1, dx1 * r0, dy1 * r0
GSVector4 _g = dxy01c * dv [ 1 ] . c . yyyy ( dv [ 0 ] . c ) ; // dx0 * g1, dy0 * g1, dx1 * g0, dy1 * g0
GSVector4 _b = dxy01c * dv [ 1 ] . c . zzzz ( dv [ 0 ] . c ) ; // dx0 * b1, dy0 * b1, dx1 * b0, dy1 * b0
GSVector4 _a = dxy01c * dv [ 1 ] . c . wwww ( dv [ 0 ] . c ) ; // dx0 * a1, dy0 * a1, dx1 * a0, dy1 * a0
dscan . c = _r . ywyw ( _g ) . hsub ( _b . ywyw ( _a ) ) ; // dy0 * r1 - dy1 * r0, dy0 * g1 - dy1 * g0, dy0 * b1 - dy1 * b0, dy0 * a1 - dy1 * a0
dedge . c = _r . zxzx ( _g ) . hsub ( _b . zxzx ( _a ) ) ; // dx1 * r0 - dx0 * r1, dx1 * g0 - dx0 * g1, dx1 * b0 - dx0 * b1, dx1 * a0 - dx0 * a1
2011-03-27 15:46:32 +00:00
2011-11-25 23:48:59 +00:00
if ( i & 1 )
2011-03-08 01:48:15 +00:00
{
2011-11-25 23:48:59 +00:00
if ( tb . y < tb . w )
{
edge = v [ 1 - j ] ;
edge . p = edge . p . insert < 0 , 1 > ( v [ j ] . p ) ;
dedge . p = ddx [ 2 - ( j < < 1 ) ] . yzzw ( dedge . p ) ;
2011-03-27 15:46:32 +00:00
2011-12-03 21:04:46 +00:00
DrawTriangleSection ( tb . x , tb . w , edge , dedge , dscan , v [ 1 - j ] . p . xxxx ( ) , v [ 1 - j ] . p . yyyy ( ) ) ;
2011-11-25 23:48:59 +00:00
}
}
else
{
GSVector4 x0 = v [ 0 ] . p . xxxx ( ) ;
2011-03-27 15:46:32 +00:00
2011-03-08 01:48:15 +00:00
if ( tb . x < tb . z )
{
2011-03-27 15:46:32 +00:00
edge = v [ 0 ] ;
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
edge . p = edge . p . xxzw ( ) ;
dedge . p = ddx [ j ] . xyzw ( dedge . p ) ;
2009-02-09 21:15:56 +00:00
2011-12-03 21:04:46 +00:00
DrawTriangleSection ( tb . x , tb . z , edge , dedge , dscan , x0 , v [ 0 ] . p . yyyy ( ) ) ;
2011-03-08 01:48:15 +00:00
}
2009-02-09 21:15:56 +00:00
2011-03-08 01:48:15 +00:00
if ( tb . y < tb . w )
{
2011-03-27 15:46:32 +00:00
edge = v [ 1 ] ;
2011-03-12 22:10:58 +00:00
2011-03-27 15:46:32 +00:00
edge . p = ( x0 + ddx [ j ] * dv [ 0 ] . p . yyyy ( ) ) . xyzw ( edge . p ) ;
dedge . p = ddx [ 2 - ( j < < 1 ) ] . yzzw ( dedge . p ) ;
2009-02-09 21:15:56 +00:00
2011-12-03 21:04:46 +00:00
DrawTriangleSection ( tb . y , tb . w , edge , dedge , dscan , v [ 1 ] . p . xxxx ( ) , v [ 1 ] . p . yyyy ( ) ) ;
2011-03-08 01:48:15 +00:00
}
2011-03-27 15:46:32 +00:00
}
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
Flush ( v , dscan ) ;
2009-02-19 13:13:20 +00:00
2011-03-27 15:46:32 +00:00
if ( m_ds - > IsEdge ( ) )
{
GSVector4 a = dx . abs ( ) < dy . abs ( ) ; // |dx| <= |dy|
GSVector4 b = dx < GSVector4 : : zero ( ) ; // dx < 0
GSVector4 c = cross < GSVector4 : : zero ( ) ; // longest.p.x < 0
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
int i = a . mask ( ) ;
int j = ( ( a | b ) ^ c ) . mask ( ) ^ 2 ; // evil
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
DrawEdge ( v [ 0 ] , v [ 1 ] , dv [ 0 ] , i & 1 , j & 1 ) ;
DrawEdge ( v [ 0 ] , v [ 2 ] , dv [ 1 ] , i & 2 , j & 2 ) ;
DrawEdge ( v [ 1 ] , v [ 2 ] , dv [ 2 ] , i & 4 , j & 4 ) ;
2009-02-09 21:15:56 +00:00
2011-03-27 15:46:32 +00:00
Flush ( v , GSVertexSW : : zero ( ) , true ) ;
2009-02-09 21:15:56 +00:00
}
}
2011-12-03 21:04:46 +00:00
void GSRasterizer : : DrawTriangleSection ( int top , int bottom , GSVertexSW & edge , const GSVertexSW & dedge , const GSVertexSW & dscan , const GSVector4 & x0 , const GSVector4 & y0 )
2009-02-09 21:15:56 +00:00
{
ASSERT ( top < bottom ) ;
2011-03-27 15:46:32 +00:00
ASSERT ( edge . p . x < = edge . p . y ) ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
GSVertexSW * RESTRICT e = & m_edge . buff [ m_edge . count ] ;
2011-03-08 01:48:15 +00:00
2011-03-27 03:12:12 +00:00
GSVector4 scissor = m_fscissor . xzxz ( ) ;
2011-12-03 21:04:46 +00:00
GSVector4 prestep = GSVector4 ( top ) - y0 ;
GSVertexSW o = dedge * prestep ;
2009-02-09 21:15:56 +00:00
while ( 1 )
{
2011-03-09 11:52:53 +00:00
if ( IsOneOfMyScanlines ( top ) )
2009-02-09 21:15:56 +00:00
{
2011-12-03 21:04:46 +00:00
GSVertexSW scan = edge + o ;
GSVector4 lrf = scan . p . ceil ( ) ;
2011-03-27 15:46:32 +00:00
GSVector4 l = lrf . max ( scissor ) ;
GSVector4 r = lrf . min ( scissor ) ;
GSVector4i lr = GSVector4i ( l . xxyy ( r ) ) ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
int left = lr . extract32 < 0 > ( ) ;
int right = lr . extract32 < 2 > ( ) ;
2009-02-19 13:13:20 +00:00
2011-03-09 11:52:53 +00:00
int pixels = right - left ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
if ( pixels > 0 )
{
m_stats . pixels + = pixels ;
2009-02-09 21:15:56 +00:00
2011-12-03 21:04:46 +00:00
prestep = l . xxxx ( ) - x0 ;
2009-02-09 21:15:56 +00:00
2011-12-03 21:04:46 +00:00
AddScanline ( e + + , pixels , left , top , scan + dscan * prestep ) ;
2009-02-09 21:15:56 +00:00
}
}
if ( + + top > = bottom ) break ;
2011-12-03 21:04:46 +00:00
// NOTE: it is more accurate to accumlate the offset, edge values (especially p.z) may become too large compared to dedge (example: 8000000 + 259.4 == 8000000 + 259.3)
o + = dedge ;
2009-02-09 21:15:56 +00:00
}
2011-03-08 01:48:15 +00:00
m_edge . count + = e - & m_edge . buff [ m_edge . count ] ;
2009-02-09 21:15:56 +00:00
}
2011-03-08 01:48:15 +00:00
void GSRasterizer : : DrawSprite ( const GSVertexSW * vertices )
2009-02-09 21:15:56 +00:00
{
GSVertexSW v [ 2 ] ;
GSVector4 mask = ( vertices [ 0 ] . p < vertices [ 1 ] . p ) . xyzw ( GSVector4 : : zero ( ) ) ;
2011-03-12 22:10:58 +00:00
v [ 0 ] . p = vertices [ 1 ] . p . blend32 ( vertices [ 0 ] . p , mask ) ;
v [ 0 ] . t = vertices [ 1 ] . t . blend32 ( vertices [ 0 ] . t , mask ) ;
2009-02-09 21:15:56 +00:00
v [ 0 ] . c = vertices [ 1 ] . c ;
2011-03-12 22:10:58 +00:00
v [ 1 ] . p = vertices [ 0 ] . p . blend32 ( vertices [ 1 ] . p , mask ) ;
v [ 1 ] . t = vertices [ 0 ] . t . blend32 ( vertices [ 1 ] . t , mask ) ;
2009-02-09 21:15:56 +00:00
GSVector4i r ( v [ 0 ] . p . xyxy ( v [ 1 ] . p ) . ceil ( ) ) ;
2011-03-08 01:48:15 +00:00
r = r . rintersect ( m_scissor ) ;
2010-04-25 00:31:27 +00:00
2009-05-14 16:41:52 +00:00
if ( r . rempty ( ) ) return ;
2009-02-09 21:15:56 +00:00
GSVertexSW scan = v [ 0 ] ;
2011-02-16 03:19:36 +00:00
if ( m_ds - > IsRect ( ) )
2009-02-09 21:15:56 +00:00
{
if ( m_id = = 0 )
{
2011-02-16 03:19:36 +00:00
m_ds - > DrawRect ( r , scan ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
m_stats . pixels + = r . width ( ) * r . height ( ) ;
2009-02-09 21:15:56 +00:00
}
return ;
}
GSVertexSW dv = v [ 1 ] - v [ 0 ] ;
2011-04-25 01:44:00 +00:00
GSVector4 dt = dv . t / dv . p . xyxy ( ) ;
GSVertexSW dedge ;
GSVertexSW dscan ;
2011-03-12 22:10:58 +00:00
2011-04-25 01:44:00 +00:00
dedge . t = GSVector4 : : zero ( ) . insert < 1 , 1 > ( dt ) ;
dscan . t = GSVector4 : : zero ( ) . insert < 0 , 0 > ( dt ) ;
2009-02-09 21:15:56 +00:00
2011-03-27 03:12:12 +00:00
GSVector4 prestep = GSVector4 ( r . left , r . top ) - scan . p ;
int m = ( prestep = = GSVector4 : : zero ( ) ) . mask ( ) ;
if ( ( m & 2 ) = = 0 ) scan . t + = dedge . t * prestep . yyyy ( ) ;
if ( ( m & 1 ) = = 0 ) scan . t + = dscan . t * prestep . xxxx ( ) ;
2009-02-09 21:15:56 +00:00
2011-02-16 03:19:36 +00:00
m_ds - > SetupPrim ( v , dscan ) ;
2009-02-09 21:15:56 +00:00
2011-03-09 11:52:53 +00:00
while ( 1 )
2009-02-09 21:15:56 +00:00
{
2010-04-25 00:31:27 +00:00
if ( IsOneOfMyScanlines ( r . top ) )
2009-02-09 21:15:56 +00:00
{
2009-05-14 16:41:52 +00:00
m_stats . pixels + = r . width ( ) ;
2011-03-08 01:48:15 +00:00
2011-03-12 22:10:58 +00:00
m_ds - > DrawScanline ( r . width ( ) , r . left , r . top , scan ) ;
2009-02-09 21:15:56 +00:00
}
2011-03-09 11:52:53 +00:00
if ( + + r . top > = r . bottom ) break ;
scan . t + = dedge . t ;
2009-02-09 21:15:56 +00:00
}
}
2011-03-08 01:48:15 +00:00
void GSRasterizer : : DrawEdge ( const GSVertexSW & v0 , const GSVertexSW & v1 , const GSVertexSW & dv , int orientation , int side )
2009-03-09 01:42:56 +00:00
{
2010-04-25 00:31:27 +00:00
// orientation:
2009-03-09 01:42:56 +00:00
// - true: |dv.p.y| > |dv.p.x|
2010-04-25 00:31:27 +00:00
// - false |dv.p.x| > |dv.p.y|
// side:
2009-03-09 01:42:56 +00:00
// - true: top/left edge
// - false: bottom/right edge
// TODO: bit slow and too much duplicated code
// TODO: inner pre-step is still missing (hardly noticable)
2011-03-27 15:46:32 +00:00
// TODO: it does not always line up with the edge of the surrounded triangle
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
GSVertexSW * RESTRICT e = & m_edge . buff [ m_edge . count ] ;
2011-03-08 01:48:15 +00:00
2009-03-09 01:42:56 +00:00
GSVector4 lrtb = v0 . p . upl ( v1 . p ) . ceil ( ) ;
if ( orientation )
{
2011-03-08 01:48:15 +00:00
GSVector4 tbmax = lrtb . max ( m_fscissor . yyyy ( ) ) ;
GSVector4 tbmin = lrtb . min ( m_fscissor . wwww ( ) ) ;
2011-03-09 11:52:53 +00:00
GSVector4i tb = GSVector4i ( tbmax . zwzw ( tbmin ) ) ;
2009-03-09 01:42:56 +00:00
int top , bottom ;
GSVertexSW edge , dedge ;
if ( ( dv . p > = GSVector4 : : zero ( ) ) . mask ( ) & 2 )
{
2011-03-09 11:52:53 +00:00
top = tb . extract32 < 0 > ( ) ;
bottom = tb . extract32 < 3 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( top > = bottom ) return ;
edge = v0 ;
dedge = dv / dv . p . yyyy ( ) ;
edge + = dedge * ( tbmax . zzzz ( ) - edge . p . yyyy ( ) ) ;
}
else
{
2011-03-09 11:52:53 +00:00
top = tb . extract32 < 1 > ( ) ;
bottom = tb . extract32 < 2 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( top > = bottom ) return ;
edge = v1 ;
dedge = dv / dv . p . yyyy ( ) ;
edge + = dedge * ( tbmax . wwww ( ) - edge . p . yyyy ( ) ) ;
}
2009-03-16 22:17:50 +00:00
GSVector4i p = GSVector4i ( edge . p . upl ( dedge . p ) * 0x10000 ) ;
int x = p . extract32 < 0 > ( ) ;
int dx = p . extract32 < 1 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( side )
{
while ( 1 )
{
2011-03-09 11:52:53 +00:00
int xi = x > > 16 ;
int xf = x & 0xffff ;
2011-03-27 15:46:32 +00:00
if ( m_scissor . left < = xi & & xi < m_scissor . right & & IsOneOfMyScanlines ( top ) )
2009-03-09 01:42:56 +00:00
{
2011-03-27 03:12:12 +00:00
AddScanline ( e , 1 , xi , top , edge ) ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e - > t . u32 [ 3 ] = ( 0x10000 - xf ) & 0xffff ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e + + ;
2009-03-09 01:42:56 +00:00
}
if ( + + top > = bottom ) break ;
edge + = dedge ;
2009-03-16 22:17:50 +00:00
x + = dx ;
2009-03-09 01:42:56 +00:00
}
}
else
{
while ( 1 )
{
2011-03-09 11:52:53 +00:00
int xi = ( x > > 16 ) + 1 ;
int xf = x & 0xffff ;
2011-03-27 15:46:32 +00:00
if ( m_scissor . left < = xi & & xi < m_scissor . right & & IsOneOfMyScanlines ( top ) )
2009-03-09 01:42:56 +00:00
{
2011-03-27 03:12:12 +00:00
AddScanline ( e , 1 , xi , top , edge ) ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e - > t . u32 [ 3 ] = xf ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e + + ;
2009-03-09 01:42:56 +00:00
}
if ( + + top > = bottom ) break ;
edge + = dedge ;
2009-03-16 22:17:50 +00:00
x + = dx ;
2009-03-09 01:42:56 +00:00
}
}
}
else
{
2011-03-08 01:48:15 +00:00
GSVector4 lrmax = lrtb . max ( m_fscissor . xxxx ( ) ) ;
GSVector4 lrmin = lrtb . min ( m_fscissor . zzzz ( ) ) ;
2011-03-09 11:52:53 +00:00
GSVector4i lr = GSVector4i ( lrmax . xyxy ( lrmin ) ) ;
2009-03-09 01:42:56 +00:00
int left , right ;
GSVertexSW edge , dedge ;
if ( ( dv . p > = GSVector4 : : zero ( ) ) . mask ( ) & 1 )
{
2011-03-09 11:52:53 +00:00
left = lr . extract32 < 0 > ( ) ;
right = lr . extract32 < 3 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( left > = right ) return ;
edge = v0 ;
dedge = dv / dv . p . xxxx ( ) ;
edge + = dedge * ( lrmax . xxxx ( ) - edge . p . xxxx ( ) ) ;
}
else
{
2011-03-09 11:52:53 +00:00
left = lr . extract32 < 1 > ( ) ;
right = lr . extract32 < 2 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( left > = right ) return ;
edge = v1 ;
dedge = dv / dv . p . xxxx ( ) ;
edge + = dedge * ( lrmax . yyyy ( ) - edge . p . xxxx ( ) ) ;
}
2009-03-16 22:17:50 +00:00
GSVector4i p = GSVector4i ( edge . p . upl ( dedge . p ) * 0x10000 ) ;
int y = p . extract32 < 2 > ( ) ;
int dy = p . extract32 < 3 > ( ) ;
2009-03-09 01:42:56 +00:00
if ( side )
{
while ( 1 )
{
2011-03-09 11:52:53 +00:00
int yi = y > > 16 ;
int yf = y & 0xffff ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
if ( m_scissor . top < = yi & & yi < m_scissor . bottom & & IsOneOfMyScanlines ( yi ) )
{
2011-03-27 03:12:12 +00:00
AddScanline ( e , 1 , left , yi , edge ) ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e - > t . u32 [ 3 ] = ( 0x10000 - yf ) & 0xffff ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e + + ;
2009-03-09 01:42:56 +00:00
}
if ( + + left > = right ) break ;
edge + = dedge ;
2009-03-16 22:17:50 +00:00
y + = dy ;
2009-03-09 01:42:56 +00:00
}
}
else
{
while ( 1 )
{
2011-03-09 11:52:53 +00:00
int yi = ( y > > 16 ) + 1 ;
int yf = y & 0xffff ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
if ( m_scissor . top < = yi & & yi < m_scissor . bottom & & IsOneOfMyScanlines ( yi ) )
{
2011-03-27 03:12:12 +00:00
AddScanline ( e , 1 , left , yi , edge ) ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e - > t . u32 [ 3 ] = yf ;
2009-03-09 01:42:56 +00:00
2011-03-09 11:52:53 +00:00
e + + ;
2009-03-09 01:42:56 +00:00
}
if ( + + left > = right ) break ;
edge + = dedge ;
2009-03-16 22:17:50 +00:00
y + = dy ;
2009-03-09 01:42:56 +00:00
}
}
}
2011-03-08 01:48:15 +00:00
2011-03-27 03:12:12 +00:00
int count = e - & m_edge . buff [ m_edge . count ] ;
m_stats . pixels + = count ;
m_edge . count + = count ;
}
void GSRasterizer : : AddScanline ( GSVertexSW * e , int pixels , int left , int top , const GSVertexSW & scan )
{
* e = scan ;
e - > p . i16 [ 0 ] = ( int16 ) pixels ;
e - > p . i16 [ 1 ] = ( int16 ) left ;
e - > p . i16 [ 2 ] = ( int16 ) top ;
2011-03-08 01:48:15 +00:00
}
2011-03-09 11:52:53 +00:00
void GSRasterizer : : Flush ( const GSVertexSW * vertices , const GSVertexSW & dscan , bool edge )
2011-03-08 01:48:15 +00:00
{
// TODO: on win64 this could be the place where xmm6-15 are preserved (not by each DrawScanline)
2011-03-09 11:52:53 +00:00
int count = m_edge . count ;
2011-03-08 01:48:15 +00:00
2011-03-09 11:52:53 +00:00
if ( count > 0 )
2011-03-08 01:48:15 +00:00
{
2011-03-09 11:52:53 +00:00
m_ds - > SetupPrim ( vertices , dscan ) ;
2011-03-08 01:48:15 +00:00
2011-03-09 11:52:53 +00:00
const GSVertexSW * RESTRICT e = m_edge . buff ;
2011-03-27 03:12:12 +00:00
const GSVertexSW * RESTRICT ee = e + count ;
2011-03-08 01:48:15 +00:00
2011-03-09 11:52:53 +00:00
if ( ! edge )
{
2011-03-27 03:12:12 +00:00
do
{
int pixels = e - > p . i16 [ 0 ] ;
int left = e - > p . i16 [ 1 ] ;
int top = e - > p . i16 [ 2 ] ;
m_ds - > DrawScanline ( pixels , left , top , * e + + ) ;
}
while ( e < ee ) ;
2011-03-09 11:52:53 +00:00
}
else
{
2011-03-27 03:12:12 +00:00
do
{
int pixels = e - > p . i16 [ 0 ] ;
int left = e - > p . i16 [ 1 ] ;
int top = e - > p . i16 [ 2 ] ;
m_ds - > DrawEdge ( pixels , left , top , * e + + ) ;
}
while ( e < ee ) ;
2011-03-09 11:52:53 +00:00
}
2011-03-08 01:48:15 +00:00
2011-03-09 11:52:53 +00:00
m_edge . count = 0 ;
}
2009-03-09 01:42:56 +00:00
}
2009-02-09 21:15:56 +00:00
//
2011-02-19 03:36:30 +00:00
GSRasterizerMT : : GSRasterizerMT ( IDrawScanline * ds , volatile long & sync )
2011-02-17 18:22:47 +00:00
: GSRasterizer ( ds )
2009-02-09 21:15:56 +00:00
, m_sync ( sync )
, m_data ( NULL )
{
2009-12-03 23:08:52 +00:00
CreateThread ( ) ;
2009-02-09 21:15:56 +00:00
}
2009-06-16 01:42:08 +00:00
GSRasterizerMT : : ~ GSRasterizerMT ( )
2009-02-09 21:15:56 +00:00
{
2011-04-01 12:36:21 +00:00
Draw ( NULL ) ;
2010-04-25 00:31:27 +00:00
2011-02-12 21:45:16 +00:00
CloseThread ( ) ;
2009-02-09 21:15:56 +00:00
}
void GSRasterizerMT : : Draw ( const GSRasterizerData * data )
{
2009-12-03 23:08:52 +00:00
m_data = data ;
2011-02-12 21:45:16 +00:00
2011-02-19 03:36:30 +00:00
m_draw . Set ( ) ;
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
void GSRasterizerMT : : ThreadProc ( )
2009-02-09 21:15:56 +00:00
{
2011-02-19 03:36:30 +00:00
while ( m_draw . Wait ( ) & & m_data ! = NULL )
2009-02-09 21:15:56 +00:00
{
2011-02-19 03:36:30 +00:00
GSRasterizer : : Draw ( m_data ) ;
2011-02-12 21:45:16 +00:00
2011-02-19 03:36:30 +00:00
_interlockedbittestandreset ( & m_sync , m_id ) ;
2009-02-09 21:15:56 +00:00
}
}
//
GSRasterizerList : : GSRasterizerList ( )
2011-02-17 03:24:37 +00:00
: m_sync ( 0 )
2009-02-09 21:15:56 +00:00
{
}
GSRasterizerList : : ~ GSRasterizerList ( )
{
2011-02-12 21:45:16 +00:00
for ( size_t i = 0 ; i < size ( ) ; i + + ) delete ( * this ) [ i ] ;
2009-02-09 21:15:56 +00:00
}
2011-02-16 03:19:36 +00:00
void GSRasterizerList : : Sync ( )
2009-02-09 21:15:56 +00:00
{
2011-02-07 01:59:05 +00:00
while ( m_sync ) _mm_pause ( ) ;
2011-02-16 03:19:36 +00:00
m_stats . ticks = __rdtsc ( ) - m_start ;
2009-02-09 21:15:56 +00:00
2011-02-17 18:22:47 +00:00
for ( int i = 0 ; i < m_threads ; i + + )
2009-02-09 21:15:56 +00:00
{
GSRasterizerStats s ;
2009-12-03 23:08:52 +00:00
( * this ) [ i ] - > GetStats ( s ) ;
2009-02-09 21:15:56 +00:00
m_stats . pixels + = s . pixels ;
2011-02-07 01:59:05 +00:00
m_stats . prims = std : : max < int > ( m_stats . prims , s . prims ) ;
2009-02-09 21:15:56 +00:00
}
}
2011-02-17 18:22:47 +00:00
void GSRasterizerList : : Draw ( const GSRasterizerData * data , int width , int height )
2011-02-16 03:19:36 +00:00
{
m_stats . Reset ( ) ;
m_start = __rdtsc ( ) ;
2011-02-17 18:22:47 +00:00
m_threads = std : : min < int > ( 1 + ( height > > THREAD_HEIGHT ) , size ( ) ) ;
m_sync = 0 ;
for ( int i = 1 ; i < m_threads ; i + + )
{
m_sync | = 1 < < i ;
}
for ( int i = 1 ; i < m_threads ; i + + )
2011-02-16 03:19:36 +00:00
{
2011-02-17 18:22:47 +00:00
( * this ) [ i ] - > SetThreadId ( i , m_threads ) ;
2011-02-16 03:19:36 +00:00
( * this ) [ i ] - > Draw ( data ) ;
}
2011-02-17 18:22:47 +00:00
( * this ) [ 0 ] - > SetThreadId ( 0 , m_threads ) ;
2011-02-16 03:19:36 +00:00
( * this ) [ 0 ] - > Draw ( data ) ;
}
2009-02-09 21:15:56 +00:00
void GSRasterizerList : : GetStats ( GSRasterizerStats & stats )
{
stats = m_stats ;
}
void GSRasterizerList : : PrintStats ( )
{
2009-05-11 08:18:00 +00:00
if ( ! empty ( ) )
2009-02-09 21:15:56 +00:00
{
2009-05-11 08:18:00 +00:00
front ( ) - > PrintStats ( ) ;
2009-02-09 21:15:56 +00:00
}
}