2013-04-17 23:09:55 -04:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2008-12-08 05:25:12 +00:00
#include <cmath>
2014-02-17 05:18:15 -05:00
#include "Common/Common.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
2011-01-31 01:28:32 +00:00
2011-01-29 04:31:56 +00:00
static bool s_bFogRangeAdjustChanged ;
2013-10-13 15:41:11 +02:00
static bool s_bViewPortChanged ;
2010-09-23 02:17:48 +00:00
static int nLightsChanged [ 2 ]; // min,max
2008-12-08 05:25:12 +00:00
2013-10-07 16:02:24 +02:00
PixelShaderConstants PixelShaderManager :: constants ;
bool PixelShaderManager :: dirty ;
2008-12-26 10:43:18 +00:00
void PixelShaderManager :: Init ()
{
2013-10-07 16:02:24 +02:00
memset ( & constants , 0 , sizeof ( constants ));
2009-09-15 21:49:15 +00:00
Dirty ();
}
void PixelShaderManager :: Dirty ()
{
2013-10-07 21:57:18 +02:00
s_bFogRangeAdjustChanged = true ;
2013-10-13 15:41:11 +02:00
s_bViewPortChanged = true ;
2010-09-23 02:17:48 +00:00
nLightsChanged [ 0 ] = 0 ; nLightsChanged [ 1 ] = 0x80 ;
2013-10-29 01:23:17 -04:00
2013-10-12 17:56:41 +02:00
SetColorChanged ( 0 , 0 );
SetColorChanged ( 0 , 1 );
SetColorChanged ( 0 , 2 );
SetColorChanged ( 0 , 3 );
SetColorChanged ( 1 , 0 );
SetColorChanged ( 1 , 1 );
SetColorChanged ( 1 , 2 );
SetColorChanged ( 1 , 3 );
SetAlpha ();
SetDestAlpha ();
SetZTextureBias ();
SetViewportChanged ();
SetIndTexScaleChanged ( false );
SetIndTexScaleChanged ( true );
SetIndMatrixChanged ( 0 );
SetIndMatrixChanged ( 1 );
SetIndMatrixChanged ( 2 );
SetZTextureTypeChanged ();
SetTexCoordChanged ( 0 );
SetTexCoordChanged ( 1 );
SetTexCoordChanged ( 2 );
SetTexCoordChanged ( 3 );
SetTexCoordChanged ( 4 );
SetTexCoordChanged ( 5 );
SetTexCoordChanged ( 6 );
SetTexCoordChanged ( 7 );
SetFogColorChanged ();
SetFogParamChanged ();
2008-12-26 10:43:18 +00:00
}
void PixelShaderManager :: Shutdown ()
{
}
2014-01-15 16:58:36 +01:00
void PixelShaderManager :: SetConstants ()
2008-12-08 05:25:12 +00:00
{
2013-06-25 13:37:38 +02:00
if ( s_bFogRangeAdjustChanged )
2011-01-29 04:31:56 +00:00
{
2013-10-07 21:57:18 +02:00
// set by two components, so keep changed flag here
// TODO: try to split both registers and move this logic to the shader
2011-01-29 04:31:56 +00:00
if ( ! g_ActiveConfig . bDisableFog && bpmem . fogRange . Base . Enabled == 1 )
{
//bpmem.fogRange.Base.Center : center of the viewport in x axis. observation: bpmem.fogRange.Base.Center = realcenter + 342;
int center = (( u32 ) bpmem . fogRange . Base . Center ) - 342 ;
2013-04-07 17:11:29 -04:00
// normalize center to make calculations easy
2011-04-11 01:49:32 +00:00
float ScreenSpaceCenter = center / ( 2.0f * xfregs . viewport . wd );
2011-01-29 04:31:56 +00:00
ScreenSpaceCenter = ( ScreenSpaceCenter * 2.0f ) - 1.0f ;
2013-04-07 17:11:29 -04:00
//bpmem.fogRange.K seems to be a table of precalculated coefficients for the adjust factor
//observations: bpmem.fogRange.K[0].LO appears to be the lowest value and bpmem.fogRange.K[4].HI the largest
// they always seems to be larger than 256 so my theory is :
// they are the coefficients from the center to the border of the screen
// so to simplify I use the hi coefficient as K in the shader taking 256 as the scale
2013-10-07 21:57:18 +02:00
constants . fog [ 2 ][ 0 ] = ScreenSpaceCenter ;
2013-11-13 04:03:46 -05:00
constants . fog [ 2 ][ 1 ] = ( float ) Renderer :: EFBToScaledX (( int )( 2.0f * xfregs . viewport . wd ));
2013-10-07 21:57:18 +02:00
constants . fog [ 2 ][ 2 ] = bpmem . fogRange . K [ 4 ]. HI / 256.0f ;
2011-06-20 05:48:12 +00:00
}
else
2013-04-24 09:21:54 -04:00
{
2013-10-07 21:57:18 +02:00
constants . fog [ 2 ][ 0 ] = 0 ;
constants . fog [ 2 ][ 1 ] = 1 ;
constants . fog [ 2 ][ 2 ] = 1 ;
2013-04-24 09:21:54 -04:00
}
2013-10-07 21:57:18 +02:00
dirty = true ;
2011-06-20 05:48:12 +00:00
2011-01-29 04:31:56 +00:00
s_bFogRangeAdjustChanged = false ;
2013-06-25 13:37:38 +02:00
}
2011-01-29 04:31:56 +00:00
2011-03-19 00:50:34 +00:00
if ( g_ActiveConfig . bEnablePixelLighting && g_ActiveConfig . backend_info . bSupportsPixelLighting ) // config check added because the code in here was crashing for me inside SetPSConstant4f
2010-09-23 02:17:48 +00:00
{
2011-02-05 18:25:34 +00:00
if ( nLightsChanged [ 0 ] >= 0 )
2010-09-23 02:17:48 +00:00
{
2011-02-05 18:25:34 +00:00
// lights don't have a 1 to 1 mapping, the color component needs to be converted to 4 floats
int istart = nLightsChanged [ 0 ] / 0x10 ;
int iend = ( nLightsChanged [ 1 ] + 15 ) / 0x10 ;
const float * xfmemptr = ( const float * ) & xfmem [ 0x10 * istart + XFMEM_LIGHTS ];
2010-09-23 02:17:48 +00:00
2011-02-05 18:25:34 +00:00
for ( int i = istart ; i < iend ; ++ i )
2010-09-23 02:17:48 +00:00
{
2011-02-05 18:25:34 +00:00
u32 color = * ( const u32 * )( xfmemptr + 3 );
2013-10-07 21:57:18 +02:00
constants . plights [ 5 * i ][ 0 ] = (( color >> 24 ) & 0xFF ) / 255.0f ;
constants . plights [ 5 * i ][ 1 ] = (( color >> 16 ) & 0xFF ) / 255.0f ;
constants . plights [ 5 * i ][ 2 ] = (( color >> 8 ) & 0xFF ) / 255.0f ;
constants . plights [ 5 * i ][ 3 ] = (( color ) & 0xFF ) / 255.0f ;
2011-02-05 18:25:34 +00:00
xfmemptr += 4 ;
for ( int j = 0 ; j < 4 ; ++ j , xfmemptr += 3 )
2010-09-23 02:17:48 +00:00
{
2011-02-05 18:25:34 +00:00
if ( j == 1 &&
fabs ( xfmemptr [ 0 ]) < 0.00001f &&
fabs ( xfmemptr [ 1 ]) < 0.00001f &&
fabs ( xfmemptr [ 2 ]) < 0.00001f )
// dist attenuation, make sure not equal to 0!!!
2013-10-07 21:57:18 +02:00
constants . plights [ 5 * i + j + 1 ][ 0 ] = 0.00001f ;
2011-02-05 18:25:34 +00:00
else
2013-10-07 21:57:18 +02:00
constants . plights [ 5 * i + j + 1 ][ 0 ] = xfmemptr [ 0 ];
constants . plights [ 5 * i + j + 1 ][ 1 ] = xfmemptr [ 1 ];
constants . plights [ 5 * i + j + 1 ][ 2 ] = xfmemptr [ 2 ];
2010-09-23 02:17:48 +00:00
}
}
2013-10-07 21:57:18 +02:00
dirty = true ;
2011-02-05 18:25:34 +00:00
nLightsChanged [ 0 ] = nLightsChanged [ 1 ] = - 1 ;
2010-09-23 02:17:48 +00:00
}
}
2013-10-29 01:23:17 -04:00
2013-10-13 15:41:11 +02:00
if ( s_bViewPortChanged )
{
constants . zbias [ 1 ][ 0 ] = xfregs . viewport . farZ / 16777216.0f ;
constants . zbias [ 1 ][ 1 ] = xfregs . viewport . zRange / 16777216.0f ;
dirty = true ;
2013-12-03 09:36:48 +01:00
s_bViewPortChanged = false ;
2013-10-13 15:41:11 +02:00
}
2008-12-08 05:25:12 +00:00
}
2012-09-02 20:00:15 +02:00
// This one is high in profiles (0.5%).
// TODO: Move conversion out, only store the raw color value
2009-08-31 20:58:57 +00:00
// and update it when the shader constant is set, only.
2013-03-29 20:59:03 +01:00
// TODO: Conversion should be checked in the context of tev_fixes..
2013-10-12 17:56:41 +02:00
void PixelShaderManager :: SetColorChanged ( int type , int num )
2008-12-08 05:25:12 +00:00
{
2013-10-07 21:57:18 +02:00
float4 * c = type ? constants . kcolors : constants . colors ;
2013-10-12 17:56:41 +02:00
c [ num ][ 0 ] = bpmem . tevregs [ num ]. low . a / 255.0f ;
c [ num ][ 3 ] = bpmem . tevregs [ num ]. low . b / 255.0f ;
c [ num ][ 2 ] = bpmem . tevregs [ num ]. high . a / 255.0f ;
c [ num ][ 1 ] = bpmem . tevregs [ num ]. high . b / 255.0f ;
2013-10-07 21:57:18 +02:00
dirty = true ;
2013-10-29 01:23:17 -04:00
2013-10-07 21:57:18 +02:00
PRIM_LOG ( "pixel %scolor%d: %f %f %f %f \n " , type ? "k" : "" , num , c [ num ][ 0 ], c [ num ][ 1 ], c [ num ][ 2 ], c [ num ][ 3 ]);
2008-12-08 05:25:12 +00:00
}
2013-10-12 17:56:41 +02:00
void PixelShaderManager :: SetAlpha ()
2008-12-08 05:25:12 +00:00
{
2013-10-12 17:56:41 +02:00
constants . alpha [ 0 ] = bpmem . alpha_test . ref0 / 255.0f ;
constants . alpha [ 1 ] = bpmem . alpha_test . ref1 / 255.0f ;
2013-10-07 21:57:18 +02:00
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2013-10-12 17:56:41 +02:00
void PixelShaderManager :: SetDestAlpha ()
2008-12-08 05:25:12 +00:00
{
2013-10-12 17:56:41 +02:00
constants . alpha [ 3 ] = bpmem . dstalpha . alpha / 255.0f ;
2013-10-07 21:57:18 +02:00
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2012-03-24 04:47:28 +01:00
void PixelShaderManager :: SetTexDims ( int texmapid , u32 width , u32 height , u32 wraps , u32 wrapt )
2008-12-08 05:25:12 +00:00
{
2013-10-07 21:57:18 +02:00
// TODO: move this check out to callee. There we could just call this function on texture changes
// or better, use textureSize() in glsl
if ( constants . texdims [ texmapid ][ 0 ] != 1.0f / width || constants . texdims [ texmapid ][ 1 ] != 1.0f / height )
dirty = true ;
2013-10-29 01:23:17 -04:00
2013-10-07 21:57:18 +02:00
constants . texdims [ texmapid ][ 0 ] = 1.0f / width ;
constants . texdims [ texmapid ][ 1 ] = 1.0f / height ;
2008-12-08 05:25:12 +00:00
}
2013-10-12 17:56:41 +02:00
void PixelShaderManager :: SetZTextureBias ()
2008-12-08 05:25:12 +00:00
{
2013-10-12 17:56:41 +02:00
constants . zbias [ 1 ][ 3 ] = bpmem . ztex1 . bias / 16777215.0f ;
2013-10-07 21:57:18 +02:00
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2011-02-05 18:25:34 +00:00
void PixelShaderManager :: SetViewportChanged ()
2009-02-08 22:08:20 +00:00
{
2013-10-13 15:41:11 +02:00
s_bViewPortChanged = true ;
2013-03-15 15:05:48 +01:00
s_bFogRangeAdjustChanged = true ; // TODO: Shouldn't be necessary with an accurate fog range adjust implementation
2009-10-25 23:10:30 +00:00
}
2013-10-12 17:56:41 +02:00
void PixelShaderManager :: SetIndTexScaleChanged ( bool high )
2008-12-08 05:25:12 +00:00
{
2013-10-12 17:56:41 +02:00
constants . indtexscale [ high ][ 0 ] = bpmem . texscale [ high ]. getScaleS ( 0 );
constants . indtexscale [ high ][ 1 ] = bpmem . texscale [ high ]. getScaleT ( 0 );
constants . indtexscale [ high ][ 2 ] = bpmem . texscale [ high ]. getScaleS ( 1 );
constants . indtexscale [ high ][ 3 ] = bpmem . texscale [ high ]. getScaleT ( 1 );
2013-10-07 21:57:18 +02:00
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2008-12-26 10:43:18 +00:00
void PixelShaderManager :: SetIndMatrixChanged ( int matrixidx )
2008-12-08 05:25:12 +00:00
{
2013-10-07 21:57:18 +02:00
int scale = (( u32 ) bpmem . indmtx [ matrixidx ]. col0 . s0 << 0 ) |
(( u32 ) bpmem . indmtx [ matrixidx ]. col1 . s1 << 2 ) |
(( u32 ) bpmem . indmtx [ matrixidx ]. col2 . s2 << 4 );
float fscale = powf ( 2.0f , ( float )( scale - 17 )) / 1024.0f ;
// xyz - static matrix
// TODO w - dynamic matrix scale / 256...... somehow / 4 works better
// rev 2972 - now using / 256.... verify that this works
2013-10-08 14:34:42 +02:00
constants . indtexmtx [ 2 * matrixidx ][ 0 ] = bpmem . indmtx [ matrixidx ]. col0 . ma * fscale ;
constants . indtexmtx [ 2 * matrixidx ][ 1 ] = bpmem . indmtx [ matrixidx ]. col1 . mc * fscale ;
constants . indtexmtx [ 2 * matrixidx ][ 2 ] = bpmem . indmtx [ matrixidx ]. col2 . me * fscale ;
constants . indtexmtx [ 2 * matrixidx ][ 3 ] = fscale * 4.0f ;
constants . indtexmtx [ 2 * matrixidx + 1 ][ 0 ] = bpmem . indmtx [ matrixidx ]. col0 . mb * fscale ;
constants . indtexmtx [ 2 * matrixidx + 1 ][ 1 ] = bpmem . indmtx [ matrixidx ]. col1 . md * fscale ;
constants . indtexmtx [ 2 * matrixidx + 1 ][ 2 ] = bpmem . indmtx [ matrixidx ]. col2 . mf * fscale ;
constants . indtexmtx [ 2 * matrixidx + 1 ][ 3 ] = fscale * 4.0f ;
2013-10-07 21:57:18 +02:00
dirty = true ;
PRIM_LOG ( "indmtx%d: scale=%f, mat=(%f %f %f; %f %f %f) \n " ,
matrixidx , 1024.0f * fscale ,
bpmem . indmtx [ matrixidx ]. col0 . ma * fscale , bpmem . indmtx [ matrixidx ]. col1 . mc * fscale , bpmem . indmtx [ matrixidx ]. col2 . me * fscale ,
bpmem . indmtx [ matrixidx ]. col0 . mb * fscale , bpmem . indmtx [ matrixidx ]. col1 . md * fscale , bpmem . indmtx [ matrixidx ]. col2 . mf * fscale );
2008-12-08 05:25:12 +00:00
}
2009-08-31 20:58:57 +00:00
2009-02-08 22:08:20 +00:00
void PixelShaderManager :: SetZTextureTypeChanged ()
{
2013-10-07 21:57:18 +02:00
switch ( bpmem . ztex2 . type )
{
case TEV_ZTEX_TYPE_U8 :
constants . zbias [ 0 ][ 0 ] = 0 ;
constants . zbias [ 0 ][ 1 ] = 0 ;
constants . zbias [ 0 ][ 2 ] = 0 ;
constants . zbias [ 0 ][ 3 ] = 255.0f / 16777215.0f ;
break ;
case TEV_ZTEX_TYPE_U16 :
constants . zbias [ 0 ][ 0 ] = 255.0f / 16777215.0f ;
constants . zbias [ 0 ][ 1 ] = 0 ;
constants . zbias [ 0 ][ 2 ] = 0 ;
constants . zbias [ 0 ][ 3 ] = 65280.0f / 16777215.0f ;
break ;
case TEV_ZTEX_TYPE_U24 :
constants . zbias [ 0 ][ 0 ] = 16711680.0f / 16777215.0f ;
constants . zbias [ 0 ][ 1 ] = 65280.0f / 16777215.0f ;
constants . zbias [ 0 ][ 2 ] = 255.0f / 16777215.0f ;
constants . zbias [ 0 ][ 3 ] = 0 ;
break ;
default :
break ;
}
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2009-04-15 03:55:38 +00:00
void PixelShaderManager :: SetTexCoordChanged ( u8 texmapid )
2008-12-08 05:25:12 +00:00
{
2013-10-07 21:57:18 +02:00
TCoordInfo & tc = bpmem . texcoords [ texmapid ];
2013-11-13 04:03:46 -05:00
constants . texdims [ texmapid ][ 2 ] = ( float )( tc . s . scale_minus_1 + 1 );
constants . texdims [ texmapid ][ 3 ] = ( float )( tc . t . scale_minus_1 + 1 );
2013-10-07 21:57:18 +02:00
dirty = true ;
2008-12-08 05:25:12 +00:00
}
2009-02-19 04:41:58 +00:00
void PixelShaderManager :: SetFogColorChanged ()
{
2013-10-07 21:57:18 +02:00
constants . fog [ 0 ][ 0 ] = bpmem . fog . color . r / 255.0f ;
constants . fog [ 0 ][ 1 ] = bpmem . fog . color . g / 255.0f ;
constants . fog [ 0 ][ 2 ] = bpmem . fog . color . b / 255.0f ;
dirty = true ;
2009-02-19 04:41:58 +00:00
}
void PixelShaderManager :: SetFogParamChanged ()
{
2013-10-07 21:57:18 +02:00
if ( ! g_ActiveConfig . bDisableFog )
{
constants . fog [ 1 ][ 0 ] = bpmem . fog . a . GetA ();
constants . fog [ 1 ][ 1 ] = ( float ) bpmem . fog . b_magnitude / 0xFFFFFF ;
constants . fog [ 1 ][ 2 ] = bpmem . fog . c_proj_fsel . GetC ();
2013-11-13 04:03:46 -05:00
constants . fog [ 1 ][ 3 ] = ( float )( 1 << bpmem . fog . b_shift );
2013-10-07 21:57:18 +02:00
}
else
{
constants . fog [ 1 ][ 0 ] = 0 ;
constants . fog [ 1 ][ 1 ] = 1 ;
constants . fog [ 1 ][ 2 ] = 0 ;
constants . fog [ 1 ][ 3 ] = 1 ;
}
dirty = true ;
2009-02-19 04:41:58 +00:00
}
2011-01-29 04:31:56 +00:00
void PixelShaderManager :: SetFogRangeAdjustChanged ()
{
2013-03-19 21:51:12 -04:00
s_bFogRangeAdjustChanged = true ;
2011-01-29 04:31:56 +00:00
}
2010-09-23 02:17:48 +00:00
void PixelShaderManager :: InvalidateXFRange ( int start , int end )
{
if ( start < XFMEM_LIGHTS_END && end > XFMEM_LIGHTS )
{
int _start = start < XFMEM_LIGHTS ? XFMEM_LIGHTS : start - XFMEM_LIGHTS ;
int _end = end < XFMEM_LIGHTS_END ? end - XFMEM_LIGHTS : XFMEM_LIGHTS_END - XFMEM_LIGHTS ;
if ( nLightsChanged [ 0 ] == - 1 )
{
nLightsChanged [ 0 ] = _start ;
nLightsChanged [ 1 ] = _end ;
}
else
{
if ( nLightsChanged [ 0 ] > _start ) nLightsChanged [ 0 ] = _start ;
if ( nLightsChanged [ 1 ] < _end ) nLightsChanged [ 1 ] = _end ;
}
}
}
2013-10-07 21:57:18 +02:00
void PixelShaderManager :: SetMaterialColorChanged ( int index , u32 color )
2010-09-23 02:17:48 +00:00
{
2013-10-07 21:57:18 +02:00
if ( g_ActiveConfig . bEnablePixelLighting && g_ActiveConfig . backend_info . bSupportsPixelLighting )
{
constants . pmaterials [ index ][ 0 ] = (( color >> 24 ) & 0xFF ) / 255.0f ;
constants . pmaterials [ index ][ 1 ] = (( color >> 16 ) & 0xFF ) / 255.0f ;
constants . pmaterials [ index ][ 2 ] = (( color >> 8 ) & 0xFF ) / 255.0f ;
constants . pmaterials [ index ][ 3 ] = ( color & 0xFF ) / 255.0f ;
dirty = true ;
}
2010-09-23 02:17:48 +00:00
}
2012-01-01 12:46:02 -08:00
void PixelShaderManager :: DoState ( PointerWrap & p )
{
2013-10-07 16:02:24 +02:00
p . Do ( constants );
p . Do ( dirty );
2013-10-29 01:23:17 -04:00
2012-01-01 12:46:02 -08:00
if ( p . GetMode () == PointerWrap :: MODE_READ )
{
Dirty ();
}
}