Blender V4.5
gpu_shader.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_matrix.h"
10#include "BLI_string.h"
11#include "BLI_time.h"
12
13#include "GPU_capabilities.hh"
14#include "GPU_debug.hh"
15#include "GPU_matrix.hh"
16#include "GPU_platform.hh"
17
19
20#include "gpu_backend.hh"
22#include "gpu_profile_report.hh"
26#include "gpu_shader_private.hh"
27
28#include <string>
29
31
32namespace blender::gpu {
33
35{
36 std::string defines;
37 for (const auto &def : info.defines_) {
38 defines += "#define ";
39 defines += def[0];
40 defines += " ";
41 defines += def[1];
42 defines += "\n";
43 }
44 return defines;
45}
46
47} // namespace blender::gpu
48
49using namespace blender;
50using namespace blender::gpu;
51
52/* -------------------------------------------------------------------- */
55
56Shader::Shader(const char *sh_name)
57{
58 STRNCPY(this->name, sh_name);
59}
60
62{
63 BLI_assert_msg(Context::get() == nullptr || Context::get()->shader != this,
64 "Shader must be unbound from context before being freed");
65 delete interface;
66}
67
69{
70 BLI_assert(sources.is_empty());
71 /* Version and specialization constants needs to be first.
72 * Exact values will be added by implementation. */
73 sources.append("version");
74 sources.append("/* specialization_constants */");
75 /* Define to identify code usage in shading language. */
76 sources.append("#define GPU_SHADER\n");
77 /* some useful defines to detect GPU type */
79 sources.append("#define GPU_ATI\n");
80 }
82 sources.append("#define GPU_NVIDIA\n");
83 }
85 sources.append("#define GPU_INTEL\n");
86 }
88 sources.append("#define GPU_APPLE\n");
89 }
90 /* some useful defines to detect OS type */
92 sources.append("#define OS_WIN\n");
93 }
95 sources.append("#define OS_MAC\n");
96 }
98 sources.append("#define OS_UNIX\n");
99 }
100 /* API Definition */
102 switch (backend) {
104 sources.append("#define GPU_OPENGL\n");
105 break;
107 sources.append("#define GPU_METAL\n");
108 break;
110 sources.append("#define GPU_VULKAN\n");
111 break;
112 default:
113 BLI_assert_msg(false, "Invalid GPU Backend Type");
114 break;
115 }
116
117 if (GPU_crappy_amd_driver()) {
118 sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n");
119 }
120}
121
122GPUShader *GPU_shader_create_ex(const std::optional<StringRefNull> vertcode,
123 const std::optional<StringRefNull> fragcode,
124 const std::optional<StringRefNull> geomcode,
125 const std::optional<StringRefNull> computecode,
126 const std::optional<StringRefNull> libcode,
127 const std::optional<StringRefNull> defines,
128 const StringRefNull shname)
129{
130 /* At least a vertex shader and a fragment shader are required, or only a compute shader. */
131 BLI_assert((fragcode.has_value() && vertcode.has_value() && !computecode.has_value()) ||
132 (!fragcode.has_value() && !vertcode.has_value() && !geomcode.has_value() &&
133 computecode.has_value()));
134
136 /* Needs to be called before init as GL uses the default specialization constants state to insert
137 * default shader inside a map. */
138 shader->constants = std::make_unique<const shader::SpecializationConstants>();
139 shader->init();
140
141 if (vertcode) {
142 Vector<StringRefNull> sources;
143 standard_defines(sources);
144 sources.append("#define GPU_VERTEX_SHADER\n");
145 sources.append("#define IN_OUT out\n");
146 if (geomcode) {
147 sources.append("#define USE_GEOMETRY_SHADER\n");
148 }
149 if (defines) {
150 sources.append(*defines);
151 }
152 sources.append(*vertcode);
153
154 shader->vertex_shader_from_glsl(sources);
155 }
156
157 if (fragcode) {
158 Vector<StringRefNull> sources;
159 standard_defines(sources);
160 sources.append("#define GPU_FRAGMENT_SHADER\n");
161 sources.append("#define IN_OUT in\n");
162 if (geomcode) {
163 sources.append("#define USE_GEOMETRY_SHADER\n");
164 }
165 if (defines) {
166 sources.append(*defines);
167 }
168 if (libcode) {
169 sources.append(*libcode);
170 }
171 sources.append(*fragcode);
172
173 shader->fragment_shader_from_glsl(sources);
174 }
175
176 if (geomcode) {
177 Vector<StringRefNull> sources;
178 standard_defines(sources);
179 sources.append("#define GPU_GEOMETRY_SHADER\n");
180 if (defines) {
181 sources.append(*defines);
182 }
183 sources.append(*geomcode);
184
185 shader->geometry_shader_from_glsl(sources);
186 }
187
188 if (computecode) {
189 Vector<StringRefNull> sources;
190 standard_defines(sources);
191 sources.append("#define GPU_COMPUTE_SHADER\n");
192 if (defines) {
193 sources.append(*defines);
194 }
195 if (libcode) {
196 sources.append(*libcode);
197 }
198 sources.append(*computecode);
199
200 shader->compute_shader_from_glsl(sources);
201 }
202
203 if (!shader->finalize()) {
204 delete shader;
205 return nullptr;
206 };
207
208 return wrap(shader);
209}
210
211void GPU_shader_free(GPUShader *shader)
212{
213 delete unwrap(shader);
214}
215
217
218/* -------------------------------------------------------------------- */
221
222GPUShader *GPU_shader_create(const std::optional<StringRefNull> vertcode,
223 const std::optional<StringRefNull> fragcode,
224 const std::optional<StringRefNull> geomcode,
225 const std::optional<StringRefNull> libcode,
226 const std::optional<StringRefNull> defines,
227 const StringRefNull shname)
228{
230 vertcode, fragcode, geomcode, std::nullopt, libcode, defines, shname);
231}
232
233GPUShader *GPU_shader_create_compute(const std::optional<StringRefNull> computecode,
234 const std::optional<StringRefNull> libcode,
235 const std::optional<StringRefNull> defines,
236 const StringRefNull shname)
237{
239 std::nullopt, std::nullopt, std::nullopt, computecode, libcode, defines, shname);
240}
241
242const GPUShaderCreateInfo *GPU_shader_create_info_get(const char *info_name)
243{
244 return gpu_shader_create_info_get(info_name);
245}
246
247bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128])
248{
249 using namespace blender::gpu::shader;
250 const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
251 std::string error = info.check_error();
252 if (error.length() == 0) {
253 return true;
254 }
255
256 BLI_strncpy(r_error, error.c_str(), 128);
257 return false;
258}
259
260GPUShader *GPU_shader_create_from_info_name(const char *info_name)
261{
262 using namespace blender::gpu::shader;
263 const GPUShaderCreateInfo *_info = gpu_shader_create_info_get(info_name);
264 const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
265 if (!info.do_static_compilation_) {
266 std::cerr << "Warning: Trying to compile \"" << info.name_
267 << "\" which was not marked for static compilation.\n";
268 }
269 return GPU_shader_create_from_info(_info);
270}
271
272GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
273{
274 using namespace blender::gpu::shader;
275 const ShaderCreateInfo &info = *reinterpret_cast<const ShaderCreateInfo *>(_info);
276 return wrap(GPUBackend::get()->get_compiler()->compile(info, false));
277}
278
280{
281 if (original.is_empty()) {
282 return original;
283 }
285 return processor.process(original);
286};
287
288GPUShader *GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info)
289{
290 using namespace blender::gpu::shader;
291 ShaderCreateInfo &info = *const_cast<ShaderCreateInfo *>(
292 reinterpret_cast<const ShaderCreateInfo *>(_info));
293
294 std::string vertex_source_original = info.vertex_source_generated;
295 std::string fragment_source_original = info.fragment_source_generated;
296 std::string geometry_source_original = info.geometry_source_generated;
297 std::string compute_source_original = info.compute_source_generated;
298
303
304 GPUShader *result = wrap(GPUBackend::get()->get_compiler()->compile(info, false));
305
306 info.vertex_source_generated = vertex_source_original;
307 info.fragment_source_generated = fragment_source_original;
308 info.geometry_source_generated = geometry_source_original;
309 info.compute_source_generated = compute_source_original;
310
311 return result;
312}
313
314GPUShader *GPU_shader_create_from_python(std::optional<StringRefNull> vertcode,
315 std::optional<StringRefNull> fragcode,
316 std::optional<StringRefNull> geomcode,
317 std::optional<StringRefNull> libcode,
318 std::optional<StringRefNull> defines,
319 const std::optional<StringRefNull> name)
320{
321 std::string defines_cat = "#define GPU_RAW_PYTHON_SHADER\n";
322 if (defines) {
323 defines_cat += defines.value();
324 defines = defines_cat;
325 }
326 else {
327 defines = defines_cat;
328 }
329
330 std::string libcodecat;
331
332 if (!libcode) {
334 }
335 else {
336 libcodecat = *libcode + datatoc_gpu_shader_colorspace_lib_glsl;
337 libcode = libcodecat;
338 }
339
340 std::string vertex_source_processed;
341 std::string fragment_source_processed;
342 std::string geometry_source_processed;
343 std::string library_source_processed;
344
345 if (vertcode.has_value()) {
346 vertex_source_processed = GPU_shader_preprocess_source(*vertcode);
347 vertcode = vertex_source_processed;
348 }
349 if (fragcode.has_value()) {
350 fragment_source_processed = GPU_shader_preprocess_source(*fragcode);
351 fragcode = fragment_source_processed;
352 }
353 if (geomcode.has_value()) {
354 geometry_source_processed = GPU_shader_preprocess_source(*geomcode);
355 geomcode = geometry_source_processed;
356 }
357 if (libcode.has_value()) {
358 library_source_processed = GPU_shader_preprocess_source(*libcode);
359 libcode = library_source_processed;
360 }
361
362 /* Use pyGPUShader as default name for shader. */
363 blender::StringRefNull shname = name.value_or("pyGPUShader");
364
365 GPUShader *sh = GPU_shader_create_ex(
366 vertcode, fragcode, geomcode, std::nullopt, libcode, defines, shname);
367
368 return sh;
369}
370
379
381{
382 return GPUBackend::get()->get_compiler()->batch_is_ready(handle);
383}
384
390
395
400
402{
403 printf("Compiling all static GPU shaders. This process takes a while.\n");
405}
406
411
413
414/* -------------------------------------------------------------------- */
417
418void GPU_shader_bind(GPUShader *gpu_shader, const shader::SpecializationConstants *constants_state)
419{
420 Shader *shader = unwrap(gpu_shader);
421
422 BLI_assert_msg(constants_state != nullptr || shader->constants->is_empty(),
423 "Shader requires specialization constants but none was passed");
424
425 Context *ctx = Context::get();
426
427 if (ctx->shader != shader) {
428 ctx->shader = shader;
429 shader->bind(constants_state);
430 GPU_matrix_bind(gpu_shader);
431 Shader::set_srgb_uniform(ctx, gpu_shader);
432 }
433 else {
434 if (constants_state) {
435 shader->bind(constants_state);
436 }
438 Shader::set_srgb_uniform(ctx, gpu_shader);
439 }
440 if (GPU_matrix_dirty_get()) {
441 GPU_matrix_bind(gpu_shader);
442 }
443 }
444#if GPU_SHADER_PRINTF_ENABLE
445 if (!ctx->printf_buf.is_empty()) {
447 }
448#endif
449}
450
452{
453 Context *ctx = Context::get();
454 if (ctx == nullptr) {
455 return;
456 }
457#ifndef NDEBUG
458 if (ctx->shader) {
459 ctx->shader->unbind();
460 }
461#endif
462 ctx->shader = nullptr;
463}
464
466{
467 Context *ctx = Context::get();
468 if (ctx) {
469 return wrap(ctx->shader);
470 }
471 return nullptr;
472}
473
475
476/* -------------------------------------------------------------------- */
479
480const char *GPU_shader_get_name(GPUShader *shader)
481{
482 return unwrap(shader)->name_get().c_str();
483}
484
486
487/* -------------------------------------------------------------------- */
490
491void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent)
492{
493 BLI_assert(shader != nullptr);
494 BLI_assert(shader != parent);
495 if (shader != parent) {
496 Shader *shd_child = unwrap(shader);
497 Shader *shd_parent = unwrap(parent);
498 shd_child->parent_set(shd_parent);
499 }
500}
501
502void GPU_shader_warm_cache(GPUShader *shader, int limit)
503{
504 unwrap(shader)->warm_cache(limit);
505}
506
508
509/* -------------------------------------------------------------------- */
512
514{
515 return *unwrap(sh)->constants;
516}
517
519{
520 using namespace shader;
523 constants_tmp.types.append(sc.type);
524 constants_tmp.values.append(sc.value);
525 }
526 constants = std::make_unique<const shader::SpecializationConstants>(std::move(constants_tmp));
527}
528
534
539
544
546
547/* -------------------------------------------------------------------- */
550
551int GPU_shader_get_uniform(GPUShader *shader, const char *name)
552{
553 const ShaderInterface *interface = unwrap(shader)->interface;
554 const ShaderInput *uniform = interface->uniform_get(name);
555 return uniform ? uniform->location : -1;
556}
557
558int GPU_shader_get_constant(GPUShader *shader, const char *name)
559{
560 const ShaderInterface *interface = unwrap(shader)->interface;
561 const ShaderInput *constant = interface->constant_get(name);
562 return constant ? constant->location : -1;
563}
564
565int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
566{
567 const ShaderInterface *interface = unwrap(shader)->interface;
568 return interface->uniform_builtin((GPUUniformBuiltin)builtin);
569}
570
571int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
572{
573 const ShaderInterface *interface = unwrap(shader)->interface;
574 return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
575}
576
577int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
578{
579 const ShaderInterface *interface = unwrap(shader)->interface;
580 const ShaderInput *ssbo = interface->ssbo_get(name);
581 return ssbo ? ssbo->location : -1;
582}
583
584int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
585{
586 const ShaderInterface *interface = unwrap(shader)->interface;
587 const ShaderInput *ubo = interface->ubo_get(name);
588 return ubo ? ubo->location : -1;
589}
590
591int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name)
592{
593 const ShaderInterface *interface = unwrap(shader)->interface;
594 const ShaderInput *ubo = interface->ubo_get(name);
595 return ubo ? ubo->binding : -1;
596}
597
598int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
599{
600 const ShaderInterface *interface = unwrap(shader)->interface;
601 const ShaderInput *tex = interface->uniform_get(name);
602 return tex ? tex->binding : -1;
603}
604
606{
607 const ShaderInterface *interface = unwrap(shader)->interface;
608 return interface->valid_bindings_get(interface->inputs_, interface->attr_len_);
609}
610
612{
613 const ShaderInterface *interface = unwrap(shader)->interface;
614 return interface->ssbo_len_;
615}
616
617int GPU_shader_get_attribute(const GPUShader *shader, const char *name)
618{
619 const ShaderInterface *interface = unwrap(shader)->interface;
620 const ShaderInput *attr = interface->attr_get(name);
621 return attr ? attr->location : -1;
622}
623
625 int attr_location,
626 char r_name[256],
627 int *r_type)
628{
629 const ShaderInterface *interface = unwrap(shader)->interface;
630
631 const ShaderInput *attr = interface->attr_get(attr_location);
632 if (!attr) {
633 return false;
634 }
635
636 BLI_strncpy(r_name, interface->input_name_get(attr), 256);
637 *r_type = attr->location != -1 ? interface->attr_types_[attr->location] : -1;
638 return true;
639}
640
641bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256])
642{
643 const ShaderInterface *interface = unwrap(shader)->interface;
644
645 const ShaderInput *ssbo_input = interface->ssbo_get(ssbo_location);
646 if (!ssbo_input) {
647 return false;
648 }
649
650 BLI_strncpy(r_name, interface->input_name_get(ssbo_input), 256);
651 return true;
652}
653
655
656/* -------------------------------------------------------------------- */
659
661 GPUShader *shader, int loc, int len, int array_size, const float *value)
662{
663 unwrap(shader)->uniform_float(loc, len, array_size, value);
664}
665
667 GPUShader *shader, int loc, int len, int array_size, const int *value)
668{
669 unwrap(shader)->uniform_int(loc, len, array_size, value);
670}
671
672void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
673{
674 const int loc = GPU_shader_get_uniform(sh, name);
675 GPU_shader_uniform_int_ex(sh, loc, 1, 1, &value);
676}
677
678void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
679{
680 GPU_shader_uniform_1i(sh, name, value ? 1 : 0);
681}
682
683void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y)
684{
685 const float data[2] = {x, y};
686 GPU_shader_uniform_2fv(sh, name, data);
687}
688
689void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z)
690{
691 const float data[3] = {x, y, z};
692 GPU_shader_uniform_3fv(sh, name, data);
693}
694
695void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w)
696{
697 const float data[4] = {x, y, z, w};
698 GPU_shader_uniform_4fv(sh, name, data);
699}
700
701void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
702{
703 const int loc = GPU_shader_get_uniform(sh, name);
704 GPU_shader_uniform_float_ex(sh, loc, 1, 1, &value);
705}
706
707void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
708{
709 const int loc = GPU_shader_get_uniform(sh, name);
710 GPU_shader_uniform_float_ex(sh, loc, 2, 1, data);
711}
712
713void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
714{
715 const int loc = GPU_shader_get_uniform(sh, name);
716 GPU_shader_uniform_float_ex(sh, loc, 3, 1, data);
717}
718
719void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
720{
721 const int loc = GPU_shader_get_uniform(sh, name);
722 GPU_shader_uniform_float_ex(sh, loc, 4, 1, data);
723}
724
725void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
726{
727 const int loc = GPU_shader_get_uniform(sh, name);
728 GPU_shader_uniform_int_ex(sh, loc, 2, 1, data);
729}
730
731void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3])
732{
733 const int loc = GPU_shader_get_uniform(sh, name);
734 GPU_shader_uniform_int_ex(sh, loc, 3, 1, data);
735}
736
737void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
738{
739 const int loc = GPU_shader_get_uniform(sh, name);
740 GPU_shader_uniform_float_ex(sh, loc, 16, 1, (const float *)data);
741}
742
743void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
744{
745 float matrix[4][4];
746 copy_m4_m3(matrix, data);
747 GPU_shader_uniform_mat4(sh, name, matrix);
748}
749
750void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val)
751{
752 const int loc = GPU_shader_get_uniform(sh, name);
753 GPU_shader_uniform_float_ex(sh, loc, 1, len, val);
754}
755
756void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2])
757{
758 const int loc = GPU_shader_get_uniform(sh, name);
759 GPU_shader_uniform_float_ex(sh, loc, 2, len, (const float *)val);
760}
761
762void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4])
763{
764 const int loc = GPU_shader_get_uniform(sh, name);
765 GPU_shader_uniform_float_ex(sh, loc, 4, len, (const float *)val);
766}
767
769
770namespace blender::gpu {
771
772/* -------------------------------------------------------------------- */
782
791
792void Shader::set_framebuffer_srgb_target(int use_srgb_to_linear)
793{
794 Context *ctx = Context::get();
795 if (ctx->shader_builtin_srgb_transform != use_srgb_to_linear) {
796 ctx->shader_builtin_srgb_transform = use_srgb_to_linear;
798 }
799}
800
802
803/* -------------------------------------------------------------------- */
806
807Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_batch_compilation)
808{
809 using Clock = std::chrono::steady_clock;
810 using TimePoint = Clock::time_point;
811
812 using namespace blender::gpu::shader;
813 const_cast<ShaderCreateInfo &>(info).finalize();
814
815 TimePoint start_time;
816
817 if (Context::get()) {
818 /* Context can be null in Vulkan compilation threads. */
821 }
822 else if (G.profile_gpu) {
823 start_time = Clock::now();
824 }
825
826 const std::string error = info.check_error();
827 if (!error.empty()) {
828 std::cerr << error << "\n";
829 BLI_assert(false);
830 }
831
833 /* Needs to be called before init as GL uses the default specialization constants state to insert
834 * default shader inside a map. */
835 shader->specialization_constants_init(info);
836 shader->init(info, is_batch_compilation);
837
838 shader->fragment_output_bits = 0;
839 for (const shader::ShaderCreateInfo::FragOut &frag_out : info.fragment_outputs_) {
840 shader->fragment_output_bits |= 1u << frag_out.index;
841 }
842
843 std::string defines = shader->defines_declare(info);
844 std::string resources = shader->resources_declare(info);
845
846 defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
847
848 Vector<StringRefNull> typedefs;
849 if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) {
850 typedefs.append(gpu_shader_dependency_get_source("GPU_shader_shared_utils.hh").c_str());
851 }
852 if (!info.typedef_source_generated.empty()) {
853 typedefs.append(info.typedef_source_generated);
854 }
855 for (auto filename : info.typedef_sources_) {
856 typedefs.append(gpu_shader_dependency_get_source(filename));
857 }
858
859 if (!info.vertex_source_.is_empty()) {
861 std::string interface = shader->vertex_interface_declare(info);
862
863 Vector<StringRefNull> sources;
864 standard_defines(sources);
865 sources.append("#define GPU_VERTEX_SHADER\n");
866 if (!info.geometry_source_.is_empty()) {
867 sources.append("#define USE_GEOMETRY_SHADER\n");
868 }
869 sources.append(defines);
870 sources.extend(typedefs);
871 sources.append(resources);
872 sources.append(interface);
873 sources.extend(code);
874 sources.extend(info.dependencies_generated);
875 sources.append(info.vertex_source_generated);
876
877 shader->vertex_shader_from_glsl(sources);
878 }
879
880 if (!info.fragment_source_.is_empty()) {
882 std::string interface = shader->fragment_interface_declare(info);
883
884 Vector<StringRefNull> sources;
885 standard_defines(sources);
886 sources.append("#define GPU_FRAGMENT_SHADER\n");
887 if (!info.geometry_source_.is_empty()) {
888 sources.append("#define USE_GEOMETRY_SHADER\n");
889 }
890 sources.append(defines);
891 sources.extend(typedefs);
892 sources.append(resources);
893 sources.append(interface);
894 sources.extend(code);
895 sources.extend(info.dependencies_generated);
896 sources.append(info.fragment_source_generated);
897
898 shader->fragment_shader_from_glsl(sources);
899 }
900
901 if (!info.geometry_source_.is_empty()) {
903 std::string layout = shader->geometry_layout_declare(info);
904 std::string interface = shader->geometry_interface_declare(info);
905
906 Vector<StringRefNull> sources;
907 standard_defines(sources);
908 sources.append("#define GPU_GEOMETRY_SHADER\n");
909 sources.append(defines);
910 sources.extend(typedefs);
911 sources.append(resources);
912 sources.append(layout);
913 sources.append(interface);
914 sources.append(info.geometry_source_generated);
915 sources.extend(code);
916
917 shader->geometry_shader_from_glsl(sources);
918 }
919
920 if (!info.compute_source_.is_empty()) {
922 std::string layout = shader->compute_layout_declare(info);
923
924 Vector<StringRefNull> sources;
925 standard_defines(sources);
926 sources.append("#define GPU_COMPUTE_SHADER\n");
927 sources.append(defines);
928 sources.extend(typedefs);
929 sources.append(resources);
930 sources.append(layout);
931 sources.extend(code);
932 sources.extend(info.dependencies_generated);
933 sources.append(info.compute_source_generated);
934
935 shader->compute_shader_from_glsl(sources);
936 }
937
938 if (!shader->finalize(&info)) {
939 delete shader;
940 shader = nullptr;
941 }
942
943 if (Context::get()) {
944 /* Context can be null in Vulkan compilation threads. */
947 }
948 else if (G.profile_gpu) {
949 TimePoint end_time = Clock::now();
950 /* Note: Used by the vulkan backend. Use the same time_since_epoch as process_frame_timings. */
952 start_time.time_since_epoch().count(),
953 end_time.time_since_epoch().count());
955 start_time.time_since_epoch().count(),
956 end_time.time_since_epoch().count());
957 }
958
959 return shader;
960}
961
962ShaderCompiler::ShaderCompiler(uint32_t threads_count,
963 GPUWorker::ContextType context_type,
964 bool support_specializations)
965{
966 support_specializations_ = support_specializations;
967
969 compilation_worker_ = std::make_unique<GPUWorker>(
970 threads_count,
971 context_type,
972 mutex_,
973 [this]() -> void * { return this->pop_work(); },
974 [this](void *work) { this->do_work(work); });
975 }
976}
977
979{
980 compilation_worker_.reset();
981
982 /* Ensure all the requested batches have been retrieved. */
983 BLI_assert(batches_.is_empty());
984}
985
987{
988 return compile(info, false);
989}
990
992 CompilationPriority priority)
993{
994 std::unique_lock lock(mutex_);
995
996 Batch *batch = MEM_new<Batch>(__func__);
997 batch->infos = infos;
998 batch->shaders.reserve(infos.size());
999
1000 BatchHandle handle = next_batch_handle_++;
1001 batches_.add(handle, batch);
1002
1003 if (compilation_worker_) {
1004 batch->shaders.resize(infos.size(), nullptr);
1005 batch->pending_compilations = infos.size();
1006 for (int i : infos.index_range()) {
1007 compilation_queue_.push({batch, i}, priority);
1008 compilation_worker_->wake_up();
1009 }
1010 }
1011 else {
1012 for (const shader::ShaderCreateInfo *info : infos) {
1013 batch->shaders.append(compile(*info, false));
1014 }
1015 }
1016
1017 return handle;
1018}
1019
1021{
1022 std::unique_lock lock(mutex_);
1023
1024 Batch *batch = batches_.pop(handle);
1025 compilation_queue_.remove_batch(batch);
1026
1027 if (batch->is_specialization_batch()) {
1028 /* For specialization batches, we block until ready, since base shader compilation may be
1029 * cancelled afterwards, leaving the specialization with a deleted base shader. */
1030 compilation_finished_notification_.wait(lock, [&]() { return batch->is_ready(); });
1031 }
1032
1033 if (batch->is_ready()) {
1034 batch->free_shaders();
1035 MEM_delete(batch);
1036 }
1037 else {
1038 /* If it's currently compiling, the compilation thread makes the cleanup. */
1039 batch->is_cancelled = true;
1040 }
1041
1042 handle = 0;
1043}
1044
1046{
1047 std::lock_guard lock(mutex_);
1048
1049 return batches_.lookup(handle)->is_ready();
1050}
1051
1053{
1054 std::unique_lock lock(mutex_);
1055 /* TODO: Move to be first on the queue. */
1056 compilation_finished_notification_.wait(lock,
1057 [&]() { return batches_.lookup(handle)->is_ready(); });
1058
1059 Batch *batch = batches_.pop(handle);
1060 Vector<Shader *> shaders = std::move(batch->shaders);
1061 MEM_delete(batch);
1062 handle = 0;
1063
1064 return shaders;
1065}
1066
1068 Span<ShaderSpecialization> specializations, CompilationPriority priority)
1069{
1070 if (!compilation_worker_ || !support_specializations_) {
1071 return 0;
1072 }
1073
1074 std::lock_guard lock(mutex_);
1075
1076 Batch *batch = MEM_new<Batch>(__func__);
1077 batch->specializations = specializations;
1078
1079 BatchHandle handle = next_batch_handle_++;
1080 batches_.add(handle, batch);
1081
1082 batch->pending_compilations = specializations.size();
1083 for (int i : specializations.index_range()) {
1084 compilation_queue_.push({batch, i}, priority);
1085 compilation_worker_->wake_up();
1086 }
1087
1088 return handle;
1089}
1090
1092{
1093 if (handle != 0 && batch_is_ready(handle)) {
1094 std::lock_guard lock(mutex_);
1095
1096 Batch *batch = batches_.pop(handle);
1097 MEM_delete(batch);
1098 handle = 0;
1099 }
1100
1101 return handle == 0;
1102}
1103
1104void *ShaderCompiler::pop_work()
1105{
1106 /* NOTE: Already under mutex lock when GPUWorker calls this function. */
1107
1108 if (compilation_queue_.is_empty()) {
1109 return nullptr;
1110 }
1111
1112 ParallelWork work = compilation_queue_.pop();
1113 return MEM_new<ParallelWork>(__func__, work);
1114}
1115
1116void ShaderCompiler::do_work(void *work_payload)
1117{
1118 ParallelWork *work = reinterpret_cast<ParallelWork *>(work_payload);
1119 Batch *batch = work->batch;
1120 int shader_index = work->shader_index;
1121 MEM_delete(work);
1122
1123 /* Compile */
1124 if (!batch->is_specialization_batch()) {
1125 batch->shaders[shader_index] = compile_shader(*batch->infos[shader_index]);
1126 }
1127 else {
1128 specialize_shader(batch->specializations[shader_index]);
1129 }
1130
1131 {
1132 std::lock_guard lock(mutex_);
1133 batch->pending_compilations--;
1134 if (batch->is_ready() && batch->is_cancelled) {
1135 batch->free_shaders();
1136 MEM_delete(batch);
1137 }
1138 }
1139
1140 compilation_finished_notification_.notify_all();
1141}
1142
1144{
1145 std::unique_lock lock(mutex_);
1146 compilation_finished_notification_.wait(lock, [&]() {
1147 if (!compilation_queue_.is_empty()) {
1148 return false;
1149 }
1150
1151 for (Batch *batch : batches_.values()) {
1152 if (!batch->is_ready()) {
1153 return false;
1154 }
1155 }
1156
1157 return true;
1158 });
1159}
1160
1162
1163} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
void copy_m4_m3(float m1[4][4], const float m2[3][3])
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned int uint
Platform independent time functions.
bool GPU_crappy_amd_driver()
bool GPU_use_main_context_workaround()
eGPUBackendType GPU_backend_get_type()
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
#define GPU_DEBUG_SHADER_COMPILATION_GROUP
Definition GPU_debug.hh:64
void GPU_matrix_bind(GPUShader *shader)
bool GPU_matrix_dirty_get()
@ GPU_DRIVER_ANY
@ GPU_OS_WIN
@ GPU_OS_UNIX
@ GPU_OS_ANY
@ GPU_OS_MAC
@ GPU_DEVICE_ATI
@ GPU_DEVICE_NVIDIA
@ GPU_DEVICE_ANY
@ GPU_DEVICE_APPLE
@ GPU_DEVICE_INTEL
bool GPU_type_matches(eGPUDeviceType device, eGPUOSType os, eGPUDriverType driver)
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
int GPU_shader_get_uniform(GPUShader *shader, const char *name)
GPUShader * GPU_shader_create_from_info_python(const GPUShaderCreateInfo *_info)
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
GPUShader * GPU_shader_create_compute(std::optional< blender::StringRefNull > computecode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
bool GPU_shader_get_attribute_info(const GPUShader *shader, int attr_location, char r_name[256], int *r_type)
const char * GPU_shader_get_name(GPUShader *shader)
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name)
void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z)
void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3])
blender::Vector< GPUShader * > GPU_shader_batch_finalize(BatchHandle &handle)
void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y)
uint GPU_shader_get_ssbo_input_len(const GPUShader *shader)
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float(*val)[2])
GPUShader * GPU_shader_create_ex(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > computecode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
void GPU_shader_uniform_int_ex(GPUShader *shader, int location, int length, int array_size, const int *value)
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_shader_cache_dir_clear_old()
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val)
uint GPU_shader_get_attribute_len(const GPUShader *shader)
int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
int GPU_shader_get_attribute(const GPUShader *shader, const char *name)
void GPU_shader_batch_wait_for_all()
void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float(*val)[4])
int64_t BatchHandle
Definition GPU_shader.hh:83
GPUShader * GPU_shader_create_from_python(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, std::optional< blender::StringRefNull > name)
void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent)
bool GPU_shader_batch_is_ready(BatchHandle handle)
int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
void GPU_shader_uniform_float_ex(GPUShader *shader, int location, int length, int array_size, const float *value)
std::string GPU_shader_preprocess_source(blender::StringRefNull original)
SpecializationBatchHandle GPU_shader_batch_specializations(blender::Span< ShaderSpecialization > specializations, CompilationPriority priority=CompilationPriority::High)
const GPUShaderCreateInfo * GPU_shader_create_info_get(const char *info_name)
CompilationPriority
Definition GPU_shader.hh:81
void GPU_shader_batch_specializations_cancel(SpecializationBatchHandle &handle)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
GPUUniformBuiltin
@ GPU_UNIFORM_SRGB_TRANSFORM
GPUShader * GPU_shader_create_from_info(const GPUShaderCreateInfo *_info)
void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w)
int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
int64_t SpecializationBatchHandle
GPUShader * GPU_shader_create(std::optional< blender::StringRefNull > vertcode, std::optional< blender::StringRefNull > fragcode, std::optional< blender::StringRefNull > geomcode, std::optional< blender::StringRefNull > libcode, std::optional< blender::StringRefNull > defines, blender::StringRefNull shname)
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
int GPU_shader_get_constant(GPUShader *shader, const char *name)
int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
void GPU_shader_batch_cancel(BatchHandle &handle)
void GPU_shader_free(GPUShader *shader)
bool GPU_shader_create_info_check_error(const GPUShaderCreateInfo *_info, char r_error[128])
void GPU_shader_unbind()
GPUShader * GPU_shader_get_bound()
BatchHandle GPU_shader_batch_create_from_infos(blender::Span< const GPUShaderCreateInfo * > infos, CompilationPriority priority=CompilationPriority::High)
void GPU_shader_warm_cache(GPUShader *shader, int limit)
GPUUniformBlockBuiltin
bool GPU_shader_batch_specializations_is_ready(SpecializationBatchHandle &handle)
const blender::gpu::shader::SpecializationConstants & GPU_shader_get_default_constant_state(GPUShader *sh)
void GPU_shader_compile_static()
bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256])
void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot)
volatile int lock
BMesh const char void * data
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
constexpr const char * c_str() const
void append(const T &value)
bool is_empty() const
void extend(Span< T > array)
static Context * get()
Vector< GPUStorageBuf * > printf_buf
static GPUBackend * get()
ShaderCompiler * get_compiler()
virtual void shader_cache_dir_clear_old()=0
virtual Shader * shader_alloc(const char *name)=0
static ProfileReport & get()
void add_group_cpu(StringRefNull name, uint64_t cpu_start, uint64_t cpu_end)
void batch_cancel(BatchHandle &handle)
BatchHandle batch_compile(Span< const shader::ShaderCreateInfo * > &infos, CompilationPriority priority)
bool specialization_batch_is_ready(SpecializationBatchHandle &handle)
Vector< Shader * > batch_finalize(BatchHandle &handle)
Shader * compile(const shader::ShaderCreateInfo &info, bool is_batch_compilation)
bool batch_is_ready(BatchHandle handle)
ShaderCompiler(uint32_t threads_count=1, GPUWorker::ContextType context_type=GPUWorker::ContextType::PerThread, bool support_specializations=false)
SpecializationBatchHandle precompile_specializations(Span< ShaderSpecialization > specializations, CompilationPriority priority)
virtual Shader * compile_shader(const shader::ShaderCreateInfo &info)
virtual void unbind()=0
static void set_srgb_uniform(Context *ctx, GPUShader *shader)
std::string defines_declare(const shader::ShaderCreateInfo &info) const
Definition gpu_shader.cc:34
std::unique_ptr< const shader::SpecializationConstants > constants
ShaderInterface * interface
void specialization_constants_init(const shader::ShaderCreateInfo &info)
void parent_set(Shader *parent)
static void set_framebuffer_srgb_target(int use_srgb_to_linear)
std::string process(SourceLanguage language, std::string str, const std::string &filename, bool do_parse_function, bool do_small_type_linting, report_callback report_error, metadata::Source &r_metadata)
struct @040300273355226347117046032274375156036214075200::@220112075160172005224025156041142162054225111362 batch
#define interface
#define printf(...)
static void standard_defines(Vector< StringRefNull > &sources)
Definition gpu_shader.cc:68
char datatoc_gpu_shader_colorspace_lib_glsl[]
Definition gpu_shader.cc:30
const GPUShaderCreateInfo * gpu_shader_create_info_get(const char *info_name)
bool gpu_shader_create_info_compile(const char *name_starts_with_filter)
#define GPU_SHADER_PRINTF_SLOT
#define G(x, y, z)
static void error(const char *str)
Vector< StringRefNull > gpu_shader_dependency_get_resolved_source(const StringRefNull shader_source_name)
StringRefNull gpu_shader_dependency_get_source(const StringRefNull shader_source_name)
static Context * unwrap(GPUContext *ctx)
static GPUContext * wrap(Context *ctx)
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
std::string fragment_source_generated
std::string check_error() const
std::string geometry_source_generated
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Vector< std::array< StringRefNull, 2 > > defines_
Vector< SpecializationConstant > specialization_constants_
Vector< SpecializationConstant::Value, 8 > values
i
Definition text_draw.cc:230
uint len