2014-02-10 13:54:46 -05:00
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
2012-08-06 23:09:43 +02:00
2014-02-10 13:54:46 -05:00
#pragma once
2012-08-06 23:09:43 +02:00
2014-02-17 05:18:15 -05:00
#include <algorithm>
#include <cstdarg>
#include <cstdio>
2014-02-23 03:45:46 +01:00
#include <iomanip>
2013-04-10 14:25:18 +02:00
#include <string>
2012-09-02 20:00:15 +02:00
#include <vector>
2014-02-17 05:18:15 -05:00
#include "Common/CommonTypes.h"
2014-06-03 01:08:54 -04:00
#include "Common/StringUtil.h"
2014-02-17 05:18:15 -05:00
#include "VideoCommon/VideoCommon.h"
2014-11-02 23:40:52 +01:00
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
2013-03-31 20:55:57 +02:00
2013-04-25 13:30:41 +02:00
/**
* Common interface for classes that need to go through the shader generation path (GenerateVertexShader, GeneratePixelShader)
* In particular, this includes the shader code generator (ShaderCode).
* A different class (ShaderUid) can be used to uniquely identify each ShaderCode object.
* More interesting things can be done with this, e.g. ShaderConstantProfile checks what shader constants are being used. This can be used to optimize buffer management.
* Each of the ShaderCode, ShaderUid and ShaderConstantProfile child classes only implement the subset of ShaderGeneratorInterface methods that are required for the specific tasks.
*/
2013-03-26 23:03:10 +01:00
class ShaderGeneratorInterface
{
public :
2013-04-25 13:30:41 +02:00
/*
* Used when the shader generator would write a piece of ShaderCode.
* Can be used like printf.
* @note In the ShaderCode implementation, this does indeed write the parameter string to an internal buffer. However, you're free to do whatever you like with the parameter.
*/
2014-10-16 20:39:58 +02:00
template < typename ... Args >
void Write ( const char * , Args ...) {}
2013-04-25 13:30:41 +02:00
/*
* Returns a read pointer to the internal buffer.
* @note When implementing this method in a child class, you likely want to return the argument of the last SetBuffer call here
* @note SetBuffer() should be called before using GetBuffer().
*/
2014-03-09 21:14:26 +01:00
const char * GetBuffer () { return nullptr ; }
2013-04-25 13:30:41 +02:00
/*
* Can be used to give the object a place to write to. This should be called before using Write().
* @param buffer pointer to a char buffer that the object can write to
*/
2013-03-26 23:03:10 +01:00
void SetBuffer ( char * buffer ) { }
2013-04-25 13:30:41 +02:00
/*
* Tells us that a specific constant range (including last_index) is being used by the shader
*/
2013-03-26 23:03:10 +01:00
inline void SetConstantsUsed ( unsigned int first_index , unsigned int last_index ) {}
2013-03-29 22:24:49 +01:00
2013-04-25 13:30:41 +02:00
/*
* Returns a pointer to an internally stored object of the uid_data type.
2014-03-09 21:14:26 +01:00
* @warning since most child classes use the default implementation you shouldn't access this directly without adding precautions against nullptr access (e.g. via adding a dummy structure, cf. the vertex/pixel shader generators)
2013-04-25 13:30:41 +02:00
*/
2013-03-29 22:24:49 +01:00
template < class uid_data >
2014-10-21 02:52:45 -04:00
uid_data * GetUidData () { return nullptr ; }
2013-03-26 23:03:10 +01:00
};
2013-04-25 13:30:41 +02:00
/**
* Shader UID class used to uniquely identify the ShaderCode output written in the shader generator.
* uid_data can be any struct of parameters that uniquely identify each shader code output.
* Unless performance is not an issue, uid_data should be tightly packed to reduce memory footprint.
* Shader generators will write to specific uid_data fields; ShaderUid methods will only read raw u32 values from a union.
*/
2013-03-26 23:03:10 +01:00
template < class uid_data >
2013-03-29 22:24:49 +01:00
class ShaderUid : public ShaderGeneratorInterface
2012-08-06 23:09:43 +02:00
{
public :
ShaderUid ()
{
2012-08-07 14:36:56 +02:00
// TODO: Move to Shadergen => can be optimized out
2012-08-06 23:09:43 +02:00
memset ( values , 0 , sizeof ( values ));
}
bool operator == ( const ShaderUid & obj ) const
{
2013-09-11 17:34:23 +02:00
return memcmp ( this -> values , obj . values , data . NumValues () * sizeof ( * values )) == 0 ;
2012-08-06 23:09:43 +02:00
}
2013-03-29 14:54:44 +01:00
bool operator != ( const ShaderUid & obj ) const
{
2013-09-11 17:34:23 +02:00
return memcmp ( this -> values , obj . values , data . NumValues () * sizeof ( * values )) != 0 ;
2013-03-29 14:54:44 +01:00
}
2013-04-25 13:30:41 +02:00
// determines the storage order inside STL containers
2012-08-06 23:09:43 +02:00
bool operator < ( const ShaderUid & obj ) const
{
2013-09-11 17:34:23 +02:00
return memcmp ( this -> values , obj . values , data . NumValues () * sizeof ( * values )) < 0 ;
2012-08-06 23:09:43 +02:00
}
2014-10-21 02:52:45 -04:00
template < class uid_data2 >
uid_data2 * GetUidData () { return & data ; }
const uid_data * GetUidData () const { return & data ; }
2014-10-25 01:52:31 +08:00
const u8 * GetUidDataRaw () const { return & values [ 0 ]; }
2012-08-06 23:09:43 +02:00
2013-04-29 21:00:39 +02:00
size_t GetUidDataSize () const { return sizeof ( values ); }
2012-08-06 23:09:43 +02:00
private :
union
{
uid_data data ;
2013-07-02 14:32:52 +02:00
u8 values [ sizeof ( uid_data )];
2012-08-06 23:09:43 +02:00
};
};
2013-03-29 22:24:49 +01:00
class ShaderCode : public ShaderGeneratorInterface
2012-08-06 23:09:43 +02:00
{
public :
2014-03-09 21:14:26 +01:00
ShaderCode () : buf ( nullptr ), write_ptr ( nullptr )
2012-08-06 23:09:43 +02:00
{
}
void Write ( const char * fmt , ...)
{
va_list arglist ;
va_start ( arglist , fmt );
write_ptr += vsprintf ( write_ptr , fmt , arglist );
va_end ( arglist );
}
const char * GetBuffer () { return buf ; }
void SetBuffer ( char * buffer ) { buf = buffer ; write_ptr = buffer ; }
private :
const char * buf ;
char * write_ptr ;
};
2013-04-25 13:30:41 +02:00
/**
* Generates a shader constant profile which can be used to query which constants are used in a shader
*/
2013-03-29 22:24:49 +01:00
class ShaderConstantProfile : public ShaderGeneratorInterface
2012-09-02 20:00:15 +02:00
{
public :
ShaderConstantProfile ( int num_constants ) { constant_usage . resize ( num_constants ); }
inline void SetConstantsUsed ( unsigned int first_index , unsigned int last_index )
{
for ( unsigned int i = first_index ; i < last_index + 1 ; ++ i )
constant_usage [ i ] = true ;
}
inline bool ConstantIsUsed ( unsigned int index )
{
2013-04-25 13:30:41 +02:00
// TODO: Not ready for usage yet
2013-03-29 20:33:28 +01:00
return true ;
2014-02-16 23:51:41 -05:00
//return constant_usage[index];
2012-09-02 20:00:15 +02:00
}
private :
std :: vector < bool > constant_usage ; // TODO: Is vector<bool> appropriate here?
};
2013-04-25 13:30:41 +02:00
/**
* Checks if there has been
*/
2013-04-10 12:54:22 +02:00
template < class UidT , class CodeT >
2013-04-29 21:00:39 +02:00
class UidChecker
2013-04-10 12:54:22 +02:00
{
2013-04-29 21:00:39 +02:00
public :
void Invalidate ()
2013-04-10 12:54:22 +02:00
{
2013-04-29 21:00:39 +02:00
m_shaders . clear ();
m_uids . clear ();
2013-04-10 12:54:22 +02:00
}
2013-04-29 21:00:39 +02:00
void AddToIndexAndCheck ( CodeT & new_code , const UidT & new_uid , const char * shader_type , const char * dump_prefix )
2013-04-10 12:54:22 +02:00
{
2013-04-29 21:00:39 +02:00
bool uid_is_indexed = std :: find ( m_uids . begin (), m_uids . end (), new_uid ) != m_uids . end ();
if ( ! uid_is_indexed )
2013-04-10 12:54:22 +02:00
{
2013-04-29 21:00:39 +02:00
m_uids . push_back ( new_uid );
m_shaders [ new_uid ] = new_code . GetBuffer ();
}
else
{
// uid is already in the index => check if there's a shader with the same uid but different code
auto & old_code = m_shaders [ new_uid ];
if ( strcmp ( old_code . c_str (), new_code . GetBuffer ()) != 0 )
{
static int num_failures = 0 ;
2013-04-10 12:54:22 +02:00
2014-06-03 01:08:54 -04:00
std :: string temp = StringFromFormat ( "%s%ssuid_mismatch_%04i.txt" , File :: GetUserPath ( D_DUMP_IDX ). c_str (),
dump_prefix , ++ num_failures );
2013-04-10 12:54:22 +02:00
2013-04-29 21:00:39 +02:00
// TODO: Should also dump uids
std :: ofstream file ;
2014-06-03 01:08:54 -04:00
OpenFStream ( file , temp , std :: ios_base :: out );
2013-04-29 21:00:39 +02:00
file << "Old shader code: \n " << old_code ;
file << " \n\n New shader code: \n " << new_code . GetBuffer ();
file << " \n\n Shader uid: \n " ;
for ( unsigned int i = 0 ; i < new_uid . GetUidDataSize (); ++ i )
{
2014-10-25 01:52:31 +08:00
u8 value = new_uid . GetUidDataRaw ()[ i ];
2013-04-29 21:00:39 +02:00
if (( i % 4 ) == 0 )
{
2013-11-13 04:03:46 -05:00
auto last_value = ( i + 3 < new_uid . GetUidDataSize () - 1 ) ? i + 3 : new_uid . GetUidDataSize ();
2013-04-29 21:00:39 +02:00
file << std :: setfill ( ' ' ) << std :: dec ;
file << "Values " << std :: setw ( 2 ) << i << " - " << last_value << ": " ;
}
2013-04-10 12:54:22 +02:00
2014-10-25 01:52:31 +08:00
file << std :: setw ( 2 ) << std :: setfill ( '0' ) << std :: hex << value << std :: setw ( 1 );
2013-04-29 21:00:39 +02:00
if (( i % 4 ) < 3 )
file << ' ' ;
else
file << std :: endl ;
}
2014-06-03 01:08:54 -04:00
ERROR_LOG ( VIDEO , "%s shader uid mismatch! See %s for details" , shader_type , temp . c_str ());
2013-04-29 21:00:39 +02:00
}
2013-04-10 12:54:22 +02:00
}
}
2013-10-29 01:23:17 -04:00
2013-04-29 21:00:39 +02:00
private :
std :: map < UidT , std :: string > m_shaders ;
std :: vector < UidT > m_uids ;
};
2014-05-30 16:17:30 +02:00
2014-11-02 23:40:52 +01:00
template < class T >
2014-12-21 12:52:14 +01:00
static void DefineOutputMember ( T & object , API_TYPE api_type , const char * qualifier , const char * type , const char * name , int var_index , const char * semantic = "" , int semantic_index = - 1 )
2014-11-02 23:40:52 +01:00
{
2014-12-21 12:52:14 +01:00
if ( qualifier != nullptr )
object . Write ( " \t %s %s %s" , qualifier , type , name );
else
object . Write ( " \t %s %s" , type , name );
2014-11-02 23:40:52 +01:00
if ( var_index != - 1 )
object . Write ( "%d" , var_index );
if ( api_type == API_D3D && strlen ( semantic ) > 0 )
{
if ( semantic_index != - 1 )
object . Write ( " : %s%d" , semantic , semantic_index );
else
object . Write ( " : %s" , semantic );
}
object . Write ( "; \n " );
}
template < class T >
2014-12-21 12:52:14 +01:00
static inline void GenerateVSOutputMembers ( T & object , API_TYPE api_type , const char * qualifier = nullptr )
2014-11-02 23:40:52 +01:00
{
2014-12-21 12:52:14 +01:00
DefineOutputMember ( object , api_type , qualifier , "float4" , "pos" , - 1 , "POSITION" );
DefineOutputMember ( object , api_type , qualifier , "float4" , "colors_" , 0 , "COLOR" , 0 );
DefineOutputMember ( object , api_type , qualifier , "float4" , "colors_" , 1 , "COLOR" , 1 );
2014-11-02 23:40:52 +01:00
for ( unsigned int i = 0 ; i < xfmem . numTexGen . numTexGens ; ++ i )
2014-12-21 12:52:14 +01:00
DefineOutputMember ( object , api_type , qualifier , "float3" , "tex" , i , "TEXCOORD" , i );
2014-11-02 23:40:52 +01:00
2014-12-21 12:52:14 +01:00
DefineOutputMember ( object , api_type , qualifier , "float4" , "clipPos" , - 1 , "TEXCOORD" , xfmem . numTexGen . numTexGens );
2014-11-02 23:40:52 +01:00
if ( g_ActiveConfig . bEnablePixelLighting )
2015-01-03 01:44:04 +13:00
{
DefineOutputMember ( object , api_type , qualifier , "float3" , "Normal" , - 1 , "TEXCOORD" , xfmem . numTexGen . numTexGens + 1 );
DefineOutputMember ( object , api_type , qualifier , "float3" , "WorldPos" , - 1 , "TEXCOORD" , xfmem . numTexGen . numTexGens + 2 );
}
2014-12-21 12:52:14 +01:00
}
2014-11-02 23:40:52 +01:00
2014-12-21 12:52:14 +01:00
template < class T >
static inline void AssignVSOutputMembers ( T & object , const char * a , const char * b )
{
object . Write ( " \t %s.pos = %s.pos; \n " , a , b );
object . Write ( " \t %s.colors_0 = %s.colors_0; \n " , a , b );
object . Write ( " \t %s.colors_1 = %s.colors_1; \n " , a , b );
for ( unsigned int i = 0 ; i < xfmem . numTexGen . numTexGens ; ++ i )
object . Write ( " \t %s.tex%d = %s.tex%d; \n " , a , i , b , i );
object . Write ( " \t %s.clipPos = %s.clipPos; \n " , a , b );
if ( g_ActiveConfig . bEnablePixelLighting )
2015-01-03 01:44:04 +13:00
{
2014-12-21 12:52:14 +01:00
object . Write ( " \t %s.Normal = %s.Normal; \n " , a , b );
2015-01-03 01:44:04 +13:00
object . Write ( " \t %s.WorldPos = %s.WorldPos; \n " , a , b );
}
2014-11-02 23:40:52 +01:00
}
2014-05-30 16:17:30 +02:00
// Constant variable names
#define I_COLORS "color"
#define I_KCOLORS "k"
#define I_ALPHA "alphaRef"
#define I_TEXDIMS "texdim"
#define I_ZBIAS "czbias"
#define I_INDTEXSCALE "cindscale"
#define I_INDTEXMTX "cindmtx"
#define I_FOGCOLOR "cfogcolor"
#define I_FOGI "cfogi"
#define I_FOGF "cfogf"
2014-12-25 00:34:22 -07:00
#define I_ZSLOPE "czslope"
2015-01-03 06:06:56 +13:00
#define I_EFBSCALE "cefbscale"
2014-05-30 16:17:30 +02:00
#define I_POSNORMALMATRIX "cpnmtx"
#define I_PROJECTION "cproj"
#define I_MATERIALS "cmtrl"
#define I_LIGHTS "clights"
#define I_TEXMATRICES "ctexmtx"
#define I_TRANSFORMMATRICES "ctrmtx"
#define I_NORMALMATRICES "cnmtx"
#define I_POSTTRANSFORMMATRICES "cpostmtx"
2014-10-25 02:59:02 +02:00
#define I_PIXELCENTERCORRECTION "cpixelcenter"
2014-12-14 21:23:13 +01:00
2014-12-16 00:21:07 +01:00
#define I_STEREOPARAMS "cstereo"
#define I_LINEPTPARAMS "clinept"
#define I_TEXOFFSET "ctexoffset"
2014-10-29 14:15:12 +01:00
static const char s_shader_uniforms [] =
" \t float4 " I_POSNORMALMATRIX "[6]; \n "
" \t float4 " I_PROJECTION "[4]; \n "
" \t int4 " I_MATERIALS "[4]; \n "
" \t Light " I_LIGHTS "[8]; \n "
" \t float4 " I_TEXMATRICES "[24]; \n "
" \t float4 " I_TRANSFORMMATRICES "[64]; \n "
" \t float4 " I_NORMALMATRICES "[32]; \n "
" \t float4 " I_POSTTRANSFORMMATRICES "[64]; \n "
2014-12-14 21:23:13 +01:00
" \t float4 " I_PIXELCENTERCORRECTION "; \n " ;