2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2018-09-29 00:12:00 +02:00
# include "GLFragmentProgram.h"
2021-01-10 20:59:39 +01:00
# include "Emu/system_config.h"
2015-05-22 19:18:20 +02:00
# include "GLCommonDecompiler.h"
2015-11-30 19:39:14 +01:00
# include "../GCM.h"
2021-05-12 23:56:01 +02:00
# include "../Program/GLSLCommon.h"
2025-02-09 19:15:23 +01:00
# include "../RSXThread.h"
2017-09-08 23:22:51 +02:00
2020-12-18 08:39:54 +01:00
std : : string GLFragmentDecompilerThread : : getFloatTypeName ( usz elementCount )
2012-11-15 00:39:56 +01:00
{
2017-08-04 16:11:39 +02:00
return glsl : : getFloatTypeNameImpl ( elementCount ) ;
2014-06-07 16:15:49 +02:00
}
2012-11-15 00:39:56 +01:00
2020-12-18 08:39:54 +01:00
std : : string GLFragmentDecompilerThread : : getHalfTypeName ( usz elementCount )
2019-04-12 23:25:44 +02:00
{
return glsl : : getHalfTypeNameImpl ( elementCount ) ;
}
2015-05-19 19:43:22 +02:00
std : : string GLFragmentDecompilerThread : : getFunction ( FUNCTION f )
2014-06-07 16:15:49 +02:00
{
2017-11-05 23:48:34 +01:00
return glsl : : getFunctionImpl ( f ) ;
2012-11-15 00:39:56 +01:00
}
2015-05-19 19:43:22 +02:00
std : : string GLFragmentDecompilerThread : : compareFunction ( COMPARE f , const std : : string & Op0 , const std : : string & Op1 )
2013-08-26 16:18:59 +02:00
{
2017-08-04 16:11:39 +02:00
return glsl : : compareFunctionImpl ( f , Op0 , Op1 ) ;
2013-06-30 10:46:29 +02:00
}
2015-05-19 19:43:22 +02:00
void GLFragmentDecompilerThread : : insertHeader ( std : : stringstream & OS )
2013-08-19 01:06:11 +02:00
{
2022-12-10 19:14:36 +01:00
int gl_version = 430 ;
std : : vector < std : : string > required_extensions ;
2019-04-12 23:25:44 +02:00
if ( device_props . has_native_half_support )
{
const auto driver_caps = gl : : get_driver_caps ( ) ;
if ( driver_caps . NV_gpu_shader5_supported )
{
2022-12-10 19:14:36 +01:00
required_extensions . push_back ( " GL_NV_gpu_shader5 " ) ;
2019-04-12 23:25:44 +02:00
}
else if ( driver_caps . AMD_gpu_shader_half_float_supported )
{
2022-12-10 19:14:36 +01:00
required_extensions . push_back ( " GL_AMD_gpu_shader_half_float " ) ;
2019-04-12 23:25:44 +02:00
}
}
2019-10-13 23:30:34 +02:00
2025-02-08 16:19:44 +01:00
if ( properties . multisampled_sampler_mask )
{
// Requires this extension or GLSL 450
const auto driver_caps = gl : : get_driver_caps ( ) ;
if ( driver_caps . glsl_version . version > = 450 )
{
gl_version = 450 ;
}
else
{
ensure ( driver_caps . ARB_shader_texture_image_samples , " MSAA support on OpenGL requires a driver running OpenGL 4.5 or supporting GL_ARB_shader_texture_image_samples. " ) ;
required_extensions . push_back ( " GL_ARB_shader_texture_image_samples " ) ;
}
}
2022-12-10 19:14:36 +01:00
if ( m_prog . ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION )
{
2022-12-11 00:12:52 +01:00
gl_version = std : : max ( gl_version , 450 ) ;
2022-12-10 19:14:36 +01:00
required_extensions . push_back ( " GL_NV_fragment_shader_barycentric " ) ;
}
OS < < " #version " < < gl_version < < " \n " ;
for ( const auto & ext : required_extensions )
{
OS < < " #extension " < < ext < < " : require \n " ;
}
2019-10-13 23:30:34 +02:00
glsl : : insert_subheader_block ( OS ) ;
2013-08-19 01:06:11 +02:00
}
2018-04-29 08:41:51 +02:00
void GLFragmentDecompilerThread : : insertInputs ( std : : stringstream & OS )
2013-06-30 10:46:29 +02:00
{
2022-12-05 20:28:43 +01:00
glsl : : insert_fragment_shader_inputs_block (
OS ,
2022-12-10 16:20:43 +01:00
glsl : : extension_flavour : : NV ,
2022-12-05 20:28:43 +01:00
m_prog ,
m_parr . params [ PF_PARAM_IN ] ,
2016-03-02 22:58:59 +01:00
{
2022-12-05 20:28:43 +01:00
. two_sided_color = ! ! ( properties . in_register_mask & in_diff_color ) ,
. two_sided_specular = ! ! ( properties . in_register_mask & in_spec_color )
} ,
gl : : get_varying_register_location
) ;
2012-11-15 00:39:56 +01:00
}
2015-05-19 19:43:22 +02:00
void GLFragmentDecompilerThread : : insertOutputs ( std : : stringstream & OS )
2012-11-15 00:39:56 +01:00
{
2015-05-19 19:43:22 +02:00
const std : : pair < std : : string , std : : string > table [ ] =
2014-06-07 16:15:49 +02:00
{
2015-11-30 19:39:14 +01:00
{ " ocol0 " , m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? " r0 " : " h0 " } ,
{ " ocol1 " , m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? " r2 " : " h4 " } ,
{ " ocol2 " , m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? " r3 " : " h6 " } ,
{ " ocol3 " , m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? " r4 " : " h8 " } ,
2014-06-07 16:15:49 +02:00
} ;
2019-04-13 12:20:50 +02:00
const bool float_type = ( m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ) | | ! device_props . has_native_half_support ;
const auto reg_type = float_type ? " vec4 " : getHalfTypeName ( 4 ) ;
2020-02-19 18:03:59 +01:00
for ( uint i = 0 ; i < std : : size ( table ) ; + + i )
2014-06-07 16:15:49 +02:00
{
2019-04-12 23:25:44 +02:00
if ( m_parr . HasParam ( PF_PARAM_NONE , reg_type , table [ i ] . second ) )
2017-09-04 11:53:17 +02:00
OS < < " layout(location= " < < i < < " ) out vec4 " < < table [ i ] . first < < " ; \n " ;
2014-06-07 16:15:49 +02:00
}
}
2015-05-19 19:43:22 +02:00
void GLFragmentDecompilerThread : : insertConstants ( std : : stringstream & OS )
2014-12-17 15:01:59 +01:00
{
2015-11-29 18:20:43 +01:00
for ( const ParamType & PT : m_parr . params [ PF_PARAM_UNIFORM ] )
2014-12-17 15:01:59 +01:00
{
2016-02-03 11:05:18 +01:00
if ( PT . type ! = " sampler1D " & &
PT . type ! = " sampler2D " & &
PT . type ! = " sampler3D " & &
PT . type ! = " samplerCube " )
2015-05-19 19:43:22 +02:00
continue ;
2016-02-03 11:05:18 +01:00
2015-11-29 18:20:43 +01:00
for ( const ParamItem & PI : PT . items )
2016-02-03 11:05:18 +01:00
{
std : : string samplerType = PT . type ;
2019-06-08 10:04:53 +02:00
int index = atoi ( & PI . name [ 3 ] ) ;
2014-12-17 15:01:59 +01:00
2017-06-14 00:33:53 +02:00
const auto mask = ( 1 < < index ) ;
2025-02-08 16:19:44 +01:00
if ( properties . multisampled_sampler_mask & mask )
2018-11-24 13:54:46 +01:00
{
2025-02-08 16:19:44 +01:00
if ( samplerType ! = " sampler1D " & & samplerType ! = " sampler2D " )
{
rsx_log . error ( " Unexpected multisampled image type '%s' " , samplerType ) ;
}
samplerType = " sampler2DMS " ;
2018-11-24 13:54:46 +01:00
}
2020-12-24 19:44:15 +01:00
else if ( properties . shadow_sampler_mask & mask )
2017-06-14 00:33:53 +02:00
{
2021-01-20 21:23:00 +01:00
if ( properties . common_access_sampler_mask & mask )
{
2020-12-24 19:44:15 +01:00
rsx_log . error ( " Texture unit %d is sampled as both a shadow texture and a depth texture " , index ) ;
2021-01-20 21:23:00 +01:00
}
2020-12-24 19:44:15 +01:00
else
2021-01-20 21:23:00 +01:00
{
samplerType + = " Shadow " ;
}
2017-06-14 00:33:53 +02:00
}
2017-06-12 11:42:30 +02:00
2025-02-08 16:19:44 +01:00
if ( properties . redirected_sampler_mask & mask )
{
// Provide a stencil view of the main resource for the S channel
OS < < " uniform u " < < samplerType < < " " < < PI . name < < " _stencil; \n " ;
}
2017-06-28 18:36:27 +02:00
OS < < " uniform " < < samplerType < < " " < < PI . name < < " ; \n " ;
2016-02-03 11:05:18 +01:00
}
2014-12-17 15:01:59 +01:00
}
2017-06-28 18:36:27 +02:00
OS < < " \n " ;
2016-02-03 11:05:18 +01:00
2018-10-20 16:43:00 +02:00
std : : string constants_block ;
2015-11-29 18:20:43 +01:00
for ( const ParamType & PT : m_parr . params [ PF_PARAM_UNIFORM ] )
2014-12-17 15:01:59 +01:00
{
2016-02-03 11:05:18 +01:00
if ( PT . type = = " sampler1D " | |
PT . type = = " sampler2D " | |
PT . type = = " sampler3D " | |
PT . type = = " samplerCube " )
2015-05-19 19:43:22 +02:00
continue ;
2016-02-03 11:05:18 +01:00
2015-11-29 18:20:43 +01:00
for ( const ParamItem & PI : PT . items )
2018-10-20 16:43:00 +02:00
{
constants_block + = " " + PT . type + " " + PI . name + " ; \n " ;
}
2014-12-17 15:01:59 +01:00
}
2016-02-03 11:05:18 +01:00
2018-10-20 16:43:00 +02:00
if ( ! constants_block . empty ( ) )
{
2021-10-09 14:12:05 +02:00
OS < < " layout(std140, binding = " < < GL_FRAGMENT_CONSTANT_BUFFERS_BIND_SLOT < < " ) uniform FragmentConstantsBuffer \n " ;
2018-10-20 16:43:00 +02:00
OS < < " { \n " ;
OS < < constants_block ;
OS < < " }; \n \n " ;
}
2021-10-09 14:12:05 +02:00
OS < < " layout(std140, binding = " < < GL_FRAGMENT_STATE_BIND_SLOT < < " ) uniform FragmentStateBuffer \n " ;
2018-10-20 16:43:00 +02:00
OS < < " { \n " ;
2017-02-10 10:08:46 +01:00
OS < < " float fog_param0; \n " ;
OS < < " float fog_param1; \n " ;
2018-03-23 12:47:03 +01:00
OS < < " uint rop_control; \n " ;
2017-02-10 10:08:46 +01:00
OS < < " float alpha_ref; \n " ;
2018-03-23 12:47:03 +01:00
OS < < " uint reserved; \n " ;
2017-08-21 19:56:31 +02:00
OS < < " uint fog_mode; \n " ;
2017-09-26 15:24:43 +02:00
OS < < " float wpos_scale; \n " ;
OS < < " float wpos_bias; \n " ;
2018-10-20 16:43:00 +02:00
OS < < " }; \n \n " ;
2021-10-09 14:12:05 +02:00
OS < < " layout(std140, binding = " < < GL_FRAGMENT_TEXTURE_PARAMS_BIND_SLOT < < " ) uniform TextureParametersBuffer \n " ;
2018-10-20 16:43:00 +02:00
OS < < " { \n " ;
2019-10-13 23:30:34 +02:00
OS < < " sampler_info texture_parameters[16]; \n " ;
2018-10-20 16:43:00 +02:00
OS < < " }; \n \n " ;
2020-05-28 23:51:36 +02:00
OS < < " layout(std140, binding = " < < GL_RASTERIZER_STATE_BIND_SLOT < < " ) uniform RasterizerHeap \n " ;
OS < < " { \n " ;
OS < < " uvec4 stipple_pattern[8]; \n " ;
OS < < " }; \n \n " ;
2014-12-17 15:01:59 +01:00
}
2017-12-02 13:13:13 +01:00
void GLFragmentDecompilerThread : : insertGlobalFunctions ( std : : stringstream & OS )
2012-11-15 00:39:56 +01:00
{
2019-10-14 00:24:04 +02:00
m_shader_props . domain = glsl : : glsl_fragment_program ;
m_shader_props . require_lit_emulation = properties . has_lit_op ;
m_shader_props . fp32_outputs = ! ! ( m_prog . ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ) ;
2020-12-24 19:44:15 +01:00
m_shader_props . require_depth_conversion = properties . redirected_sampler_mask ! = 0 ;
2019-10-14 00:24:04 +02:00
m_shader_props . require_wpos = ! ! ( properties . in_register_mask & in_wpos ) ;
m_shader_props . require_texture_ops = properties . has_tex_op ;
2023-06-20 13:54:32 +02:00
m_shader_props . require_tex_shadow_ops = properties . shadow_sampler_mask ! = 0 ;
2025-02-08 16:19:44 +01:00
m_shader_props . require_msaa_ops = properties . multisampled_sampler_mask ! = 0 ;
2020-06-11 21:46:53 +02:00
m_shader_props . require_texture_expand = properties . has_exp_tex_op ;
2021-06-05 01:40:39 +02:00
m_shader_props . require_srgb_to_linear = properties . has_upg ;
m_shader_props . require_linear_to_srgb = properties . has_pkg ;
2023-06-19 23:20:51 +02:00
m_shader_props . require_fog_read = properties . in_register_mask & in_fogc ;
2025-02-09 19:15:23 +01:00
m_shader_props . emulate_coverage_tests = ! rsx : : get_renderer_backend_config ( ) . supports_hw_a2c_1spp ;
2019-10-14 00:24:04 +02:00
m_shader_props . emulate_shadow_compare = device_props . emulate_depth_compare ;
2022-12-05 20:28:43 +01:00
m_shader_props . low_precision_tests = : : gl : : get_driver_caps ( ) . vendor_NVIDIA & & ! ( m_prog . ctrl & RSX_SHADER_CONTROL_ATTRIBUTE_INTERPOLATION ) ;
2019-10-14 00:24:04 +02:00
m_shader_props . disable_early_discard = ! : : gl : : get_driver_caps ( ) . vendor_NVIDIA ;
m_shader_props . supports_native_fp16 = device_props . has_native_half_support ;
2023-11-21 01:02:59 +01:00
m_shader_props . ROP_output_rounding = g_cfg . video . shader_precision ! = gpu_preset_level : : low ;
2023-06-20 13:54:32 +02:00
m_shader_props . require_tex1D_ops = properties . has_tex1D ;
m_shader_props . require_tex2D_ops = properties . has_tex2D ;
m_shader_props . require_tex3D_ops = properties . has_tex3D ;
2023-07-08 15:47:04 +02:00
m_shader_props . require_shadowProj_ops = properties . shadow_sampler_mask ! = 0 & & properties . has_texShadowProj ;
2019-10-14 00:24:04 +02:00
glsl : : insert_glsl_legacy_function ( OS , m_shader_props ) ;
2017-12-02 13:13:13 +01:00
}
2016-01-03 18:40:19 +01:00
2017-12-02 13:13:13 +01:00
void GLFragmentDecompilerThread : : insertMainStart ( std : : stringstream & OS )
{
2019-08-25 16:23:46 +02:00
std : : set < std : : string > output_registers ;
if ( m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS )
2016-09-26 14:21:17 +02:00
{
2019-08-25 16:23:46 +02:00
output_registers = { " r0 " , " r2 " , " r3 " , " r4 " } ;
}
else
{
output_registers = { " h0 " , " h4 " , " h6 " , " h8 " } ;
}
2016-09-26 14:21:17 +02:00
2019-08-25 16:23:46 +02:00
if ( m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT )
{
output_registers . insert ( " r1 " ) ;
}
std : : string registers ;
std : : string reg_type ;
2019-04-12 23:25:44 +02:00
const auto half4 = getHalfTypeName ( 4 ) ;
2019-08-25 16:23:46 +02:00
for ( auto & reg_name : output_registers )
2016-09-26 14:21:17 +02:00
{
2019-04-12 23:25:44 +02:00
const auto type = ( reg_name [ 0 ] = = ' r ' | | ! device_props . has_native_half_support ) ? " vec4 " : half4 ;
2020-02-05 08:00:08 +01:00
if ( reg_type = = type ) [[likely]]
2016-09-26 14:21:17 +02:00
{
2019-08-25 16:23:46 +02:00
registers + = " , " + reg_name + " = " + type + " (0.) " ;
}
else
{
if ( ! registers . empty ( ) )
registers + = " ; \n " ;
2016-09-26 14:21:17 +02:00
2019-08-25 16:23:46 +02:00
registers + = type + " " + reg_name + " = " + type + " (0.) " ;
2016-09-26 14:21:17 +02:00
}
2019-08-25 16:23:46 +02:00
reg_type = type ;
2016-09-26 14:21:17 +02:00
}
2019-08-25 16:23:46 +02:00
if ( ! registers . empty ( ) )
{
OS < < registers < < " ; \n " ;
}
OS < < " void fs_main() \n " ;
2017-06-28 18:36:27 +02:00
OS < < " { \n " ;
2012-11-15 00:39:56 +01:00
2015-11-29 18:20:43 +01:00
for ( const ParamType & PT : m_parr . params [ PF_PARAM_NONE ] )
2012-11-15 00:39:56 +01:00
{
2019-08-25 16:23:46 +02:00
for ( const auto & PI : PT . items )
2012-11-15 00:39:56 +01:00
{
2019-08-25 16:23:46 +02:00
if ( output_registers . find ( PI . name ) ! = output_registers . end ( ) )
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 " ;
2012-11-15 00:39:56 +01:00
}
}
2016-02-22 21:53:46 +01:00
2019-08-25 16:23:46 +02:00
if ( properties . has_w_access )
OS < < " float in_w = (1. / gl_FragCoord.w); \n " ;
2016-02-27 18:43:51 +01:00
2019-08-23 18:36:01 +02:00
if ( properties . in_register_mask & in_ssa )
OS < < " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.); \n " ;
2016-09-26 14:21:17 +02:00
2019-08-23 18:36:01 +02:00
if ( properties . in_register_mask & in_wpos )
OS < < " vec4 wpos = get_wpos(); \n " ;
2016-09-26 14:21:17 +02:00
2019-08-23 18:36:01 +02:00
if ( properties . in_register_mask & in_fogc )
OS < < " vec4 fogc = fetch_fog_value(fog_mode); \n " ;
2016-09-26 14:21:17 +02:00
2019-08-23 18:36:01 +02:00
if ( m_prog . two_sided_lighting )
{
if ( properties . in_register_mask & in_diff_color )
OS < < " vec4 diff_color = gl_FrontFacing ? diff_color1 : diff_color0; \n " ;
if ( properties . in_register_mask & in_spec_color )
OS < < " vec4 spec_color = gl_FrontFacing ? spec_color1 : spec_color0; \n " ;
2016-02-27 18:43:51 +01:00
}
2012-11-15 00:39:56 +01:00
}
2015-05-19 19:43:22 +02:00
void GLFragmentDecompilerThread : : insertMainEnd ( std : : stringstream & OS )
2012-11-15 00:39:56 +01:00
{
2018-03-09 10:31:01 +01:00
OS < < " } \n \n " ;
OS < < " void main() \n " ;
OS < < " { \n " ;
2020-05-28 23:51:36 +02:00
: : glsl : : insert_rop_init ( OS ) ;
2019-08-25 16:23:46 +02:00
OS < < " \n " < < " fs_main(); \n \n " ;
2018-03-09 10:31:01 +01:00
2019-10-14 00:24:04 +02:00
glsl : : insert_rop ( OS , m_shader_props ) ;
2016-09-26 14:21:17 +02:00
if ( m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT )
{
2017-03-07 11:40:38 +01:00
if ( m_parr . HasParam ( PF_PARAM_NONE , " vec4 " , " r1 " ) )
2016-09-26 14:21:17 +02:00
{
2018-02-25 10:46:27 +01:00
//Depth writes are always from a fp32 register. See issues section on nvidia's NV_fragment_program spec
//https://www.khronos.org/registry/OpenGL/extensions/NV/NV_fragment_program.txt
2016-09-26 14:21:17 +02:00
OS < < " gl_FragDepth = r1.z; \n " ;
}
2017-03-07 11:40:38 +01:00
else
{
//Input not declared. Leave commented to assist in debugging the shader
OS < < " //gl_FragDepth = r1.z; \n " ;
}
2016-09-26 14:21:17 +02:00
}
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 GLFragmentDecompilerThread : : 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
GLFragmentProgram : : GLFragmentProgram ( ) = default ;
2012-11-15 00:39:56 +01:00
2015-01-01 23:55:02 +01:00
GLFragmentProgram : : ~ GLFragmentProgram ( )
2012-11-15 00:39:56 +01:00
{
Delete ( ) ;
}
2016-01-10 20:09:56 +01:00
void GLFragmentProgram : : Decompile ( const RSXFragmentProgram & prog )
2012-11-15 00:39:56 +01:00
{
2016-01-10 20:09:56 +01:00
u32 size ;
2020-05-16 07:50:28 +02:00
std : : string source ;
GLFragmentDecompilerThread decompiler ( source , parr , prog , size ) ;
2019-04-12 23:25:44 +02:00
2022-10-10 15:19:11 +02:00
if ( g_cfg . video . shader_precision = = gpu_preset_level : : low )
2019-04-12 23:25:44 +02:00
{
const auto driver_caps = gl : : get_driver_caps ( ) ;
decompiler . device_props . has_native_half_support = driver_caps . NV_gpu_shader5_supported | | driver_caps . AMD_gpu_shader_half_float_supported ;
2021-06-09 00:37:59 +02:00
decompiler . device_props . has_low_precision_rounding = driver_caps . vendor_NVIDIA ;
2019-04-12 23:25:44 +02:00
}
2014-04-15 16:12:15 +02:00
decompiler . Task ( ) ;
2019-04-12 23:25:44 +02:00
2015-05-19 19:43:22 +02:00
for ( const ParamType & PT : decompiler . m_parr . params [ PF_PARAM_UNIFORM ] )
{
2015-11-29 18:20:43 +01:00
for ( const ParamItem & PI : PT . items )
2015-05-19 19:43:22 +02:00
{
2016-09-26 14:21:17 +02:00
if ( PT . type = = " sampler1D " | |
PT . type = = " sampler2D " | |
PT . type = = " sampler3D " | |
PT . type = = " samplerCube " )
2015-06-05 00:44:27 +02:00
continue ;
2016-09-26 14:21:17 +02:00
2020-12-18 08:39:54 +01:00
usz offset = atoi ( PI . name . c_str ( ) + 2 ) ;
2015-05-19 19:43:22 +02:00
FragmentConstantOffsetCache . push_back ( offset ) ;
}
}
2020-05-16 07:50:28 +02:00
2020-05-16 08:31:25 +02:00
shader . create ( : : glsl : : program_domain : : glsl_fragment_program , source ) ;
2020-05-16 07:50:28 +02:00
id = shader . id ( ) ;
2012-11-15 00:39:56 +01:00
}
2015-01-01 23:55:02 +01:00
void GLFragmentProgram : : Delete ( )
2012-11-15 00:39:56 +01:00
{
2020-05-16 07:50:28 +02:00
shader . remove ( ) ;
id = 0 ;
2013-11-19 11:30:58 +01:00
}