1 | /**************************************************************************/ |
2 | /* shader_rd.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef SHADER_RD_H |
32 | #define SHADER_RD_H |
33 | |
34 | #include "core/os/mutex.h" |
35 | #include "core/string/string_builder.h" |
36 | #include "core/templates/hash_map.h" |
37 | #include "core/templates/local_vector.h" |
38 | #include "core/templates/rb_map.h" |
39 | #include "core/templates/rid_owner.h" |
40 | #include "core/variant/variant.h" |
41 | #include "servers/rendering_server.h" |
42 | |
43 | class ShaderRD { |
44 | public: |
45 | struct VariantDefine { |
46 | int group = 0; |
47 | CharString text; |
48 | bool default_enabled = true; |
49 | VariantDefine(){}; |
50 | VariantDefine(int p_group, const String &p_text, bool p_default_enabled) { |
51 | group = p_group; |
52 | default_enabled = p_default_enabled; |
53 | text = p_text.utf8(); |
54 | } |
55 | }; |
56 | |
57 | private: |
58 | //versions |
59 | CharString general_defines; |
60 | Vector<VariantDefine> variant_defines; |
61 | Vector<bool> variants_enabled; |
62 | HashMap<int, LocalVector<int>> group_to_variant_map; |
63 | Vector<bool> group_enabled; |
64 | |
65 | struct Version { |
66 | CharString uniforms; |
67 | CharString vertex_globals; |
68 | CharString compute_globals; |
69 | CharString fragment_globals; |
70 | HashMap<StringName, CharString> code_sections; |
71 | Vector<CharString> custom_defines; |
72 | |
73 | Vector<uint8_t> *variant_data = nullptr; |
74 | RID *variants = nullptr; // Same size as variant defines. |
75 | |
76 | bool valid; |
77 | bool dirty; |
78 | bool initialize_needed; |
79 | }; |
80 | |
81 | Mutex variant_set_mutex; |
82 | |
83 | struct CompileData { |
84 | Version *version; |
85 | int group = 0; |
86 | }; |
87 | |
88 | void _compile_variant(uint32_t p_variant, const CompileData *p_data); |
89 | |
90 | void _initialize_version(Version *p_version); |
91 | void _clear_version(Version *p_version); |
92 | void _compile_version(Version *p_version, int p_group); |
93 | void _allocate_placeholders(Version *p_version, int p_group); |
94 | |
95 | RID_Owner<Version> version_owner; |
96 | |
97 | struct StageTemplate { |
98 | struct Chunk { |
99 | enum Type { |
100 | TYPE_VERSION_DEFINES, |
101 | TYPE_MATERIAL_UNIFORMS, |
102 | TYPE_VERTEX_GLOBALS, |
103 | TYPE_FRAGMENT_GLOBALS, |
104 | TYPE_COMPUTE_GLOBALS, |
105 | TYPE_CODE, |
106 | TYPE_TEXT |
107 | }; |
108 | |
109 | Type type; |
110 | StringName code; |
111 | CharString text; |
112 | }; |
113 | LocalVector<Chunk> chunks; |
114 | }; |
115 | |
116 | bool is_compute = false; |
117 | |
118 | String name; |
119 | |
120 | CharString base_compute_defines; |
121 | |
122 | String base_sha256; |
123 | LocalVector<String> group_sha256; |
124 | |
125 | static String shader_cache_dir; |
126 | static bool shader_cache_cleanup_on_start; |
127 | static bool shader_cache_save_compressed; |
128 | static bool shader_cache_save_compressed_zstd; |
129 | static bool shader_cache_save_debug; |
130 | bool shader_cache_dir_valid = false; |
131 | |
132 | enum StageType { |
133 | STAGE_TYPE_VERTEX, |
134 | STAGE_TYPE_FRAGMENT, |
135 | STAGE_TYPE_COMPUTE, |
136 | STAGE_TYPE_MAX, |
137 | }; |
138 | |
139 | StageTemplate stage_templates[STAGE_TYPE_MAX]; |
140 | |
141 | void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template); |
142 | |
143 | void _add_stage(const char *p_code, StageType p_stage_type); |
144 | |
145 | String _version_get_sha1(Version *p_version) const; |
146 | bool _load_from_cache(Version *p_version, int p_group); |
147 | void _save_to_cache(Version *p_version, int p_group); |
148 | void _initialize_cache(); |
149 | |
150 | protected: |
151 | ShaderRD(); |
152 | void setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name); |
153 | |
154 | public: |
155 | RID version_create(); |
156 | |
157 | 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); |
158 | void version_set_compute_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines); |
159 | |
160 | _FORCE_INLINE_ RID version_get_shader(RID p_version, int p_variant) { |
161 | ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); |
162 | ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); |
163 | |
164 | Version *version = version_owner.get_or_null(p_version); |
165 | ERR_FAIL_COND_V(!version, RID()); |
166 | |
167 | if (version->dirty) { |
168 | _initialize_version(version); |
169 | for (int i = 0; i < group_enabled.size(); i++) { |
170 | if (!group_enabled[i]) { |
171 | _allocate_placeholders(version, i); |
172 | continue; |
173 | } |
174 | _compile_version(version, i); |
175 | } |
176 | } |
177 | |
178 | if (!version->valid) { |
179 | return RID(); |
180 | } |
181 | |
182 | return version->variants[p_variant]; |
183 | } |
184 | |
185 | bool version_is_valid(RID p_version); |
186 | |
187 | bool version_free(RID p_version); |
188 | |
189 | // Enable/disable variants for things that you know won't be used at engine initialization time . |
190 | void set_variant_enabled(int p_variant, bool p_enabled); |
191 | bool is_variant_enabled(int p_variant) const; |
192 | |
193 | // Enable/disable groups for things that might be enabled at run time. |
194 | void enable_group(int p_group); |
195 | bool is_group_enabled(int p_group) const; |
196 | |
197 | static void set_shader_cache_dir(const String &p_dir); |
198 | static void set_shader_cache_save_compressed(bool p_enable); |
199 | static void set_shader_cache_save_compressed_zstd(bool p_enable); |
200 | static void set_shader_cache_save_debug(bool p_enable); |
201 | |
202 | RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version); |
203 | |
204 | void initialize(const Vector<String> &p_variant_defines, const String &p_general_defines = "" ); |
205 | void initialize(const Vector<VariantDefine> &p_variant_defines, const String &p_general_defines = "" ); |
206 | |
207 | virtual ~ShaderRD(); |
208 | }; |
209 | |
210 | #endif // SHADER_RD_H |
211 | |