Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/servers/rendering/renderer_rd/shader_rd.cpp
10279 views
1
/**************************************************************************/
2
/* shader_rd.cpp */
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
#include "shader_rd.h"
32
33
#include "core/io/dir_access.h"
34
#include "core/io/file_access.h"
35
#include "core/object/worker_thread_pool.h"
36
#include "core/version.h"
37
#include "servers/rendering/rendering_device.h"
38
#include "servers/rendering/shader_include_db.h"
39
40
#define ENABLE_SHADER_CACHE 1
41
42
void ShaderRD::_add_stage(const char *p_code, StageType p_stage_type) {
43
Vector<String> lines = String(p_code).split("\n");
44
45
String text;
46
47
int line_count = lines.size();
48
for (int i = 0; i < line_count; i++) {
49
const String &l = lines[i];
50
bool push_chunk = false;
51
52
StageTemplate::Chunk chunk;
53
54
if (l.begins_with("#VERSION_DEFINES")) {
55
chunk.type = StageTemplate::Chunk::TYPE_VERSION_DEFINES;
56
push_chunk = true;
57
} else if (l.begins_with("#GLOBALS")) {
58
switch (p_stage_type) {
59
case STAGE_TYPE_VERTEX:
60
chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
61
break;
62
case STAGE_TYPE_FRAGMENT:
63
chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS;
64
break;
65
case STAGE_TYPE_COMPUTE:
66
chunk.type = StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS;
67
break;
68
default: {
69
}
70
}
71
72
push_chunk = true;
73
} else if (l.begins_with("#MATERIAL_UNIFORMS")) {
74
chunk.type = StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS;
75
push_chunk = true;
76
} else if (l.begins_with("#CODE")) {
77
chunk.type = StageTemplate::Chunk::TYPE_CODE;
78
push_chunk = true;
79
chunk.code = l.replace_first("#CODE", String()).remove_char(':').strip_edges().to_upper();
80
} else if (l.begins_with("#include ")) {
81
String include_file = l.replace("#include ", "").strip_edges();
82
if (include_file[0] == '"') {
83
int end_pos = include_file.find_char('"', 1);
84
if (end_pos >= 0) {
85
include_file = include_file.substr(1, end_pos - 1);
86
87
String include_code = ShaderIncludeDB::get_built_in_include_file(include_file);
88
if (!include_code.is_empty()) {
89
// Add these lines into our parse list so we parse them as well.
90
Vector<String> include_lines = include_code.split("\n");
91
92
for (int j = include_lines.size() - 1; j >= 0; j--) {
93
lines.insert(i + 1, include_lines[j]);
94
}
95
96
line_count = lines.size();
97
} else {
98
// Add it in as is.
99
text += l + "\n";
100
}
101
} else {
102
// Add it in as is.
103
text += l + "\n";
104
}
105
} else {
106
// Add it in as is.
107
text += l + "\n";
108
}
109
} else {
110
text += l + "\n";
111
}
112
113
if (push_chunk) {
114
if (!text.is_empty()) {
115
StageTemplate::Chunk text_chunk;
116
text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
117
text_chunk.text = text.utf8();
118
stage_templates[p_stage_type].chunks.push_back(text_chunk);
119
text = String();
120
}
121
stage_templates[p_stage_type].chunks.push_back(chunk);
122
}
123
}
124
125
if (!text.is_empty()) {
126
StageTemplate::Chunk text_chunk;
127
text_chunk.type = StageTemplate::Chunk::TYPE_TEXT;
128
text_chunk.text = text.utf8();
129
stage_templates[p_stage_type].chunks.push_back(text_chunk);
130
text = String();
131
}
132
}
133
134
void ShaderRD::setup(const char *p_vertex_code, const char *p_fragment_code, const char *p_compute_code, const char *p_name) {
135
name = p_name;
136
137
if (p_compute_code) {
138
_add_stage(p_compute_code, STAGE_TYPE_COMPUTE);
139
is_compute = true;
140
} else {
141
is_compute = false;
142
if (p_vertex_code) {
143
_add_stage(p_vertex_code, STAGE_TYPE_VERTEX);
144
}
145
if (p_fragment_code) {
146
_add_stage(p_fragment_code, STAGE_TYPE_FRAGMENT);
147
}
148
}
149
150
StringBuilder tohash;
151
tohash.append("[GodotVersionNumber]");
152
tohash.append(GODOT_VERSION_NUMBER);
153
tohash.append("[GodotVersionHash]");
154
tohash.append(GODOT_VERSION_HASH);
155
tohash.append("[Vertex]");
156
tohash.append(p_vertex_code ? p_vertex_code : "");
157
tohash.append("[Fragment]");
158
tohash.append(p_fragment_code ? p_fragment_code : "");
159
tohash.append("[Compute]");
160
tohash.append(p_compute_code ? p_compute_code : "");
161
tohash.append("[DebugInfo]");
162
tohash.append(Engine::get_singleton()->is_generate_spirv_debug_info_enabled() ? "1" : "0");
163
164
base_sha256 = tohash.as_string().sha256_text();
165
}
166
167
RID ShaderRD::version_create(bool p_embedded) {
168
//initialize() was never called
169
ERR_FAIL_COND_V(group_to_variant_map.is_empty(), RID());
170
171
Version version;
172
version.dirty = true;
173
version.valid = false;
174
version.initialize_needed = true;
175
version.embedded = p_embedded;
176
version.variants.clear();
177
version.variant_data.clear();
178
179
version.mutex = memnew(Mutex);
180
RID rid = version_owner.make_rid(version);
181
{
182
MutexLock lock(versions_mutex);
183
version_mutexes.insert(rid, version.mutex);
184
}
185
186
if (p_embedded) {
187
MutexLock lock(shader_versions_embedded_set_mutex);
188
shader_versions_embedded_set.insert({ this, rid });
189
}
190
191
return rid;
192
}
193
194
void ShaderRD::_initialize_version(Version *p_version) {
195
_clear_version(p_version);
196
197
p_version->valid = false;
198
p_version->dirty = false;
199
200
p_version->variants.resize_initialized(variant_defines.size());
201
p_version->variant_data.resize(variant_defines.size());
202
p_version->group_compilation_tasks.resize_initialized(group_enabled.size());
203
}
204
205
void ShaderRD::_clear_version(Version *p_version) {
206
_compile_ensure_finished(p_version);
207
208
// Clear versions if they exist.
209
if (!p_version->variants.is_empty()) {
210
for (int i = 0; i < variant_defines.size(); i++) {
211
if (p_version->variants[i].is_valid()) {
212
RD::get_singleton()->free(p_version->variants[i]);
213
}
214
}
215
216
p_version->variants.clear();
217
p_version->variant_data.clear();
218
}
219
}
220
221
void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, const StageTemplate &p_template) {
222
for (const StageTemplate::Chunk &chunk : p_template.chunks) {
223
switch (chunk.type) {
224
case StageTemplate::Chunk::TYPE_VERSION_DEFINES: {
225
builder.append("\n"); //make sure defines begin at newline
226
builder.append(general_defines.get_data());
227
builder.append(variant_defines[p_variant].text.get_data());
228
for (int j = 0; j < p_version->custom_defines.size(); j++) {
229
builder.append(p_version->custom_defines[j].get_data());
230
}
231
builder.append("\n"); //make sure defines begin at newline
232
if (p_version->uniforms.size()) {
233
builder.append("#define MATERIAL_UNIFORMS_USED\n");
234
}
235
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
236
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
237
}
238
builder.append(String("#define RENDER_DRIVER_") + OS::get_singleton()->get_current_rendering_driver_name().to_upper() + "\n");
239
builder.append("#define samplerExternalOES sampler2D\n");
240
builder.append("#define textureExternalOES texture2D\n");
241
} break;
242
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
243
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
244
} break;
245
case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
246
builder.append(p_version->vertex_globals.get_data()); // vertex globals
247
} break;
248
case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
249
builder.append(p_version->fragment_globals.get_data()); // fragment globals
250
} break;
251
case StageTemplate::Chunk::TYPE_COMPUTE_GLOBALS: {
252
builder.append(p_version->compute_globals.get_data()); // compute globals
253
} break;
254
case StageTemplate::Chunk::TYPE_CODE: {
255
if (p_version->code_sections.has(chunk.code)) {
256
builder.append(p_version->code_sections[chunk.code].get_data());
257
}
258
} break;
259
case StageTemplate::Chunk::TYPE_TEXT: {
260
builder.append(chunk.text.get_data());
261
} break;
262
}
263
}
264
}
265
266
Vector<String> ShaderRD::_build_variant_stage_sources(uint32_t p_variant, CompileData p_data) {
267
if (!variants_enabled[p_variant]) {
268
return Vector<String>(); // Variant is disabled, return.
269
}
270
271
Vector<String> stage_sources;
272
stage_sources.resize(RD::SHADER_STAGE_MAX);
273
274
if (is_compute) {
275
// Compute stage.
276
StringBuilder builder;
277
_build_variant_code(builder, p_variant, p_data.version, stage_templates[STAGE_TYPE_COMPUTE]);
278
stage_sources.write[RD::SHADER_STAGE_COMPUTE] = builder.as_string();
279
} else {
280
{
281
// Vertex stage.
282
StringBuilder builder;
283
_build_variant_code(builder, p_variant, p_data.version, stage_templates[STAGE_TYPE_VERTEX]);
284
stage_sources.write[RD::SHADER_STAGE_VERTEX] = builder.as_string();
285
}
286
287
{
288
// Fragment stage.
289
StringBuilder builder;
290
_build_variant_code(builder, p_variant, p_data.version, stage_templates[STAGE_TYPE_FRAGMENT]);
291
stage_sources.write[RD::SHADER_STAGE_FRAGMENT] = builder.as_string();
292
}
293
}
294
295
return stage_sources;
296
}
297
298
void ShaderRD::_compile_variant(uint32_t p_variant, CompileData p_data) {
299
uint32_t variant = group_to_variant_map[p_data.group][p_variant];
300
if (!variants_enabled[variant]) {
301
return; // Variant is disabled, return.
302
}
303
304
Vector<String> variant_stage_sources = _build_variant_stage_sources(variant, p_data);
305
Vector<RD::ShaderStageSPIRVData> variant_stages = compile_stages(variant_stage_sources);
306
ERR_FAIL_COND(variant_stages.is_empty());
307
308
Vector<uint8_t> shader_data = RD::get_singleton()->shader_compile_binary_from_spirv(variant_stages, name + ":" + itos(variant));
309
ERR_FAIL_COND(shader_data.is_empty());
310
311
{
312
p_data.version->variants.write[variant] = RD::get_singleton()->shader_create_from_bytecode_with_samplers(shader_data, p_data.version->variants[variant], immutable_samplers);
313
p_data.version->variant_data.write[variant] = shader_data;
314
}
315
}
316
317
Vector<String> ShaderRD::version_build_variant_stage_sources(RID p_version, int p_variant) {
318
Version *version = version_owner.get_or_null(p_version);
319
ERR_FAIL_NULL_V(version, Vector<String>());
320
321
if (version->dirty) {
322
_initialize_version(version);
323
}
324
325
CompileData compile_data;
326
compile_data.version = version;
327
compile_data.group = variant_to_group[p_variant];
328
return _build_variant_stage_sources(p_variant, compile_data);
329
}
330
331
RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) {
332
Version *version = version_owner.get_or_null(p_version);
333
RS::ShaderNativeSourceCode source_code;
334
ERR_FAIL_NULL_V(version, source_code);
335
336
MutexLock lock(*version->mutex);
337
338
source_code.versions.resize(variant_defines.size());
339
340
for (int i = 0; i < source_code.versions.size(); i++) {
341
if (!is_compute) {
342
//vertex stage
343
344
StringBuilder builder;
345
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_VERTEX]);
346
347
RS::ShaderNativeSourceCode::Version::Stage stage;
348
stage.name = "vertex";
349
stage.code = builder.as_string();
350
351
source_code.versions.write[i].stages.push_back(stage);
352
}
353
354
if (!is_compute) {
355
//fragment stage
356
357
StringBuilder builder;
358
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_FRAGMENT]);
359
360
RS::ShaderNativeSourceCode::Version::Stage stage;
361
stage.name = "fragment";
362
stage.code = builder.as_string();
363
364
source_code.versions.write[i].stages.push_back(stage);
365
}
366
367
if (is_compute) {
368
//compute stage
369
370
StringBuilder builder;
371
_build_variant_code(builder, i, version, stage_templates[STAGE_TYPE_COMPUTE]);
372
373
RS::ShaderNativeSourceCode::Version::Stage stage;
374
stage.name = "compute";
375
stage.code = builder.as_string();
376
377
source_code.versions.write[i].stages.push_back(stage);
378
}
379
}
380
381
return source_code;
382
}
383
384
String ShaderRD::version_get_cache_file_relative_path(RID p_version, int p_group, const String &p_api_name) {
385
Version *version = version_owner.get_or_null(p_version);
386
ERR_FAIL_NULL_V(version, String());
387
388
return _get_cache_file_relative_path(version, p_group, p_api_name);
389
}
390
391
String ShaderRD::_version_get_sha1(Version *p_version) const {
392
StringBuilder hash_build;
393
394
hash_build.append("[uniforms]");
395
hash_build.append(p_version->uniforms.get_data());
396
hash_build.append("[vertex_globals]");
397
hash_build.append(p_version->vertex_globals.get_data());
398
hash_build.append("[fragment_globals]");
399
hash_build.append(p_version->fragment_globals.get_data());
400
hash_build.append("[compute_globals]");
401
hash_build.append(p_version->compute_globals.get_data());
402
403
Vector<StringName> code_sections;
404
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
405
code_sections.push_back(E.key);
406
}
407
code_sections.sort_custom<StringName::AlphCompare>();
408
409
for (int i = 0; i < code_sections.size(); i++) {
410
hash_build.append(String("[code:") + String(code_sections[i]) + "]");
411
hash_build.append(p_version->code_sections[code_sections[i]].get_data());
412
}
413
for (int i = 0; i < p_version->custom_defines.size(); i++) {
414
hash_build.append("[custom_defines:" + itos(i) + "]");
415
hash_build.append(p_version->custom_defines[i].get_data());
416
}
417
418
return hash_build.as_string().sha1_text();
419
}
420
421
static const char *shader_file_header = "GDSC";
422
static const uint32_t cache_file_version = 4;
423
424
String ShaderRD::_get_cache_file_relative_path(Version *p_version, int p_group, const String &p_api_name) {
425
String sha1 = _version_get_sha1(p_version);
426
return name.path_join(group_sha256[p_group]).path_join(sha1) + "." + p_api_name + ".cache";
427
}
428
429
String ShaderRD::_get_cache_file_path(Version *p_version, int p_group, const String &p_api_name, bool p_user_dir) {
430
const String &shader_cache_dir = p_user_dir ? shader_cache_user_dir : shader_cache_res_dir;
431
String relative_path = _get_cache_file_relative_path(p_version, p_group, p_api_name);
432
return shader_cache_dir.path_join(relative_path);
433
}
434
435
bool ShaderRD::_load_from_cache(Version *p_version, int p_group) {
436
String api_safe_name = String(RD::get_singleton()->get_device_api_name()).validate_filename().to_lower();
437
Ref<FileAccess> f;
438
if (shader_cache_user_dir_valid) {
439
f = FileAccess::open(_get_cache_file_path(p_version, p_group, api_safe_name, true), FileAccess::READ);
440
}
441
442
if (f.is_null() && shader_cache_res_dir_valid) {
443
f = FileAccess::open(_get_cache_file_path(p_version, p_group, api_safe_name, false), FileAccess::READ);
444
}
445
446
if (f.is_null()) {
447
const String &sha1 = _version_get_sha1(p_version);
448
print_verbose(vformat("Shader cache miss for %s", name.path_join(group_sha256[p_group]).path_join(sha1)));
449
return false;
450
}
451
452
char header[5] = { 0, 0, 0, 0, 0 };
453
f->get_buffer((uint8_t *)header, 4);
454
ERR_FAIL_COND_V(header != String(shader_file_header), false);
455
456
uint32_t file_version = f->get_32();
457
if (file_version != cache_file_version) {
458
return false; // wrong version
459
}
460
461
uint32_t variant_count = f->get_32();
462
463
ERR_FAIL_COND_V(variant_count != (uint32_t)group_to_variant_map[p_group].size(), false); //should not happen but check
464
465
for (uint32_t i = 0; i < variant_count; i++) {
466
int variant_id = group_to_variant_map[p_group][i];
467
uint32_t variant_size = f->get_32();
468
if (!variants_enabled[variant_id]) {
469
continue;
470
}
471
if (variant_size == 0) {
472
// A new variant has been requested, failing the entire load will generate it
473
print_verbose(vformat("Shader cache miss for %s due to missing variant %d", name.path_join(group_sha256[p_group]).path_join(_version_get_sha1(p_version)), variant_id));
474
return false;
475
}
476
Vector<uint8_t> variant_bytes;
477
variant_bytes.resize(variant_size);
478
479
uint32_t br = f->get_buffer(variant_bytes.ptrw(), variant_size);
480
481
ERR_FAIL_COND_V(br != variant_size, false);
482
483
p_version->variant_data.write[variant_id] = variant_bytes;
484
}
485
486
for (uint32_t i = 0; i < variant_count; i++) {
487
int variant_id = group_to_variant_map[p_group][i];
488
if (!variants_enabled[variant_id]) {
489
p_version->variants.write[variant_id] = RID();
490
continue;
491
}
492
print_verbose(vformat("Loading cache for shader %s, variant %d", name, i));
493
{
494
RID shader = RD::get_singleton()->shader_create_from_bytecode_with_samplers(p_version->variant_data[variant_id], p_version->variants[variant_id], immutable_samplers);
495
if (shader.is_null()) {
496
for (uint32_t j = 0; j < i; j++) {
497
int variant_free_id = group_to_variant_map[p_group][j];
498
RD::get_singleton()->free(p_version->variants[variant_free_id]);
499
}
500
ERR_FAIL_COND_V(shader.is_null(), false);
501
}
502
503
p_version->variants.write[variant_id] = shader;
504
}
505
}
506
507
p_version->valid = true;
508
return true;
509
}
510
511
void ShaderRD::_save_to_cache(Version *p_version, int p_group) {
512
ERR_FAIL_COND(!shader_cache_user_dir_valid);
513
String api_safe_name = String(RD::get_singleton()->get_device_api_name()).validate_filename().to_lower();
514
const String &path = _get_cache_file_path(p_version, p_group, api_safe_name, true);
515
Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
516
ERR_FAIL_COND(f.is_null());
517
518
PackedByteArray shader_cache_bytes = ShaderRD::save_shader_cache_bytes(group_to_variant_map[p_group], p_version->variant_data);
519
f->store_buffer(shader_cache_bytes);
520
}
521
522
void ShaderRD::_allocate_placeholders(Version *p_version, int p_group) {
523
ERR_FAIL_COND(p_version->variants.is_empty());
524
525
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
526
int variant_id = group_to_variant_map[p_group][i];
527
RID shader = RD::get_singleton()->shader_create_placeholder();
528
{
529
p_version->variants.write[variant_id] = shader;
530
}
531
}
532
}
533
534
// Try to compile all variants for a given group.
535
// Will skip variants that are disabled.
536
void ShaderRD::_compile_version_start(Version *p_version, int p_group) {
537
if (!group_enabled[p_group]) {
538
return;
539
}
540
541
p_version->dirty = false;
542
543
#if ENABLE_SHADER_CACHE
544
if (shader_cache_user_dir_valid || shader_cache_res_dir_valid) {
545
if (_load_from_cache(p_version, p_group)) {
546
return;
547
}
548
}
549
#endif
550
551
CompileData compile_data;
552
compile_data.version = p_version;
553
compile_data.group = p_group;
554
555
WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &ShaderRD::_compile_variant, compile_data, group_to_variant_map[p_group].size(), -1, true, SNAME("ShaderCompilation"));
556
p_version->group_compilation_tasks.write[p_group] = group_task;
557
}
558
559
void ShaderRD::_compile_version_end(Version *p_version, int p_group) {
560
if (p_version->group_compilation_tasks.size() <= p_group || p_version->group_compilation_tasks[p_group] == 0) {
561
return;
562
}
563
WorkerThreadPool::GroupID group_task = p_version->group_compilation_tasks[p_group];
564
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
565
p_version->group_compilation_tasks.write[p_group] = 0;
566
567
bool all_valid = true;
568
569
for (uint32_t i = 0; i < group_to_variant_map[p_group].size(); i++) {
570
int variant_id = group_to_variant_map[p_group][i];
571
if (!variants_enabled[variant_id]) {
572
continue; // Disabled.
573
}
574
if (p_version->variants[variant_id].is_null()) {
575
all_valid = false;
576
break;
577
}
578
}
579
580
if (!all_valid) {
581
// Clear versions if they exist.
582
for (int i = 0; i < variant_defines.size(); i++) {
583
if (!variants_enabled[i] || !group_enabled[variant_defines[i].group]) {
584
continue; // Disabled.
585
}
586
if (!p_version->variants[i].is_null()) {
587
RD::get_singleton()->free(p_version->variants[i]);
588
}
589
}
590
591
p_version->variants.clear();
592
p_version->variant_data.clear();
593
return;
594
}
595
#if ENABLE_SHADER_CACHE
596
else if (shader_cache_user_dir_valid) {
597
_save_to_cache(p_version, p_group);
598
}
599
#endif
600
601
p_version->valid = true;
602
}
603
604
void ShaderRD::_compile_ensure_finished(Version *p_version) {
605
// Wait for compilation of existing groups if necessary.
606
for (int i = 0; i < group_enabled.size(); i++) {
607
_compile_version_end(p_version, i);
608
}
609
}
610
611
void ShaderRD::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) {
612
ERR_FAIL_COND(is_compute);
613
614
Version *version = version_owner.get_or_null(p_version);
615
ERR_FAIL_NULL(version);
616
617
MutexLock lock(*version->mutex);
618
619
_compile_ensure_finished(version);
620
621
version->vertex_globals = p_vertex_globals.utf8();
622
version->fragment_globals = p_fragment_globals.utf8();
623
version->uniforms = p_uniforms.utf8();
624
version->code_sections.clear();
625
for (const KeyValue<String, String> &E : p_code) {
626
version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
627
}
628
629
version->custom_defines.clear();
630
for (int i = 0; i < p_custom_defines.size(); i++) {
631
version->custom_defines.push_back(p_custom_defines[i].utf8());
632
}
633
634
version->dirty = true;
635
if (version->initialize_needed) {
636
_initialize_version(version);
637
for (int i = 0; i < group_enabled.size(); i++) {
638
if (!group_enabled[i]) {
639
_allocate_placeholders(version, i);
640
continue;
641
}
642
_compile_version_start(version, i);
643
}
644
version->initialize_needed = false;
645
}
646
}
647
648
void ShaderRD::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) {
649
ERR_FAIL_COND(!is_compute);
650
651
Version *version = version_owner.get_or_null(p_version);
652
ERR_FAIL_NULL(version);
653
654
MutexLock lock(*version->mutex);
655
656
_compile_ensure_finished(version);
657
658
version->compute_globals = p_compute_globals.utf8();
659
version->uniforms = p_uniforms.utf8();
660
661
version->code_sections.clear();
662
for (const KeyValue<String, String> &E : p_code) {
663
version->code_sections[StringName(E.key.to_upper())] = E.value.utf8();
664
}
665
666
version->custom_defines.clear();
667
for (int i = 0; i < p_custom_defines.size(); i++) {
668
version->custom_defines.push_back(p_custom_defines[i].utf8());
669
}
670
671
version->dirty = true;
672
if (version->initialize_needed) {
673
_initialize_version(version);
674
for (int i = 0; i < group_enabled.size(); i++) {
675
if (!group_enabled[i]) {
676
_allocate_placeholders(version, i);
677
continue;
678
}
679
_compile_version_start(version, i);
680
}
681
version->initialize_needed = false;
682
}
683
}
684
685
bool ShaderRD::version_is_valid(RID p_version) {
686
Version *version = version_owner.get_or_null(p_version);
687
ERR_FAIL_NULL_V(version, false);
688
689
MutexLock lock(*version->mutex);
690
691
if (version->dirty) {
692
_initialize_version(version);
693
for (int i = 0; i < group_enabled.size(); i++) {
694
if (!group_enabled[i]) {
695
_allocate_placeholders(version, i);
696
continue;
697
}
698
_compile_version_start(version, i);
699
}
700
}
701
702
_compile_ensure_finished(version);
703
704
return version->valid;
705
}
706
707
bool ShaderRD::version_free(RID p_version) {
708
if (version_owner.owns(p_version)) {
709
{
710
MutexLock lock(versions_mutex);
711
version_mutexes.erase(p_version);
712
}
713
714
Version *version = version_owner.get_or_null(p_version);
715
if (version->embedded) {
716
MutexLock lock(shader_versions_embedded_set_mutex);
717
shader_versions_embedded_set.erase({ this, p_version });
718
}
719
720
version->mutex->lock();
721
_clear_version(version);
722
version_owner.free(p_version);
723
version->mutex->unlock();
724
memdelete(version->mutex);
725
} else {
726
return false;
727
}
728
729
return true;
730
}
731
732
void ShaderRD::set_variant_enabled(int p_variant, bool p_enabled) {
733
ERR_FAIL_COND(version_owner.get_rid_count() > 0); //versions exist
734
ERR_FAIL_INDEX(p_variant, variants_enabled.size());
735
variants_enabled.write[p_variant] = p_enabled;
736
}
737
738
bool ShaderRD::is_variant_enabled(int p_variant) const {
739
ERR_FAIL_INDEX_V(p_variant, variants_enabled.size(), false);
740
return variants_enabled[p_variant];
741
}
742
743
int64_t ShaderRD::get_variant_count() const {
744
return variants_enabled.size();
745
}
746
747
int ShaderRD::get_variant_to_group(int p_variant) const {
748
return variant_to_group[p_variant];
749
}
750
751
void ShaderRD::enable_group(int p_group) {
752
ERR_FAIL_INDEX(p_group, group_enabled.size());
753
754
if (group_enabled[p_group]) {
755
// Group already enabled, do nothing.
756
return;
757
}
758
759
group_enabled.write[p_group] = true;
760
761
// Compile all versions again to include the new group.
762
for (const RID &version_rid : version_owner.get_owned_list()) {
763
Version *version = version_owner.get_or_null(version_rid);
764
version->mutex->lock();
765
_compile_version_start(version, p_group);
766
version->mutex->unlock();
767
}
768
}
769
770
bool ShaderRD::is_group_enabled(int p_group) const {
771
return group_enabled[p_group];
772
}
773
774
int64_t ShaderRD::get_group_count() const {
775
return group_enabled.size();
776
}
777
778
const LocalVector<int> &ShaderRD::get_group_to_variants(int p_group) const {
779
return group_to_variant_map[p_group];
780
}
781
782
const String &ShaderRD::get_name() const {
783
return name;
784
}
785
786
bool ShaderRD::shader_cache_cleanup_on_start = false;
787
788
ShaderRD::ShaderRD() {
789
// Do not feel forced to use this, in most cases it makes little to no difference.
790
bool use_32_threads = false;
791
if (RD::get_singleton()->get_device_vendor_name() == "NVIDIA") {
792
use_32_threads = true;
793
}
794
String base_compute_define_text;
795
if (use_32_threads) {
796
base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 32\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 4\n";
797
} else {
798
base_compute_define_text = "\n#define NATIVE_LOCAL_GROUP_SIZE 64\n#define NATIVE_LOCAL_SIZE_2D_X 8\n#define NATIVE_LOCAL_SIZE_2D_Y 8\n";
799
}
800
801
base_compute_defines = base_compute_define_text.ascii();
802
}
803
804
void ShaderRD::initialize(const Vector<String> &p_variant_defines, const String &p_general_defines, const Vector<RD::PipelineImmutableSampler> &p_immutable_samplers) {
805
ERR_FAIL_COND(variant_defines.size());
806
ERR_FAIL_COND(p_variant_defines.is_empty());
807
808
general_defines = p_general_defines.utf8();
809
immutable_samplers = p_immutable_samplers;
810
811
// When initialized this way, there is just one group and its always enabled.
812
group_to_variant_map.insert(0, LocalVector<int>{});
813
group_enabled.push_back(true);
814
815
for (int i = 0; i < p_variant_defines.size(); i++) {
816
variant_defines.push_back(VariantDefine(0, p_variant_defines[i], true));
817
variants_enabled.push_back(true);
818
variant_to_group.push_back(0);
819
group_to_variant_map[0].push_back(i);
820
}
821
822
if (!shader_cache_user_dir.is_empty() || !shader_cache_res_dir.is_empty()) {
823
group_sha256.resize(1);
824
_initialize_cache();
825
}
826
}
827
828
void ShaderRD::_initialize_cache() {
829
shader_cache_user_dir_valid = !shader_cache_user_dir.is_empty();
830
shader_cache_res_dir_valid = !shader_cache_res_dir.is_empty();
831
if (!shader_cache_user_dir_valid) {
832
return;
833
}
834
835
for (const KeyValue<int, LocalVector<int>> &E : group_to_variant_map) {
836
StringBuilder hash_build;
837
838
hash_build.append("[base_hash]");
839
hash_build.append(base_sha256);
840
hash_build.append("[general_defines]");
841
hash_build.append(general_defines.get_data());
842
hash_build.append("[group_id]");
843
hash_build.append(itos(E.key));
844
for (uint32_t i = 0; i < E.value.size(); i++) {
845
hash_build.append("[variant_defines:" + itos(E.value[i]) + "]");
846
hash_build.append(variant_defines[E.value[i]].text.get_data());
847
}
848
849
group_sha256[E.key] = hash_build.as_string().sha256_text();
850
851
if (!shader_cache_user_dir.is_empty()) {
852
// Validate if it's possible to write to all the directories required by in the user directory.
853
Ref<DirAccess> d = DirAccess::open(shader_cache_user_dir);
854
if (d.is_null()) {
855
shader_cache_user_dir_valid = false;
856
ERR_FAIL_MSG(vformat("Unable to open shader cache directory at %s.", shader_cache_user_dir));
857
}
858
859
if (d->change_dir(name) != OK) {
860
Error err = d->make_dir(name);
861
if (err != OK) {
862
shader_cache_user_dir_valid = false;
863
ERR_FAIL_MSG(vformat("Unable to create shader cache directory %s at %s.", name, shader_cache_user_dir));
864
}
865
866
d->change_dir(name);
867
}
868
869
if (d->change_dir(group_sha256[E.key]) != OK) {
870
Error err = d->make_dir(group_sha256[E.key]);
871
if (err != OK) {
872
shader_cache_user_dir_valid = false;
873
ERR_FAIL_MSG(vformat("Unable to create shader cache directory %s/%s at %s.", name, group_sha256[E.key], shader_cache_user_dir));
874
}
875
}
876
}
877
878
print_verbose("Shader '" + name + "' (group " + itos(E.key) + ") SHA256: " + group_sha256[E.key]);
879
}
880
}
881
882
// Same as above, but allows specifying shader compilation groups.
883
void ShaderRD::initialize(const Vector<VariantDefine> &p_variant_defines, const String &p_general_defines, const Vector<RD::PipelineImmutableSampler> &p_immutable_samplers) {
884
ERR_FAIL_COND(variant_defines.size());
885
ERR_FAIL_COND(p_variant_defines.is_empty());
886
887
general_defines = p_general_defines.utf8();
888
immutable_samplers = p_immutable_samplers;
889
890
int max_group_id = 0;
891
892
for (int i = 0; i < p_variant_defines.size(); i++) {
893
// Fill variant array.
894
variant_defines.push_back(p_variant_defines[i]);
895
variants_enabled.push_back(true);
896
variant_to_group.push_back(p_variant_defines[i].group);
897
898
// Map variant array index to group id, so we can iterate over groups later.
899
if (!group_to_variant_map.has(p_variant_defines[i].group)) {
900
group_to_variant_map.insert(p_variant_defines[i].group, LocalVector<int>{});
901
}
902
group_to_variant_map[p_variant_defines[i].group].push_back(i);
903
904
// Track max size.
905
if (p_variant_defines[i].group > max_group_id) {
906
max_group_id = p_variant_defines[i].group;
907
}
908
}
909
910
// Set all to groups to false, then enable those that should be default.
911
group_enabled.resize_initialized(max_group_id + 1);
912
bool *enabled_ptr = group_enabled.ptrw();
913
for (int i = 0; i < p_variant_defines.size(); i++) {
914
if (p_variant_defines[i].default_enabled) {
915
enabled_ptr[p_variant_defines[i].group] = true;
916
}
917
}
918
919
if (!shader_cache_user_dir.is_empty()) {
920
group_sha256.resize(max_group_id + 1);
921
_initialize_cache();
922
}
923
}
924
925
void ShaderRD::shaders_embedded_set_lock() {
926
shader_versions_embedded_set_mutex.lock();
927
}
928
929
const ShaderRD::ShaderVersionPairSet &ShaderRD::shaders_embedded_set_get() {
930
return shader_versions_embedded_set;
931
}
932
933
void ShaderRD::shaders_embedded_set_unlock() {
934
shader_versions_embedded_set_mutex.unlock();
935
}
936
937
void ShaderRD::set_shader_cache_user_dir(const String &p_dir) {
938
shader_cache_user_dir = p_dir;
939
}
940
941
const String &ShaderRD::get_shader_cache_user_dir() {
942
return shader_cache_user_dir;
943
}
944
945
void ShaderRD::set_shader_cache_res_dir(const String &p_dir) {
946
shader_cache_res_dir = p_dir;
947
}
948
949
const String &ShaderRD::get_shader_cache_res_dir() {
950
return shader_cache_res_dir;
951
}
952
953
void ShaderRD::set_shader_cache_save_compressed(bool p_enable) {
954
shader_cache_save_compressed = p_enable;
955
}
956
957
void ShaderRD::set_shader_cache_save_compressed_zstd(bool p_enable) {
958
shader_cache_save_compressed_zstd = p_enable;
959
}
960
961
void ShaderRD::set_shader_cache_save_debug(bool p_enable) {
962
shader_cache_save_debug = p_enable;
963
}
964
965
Vector<RD::ShaderStageSPIRVData> ShaderRD::compile_stages(const Vector<String> &p_stage_sources) {
966
RD::ShaderStageSPIRVData stage;
967
Vector<RD::ShaderStageSPIRVData> stages;
968
String error;
969
RD::ShaderStage compilation_failed_stage = RD::SHADER_STAGE_MAX;
970
bool compilation_failed = false;
971
for (int64_t i = 0; i < p_stage_sources.size() && !compilation_failed; i++) {
972
if (p_stage_sources[i].is_empty()) {
973
continue;
974
}
975
976
stage.spirv = RD::get_singleton()->shader_compile_spirv_from_source(RD::ShaderStage(i), p_stage_sources[i], RD::SHADER_LANGUAGE_GLSL, &error);
977
stage.shader_stage = RD::ShaderStage(i);
978
if (!stage.spirv.is_empty()) {
979
stages.push_back(stage);
980
981
} else {
982
compilation_failed_stage = RD::ShaderStage(i);
983
compilation_failed = true;
984
}
985
}
986
987
if (compilation_failed) {
988
ERR_PRINT("Error compiling " + String(compilation_failed_stage == RD::SHADER_STAGE_COMPUTE ? "Compute " : (compilation_failed_stage == RD::SHADER_STAGE_VERTEX ? "Vertex" : "Fragment")) + " shader.");
989
ERR_PRINT(error);
990
991
#ifdef DEBUG_ENABLED
992
ERR_PRINT("code:\n" + p_stage_sources[compilation_failed_stage].get_with_code_lines());
993
#endif
994
995
return Vector<RD::ShaderStageSPIRVData>();
996
} else {
997
return stages;
998
}
999
}
1000
1001
PackedByteArray ShaderRD::save_shader_cache_bytes(const LocalVector<int> &p_variants, const Vector<Vector<uint8_t>> &p_variant_data) {
1002
uint32_t variant_count = p_variants.size();
1003
PackedByteArray bytes;
1004
int64_t total_size = 0;
1005
total_size += 4 + sizeof(uint32_t) * 2;
1006
for (uint32_t i = 0; i < variant_count; i++) {
1007
total_size += sizeof(uint32_t) + p_variant_data[p_variants[i]].size();
1008
}
1009
1010
bytes.resize(total_size);
1011
1012
uint8_t *bytes_ptr = bytes.ptrw();
1013
memcpy(bytes_ptr, shader_file_header, 4);
1014
bytes_ptr += 4;
1015
1016
*(uint32_t *)(bytes_ptr) = cache_file_version;
1017
bytes_ptr += sizeof(uint32_t);
1018
1019
*(uint32_t *)(bytes_ptr) = variant_count;
1020
bytes_ptr += sizeof(uint32_t);
1021
1022
for (uint32_t i = 0; i < variant_count; i++) {
1023
int variant_id = p_variants[i];
1024
*(uint32_t *)(bytes_ptr) = uint32_t(p_variant_data[variant_id].size());
1025
bytes_ptr += sizeof(uint32_t);
1026
1027
memcpy(bytes_ptr, p_variant_data[variant_id].ptr(), p_variant_data[variant_id].size());
1028
bytes_ptr += p_variant_data[variant_id].size();
1029
}
1030
1031
DEV_ASSERT((bytes.ptrw() + bytes.size()) == bytes_ptr);
1032
return bytes;
1033
}
1034
1035
String ShaderRD::shader_cache_user_dir;
1036
String ShaderRD::shader_cache_res_dir;
1037
bool ShaderRD::shader_cache_save_compressed = true;
1038
bool ShaderRD::shader_cache_save_compressed_zstd = true;
1039
bool ShaderRD::shader_cache_save_debug = true;
1040
1041
ShaderRD::~ShaderRD() {
1042
LocalVector<RID> remaining = version_owner.get_owned_list();
1043
if (remaining.size()) {
1044
ERR_PRINT(itos(remaining.size()) + " shaders of type " + name + " were never freed");
1045
for (const RID &version_rid : remaining) {
1046
version_free(version_rid);
1047
}
1048
}
1049
}
1050
1051