2013-04-17 21:09:55 -06:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2008-12-07 22:25:12 -07:00
# include <cmath>
2009-05-13 17:37:26 -06:00
# include "Common.h"
2008-12-07 22:25:12 -07:00
# include "Statistics.h"
# include "PixelShaderManager.h"
2008-12-26 05:47:32 -07:00
# include "VideoCommon.h"
2009-12-09 06:51:28 -07:00
# include "VideoConfig.h"
2011-01-30 18:28:32 -07:00
2011-01-28 21:31:56 -07:00
# include "RenderBase.h"
static bool s_bFogRangeAdjustChanged ;
2010-09-22 20:17:48 -06:00
static int nLightsChanged [ 2 ] ; // min,max
2008-12-07 22:25:12 -07:00
2013-10-07 08:02:24 -06:00
PixelShaderConstants PixelShaderManager : : constants ;
bool PixelShaderManager : : dirty ;
2008-12-26 03:43:18 -07:00
void PixelShaderManager : : Init ( )
{
2013-10-07 08:02:24 -06:00
memset ( & constants , 0 , sizeof ( constants ) ) ;
2009-09-15 15:49:15 -06:00
Dirty ( ) ;
}
void PixelShaderManager : : Dirty ( )
{
2013-10-07 13:57:18 -06:00
s_bFogRangeAdjustChanged = true ;
2010-09-22 20:17:48 -06:00
nLightsChanged [ 0 ] = 0 ; nLightsChanged [ 1 ] = 0x80 ;
2013-10-07 08:02:24 -06:00
dirty = true ;
2008-12-26 03:43:18 -07:00
}
void PixelShaderManager : : Shutdown ( )
{
}
2012-09-02 12:00:15 -06:00
void PixelShaderManager : : SetConstants ( u32 components )
2008-12-07 22:25:12 -07:00
{
2013-06-25 05:37:38 -06:00
if ( s_bFogRangeAdjustChanged )
2011-01-28 21:31:56 -07:00
{
2013-10-07 13:57:18 -06: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-28 21:31:56 -07: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 15:11:29 -06:00
// normalize center to make calculations easy
2011-04-10 19:49:32 -06:00
float ScreenSpaceCenter = center / ( 2.0f * xfregs . viewport . wd ) ;
2011-01-28 21:31:56 -07:00
ScreenSpaceCenter = ( ScreenSpaceCenter * 2.0f ) - 1.0f ;
2013-04-07 15:11:29 -06: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 13:57:18 -06:00
constants . fog [ 2 ] [ 0 ] = ScreenSpaceCenter ;
constants . fog [ 2 ] [ 1 ] = Renderer : : EFBToScaledX ( ( int ) ( 2.0f * xfregs . viewport . wd ) ) ;
constants . fog [ 2 ] [ 2 ] = bpmem . fogRange . K [ 4 ] . HI / 256.0f ;
2011-06-19 23:48:12 -06:00
}
else
2013-04-24 07:21:54 -06:00
{
2013-10-07 13:57:18 -06:00
constants . fog [ 2 ] [ 0 ] = 0 ;
constants . fog [ 2 ] [ 1 ] = 1 ;
constants . fog [ 2 ] [ 2 ] = 1 ;
2013-04-24 07:21:54 -06:00
}
2013-10-07 13:57:18 -06:00
dirty = true ;
2011-06-19 23:48:12 -06:00
2011-01-28 21:31:56 -07:00
s_bFogRangeAdjustChanged = false ;
2013-06-25 05:37:38 -06:00
}
2011-01-28 21:31:56 -07:00
2011-03-18 18:50:34 -06: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-22 20:17:48 -06:00
{
2011-02-05 11:25:34 -07:00
if ( nLightsChanged [ 0 ] > = 0 )
2010-09-22 20:17:48 -06:00
{
2011-02-05 11:25:34 -07: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 ] ;
for ( int i = istart ; i < iend ; + + i )
2010-09-22 20:17:48 -06:00
{
2011-02-05 11:25:34 -07:00
u32 color = * ( const u32 * ) ( xfmemptr + 3 ) ;
2013-10-07 13:57:18 -06: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 11:25:34 -07:00
xfmemptr + = 4 ;
for ( int j = 0 ; j < 4 ; + + j , xfmemptr + = 3 )
2010-09-22 20:17:48 -06:00
{
2011-02-05 11:25:34 -07: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 13:57:18 -06:00
constants . plights [ 5 * i + j + 1 ] [ 0 ] = 0.00001f ;
2011-02-05 11:25:34 -07:00
else
2013-10-07 13:57:18 -06: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-22 20:17:48 -06:00
}
}
2013-10-07 13:57:18 -06:00
dirty = true ;
2011-02-05 11:25:34 -07:00
nLightsChanged [ 0 ] = nLightsChanged [ 1 ] = - 1 ;
2010-09-22 20:17:48 -06:00
}
}
2008-12-07 22:25:12 -07:00
}
2012-09-02 12:00:15 -06:00
// This one is high in profiles (0.5%).
// TODO: Move conversion out, only store the raw color value
2009-08-31 14:58:57 -06:00
// and update it when the shader constant is set, only.
2013-03-29 13:59:03 -06:00
// TODO: Conversion should be checked in the context of tev_fixes..
2011-07-04 07:49:40 -06:00
void PixelShaderManager : : SetColorChanged ( int type , int num , bool high )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06:00
float4 * c = type ? constants . kcolors : constants . colors ;
2013-04-24 07:21:54 -06:00
if ( ! high )
{
2013-10-07 13:57:18 -06:00
c [ num ] [ 0 ] = bpmem . tevregs [ num ] . low . a / 255.0f ;
c [ num ] [ 3 ] = bpmem . tevregs [ num ] . low . b / 255.0f ;
2013-04-24 07:21:54 -06:00
}
else
{
2013-10-07 13:57:18 -06:00
c [ num ] [ 2 ] = bpmem . tevregs [ num ] . high . a / 255.0f ;
c [ num ] [ 1 ] = bpmem . tevregs [ num ] . high . b / 255.0f ;
2011-07-04 07:49:40 -06:00
}
2013-10-07 13:57:18 -06:00
dirty = true ;
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-07 22:25:12 -07:00
}
2013-01-08 09:18:45 -07:00
void PixelShaderManager : : SetAlpha ( const AlphaTest & alpha )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06:00
constants . alpha [ 0 ] = alpha . ref0 / 255.0f ;
constants . alpha [ 1 ] = alpha . ref1 / 255.0f ;
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2008-12-26 03:43:18 -07:00
void PixelShaderManager : : SetDestAlpha ( const ConstantAlpha & alpha )
2008-12-07 22:25:12 -07:00
{
2013-10-09 08:33:45 -06:00
constants . alpha [ 3 ] = alpha . alpha / 255.0f ;
2013-10-07 13:57:18 -06:00
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2012-03-23 21:47:28 -06:00
void PixelShaderManager : : SetTexDims ( int texmapid , u32 width , u32 height , u32 wraps , u32 wrapt )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06: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 ;
constants . texdims [ texmapid ] [ 0 ] = 1.0f / width ;
constants . texdims [ texmapid ] [ 1 ] = 1.0f / height ;
2008-12-07 22:25:12 -07:00
}
2008-12-26 03:43:18 -07:00
void PixelShaderManager : : SetZTextureBias ( u32 bias )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06:00
constants . zbias [ 1 ] [ 3 ] = bias / 16777215.0f ;
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2011-02-05 11:25:34 -07:00
void PixelShaderManager : : SetViewportChanged ( )
2009-02-08 15:08:20 -07:00
{
2013-10-07 13:57:18 -06:00
constants . zbias [ 1 ] [ 0 ] = xfregs . viewport . farZ / 16777216.0f ;
constants . zbias [ 1 ] [ 1 ] = xfregs . viewport . zRange / 16777216.0f ;
dirty = true ;
2013-03-15 08:05:48 -06:00
s_bFogRangeAdjustChanged = true ; // TODO: Shouldn't be necessary with an accurate fog range adjust implementation
2009-10-25 17:10:30 -06:00
}
2009-04-14 21:55:38 -06:00
void PixelShaderManager : : SetIndTexScaleChanged ( u8 stagemask )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06:00
bool high_stage = stagemask = = 0x0c ;
constants . indtexscale [ high_stage ] [ 0 ] = bpmem . texscale [ high_stage ] . getScaleS ( 0 ) ;
constants . indtexscale [ high_stage ] [ 1 ] = bpmem . texscale [ high_stage ] . getScaleT ( 0 ) ;
constants . indtexscale [ high_stage ] [ 2 ] = bpmem . texscale [ high_stage ] . getScaleS ( 1 ) ;
constants . indtexscale [ high_stage ] [ 3 ] = bpmem . texscale [ high_stage ] . getScaleT ( 1 ) ;
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2008-12-26 03:43:18 -07:00
void PixelShaderManager : : SetIndMatrixChanged ( int matrixidx )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06: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 06:34:42 -06: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 13:57:18 -06: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-07 22:25:12 -07:00
}
2009-08-31 14:58:57 -06:00
2009-02-08 15:08:20 -07:00
void PixelShaderManager : : SetZTextureTypeChanged ( )
{
2013-10-07 13:57:18 -06: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-07 22:25:12 -07:00
}
2009-04-14 21:55:38 -06:00
void PixelShaderManager : : SetTexCoordChanged ( u8 texmapid )
2008-12-07 22:25:12 -07:00
{
2013-10-07 13:57:18 -06:00
TCoordInfo & tc = bpmem . texcoords [ texmapid ] ;
constants . texdims [ texmapid ] [ 2 ] = tc . s . scale_minus_1 + 1 ;
constants . texdims [ texmapid ] [ 3 ] = tc . t . scale_minus_1 + 1 ;
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2009-02-18 21:41:58 -07:00
void PixelShaderManager : : SetFogColorChanged ( )
{
2013-10-07 13:57:18 -06: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-18 21:41:58 -07:00
}
void PixelShaderManager : : SetFogParamChanged ( )
{
2013-10-07 13:57:18 -06: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 ( ) ;
constants . fog [ 1 ] [ 3 ] = 1 < < bpmem . fog . b_shift ;
}
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-18 21:41:58 -07:00
}
2011-01-28 21:31:56 -07:00
void PixelShaderManager : : SetFogRangeAdjustChanged ( )
{
2013-03-19 19:51:12 -06:00
s_bFogRangeAdjustChanged = true ;
2011-01-28 21:31:56 -07:00
}
2010-09-22 20:17:48 -06: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 13:57:18 -06:00
void PixelShaderManager : : SetMaterialColorChanged ( int index , u32 color )
2010-09-22 20:17:48 -06:00
{
2013-10-07 13:57:18 -06: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-22 20:17:48 -06:00
}
2012-01-01 13:46:02 -07:00
void PixelShaderManager : : DoState ( PointerWrap & p )
{
2013-10-07 08:02:24 -06:00
p . Do ( constants ) ;
p . Do ( dirty ) ;
2012-01-01 13:46:02 -07:00
if ( p . GetMode ( ) = = PointerWrap : : MODE_READ )
{
Dirty ( ) ;
}
}