2013-04-18 03:09:55 +00:00
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2008-12-08 05:30:24 +00:00
2014-02-19 01:27:20 +00:00
# include <cassert>
2008-12-08 05:30:24 +00:00
# include <cmath>
2014-02-17 10:18:15 +00:00
# include <cstdio>
2009-10-14 01:58:39 +00:00
# include <locale.h>
2013-06-15 11:21:57 +00:00
# ifdef __APPLE__
# include <xlocale.h>
# endif
2008-12-08 05:30:24 +00:00
2014-02-17 10:18:15 +00:00
# include "VideoCommon/BPMemory.h"
# include "VideoCommon/LightingShaderGen.h"
# include "VideoCommon/NativeVertexFormat.h"
# include "VideoCommon/PixelShaderGen.h"
# include "VideoCommon/VideoConfig.h"
# include "VideoCommon/XFMemory.h" // for texture projection mode
2012-08-10 16:57:37 +00:00
2013-01-08 15:40:15 +00:00
2014-02-28 19:34:09 +00:00
static const char * tevKSelTableC [ ] =
2008-12-08 05:30:24 +00:00
{
2013-08-14 14:25:39 +00:00
" 255,255,255 " , // 1 = 0x00
" 223,223,223 " , // 7_8 = 0x01
" 191,191,191 " , // 3_4 = 0x02
" 159,159,159 " , // 5_8 = 0x03
" 127,127,127 " , // 1_2 = 0x04
" 95,95,95 " , // 3_8 = 0x05
" 63,63,63 " , // 1_4 = 0x06
" 31,31,31 " , // 1_8 = 0x07
2013-01-11 14:47:38 +00:00
" ERROR1 " , // 0x08
" ERROR2 " , // 0x09
" ERROR3 " , // 0x0a
" ERROR4 " , // 0x0b
2013-10-10 18:26:41 +00:00
I_KCOLORS " [0].rgb " , // K0 = 0x0C
I_KCOLORS " [1].rgb " , // K1 = 0x0D
I_KCOLORS " [2].rgb " , // K2 = 0x0E
I_KCOLORS " [3].rgb " , // K3 = 0x0F
I_KCOLORS " [0].rrr " , // K0_R = 0x10
I_KCOLORS " [1].rrr " , // K1_R = 0x11
I_KCOLORS " [2].rrr " , // K2_R = 0x12
I_KCOLORS " [3].rrr " , // K3_R = 0x13
I_KCOLORS " [0].ggg " , // K0_G = 0x14
I_KCOLORS " [1].ggg " , // K1_G = 0x15
I_KCOLORS " [2].ggg " , // K2_G = 0x16
I_KCOLORS " [3].ggg " , // K3_G = 0x17
I_KCOLORS " [0].bbb " , // K0_B = 0x18
I_KCOLORS " [1].bbb " , // K1_B = 0x19
I_KCOLORS " [2].bbb " , // K2_B = 0x1A
I_KCOLORS " [3].bbb " , // K3_B = 0x1B
I_KCOLORS " [0].aaa " , // K0_A = 0x1C
I_KCOLORS " [1].aaa " , // K1_A = 0x1D
I_KCOLORS " [2].aaa " , // K2_A = 0x1E
I_KCOLORS " [3].aaa " , // K3_A = 0x1F
2008-12-08 05:30:24 +00:00
} ;
2014-02-28 19:34:09 +00:00
static const char * tevKSelTableA [ ] =
2008-12-08 05:30:24 +00:00
{
2013-08-14 14:25:39 +00:00
" 255 " , // 1 = 0x00
" 223 " , // 7_8 = 0x01
" 191 " , // 3_4 = 0x02
" 159 " , // 5_8 = 0x03
" 127 " , // 1_2 = 0x04
" 95 " , // 3_8 = 0x05
" 63 " , // 1_4 = 0x06
" 31 " , // 1_8 = 0x07
2013-01-11 14:47:38 +00:00
" ERROR5 " , // 0x08
" ERROR6 " , // 0x09
" ERROR7 " , // 0x0a
" ERROR8 " , // 0x0b
" ERROR9 " , // 0x0c
" ERROR10 " , // 0x0d
" ERROR11 " , // 0x0e
" ERROR12 " , // 0x0f
2013-10-10 18:26:41 +00:00
I_KCOLORS " [0].r " , // K0_R = 0x10
I_KCOLORS " [1].r " , // K1_R = 0x11
I_KCOLORS " [2].r " , // K2_R = 0x12
I_KCOLORS " [3].r " , // K3_R = 0x13
I_KCOLORS " [0].g " , // K0_G = 0x14
I_KCOLORS " [1].g " , // K1_G = 0x15
I_KCOLORS " [2].g " , // K2_G = 0x16
I_KCOLORS " [3].g " , // K3_G = 0x17
I_KCOLORS " [0].b " , // K0_B = 0x18
I_KCOLORS " [1].b " , // K1_B = 0x19
I_KCOLORS " [2].b " , // K2_B = 0x1A
I_KCOLORS " [3].b " , // K3_B = 0x1B
I_KCOLORS " [0].a " , // K0_A = 0x1C
I_KCOLORS " [1].a " , // K1_A = 0x1D
I_KCOLORS " [2].a " , // K2_A = 0x1E
I_KCOLORS " [3].a " , // K3_A = 0x1F
2008-12-08 05:30:24 +00:00
} ;
2014-02-28 19:34:09 +00:00
static const char * tevCInputTable [ ] =
2008-12-08 05:30:24 +00:00
{
2014-03-06 18:28:29 +00:00
" prev.rgb " , // CPREV,
" prev.aaa " , // APREV,
" c0.rgb " , // C0,
" c0.aaa " , // A0,
" c1.rgb " , // C1,
" c1.aaa " , // A1,
" c2.rgb " , // C2,
" c2.aaa " , // A2,
" textemp.rgb " , // TEXC,
" textemp.aaa " , // TEXA,
" rastemp.rgb " , // RASC,
" rastemp.aaa " , // RASA,
2013-08-14 15:26:15 +00:00
" int3(255,255,255) " , // ONE
" int3(127,127,127) " , // HALF
2014-03-06 18:28:29 +00:00
" konsttemp.rgb " , // KONST
2013-08-14 15:26:15 +00:00
" int3(0,0,0) " , // ZERO
2008-12-08 05:30:24 +00:00
} ;
2014-02-28 19:34:09 +00:00
static const char * tevAInputTable [ ] =
2008-12-08 05:30:24 +00:00
{
2014-03-24 13:41:56 +00:00
" prev.a " , // APREV,
" c0.a " , // A0,
" c1.a " , // A1,
" c2.a " , // A2,
" textemp.a " , // TEXA,
" rastemp.a " , // RASA,
" konsttemp.a " , // KONST, (hw1 had quarter)
" 0 " , // ZERO
2010-07-06 13:14:51 +00:00
} ;
2008-12-08 05:30:24 +00:00
static const char * tevRasTable [ ] =
{
2013-08-14 14:16:06 +00:00
" int4(round(colors_0 * 255.0)) " ,
" int4(round(colors_1 * 255.0)) " ,
2013-01-11 14:47:38 +00:00
" ERROR13 " , //2
" ERROR14 " , //3
" ERROR15 " , //4
2014-02-28 19:43:43 +00:00
" (int4(1, 1, 1, 1) * alphabump) " , // bump alpha (0..248)
" (int4(1, 1, 1, 1) * (alphabump | (alphabump >> 5))) " , // normalized bump alpha (0..255)
2013-08-14 14:16:06 +00:00
" int4(0, 0, 0, 0) " , // zero
2008-12-08 05:30:24 +00:00
} ;
2014-03-06 18:27:11 +00:00
static const char * tevCOutputTable [ ] = { " prev.rgb " , " c0.rgb " , " c1.rgb " , " c2.rgb " } ;
static const char * tevAOutputTable [ ] = { " prev.a " , " c0.a " , " c1.a " , " c2.a " } ;
2008-12-08 05:30:24 +00:00
2013-06-17 09:37:41 +00:00
static char text [ 16384 ] ;
2012-08-11 14:54:46 +00:00
2013-08-14 16:24:47 +00:00
template < class T > static inline void WriteStage ( T & out , pixel_shader_uid_data & uid_data , int n , API_TYPE ApiType , const char swapModeTable [ 4 ] [ 5 ] ) ;
2014-03-24 13:41:56 +00:00
template < class T > static inline void WriteTevRegular ( T & out , const char * components , int bias , int op , int clamp , int shift ) ;
2013-08-12 10:52:28 +00:00
template < class T > static inline void SampleTexture ( T & out , const char * texcoords , const char * texswap , int texmap , API_TYPE ApiType ) ;
template < class T > static inline void WriteAlphaTest ( T & out , pixel_shader_uid_data & uid_data , API_TYPE ApiType , DSTALPHA_MODE dstAlphaMode , bool per_pixel_depth ) ;
template < class T > static inline void WriteFog ( T & out , pixel_shader_uid_data & uid_data ) ;
2013-06-17 09:37:41 +00:00
2013-03-26 22:21:08 +00:00
template < class T >
2013-08-12 10:52:28 +00:00
static inline void GeneratePixelShader ( T & out , DSTALPHA_MODE dstAlphaMode , API_TYPE ApiType , u32 components )
2008-12-08 05:30:24 +00:00
{
2013-03-29 20:53:57 +00:00
// Non-uid template parameters will write to the dummy data (=> gets optimized out)
pixel_shader_uid_data dummy_data ;
2014-03-09 20:14:26 +00:00
pixel_shader_uid_data & uid_data = ( & out . template GetUidData < pixel_shader_uid_data > ( ) ! = nullptr )
2013-03-29 21:24:49 +00:00
? out . template GetUidData < pixel_shader_uid_data > ( ) : dummy_data ;
2013-03-29 20:53:57 +00:00
2013-03-29 19:33:28 +00:00
out . SetBuffer ( text ) ;
2014-03-09 20:14:26 +00:00
const bool is_writing_shadercode = ( out . GetBuffer ( ) ! = nullptr ) ;
2013-06-16 12:34:23 +00:00
# ifndef ANDROID
2013-06-17 10:05:47 +00:00
locale_t locale ;
locale_t old_locale ;
2013-08-12 11:31:29 +00:00
if ( is_writing_shadercode )
2013-06-17 10:05:47 +00:00
{
2014-03-09 20:14:26 +00:00
locale = newlocale ( LC_NUMERIC_MASK , " C " , nullptr ) ; // New locale for compilation
2013-06-17 10:05:47 +00:00
old_locale = uselocale ( locale ) ; // Apply the locale for this thread
}
2013-06-16 12:34:23 +00:00
# endif
2013-03-29 19:33:28 +00:00
2013-08-12 11:31:29 +00:00
if ( is_writing_shadercode )
text [ sizeof ( text ) - 1 ] = 0x7C ; // canary
2008-12-08 05:30:24 +00:00
2012-08-06 23:02:04 +00:00
unsigned int numStages = bpmem . genMode . numtevstages + 1 ;
unsigned int numTexgen = bpmem . genMode . numtexgens ;
2008-12-08 05:30:24 +00:00
2013-07-22 12:38:09 +00:00
const bool forced_early_z = g_ActiveConfig . backend_info . bSupportsEarlyZ & & bpmem . UseEarlyDepthTest ( ) & & ( g_ActiveConfig . bFastDepthCalc | | bpmem . alpha_test . TestResult ( ) = = AlphaTest : : UNDETERMINED ) ;
2013-08-12 09:33:36 +00:00
const bool per_pixel_depth = ( bpmem . ztex2 . op ! = ZTEXTURE_DISABLE & & bpmem . UseLateDepthTest ( ) ) | | ( ! g_ActiveConfig . bFastDepthCalc & & bpmem . zmode . testenable & & ! forced_early_z ) ;
2011-12-08 07:51:08 +00:00
2012-08-06 23:02:04 +00:00
out . Write ( " //Pixel Shader for TEV stages \n " ) ;
2013-04-29 17:52:12 +00:00
out . Write ( " //%i TEV stages, %i texgens, %i IND stages \n " ,
numStages , numTexgen , bpmem . genMode . numindstages ) ;
2008-12-08 05:30:24 +00:00
2013-03-29 20:53:57 +00:00
uid_data . dstAlphaMode = dstAlphaMode ;
2013-05-01 09:39:30 +00:00
uid_data . genMode_numindstages = bpmem . genMode . numindstages ;
uid_data . genMode_numtevstages = bpmem . genMode . numtevstages ;
uid_data . genMode_numtexgens = bpmem . genMode . numtexgens ;
2012-08-06 23:02:04 +00:00
2013-10-08 01:04:41 +00:00
// dot product for integer vectors
2014-03-06 18:21:03 +00:00
out . Write ( " int idot(int3 x, int3 y) \n "
2014-03-06 19:08:47 +00:00
" { \n "
" \t int3 tmp = x * y; \n "
" \t return tmp.x + tmp.y + tmp.z; \n "
" } \n " ) ;
2014-03-06 18:21:03 +00:00
out . Write ( " int idot(int4 x, int4 y) \n "
2014-03-06 19:08:47 +00:00
" { \n "
" \t int4 tmp = x * y; \n "
" \t return tmp.x + tmp.y + tmp.z + tmp.w; \n "
" } \n \n " ) ;
2013-10-08 01:04:41 +00:00
2012-12-28 04:46:29 +00:00
if ( ApiType = = API_OPENGL )
2010-08-29 19:34:54 +00:00
{
2012-12-28 20:18:39 +00:00
// Fmod implementation gleaned from Nvidia
// At http://http.developer.nvidia.com/Cg/fmod.html
2013-03-26 21:16:29 +00:00
out . Write ( " float fmod( float x, float y ) \n " ) ;
out . Write ( " { \n " ) ;
out . Write ( " \t float z = fract( abs( x / y) ) * abs( y ); \n " ) ;
2013-06-17 10:51:57 +00:00
out . Write ( " \t return (x < 0.0) ? -z : z; \n " ) ;
2013-06-17 10:05:47 +00:00
out . Write ( " } \n " ) ;
2011-12-11 13:02:13 +00:00
2013-03-26 21:16:29 +00:00
// Declare samplers
2010-07-06 13:14:51 +00:00
for ( int i = 0 ; i < 8 ; + + i )
2013-03-26 21:16:29 +00:00
out . Write ( " uniform sampler2D samp%d; \n " , i ) ;
2010-07-06 13:14:51 +00:00
}
2013-09-22 16:07:21 +00:00
else // D3D
2010-09-23 02:17:48 +00:00
{
2011-12-08 07:51:08 +00:00
// Declare samplers
for ( int i = 0 ; i < 8 ; + + i )
2013-09-22 16:07:21 +00:00
out . Write ( " sampler samp%d : register(s%d); \n " , i , i ) ;
2013-03-26 21:16:29 +00:00
2013-09-22 16:07:21 +00:00
out . Write ( " \n " ) ;
for ( int i = 0 ; i < 8 ; + + i )
out . Write ( " Texture2D Tex%d : register(t%d); \n " , i , i ) ;
2010-09-23 02:17:48 +00:00
}
2013-03-26 21:16:29 +00:00
out . Write ( " \n " ) ;
2010-06-14 14:36:01 +00:00
2014-01-30 15:38:11 +00:00
if ( ApiType = = API_OPENGL )
2014-01-05 09:38:45 +00:00
out . Write ( " layout(std140%s) uniform PSBlock { \n " , g_ActiveConfig . backend_info . bSupportShadingLanguage420pack ? " , binding = 1 " : " " ) ;
2013-03-26 21:16:29 +00:00
2013-10-10 18:26:41 +00:00
DeclareUniform ( out , ApiType , C_COLORS , " int4 " , I_COLORS " [4] " ) ;
DeclareUniform ( out , ApiType , C_KCOLORS , " int4 " , I_KCOLORS " [4] " ) ;
2013-11-23 19:58:24 +00:00
DeclareUniform ( out , ApiType , C_ALPHA , " int4 " , I_ALPHA ) ;
2014-01-30 15:38:11 +00:00
DeclareUniform ( out , ApiType , C_TEXDIMS , " float4 " , I_TEXDIMS " [8] " ) ;
2013-11-23 19:58:24 +00:00
DeclareUniform ( out , ApiType , C_ZBIAS , " int4 " , I_ZBIAS " [2] " ) ;
2014-01-29 14:52:24 +00:00
DeclareUniform ( out , ApiType , C_INDTEXSCALE , " int4 " , I_INDTEXSCALE " [2] " ) ;
2013-10-10 19:09:00 +00:00
DeclareUniform ( out , ApiType , C_INDTEXMTX , " int4 " , I_INDTEXMTX " [6] " ) ;
2013-10-27 12:10:00 +00:00
DeclareUniform ( out , ApiType , C_FOGCOLOR , " int4 " , I_FOGCOLOR ) ;
2014-03-03 18:23:46 +00:00
DeclareUniform ( out , ApiType , C_FOGI , " int4 " , I_FOGI ) ;
2013-12-16 12:08:09 +00:00
DeclareUniform ( out , ApiType , C_FOGF , " float4 " , I_FOGF " [2] " ) ;
2013-03-31 21:29:33 +00:00
2013-03-26 21:16:29 +00:00
// For pixel lighting - TODO: Should only be defined when per pixel lighting is enabled!
2013-10-27 12:57:40 +00:00
DeclareUniform ( out , ApiType , C_PLIGHT_COLORS , " int4 " , I_PLIGHT_COLORS " [8] " ) ;
DeclareUniform ( out , ApiType , C_PLIGHTS , " float4 " , I_PLIGHTS " [32] " ) ;
2013-10-27 13:07:13 +00:00
DeclareUniform ( out , ApiType , C_PMATERIALS , " int4 " , I_PMATERIALS " [4] " ) ;
2013-03-31 21:29:33 +00:00
2014-01-30 15:38:11 +00:00
if ( ApiType = = API_OPENGL )
2013-03-26 21:16:29 +00:00
out . Write ( " }; \n " ) ;
2011-06-04 19:56:18 +00:00
2012-12-28 20:18:39 +00:00
if ( ApiType = = API_OPENGL )
2010-10-21 05:22:18 +00:00
{
2013-11-25 00:06:29 +00:00
out . Write ( " out vec4 ocol0; \n " ) ;
2011-12-26 05:15:54 +00:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2013-09-03 18:56:24 +00:00
out . Write ( " out vec4 ocol1; \n " ) ;
2013-04-25 12:01:07 +00:00
2013-03-15 16:19:52 +00:00
if ( per_pixel_depth )
2013-03-26 21:16:29 +00:00
out . Write ( " #define depth gl_FragDepth \n " ) ;
2008-12-08 05:30:24 +00:00
2014-02-25 14:52:22 +00:00
out . Write ( " centroid in float4 colors_02; \n " ) ;
out . Write ( " centroid in float4 colors_12; \n " ) ;
2013-08-12 16:21:35 +00:00
2011-12-01 03:00:21 +00:00
// compute window position if needed because binding semantic WPOS is not widely supported
2013-03-31 21:29:33 +00:00
// Let's set up attributes
2013-11-13 09:03:46 +00:00
for ( unsigned int i = 0 ; i < xfregs . numTexGen . numTexGens ; + + i )
{
2014-02-25 14:52:22 +00:00
out . Write ( " centroid in float3 uv%d_2; \n " , i ) ;
2013-11-13 09:03:46 +00:00
}
2014-02-25 14:52:22 +00:00
out . Write ( " centroid in float4 clipPos_2; \n " ) ;
2013-10-15 12:38:26 +00:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2010-11-24 19:13:19 +00:00
{
2014-02-25 14:52:22 +00:00
out . Write ( " centroid in float4 Normal_2; \n " ) ;
2010-11-24 19:13:19 +00:00
}
2013-07-22 12:38:09 +00:00
2013-07-22 10:02:16 +00:00
if ( forced_early_z )
{
// HACK: This doesn't force the driver to write to depth buffer if alpha test fails.
// It just allows it, but it seems that all drivers do.
out . Write ( " layout(early_fragment_tests) in; \n " ) ;
}
2013-08-12 11:31:29 +00:00
else if ( bpmem . UseEarlyDepthTest ( ) & & ( g_ActiveConfig . bFastDepthCalc | | bpmem . alpha_test . TestResult ( ) = = AlphaTest : : UNDETERMINED ) & & is_writing_shadercode )
2013-07-22 12:38:09 +00:00
{
static bool warn_once = true ;
if ( warn_once )
2013-10-06 11:37:10 +00:00
WARN_LOG ( VIDEO , " Early z test enabled but not possible to emulate with current configuration. Make sure to enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU with D3D 11.0 / OGL 4.2 support is required). " ) ;
2013-07-22 12:38:09 +00:00
warn_once = false ;
}
2013-03-26 21:16:29 +00:00
out . Write ( " void main() \n { \n " ) ;
2010-10-21 05:22:18 +00:00
}
2013-09-22 16:07:21 +00:00
else // D3D
2010-10-21 05:22:18 +00:00
{
2013-07-22 12:38:09 +00:00
if ( forced_early_z )
{
out . Write ( " [earlydepthstencil] \n " ) ;
}
2013-08-12 11:31:29 +00:00
else if ( bpmem . UseEarlyDepthTest ( ) & & ( g_ActiveConfig . bFastDepthCalc | | bpmem . alpha_test . TestResult ( ) = = AlphaTest : : UNDETERMINED ) & & is_writing_shadercode )
2013-07-22 12:38:09 +00:00
{
static bool warn_once = true ;
if ( warn_once )
2013-10-06 11:37:10 +00:00
WARN_LOG ( VIDEO , " Early z test enabled but not possible to emulate with current configuration. Make sure to enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU with D3D 11.0 / OGL 4.2 support is required). " ) ;
2013-07-22 12:38:09 +00:00
warn_once = false ;
}
2013-03-26 21:16:29 +00:00
out . Write ( " void main( \n " ) ;
2013-09-22 16:07:21 +00:00
out . Write ( " out float4 ocol0 : SV_Target0,%s%s \n in float4 rawpos : SV_Position, \n " ,
dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND ? " \n out float4 ocol1 : SV_Target1, " : " " ,
per_pixel_depth ? " \n out float depth : SV_Depth, " : " " ) ;
2011-06-04 19:56:18 +00:00
2013-09-22 16:07:21 +00:00
// Use centroid sampling to make MSAA work properly
const char * optCentroid = " centroid " ;
2013-04-07 18:58:48 +00:00
2013-04-25 12:01:07 +00:00
out . Write ( " in %s float4 colors_0 : COLOR0, \n " , optCentroid ) ;
out . Write ( " in %s float4 colors_1 : COLOR1 " , optCentroid ) ;
2008-12-08 05:30:24 +00:00
2012-12-28 20:18:39 +00:00
// compute window position if needed because binding semantic WPOS is not widely supported
2013-10-15 12:48:40 +00:00
for ( unsigned int i = 0 ; i < numTexgen ; + + i )
out . Write ( " , \n in %s float3 uv%d : TEXCOORD%d " , optCentroid , i , i ) ;
out . Write ( " , \n in %s float4 clipPos : TEXCOORD%d " , optCentroid , numTexgen ) ;
2014-03-10 11:30:55 +00:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2013-10-15 12:48:40 +00:00
out . Write ( " , \n in %s float4 Normal : TEXCOORD%d " , optCentroid , numTexgen + 1 ) ;
out . Write ( " ) { \n " ) ;
2009-02-19 04:41:58 +00:00
}
2012-08-10 16:57:37 +00:00
2014-03-06 18:27:11 +00:00
out . Write ( " \t int4 c0 = " I_COLORS " [1], c1 = " I_COLORS " [2], c2 = " I_COLORS " [3], prev = " I_COLORS " [0]; \n "
2014-03-06 19:08:47 +00:00
" \t int4 rastemp = int4(0, 0, 0, 0), textemp = int4(0, 0, 0, 0), konsttemp = int4(0, 0, 0, 0); \n "
" \t int3 comp16 = int3(1, 256, 0), comp24 = int3(1, 256, 256*256); \n "
" \t int alphabump=0; \n "
" \t int3 tevcoord=int3(0, 0, 0); \n "
2014-03-20 19:34:51 +00:00
" \t int2 wrappedcoord=int2(0,0), tempcoord=int2(0,0); \n "
" \t int4 tevin_a=int4(0,0,0,0),tevin_b=int4(0,0,0,0),tevin_c=int4(0,0,0,0),tevin_d=int4(0,0,0,0); \n \n " ) ; // tev combiner inputs
2011-06-04 19:56:18 +00:00
2013-07-25 16:13:33 +00:00
if ( ApiType = = API_OPENGL )
{
// On Mali, global variables must be initialized as constants.
// This is why we initialize these variables locally instead.
2014-03-01 13:08:45 +00:00
out . Write ( " \t float4 rawpos = gl_FragCoord; \n " ) ;
out . Write ( " \t float4 colors_0 = colors_02; \n " ) ;
out . Write ( " \t float4 colors_1 = colors_12; \n " ) ;
2013-07-25 16:13:33 +00:00
// compute window position if needed because binding semantic WPOS is not widely supported
// Let's set up attributes
2013-11-13 09:03:46 +00:00
if ( numTexgen )
{
for ( unsigned int i = 0 ; i < xfregs . numTexGen . numTexGens ; + + i )
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t float3 uv%d = uv%d_2; \n " , i , i ) ;
2013-11-13 09:03:46 +00:00
}
}
2014-03-01 13:08:45 +00:00
out . Write ( " \t float4 clipPos = clipPos_2; \n " ) ;
2013-10-15 12:38:26 +00:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2013-07-25 16:13:33 +00:00
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t float4 Normal = Normal_2; \n " ) ;
2013-07-25 16:13:33 +00:00
}
}
2011-12-26 05:15:54 +00:00
if ( g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting )
2010-09-23 02:17:48 +00:00
{
2013-10-15 12:38:26 +00:00
out . Write ( " \t float3 _norm0 = normalize(Normal.xyz); \n \n " ) ;
out . Write ( " \t float3 pos = float3(clipPos.x,clipPos.y,Normal.w); \n " ) ;
2010-09-23 02:17:48 +00:00
2013-10-27 13:43:29 +00:00
out . Write ( " \t int4 lacc; \n "
2013-03-26 21:16:29 +00:00
" \t float3 ldir, h; \n "
" \t float dist, dist2, attn; \n " ) ;
2013-03-31 21:29:33 +00:00
2013-10-27 12:57:40 +00:00
out . SetConstantsUsed ( C_PLIGHT_COLORS , C_PLIGHT_COLORS + 7 ) ; // TODO: Can be optimized further
out . SetConstantsUsed ( C_PLIGHTS , C_PLIGHTS + 31 ) ; // TODO: Can be optimized further
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_PMATERIALS , C_PMATERIALS + 3 ) ;
2013-03-31 21:57:39 +00:00
uid_data . components = components ;
2013-10-27 12:57:40 +00:00
GenerateLightingShader < T > ( out , uid_data . lighting , components , I_PMATERIALS , I_PLIGHT_COLORS , I_PLIGHTS , " colors_ " , " colors_ " ) ;
2010-09-23 02:17:48 +00:00
}
2009-04-15 03:55:38 +00:00
2013-10-15 12:38:26 +00:00
out . Write ( " \t clipPos = float4(rawpos.x, rawpos.y, clipPos.z, clipPos.w); \n " ) ;
2011-06-04 19:56:18 +00:00
2010-01-12 03:39:14 +00:00
// HACK to handle cases where the tex gen is not enabled
2010-07-06 13:14:51 +00:00
if ( numTexgen = = 0 )
2010-01-12 03:39:14 +00:00
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 fixpoint_uv0 = int2(0, 0); \n \n " ) ;
2010-01-12 03:39:14 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_TEXDIMS , C_TEXDIMS + numTexgen - 1 ) ;
2012-08-06 23:02:04 +00:00
for ( unsigned int i = 0 ; i < numTexgen ; + + i )
2010-01-12 03:39:14 +00:00
{
// optional perspective divides
2013-05-01 09:39:30 +00:00
uid_data . texMtxInfo_n_projection | = xfregs . texMtxInfo [ i ] . projection < < i ;
2011-02-05 18:25:34 +00:00
if ( xfregs . texMtxInfo [ i ] . projection = = XF_TEXPROJ_STQ )
2010-12-01 04:26:21 +00:00
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t if (uv%d.z != 0.0) \n " , i ) ;
2013-03-26 21:16:29 +00:00
out . Write ( " \t \t uv%d.xy = uv%d.xy / uv%d.z; \n " , i , i , i ) ;
2010-12-01 04:26:21 +00:00
}
2011-06-04 19:56:18 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 fixpoint_uv%d = int2(round(uv%d.xy * " I_TEXDIMS " [%d].zw * 128.0)); \n \n " , i , i , i ) ;
2014-01-29 14:28:22 +00:00
// TODO: S24 overflows here?
2010-01-12 03:39:14 +00:00
}
}
2008-12-08 05:30:24 +00:00
2010-07-06 13:14:51 +00:00
// indirect texture map lookup
2013-01-28 21:51:15 +00:00
int nIndirectStagesUsed = 0 ;
if ( bpmem . genMode . numindstages > 0 )
{
for ( unsigned int i = 0 ; i < numStages ; + + i )
{
if ( bpmem . tevind [ i ] . IsActive ( ) & & bpmem . tevind [ i ] . bt < bpmem . genMode . numindstages )
nIndirectStagesUsed | = 1 < < bpmem . tevind [ i ] . bt ;
}
}
2013-03-29 20:53:57 +00:00
uid_data . nIndirectStagesUsed = nIndirectStagesUsed ;
2011-12-26 05:15:54 +00:00
for ( u32 i = 0 ; i < bpmem . genMode . numindstages ; + + i )
2009-07-26 09:52:35 +00:00
{
2013-01-28 21:51:15 +00:00
if ( nIndirectStagesUsed & ( 1 < < i ) )
2009-07-26 09:52:35 +00:00
{
2012-08-06 23:16:02 +00:00
unsigned int texcoord = bpmem . tevindref . getTexCoord ( i ) ;
unsigned int texmap = bpmem . tevindref . getTexMap ( i ) ;
2008-12-08 05:30:24 +00:00
2013-05-01 09:39:30 +00:00
uid_data . SetTevindrefValues ( i , texcoord , texmap ) ;
2011-01-09 14:13:24 +00:00
if ( texcoord < numTexgen )
2012-09-02 18:00:15 +00:00
{
out . SetConstantsUsed ( C_INDTEXSCALE + i / 2 , C_INDTEXSCALE + i / 2 ) ;
2014-01-29 14:52:24 +00:00
out . Write ( " \t tempcoord = fixpoint_uv%d >> " I_INDTEXSCALE " [%d].%s; \n " , texcoord , i / 2 , ( i & 1 ) ? " zw " : " xy " ) ;
2012-09-02 18:00:15 +00:00
}
2010-07-06 13:14:51 +00:00
else
2014-01-29 14:52:24 +00:00
out . Write ( " \t tempcoord = int2(0, 0); \n " ) ;
2009-04-11 07:05:57 +00:00
2013-08-14 13:40:24 +00:00
out . Write ( " \t int3 iindtex%d = " , i ) ;
2014-01-29 14:52:24 +00:00
SampleTexture < T > ( out , " (float2(tempcoord)/128.0) " , " abg " , texmap , ApiType ) ;
2010-07-06 13:14:51 +00:00
}
}
2008-12-08 05:30:24 +00:00
2012-09-02 12:31:37 +00:00
// Uid fields for BuildSwapModeTable are set in WriteStage
2013-09-04 19:56:03 +00:00
char swapModeTable [ 4 ] [ 5 ] ;
const char * swapColors = " rgba " ;
for ( int i = 0 ; i < 4 ; i + + )
{
swapModeTable [ i ] [ 0 ] = swapColors [ bpmem . tevksel [ i * 2 ] . swap1 ] ;
swapModeTable [ i ] [ 1 ] = swapColors [ bpmem . tevksel [ i * 2 ] . swap2 ] ;
swapModeTable [ i ] [ 2 ] = swapColors [ bpmem . tevksel [ i * 2 + 1 ] . swap1 ] ;
swapModeTable [ i ] [ 3 ] = swapColors [ bpmem . tevksel [ i * 2 + 1 ] . swap2 ] ;
swapModeTable [ i ] [ 4 ] = ' \0 ' ;
}
2012-08-06 23:02:04 +00:00
for ( unsigned int i = 0 ; i < numStages ; i + + )
2013-08-14 16:24:47 +00:00
WriteStage < T > ( out , uid_data , i , ApiType , swapModeTable ) ; // build the equation for this stage
2010-06-29 14:40:37 +00:00
2013-06-22 19:24:21 +00:00
# define MY_STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str)))
bool enable_pl = g_ActiveConfig . bEnablePixelLighting & & g_ActiveConfig . backend_info . bSupportsPixelLighting ;
2013-07-02 12:32:52 +00:00
uid_data . num_values = ( enable_pl ) ? sizeof ( uid_data ) : MY_STRUCT_OFFSET ( uid_data , stagehash [ numStages ] ) ;
2013-06-22 19:24:21 +00:00
2011-12-26 05:15:54 +00:00
if ( numStages )
2010-05-22 19:55:07 +00:00
{
// The results of the last texenv stage are put onto the screen,
// regardless of the used destination register
2014-03-10 11:30:55 +00:00
if ( bpmem . combiners [ numStages - 1 ] . colorC . dest ! = 0 )
2012-08-11 14:54:46 +00:00
{
2014-03-06 18:27:11 +00:00
out . Write ( " \t prev.rgb = %s; \n " , tevCOutputTable [ bpmem . combiners [ numStages - 1 ] . colorC . dest ] ) ;
2012-08-11 14:54:46 +00:00
}
2014-03-10 11:30:55 +00:00
if ( bpmem . combiners [ numStages - 1 ] . alphaC . dest ! = 0 )
2012-08-11 14:54:46 +00:00
{
2014-03-06 18:27:11 +00:00
out . Write ( " \t prev.a = %s; \n " , tevAOutputTable [ bpmem . combiners [ numStages - 1 ] . alphaC . dest ] ) ;
2012-08-11 14:54:46 +00:00
}
2010-05-22 19:55:07 +00:00
}
2014-03-06 18:27:11 +00:00
out . Write ( " \t prev = prev & 255; \n " ) ;
2011-06-04 19:56:18 +00:00
2013-01-08 16:18:45 +00:00
AlphaTest : : TEST_RESULT Pretest = bpmem . alpha_test . TestResult ( ) ;
2013-03-29 20:53:57 +00:00
uid_data . Pretest = Pretest ;
2013-08-19 19:27:54 +00:00
2013-10-29 05:23:17 +00:00
// NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled
2013-08-19 19:27:54 +00:00
// (in this case we need to write a depth value if depth test passes regardless of the alpha testing result)
if ( Pretest = = AlphaTest : : UNDETERMINED | | ( Pretest = = AlphaTest : : FAIL & & bpmem . UseLateDepthTest ( ) ) )
2013-03-29 20:53:57 +00:00
WriteAlphaTest < T > ( out , uid_data , ApiType , dstAlphaMode , per_pixel_depth ) ;
2012-08-10 16:57:37 +00:00
2013-10-13 14:14:30 +00:00
// FastDepth means to trust the depth generated in perspective division.
2013-10-13 14:59:59 +00:00
// It should be correct, but it seems not to be as accurate as required. TODO: Find out why!
// For disabled FastDepth we just calculate the depth value again.
// The performance impact of this additional calculation doesn't matter, but it prevents
// the host GPU driver from performing any early depth test optimizations.
2013-09-22 16:07:21 +00:00
if ( g_ActiveConfig . bFastDepthCalc )
2014-03-01 17:25:21 +00:00
out . Write ( " \t int zCoord = int(round(rawpos.z * float(0xFFFFFF))); \n " ) ;
2013-03-04 19:12:58 +00:00
else
2013-03-26 21:16:29 +00:00
{
out . SetConstantsUsed ( C_ZBIAS + 1 , C_ZBIAS + 1 ) ;
2013-05-09 15:48:48 +00:00
// the screen space depth value = far z + (clip z / clip w) * z range
2014-03-01 13:08:45 +00:00
out . Write ( " \t int zCoord = " I_ZBIAS " [1].x + int(round((clipPos.z / clipPos.w) * float( " I_ZBIAS " [1].y))); \n " ) ;
2013-03-26 21:16:29 +00:00
}
2012-08-10 16:57:37 +00:00
2013-03-14 23:52:50 +00:00
// depth texture can safely be ignored if the result won't be written to the depth buffer (early_ztest) and isn't used for fog either
2013-06-17 10:51:57 +00:00
const bool skip_ztexture = ! per_pixel_depth & & ! bpmem . fog . c_proj_fsel . fsel ;
2013-06-17 10:05:47 +00:00
2013-04-29 17:37:32 +00:00
uid_data . ztex_op = bpmem . ztex2 . op ;
2013-03-29 20:53:57 +00:00
uid_data . per_pixel_depth = per_pixel_depth ;
2013-07-22 10:02:16 +00:00
uid_data . forced_early_z = forced_early_z ;
2013-06-17 10:51:57 +00:00
uid_data . fast_depth_calc = g_ActiveConfig . bFastDepthCalc ;
2013-07-22 12:38:09 +00:00
uid_data . early_ztest = bpmem . UseEarlyDepthTest ( ) ;
2013-05-01 09:39:30 +00:00
uid_data . fog_fsel = bpmem . fog . c_proj_fsel . fsel ;
2013-03-14 23:52:50 +00:00
2013-05-10 10:51:06 +00:00
// Note: z-textures are not written to depth buffer if early depth test is used
2013-07-22 12:38:09 +00:00
if ( per_pixel_depth & & bpmem . UseEarlyDepthTest ( ) )
2014-03-01 17:25:21 +00:00
out . Write ( " \t depth = float(zCoord) / float(0xFFFFFF); \n " ) ;
2013-06-17 10:05:47 +00:00
2013-06-29 21:14:08 +00:00
// Note: depth texture output is only written to depth buffer if late depth test is used
// theoretical final depth value is used for fog calculation, though, so we have to emulate ztextures anyway
2013-03-14 23:52:50 +00:00
if ( bpmem . ztex2 . op ! = ZTEXTURE_DISABLE & & ! skip_ztexture )
2012-03-25 03:01:47 +00:00
{
2014-03-06 18:27:11 +00:00
// use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format...
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_ZBIAS , C_ZBIAS + 1 ) ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t zCoord = idot( " I_ZBIAS " [0].xyzw, textemp.xyzw) + " I_ZBIAS " [1].w %s; \n " ,
2013-01-08 15:40:15 +00:00
( bpmem . ztex2 . op = = ZTEXTURE_ADD ) ? " + zCoord " : " " ) ;
2014-03-01 17:25:21 +00:00
out . Write ( " \t zCoord = zCoord & 0xFFFFFF; \n " ) ;
2012-08-10 16:57:37 +00:00
}
2013-06-29 21:14:08 +00:00
2013-07-22 12:38:09 +00:00
if ( per_pixel_depth & & bpmem . UseLateDepthTest ( ) )
2014-03-01 17:25:21 +00:00
out . Write ( " \t depth = float(zCoord) / float(0xFFFFFF); \n " ) ;
2010-10-20 03:11:22 +00:00
2012-08-10 16:57:37 +00:00
if ( dstAlphaMode = = DSTALPHA_ALPHA_PASS )
2012-09-02 18:00:15 +00:00
{
out . SetConstantsUsed ( C_ALPHA , C_ALPHA ) ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t ocol0 = float4(float3(prev.rgb), float( " I_ALPHA " .a)) / 255.0; \n " ) ;
2012-09-02 18:00:15 +00:00
}
2012-03-25 03:01:47 +00:00
else
{
2013-06-18 12:52:36 +00:00
WriteFog < T > ( out , uid_data ) ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t ocol0 = float4(prev) / 255.0; \n " ) ;
2010-07-06 13:14:51 +00:00
}
2012-03-25 03:01:47 +00:00
2013-04-25 12:01:07 +00:00
// Use dual-source color blending to perform dst alpha in a single pass
2012-08-10 16:57:37 +00:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2012-03-25 03:01:47 +00:00
{
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_ALPHA , C_ALPHA ) ;
2013-09-22 16:07:21 +00:00
// Colors will be blended against the alpha from ocol1 and
// the alpha from ocol0 will be written to the framebuffer.
2014-03-06 18:27:11 +00:00
out . Write ( " \t ocol1 = float4(prev) / 255.0; \n " ) ;
2013-10-10 18:36:55 +00:00
out . Write ( " \t ocol0.a = float( " I_ALPHA " .a) / 255.0; \n " ) ;
2012-03-25 03:01:47 +00:00
}
2013-04-25 12:01:07 +00:00
2012-08-06 23:02:04 +00:00
out . Write ( " } \n " ) ;
2013-03-29 20:53:57 +00:00
2013-08-12 11:31:29 +00:00
if ( is_writing_shadercode )
{
if ( text [ sizeof ( text ) - 1 ] ! = 0x7C )
PanicAlert ( " PixelShader generator - buffer too small, canary has been eaten! " ) ;
2009-07-26 09:52:35 +00:00
2013-06-16 12:34:23 +00:00
# ifndef ANDROID
2013-06-17 10:05:47 +00:00
uselocale ( old_locale ) ; // restore locale
freelocale ( locale ) ;
2013-06-16 12:34:23 +00:00
# endif
2013-08-12 11:31:29 +00:00
}
2008-12-08 05:30:24 +00:00
}
2009-10-29 03:28:38 +00:00
2013-03-26 22:21:08 +00:00
template < class T >
2013-08-14 16:24:47 +00:00
static inline void WriteStage ( T & out , pixel_shader_uid_data & uid_data , int n , API_TYPE ApiType , const char swapModeTable [ 4 ] [ 5 ] )
2008-12-08 05:30:24 +00:00
{
2010-07-06 13:14:51 +00:00
int texcoord = bpmem . tevorders [ n / 2 ] . getTexCoord ( n & 1 ) ;
bool bHasTexCoord = ( u32 ) texcoord < bpmem . genMode . numtexgens ;
bool bHasIndStage = bpmem . tevind [ n ] . IsActive ( ) & & bpmem . tevind [ n ] . bt < bpmem . genMode . numindstages ;
// HACK to handle cases where the tex gen is not enabled
if ( ! bHasTexCoord )
texcoord = 0 ;
2009-03-05 05:10:25 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t // TEV stage %d \n " , n ) ;
2011-09-29 19:52:13 +00:00
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . hasindstage = bHasIndStage ;
uid_data . stagehash [ n ] . tevorders_texcoord = texcoord ;
2010-07-06 13:14:51 +00:00
if ( bHasIndStage )
2009-07-26 09:52:35 +00:00
{
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . tevind = bpmem . tevind [ n ] . hex & 0x7FFFFF ;
2012-08-07 12:36:56 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t // indirect op \n " ) ;
2013-08-14 14:08:50 +00:00
// perform the indirect op on the incoming regular coordinates using iindtex%d as the offset coords
2010-07-06 13:14:51 +00:00
if ( bpmem . tevind [ n ] . bs ! = ITBA_OFF )
2009-07-26 09:52:35 +00:00
{
2013-09-12 11:55:38 +00:00
const char * tevIndAlphaSel [ ] = { " " , " x " , " y " , " z " } ;
2014-03-01 17:25:21 +00:00
const char * tevIndAlphaMask [ ] = { " 248 " , " 224 " , " 240 " , " 248 " } ; // 0b11111000, 0b11100000, 0b11110000, 0b11111000
2013-08-14 16:24:47 +00:00
out . Write ( " alphabump = iindtex%d.%s & %s; \n " ,
2011-06-04 19:56:18 +00:00
bpmem . tevind [ n ] . bt ,
tevIndAlphaSel [ bpmem . tevind [ n ] . bs ] ,
2013-08-14 14:08:50 +00:00
tevIndAlphaMask [ bpmem . tevind [ n ] . fmt ] ) ;
2010-07-06 13:14:51 +00:00
}
2013-09-12 11:55:38 +00:00
else
{
// TODO: Should we reset alphabump to 0 here?
}
2010-07-06 13:14:51 +00:00
// format
2013-10-07 22:56:03 +00:00
const char * tevIndFmtMask [ ] = { " 255 " , " 31 " , " 15 " , " 7 " } ;
2014-03-01 13:08:45 +00:00
out . Write ( " \t int3 iindtevcrd%d = iindtex%d & %s; \n " , n , bpmem . tevind [ n ] . bt , tevIndFmtMask [ bpmem . tevind [ n ] . fmt ] ) ;
2009-04-15 03:55:38 +00:00
2013-08-14 14:08:50 +00:00
// bias - TODO: Check if this needs to be this complicated..
2013-09-12 11:55:38 +00:00
const char * tevIndBiasField [ ] = { " " , " x " , " y " , " xy " , " z " , " xz " , " yz " , " xyz " } ; // indexed by bias
const char * tevIndBiasAdd [ ] = { " -128 " , " 1 " , " 1 " , " 1 " } ; // indexed by fmt
2013-08-14 14:08:50 +00:00
if ( bpmem . tevind [ n ] . bias = = ITB_S | | bpmem . tevind [ n ] . bias = = ITB_T | | bpmem . tevind [ n ] . bias = = ITB_U )
2014-03-01 13:08:45 +00:00
out . Write ( " \t iindtevcrd%d.%s += int(%s); \n " , n , tevIndBiasField [ bpmem . tevind [ n ] . bias ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] ) ;
2013-08-14 14:08:50 +00:00
else if ( bpmem . tevind [ n ] . bias = = ITB_ST | | bpmem . tevind [ n ] . bias = = ITB_SU | | bpmem . tevind [ n ] . bias = = ITB_TU )
2014-03-01 13:08:45 +00:00
out . Write ( " \t iindtevcrd%d.%s += int2(%s, %s); \n " , n , tevIndBiasField [ bpmem . tevind [ n ] . bias ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] ) ;
2013-08-14 14:08:50 +00:00
else if ( bpmem . tevind [ n ] . bias = = ITB_STU )
2014-03-01 13:08:45 +00:00
out . Write ( " \t iindtevcrd%d.%s += int3(%s, %s, %s); \n " , n , tevIndBiasField [ bpmem . tevind [ n ] . bias ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] , tevIndBiasAdd [ bpmem . tevind [ n ] . fmt ] ) ;
2008-12-08 05:30:24 +00:00
2013-09-12 11:55:38 +00:00
// multiply by offset matrix and scale - calculations are likely to overflow badly,
// yet it works out since we only care about the lower 23 bits (+1 sign bit) of the result
2010-07-06 13:14:51 +00:00
if ( bpmem . tevind [ n ] . mid ! = 0 )
2009-07-26 09:52:35 +00:00
{
2011-01-09 14:13:24 +00:00
if ( bpmem . tevind [ n ] . mid < = 3 )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 1 ) ;
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_INDTEXMTX + mtxidx , C_INDTEXMTX + mtxidx ) ;
2013-09-12 11:55:38 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 indtevtrans%d = int2(idot( " I_INDTEXMTX " [%d].xyz, iindtevcrd%d), idot( " I_INDTEXMTX " [%d].xyz, iindtevcrd%d)) >> 3; \n " , n , mtxidx , n , mtxidx + 1 , n ) ;
2013-10-10 19:09:00 +00:00
2014-02-05 12:26:01 +00:00
// TODO: should use a shader uid branch for this for better performance
2014-03-01 13:08:45 +00:00
out . Write ( " \t if ( " I_INDTEXMTX " [%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX " [%d].w; \n " , mtxidx , n , n , mtxidx ) ;
out . Write ( " \t else indtevtrans%d = indtevtrans%d << (- " I_INDTEXMTX " [%d].w); \n " , n , n , mtxidx ) ;
2010-07-06 13:14:51 +00:00
}
2011-01-09 14:13:24 +00:00
else if ( bpmem . tevind [ n ] . mid < = 7 & & bHasTexCoord )
2009-07-26 09:52:35 +00:00
{ // s matrix
2011-09-29 21:32:05 +00:00
_assert_ ( bpmem . tevind [ n ] . mid > = 5 ) ;
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 5 ) ;
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_INDTEXMTX + mtxidx , C_INDTEXMTX + mtxidx ) ;
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.xx) >> 8; \n " , n , texcoord , n ) ;
2013-10-10 19:09:00 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t if ( " I_INDTEXMTX " [%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX " [%d].w; \n " , mtxidx , n , n , mtxidx ) ;
out . Write ( " \t else indtevtrans%d = indtevtrans%d << (- " I_INDTEXMTX " [%d].w); \n " , n , n , mtxidx ) ;
2010-07-06 13:14:51 +00:00
}
2011-01-09 14:13:24 +00:00
else if ( bpmem . tevind [ n ] . mid < = 11 & & bHasTexCoord )
2009-07-26 09:52:35 +00:00
{ // t matrix
2011-09-29 21:32:05 +00:00
_assert_ ( bpmem . tevind [ n ] . mid > = 9 ) ;
2010-07-06 13:14:51 +00:00
int mtxidx = 2 * ( bpmem . tevind [ n ] . mid - 9 ) ;
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_INDTEXMTX + mtxidx , C_INDTEXMTX + mtxidx ) ;
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 indtevtrans%d = int2(fixpoint_uv%d * iindtevcrd%d.yy) >> 8; \n " , n , texcoord , n ) ;
2013-10-10 19:09:00 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t if ( " I_INDTEXMTX " [%d].w >= 0) indtevtrans%d = indtevtrans%d >> " I_INDTEXMTX " [%d].w; \n " , mtxidx , n , n , mtxidx ) ;
out . Write ( " \t else indtevtrans%d = indtevtrans%d << (- " I_INDTEXMTX " [%d].w); \n " , n , n , mtxidx ) ;
2010-07-06 13:14:51 +00:00
}
else
2013-04-24 13:21:54 +00:00
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 indtevtrans%d = int2(0, 0); \n " , n ) ;
2013-04-24 13:21:54 +00:00
}
2010-07-06 13:14:51 +00:00
}
else
2013-04-24 13:21:54 +00:00
{
2014-03-01 13:08:45 +00:00
out . Write ( " \t int2 indtevtrans%d = int2(0, 0); \n " , n ) ;
2013-04-24 13:21:54 +00:00
}
2010-07-06 13:14:51 +00:00
// ---------
2009-07-26 09:52:35 +00:00
// Wrapping
// ---------
2013-11-02 10:42:30 +00:00
const char * tevIndWrapStart [ ] = { " 0 " , " (256<<7) " , " (128<<7) " , " (64<<7) " , " (32<<7) " , " (16<<7) " , " 1 " } ; // TODO: Should the last one be 1 or (1<<7)?
2012-08-07 12:36:56 +00:00
2010-07-06 13:14:51 +00:00
// wrap S
if ( bpmem . tevind [ n ] . sw = = ITW_OFF )
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.x = fixpoint_uv%d.x; \n " , texcoord ) ;
2010-07-06 13:14:51 +00:00
else if ( bpmem . tevind [ n ] . sw = = ITW_0 )
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.x = 0; \n " ) ;
2010-07-06 13:14:51 +00:00
else
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.x = fixpoint_uv%d.x %% %s; \n " , texcoord , tevIndWrapStart [ bpmem . tevind [ n ] . sw ] ) ;
2010-07-06 13:14:51 +00:00
// wrap T
if ( bpmem . tevind [ n ] . tw = = ITW_OFF )
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.y = fixpoint_uv%d.y; \n " , texcoord ) ;
2010-07-06 13:14:51 +00:00
else if ( bpmem . tevind [ n ] . tw = = ITW_0 )
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.y = 0; \n " ) ;
2010-07-06 13:14:51 +00:00
else
2014-03-01 13:08:45 +00:00
out . Write ( " \t wrappedcoord.y = fixpoint_uv%d.y %% %s; \n " , texcoord , tevIndWrapStart [ bpmem . tevind [ n ] . tw ] ) ;
2010-07-06 13:14:51 +00:00
if ( bpmem . tevind [ n ] . fb_addprev ) // add previous tevcoord
2014-03-01 13:08:45 +00:00
out . Write ( " \t tevcoord.xy += wrappedcoord + indtevtrans%d; \n " , n ) ;
2010-07-06 13:14:51 +00:00
else
2014-03-01 13:08:45 +00:00
out . Write ( " \t tevcoord.xy = wrappedcoord + indtevtrans%d; \n " , n ) ;
2013-09-12 11:55:38 +00:00
// Emulate s24 overflows
2014-03-01 13:08:45 +00:00
out . Write ( " \t tevcoord.xy = (tevcoord.xy << 8) >> 8; \n " ) ;
2010-07-06 13:14:51 +00:00
}
2010-08-16 22:37:04 +00:00
TevStageCombiner : : ColorCombiner & cc = bpmem . combiners [ n ] . colorC ;
TevStageCombiner : : AlphaCombiner & ac = bpmem . combiners [ n ] . alphaC ;
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . cc = cc . hex & 0xFFFFFF ;
uid_data . stagehash [ n ] . ac = ac . hex & 0xFFFFF0 ; // Storing rswap and tswap later
2012-09-02 16:30:21 +00:00
2014-03-10 11:30:55 +00:00
if ( cc . a = = TEVCOLORARG_RASA | | cc . a = = TEVCOLORARG_RASC | |
cc . b = = TEVCOLORARG_RASA | | cc . b = = TEVCOLORARG_RASC | |
cc . c = = TEVCOLORARG_RASA | | cc . c = = TEVCOLORARG_RASC | |
cc . d = = TEVCOLORARG_RASA | | cc . d = = TEVCOLORARG_RASC | |
ac . a = = TEVALPHAARG_RASA | | ac . b = = TEVALPHAARG_RASA | |
ac . c = = TEVALPHAARG_RASA | | ac . d = = TEVALPHAARG_RASA )
2010-08-16 22:37:04 +00:00
{
2012-08-07 12:36:56 +00:00
const int i = bpmem . combiners [ n ] . alphaC . rswap ;
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . ac | = bpmem . combiners [ n ] . alphaC . rswap ;
uid_data . stagehash [ n ] . tevksel_swap1a = bpmem . tevksel [ i * 2 ] . swap1 ;
uid_data . stagehash [ n ] . tevksel_swap2a = bpmem . tevksel [ i * 2 ] . swap2 ;
uid_data . stagehash [ n ] . tevksel_swap1b = bpmem . tevksel [ i * 2 + 1 ] . swap1 ;
uid_data . stagehash [ n ] . tevksel_swap2b = bpmem . tevksel [ i * 2 + 1 ] . swap2 ;
uid_data . stagehash [ n ] . tevorders_colorchan = bpmem . tevorders [ n / 2 ] . getColorChan ( n & 1 ) ;
2012-08-07 12:36:56 +00:00
2013-09-04 19:56:03 +00:00
const char * rasswap = swapModeTable [ bpmem . combiners [ n ] . alphaC . rswap ] ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t rastemp = %s.%s; \n " , tevRasTable [ bpmem . tevorders [ n / 2 ] . getColorChan ( n & 1 ) ] , rasswap ) ;
2010-08-16 22:37:04 +00:00
}
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . tevorders_enable = bpmem . tevorders [ n / 2 ] . getEnable ( n & 1 ) ;
2010-07-06 13:14:51 +00:00
if ( bpmem . tevorders [ n / 2 ] . getEnable ( n & 1 ) )
2009-07-26 09:52:35 +00:00
{
2013-09-12 11:55:38 +00:00
int texmap = bpmem . tevorders [ n / 2 ] . getTexMap ( n & 1 ) ;
2011-12-26 05:15:54 +00:00
if ( ! bHasIndStage )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
// calc tevcord
2014-03-10 11:30:55 +00:00
if ( bHasTexCoord )
2014-03-01 13:08:45 +00:00
out . Write ( " \t tevcoord.xy = fixpoint_uv%d; \n " , texcoord ) ;
2010-07-06 13:14:51 +00:00
else
2014-03-01 13:08:45 +00:00
out . Write ( " \t tevcoord.xy = int2(0, 0); \n " ) ;
2010-07-06 13:14:51 +00:00
}
2008-12-08 05:30:24 +00:00
2012-08-07 12:36:56 +00:00
const int i = bpmem . combiners [ n ] . alphaC . tswap ;
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . ac | = bpmem . combiners [ n ] . alphaC . tswap < < 2 ;
uid_data . stagehash [ n ] . tevksel_swap1c = bpmem . tevksel [ i * 2 ] . swap1 ;
uid_data . stagehash [ n ] . tevksel_swap2c = bpmem . tevksel [ i * 2 ] . swap2 ;
uid_data . stagehash [ n ] . tevksel_swap1d = bpmem . tevksel [ i * 2 + 1 ] . swap1 ;
uid_data . stagehash [ n ] . tevksel_swap2d = bpmem . tevksel [ i * 2 + 1 ] . swap2 ;
uid_data . stagehash [ n ] . tevorders_texmap = bpmem . tevorders [ n / 2 ] . getTexMap ( n & 1 ) ;
2012-08-07 12:36:56 +00:00
2013-09-04 19:56:03 +00:00
const char * texswap = swapModeTable [ bpmem . combiners [ n ] . alphaC . tswap ] ;
2013-05-01 09:39:30 +00:00
uid_data . SetTevindrefTexmap ( i , texmap ) ;
2013-08-12 11:31:29 +00:00
2014-03-06 18:27:11 +00:00
out . Write ( " \t textemp = " ) ;
2013-11-02 10:42:30 +00:00
SampleTexture < T > ( out , " (float2(tevcoord.xy)/128.0) " , texswap , texmap , ApiType ) ;
2010-07-06 13:14:51 +00:00
}
else
2013-04-24 13:21:54 +00:00
{
2014-03-06 18:27:11 +00:00
out . Write ( " \t textemp = int4(255, 255, 255, 255); \n " ) ;
2013-04-24 13:21:54 +00:00
}
2008-12-08 05:30:24 +00:00
2011-06-04 19:56:18 +00:00
2014-03-10 11:30:55 +00:00
if ( cc . a = = TEVCOLORARG_KONST | | cc . b = = TEVCOLORARG_KONST | |
cc . c = = TEVCOLORARG_KONST | | cc . d = = TEVCOLORARG_KONST | |
ac . a = = TEVALPHAARG_KONST | | ac . b = = TEVALPHAARG_KONST | |
ac . c = = TEVALPHAARG_KONST | | ac . d = = TEVALPHAARG_KONST )
2010-08-16 22:37:04 +00:00
{
2011-09-29 19:52:13 +00:00
int kc = bpmem . tevksel [ n / 2 ] . getKC ( n & 1 ) ;
int ka = bpmem . tevksel [ n / 2 ] . getKA ( n & 1 ) ;
2013-06-22 18:41:32 +00:00
uid_data . stagehash [ n ] . tevksel_kc = kc ;
uid_data . stagehash [ n ] . tevksel_ka = ka ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t konsttemp = int4(%s, %s); \n " , tevKSelTableC [ kc ] , tevKSelTableA [ ka ] ) ;
2013-08-14 14:25:39 +00:00
2012-09-02 18:00:15 +00:00
if ( kc > 7 )
out . SetConstantsUsed ( C_KCOLORS + ( ( kc - 0xc ) % 4 ) , C_KCOLORS + ( ( kc - 0xc ) % 4 ) ) ;
if ( ka > 7 )
out . SetConstantsUsed ( C_KCOLORS + ( ( ka - 0xc ) % 4 ) , C_KCOLORS + ( ( ka - 0xc ) % 4 ) ) ;
2010-08-16 22:37:04 +00:00
}
2008-12-08 05:30:24 +00:00
2013-03-29 19:59:03 +00:00
if ( cc . d = = TEVCOLORARG_C0 | | cc . d = = TEVCOLORARG_A0 | | ac . d = = TEVALPHAARG_A0 )
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_COLORS + 1 , C_COLORS + 1 ) ;
2013-03-29 19:59:03 +00:00
2012-09-02 18:00:15 +00:00
if ( cc . d = = TEVCOLORARG_C1 | | cc . d = = TEVCOLORARG_A1 | | ac . d = = TEVALPHAARG_A1 )
out . SetConstantsUsed ( C_COLORS + 2 , C_COLORS + 2 ) ;
2013-03-29 19:59:03 +00:00
2012-09-02 18:00:15 +00:00
if ( cc . d = = TEVCOLORARG_C2 | | cc . d = = TEVCOLORARG_A2 | | ac . d = = TEVALPHAARG_A2 )
out . SetConstantsUsed ( C_COLORS + 3 , C_COLORS + 3 ) ;
2013-03-29 19:59:03 +00:00
if ( cc . dest > = GX_TEVREG0 & & cc . dest < = GX_TEVREG2 )
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_COLORS + cc . dest , C_COLORS + cc . dest ) ;
2013-03-29 19:59:03 +00:00
if ( ac . dest > = GX_TEVREG0 & & ac . dest < = GX_TEVREG2 )
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_COLORS + ac . dest , C_COLORS + ac . dest ) ;
2014-03-20 19:34:51 +00:00
2014-03-24 13:41:56 +00:00
out . Write ( " tevin_a = int4(%s, %s)&255; \n " , tevCInputTable [ cc . a ] , tevAInputTable [ ac . a ] ) ;
out . Write ( " tevin_b = int4(%s, %s)&255; \n " , tevCInputTable [ cc . b ] , tevAInputTable [ ac . b ] ) ;
out . Write ( " tevin_c = int4(%s, %s)&255; \n " , tevCInputTable [ cc . c ] , tevAInputTable [ ac . c ] ) ;
out . Write ( " tevin_d = int4(%s, %s); \n " , tevCInputTable [ cc . d ] , tevAInputTable [ ac . d ] ) ;
2014-03-20 19:34:51 +00:00
2014-03-01 13:08:45 +00:00
out . Write ( " \t // color combine \n " ) ;
out . Write ( " \t %s = clamp( " , tevCOutputTable [ cc . dest ] ) ;
2014-03-24 13:41:56 +00:00
if ( cc . bias ! = TevBias_COMPARE )
2009-07-26 09:52:35 +00:00
{
2014-03-24 13:41:56 +00:00
WriteTevRegular ( out , " rgb " , cc . bias , cc . op , cc . clamp , cc . shift ) ;
2010-07-06 13:14:51 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2014-03-06 18:28:29 +00:00
const char * function_table [ ] =
2014-02-28 19:24:00 +00:00
{
2014-03-20 19:34:51 +00:00
" ((tevin_a.r > tevin_b.r) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_R8_GT
" ((tevin_a.r == tevin_b.r) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_R8_EQ
" ((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_GR16_GT
" ((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_GR16_EQ
" ((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_BGR24_GT
" ((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.rgb : int3(0,0,0)) " , // TEVCMP_BGR24_EQ
" (max(sign(tevin_a.rgb - tevin_b.rgb), int3(0,0,0)) * tevin_c.rgb) " , // TEVCMP_RGB8_GT
" ((int3(255,255,255) - max(sign(abs(tevin_a.rgb - tevin_b.rgb))), int3(0,0,0))) * tevin_c.rgb) " // TEVCMP_RGB8_EQ
2014-02-28 19:24:00 +00:00
} ;
int mode = ( cc . shift < < 1 ) | cc . op ;
2014-03-20 19:34:51 +00:00
out . Write ( " tevin_d.rgb + " ) ;
out . Write ( function_table [ mode ] ) ;
2010-07-06 13:14:51 +00:00
}
2010-01-12 03:39:14 +00:00
if ( cc . clamp )
2013-08-14 16:24:47 +00:00
out . Write ( " , int3(0,0,0), int3(255,255,255)) " ) ;
2013-08-14 16:54:43 +00:00
else
out . Write ( " , int3(-1024,-1024,-1024), int3(1023,1023,1023)) " ) ;
2013-08-14 16:24:47 +00:00
out . Write ( " ; \n " ) ;
2012-08-11 14:54:46 +00:00
2013-08-14 16:54:43 +00:00
out . Write ( " \t // alpha combine \n " ) ;
out . Write ( " \t %s = clamp( " , tevAOutputTable [ ac . dest ] ) ;
2014-03-24 13:41:56 +00:00
if ( ac . bias ! = TevBias_COMPARE )
2009-07-26 09:52:35 +00:00
{
2014-03-24 13:41:56 +00:00
WriteTevRegular ( out , " a " , ac . bias , ac . op , ac . clamp , ac . shift ) ;
2010-07-06 13:14:51 +00:00
}
else
2009-07-26 09:52:35 +00:00
{
2014-03-06 18:28:29 +00:00
const char * function_table [ ] =
2014-02-28 19:24:00 +00:00
{
2014-03-20 19:34:51 +00:00
" ((tevin_a.r > tevin_b.r) ? tevin_c.a : 0) " , // TEVCMP_R8_GT
" ((tevin_a.r == tevin_b.r) ? tevin_c.a : 0) " , // TEVCMP_R8_EQ
" ((idot(tevin_a.rgb, comp16) > idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0) " , // TEVCMP_GR16_GT
" ((idot(tevin_a.rgb, comp16) == idot(tevin_b.rgb, comp16)) ? tevin_c.a : 0) " , // TEVCMP_GR16_EQ
" ((idot(tevin_a.rgb, comp24) > idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0) " , // TEVCMP_BGR24_GT
" ((idot(tevin_a.rgb, comp24) == idot(tevin_b.rgb, comp24)) ? tevin_c.a : 0) " , // TEVCMP_BGR24_EQ
" ((tevin_a.a > tevin_b.a) ? tevin_c.a : 0) " , // TEVCMP_A8_GT
" ((tevin_a.a == tevin_b.a) ? tevin_c.a : 0) " // TEVCMP_A8_EQ
2014-02-28 19:24:00 +00:00
} ;
int mode = ( ac . shift < < 1 ) | ac . op ;
2014-03-20 19:34:51 +00:00
out . Write ( " tevin_d.a + " ) ;
out . Write ( function_table [ mode ] ) ;
2010-07-06 13:14:51 +00:00
}
2010-01-12 03:39:14 +00:00
if ( ac . clamp )
2013-08-14 16:24:47 +00:00
out . Write ( " , 0, 255) " ) ;
2013-08-14 16:54:43 +00:00
else
out . Write ( " , -1024, 1023) " ) ;
2013-08-14 16:24:47 +00:00
out . Write ( " ; \n \n " ) ;
2008-12-08 05:30:24 +00:00
}
2014-03-24 13:41:56 +00:00
template < class T >
static inline void WriteTevRegular ( T & out , const char * components , int bias , int op , int clamp , int shift )
{
const char * tevScaleTableLeft [ ] =
{
" " , // SCALE_1
" << 1 " , // SCALE_2
" << 2 " , // SCALE_4
" " , // DIVIDE_2
} ;
const char * tevScaleTableRight [ ] =
{
" " , // SCALE_1
" " , // SCALE_2
" " , // SCALE_4
" >> 1 " , // DIVIDE_2
} ;
const char * tevLerpBias [ ] = // indexed by 2*op+(shift==3)
{
" " ,
" + 128 " ,
" " ,
" + 127 " ,
} ;
const char * tevBiasTable [ ] =
{
" " , // ZERO,
" + 128 " , // ADDHALF,
" - 128 " , // SUBHALF,
" " ,
} ;
const char * tevOpTable [ ] = {
" + " , // TEVOP_ADD = 0,
" - " , // TEVOP_SUB = 1,
} ;
// Regular TEV stage: (d + bias + lerp(a,b,c)) * scale
// The GC/Wii GPU uses a very sophisticated algorithm for scale-lerping:
// - c is scaled from 0..255 to 0..256, which allows dividing the result by 256 instead of 255
// - if scale is bigger than one, it is moved inside the lerp calculation for increased accuracy
// - a rounding bias is added before dividing by 256
out . Write ( " (((tevin_d.%s%s)%s) " , components , tevBiasTable [ bias ] , tevScaleTableLeft [ shift ] ) ;
out . Write ( " %s " , tevOpTable [ op ] ) ;
out . Write ( " ((((tevin_a.%s*256 + (tevin_b.%s-tevin_a.%s)*(tevin_c.%s+(tevin_c.%s>>7)))%s)%s)>>8) " ,
components , components , components , components , components ,
tevScaleTableLeft [ shift ] , tevLerpBias [ 2 * op + ( shift = = 3 ) ] ) ;
out . Write ( " )%s " , tevScaleTableRight [ shift ] ) ;
}
2013-03-26 22:21:08 +00:00
template < class T >
2013-08-14 11:21:43 +00:00
static inline void SampleTexture ( T & out , const char * texcoords , const char * texswap , int texmap , API_TYPE ApiType )
2008-12-08 05:30:24 +00:00
{
2012-09-02 18:00:15 +00:00
out . SetConstantsUsed ( C_TEXDIMS + texmap , C_TEXDIMS + texmap ) ;
2013-08-12 11:31:29 +00:00
2013-09-22 16:07:21 +00:00
if ( ApiType = = API_D3D )
2013-08-14 13:40:24 +00:00
out . Write ( " int4(round(255.0 * Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS " [%d].xy))).%s; \n " , texmap , texmap , texcoords , texmap , texswap ) ;
else
out . Write ( " int4(round(255.0 * texture(samp%d,%s.xy * " I_TEXDIMS " [%d].xy))).%s; \n " , texmap , texcoords , texmap , texswap ) ;
2008-12-08 05:30:24 +00:00
}
2010-07-06 13:14:51 +00:00
static const char * tevAlphaFuncsTable [ ] =
2008-12-08 05:30:24 +00:00
{
2013-08-14 13:06:47 +00:00
" (false) " , // NEVER
2014-03-06 18:27:11 +00:00
" (prev.a < %s) " , // LESS
" (prev.a == %s) " , // EQUAL
" (prev.a <= %s) " , // LEQUAL
" (prev.a > %s) " , // GREATER
" (prev.a != %s) " , // NEQUAL
" (prev.a >= %s) " , // GEQUAL
2013-08-14 13:06:47 +00:00
" (true) " // ALWAYS
2009-10-25 02:35:21 +00:00
} ;
static const char * tevAlphaFunclogicTable [ ] =
{
" && " , // and
2010-07-06 13:14:51 +00:00
" || " , // or
" != " , // xor
" == " // xnor
2009-10-25 02:35:21 +00:00
} ;
2013-01-08 15:40:15 +00:00
2013-03-26 22:21:08 +00:00
template < class T >
2013-08-12 10:52:28 +00:00
static inline void WriteAlphaTest ( T & out , pixel_shader_uid_data & uid_data , API_TYPE ApiType , DSTALPHA_MODE dstAlphaMode , bool per_pixel_depth )
2010-10-10 14:35:31 +00:00
{
2011-09-29 19:52:13 +00:00
static const char * alphaRef [ 2 ] =
{
2013-10-10 18:36:55 +00:00
I_ALPHA " .r " ,
I_ALPHA " .g "
2012-09-02 18:00:15 +00:00
} ;
out . SetConstantsUsed ( C_ALPHA , C_ALPHA ) ;
2010-10-10 14:35:31 +00:00
2013-03-26 21:16:29 +00:00
out . Write ( " \t if(!( " ) ;
2009-07-26 09:52:35 +00:00
2013-05-01 09:39:30 +00:00
uid_data . alpha_test_comp0 = bpmem . alpha_test . comp0 ;
2013-07-23 00:13:40 +00:00
uid_data . alpha_test_comp1 = bpmem . alpha_test . comp1 ;
2013-05-01 09:39:30 +00:00
uid_data . alpha_test_logic = bpmem . alpha_test . logic ;
2012-08-07 12:36:56 +00:00
// Lookup the first component from the alpha function table
2013-01-08 16:18:45 +00:00
int compindex = bpmem . alpha_test . comp0 ;
2012-08-07 12:36:56 +00:00
out . Write ( tevAlphaFuncsTable [ compindex ] , alphaRef [ 0 ] ) ;
2011-06-04 19:56:18 +00:00
2014-02-05 12:26:01 +00:00
out . Write ( " %s " , tevAlphaFunclogicTable [ bpmem . alpha_test . logic ] ) ; // lookup the logic op
2011-06-04 19:56:18 +00:00
2012-08-07 12:36:56 +00:00
// Lookup the second component from the alpha function table
2013-01-08 16:18:45 +00:00
compindex = bpmem . alpha_test . comp1 ;
2012-08-07 12:36:56 +00:00
out . Write ( tevAlphaFuncsTable [ compindex ] , alphaRef [ 1 ] ) ;
2012-08-06 23:02:04 +00:00
out . Write ( " )) { \n " ) ;
2011-09-04 02:44:50 +00:00
2013-10-06 08:12:13 +00:00
out . Write ( " \t \t ocol0 = float4(0.0, 0.0, 0.0, 0.0); \n " ) ;
2012-08-10 16:57:37 +00:00
if ( dstAlphaMode = = DSTALPHA_DUAL_SOURCE_BLEND )
2013-10-06 08:12:13 +00:00
out . Write ( " \t \t ocol1 = float4(0.0, 0.0, 0.0, 0.0); \n " ) ;
2014-03-10 11:30:55 +00:00
if ( per_pixel_depth )
2013-10-06 08:12:13 +00:00
out . Write ( " \t \t depth = 1.0; \n " ) ;
2012-08-10 16:57:37 +00:00
2013-01-08 15:51:01 +00:00
// HAXX: zcomploc (aka early_ztest) is a way to control whether depth test is done before
2013-07-22 10:02:16 +00:00
// or after texturing and alpha test. PC graphics APIs have no way to support this
// feature properly as of 2012: Depth buffer and depth test are not
2013-01-08 15:51:01 +00:00
// programmable and the depth test is always done after texturing.
2013-07-22 10:02:16 +00:00
// Most importantly, they do not allow writing to the z-buffer without
2013-01-08 15:51:01 +00:00
// writing a color value (unless color writing is disabled altogether).
2013-07-22 10:02:16 +00:00
// We implement "depth test before texturing" by disabling alpha test when early-z is in use.
// It seems to be less buggy than not to update the depth buffer if alpha test fails,
// but both ways wouldn't be accurate.
2013-07-22 12:38:09 +00:00
2013-09-22 16:07:21 +00:00
// OpenGL 4.2 has a flag which allows the driver to still update the depth buffer
2013-07-22 10:02:16 +00:00
// if alpha test fails. The driver doesn't have to, but I assume they all do because
// it's the much faster code path for the GPU.
2013-07-22 12:38:09 +00:00
uid_data . alpha_test_use_zcomploc_hack = bpmem . UseEarlyDepthTest ( ) & & bpmem . zmode . updateenable & & ! g_ActiveConfig . backend_info . bSupportsEarlyZ ;
2013-07-22 10:02:16 +00:00
if ( ! uid_data . alpha_test_use_zcomploc_hack )
2012-08-10 16:57:37 +00:00
{
2013-03-26 21:16:29 +00:00
out . Write ( " \t \t discard; \n " ) ;
2013-09-22 16:07:21 +00:00
if ( ApiType ! = API_D3D )
2013-03-26 21:16:29 +00:00
out . Write ( " \t \t return; \n " ) ;
2012-08-10 16:57:37 +00:00
}
2011-09-04 02:44:50 +00:00
2012-08-06 23:02:04 +00:00
out . Write ( " } \n " ) ;
2008-12-08 05:30:24 +00:00
}
2009-02-19 04:41:58 +00:00
2009-10-25 02:35:21 +00:00
static const char * tevFogFuncsTable [ ] =
{
2014-02-16 20:30:18 +00:00
" " , // No Fog
" " , // ?
" " , // Linear
" " , // ?
" \t fog = 1.0 - exp2(-8.0 * fog); \n " , // exp
" \t fog = 1.0 - exp2(-8.0 * fog * fog); \n " , // exp2
" \t fog = exp2(-8.0 * (1.0 - fog)); \n " , // backward exp
" \t fog = 1.0 - fog; \n fog = exp2(-8.0 * fog * fog); \n " // backward exp2
2009-10-25 02:35:21 +00:00
} ;
2013-03-26 22:21:08 +00:00
template < class T >
2013-08-12 10:52:28 +00:00
static inline void WriteFog ( T & out , pixel_shader_uid_data & uid_data )
2009-02-19 04:41:58 +00:00
{
2013-05-01 09:39:30 +00:00
uid_data . fog_fsel = bpmem . fog . c_proj_fsel . fsel ;
2014-03-10 11:30:55 +00:00
if ( bpmem . fog . c_proj_fsel . fsel = = 0 )
2011-12-26 05:15:54 +00:00
return ; // no Fog
2009-02-19 04:41:58 +00:00
2013-05-01 09:39:30 +00:00
uid_data . fog_proj = bpmem . fog . c_proj_fsel . proj ;
2012-09-02 16:30:21 +00:00
2013-10-27 12:10:00 +00:00
out . SetConstantsUsed ( C_FOGCOLOR , C_FOGCOLOR ) ;
2013-12-16 12:08:09 +00:00
out . SetConstantsUsed ( C_FOGI , C_FOGI ) ;
out . SetConstantsUsed ( C_FOGF , C_FOGF + 1 ) ;
2011-06-04 19:56:18 +00:00
if ( bpmem . fog . c_proj_fsel . proj = = 0 )
2009-07-26 09:52:35 +00:00
{
2010-07-06 13:14:51 +00:00
// perspective
2010-11-23 13:57:01 +00:00
// ze = A/(B - (Zs >> B_SHF)
2013-12-16 12:08:09 +00:00
// TODO: Verify that we want to drop lower bits here! (currently taken over from software renderer)
2014-02-28 19:53:31 +00:00
// Maybe we want to use "ze = (A << B_SHF)/((B << B_SHF) - Zs)" instead?
// That's equivalent, but keeps the lower bits of Zs.
2014-03-03 18:23:46 +00:00
out . Write ( " \t float ze = ( " I_FOGF " [1].x * 16777215.0) / float( " I_FOGI " .y - (zCoord >> " I_FOGI " .w)); \n " ) ;
2010-07-06 13:14:51 +00:00
}
else
2009-10-25 02:35:21 +00:00
{
2010-07-06 13:14:51 +00:00
// orthographic
2014-02-16 20:30:18 +00:00
// ze = a*Zs (here, no B_SHF)
2013-12-16 12:08:09 +00:00
out . Write ( " \t float ze = " I_FOGF " [1].x * float(zCoord) / 16777215.0; \n " ) ;
2010-07-06 13:14:51 +00:00
}
2011-06-04 19:56:18 +00:00
2010-11-23 13:57:01 +00:00
// x_adjust = sqrt((x-center)^2 + k^2)/k
// ze *= x_adjust
2013-12-16 12:08:09 +00:00
// TODO Instead of this theoretical calculation, we should use the
// coefficient table given in the fog range BP registers!
2013-05-01 09:39:30 +00:00
uid_data . fog_RangeBaseEnabled = bpmem . fogRange . Base . Enabled ;
2011-12-26 05:15:54 +00:00
if ( bpmem . fogRange . Base . Enabled )
2011-01-29 04:31:56 +00:00
{
2013-12-16 12:08:09 +00:00
out . SetConstantsUsed ( C_FOGF , C_FOGF ) ;
out . Write ( " \t float x_adjust = (2.0 * (clipPos.x / " I_FOGF " [0].y)) - 1.0 - " I_FOGF " [0].x; \n " ) ;
out . Write ( " \t x_adjust = sqrt(x_adjust * x_adjust + " I_FOGF " [0].z * " I_FOGF " [0].z) / " I_FOGF " [0].z; \n " ) ;
2013-03-26 21:16:29 +00:00
out . Write ( " \t ze *= x_adjust; \n " ) ;
2011-01-29 04:31:56 +00:00
}
2009-02-19 04:41:58 +00:00
2013-12-16 12:08:09 +00:00
out . Write ( " \t float fog = clamp(ze - " I_FOGF " [1].z, 0.0, 1.0); \n " ) ;
2009-02-19 04:41:58 +00:00
2011-12-26 05:15:54 +00:00
if ( bpmem . fog . c_proj_fsel . fsel > 3 )
2009-10-25 02:35:21 +00:00
{
2012-08-06 23:02:04 +00:00
out . Write ( " %s " , tevFogFuncsTable [ bpmem . fog . c_proj_fsel . fsel ] ) ;
2009-10-25 02:35:21 +00:00
}
else
{
2014-03-09 20:14:26 +00:00
if ( bpmem . fog . c_proj_fsel . fsel ! = 2 & & out . GetBuffer ( ) ! = nullptr )
2009-10-25 02:35:21 +00:00
WARN_LOG ( VIDEO , " Unknown Fog Type! %08x " , bpmem . fog . c_proj_fsel . fsel ) ;
2010-07-06 13:14:51 +00:00
}
2009-02-19 04:41:58 +00:00
2013-10-08 00:14:52 +00:00
out . Write ( " \t int ifog = int(round(fog * 256.0)); \n " ) ;
2014-03-06 18:27:11 +00:00
out . Write ( " \t prev.rgb = (prev.rgb * (256 - ifog) + " I_FOGCOLOR " .rgb * ifog) >> 8; \n " ) ;
2012-08-06 23:02:04 +00:00
}
2011-06-04 19:56:18 +00:00
2012-09-02 12:31:37 +00:00
void GetPixelShaderUid ( PixelShaderUid & object , DSTALPHA_MODE dstAlphaMode , API_TYPE ApiType , u32 components )
2012-08-06 23:02:04 +00:00
{
2013-03-26 22:21:08 +00:00
GeneratePixelShader < PixelShaderUid > ( object , dstAlphaMode , ApiType , components ) ;
2012-08-06 23:02:04 +00:00
}
2011-06-04 19:56:18 +00:00
2012-09-02 12:31:37 +00:00
void GeneratePixelShaderCode ( PixelShaderCode & object , DSTALPHA_MODE dstAlphaMode , API_TYPE ApiType , u32 components )
2012-08-06 23:02:04 +00:00
{
2013-03-26 22:21:08 +00:00
GeneratePixelShader < PixelShaderCode > ( object , dstAlphaMode , ApiType , components ) ;
2009-02-19 04:41:58 +00:00
}
2012-09-02 18:00:15 +00:00
void GetPixelShaderConstantProfile ( PixelShaderConstantProfile & object , DSTALPHA_MODE dstAlphaMode , API_TYPE ApiType , u32 components )
{
2013-03-26 22:21:08 +00:00
GeneratePixelShader < PixelShaderConstantProfile > ( object , dstAlphaMode , ApiType , components ) ;
2012-09-02 18:00:15 +00:00
}