2020-11-18 19:11:30 +01:00
/*************************************************************************/
2021-10-26 17:18:39 +02:00
/* shader_gles3.h */
2020-11-18 19:11:30 +01:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
2022-01-03 21:27:34 +01:00
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
2020-11-18 19:11:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2021-09-27 01:07:10 +02:00
# ifndef SHADER_OPENGL_H
# define SHADER_OPENGL_H
2020-11-18 19:11:30 +01:00
2022-05-18 17:04:41 +02:00
# include "core/math/camera_matrix.h"
2021-11-13 12:54:58 +01:00
# include "core/os/mutex.h"
# include "core/string/string_builder.h"
# include "core/templates/hash_map.h"
# include "core/templates/local_vector.h"
2022-05-13 15:04:37 +02:00
# include "core/templates/rb_map.h"
2021-11-13 12:54:58 +01:00
# include "core/templates/rid_owner.h"
# include "core/variant/variant.h"
# include "servers/rendering_server.h"
2021-11-16 16:25:42 +01:00
# ifdef GLES3_ENABLED
2020-11-18 19:11:30 +01:00
// This must come first to avoid windows.h mess
# include "platform_config.h"
2021-09-27 01:07:10 +02:00
# ifndef OPENGL_INCLUDE_H
# include <GLES3/gl3.h>
2020-11-18 19:11:30 +01:00
# else
2021-09-27 01:07:10 +02:00
# include OPENGL_INCLUDE_H
2020-11-18 19:11:30 +01:00
# endif
# include <stdio.h>
2021-10-26 17:18:39 +02:00
class ShaderGLES3 {
2020-11-18 19:11:30 +01:00
protected :
2021-11-13 12:54:58 +01:00
struct TexUnitPair {
2020-11-18 19:11:30 +01:00
const char * name ;
int index ;
} ;
2021-11-13 12:54:58 +01:00
struct UBOPair {
2020-11-18 19:11:30 +01:00
const char * name ;
2021-11-13 12:54:58 +01:00
int index ;
2020-11-18 19:11:30 +01:00
} ;
2021-11-13 12:54:58 +01:00
struct Specialization {
2020-11-18 19:11:30 +01:00
const char * name ;
2021-11-16 16:25:42 +01:00
bool default_value = false ;
2020-11-18 19:11:30 +01:00
} ;
private :
2021-11-13 12:54:58 +01:00
//versions
CharString general_defines ;
2020-11-18 19:11:30 +01:00
2022-05-03 22:28:15 +02:00
// A version is a high-level construct which is a combination of built-in and user-defined shader code, Each user-created Shader makes one version
// Variants use #ifdefs to toggle behaviour on and off to change behaviour of the shader
// All variants are compiled each time a new version is created
2021-11-16 16:25:42 +01:00
// Specializations use #ifdefs to toggle behaviour on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
2022-05-03 22:28:15 +02:00
// Use specializations to enable and disabled advanced features, use variants to toggle behaviour when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
2020-11-18 19:11:30 +01:00
struct Version {
2021-11-13 12:54:58 +01:00
Vector < StringName > texture_uniforms ;
CharString uniforms ;
CharString vertex_globals ;
CharString fragment_globals ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , CharString > code_sections ;
2021-11-13 12:54:58 +01:00
Vector < CharString > custom_defines ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
struct Specialization {
GLuint id ;
GLuint vert_id ;
GLuint frag_id ;
LocalVector < GLint > uniform_location ;
LocalVector < GLint > texture_uniform_locations ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , GLint > custom_uniform_locations ;
2021-11-13 12:54:58 +01:00
bool build_queued = false ;
bool ok = false ;
Specialization ( ) {
id = 0 ;
vert_id = 0 ;
frag_id = 0 ;
}
2020-11-18 19:11:30 +01:00
} ;
2021-11-13 12:54:58 +01:00
LocalVector < OAHashMap < uint64_t , Specialization > > variants ;
2020-11-18 19:11:30 +01:00
} ;
2021-11-13 12:54:58 +01:00
Mutex variant_set_mutex ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
void _compile_specialization ( Version : : Specialization & spec , uint32_t p_variant , Version * p_version , uint64_t p_specialization ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
void _clear_version ( Version * p_version ) ;
void _initialize_version ( Version * p_version ) ;
2020-11-18 19:11:30 +01:00
2022-02-20 01:08:53 +01:00
RID_Owner < Version , true > version_owner ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
struct StageTemplate {
struct Chunk {
enum Type {
TYPE_MATERIAL_UNIFORMS ,
TYPE_VERTEX_GLOBALS ,
TYPE_FRAGMENT_GLOBALS ,
TYPE_CODE ,
TYPE_TEXT
} ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
Type type ;
StringName code ;
CharString text ;
} ;
LocalVector < Chunk > chunks ;
} ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
String name ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
String base_sha256 ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
static String shader_cache_dir ;
static bool shader_cache_cleanup_on_start ;
static bool shader_cache_save_compressed ;
static bool shader_cache_save_compressed_zstd ;
static bool shader_cache_save_debug ;
bool shader_cache_dir_valid = false ;
2020-11-18 19:11:30 +01:00
2022-05-02 16:28:25 +02:00
GLint max_image_units = 0 ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
enum StageType {
STAGE_TYPE_VERTEX ,
STAGE_TYPE_FRAGMENT ,
STAGE_TYPE_MAX ,
} ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
StageTemplate stage_templates [ STAGE_TYPE_MAX ] ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
void _build_variant_code ( StringBuilder & p_builder , uint32_t p_variant , const Version * p_version , const StageTemplate & p_template , uint64_t p_specialization ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
void _add_stage ( const char * p_code , StageType p_stage_type ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
String _version_get_sha1 ( Version * p_version ) const ;
bool _load_from_cache ( Version * p_version ) ;
void _save_to_cache ( Version * p_version ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
const char * * uniform_names = nullptr ;
int uniform_count = 0 ;
const UBOPair * ubo_pairs = nullptr ;
int ubo_count = 0 ;
const TexUnitPair * texunit_pairs = nullptr ;
int texunit_pair_count = 0 ;
int specialization_count = 0 ;
const Specialization * specializations = nullptr ;
uint64_t specialization_default_mask = 0 ;
const char * * variant_defines = nullptr ;
int variant_count = 0 ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
int base_texture_index = 0 ;
2021-11-16 16:25:42 +01:00
Version : : Specialization * current_shader = nullptr ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
protected :
ShaderGLES3 ( ) ;
void _setup ( const char * p_vertex_code , const char * p_fragment_code , const char * p_name , int p_uniform_count , const char * * p_uniform_names , int p_ubo_count , const UBOPair * p_ubos , int p_texture_count , const TexUnitPair * p_tex_units , int p_specialization_count , const Specialization * p_specializations , int p_variant_count , const char * * p_variants ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
_FORCE_INLINE_ void _version_bind_shader ( RID p_version , int p_variant , uint64_t p_specialization ) {
ERR_FAIL_INDEX ( p_variant , variant_count ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
Version * version = version_owner . get_or_null ( p_version ) ;
ERR_FAIL_COND ( ! version ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
if ( version - > variants . size ( ) = = 0 ) {
_initialize_version ( version ) ; //may lack initialization
}
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
Version : : Specialization * spec = version - > variants [ p_variant ] . lookup_ptr ( p_specialization ) ;
if ( ! spec ) {
if ( false ) {
// Queue load this specialization and use defaults in the meantime (TODO)
spec = version - > variants [ p_variant ] . lookup_ptr ( specialization_default_mask ) ;
} else {
// Compile on the spot
Version : : Specialization s ;
_compile_specialization ( s , p_variant , version , p_specialization ) ;
version - > variants [ p_variant ] . insert ( p_specialization , s ) ;
spec = version - > variants [ p_variant ] . lookup_ptr ( p_specialization ) ;
}
} else if ( spec - > build_queued ) {
// Still queued, wait
spec = version - > variants [ p_variant ] . lookup_ptr ( specialization_default_mask ) ;
}
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
ERR_FAIL_COND ( ! spec ) ; // Should never happen
ERR_FAIL_COND ( ! spec - > ok ) ; // Should never happen
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
glUseProgram ( spec - > id ) ;
2021-11-16 16:25:42 +01:00
current_shader = spec ;
}
_FORCE_INLINE_ int _version_get_uniform ( int p_which , RID p_version , int p_variant , uint64_t p_specialization ) {
ERR_FAIL_INDEX_V ( p_which , uniform_count , - 1 ) ;
Version * version = version_owner . get_or_null ( p_version ) ;
ERR_FAIL_COND_V ( ! version , - 1 ) ;
2022-05-10 19:02:44 +02:00
ERR_FAIL_INDEX_V ( p_variant , int ( version - > variants . size ( ) ) , - 1 ) ;
2022-05-16 20:56:03 +02:00
Version : : Specialization * spec = version - > variants [ p_variant ] . lookup_ptr ( p_specialization ) ;
ERR_FAIL_COND_V ( ! spec , - 1 ) ;
ERR_FAIL_INDEX_V ( p_which , int ( spec - > uniform_location . size ( ) ) , - 1 ) ;
return spec - > uniform_location [ p_which ] ;
2020-11-18 19:11:30 +01:00
}
2021-11-13 12:54:58 +01:00
virtual void _init ( ) = 0 ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
public :
RID version_create ( ) ;
2020-11-18 19:11:30 +01:00
2022-05-13 15:04:37 +02:00
void version_set_code ( RID p_version , const HashMap < String , String > & p_code , const String & p_uniforms , const String & p_vertex_globals , const String & p_fragment_globals , const Vector < String > & p_custom_defines , const Vector < StringName > & p_texture_uniforms , bool p_initialize = false ) ;
2021-11-13 12:54:58 +01:00
bool version_is_valid ( RID p_version ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
bool version_free ( RID p_version ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
static void set_shader_cache_dir ( const String & p_dir ) ;
static void set_shader_cache_save_compressed ( bool p_enable ) ;
static void set_shader_cache_save_compressed_zstd ( bool p_enable ) ;
static void set_shader_cache_save_debug ( bool p_enable ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
RS : : ShaderNativeSourceCode version_get_native_source_code ( RID p_version ) ;
2020-11-18 19:11:30 +01:00
2021-11-13 12:54:58 +01:00
void initialize ( const String & p_general_defines = " " , int p_base_texture_index = 0 ) ;
virtual ~ ShaderGLES3 ( ) ;
} ;
2021-09-27 01:07:10 +02:00
# endif // SHADER_OPENGL_H
2021-11-13 12:54:58 +01:00
# endif