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
405
407{
408 printf("Compiling all static GPU shaders. This process takes a while.\n");
410}
411
416
418
419/* -------------------------------------------------------------------- */
422
423void GPU_shader_bind(GPUShader *gpu_shader, const shader::SpecializationConstants *constants_state)
424{
425 Shader *shader = unwrap(gpu_shader);
426
427 BLI_assert_msg(constants_state != nullptr || shader->constants->is_empty(),
428 "Shader requires specialization constants but none was passed");
429
430 Context *ctx = Context::get();
431
432 if (ctx->shader != shader) {
433 ctx->shader = shader;
434 shader->bind(constants_state);
435 GPU_matrix_bind(gpu_shader);
436 Shader::set_srgb_uniform(ctx, gpu_shader);
437 }
438 else {
439 if (constants_state) {
440 shader->bind(constants_state);
441 }
443 Shader::set_srgb_uniform(ctx, gpu_shader);
444 }
445 if (GPU_matrix_dirty_get()) {
446 GPU_matrix_bind(gpu_shader);
447 }
448 }
449#if GPU_SHADER_PRINTF_ENABLE
450 if (!ctx->printf_buf.is_empty()) {
452 }
453#endif
454}
455
457{
458 Context *ctx = Context::get();
459 if (ctx == nullptr) {
460 return;
461 }
462#ifndef NDEBUG
463 if (ctx->shader) {
464 ctx->shader->unbind();
465 }
466#endif
467 ctx->shader = nullptr;
468}
469
471{
472 Context *ctx = Context::get();
473 if (ctx) {
474 return wrap(ctx->shader);
475 }
476 return nullptr;
477}
478
480
481/* -------------------------------------------------------------------- */
484
485const char *GPU_shader_get_name(GPUShader *shader)
486{
487 return unwrap(shader)->name_get().c_str();
488}
489
491
492/* -------------------------------------------------------------------- */
495
496void GPU_shader_set_parent(GPUShader *shader, GPUShader *parent)
497{
498 BLI_assert(shader != nullptr);
499 BLI_assert(shader != parent);
500 if (shader != parent) {
501 Shader *shd_child = unwrap(shader);
502 Shader *shd_parent = unwrap(parent);
503 shd_child->parent_set(shd_parent);
504 }
505}
506
507void GPU_shader_warm_cache(GPUShader *shader, int limit)
508{
509 unwrap(shader)->warm_cache(limit);
510}
511
513
514/* -------------------------------------------------------------------- */
517
519{
520 return *unwrap(sh)->constants;
521}
522
524{
525 using namespace shader;
528 constants_tmp.types.append(sc.type);
529 constants_tmp.values.append(sc.value);
530 }
531 constants = std::make_unique<const shader::SpecializationConstants>(std::move(constants_tmp));
532}
533
539
544
549
551
552/* -------------------------------------------------------------------- */
555
556int GPU_shader_get_uniform(GPUShader *shader, const char *name)
557{
558 const ShaderInterface *interface = unwrap(shader)->interface;
559 const ShaderInput *uniform = interface->uniform_get(name);
560 return uniform ? uniform->location : -1;
561}
562
563int GPU_shader_get_constant(GPUShader *shader, const char *name)
564{
565 const ShaderInterface *interface = unwrap(shader)->interface;
566 const ShaderInput *constant = interface->constant_get(name);
567 return constant ? constant->location : -1;
568}
569
570int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
571{
572 const ShaderInterface *interface = unwrap(shader)->interface;
573 return interface->uniform_builtin((GPUUniformBuiltin)builtin);
574}
575
576int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
577{
578 const ShaderInterface *interface = unwrap(shader)->interface;
579 return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
580}
581
582int GPU_shader_get_ssbo_binding(GPUShader *shader, const char *name)
583{
584 const ShaderInterface *interface = unwrap(shader)->interface;
585 const ShaderInput *ssbo = interface->ssbo_get(name);
586 return ssbo ? ssbo->location : -1;
587}
588
589int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
590{
591 const ShaderInterface *interface = unwrap(shader)->interface;
592 const ShaderInput *ubo = interface->ubo_get(name);
593 return ubo ? ubo->location : -1;
594}
595
596int GPU_shader_get_ubo_binding(GPUShader *shader, const char *name)
597{
598 const ShaderInterface *interface = unwrap(shader)->interface;
599 const ShaderInput *ubo = interface->ubo_get(name);
600 return ubo ? ubo->binding : -1;
601}
602
603int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
604{
605 const ShaderInterface *interface = unwrap(shader)->interface;
606 const ShaderInput *tex = interface->uniform_get(name);
607 return tex ? tex->binding : -1;
608}
609
611{
612 const ShaderInterface *interface = unwrap(shader)->interface;
613 return interface->valid_bindings_get(interface->inputs_, interface->attr_len_);
614}
615
617{
618 const ShaderInterface *interface = unwrap(shader)->interface;
619 return interface->ssbo_len_;
620}
621
622int GPU_shader_get_attribute(const GPUShader *shader, const char *name)
623{
624 const ShaderInterface *interface = unwrap(shader)->interface;
625 const ShaderInput *attr = interface->attr_get(name);
626 return attr ? attr->location : -1;
627}
628
630 int attr_location,
631 char r_name[256],
632 int *r_type)
633{
634 const ShaderInterface *interface = unwrap(shader)->interface;
635
636 const ShaderInput *attr = interface->attr_get(attr_location);
637 if (!attr) {
638 return false;
639 }
640
641 BLI_strncpy(r_name, interface->input_name_get(attr), 256);
642 *r_type = attr->location != -1 ? interface->attr_types_[attr->location] : -1;
643 return true;
644}
645
646bool GPU_shader_get_ssbo_input_info(const GPUShader *shader, int ssbo_location, char r_name[256])
647{
648 const ShaderInterface *interface = unwrap(shader)->interface;
649
650 const ShaderInput *ssbo_input = interface->ssbo_get(ssbo_location);
651 if (!ssbo_input) {
652 return false;
653 }
654
655 BLI_strncpy(r_name, interface->input_name_get(ssbo_input), 256);
656 return true;
657}
658
660
661/* -------------------------------------------------------------------- */
664
666 GPUShader *shader, int loc, int len, int array_size, const float *value)
667{
668 unwrap(shader)->uniform_float(loc, len, array_size, value);
669}
670
672 GPUShader *shader, int loc, int len, int array_size, const int *value)
673{
674 unwrap(shader)->uniform_int(loc, len, array_size, value);
675}
676
677void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
678{
679 const int loc = GPU_shader_get_uniform(sh, name);
680 GPU_shader_uniform_int_ex(sh, loc, 1, 1, &value);
681}
682
683void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
684{
685 GPU_shader_uniform_1i(sh, name, value ? 1 : 0);
686}
687
688void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y)
689{
690 const float data[2] = {x, y};
691 GPU_shader_uniform_2fv(sh, name, data);
692}
693
694void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z)
695{
696 const float data[3] = {x, y, z};
697 GPU_shader_uniform_3fv(sh, name, data);
698}
699
700void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w)
701{
702 const float data[4] = {x, y, z, w};
703 GPU_shader_uniform_4fv(sh, name, data);
704}
705
706void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
707{
708 const int loc = GPU_shader_get_uniform(sh, name);
709 GPU_shader_uniform_float_ex(sh, loc, 1, 1, &value);
710}
711
712void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
713{
714 const int loc = GPU_shader_get_uniform(sh, name);
715 GPU_shader_uniform_float_ex(sh, loc, 2, 1, data);
716}
717
718void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
719{
720 const int loc = GPU_shader_get_uniform(sh, name);
721 GPU_shader_uniform_float_ex(sh, loc, 3, 1, data);
722}
723
724void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
725{
726 const int loc = GPU_shader_get_uniform(sh, name);
727 GPU_shader_uniform_float_ex(sh, loc, 4, 1, data);
728}
729
730void GPU_shader_uniform_2iv(GPUShader *sh, const char *name, const int data[2])
731{
732 const int loc = GPU_shader_get_uniform(sh, name);
733 GPU_shader_uniform_int_ex(sh, loc, 2, 1, data);
734}
735
736void GPU_shader_uniform_3iv(GPUShader *sh, const char *name, const int data[3])
737{
738 const int loc = GPU_shader_get_uniform(sh, name);
739 GPU_shader_uniform_int_ex(sh, loc, 3, 1, data);
740}
741
742void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
743{
744 const int loc = GPU_shader_get_uniform(sh, name);
745 GPU_shader_uniform_float_ex(sh, loc, 16, 1, (const float *)data);
746}
747
748void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
749{
750 float matrix[4][4];
751 copy_m4_m3(matrix, data);
752 GPU_shader_uniform_mat4(sh, name, matrix);
753}
754
755void GPU_shader_uniform_1f_array(GPUShader *sh, const char *name, int len, const float *val)
756{
757 const int loc = GPU_shader_get_uniform(sh, name);
758 GPU_shader_uniform_float_ex(sh, loc, 1, len, val);
759}
760
761void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2])
762{
763 const int loc = GPU_shader_get_uniform(sh, name);
764 GPU_shader_uniform_float_ex(sh, loc, 2, len, (const float *)val);
765}
766
767void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4])
768{
769 const int loc = GPU_shader_get_uniform(sh, name);
770 GPU_shader_uniform_float_ex(sh, loc, 4, len, (const float *)val);
771}
772
774
775namespace blender::gpu {
776
777/* -------------------------------------------------------------------- */
787
796
797void Shader::set_framebuffer_srgb_target(int use_srgb_to_linear)
798{
799 Context *ctx = Context::get();
800 if (ctx->shader_builtin_srgb_transform != use_srgb_to_linear) {
801 ctx->shader_builtin_srgb_transform = use_srgb_to_linear;
803 }
804}
805
807
808/* -------------------------------------------------------------------- */
811
812Shader *ShaderCompiler::compile(const shader::ShaderCreateInfo &info, bool is_batch_compilation)
813{
814 using Clock = std::chrono::steady_clock;
815 using TimePoint = Clock::time_point;
816
817 using namespace blender::gpu::shader;
818 const_cast<ShaderCreateInfo &>(info).finalize();
819
820 TimePoint start_time;
821
822 if (Context::get()) {
823 /* Context can be null in Vulkan compilation threads. */
826 }
827 else if (G.profile_gpu) {
828 start_time = Clock::now();
829 }
830
831 const std::string error = info.check_error();
832 if (!error.empty()) {
833 std::cerr << error << "\n";
834 BLI_assert(false);
835 }
836
838 /* Needs to be called before init as GL uses the default specialization constants state to insert
839 * default shader inside a map. */
840 shader->specialization_constants_init(info);
841 shader->init(info, is_batch_compilation);
842
843 shader->fragment_output_bits = 0;
844 for (const shader::ShaderCreateInfo::FragOut &frag_out : info.fragment_outputs_) {
845 shader->fragment_output_bits |= 1u << frag_out.index;
846 }
847
848 std::string defines = shader->defines_declare(info);
849 std::string resources = shader->resources_declare(info);
850
851 defines += "#define USE_GPU_SHADER_CREATE_INFO\n";
852
853 Vector<StringRefNull> typedefs;
854 if (!info.typedef_sources_.is_empty() || !info.typedef_source_generated.empty()) {
855 typedefs.append(gpu_shader_dependency_get_source("GPU_shader_shared_utils.hh").c_str());
856 }
857 if (!info.typedef_source_generated.empty()) {
858 typedefs.append(info.typedef_source_generated);
859 }
860 for (auto filename : info.typedef_sources_) {
861 typedefs.append(gpu_shader_dependency_get_source(filename));
862 }
863
864 if (!info.vertex_source_.is_empty()) {
866 std::string interface = shader->vertex_interface_declare(info);
867
868 Vector<StringRefNull> sources;
869 standard_defines(sources);
870 sources.append("#define GPU_VERTEX_SHADER\n");
871 if (!info.geometry_source_.is_empty()) {
872 sources.append("#define USE_GEOMETRY_SHADER\n");
873 }
874 sources.append(defines);
875 sources.extend(typedefs);
876 sources.append(resources);
877 sources.append(interface);
878 sources.extend(code);
879 sources.extend(info.dependencies_generated);
880 sources.append(info.vertex_source_generated);
881
882 shader->vertex_shader_from_glsl(sources);
883 }
884
885 if (!info.fragment_source_.is_empty()) {
887 std::string interface = shader->fragment_interface_declare(info);
888
889 Vector<StringRefNull> sources;
890 standard_defines(sources);
891 sources.append("#define GPU_FRAGMENT_SHADER\n");
892 if (!info.geometry_source_.is_empty()) {
893 sources.append("#define USE_GEOMETRY_SHADER\n");
894 }
895 sources.append(defines);
896 sources.extend(typedefs);
897 sources.append(resources);
898 sources.append(interface);
899 sources.extend(code);
900 sources.extend(info.dependencies_generated);
901 sources.append(info.fragment_source_generated);
902
903 shader->fragment_shader_from_glsl(sources);
904 }
905
906 if (!info.geometry_source_.is_empty()) {
908 std::string layout = shader->geometry_layout_declare(info);
909 std::string interface = shader->geometry_interface_declare(info);
910
911 Vector<StringRefNull> sources;
912 standard_defines(sources);
913 sources.append("#define GPU_GEOMETRY_SHADER\n");
914 sources.append(defines);
915 sources.extend(typedefs);
916 sources.append(resources);
917 sources.append(layout);
918 sources.append(interface);
919 sources.append(info.geometry_source_generated);
920 sources.extend(code);
921
922 shader->geometry_shader_from_glsl(sources);
923 }
924
925 if (!info.compute_source_.is_empty()) {
927 std::string layout = shader->compute_layout_declare(info);
928
929 Vector<StringRefNull> sources;
930 standard_defines(sources);
931 sources.append("#define GPU_COMPUTE_SHADER\n");
932 sources.append(defines);
933 sources.extend(typedefs);
934 sources.append(resources);
935 sources.append(layout);
936 sources.extend(code);
937 sources.extend(info.dependencies_generated);
938 sources.append(info.compute_source_generated);
939
940 shader->compute_shader_from_glsl(sources);
941 }
942
943 if (!shader->finalize(&info)) {
944 delete shader;
945 shader = nullptr;
946 }
947
948 if (Context::get()) {
949 /* Context can be null in Vulkan compilation threads. */
952 }
953 else if (G.profile_gpu) {
954 TimePoint end_time = Clock::now();
955 /* Note: Used by the vulkan backend. Use the same time_since_epoch as process_frame_timings. */
957 start_time.time_since_epoch().count(),
958 end_time.time_since_epoch().count());
960 start_time.time_since_epoch().count(),
961 end_time.time_since_epoch().count());
962 }
963
964 return shader;
965}
966
967ShaderCompiler::ShaderCompiler(uint32_t threads_count,
968 GPUWorker::ContextType context_type,
969 bool support_specializations)
970{
971 support_specializations_ = support_specializations;
972
974 compilation_worker_ = std::make_unique<GPUWorker>(
975 threads_count,
976 context_type,
977 mutex_,
978 [this]() -> void * { return this->pop_work(); },
979 [this](void *work) { this->do_work(work); });
980 }
981}
982
984{
985 compilation_worker_.reset();
986
987 /* Ensure all the requested batches have been retrieved. */
988 BLI_assert(batches_.is_empty());
989}
990
992{
993 return compile(info, false);
994}
995
997 CompilationPriority priority)
998{
999 std::unique_lock lock(mutex_);
1000
1001 Batch *batch = MEM_new<Batch>(__func__);
1002 batch->infos = infos;
1003 batch->shaders.reserve(infos.size());
1004
1005 BatchHandle handle = next_batch_handle_++;
1006 batches_.add(handle, batch);
1007
1008 if (compilation_worker_) {
1009 batch->shaders.resize(infos.size(), nullptr);
1010 batch->pending_compilations = infos.size();
1011 for (int i : infos.index_range()) {
1012 compilation_queue_.push({batch, i}, priority);
1013 compilation_worker_->wake_up();
1014 }
1015 }
1016 else {
1017 for (const shader::ShaderCreateInfo *info : infos) {
1018 batch->shaders.append(compile(*info, false));
1019 }
1020 }
1021
1022 return handle;
1023}
1024
1026{
1027 std::unique_lock lock(mutex_);
1028
1029 Batch *batch = batches_.pop(handle);
1030 compilation_queue_.remove_batch(batch);
1031
1032 if (batch->is_specialization_batch()) {
1033 /* For specialization batches, we block until ready, since base shader compilation may be
1034 * cancelled afterwards, leaving the specialization with a deleted base shader. */
1035 compilation_finished_notification_.wait(lock, [&]() { return batch->is_ready(); });
1036 }
1037
1038 if (batch->is_ready()) {
1039 batch->free_shaders();
1040 MEM_delete(batch);
1041 }
1042 else {
1043 /* If it's currently compiling, the compilation thread makes the cleanup. */
1044 batch->is_cancelled = true;
1045 }
1046
1047 handle = 0;
1048}
1049
1051{
1052 std::lock_guard lock(mutex_);
1053
1054 return batches_.lookup(handle)->is_ready();
1055}
1056
1058{
1059 std::unique_lock lock(mutex_);
1060 /* TODO: Move to be first on the queue. */
1061 compilation_finished_notification_.wait(lock,
1062 [&]() { return batches_.lookup(handle)->is_ready(); });
1063
1064 Batch *batch = batches_.pop(handle);
1065 Vector<Shader *> shaders = std::move(batch->shaders);
1066 MEM_delete(batch);
1067 handle = 0;
1068
1069 return shaders;
1070}
1071
1073 Span<ShaderSpecialization> specializations, CompilationPriority priority)
1074{
1075 if (!compilation_worker_ || !support_specializations_) {
1076 return 0;
1077 }
1078
1079 std::lock_guard lock(mutex_);
1080
1081 Batch *batch = MEM_new<Batch>(__func__);
1082 batch->specializations = specializations;
1083
1084 BatchHandle handle = next_batch_handle_++;
1085 batches_.add(handle, batch);
1086
1087 batch->pending_compilations = specializations.size();
1088 for (int i : specializations.index_range()) {
1089 compilation_queue_.push({batch, i}, priority);
1090 compilation_worker_->wake_up();
1091 }
1092
1093 return handle;
1094}
1095
1097{
1098 if (handle != 0 && batch_is_ready(handle)) {
1099 std::lock_guard lock(mutex_);
1100
1101 Batch *batch = batches_.pop(handle);
1102 MEM_delete(batch);
1103 handle = 0;
1104 }
1105
1106 return handle == 0;
1107}
1108
1109void *ShaderCompiler::pop_work()
1110{
1111 /* NOTE: Already under mutex lock when GPUWorker calls this function. */
1112
1113 if (compilation_queue_.is_empty()) {
1114 return nullptr;
1115 }
1116
1117 ParallelWork work = compilation_queue_.pop();
1118 return MEM_new<ParallelWork>(__func__, work);
1119}
1120
1121void ShaderCompiler::do_work(void *work_payload)
1122{
1123 ParallelWork *work = reinterpret_cast<ParallelWork *>(work_payload);
1124 Batch *batch = work->batch;
1125 int shader_index = work->shader_index;
1126 MEM_delete(work);
1127
1128 /* Compile */
1129 if (!batch->is_specialization_batch()) {
1130 batch->shaders[shader_index] = compile_shader(*batch->infos[shader_index]);
1131 }
1132 else {
1133 specialize_shader(batch->specializations[shader_index]);
1134 }
1135
1136 {
1137 std::lock_guard lock(mutex_);
1138 batch->pending_compilations--;
1139 if (batch->is_ready() && batch->is_cancelled) {
1140 batch->free_shaders();
1141 MEM_delete(batch);
1142 }
1143 }
1144
1145 compilation_finished_notification_.notify_all();
1146}
1147
1148bool ShaderCompiler::is_compiling_impl()
1149{
1150 /* The mutex should be locked befor calling this function. */
1151 BLI_assert(!mutex_.try_lock());
1152
1153 if (!compilation_queue_.is_empty()) {
1154 return true;
1155 }
1156
1157 for (Batch *batch : batches_.values()) {
1158 if (!batch->is_ready()) {
1159 return true;
1160 }
1161 }
1162
1163 return false;
1164}
1165
1167{
1168 std::unique_lock lock(mutex_);
1169 return is_compiling_impl();
1170}
1171
1173{
1174 std::unique_lock lock(mutex_);
1175 compilation_finished_notification_.wait(lock, [&]() { return !is_compiling_impl(); });
1176}
1177
1179
1180} // 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)
bool GPU_shader_batch_is_compiling()
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 @242053044010324116347033273112253060004051364061::@051143074301336237271216303350234260141112266062 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