Blender V4.3
vk_shader.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <sstream>
10
11#include "GPU_capabilities.hh"
12
13#include "vk_shader.hh"
14
15#include "vk_backend.hh"
16#include "vk_framebuffer.hh"
17#include "vk_memory.hh"
19#include "vk_shader_log.hh"
20#include "vk_state_manager.hh"
22
23#include "BLI_string_utils.hh"
24#include "BLI_vector.hh"
25
26#include "BKE_global.hh"
27
28using namespace blender::gpu::shader;
29
30namespace blender::gpu {
31
32/* -------------------------------------------------------------------- */
35
36static const char *to_string(const Interpolation &interp)
37{
38 switch (interp) {
39 case Interpolation::SMOOTH:
40 return "smooth";
41 case Interpolation::FLAT:
42 return "flat";
43 case Interpolation::NO_PERSPECTIVE:
44 return "noperspective";
45 default:
46 return "unknown";
47 }
48}
49
50static const char *to_string(const Type &type)
51{
52 switch (type) {
53 case Type::FLOAT:
54 return "float";
55 case Type::VEC2:
56 return "vec2";
57 case Type::VEC3:
58 return "vec3";
59 case Type::VEC4:
60 return "vec4";
61 case Type::MAT3:
62 return "mat3";
63 case Type::MAT4:
64 return "mat4";
65 case Type::UINT:
66 return "uint";
67 case Type::UVEC2:
68 return "uvec2";
69 case Type::UVEC3:
70 return "uvec3";
71 case Type::UVEC4:
72 return "uvec4";
73 case Type::INT:
74 return "int";
75 case Type::IVEC2:
76 return "ivec2";
77 case Type::IVEC3:
78 return "ivec3";
79 case Type::IVEC4:
80 return "ivec4";
81 case Type::BOOL:
82 return "bool";
83 default:
84 return "unknown";
85 }
86}
87
88static const char *to_string(const eGPUTextureFormat &type)
89{
90 switch (type) {
91 case GPU_RGBA8UI:
92 return "rgba8ui";
93 case GPU_RGBA8I:
94 return "rgba8i";
95 case GPU_RGBA8:
96 return "rgba8";
97 case GPU_RGBA32UI:
98 return "rgba32ui";
99 case GPU_RGBA32I:
100 return "rgba32i";
101 case GPU_RGBA32F:
102 return "rgba32f";
103 case GPU_RGBA16UI:
104 return "rgba16ui";
105 case GPU_RGBA16I:
106 return "rgba16i";
107 case GPU_RGBA16F:
108 return "rgba16f";
109 case GPU_RGBA16:
110 return "rgba16";
111 case GPU_RG8UI:
112 return "rg8ui";
113 case GPU_RG8I:
114 return "rg8i";
115 case GPU_RG8:
116 return "rg8";
117 case GPU_RG32UI:
118 return "rg32ui";
119 case GPU_RG32I:
120 return "rg32i";
121 case GPU_RG32F:
122 return "rg32f";
123 case GPU_RG16UI:
124 return "rg16ui";
125 case GPU_RG16I:
126 return "rg16i";
127 case GPU_RG16F:
128 return "rg16f";
129 case GPU_RG16:
130 return "rg16";
131 case GPU_R8UI:
132 return "r8ui";
133 case GPU_R8I:
134 return "r8i";
135 case GPU_R8:
136 return "r8";
137 case GPU_R32UI:
138 return "r32ui";
139 case GPU_R32I:
140 return "r32i";
141 case GPU_R32F:
142 return "r32f";
143 case GPU_R16UI:
144 return "r16ui";
145 case GPU_R16I:
146 return "r16i";
147 case GPU_R16F:
148 return "r16f";
149 case GPU_R16:
150 return "r16";
152 return "r11f_g11f_b10f";
153 case GPU_RGB10_A2:
154 return "rgb10_a2";
155 default:
156 return "unknown";
157 }
158}
159
160static const char *to_string(const PrimitiveIn &layout)
161{
162 switch (layout) {
164 return "points";
166 return "lines";
168 return "lines_adjacency";
170 return "triangles";
172 return "triangles_adjacency";
173 default:
174 return "unknown";
175 }
176}
177
178static const char *to_string(const PrimitiveOut &layout)
179{
180 switch (layout) {
181 case PrimitiveOut::POINTS:
182 return "points";
183 case PrimitiveOut::LINE_STRIP:
184 return "line_strip";
185 case PrimitiveOut::TRIANGLE_STRIP:
186 return "triangle_strip";
187 default:
188 return "unknown";
189 }
190}
191
192static const char *to_string(const DepthWrite &value)
193{
194 switch (value) {
195 case DepthWrite::ANY:
196 return "depth_any";
198 return "depth_greater";
199 case DepthWrite::LESS:
200 return "depth_less";
201 default:
202 return "depth_unchanged";
203 }
204}
205
206static void print_image_type(std::ostream &os,
207 const ImageType &type,
209{
210 switch (type) {
222 os << "i";
223 break;
235 os << "u";
236 break;
237 default:
238 break;
239 }
240
242 os << "image";
243 }
244 else {
245 os << "sampler";
246 }
247
248 switch (type) {
252 os << "Buffer";
253 break;
260 os << "1D";
261 break;
276 os << "2D";
277 break;
283 os << "3D";
284 break;
295 os << "Cube";
296 break;
297 default:
298 break;
299 }
300
301 switch (type) {
316 os << "Array";
317 break;
318 default:
319 break;
320 }
321
322 switch (type) {
327 os << "Shadow";
328 break;
329 default:
330 break;
331 }
332 os << " ";
333}
334
335static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers)
336{
337 if (bool(qualifiers & Qualifier::NO_RESTRICT) == false) {
338 os << "restrict ";
339 }
340 if (bool(qualifiers & Qualifier::READ) == false) {
341 os << "writeonly ";
342 }
343 if (bool(qualifiers & Qualifier::WRITE) == false) {
344 os << "readonly ";
345 }
346 return os;
347}
348
349static void print_resource(std::ostream &os,
350 const VKDescriptorSet::Location location,
352{
353 os << "layout(binding = " << uint32_t(location);
355 os << ", " << to_string(res.image.format);
356 }
358 os << ", std140";
359 }
361 os << ", std430";
362 }
363 os << ") ";
364
365 int64_t array_offset;
366 StringRef name_no_array;
367
368 switch (res.bind_type) {
370 os << "uniform ";
372 os << res.sampler.name << ";\n";
373 break;
375 os << "uniform ";
377 print_image_type(os, res.image.type, res.bind_type);
378 os << res.image.name << ";\n";
379 break;
381 array_offset = res.uniformbuf.name.find_first_of("[");
382 name_no_array = (array_offset == -1) ? res.uniformbuf.name :
383 StringRef(res.uniformbuf.name.c_str(), array_offset);
384 os << "uniform _" << name_no_array << " { " << res.uniformbuf.type_name << " "
385 << res.uniformbuf.name << "; };\n";
386 break;
388 array_offset = res.storagebuf.name.find_first_of("[");
389 name_no_array = (array_offset == -1) ? res.storagebuf.name :
390 StringRef(res.storagebuf.name.c_str(), array_offset);
391 print_qualifier(os, res.storagebuf.qualifiers);
392 os << "buffer _";
393 os << name_no_array << " { " << res.storagebuf.type_name << " " << res.storagebuf.name
394 << "; };\n";
395 break;
396 }
397}
398
399static void print_resource(std::ostream &os,
400 const VKShaderInterface &shader_interface,
402{
403 const VKDescriptorSet::Location location = shader_interface.descriptor_set_location(res);
404 print_resource(os, location, res);
405}
406
407inline int get_location_count(const Type &type)
408{
409 if (type == shader::Type::MAT4) {
410 return 4;
411 }
412 else if (type == shader::Type::MAT3) {
413 return 3;
414 }
415 return 1;
416}
417
418static void print_interface_as_attributes(std::ostream &os,
419 const std::string &prefix,
420 const StageInterfaceInfo &iface,
421 int &location)
422{
423 for (const StageInterfaceInfo::InOut &inout : iface.inouts) {
424 os << "layout(location=" << location << ") " << prefix << " " << to_string(inout.interp) << " "
425 << to_string(inout.type) << " " << inout.name << ";\n";
426 location += get_location_count(inout.type);
427 }
428}
429
430static void print_interface_as_struct(std::ostream &os,
431 const std::string &prefix,
432 const StageInterfaceInfo &iface,
433 int &location,
434 const StringRefNull &suffix)
435{
436 std::string struct_name = prefix + iface.name;
437 Interpolation qualifier = iface.inouts[0].interp;
438
439 os << "struct " << struct_name << " {\n";
440 for (const StageInterfaceInfo::InOut &inout : iface.inouts) {
441 os << " " << to_string(inout.type) << " " << inout.name << ";\n";
442 }
443 os << "};\n";
444 os << "layout(location=" << location << ") " << prefix << " " << to_string(qualifier) << " "
445 << struct_name << " " << iface.instance_name << suffix << ";\n";
446
447 for (const StageInterfaceInfo::InOut &inout : iface.inouts) {
448 location += get_location_count(inout.type);
449 }
450}
451
452static void print_interface(std::ostream &os,
453 const std::string &prefix,
454 const StageInterfaceInfo &iface,
455 int &location,
456 const StringRefNull &suffix = "")
457{
458 if (iface.instance_name.is_empty()) {
459 print_interface_as_attributes(os, prefix, iface, location);
460 }
461 else {
462 print_interface_as_struct(os, prefix, iface, location, suffix);
463 }
464}
465
467static std::string main_function_wrapper(std::string &pre_main, std::string &post_main)
468{
469 std::stringstream ss;
470 /* Prototype for the original main. */
471 ss << "\n";
472 ss << "void main_function_();\n";
473 /* Wrapper to the main function in order to inject code processing on globals. */
474 ss << "void main() {\n";
475 ss << pre_main;
476 ss << " main_function_();\n";
477 ss << post_main;
478 ss << "}\n";
479 /* Rename the original main. */
480 ss << "#define main main_function_\n";
481 ss << "\n";
482 return ss.str();
483}
484
485static std::string combine_sources(Span<const char *> sources)
486{
487 char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
488 std::string result(sources_combined);
489 MEM_freeN(sources_combined);
490 return result;
491}
492
494{
495 context_ = VKContext::get();
496}
497
498void VKShader::init(const shader::ShaderCreateInfo &info, bool is_batch_compilation)
499{
500 VKShaderInterface *vk_interface = new VKShaderInterface();
501 vk_interface->init(info);
502 interface = vk_interface;
503 is_static_shader_ = info.do_static_compilation_;
504 is_compute_shader_ = !info.compute_source_.is_empty() || !info.compute_source_generated.empty();
505 use_batch_compilation_ = is_batch_compilation;
506}
507
509{
510 VKDevice &device = VKBackend::get().device;
511 VKDiscardPool &discard_pool = device.discard_pool_for_current_thread();
512
513 if (vk_pipeline_layout != VK_NULL_HANDLE) {
515 vk_pipeline_layout = VK_NULL_HANDLE;
516 }
517 /* Unset not owning handles. */
518 vk_descriptor_set_layout_ = VK_NULL_HANDLE;
519}
520
521void VKShader::build_shader_module(MutableSpan<const char *> sources,
522 shaderc_shader_kind stage,
523 VKShaderModule &r_shader_module)
524{
525 BLI_assert_msg(ELEM(stage,
526 shaderc_vertex_shader,
527 shaderc_geometry_shader,
528 shaderc_fragment_shader,
529 shaderc_compute_shader),
530 "Only forced ShaderC shader kinds are supported.");
531 r_shader_module.is_ready = false;
532 const VKDevice &device = VKBackend::get().device;
533 sources[SOURCES_INDEX_VERSION] = device.glsl_patch_get();
534 r_shader_module.combined_sources = combine_sources(sources);
535 if (!use_batch_compilation_) {
536 VKShaderCompiler::compile_module(*this, stage, r_shader_module);
537 r_shader_module.is_ready = true;
538 }
539}
540
542{
543 build_shader_module(sources, shaderc_vertex_shader, vertex_module);
544}
545
547{
548 build_shader_module(sources, shaderc_geometry_shader, geometry_module);
549}
550
552{
553 build_shader_module(sources, shaderc_fragment_shader, fragment_module);
554}
555
557{
558 build_shader_module(sources, shaderc_compute_shader, compute_module);
559}
560
561void VKShader::warm_cache(int /*limit*/)
562{
564}
565
567{
568 if (!use_batch_compilation_) {
570 }
571 if (compilation_failed) {
572 return false;
573 }
574 /* Add-ons that still use old API will crash as the shader create info isn't available.
575 * See #130555 */
576 if (info == nullptr) {
577 return false;
578 }
579
580 if (do_geometry_shader_injection(info)) {
581 std::string source = workaround_geometry_shader_source_create(*info);
582 Vector<const char *> sources;
583 sources.append("version");
584 sources.append(source.c_str());
586 }
587
588 const VKShaderInterface &vk_interface = interface_get();
589 VKDevice &device = VKBackend::get().device;
590 if (!finalize_descriptor_set_layouts(device, vk_interface)) {
591 return false;
592 }
593 if (!finalize_pipeline_layout(device.vk_handle(), vk_interface)) {
594 return false;
595 }
596
598 if (use_batch_compilation_) {
599 return true;
600 }
601 return finalize_post();
602}
603
605{
606 bool result = finalize_shader_module(vertex_module, "vertex") &&
607 finalize_shader_module(geometry_module, "geometry") &&
608 finalize_shader_module(fragment_module, "fragment") &&
609 finalize_shader_module(compute_module, "compute");
610
611 /* Ensure that pipeline of compute shaders are already build. This can improve performance as it
612 * can triggers a back-end compilation step. In this step the Shader module SPIR-V is
613 * compiled to a shader program that can be executed by the device. Depending on the driver this
614 * can take some time as well. If this is done inside the main thread it will stall user
615 * interactivity.
616 *
617 * TODO: We should check if VK_EXT_graphics_pipeline_library can improve the pipeline creation
618 * step for graphical shaders.
619 */
620 if (result && is_compute_shader_) {
622 }
623 return result;
624}
625
626bool VKShader::finalize_shader_module(VKShaderModule &shader_module, const char *stage_name)
627{
628 VKLogParser parser;
629 bool compilation_succeeded = ELEM(shader_module.compilation_result.GetCompilationStatus(),
630 shaderc_compilation_status_null_result_object,
631 shaderc_compilation_status_success);
632 if (bool(shader_module.compilation_result.GetNumWarnings() +
633 shader_module.compilation_result.GetNumErrors()))
634 {
635 const char *sources = shader_module.combined_sources.c_str();
636 print_log(Span<const char *>(&sources, 1),
637 shader_module.compilation_result.GetErrorMessage().c_str(),
638 stage_name,
639 bool(shader_module.compilation_result.GetNumErrors()),
640 &parser);
641 }
642
643 std::string full_name = std::string(name) + "_" + stage_name;
644 shader_module.finalize(full_name.c_str());
645 shader_module.combined_sources.clear();
646 shader_module.sources_hash.clear();
647 shader_module.compilation_result = {};
648 shader_module.spirv_binary.clear();
649 return compilation_succeeded;
650}
651
653{
655}
656
657bool VKShader::finalize_pipeline_layout(VkDevice vk_device,
658 const VKShaderInterface &shader_interface)
659{
661
662 const uint32_t layout_count = vk_descriptor_set_layout_ == VK_NULL_HANDLE ? 0 : 1;
663 VkPipelineLayoutCreateInfo pipeline_info = {};
664 VkPushConstantRange push_constant_range = {};
665 pipeline_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
666 pipeline_info.flags = 0;
667 pipeline_info.setLayoutCount = layout_count;
668 pipeline_info.pSetLayouts = &vk_descriptor_set_layout_;
669
670 /* Setup push constants. */
671 const VKPushConstants::Layout &push_constants_layout =
672 shader_interface.push_constants_layout_get();
673 if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::PUSH_CONSTANTS) {
674 push_constant_range.offset = 0;
675 push_constant_range.size = push_constants_layout.size_in_bytes();
676 push_constant_range.stageFlags = is_compute_shader_ ? VK_SHADER_STAGE_COMPUTE_BIT :
677 VK_SHADER_STAGE_ALL_GRAPHICS;
678 pipeline_info.pushConstantRangeCount = 1;
679 pipeline_info.pPushConstantRanges = &push_constant_range;
680 }
681
682 if (vkCreatePipelineLayout(
683 vk_device, &pipeline_info, vk_allocation_callbacks, &vk_pipeline_layout) != VK_SUCCESS)
684 {
685 return false;
686 };
687
688 return true;
689}
690
691bool VKShader::finalize_descriptor_set_layouts(VKDevice &vk_device,
692 const VKShaderInterface &shader_interface)
693{
694 bool created;
695 bool needed;
696
697 vk_descriptor_set_layout_ = vk_device.descriptor_set_layouts_get().get_or_create(
698 shader_interface.descriptor_set_layout_info_get(), created, needed);
699 if (created) {
700 debug::object_label(vk_descriptor_set_layout_, name_get());
701 }
702 if (!needed) {
703 BLI_assert(vk_descriptor_set_layout_ == VK_NULL_HANDLE);
704 return true;
705 }
706 return vk_descriptor_set_layout_ != VK_NULL_HANDLE;
707}
708
709/* -------------------------------------------------------------------- */
715
721
723{
724 return false;
725}
726
731
733
735{
736 /* Intentionally empty. Binding of the pipeline are done just before drawing/dispatching.
737 * See #VKPipeline.update_and_bind */
738}
739
741
742void VKShader::uniform_float(int location, int comp_len, int array_size, const float *data)
743{
744 push_constants.push_constant_set(location, comp_len, array_size, data);
745}
746
747void VKShader::uniform_int(int location, int comp_len, int array_size, const int *data)
748{
749 push_constants.push_constant_set(location, comp_len, array_size, data);
750}
751
753{
754 const VKShaderInterface &vk_interface = interface_get();
755 std::stringstream ss;
756
757 ss << "\n/* Specialization Constants (pass-through). */\n";
758 uint constant_id = 0;
760 ss << "layout (constant_id=" << constant_id++ << ") const ";
761 switch (sc.type) {
762 case Type::INT:
763 ss << "int " << sc.name << "=" << std::to_string(sc.value.i) << ";\n";
764 break;
765 case Type::UINT:
766 ss << "uint " << sc.name << "=" << std::to_string(sc.value.u) << "u;\n";
767 break;
768 case Type::BOOL:
769 ss << "bool " << sc.name << "=" << (sc.value.u ? "true" : "false") << ";\n";
770 break;
771 case Type::FLOAT:
772 /* Use uint representation to allow exact same bit pattern even if NaN. uintBitsToFloat
773 * isn't supported during global const initialization. */
774 ss << "uint " << sc.name << "_uint=" << std::to_string(sc.value.u) << "u;\n";
775 ss << "#define " << sc.name << " uintBitsToFloat(" << sc.name << "_uint)\n";
776 break;
777 default:
779 break;
780 }
781 }
782
783 ss << "\n/* Pass Resources. */\n";
784 for (const ShaderCreateInfo::Resource &res : info.pass_resources_) {
785 print_resource(ss, vk_interface, res);
786 }
787
788 ss << "\n/* Batch Resources. */\n";
789 for (const ShaderCreateInfo::Resource &res : info.batch_resources_) {
790 print_resource(ss, vk_interface, res);
791 }
792
793 ss << "\n/* Geometry Resources. */\n";
794 for (const ShaderCreateInfo::Resource &res : info.geometry_resources_) {
795 print_resource(ss, vk_interface, res);
796 }
797
798 /* Push constants. */
799 const VKPushConstants::Layout &push_constants_layout = vk_interface.push_constants_layout_get();
800 const VKPushConstants::StorageType push_constants_storage =
801 push_constants_layout.storage_type_get();
802 if (push_constants_storage != VKPushConstants::StorageType::NONE) {
803 ss << "\n/* Push Constants. */\n";
804 if (push_constants_storage == VKPushConstants::StorageType::PUSH_CONSTANTS) {
805 ss << "layout(push_constant, std430) uniform constants\n";
806 }
807 else if (push_constants_storage == VKPushConstants::StorageType::UNIFORM_BUFFER) {
808 ss << "layout(binding = " << push_constants_layout.descriptor_set_location_get()
809 << ", std140) uniform constants\n";
810 }
811 ss << "{\n";
812 for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
813 ss << " " << to_string(uniform.type) << " pc_" << uniform.name;
814 if (uniform.array_size > 0) {
815 ss << "[" << uniform.array_size << "]";
816 }
817 ss << ";\n";
818 }
819 ss << "} PushConstants;\n";
820 for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) {
821 ss << "#define " << uniform.name << " (PushConstants.pc_" << uniform.name << ")\n";
822 }
823 }
824
825 ss << "\n";
826 return ss.str();
827}
828
830{
831 std::stringstream ss;
832 std::string post_main;
833 const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
834
835 ss << "\n/* Inputs. */\n";
836 for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
837 ss << "layout(location = " << attr.index << ") ";
838 ss << "in " << to_string(attr.type) << " " << attr.name << ";\n";
839 }
840 ss << "\n/* Interfaces. */\n";
841 int location = 0;
842 for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
843 print_interface(ss, "out", *iface, location);
844 }
845 if (workarounds.shader_output_layer && bool(info.builtins_ & BuiltinBits::LAYER)) {
846 ss << "layout(location=" << (location++) << ") out int gpu_Layer;\n ";
847 }
848 if (workarounds.shader_output_viewport_index &&
850 {
851 ss << "layout(location=" << (location++) << ") out int gpu_ViewportIndex;\n";
852 }
853 ss << "\n";
854
855 /* Retarget depth from -1..1 to 0..1. This will be done by geometry stage, when geometry shaders
856 * are used. */
857 const bool has_geometry_stage = do_geometry_shader_injection(&info) ||
859 const bool retarget_depth = !has_geometry_stage;
860 if (retarget_depth) {
861 post_main += "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n";
862 }
863
864 if (post_main.empty() == false) {
865 std::string pre_main;
866 ss << main_function_wrapper(pre_main, post_main);
867 }
868 return ss.str();
869}
870
871static Type to_component_type(const Type &type)
872{
873 switch (type) {
874 case Type::FLOAT:
875 case Type::VEC2:
876 case Type::VEC3:
877 case Type::VEC4:
878 case Type::MAT3:
879 case Type::MAT4:
880 return Type::FLOAT;
881 case Type::UINT:
882 case Type::UVEC2:
883 case Type::UVEC3:
884 case Type::UVEC4:
885 return Type::UINT;
886 case Type::INT:
887 case Type::IVEC2:
888 case Type::IVEC3:
889 case Type::IVEC4:
890 case Type::BOOL:
891 return Type::INT;
892 /* Alias special types. */
893 case Type::UCHAR:
894 case Type::UCHAR2:
895 case Type::UCHAR3:
896 case Type::UCHAR4:
897 case Type::USHORT:
898 case Type::USHORT2:
899 case Type::USHORT3:
900 case Type::USHORT4:
901 return Type::UINT;
902 case Type::CHAR:
903 case Type::CHAR2:
904 case Type::CHAR3:
905 case Type::CHAR4:
906 case Type::SHORT:
907 case Type::SHORT2:
908 case Type::SHORT3:
909 case Type::SHORT4:
910 return Type::INT;
912 return Type::FLOAT;
913 }
915 return Type::FLOAT;
916}
917
919{
920 std::stringstream ss;
921 std::string pre_main;
922 const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
923
924 ss << "\n/* Interfaces. */\n";
925 const Span<StageInterfaceInfo *> in_interfaces = info.geometry_source_.is_empty() ?
928 int location = 0;
929 for (const StageInterfaceInfo *iface : in_interfaces) {
930 print_interface(ss, "in", *iface, location);
931 }
932 if (workarounds.shader_output_layer && bool(info.builtins_ & BuiltinBits::LAYER)) {
933 ss << "#define gpu_Layer gl_Layer\n";
934 }
935 if (workarounds.shader_output_viewport_index &&
937 {
938 ss << "#define gpu_ViewportIndex gl_ViewportIndex\n";
939 }
940
941 if (workarounds.fragment_shader_barycentric &&
943 {
944 ss << "layout(location=" << (location++) << ") smooth in vec3 gpu_BaryCoord;\n";
945 ss << "layout(location=" << (location++) << ") noperspective in vec3 gpu_BaryCoordNoPersp;\n";
946 }
947
948 if (info.early_fragment_test_) {
949 ss << "layout(early_fragment_tests) in;\n";
950 }
951 const bool use_gl_frag_depth = info.depth_write_ != DepthWrite::UNCHANGED &&
952 info.fragment_source_.find("gl_FragDepth") != std::string::npos;
953 if (use_gl_frag_depth) {
954 ss << "layout(" << to_string(info.depth_write_) << ") out float gl_FragDepth;\n";
955 }
956
957 ss << "\n/* Sub-pass Inputs. */\n";
958 for (const ShaderCreateInfo::SubpassIn &input : info.subpass_inputs_) {
959 std::string image_name = "gpu_subpass_img_";
960 image_name += std::to_string(input.index);
961
962 /* Declare global for input. */
963 ss << to_string(input.type) << " " << input.name << ";\n";
964
965 /* IMPORTANT: We assume that the frame-buffer will be layered or not based on the layer
966 * built-in flag. */
967 bool is_layered_fb = bool(info.builtins_ & BuiltinBits::LAYER);
968
969 /* Start with invalid value to detect failure cases. */
971 switch (to_component_type(input.type)) {
972 case Type::FLOAT:
973 image_type = is_layered_fb ? ImageType::FLOAT_2D_ARRAY : ImageType::FLOAT_2D;
974 break;
975 case Type::INT:
976 image_type = is_layered_fb ? ImageType::INT_2D_ARRAY : ImageType::INT_2D;
977 break;
978 case Type::UINT:
979 image_type = is_layered_fb ? ImageType::UINT_2D_ARRAY : ImageType::UINT_2D;
980 break;
981 default:
982 break;
983 }
984 /* Declare image. */
985 using Resource = ShaderCreateInfo::Resource;
986 /* NOTE(fclem): Using the attachment index as resource index might be problematic as it might
987 * collide with other resources. */
988 Resource res(Resource::BindType::SAMPLER, input.index);
989 res.sampler.type = image_type;
990 res.sampler.sampler = GPUSamplerState::default_sampler();
991 res.sampler.name = image_name;
992 print_resource(ss, interface_get(), res);
993
994 char swizzle[] = "xyzw";
995 swizzle[to_component_count(input.type)] = '\0';
996
997 std::string texel_co = (is_layered_fb) ? "ivec3(gl_FragCoord.xy, gpu_Layer)" :
998 "ivec2(gl_FragCoord.xy)";
999
1000 std::stringstream ss_pre;
1001 /* Populate the global before main using imageLoad. */
1002 ss_pre << " " << input.name << " = texelFetch(" << image_name << ", " << texel_co << ", 0)."
1003 << swizzle << ";\n";
1004
1005 pre_main += ss_pre.str();
1006 }
1007
1008 ss << "\n/* Outputs. */\n";
1010 ss << "layout(location = " << output.index;
1011 switch (output.blend) {
1012 case DualBlend::SRC_0:
1013 ss << ", index = 0";
1014 break;
1015 case DualBlend::SRC_1:
1016 ss << ", index = 1";
1017 break;
1018 default:
1019 break;
1020 }
1021 ss << ") ";
1022 ss << "out " << to_string(output.type) << " " << output.name << ";\n";
1023 }
1024 ss << "\n";
1025
1026 if (pre_main.empty() == false) {
1027 std::string post_main;
1028 ss << main_function_wrapper(pre_main, post_main);
1029 }
1030 return ss.str();
1031}
1032
1034{
1035 int max_verts = info.geometry_layout_.max_vertices;
1036 int invocations = info.geometry_layout_.invocations;
1037
1038 std::stringstream ss;
1039 ss << "\n/* Geometry Layout. */\n";
1040 ss << "layout(" << to_string(info.geometry_layout_.primitive_in);
1041 if (invocations != -1) {
1042 ss << ", invocations = " << invocations;
1043 }
1044 ss << ") in;\n";
1045
1046 ss << "layout(" << to_string(info.geometry_layout_.primitive_out)
1047 << ", max_vertices = " << max_verts << ") out;\n";
1048 ss << "\n";
1049 return ss.str();
1050}
1051
1053 const StringRefNull name)
1054{
1055 for (StageInterfaceInfo *iface : ifaces) {
1056 if (iface->instance_name == name) {
1057 return iface;
1058 }
1059 }
1060 return nullptr;
1061}
1062
1063static void declare_emit_vertex(std::stringstream &ss)
1064{
1065 ss << "void gpu_EmitVertex() {\n";
1066 ss << " gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n";
1067 ss << " EmitVertex();\n";
1068 ss << "}\n";
1069}
1070
1072{
1073 std::stringstream ss;
1074
1075 ss << "\n/* Interfaces. */\n";
1076 int location = 0;
1077 for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
1078 bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_,
1079 iface->instance_name) != nullptr;
1080 const char *suffix = (has_matching_output_iface) ? "_in[]" : "[]";
1081 print_interface(ss, "in", *iface, location, suffix);
1082 }
1083 ss << "\n";
1084
1085 location = 0;
1086 for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) {
1087 bool has_matching_input_iface = find_interface_by_name(info.vertex_out_interfaces_,
1088 iface->instance_name) != nullptr;
1089 const char *suffix = (has_matching_input_iface) ? "_out" : "";
1090 print_interface(ss, "out", *iface, location, suffix);
1091 }
1092 ss << "\n";
1093
1095
1096 return ss.str();
1097}
1098
1100{
1101 std::stringstream ss;
1102 ss << "\n/* Compute Layout. */\n";
1103 ss << "layout(local_size_x = " << info.compute_layout_.local_size_x;
1104 if (info.compute_layout_.local_size_y != -1) {
1105 ss << ", local_size_y = " << info.compute_layout_.local_size_y;
1106 }
1107 if (info.compute_layout_.local_size_z != -1) {
1108 ss << ", local_size_z = " << info.compute_layout_.local_size_z;
1109 }
1110 ss << ") in;\n";
1111 ss << "\n";
1112 return ss.str();
1113}
1114
1115/* -------------------------------------------------------------------- */
1119
1120std::string VKShader::workaround_geometry_shader_source_create(
1121 const shader::ShaderCreateInfo &info)
1122{
1123 std::stringstream ss;
1124 const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
1125
1126 const bool do_layer_workaround = workarounds.shader_output_layer &&
1127 bool(info.builtins_ & BuiltinBits::LAYER);
1128 const bool do_viewport_workaround = workarounds.shader_output_viewport_index &&
1130 const bool do_barycentric_workaround = workarounds.fragment_shader_barycentric &&
1132
1133 shader::ShaderCreateInfo info_modified = info;
1134 info_modified.geometry_out_interfaces_ = info_modified.vertex_out_interfaces_;
1140
1141 ss << geometry_layout_declare(info_modified);
1142 ss << geometry_interface_declare(info_modified);
1143 int location = 0;
1144 for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) {
1145 for (const StageInterfaceInfo::InOut &inout : iface->inouts) {
1146 location += get_location_count(inout.type);
1147 }
1148 }
1149
1150 int location_in = location;
1151 int location_out = location;
1152 if (do_layer_workaround) {
1153 ss << "layout(location=" << (location_in++) << ") in int gpu_Layer[];\n";
1154 }
1155 if (do_viewport_workaround) {
1156 ss << "layout(location=" << (location_in++) << ") in int gpu_ViewportIndex[];\n";
1157 }
1158 if (do_barycentric_workaround) {
1159 ss << "layout(location=" << (location_out++) << ") smooth out vec3 gpu_BaryCoord;\n";
1160 ss << "layout(location=" << (location_out++)
1161 << ") noperspective out vec3 gpu_BaryCoordNoPersp;\n";
1162 }
1163 ss << "\n";
1164
1165 ss << "void main()\n";
1166 ss << "{\n";
1167 if (do_layer_workaround) {
1168 ss << " gl_Layer = gpu_Layer[0];\n";
1169 }
1170 if (do_viewport_workaround) {
1171 ss << " gl_ViewportIndex = gpu_ViewportIndex[0];\n";
1172 }
1173 for (auto i : IndexRange(3)) {
1174 for (StageInterfaceInfo *iface : info_modified.vertex_out_interfaces_) {
1175 for (auto &inout : iface->inouts) {
1176 ss << " " << iface->instance_name << "_out." << inout.name;
1177 ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n";
1178 }
1179 }
1180 if (do_barycentric_workaround) {
1181 ss << " gpu_BaryCoordNoPersp = gpu_BaryCoord =";
1182 ss << " vec3(" << int(i == 0) << ", " << int(i == 1) << ", " << int(i == 2) << ");\n";
1183 }
1184 ss << " gl_Position = gl_in[" << i << "].gl_Position;\n";
1185 ss << " gpu_EmitVertex();\n";
1186 }
1187 ss << "}\n";
1188 return ss.str();
1189}
1190
1191bool VKShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info) const
1192{
1193 const VKWorkarounds &workarounds = VKBackend::get().device.workarounds_get();
1194 BuiltinBits builtins = info->builtins_;
1195 if (workarounds.fragment_shader_barycentric && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) {
1196 return true;
1197 }
1198 if (workarounds.shader_output_layer && bool(builtins & BuiltinBits::LAYER)) {
1199 return true;
1200 }
1201 if (workarounds.shader_output_viewport_index && bool(builtins & BuiltinBits::VIEWPORT_INDEX)) {
1202 return true;
1203 }
1204 return false;
1205}
1206
1208
1210{
1211 BLI_assert(is_compute_shader_);
1212 BLI_assert(compute_module.vk_shader_module != VK_NULL_HANDLE);
1213 BLI_assert(vk_pipeline_layout != VK_NULL_HANDLE);
1214
1215 /* Early exit when no specialization constants are used and the vk_pipeline_base_ is already
1216 * valid. This would handle most cases. */
1217 if (constants.values.is_empty() && vk_pipeline_base_ != VK_NULL_HANDLE) {
1218 return vk_pipeline_base_;
1219 }
1220
1221 VKComputeInfo compute_info = {};
1222 compute_info.specialization_constants.extend(constants.values);
1223 compute_info.vk_shader_module = compute_module.vk_shader_module;
1225
1226 VKDevice &device = VKBackend::get().device;
1227 /* Store result in local variable to ensure thread safety. */
1228 VkPipeline vk_pipeline = device.pipelines.get_or_create_compute_pipeline(
1229 compute_info, is_static_shader_, vk_pipeline_base_);
1230 if (vk_pipeline_base_ == VK_NULL_HANDLE) {
1231 vk_pipeline_base_ = vk_pipeline;
1232 }
1233 return vk_pipeline;
1234}
1235
1238 VKStateManager &state_manager,
1239 VKFrameBuffer &framebuffer)
1240{
1241 BLI_assert(!is_compute_shader_);
1243 primitive != GPU_PRIM_POINTS || interface_get().is_point_shader(),
1244 "GPU_PRIM_POINTS is used with a shader that doesn't set point size before "
1245 "drawing fragments. Calling code should be adapted to use a shader that sets the "
1246 "gl_PointSize before entering the fragment stage. For example `GPU_SHADER_3D_POINT_*`.");
1247
1248 /* TODO: Graphics info should be cached in VKContext and only the changes should be applied. */
1249 VKGraphicsInfo graphics_info = {};
1250 graphics_info.specialization_constants.extend(constants.values);
1251 graphics_info.vk_pipeline_layout = vk_pipeline_layout;
1252
1253 graphics_info.vertex_in.vk_topology = to_vk_primitive_topology(primitive);
1254 graphics_info.vertex_in.attributes = vao.attributes;
1255 graphics_info.vertex_in.bindings = vao.bindings;
1256
1257 graphics_info.pre_rasterization.vk_vertex_module = vertex_module.vk_shader_module;
1258 graphics_info.pre_rasterization.vk_geometry_module = geometry_module.vk_shader_module;
1259
1260 graphics_info.fragment_shader.vk_fragment_module = fragment_module.vk_shader_module;
1261 graphics_info.state = state_manager.state;
1262 graphics_info.mutable_state = state_manager.mutable_state;
1263 // TODO: in stead of extend use a build pattern.
1264 graphics_info.fragment_shader.viewports.clear();
1265 graphics_info.fragment_shader.viewports.extend(framebuffer.vk_viewports_get());
1266 graphics_info.fragment_shader.scissors.clear();
1267 graphics_info.fragment_shader.scissors.extend(framebuffer.vk_render_areas_get());
1268
1271 framebuffer.stencil_attachment_format_get();
1273 framebuffer.color_attachment_formats_get());
1274
1275 VKDevice &device = VKBackend::get().device;
1276 /* Store result in local variable to ensure thread safety. */
1277 VkPipeline vk_pipeline = device.pipelines.get_or_create_graphics_pipeline(
1278 graphics_info, is_static_shader_, vk_pipeline_base_);
1279 if (vk_pipeline_base_ == VK_NULL_HANDLE) {
1280 vk_pipeline_base_ = vk_pipeline;
1281 }
1282 return vk_pipeline;
1283}
1284
1286{
1287 return -1;
1288}
1289
1291{
1292 BLI_assert_msg(interface != nullptr,
1293 "Interface can be accessed after the VKShader has been initialized "
1294 "`VKShader::init`");
1295 return *static_cast<const VKShaderInterface *>(interface);
1296}
1297
1298} // namespace blender::gpu
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
char * BLI_string_join_arrayN(const char *strings[], uint strings_num) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
unsigned int uint
#define ELEM(...)
GPUPrimType
@ GPU_PRIM_POINTS
eGPUShaderTFBType
eGPUTextureFormat
@ GPU_R16UI
@ GPU_R16I
@ GPU_RGB10_A2
@ GPU_R32I
@ GPU_RG8UI
@ GPU_RG8I
@ GPU_RG16I
@ GPU_RG32UI
@ GPU_RG8
@ GPU_RG32I
@ GPU_RGBA32UI
@ GPU_R8I
@ GPU_R16
@ GPU_RG16UI
@ GPU_RGBA8I
@ GPU_RGBA8UI
@ GPU_RGBA16UI
@ GPU_RGBA16I
@ GPU_R8UI
@ GPU_RGBA16
@ GPU_RG32F
@ GPU_R8
@ GPU_RGBA32I
#define output
void extend(Span< T > array)
void clear()
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr int64_t find(char c, int64_t pos=0) const
constexpr bool is_empty() const
void append(const T &value)
void extend(Span< T > array)
ShaderInterface * interface
const char *const name_get() const
struct blender::gpu::Shader::Constants constants
void print_log(Span< const char * > sources, const char *log, const char *stage, bool error, GPULogParser *parser)
Shader(const char *name)
Definition gpu_shader.cc:55
static VKBackend & get()
Definition vk_backend.hh:92
static VKContext * get()
Definition vk_context.hh:97
VkDescriptorSetLayout get_or_create(const VKDescriptorSetLayoutInfo &info, bool &r_created, bool &r_needed)
VKPipelinePool pipelines
Definition vk_device.hh:174
VKDescriptorSetLayouts & descriptor_set_layouts_get()
Definition vk_device.hh:248
VkDevice vk_handle() const
Definition vk_device.hh:224
VKDiscardPool & discard_pool_for_current_thread()
Definition vk_device.cc:399
const char * glsl_patch_get() const
Definition vk_device.cc:250
const VKWorkarounds & workarounds_get() const
Definition vk_device.hh:286
void discard_pipeline_layout(VkPipelineLayout vk_pipeline_layout)
VkFormat stencil_attachment_format_get() const
VkFormat depth_attachment_format_get() const
Array< VkViewport, 16 > vk_viewports_get() const
Array< VkRect2D, 16 > vk_render_areas_get() const
Span< VkFormat > color_attachment_formats_get() const
VkPipeline get_or_create_compute_pipeline(VKComputeInfo &compute_info, bool is_static_shader, VkPipeline vk_pipeline_base)
VkPipeline get_or_create_graphics_pipeline(VKGraphicsInfo &graphics_info, bool is_static_shader, VkPipeline vk_pipeline_base)
static bool compile_module(VKShader &shader, shaderc_shader_kind stage, VKShaderModule &shader_module)
const VKPushConstants::Layout & push_constants_layout_get() const
const VKDescriptorSetLayoutInfo & descriptor_set_layout_info_get() const
const VKDescriptorSet::Location descriptor_set_location(const shader::ShaderCreateInfo::Resource &resource) const
void init(const shader::ShaderCreateInfo &info)
shaderc::SpvCompilationResult compilation_result
void finalize(StringRefNull name)
void unbind() override
Definition vk_shader.cc:740
VKShaderModule compute_module
Definition vk_shader.hh:50
void init(const shader::ShaderCreateInfo &info, bool is_batch_compilation) override
Definition vk_shader.cc:498
std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override
Definition vk_shader.cc:918
int program_handle_get() const override
void bind() override
Definition vk_shader.cc:734
VKShaderModule fragment_module
Definition vk_shader.hh:49
void transform_feedback_names_set(Span< const char * > name_list, eGPUShaderTFBType geom_type) override
Definition vk_shader.cc:716
void geometry_shader_from_glsl(MutableSpan< const char * > sources) override
Definition vk_shader.cc:546
void compute_shader_from_glsl(MutableSpan< const char * > sources) override
Definition vk_shader.cc:556
std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override
void warm_cache(int limit) override
Definition vk_shader.cc:561
VKPushConstants push_constants
Definition vk_shader.hh:55
std::string resources_declare(const shader::ShaderCreateInfo &info) const override
Definition vk_shader.cc:752
bool is_ready() const
Definition vk_shader.cc:652
std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override
VkPipelineLayout vk_pipeline_layout
Definition vk_shader.hh:54
VkPipeline ensure_and_get_compute_pipeline()
void transform_feedback_disable() override
Definition vk_shader.cc:727
void uniform_int(int location, int comp_len, int array_size, const int *data) override
Definition vk_shader.cc:747
VKShader(const char *name)
Definition vk_shader.cc:493
VKShaderModule vertex_module
Definition vk_shader.hh:47
void vertex_shader_from_glsl(MutableSpan< const char * > sources) override
Definition vk_shader.cc:541
VKShaderModule geometry_module
Definition vk_shader.hh:48
VkPipeline ensure_and_get_graphics_pipeline(GPUPrimType primitive, VKVertexAttributeObject &vao, VKStateManager &state_manager, VKFrameBuffer &framebuffer)
std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override
void uniform_float(int location, int comp_len, int array_size, const float *data) override
Definition vk_shader.cc:742
const VKShaderInterface & interface_get() const
bool transform_feedback_enable(VertBuf *) override
Definition vk_shader.cc:722
void fragment_shader_from_glsl(MutableSpan< const char * > sources) override
Definition vk_shader.cc:551
bool finalize(const shader::ShaderCreateInfo *info=nullptr) override
Definition vk_shader.cc:566
std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override
Definition vk_shader.cc:829
Vector< VkVertexInputAttributeDescription > attributes
Vector< VkVertexInputBindingDescription > bindings
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
DOF_TILES_FLATTEN_GROUP_SIZE coc_tx GPU_R11F_G11F_B10F
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
out_radiance out_gbuf_normal out_gbuf_closure2 GPU_RG16
SHADOW_TILEMAP_RES tiles_buf[] statistics_buf render_view_buf[SHADOW_VIEW_MAX] GPU_R32UI
RAYTRACE_GROUP_SIZE additional_info("eevee_shared", "eevee_gbuffer_data", "eevee_global_ubo", "eevee_sampling_data", "eevee_utility_texture", "eevee_hiz_data", "draw_view") .specialization_constant(Type RAYTRACE_GROUP_SIZE in_sh_0_tx in_sh_2_tx screen_normal_tx GPU_RGBA8
#define SOURCES_INDEX_VERSION
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:344
BLI_INLINE int to_component_count(const Type &type)
static void print_image_type(std::ostream &os, const ImageType &type, const ShaderCreateInfo::Resource::BindType bind_type)
Definition vk_shader.cc:206
static std::string combine_sources(Span< const char * > sources)
Definition vk_shader.cc:485
const char * to_string(ShaderStage stage)
Definition mtl_shader.mm:52
int get_location_count(const Type &type)
Definition vk_shader.cc:407
static StageInterfaceInfo * find_interface_by_name(const Span< StageInterfaceInfo * > ifaces, const StringRefNull name)
static void print_interface(std::ostream &os, const std::string &prefix, const StageInterfaceInfo &iface, int &location, const StringRefNull &suffix="")
Definition vk_shader.cc:452
static std::ostream & print_qualifier(std::ostream &os, const Qualifier &qualifiers)
Definition vk_shader.cc:335
static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res)
static Type to_component_type(const Type &type)
Definition vk_shader.cc:871
static void print_interface_as_struct(std::ostream &os, const std::string &prefix, const StageInterfaceInfo &iface, int &location, const StringRefNull &suffix)
Definition vk_shader.cc:430
static std::string main_function_wrapper(std::string &pre_main, std::string &post_main)
Definition vk_shader.cc:467
VkPrimitiveTopology to_vk_primitive_topology(const GPUPrimType prim_type)
Definition vk_common.cc:853
static void declare_emit_vertex(std::stringstream &ss)
static void print_interface_as_attributes(std::ostream &os, const std::string &prefix, const StageInterfaceInfo &iface, int &location)
Definition vk_shader.cc:418
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
static constexpr GPUSamplerState default_sampler()
Vector< shader::SpecializationConstant::Value > specialization_constants
VkPipelineLayout vk_pipeline_layout
Vector< VkVertexInputBindingDescription > bindings
Vector< VkVertexInputAttributeDescription > attributes
Vector< shader::SpecializationConstant::Value > specialization_constants
VKDescriptorSet::Location descriptor_set_location_get() const
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Vector< StageInterfaceInfo * > vertex_out_interfaces_
Self & geometry_layout(PrimitiveIn prim_in, PrimitiveOut prim_out, int max_vertices, int invocations=-1)
Vector< StageInterfaceInfo * > geometry_out_interfaces_
Vector< SpecializationConstant > specialization_constants_
#define NOT_YET_IMPLEMENTED
Definition vk_common.hh:132
#define VK_ALLOCATION_CALLBACKS
Definition vk_memory.hh:58