1/**************************************************************************/
2/* shader_gles3.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_GLES3_H
32#define SHADER_GLES3_H
33
34#include "core/math/projection.h"
35#include "core/os/mutex.h"
36#include "core/string/string_builder.h"
37#include "core/templates/hash_map.h"
38#include "core/templates/local_vector.h"
39#include "core/templates/rb_map.h"
40#include "core/templates/rid_owner.h"
41#include "core/variant/variant.h"
42#include "servers/rendering_server.h"
43
44#ifdef GLES3_ENABLED
45
46// This must come first to avoid windows.h mess
47#include "platform_config.h"
48#ifndef OPENGL_INCLUDE_H
49#include <GLES3/gl3.h>
50#else
51#include OPENGL_INCLUDE_H
52#endif
53
54#include <stdio.h>
55
56class ShaderGLES3 {
57public:
58 struct TextureUniformData {
59 StringName name;
60 int array_size;
61 };
62
63protected:
64 struct TexUnitPair {
65 const char *name;
66 int index;
67 };
68
69 struct UBOPair {
70 const char *name;
71 int index;
72 };
73
74 struct Specialization {
75 const char *name;
76 bool default_value = false;
77 };
78
79 struct Feedback {
80 const char *name;
81 uint64_t specialization;
82 };
83
84private:
85 //versions
86 CharString general_defines;
87
88 // 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
89 // Variants use #ifdefs to toggle behavior on and off to change behavior of the shader
90 // All variants are compiled each time a new version is created
91 // Specializations use #ifdefs to toggle behavior on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
92 // Use specializations to enable and disabled advanced features, use variants to toggle behavior when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
93 struct Version {
94 LocalVector<TextureUniformData> texture_uniforms;
95 CharString uniforms;
96 CharString vertex_globals;
97 CharString fragment_globals;
98 HashMap<StringName, CharString> code_sections;
99 Vector<CharString> custom_defines;
100
101 struct Specialization {
102 GLuint id;
103 GLuint vert_id;
104 GLuint frag_id;
105 LocalVector<GLint> uniform_location;
106 LocalVector<GLint> texture_uniform_locations;
107 bool build_queued = false;
108 bool ok = false;
109 Specialization() {
110 id = 0;
111 vert_id = 0;
112 frag_id = 0;
113 }
114 };
115
116 LocalVector<OAHashMap<uint64_t, Specialization>> variants;
117 };
118
119 Mutex variant_set_mutex;
120
121 void _get_uniform_locations(Version::Specialization &spec, Version *p_version);
122 void _compile_specialization(Version::Specialization &spec, uint32_t p_variant, Version *p_version, uint64_t p_specialization);
123
124 void _clear_version(Version *p_version);
125 void _initialize_version(Version *p_version);
126
127 RID_Owner<Version, true> version_owner;
128
129 struct StageTemplate {
130 struct Chunk {
131 enum Type {
132 TYPE_MATERIAL_UNIFORMS,
133 TYPE_VERTEX_GLOBALS,
134 TYPE_FRAGMENT_GLOBALS,
135 TYPE_CODE,
136 TYPE_TEXT
137 };
138
139 Type type;
140 StringName code;
141 CharString text;
142 };
143 LocalVector<Chunk> chunks;
144 };
145
146 String name;
147
148 String base_sha256;
149
150 static String shader_cache_dir;
151 static bool shader_cache_cleanup_on_start;
152 static bool shader_cache_save_compressed;
153 static bool shader_cache_save_compressed_zstd;
154 static bool shader_cache_save_debug;
155 bool shader_cache_dir_valid = false;
156
157 int64_t max_image_units = 0;
158
159 enum StageType {
160 STAGE_TYPE_VERTEX,
161 STAGE_TYPE_FRAGMENT,
162 STAGE_TYPE_MAX,
163 };
164
165 StageTemplate stage_templates[STAGE_TYPE_MAX];
166
167 void _build_variant_code(StringBuilder &p_builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization);
168
169 void _add_stage(const char *p_code, StageType p_stage_type);
170
171 String _version_get_sha1(Version *p_version) const;
172 bool _load_from_cache(Version *p_version);
173 void _save_to_cache(Version *p_version);
174
175 const char **uniform_names = nullptr;
176 int uniform_count = 0;
177 const UBOPair *ubo_pairs = nullptr;
178 int ubo_count = 0;
179 const Feedback *feedbacks;
180 int feedback_count = 0;
181 const TexUnitPair *texunit_pairs = nullptr;
182 int texunit_pair_count = 0;
183 int specialization_count = 0;
184 const Specialization *specializations = nullptr;
185 uint64_t specialization_default_mask = 0;
186 const char **variant_defines = nullptr;
187 int variant_count = 0;
188
189 int base_texture_index = 0;
190 Version::Specialization *current_shader = nullptr;
191
192protected:
193 ShaderGLES3();
194 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_feedback_count, const Feedback *p_feedback, 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);
195
196 _FORCE_INLINE_ bool _version_bind_shader(RID p_version, int p_variant, uint64_t p_specialization) {
197 ERR_FAIL_INDEX_V(p_variant, variant_count, false);
198
199 Version *version = version_owner.get_or_null(p_version);
200 ERR_FAIL_NULL_V(version, false);
201
202 if (version->variants.size() == 0) {
203 _initialize_version(version); //may lack initialization
204 }
205
206 Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
207 if (!spec) {
208 if (false) {
209 // Queue load this specialization and use defaults in the meantime (TODO)
210
211 spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
212 } else {
213 // Compile on the spot
214 Version::Specialization s;
215 _compile_specialization(s, p_variant, version, p_specialization);
216 version->variants[p_variant].insert(p_specialization, s);
217 spec = version->variants[p_variant].lookup_ptr(p_specialization);
218 _save_to_cache(version);
219 }
220 } else if (spec->build_queued) {
221 // Still queued, wait
222 spec = version->variants[p_variant].lookup_ptr(specialization_default_mask);
223 }
224
225 if (!spec || !spec->ok) {
226 WARN_PRINT_ONCE("shader failed to compile, unable to bind shader.");
227 return false;
228 }
229
230 glUseProgram(spec->id);
231 current_shader = spec;
232 return true;
233 }
234
235 _FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) {
236 ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
237 Version *version = version_owner.get_or_null(p_version);
238 ERR_FAIL_NULL_V(version, -1);
239 ERR_FAIL_INDEX_V(p_variant, int(version->variants.size()), -1);
240 Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
241 ERR_FAIL_NULL_V(spec, -1);
242 ERR_FAIL_INDEX_V(p_which, int(spec->uniform_location.size()), -1);
243 return spec->uniform_location[p_which];
244 }
245
246 virtual void _init() = 0;
247
248public:
249 RID version_create();
250
251 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 LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize = false);
252
253 bool version_is_valid(RID p_version);
254
255 bool version_free(RID p_version);
256
257 static void set_shader_cache_dir(const String &p_dir);
258 static void set_shader_cache_save_compressed(bool p_enable);
259 static void set_shader_cache_save_compressed_zstd(bool p_enable);
260 static void set_shader_cache_save_debug(bool p_enable);
261
262 RS::ShaderNativeSourceCode version_get_native_source_code(RID p_version);
263
264 void initialize(const String &p_general_defines = "", int p_base_texture_index = 0);
265 virtual ~ShaderGLES3();
266};
267
268#endif // GLES3_ENABLED
269
270#endif // SHADER_GLES3_H
271