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>
2014-02-17 03:18:15 -07: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-30 18:28:32 -07:00
2011-01-28 21:31:56 -07:00
static bool s_bFogRangeAdjustChanged ;
2013-10-13 07:41:11 -06:00
static bool s_bViewPortChanged ;
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 ;
2013-10-13 07:41:11 -06:00
s_bViewPortChanged = true ;
2010-09-22 20:17:48 -06:00
nLightsChanged [ 0 ] = 0 ; nLightsChanged [ 1 ] = 0x80 ;
2013-10-28 23:23:17 -06:00
2013-10-12 09:56:41 -06: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 03:43:18 -07:00
}
void PixelShaderManager : : Shutdown ( )
{
}
2014-01-15 08:58:36 -07:00
void PixelShaderManager : : SetConstants ( )
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
2014-03-10 05:30:55 -06:00
if ( ! g_ActiveConfig . bDisableFog & & bpmem . fogRange . Base . Enabled = = 1 )
2011-01-28 21:31:56 -07:00
{
//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-27 06:10:00 -06:00
// TODO: Shouldn't this be EFBToScaledXf?
2013-12-16 05:08:09 -07:00
constants . fogf [ 0 ] [ 0 ] = ScreenSpaceCenter ;
constants . fogf [ 0 ] [ 1 ] = ( float ) Renderer : : EFBToScaledX ( ( int ) ( 2.0f * xfregs . viewport . wd ) ) ;
constants . fogf [ 0 ] [ 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-12-16 05:08:09 -07:00
constants . fogf [ 0 ] [ 0 ] = 0 ;
constants . fogf [ 0 ] [ 1 ] = 1 ;
constants . fogf [ 0 ] [ 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
{
2013-10-27 06:57:40 -06:00
// TODO: Outdated comment
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-27 06:57:40 -06:00
constants . plight_colors [ i ] [ 0 ] = ( color > > 24 ) & 0xFF ;
constants . plight_colors [ i ] [ 1 ] = ( color > > 16 ) & 0xFF ;
constants . plight_colors [ i ] [ 2 ] = ( color > > 8 ) & 0xFF ;
constants . plight_colors [ i ] [ 3 ] = ( color ) & 0xFF ;
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-27 06:57:40 -06:00
constants . plights [ 4 * i + j ] [ 0 ] = 0.00001f ;
2011-02-05 11:25:34 -07:00
else
2013-10-27 06:57:40 -06:00
constants . plights [ 4 * i + j ] [ 0 ] = xfmemptr [ 0 ] ;
constants . plights [ 4 * i + j ] [ 1 ] = xfmemptr [ 1 ] ;
constants . plights [ 4 * i + j ] [ 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
}
}
2013-10-28 23:23:17 -06:00
2014-03-10 05:30:55 -06:00
if ( s_bViewPortChanged )
2013-10-13 07:41:11 -06:00
{
2013-11-23 12:58:24 -07:00
constants . zbias [ 1 ] [ 0 ] = xfregs . viewport . farZ ;
constants . zbias [ 1 ] [ 1 ] = xfregs . viewport . zRange ;
2013-10-13 07:41:11 -06:00
dirty = true ;
2013-12-03 01:36:48 -07:00
s_bViewPortChanged = false ;
2013-10-13 07:41:11 -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..
2013-10-12 09:56:41 -06:00
void PixelShaderManager : : SetColorChanged ( int type , int num )
2008-12-07 22:25:12 -07:00
{
2013-10-10 12:26:41 -06:00
int4 * c = type ? constants . kcolors : constants . colors ;
c [ num ] [ 0 ] = bpmem . tevregs [ num ] . low . a ;
c [ num ] [ 3 ] = bpmem . tevregs [ num ] . low . b ;
c [ num ] [ 2 ] = bpmem . tevregs [ num ] . high . a ;
c [ num ] [ 1 ] = bpmem . tevregs [ num ] . high . b ;
2013-10-07 13:57:18 -06:00
dirty = true ;
2013-10-28 23:23:17 -06:00
2013-10-10 12:26:41 -06:00
PRIM_LOG ( " pixel %scolor%d: %d %d %d %d \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-10-12 09:56:41 -06:00
void PixelShaderManager : : SetAlpha ( )
2008-12-07 22:25:12 -07:00
{
2013-10-10 12:36:55 -06:00
constants . alpha [ 0 ] = bpmem . alpha_test . ref0 ;
constants . alpha [ 1 ] = bpmem . alpha_test . ref1 ;
2013-10-07 13:57:18 -06:00
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2013-10-12 09:56:41 -06:00
void PixelShaderManager : : SetDestAlpha ( )
2008-12-07 22:25:12 -07:00
{
2013-10-10 12:36:55 -06:00
constants . alpha [ 3 ] = bpmem . dstalpha . alpha ;
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
2014-03-10 05:30:55 -06:00
if ( constants . texdims [ texmapid ] [ 0 ] ! = 1.0f / width | | constants . texdims [ texmapid ] [ 1 ] ! = 1.0f / height )
2013-10-07 13:57:18 -06:00
dirty = true ;
2013-10-28 23:23:17 -06:00
2013-10-07 13:57:18 -06:00
constants . texdims [ texmapid ] [ 0 ] = 1.0f / width ;
constants . texdims [ texmapid ] [ 1 ] = 1.0f / height ;
2008-12-07 22:25:12 -07:00
}
2013-10-12 09:56:41 -06:00
void PixelShaderManager : : SetZTextureBias ( )
2008-12-07 22:25:12 -07:00
{
2013-11-23 12:58:24 -07:00
constants . zbias [ 1 ] [ 3 ] = bpmem . ztex1 . bias ;
2013-10-07 13:57:18 -06:00
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-13 07:41:11 -06:00
s_bViewPortChanged = 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
}
2013-10-12 09:56:41 -06:00
void PixelShaderManager : : SetIndTexScaleChanged ( bool high )
2008-12-07 22:25:12 -07:00
{
2014-01-29 07:52:24 -07:00
constants . indtexscale [ high ] [ 0 ] = bpmem . texscale [ high ] . ss0 ;
constants . indtexscale [ high ] [ 1 ] = bpmem . texscale [ high ] . ts0 ;
constants . indtexscale [ high ] [ 2 ] = bpmem . texscale [ high ] . ss1 ;
constants . indtexscale [ high ] [ 3 ] = bpmem . texscale [ high ] . ts1 ;
2013-10-07 13:57:18 -06:00
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 ) |
2013-10-10 13:09:00 -06:00
( ( u32 ) bpmem . indmtx [ matrixidx ] . col1 . s1 < < 2 ) |
( ( u32 ) bpmem . indmtx [ matrixidx ] . col2 . s2 < < 4 ) ;
2013-10-07 13:57:18 -06:00
// xyz - static matrix
2013-09-12 05:55:38 -06:00
// w - dynamic matrix scale / 128
2013-10-10 13:09:00 -06:00
constants . indtexmtx [ 2 * matrixidx ] [ 0 ] = bpmem . indmtx [ matrixidx ] . col0 . ma ;
constants . indtexmtx [ 2 * matrixidx ] [ 1 ] = bpmem . indmtx [ matrixidx ] . col1 . mc ;
constants . indtexmtx [ 2 * matrixidx ] [ 2 ] = bpmem . indmtx [ matrixidx ] . col2 . me ;
constants . indtexmtx [ 2 * matrixidx ] [ 3 ] = 17 - scale ;
constants . indtexmtx [ 2 * matrixidx + 1 ] [ 0 ] = bpmem . indmtx [ matrixidx ] . col0 . mb ;
constants . indtexmtx [ 2 * matrixidx + 1 ] [ 1 ] = bpmem . indmtx [ matrixidx ] . col1 . md ;
constants . indtexmtx [ 2 * matrixidx + 1 ] [ 2 ] = bpmem . indmtx [ matrixidx ] . col2 . mf ;
constants . indtexmtx [ 2 * matrixidx + 1 ] [ 3 ] = 17 - scale ;
2013-10-07 13:57:18 -06:00
dirty = true ;
2013-10-10 13:09:00 -06:00
PRIM_LOG ( " indmtx%d: scale=%d, mat=(%d %d %d; %d %d %d) \n " ,
matrixidx , scale ,
bpmem . indmtx [ matrixidx ] . col0 . ma , bpmem . indmtx [ matrixidx ] . col1 . mc , bpmem . indmtx [ matrixidx ] . col2 . me ,
bpmem . indmtx [ matrixidx ] . col0 . mb , bpmem . indmtx [ matrixidx ] . col1 . md , bpmem . indmtx [ matrixidx ] . col2 . mf ) ;
2013-10-07 13:57:18 -06:00
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 ;
2013-11-23 12:58:24 -07:00
constants . zbias [ 0 ] [ 3 ] = 1 ;
2013-10-07 13:57:18 -06:00
break ;
case TEV_ZTEX_TYPE_U16 :
2013-11-23 12:58:24 -07:00
constants . zbias [ 0 ] [ 0 ] = 1 ;
2013-10-07 13:57:18 -06:00
constants . zbias [ 0 ] [ 1 ] = 0 ;
constants . zbias [ 0 ] [ 2 ] = 0 ;
2013-11-23 12:58:24 -07:00
constants . zbias [ 0 ] [ 3 ] = 256 ;
2013-10-07 13:57:18 -06:00
break ;
case TEV_ZTEX_TYPE_U24 :
2013-11-23 12:58:24 -07:00
constants . zbias [ 0 ] [ 0 ] = 65536 ;
constants . zbias [ 0 ] [ 1 ] = 256 ;
constants . zbias [ 0 ] [ 2 ] = 1 ;
2013-10-07 13:57:18 -06:00
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 ] ;
2013-11-13 02:03:46 -07: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 13:57:18 -06:00
dirty = true ;
2008-12-07 22:25:12 -07:00
}
2009-02-18 21:41:58 -07:00
void PixelShaderManager : : SetFogColorChanged ( )
{
2013-10-27 06:10:00 -06:00
constants . fogcolor [ 0 ] = bpmem . fog . color . r ;
constants . fogcolor [ 1 ] = bpmem . fog . color . g ;
constants . fogcolor [ 2 ] = bpmem . fog . color . b ;
2013-10-07 13:57:18 -06:00
dirty = true ;
2009-02-18 21:41:58 -07:00
}
void PixelShaderManager : : SetFogParamChanged ( )
{
2014-03-10 05:30:55 -06:00
if ( ! g_ActiveConfig . bDisableFog )
2013-10-07 13:57:18 -06:00
{
2013-12-16 05:08:09 -07:00
constants . fogf [ 1 ] [ 0 ] = bpmem . fog . a . GetA ( ) ;
constants . fogi [ 0 ] [ 1 ] = bpmem . fog . b_magnitude ;
constants . fogf [ 1 ] [ 2 ] = bpmem . fog . c_proj_fsel . GetC ( ) ;
constants . fogi [ 0 ] [ 3 ] = bpmem . fog . b_shift ;
2013-10-07 13:57:18 -06:00
}
else
{
2013-12-16 05:08:09 -07:00
constants . fogf [ 1 ] [ 0 ] = 0.f ;
constants . fogi [ 0 ] [ 1 ] = 1 ;
constants . fogf [ 1 ] [ 2 ] = 0.f ;
constants . fogi [ 0 ] [ 3 ] = 1 ;
2013-10-07 13:57:18 -06:00
}
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
{
2014-03-10 05:30:55 -06:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2013-10-07 13:57:18 -06:00
{
2013-10-27 07:07:13 -06:00
constants . pmaterials [ index ] [ 0 ] = ( color > > 24 ) & 0xFF ;
constants . pmaterials [ index ] [ 1 ] = ( color > > 16 ) & 0xFF ;
constants . pmaterials [ index ] [ 2 ] = ( color > > 8 ) & 0xFF ;
constants . pmaterials [ index ] [ 3 ] = ( color ) & 0xFF ;
2013-10-07 13:57:18 -06:00
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 ) ;
2013-10-28 23:23:17 -06:00
2012-01-01 13:46:02 -07:00
if ( p . GetMode ( ) = = PointerWrap : : MODE_READ )
{
Dirty ( ) ;
}
}