2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2018-09-29 00:12:00 +02:00
# include "GLVertexProgram.h"
2023-04-26 19:21:26 +02:00
# include "Emu/system_config.h"
2014-06-02 19:27:24 +02:00
2015-05-22 19:18:20 +02:00
# include "GLCommonDecompiler.h"
2021-05-12 23:56:01 +02:00
# include "../Program/GLSLCommon.h"
2012-11-15 00:39:56 +01:00
2020-12-18 08:39:54 +01:00
std : : string GLVertexDecompilerThread : : getFloatTypeName ( usz elementCount )
2012-11-15 00:39:56 +01:00
{
2017-08-04 16:11:39 +02:00
return glsl : : getFloatTypeNameImpl ( elementCount ) ;
2012-11-15 00:39:56 +01:00
}
2021-03-05 20:05:37 +01:00
std : : string GLVertexDecompilerThread : : getIntTypeName ( usz /*elementCount*/ )
2015-10-05 19:30:06 +02:00
{
return " ivec4 " ;
}
2015-05-19 19:43:22 +02:00
std : : string GLVertexDecompilerThread : : getFunction ( FUNCTION f )
2012-11-15 00:39:56 +01:00
{
2017-11-05 23:48:34 +01:00
return glsl : : getFunctionImpl ( f ) ;
2012-11-15 00:39:56 +01:00
}
2018-07-06 13:50:29 +02:00
std : : string GLVertexDecompilerThread : : compareFunction ( COMPARE f , const std : : string & Op0 , const std : : string & Op1 , bool scalar )
2013-06-30 10:46:29 +02:00
{
2018-07-06 13:50:29 +02:00
return glsl : : compareFunctionImpl ( f , Op0 , Op1 , scalar ) ;
2013-06-30 10:46:29 +02:00
}
2015-05-19 19:43:22 +02:00
void GLVertexDecompilerThread : : insertHeader ( std : : stringstream & OS )
2014-12-17 15:01:59 +01:00
{
2025-03-15 20:52:36 +01:00
OS < <
" #version 430 \n "
" layout(std140, binding = " < < GL_VERTEX_PARAMS_BIND_SLOT < < " ) uniform VertexContextBuffer \n "
" { \n "
" mat4 scale_offset_mat; \n "
" ivec4 user_clip_enabled[2]; \n "
" vec4 user_clip_factor[2]; \n "
" uint transform_branch_bits; \n "
" float point_size; \n "
" float z_near; \n "
" float z_far; \n "
" }; \n \n "
" layout(std140, binding = " < < GL_VERTEX_LAYOUT_BIND_SLOT < < " ) uniform VertexLayoutBuffer \n "
" { \n "
" uint vertex_base_index; \n "
" uint vertex_index_offset; \n "
" uvec4 input_attributes_blob[16 / 2]; \n "
" }; \n \n " ;
2014-12-17 15:01:59 +01:00
}
2021-03-05 20:05:37 +01:00
void GLVertexDecompilerThread : : insertInputs ( std : : stringstream & OS , const std : : vector < ParamType > & /*inputs*/ )
2012-11-15 00:39:56 +01:00
{
2025-03-15 20:52:36 +01:00
OS < < " layout(location=0) uniform usamplerBuffer persistent_input_stream; \n " ; // Data stream with persistent vertex data (cacheable)
OS < < " layout(location=1) uniform usamplerBuffer volatile_input_stream; \n " ; // Data stream with per-draw data (registers and immediate draw data)
2014-06-08 16:52:35 +02:00
}
2021-03-05 20:05:37 +01:00
void GLVertexDecompilerThread : : insertConstants ( std : : stringstream & OS , const std : : vector < ParamType > & constants )
2014-12-17 15:01:59 +01:00
{
2016-09-20 16:23:56 +02:00
for ( const ParamType & PT : constants )
{
for ( const ParamItem & PI : PT . items )
{
2022-03-23 21:59:42 +01:00
if ( PI . name . starts_with ( " vc[ " ) )
{
2025-03-15 20:52:36 +01:00
if ( ! ( m_prog . ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS ) )
{
OS < <
" layout(std140, binding = " < < GL_VERTEX_CONSTANT_BUFFERS_BIND_SLOT < < " ) uniform VertexConstantsBuffer \n "
" { \n "
" vec4 " < < PI . name < < " ; \n "
" }; \n \n " ;
}
else
{
OS < <
" layout(std430, binding = " < < GL_INSTANCING_LUT_BIND_SLOT < < " ) readonly buffer InstancingIndirectionLUT \n "
" { \n "
" int constants_addressing_lookup[]; \n "
" }; \n \n "
" layout(std430, binding = " < < GL_INSTANCING_XFORM_CONSTANTS_SLOT < < " ) readonly buffer InstancingVertexConstantsBlock \n "
" { \n "
" vec4 instanced_constants_array[]; \n "
" }; \n \n "
" #define CONSTANTS_ARRAY_LENGTH " < < ( properties . has_indexed_constants ? 468 : : : size32 ( m_constant_ids ) ) < < " \n \n " ;
}
2022-03-23 21:59:42 +01:00
2016-09-20 16:23:56 +02:00
continue ;
2022-03-23 21:59:42 +01:00
}
2016-09-20 16:23:56 +02:00
2025-02-08 16:19:44 +01:00
auto type = PT . type ;
if ( PT . type = = " sampler2D " | |
PT . type = = " samplerCube " | |
PT . type = = " sampler1D " | |
PT . type = = " sampler3D " )
{
if ( m_prog . texture_state . multisampled_textures ) [[ unlikely ]]
{
ensure ( PI . name . length ( ) > 3 ) ;
int index = atoi ( & PI . name [ 3 ] ) ;
if ( m_prog . texture_state . multisampled_textures & ( 1 < < index ) )
{
if ( type ! = " sampler1D " & & type ! = " sampler2D " )
{
rsx_log . error ( " Unexpected multisampled sampler type '%s' " , type ) ;
}
type = " sampler2DMS " ;
}
}
}
OS < < " uniform " < < type < < " " < < PI . name < < " ; \n " ;
2016-09-20 16:23:56 +02:00
}
}
2014-12-17 15:01:59 +01:00
}
2017-05-11 00:42:55 +02:00
static const vertex_reg_info reg_table [ ] =
2014-06-08 16:52:35 +02:00
{
2015-05-19 19:43:22 +02:00
{ " gl_Position " , false , " dst_reg0 " , " " , false } ,
2019-08-23 18:36:01 +02:00
{ " diff_color " , true , " dst_reg1 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE } ,
{ " spec_color " , true , " dst_reg2 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR } ,
2025-03-15 20:52:36 +01:00
// These are only present when back variants are specified, otherwise the default diff/spec color vars are for both front and back
2019-08-23 18:36:01 +02:00
{ " diff_color1 " , true , " dst_reg3 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE } ,
{ " spec_color1 " , true , " dst_reg4 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR | CELL_GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR } ,
2025-03-15 20:52:36 +01:00
// Fog output shares a data source register with clip planes 0-2 so only declare when specified
2017-05-11 00:42:55 +02:00
{ " fog_c " , true , " dst_reg5 " , " .xxxx " , true , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_FOG } ,
2025-03-15 20:52:36 +01:00
// Warning: Always define all 3 clip plane groups together to avoid flickering with openGL
2022-10-20 19:54:35 +02:00
{ " gl_ClipDistance[0] " , false , " dst_reg5 " , " .y * user_clip_factor[0].x " , false , " user_clip_enabled[0].x > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC0 } ,
{ " gl_ClipDistance[1] " , false , " dst_reg5 " , " .z * user_clip_factor[0].y " , false , " user_clip_enabled[0].y > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC1 } ,
{ " gl_ClipDistance[2] " , false , " dst_reg5 " , " .w * user_clip_factor[0].z " , false , " user_clip_enabled[0].z > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC2 } ,
2022-11-03 21:03:23 +01:00
{ " gl_PointSize " , false , " dst_reg6 " , " .x " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_POINTSIZE } ,
2022-10-20 19:54:35 +02:00
{ " gl_ClipDistance[3] " , false , " dst_reg6 " , " .y * user_clip_factor[0].w " , false , " user_clip_enabled[0].w > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC3 } ,
{ " gl_ClipDistance[4] " , false , " dst_reg6 " , " .z * user_clip_factor[1].x " , false , " user_clip_enabled[1].x > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC4 } ,
{ " gl_ClipDistance[5] " , false , " dst_reg6 " , " .w * user_clip_factor[1].y " , false , " user_clip_enabled[1].y > 0 " , " 0.5 " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_UC5 } ,
2019-08-23 18:36:01 +02:00
{ " tc0 " , true , " dst_reg7 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX0 } ,
{ " tc1 " , true , " dst_reg8 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX1 } ,
{ " tc2 " , true , " dst_reg9 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX2 } ,
{ " tc3 " , true , " dst_reg10 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX3 } ,
{ " tc4 " , true , " dst_reg11 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX4 } ,
{ " tc5 " , true , " dst_reg12 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX5 } ,
{ " tc6 " , true , " dst_reg13 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX6 } ,
{ " tc7 " , true , " dst_reg14 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX7 } ,
{ " tc8 " , true , " dst_reg15 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX8 } ,
2017-05-11 00:42:55 +02:00
{ " tc9 " , true , " dst_reg6 " , " " , false , " " , " " , " " , true , CELL_GCM_ATTRIB_OUTPUT_MASK_TEX9 } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15.
2015-05-19 19:43:22 +02:00
} ;
2021-03-05 20:05:37 +01:00
void GLVertexDecompilerThread : : insertOutputs ( std : : stringstream & OS , const std : : vector < ParamType > & /*outputs*/ )
2014-06-08 16:52:35 +02:00
{
2016-09-26 14:21:17 +02:00
for ( auto & i : reg_table )
2015-05-19 19:43:22 +02:00
{
2017-09-08 23:22:51 +02:00
if ( i . need_declare )
2015-05-24 17:05:54 +02:00
{
2019-08-23 18:36:01 +02:00
// All outputs must be declared always to allow setting default values
OS < < " layout(location= " < < gl : : get_varying_register_location ( i . name ) < < " ) out vec4 " < < i . name < < " ; \n " ;
2017-05-12 18:32:31 +02:00
}
2015-05-19 19:43:22 +02:00
}
2014-06-08 16:52:35 +02:00
}
2015-05-19 19:43:22 +02:00
void GLVertexDecompilerThread : : insertMainStart ( std : : stringstream & OS )
2014-01-07 21:11:02 +01:00
{
2019-04-16 12:50:39 +02:00
const auto & dev_caps = gl : : get_driver_caps ( ) ;
2019-06-15 15:15:44 +02:00
glsl : : shader_properties properties2 { } ;
2019-04-16 12:50:39 +02:00
properties2 . domain = glsl : : glsl_vertex_program ;
properties2 . require_lit_emulation = properties . has_lit_op ;
2020-08-16 11:48:20 +02:00
properties2 . emulate_zclip_transform = true ;
properties2 . emulate_depth_clip_only = dev_caps . NV_depth_buffer_float_supported ;
2022-04-24 10:56:42 +02:00
properties2 . low_precision_tests = dev_caps . vendor_NVIDIA ;
2022-10-22 22:45:29 +02:00
properties2 . require_explicit_invariance = dev_caps . vendor_MESA | | ( dev_caps . vendor_NVIDIA & & g_cfg . video . shader_precision ! = gpu_preset_level : : low ) ;
2025-03-15 20:52:36 +01:00
properties2 . require_instanced_render = ! ! ( m_prog . ctrl & RSX_SHADER_CONTROL_INSTANCED_CONSTANTS ) ;
2019-04-16 12:50:39 +02:00
insert_glsl_legacy_function ( OS , properties2 ) ;
glsl : : insert_vertex_input_fetch ( OS , glsl : : glsl_rules_opengl4 , dev_caps . vendor_INTEL = = false ) ;
2016-01-31 20:01:00 +01:00
2019-08-25 16:23:46 +02:00
// Declare global registers with optional initialization
std : : string registers ;
if ( ParamType * vec4Types = m_parr . SearchParam ( PF_PARAM_OUT , " vec4 " ) )
2016-09-26 14:21:17 +02:00
{
2019-08-25 16:23:46 +02:00
for ( auto & PI : vec4Types - > items )
2016-09-26 14:21:17 +02:00
{
2019-08-25 16:23:46 +02:00
if ( registers . length ( ) )
registers + = " , " ;
else
registers = " vec4 " ;
registers + = PI . name ;
2016-09-26 14:21:17 +02:00
2019-08-25 16:23:46 +02:00
if ( ! PI . value . empty ( ) )
{
// Simplify default initialization
if ( PI . value = = " vec4(0.0, 0.0, 0.0, 0.0) " )
registers + = " = vec4(0.) " ;
else
registers + = " = " + PI . value ;
}
2016-09-26 14:21:17 +02:00
}
}
2019-08-25 16:23:46 +02:00
if ( ! registers . empty ( ) )
{
OS < < registers < < " ; \n " ;
}
OS < < " void vs_main() \n " ;
2017-06-28 18:36:27 +02:00
OS < < " { \n " ;
2014-01-07 21:11:02 +01:00
2025-03-15 20:52:36 +01:00
// Declare temporary registers, ignoring those mapped to outputs
2019-06-08 08:01:28 +02:00
for ( const ParamType & PT : m_parr . params [ PF_PARAM_NONE ] )
2014-01-07 21:11:02 +01:00
{
2015-05-19 19:43:22 +02:00
for ( const ParamItem & PI : PT . items )
2014-01-07 21:11:02 +01:00
{
2020-02-29 06:29:28 +01:00
if ( PI . name . starts_with ( " dst_reg " ) )
2016-09-26 14:21:17 +02:00
continue ;
2015-05-19 19:43:22 +02:00
OS < < " " < < PT . type < < " " < < PI . name ;
if ( ! PI . value . empty ( ) )
OS < < " = " < < PI . value ;
2016-09-26 14:21:17 +02:00
2017-06-28 18:36:27 +02:00
OS < < " ; \n " ;
2014-01-07 21:11:02 +01:00
}
}
2016-01-28 18:01:10 +01:00
for ( const ParamType & PT : m_parr . params [ PF_PARAM_IN ] )
{
for ( const ParamItem & PI : PT . items )
2017-07-31 13:38:28 +02:00
{
OS < < " vec4 " < < PI . name < < " = read_location( " < < std : : to_string ( PI . location ) < < " ); \n " ;
}
2016-01-28 18:01:10 +01:00
}
2012-11-15 00:39:56 +01:00
}
2015-05-19 19:43:22 +02:00
void GLVertexDecompilerThread : : insertMainEnd ( std : : stringstream & OS )
2012-11-15 00:39:56 +01:00
{
2017-06-28 18:36:27 +02:00
OS < < " } \n \n " ;
2016-09-26 14:21:17 +02:00
2017-06-28 18:36:27 +02:00
OS < < " void main () \n " ;
OS < < " { \n " ;
2016-09-26 14:21:17 +02:00
2019-08-25 16:23:46 +02:00
OS < < " \n " < < " vs_main(); \n \n " ;
2016-09-26 14:21:17 +02:00
for ( auto & i : reg_table )
2014-06-08 16:52:35 +02:00
{
2019-08-23 18:36:01 +02:00
if ( ! i . check_mask | | i . test ( rsx_vertex_program . output_mask ) )
2016-09-26 14:21:17 +02:00
{
2019-08-23 18:36:01 +02:00
if ( m_parr . HasParam ( PF_PARAM_OUT , " vec4 " , i . src_reg ) )
{
std : : string condition = ( ! i . cond . empty ( ) ) ? " ( " + i . cond + " ) " : " " ;
2016-09-26 14:21:17 +02:00
2019-08-23 18:36:01 +02:00
if ( condition . empty ( ) | | i . default_val . empty ( ) )
{
if ( ! condition . empty ( ) ) condition = " if " + condition ;
OS < < " " < < condition < < i . name < < " = " < < i . src_reg < < i . src_reg_mask < < " ; \n " ;
}
else
{
2025-03-15 20:52:36 +01:00
// Insert if-else condition
2019-08-23 18:36:01 +02:00
OS < < " " < < i . name < < " = " < < condition < < " ? " < < i . src_reg < < i . src_reg_mask < < " : " < < i . default_val < < " ; \n " ;
}
2016-09-26 14:21:17 +02:00
2019-08-23 18:36:01 +02:00
// Register was marked for output and a properly initialized source register exists
// Nothing more to do
continue ;
2017-05-11 00:42:55 +02:00
}
2016-09-26 14:21:17 +02:00
}
2019-08-23 18:36:01 +02:00
if ( i . need_declare )
2017-06-26 15:41:14 +02:00
{
2019-08-23 18:36:01 +02:00
OS < < " " < < i . name < < " = vec4(0., 0., 0., 1.); \n " ;
2017-06-26 15:41:14 +02:00
}
2019-09-29 11:11:08 +02:00
else if ( i . check_mask_value = = CELL_GCM_ATTRIB_OUTPUT_MASK_POINTSIZE )
{
// Default point size if none was generated by the program
OS < < " gl_PointSize = point_size; \n " ;
}
2019-08-23 18:36:01 +02:00
}
2016-09-26 14:21:17 +02:00
2017-07-31 13:38:28 +02:00
OS < < " gl_Position = gl_Position * scale_offset_mat; \n " ;
2018-01-18 13:06:28 +01:00
OS < < " gl_Position = apply_zclip_xform(gl_Position, z_near, z_far); \n " ;
2017-06-14 17:47:01 +02:00
2025-03-15 20:52:36 +01:00
// Since our clip_space is symmetrical [-1, 1] we map it to linear space using the eqn:
// ln = (clip * 2) - 1 to fully utilize the 0-1 range of the depth buffer
// RSX matrices passed already map to the [0, 1] range but mapping to classic OGL requires that we undo this step
// This can be made unnecessary using the call glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE).
// However, ClipControl only made it to opengl core in ver 4.5 though, so this is a workaround.
// NOTE: It is completely valid for games to use very large w values, causing the post-multiplied z to be in the hundreds
// It is therefore critical that this step is done post-transform and the result re-scaled by w
// SEE Naruto: UNS
// NOTE: On GPUs, poor fp32 precision means dividing z by w, then multiplying by w again gives slightly incorrect results
// This equation is simplified algebraically to an addition and subtraction which gives more accurate results (Fixes flickering skybox in Dark Souls 2)
// OS << " float ndc_z = gl_Position.z / gl_Position.w;\n";
// OS << " ndc_z = (ndc_z * 2.) - 1.;\n";
// OS << " gl_Position.z = ndc_z * gl_Position.w;\n";
2017-11-18 11:02:10 +01:00
OS < < " gl_Position.z = (gl_Position.z + gl_Position.z) - gl_Position.w; \n " ;
2017-06-28 18:36:27 +02:00
OS < < " } \n " ;
2012-11-15 00:39:56 +01:00
}
2013-11-09 22:29:49 +01:00
void GLVertexDecompilerThread : : Task ( )
2012-11-15 00:39:56 +01:00
{
2015-05-19 19:43:22 +02:00
m_shader = Decompile ( ) ;
2012-11-15 00:39:56 +01:00
}
2019-06-08 09:33:48 +02:00
GLVertexProgram : : GLVertexProgram ( ) = default ;
2012-11-15 00:39:56 +01:00
2013-11-09 22:29:49 +01:00
GLVertexProgram : : ~ GLVertexProgram ( )
2012-11-15 00:39:56 +01:00
{
Delete ( ) ;
}
2016-01-10 20:09:56 +01:00
void GLVertexProgram : : Decompile ( const RSXVertexProgram & prog )
2012-11-15 00:39:56 +01:00
{
2020-05-16 07:50:28 +02:00
std : : string source ;
GLVertexDecompilerThread decompiler ( prog , source , parr ) ;
2014-06-11 22:22:32 +02:00
decompiler . Task ( ) ;
2020-05-16 07:50:28 +02:00
2022-03-23 23:23:20 +01:00
has_indexed_constants = decompiler . properties . has_indexed_constants ;
constant_ids = std : : vector < u16 > ( decompiler . m_constant_ids . begin ( ) , decompiler . m_constant_ids . end ( ) ) ;
2022-03-23 21:59:42 +01:00
2020-05-16 08:31:25 +02:00
shader . create ( : : glsl : : program_domain : : glsl_vertex_program , source ) ;
2020-05-16 07:50:28 +02:00
id = shader . id ( ) ;
2012-11-15 00:39:56 +01:00
}
2013-11-09 22:29:49 +01:00
void GLVertexProgram : : Delete ( )
2012-11-15 00:39:56 +01:00
{
2020-05-16 07:50:28 +02:00
shader . remove ( ) ;
id = 0 ;
2012-11-15 00:39:56 +01:00
}