Blender V5.0
gpu_shader_create_info.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
13
14#pragma once
15
16#if !defined(GPU_SHADER)
17# include "BLI_hash.hh"
18# include "BLI_string_ref.hh"
20# include "BLI_vector.hh"
21# include "GPU_common_types.hh"
22# include "GPU_material.hh"
23# include "GPU_texture.hh"
24
25# include <iostream>
26#endif
27
28#if defined(GPU_SHADER)
29# include "gpu_shader_srd_cpp.hh"
30#else
31# include "gpu_shader_srd_info.hh"
32#endif
33
34/* Force enable `printf` support in release build. */
35#define GPU_FORCE_ENABLE_SHADER_PRINTF 0
36
37#if !defined(NDEBUG) || GPU_FORCE_ENABLE_SHADER_PRINTF
38# define GPU_SHADER_PRINTF_ENABLE 1
39#else
40# define GPU_SHADER_PRINTF_ENABLE 0
41#endif
42#define GPU_SHADER_PRINTF_SLOT 13
43#define GPU_SHADER_PRINTF_MAX_CAPACITY (1024 * 4)
44
45/* Used for primitive expansion. */
46#define GPU_SSBO_INDEX_BUF_SLOT 7
47/* Used for polylines. */
48#define GPU_SSBO_POLYLINE_POS_BUF_SLOT 0
49#define GPU_SSBO_POLYLINE_COL_BUF_SLOT 1
50
51#if defined(GLSL_CPP_STUBS)
52# define GPU_SHADER_NAMED_INTERFACE_INFO(_interface, _inst_name) \
53 namespace interface::_interface { \
54 struct {
55# define GPU_SHADER_NAMED_INTERFACE_END(_inst_name) \
56 } \
57 _inst_name; \
58 }
59
60# define GPU_SHADER_INTERFACE_INFO(_interface) namespace interface::_interface {
61# define GPU_SHADER_INTERFACE_END() }
62
63# define GPU_SHADER_CREATE_INFO(_info) \
64 namespace _info { \
65 namespace gl_VertexShader { \
66 } \
67 namespace gl_FragmentShader { \
68 } \
69 namespace gl_ComputeShader { \
70 }
71# define GPU_SHADER_CREATE_END() }
72
73# define SHADER_LIBRARY_CREATE_INFO(_info) using namespace _info;
74# define VERTEX_SHADER_CREATE_INFO(_info) \
75 using namespace ::gl_VertexShader; \
76 using namespace _info::gl_VertexShader; \
77 using namespace _info;
78# define FRAGMENT_SHADER_CREATE_INFO(_info) \
79 using namespace ::gl_FragmentShader; \
80 using namespace _info::gl_FragmentShader; \
81 using namespace _info;
82# define COMPUTE_SHADER_CREATE_INFO(_info) \
83 using namespace ::gl_ComputeShader; \
84 using namespace _info::gl_ComputeShader; \
85 using namespace _info;
86
87#elif !defined(GPU_SHADER_CREATE_INFO)
88/* Helps intellisense / auto-completion inside info files. */
89# define GPU_SHADER_NAMED_INTERFACE_INFO(_interface, _inst_name) \
90 static inline void autocomplete_helper_interface_##_interface() \
91 { \
92 StageInterfaceInfo _interface(#_interface, _inst_name); \
93 _interface
94# define GPU_SHADER_INTERFACE_INFO(_interface) \
95 static inline void autocomplete_helper_interface_##_interface() \
96 { \
97 StageInterfaceInfo _interface(#_interface); \
98 _interface
99# define GPU_SHADER_CREATE_INFO(_info) \
100 static inline void autocomplete_helper_info_##_info() \
101 { \
102 ShaderCreateInfo _info(#_info); \
103 _info
104
105# define GPU_SHADER_NAMED_INTERFACE_END(_inst_name) \
106 ; \
107 }
108# define GPU_SHADER_INTERFACE_END() \
109 ; \
110 }
111# define GPU_SHADER_CREATE_END() \
112 ; \
113 }
114
115#endif
116
117#ifndef GLSL_CPP_STUBS
118# define SMOOTH(type, name) .smooth(Type::type##_t, #name)
119# define FLAT(type, name) .flat(Type::type##_t, #name)
120# define NO_PERSPECTIVE(type, name) .no_perspective(Type::type##_t, #name)
121
122/* LOCAL_GROUP_SIZE(int size_x, int size_y = 1, int size_z = 1) */
123# define LOCAL_GROUP_SIZE(...) .local_group_size(__VA_ARGS__)
124
125# define VERTEX_IN(slot, type, name) .vertex_in(slot, Type::type##_t, #name)
126# define VERTEX_IN_SRD(srd) .shared_resource_descriptor(srd::populate)
127# define VERTEX_OUT(stage_interface) .vertex_out(stage_interface)
128# define VERTEX_OUT_SRD(srd) .vertex_out(srd)
129/* TO REMOVE. */
130# define GEOMETRY_LAYOUT(...) .geometry_layout(__VA_ARGS__)
131# define GEOMETRY_OUT(stage_interface) .geometry_out(stage_interface)
132
133# define SUBPASS_IN(slot, type, img_type, name, rog) \
134 .subpass_in(slot, Type::type##_t, ImageType::img_type, #name, rog)
135
136# define FRAGMENT_OUT(slot, type, name) .fragment_out(slot, Type::type##_t, #name)
137# define FRAGMENT_OUT_SRD(srd) .shared_resource_descriptor(srd::populate)
138# define FRAGMENT_OUT_DUAL(slot, type, name, blend) \
139 .fragment_out(slot, Type::type##_t, #name, DualBlend::blend)
140# define FRAGMENT_OUT_ROG(slot, type, name, rog) \
141 .fragment_out(slot, Type::type##_t, #name, DualBlend::NONE, rog)
142
143# define RESOURCE_SRD(srd) .shared_resource_descriptor(srd::populate)
144
145# define EARLY_FRAGMENT_TEST(enable) .early_fragment_test(enable)
146# define DEPTH_WRITE(value) .depth_write(value)
147
148# define SPECIALIZATION_CONSTANT(type, name, default_value) \
149 .specialization_constant(Type::type##_t, #name, default_value)
150
151# define COMPILATION_CONSTANT(type, name, value) \
152 .compilation_constant(Type::type##_t, #name, value)
153
154# define PUSH_CONSTANT(type, name) .push_constant(Type::type##_t, #name)
155# define PUSH_CONSTANT_ARRAY(type, name, array_size) \
156 .push_constant(Type::type##_t, #name, array_size)
157
158# define UNIFORM_BUF(slot, type_name, name) .uniform_buf(slot, #type_name, #name)
159# define UNIFORM_BUF_FREQ(slot, type_name, name, freq) \
160 .uniform_buf(slot, #type_name, #name, Frequency::freq)
161
162# define STORAGE_BUF(slot, qualifiers, type_name, name) \
163 .storage_buf(slot, Qualifier::qualifiers, STRINGIFY(type_name), #name)
164# define STORAGE_BUF_FREQ(slot, qualifiers, type_name, name, freq) \
165 .storage_buf(slot, Qualifier::qualifiers, STRINGIFY(type_name), #name, Frequency::freq)
166
167# define SAMPLER(slot, type, name) .sampler(slot, ImageType::type, #name)
168# define SAMPLER_FREQ(slot, type, name, freq) \
169 .sampler(slot, ImageType::type, #name, Frequency::freq)
170
171# define IMAGE(slot, format, qualifiers, type, name) \
172 .image(slot, \
173 blender::gpu::TextureFormat::format, \
174 Qualifier::qualifiers, \
175 ImageReadWriteType::type, \
176 #name)
177# define IMAGE_FREQ(slot, format, qualifiers, type, name, freq) \
178 .image(slot, \
179 blender::gpu::TextureFormat::format, \
180 Qualifier::qualifiers, \
181 ImageReadWriteType::type, \
182 #name, \
183 Frequency::freq)
184
185# define GROUP_SHARED(type, name) .shared_variable(Type::type##_t, #name)
186
187# define BUILTINS(builtin) .builtins(builtin)
188
189# define VERTEX_SOURCE(filename) .vertex_source(filename)
190# define FRAGMENT_SOURCE(filename) .fragment_source(filename)
191# define COMPUTE_SOURCE(filename) .compute_source(filename)
192
193# define VERTEX_FUNCTION(function) .vertex_function(function)
194# define FRAGMENT_FUNCTION(function) .fragment_function(function)
195# define COMPUTE_FUNCTION(function) .compute_function(function)
196
197# define DEFINE(name) .define(name)
198# define DEFINE_VALUE(name, value) .define(name, value)
199
200# define DO_STATIC_COMPILATION() .do_static_compilation(true)
201# define AUTO_RESOURCE_LOCATION() .auto_resource_location(true)
202
203/* TO REMOVE. */
204# define METAL_BACKEND_ONLY() .metal_backend_only(true)
205
206# define ADDITIONAL_INFO(info_name) .additional_info(#info_name)
207# define TYPEDEF_SOURCE(filename) .typedef_source(filename)
208
209# define MTL_MAX_TOTAL_THREADS_PER_THREADGROUP(value) \
210 .mtl_max_total_threads_per_threadgroup(value)
211
212#else
213
214# define _read const
215# define _write
216# define _read_write
217
218# define SMOOTH(type, name) type name = {};
219# define FLAT(type, name) type name = {};
220# define NO_PERSPECTIVE(type, name) type name = {};
221
222/* LOCAL_GROUP_SIZE(int size_x, int size_y = -1, int size_z = -1) */
223# define LOCAL_GROUP_SIZE(...)
224
225# define VERTEX_IN(slot, type, name) \
226 namespace gl_VertexShader { \
227 const type name = {}; \
228 }
229# define VERTEX_IN_SRD(srd) \
230 namespace gl_VertexShader { \
231 using namespace srd; \
232 }
233# define VERTEX_OUT(stage_interface) using namespace interface::stage_interface;
234# define VERTEX_OUT_SRD(srd) using namespace interface::srd;
235/* TO REMOVE. */
236# define GEOMETRY_LAYOUT(...)
237# define GEOMETRY_OUT(stage_interface) using namespace interface::stage_interface;
238
239# define SUBPASS_IN(slot, type, img_type, name, rog) const type name = {};
240
241# define FRAGMENT_OUT(slot, type, name) \
242 namespace gl_FragmentShader { \
243 type name; \
244 }
245# define FRAGMENT_OUT_DUAL(slot, type, name, blend) \
246 namespace gl_FragmentShader { \
247 type name; \
248 }
249# define FRAGMENT_OUT_ROG(slot, type, name, rog) \
250 namespace gl_FragmentShader { \
251 type name; \
252 }
253# define FRAGMENT_OUT_SRD(srd) \
254 namespace gl_FragmentShader { \
255 using namespace srd; \
256 }
257
258# define RESOURCE_SRD(srd) using namespace srd;
259
260# define EARLY_FRAGMENT_TEST(enable)
261# define DEPTH_WRITE(value)
262
263# define SPECIALIZATION_CONSTANT(type, name, default_value) \
264 constexpr type name = type(default_value);
265
266# define COMPILATION_CONSTANT(type, name, value) constexpr type name = type(value);
267
268# define PUSH_CONSTANT(type, name) extern const type name;
269# define PUSH_CONSTANT_ARRAY(type, name, array_size) extern const type name[array_size];
270
271# define UNIFORM_BUF(slot, type_name, name) extern const type_name name;
272# define UNIFORM_BUF_FREQ(slot, type_name, name, freq) extern const type_name name;
273
274# define STORAGE_BUF(slot, qualifiers, type_name, name) extern _##qualifiers type_name name;
275# define STORAGE_BUF_FREQ(slot, qualifiers, type_name, name, freq) \
276 extern _##qualifiers type_name name;
277
278# define SAMPLER(slot, type, name) type name;
279# define SAMPLER_FREQ(slot, type, name, freq) type name;
280
281# define IMAGE(slot, format, qualifiers, type, name) _##qualifiers type name;
282# define IMAGE_FREQ(slot, format, qualifiers, type, name, freq) _##qualifiers type name;
283
284# define GROUP_SHARED(type, name) type name;
285
286# define BUILTINS(builtin)
287
288# define VERTEX_SOURCE(filename)
289# define FRAGMENT_SOURCE(filename)
290# define COMPUTE_SOURCE(filename)
291
292# define VERTEX_FUNCTION(filename)
293# define FRAGMENT_FUNCTION(filename)
294# define COMPUTE_FUNCTION(filename)
295
296# define DEFINE(name)
297# define DEFINE_VALUE(name, value)
298
299# define DO_STATIC_COMPILATION()
300# define AUTO_RESOURCE_LOCATION()
301
302/* TO REMOVE. */
303# define METAL_BACKEND_ONLY()
304
305# define ADDITIONAL_INFO(info_name) \
306 using namespace info_name; \
307 using namespace info_name::gl_FragmentShader; \
308 using namespace info_name::gl_VertexShader;
309
310# define TYPEDEF_SOURCE(filename)
311
312# define MTL_MAX_TOTAL_THREADS_PER_THREADGROUP(value)
313#endif
314
315#define _INFO_EXPAND2(a, b) ADDITIONAL_INFO(a) ADDITIONAL_INFO(b)
316#define _INFO_EXPAND3(a, b, c) _INFO_EXPAND2(a, b) ADDITIONAL_INFO(c)
317#define _INFO_EXPAND4(a, b, c, d) _INFO_EXPAND3(a, b, c) ADDITIONAL_INFO(d)
318#define _INFO_EXPAND5(a, b, c, d, e) _INFO_EXPAND4(a, b, c, d) ADDITIONAL_INFO(e)
319#define _INFO_EXPAND6(a, b, c, d, e, f) _INFO_EXPAND5(a, b, c, d, e) ADDITIONAL_INFO(f)
320
321#define ADDITIONAL_INFO_EXPAND(...) VA_NARGS_CALL_OVERLOAD(_INFO_EXPAND, __VA_ARGS__)
322
323#define CREATE_INFO_VARIANT(name, ...) \
324 GPU_SHADER_CREATE_INFO(name) \
325 DO_STATIC_COMPILATION() \
326 ADDITIONAL_INFO_EXPAND(__VA_ARGS__) \
327 GPU_SHADER_CREATE_END()
328
329#if !defined(GLSL_CPP_STUBS)
330
331namespace blender::gpu {
332struct GPUSource;
333}
334
335namespace blender::gpu::shader {
336
337/* All of these functions is a bit out of place */
338static inline Type to_type(const GPUType type)
339{
340 switch (type) {
341 case GPU_FLOAT:
342 return Type::float_t;
343 case GPU_VEC2:
344 return Type::float2_t;
345 case GPU_VEC3:
346 return Type::float3_t;
347 case GPU_VEC4:
348 return Type::float4_t;
349 case GPU_MAT3:
350 return Type::float3x3_t;
351 case GPU_MAT4:
352 return Type::float4x4_t;
353 default:
354 BLI_assert_msg(0, "Error: Cannot convert GPUType to shader::Type.");
355 return Type::float_t;
356 }
357}
358
359static inline std::ostream &operator<<(std::ostream &stream, const Type type)
360{
361 switch (type) {
362 case Type::float_t:
363 return stream << "float";
364 case Type::float2_t:
365 return stream << "vec2";
366 case Type::float3_t:
367 return stream << "vec3";
368 case Type::float4_t:
369 return stream << "vec4";
370 case Type::float3x3_t:
371 return stream << "mat3";
372 case Type::float4x4_t:
373 return stream << "mat4";
375 return stream << "vec3_1010102_Inorm";
376 case Type::uchar_t:
377 return stream << "uchar";
378 case Type::uchar2_t:
379 return stream << "uchar2";
380 case Type::uchar3_t:
381 return stream << "uchar3";
382 case Type::uchar4_t:
383 return stream << "uchar4";
384 case Type::char_t:
385 return stream << "char";
386 case Type::char2_t:
387 return stream << "char2";
388 case Type::char3_t:
389 return stream << "char3";
390 case Type::char4_t:
391 return stream << "char4";
392 case Type::int_t:
393 return stream << "int";
394 case Type::int2_t:
395 return stream << "ivec2";
396 case Type::int3_t:
397 return stream << "ivec3";
398 case Type::int4_t:
399 return stream << "ivec4";
400 case Type::uint_t:
401 return stream << "uint";
402 case Type::uint2_t:
403 return stream << "uvec2";
404 case Type::uint3_t:
405 return stream << "uvec3";
406 case Type::uint4_t:
407 return stream << "uvec4";
408 case Type::ushort_t:
409 return stream << "ushort";
410 case Type::ushort2_t:
411 return stream << "ushort2";
412 case Type::ushort3_t:
413 return stream << "ushort3";
414 case Type::ushort4_t:
415 return stream << "ushort4";
416 case Type::short_t:
417 return stream << "short";
418 case Type::short2_t:
419 return stream << "short2";
420 case Type::short3_t:
421 return stream << "short3";
422 case Type::short4_t:
423 return stream << "short4";
424 case Type::bool_t:
425 return stream << "bool";
426 default:
427 BLI_assert(0);
428 return stream;
429 }
430}
431
432static inline std::ostream &operator<<(std::ostream &stream, const GPUType type)
433{
434 switch (type) {
435 case GPU_CLOSURE:
436 return stream << "Closure";
437 default:
438 return stream << to_type(type);
439 }
440}
441
442enum class BuiltinBits {
443 NONE = 0,
449 STENCIL_REF = (1 << 1),
450 FRAG_COORD = (1 << 2),
451 FRONT_FACING = (1 << 4),
453 INSTANCE_ID = (1 << 6),
458 LAYER = (1 << 7),
461 NUM_WORK_GROUP = (1 << 10),
462 POINT_COORD = (1 << 11),
463 POINT_SIZE = (1 << 12),
464 PRIMITIVE_ID = (1 << 13),
465 VERTEX_ID = (1 << 14),
466 WORK_GROUP_ID = (1 << 15),
467 WORK_GROUP_SIZE = (1 << 16),
472 VIEWPORT_INDEX = (1 << 17),
473
474 /* Texture atomics requires usage options to alter compilation flag. */
475 TEXTURE_ATOMIC = (1 << 18),
476
477 /* Enable shader patching on GL to remap clip range to 0..1.
478 * Will do nothing if ClipControl is unsupported. */
479 CLIP_CONTROL = (1 << 19),
480
481 /* Not a builtin but a flag we use to tag shaders that use the debug features. */
482 USE_PRINTF = (1 << 28),
483 USE_DEBUG_DRAW = (1 << 29),
484
485 /* Shader source needs to be implemented at runtime. */
486 RUNTIME_GENERATED = (1 << 30),
487};
489
494enum class DepthWrite {
495 /* UNCHANGED specified as default to indicate gl_FragDepth is not used. */
500};
501
502/* Samplers & images. */
503enum class ImageType {
505# define TYPES_EXPAND(s) \
506 Float##s, Uint##s, Int##s, sampler##s = Float##s, usampler##s = Uint##s, isampler##s = Int##s
507
509 TYPES_EXPAND(1DArray),
511 TYPES_EXPAND(2DArray),
514 TYPES_EXPAND(CubeArray),
516# undef TYPES_EXPAND
517
518# define TYPES_EXPAND(s) \
519 Shadow##s, Depth##s, sampler##s##Shadow = Shadow##s, sampler##s##Depth = Depth##s
522 TYPES_EXPAND(2DArray),
524 TYPES_EXPAND(CubeArray),
525# undef TYPES_EXPAND
526
527# define TYPES_EXPAND(s) \
528 AtomicUint##s, AtomicInt##s, usampler##s##Atomic = AtomicUint##s, \
529 isampler##s##Atomic = AtomicInt##s
539 TYPES_EXPAND(2DArray),
541# undef TYPES_EXPAND
542};
543
544/* Samplers & images. */
547# define TYPES_EXPAND(s) \
548 Float##s = int(ImageType::Float##s), Uint##s = int(ImageType::Uint##s), \
549 Int##s = int(ImageType::Int##s), image##s = Float##s, uimage##s = Uint##s, iimage##s = Int##s
552 TYPES_EXPAND(1DArray),
554 TYPES_EXPAND(2DArray),
556# undef TYPES_EXPAND
557
558# define TYPES_EXPAND(s) \
559 AtomicUint##s = int(ImageType::AtomicUint##s), AtomicInt##s = int(ImageType::AtomicInt##s), \
560 uimage##s##Atomic = AtomicUint##s, iimage##s##Atomic = AtomicInt##s
570 TYPES_EXPAND(2DArray),
572# undef TYPES_EXPAND
573};
574
575/* Storage qualifiers. */
576enum class Qualifier {
578 no_restrict = (1 << 0),
579 read = (1 << 1),
580 write = (1 << 2),
583 QUALIFIER_MAX = (write << 1) - 1,
584};
586
588enum class Frequency {
589 BATCH = 0,
593};
594
596enum class DualBlend {
597 NONE = 0,
600};
601
608
617
626
633
642
643 StageInterfaceInfo(const char *name_, const char *instance_name_ = "")
644 : name(name_), instance_name(instance_name_) {};
646
648
650 {
651 inouts.append({Interpolation::SMOOTH, type, _name});
652 return *(Self *)this;
653 }
654
656 {
657 inouts.append({Interpolation::FLAT, type, _name});
658 return *(Self *)this;
659 }
660
662 {
663 inouts.append({Interpolation::NO_PERSPECTIVE, type, _name});
664 return *(Self *)this;
665 }
666};
667
670 /* Associated filename this source replaces. */
673 std::string content;
674};
675
677
692 bool is_generated_ = true;
694 bool finalized_ = false;
719
721
722 /* Same as StringRefNull but with a few extra member functions. */
724 constexpr ResourceString() : StringRefNull() {}
725 constexpr ResourceString(const char *str, int64_t size) : StringRefNull(str, size) {}
726 ResourceString(std::nullptr_t) = delete;
727 constexpr ResourceString(const char *str) : StringRefNull(str) {}
728 ResourceString(const std::string &str) : StringRefNull(str) {}
730
732 {
733 return this->find_first_of("[");
734 }
735
736 bool is_array() const
737 {
738 return array_offset() != -1;
739 }
740
742 {
743 return StringRef(this->c_str(), this->array_offset());
744 }
745
747 {
748 return this->substr(this->array_offset());
749 }
750 };
751
752# define TEST_EQUAL(a, b, _member) \
753 if (!((a)._member == (b)._member)) { \
754 return false; \
755 }
756
757# define TEST_VECTOR_EQUAL(a, b, _vector) \
758 TEST_EQUAL(a, b, _vector.size()); \
759 for (auto i : _vector.index_range()) { \
760 TEST_EQUAL(a, b, _vector[i]); \
761 }
762
763 struct VertIn {
764 int index;
767
768 bool operator==(const VertIn &b) const
769 {
770 TEST_EQUAL(*this, b, index);
771 TEST_EQUAL(*this, b, type);
772 TEST_EQUAL(*this, b, name);
773 return true;
774 }
775 };
777
783 int max_vertices = -1;
784
786 {
787 TEST_EQUAL(*this, b, primitive_in);
788 TEST_EQUAL(*this, b, invocations);
789 TEST_EQUAL(*this, b, primitive_out);
790 TEST_EQUAL(*this, b, max_vertices);
791 return true;
792 }
793 };
795
797 int local_size_x = -1;
798 int local_size_y = -1;
799 int local_size_z = -1;
800
801 bool operator==(const ComputeStageLayout &b) const
802 {
803 TEST_EQUAL(*this, b, local_size_x);
804 TEST_EQUAL(*this, b, local_size_y);
805 TEST_EQUAL(*this, b, local_size_z);
806 return true;
807 }
808 };
810
811 struct FragOut {
812 int index;
816 /* NOTE: Currently only supported by Metal. */
818
819 bool operator==(const FragOut &b) const
820 {
821 TEST_EQUAL(*this, b, index);
822 TEST_EQUAL(*this, b, type);
823 TEST_EQUAL(*this, b, blend);
824 TEST_EQUAL(*this, b, name);
826 return true;
827 }
828 };
830
831 struct SubpassIn {
832 int index;
836 /* NOTE: Currently only supported by Metal. */
838
839 bool operator==(const SubpassIn &b) const
840 {
841 TEST_EQUAL(*this, b, index);
842 TEST_EQUAL(*this, b, type);
843 TEST_EQUAL(*this, b, img_type);
844 TEST_EQUAL(*this, b, name);
846 return true;
847 }
848 };
850
853
858
860
866
873
878
884
885 struct Resource {
892
894 int slot;
895 union {
900 };
901
902 Resource(BindType type, int _slot) : bind_type(type), slot(_slot) {};
903
904 bool operator==(const Resource &b) const
905 {
906 TEST_EQUAL(*this, b, bind_type);
907 TEST_EQUAL(*this, b, slot);
908 switch (bind_type) {
909 case UNIFORM_BUFFER:
910 TEST_EQUAL(*this, b, uniformbuf.type_name);
911 TEST_EQUAL(*this, b, uniformbuf.name);
912 break;
913 case STORAGE_BUFFER:
914 TEST_EQUAL(*this, b, storagebuf.qualifiers);
915 TEST_EQUAL(*this, b, storagebuf.type_name);
916 TEST_EQUAL(*this, b, storagebuf.name);
917 break;
918 case SAMPLER:
919 TEST_EQUAL(*this, b, sampler.type);
920 TEST_EQUAL(*this, b, sampler.sampler);
921 TEST_EQUAL(*this, b, sampler.name);
922 break;
923 case IMAGE:
924 TEST_EQUAL(*this, b, image.format);
925 TEST_EQUAL(*this, b, image.type);
926 TEST_EQUAL(*this, b, image.qualifiers);
927 TEST_EQUAL(*this, b, image.name);
928 break;
929 }
930 return true;
931 }
932 };
933
941
943 {
944 switch (freq) {
945 case Frequency::PASS:
946 return pass_resources_;
947 case Frequency::BATCH:
948 return batch_resources_;
950 return geometry_resources_;
951 }
953 return pass_resources_;
954 }
955
956 /* Return all resources regardless of their frequency. */
958 {
959 Vector<Resource> all_resources;
960 all_resources.extend(pass_resources_);
961 all_resources.extend(batch_resources_);
962 all_resources.extend(geometry_resources_);
963 return all_resources;
964 }
965
968
969 struct PushConst {
973
974 bool operator==(const PushConst &b) const
975 {
976 TEST_EQUAL(*this, b, type);
977 TEST_EQUAL(*this, b, name);
978 TEST_EQUAL(*this, b, array_size);
979 return true;
980 }
981 };
982
984
985 /* Sources for resources type definitions. */
987
991
998
999 /* API-specific parameters. */
1000# ifdef WITH_METAL_BACKEND
1001 ushort mtl_max_threads_per_threadgroup_ = 0;
1002# endif
1003
1004 public:
1005 ShaderCreateInfo(const char *name) : name_(name) {};
1007
1009
1010 /* -------------------------------------------------------------------- */
1013
1015 {
1016 vertex_inputs_.append({slot, type, name});
1017 interface_names_size_ += name.size() + 1;
1018 return *(Self *)this;
1019 }
1020
1022 {
1024 return *(Self *)this;
1025 }
1026
1028 PrimitiveOut prim_out,
1029 int max_vertices,
1030 int invocations = -1)
1031 {
1032 geometry_layout_.primitive_in = prim_in;
1033 geometry_layout_.primitive_out = prim_out;
1034 geometry_layout_.max_vertices = max_vertices;
1035 geometry_layout_.invocations = invocations;
1036 return *(Self *)this;
1037 }
1038
1039 Self &local_group_size(int local_size_x, int local_size_y = 1, int local_size_z = 1)
1040 {
1041 compute_layout_.local_size_x = local_size_x;
1042 compute_layout_.local_size_y = local_size_y;
1043 compute_layout_.local_size_z = local_size_z;
1044 return *(Self *)this;
1045 }
1046
1052 {
1053 early_fragment_test_ = enable;
1054 return *(Self *)this;
1055 }
1056
1064 {
1066 return *(Self *)this;
1067 }
1068
1070 Type type,
1073 int raster_order_group = -1)
1074 {
1075 fragment_outputs_.append({slot, type, blend, name, raster_order_group});
1076 return *(Self *)this;
1077 }
1078
1094 int slot, Type type, ImageType img_type, StringRefNull name, int raster_order_group = -1)
1095 {
1096 subpass_inputs_.append({slot, type, img_type, name, raster_order_group});
1097 return *(Self *)this;
1098 }
1099
1101 {
1102 fn(*this);
1103 return *(Self *)this;
1104 }
1105
1107
1108 /* -------------------------------------------------------------------- */
1115
1116 Self &compilation_constant(Type type, StringRefNull name, double default_value)
1117 {
1118 CompilationConstant constant;
1119 constant.type = type;
1120 constant.name = name;
1121 switch (type) {
1122 case Type::int_t:
1123 constant.value.i = int(default_value);
1124 break;
1125 case Type::bool_t:
1126 case Type::uint_t:
1127 constant.value.u = uint(default_value);
1128 break;
1129 default:
1130 BLI_assert_msg(0, "Only scalar integer and bool types can be used as constants");
1131 break;
1132 }
1133 compilation_constants_.append(constant);
1134 interface_names_size_ += name.size() + 1;
1135 return *(Self *)this;
1136 }
1137
1139
1140 /* -------------------------------------------------------------------- */
1143
1144 /* Adds a specialization constant which is a dynamically modifiable value, which will be
1145 * statically compiled into a PSO configuration to provide optimal runtime performance,
1146 * with a reduced re-compilation cost vs Macro's with easier generation of unique permutations
1147 * based on run-time values.
1148 *
1149 * Tip: To evaluate use-cases of where specialization constants can provide a performance
1150 * gain, benchmark a given shader in its default case. Attempt to statically disable branches or
1151 * conditions which rely on uniform look-ups and measure if there is a marked improvement in
1152 * performance and/or reduction in memory bandwidth/register pressure.
1153 *
1154 * NOTE: Specialization constants will incur new compilation of PSOs and thus can incur an
1155 * unexpected cost. Specialization constants should be reserved for infrequently changing
1156 * parameters (e.g. user setting parameters such as toggling of features or quality level
1157 * presets), or those with a low set of possible runtime permutations.
1158 *
1159 * Specialization constants are assigned at runtime using:
1160 * - `GPU_shader_constant_*(shader, name, value)`
1161 * or
1162 * - `DrawPass::specialize_constant(shader, name, value)`
1163 *
1164 * All constants **MUST** be specified before binding a shader.
1165 */
1167 {
1168 SpecializationConstant constant;
1169 constant.type = type;
1170 constant.name = name;
1171 switch (type) {
1172 case Type::int_t:
1173 constant.value.i = int(default_value);
1174 break;
1175 case Type::bool_t:
1176 case Type::uint_t:
1177 constant.value.u = uint(default_value);
1178 break;
1179 case Type::float_t:
1180 constant.value.f = float(default_value);
1181 break;
1182 default:
1183 BLI_assert_msg(0, "Only scalar types can be used as constants");
1184 break;
1185 }
1186 specialization_constants_.append(constant);
1187 interface_names_size_ += name.size() + 1;
1188 return *(Self *)this;
1189 }
1190
1191 /* TODO: Add API to specify unique specialization config permutations in CreateInfo, allowing
1192 * specialized compilation to be primed and handled in the background at start-up, rather than
1193 * waiting for a given permutation to occur dynamically. */
1194
1196
1197 /* -------------------------------------------------------------------- */
1200
1202 {
1203 shared_variables_.append({type, name});
1204 return *(Self *)this;
1205 }
1206
1208
1209 /* -------------------------------------------------------------------- */
1212
1214 StringRefNull type_name,
1217 {
1219 res.uniformbuf.name = name;
1220 res.uniformbuf.type_name = type_name;
1221 resources_get_(freq).append(res);
1222 interface_names_size_ += name.size() + 1;
1223 return *(Self *)this;
1224 }
1225
1227 Qualifier qualifiers,
1228 StringRefNull type_name,
1231 {
1233 res.storagebuf.qualifiers = qualifiers;
1234 res.storagebuf.type_name = type_name;
1235 res.storagebuf.name = name;
1236 resources_get_(freq).append(res);
1237 interface_names_size_ += name.size() + 1;
1238 return *(Self *)this;
1239 }
1240
1241 Self &image(int slot,
1243 Qualifier qualifiers,
1244 ImageReadWriteType type,
1247 {
1249 res.image.format = format;
1250 res.image.qualifiers = qualifiers;
1251 res.image.type = ImageType(type);
1252 res.image.name = name;
1253 resources_get_(freq).append(res);
1254 interface_names_size_ += name.size() + 1;
1255 return *(Self *)this;
1256 }
1257
1258 Self &sampler(int slot,
1259 ImageType type,
1263 {
1265 res.sampler.type = type;
1266 res.sampler.name = name;
1267 /* Produces ASAN errors for the moment. */
1268 // res.sampler.sampler = sampler;
1270 resources_get_(freq).append(res);
1271 interface_names_size_ += name.size() + 1;
1272 return *(Self *)this;
1273 }
1274
1276
1277 /* -------------------------------------------------------------------- */
1280
1282 {
1283 vertex_source_ = filename;
1284 return *(Self *)this;
1285 }
1286
1288 {
1289 fragment_source_ = filename;
1290 return *(Self *)this;
1291 }
1292
1294 {
1295 compute_source_ = filename;
1296 return *(Self *)this;
1297 }
1298
1300 {
1301 vertex_entry_fn_ = function_name;
1302 return *(Self *)this;
1303 }
1304
1306 {
1307 fragment_entry_fn_ = function_name;
1308 return *(Self *)this;
1309 }
1310
1312 {
1313 compute_entry_fn_ = function_name;
1314 return *(Self *)this;
1315 }
1316
1318
1319 /* -------------------------------------------------------------------- */
1325
1326 Self &push_constant(Type type, StringRefNull name, int array_size = 0)
1327 {
1328 /* We don't have support for UINT push constants yet, use INT instead. */
1329 BLI_assert(type != Type::uint_t);
1330 BLI_assert_msg(name.find("[") == -1,
1331 "Array syntax is forbidden for push constants."
1332 "Use the array_size parameter instead.");
1333 push_constants_.append({type, name, array_size});
1334 interface_names_size_ += name.size() + 1;
1335 return *(Self *)this;
1336 }
1337
1339
1340 /* -------------------------------------------------------------------- */
1343
1345 {
1346 defines_.append({name, value});
1347 return *(Self *)this;
1348 }
1349
1351
1352 /* -------------------------------------------------------------------- */
1355
1357 {
1358 do_static_compilation_ = value;
1359 return *(Self *)this;
1360 }
1361
1363 {
1364 builtins_ |= builtin;
1365 return *(Self *)this;
1366 }
1367
1368 /* Defines how the fragment shader will write to gl_FragDepth. */
1370 {
1371 depth_write_ = value;
1372 return *(Self *)this;
1373 }
1374
1376 {
1378 return *(Self *)this;
1379 }
1380
1382 {
1384 return *(Self *)this;
1385 }
1386
1388
1389 /* -------------------------------------------------------------------- */
1394
1396 {
1397 additional_infos_.append(info_name);
1398 return *(Self *)this;
1399 }
1400
1401 template<typename... Args> Self &additional_info(StringRefNull info_name, Args... args)
1402 {
1403 additional_info(info_name);
1404 additional_info(args...);
1405 return *(Self *)this;
1406 }
1407
1409
1410 /* -------------------------------------------------------------------- */
1417
1419 {
1420 typedef_sources_.append(filename);
1421 return *(Self *)this;
1422 }
1423
1425
1426 /* -------------------------------------------------------------------- */
1433
1439 Self &mtl_max_total_threads_per_threadgroup(ushort max_total_threads_per_threadgroup)
1440 {
1441# ifdef WITH_METAL_BACKEND
1442 mtl_max_threads_per_threadgroup_ = max_total_threads_per_threadgroup;
1443# else
1444 UNUSED_VARS(max_total_threads_per_threadgroup);
1445# endif
1446 return *(Self *)this;
1447 }
1448
1450
1451 /* -------------------------------------------------------------------- */
1457
1458 /* WARNING: Recursive evaluation is not thread safe.
1459 * Non-recursive evaluation expects their dependencies to be already finalized.
1460 * (All statically declared CreateInfos are automatically finalized at startup) */
1461 void finalize(const bool recursive = false);
1462
1463 void resource_guard_defines(std::string &defines) const;
1464
1465 std::string check_error() const;
1466 bool is_vulkan_compatible() const;
1467
1469 void validate_merge(const ShaderCreateInfo &other_info);
1470 void validate_vertex_attributes(const ShaderCreateInfo *other_info = nullptr);
1471
1473
1474 /* -------------------------------------------------------------------- */
1478
1479 /* Comparison operator for GPUPass cache. We only compare if it will create the same shader
1480 * code. So we do not compare name and some other internal stuff. */
1508
1510 friend std::ostream &operator<<(std::ostream &stream, const ShaderCreateInfo &info)
1511 {
1512 /* TODO(@fclem): Complete print. */
1513
1514 auto print_resource = [&](const Resource &res) {
1515 switch (res.bind_type) {
1517 stream << "UNIFORM_BUFFER(" << res.slot << ", " << res.uniformbuf.name << ")"
1518 << std::endl;
1519 break;
1521 stream << "STORAGE_BUFFER(" << res.slot << ", " << res.storagebuf.name << ")"
1522 << std::endl;
1523 break;
1525 stream << "SAMPLER(" << res.slot << ", " << res.sampler.name << ")" << std::endl;
1526 break;
1528 stream << "IMAGE(" << res.slot << ", " << res.image.name << ")" << std::endl;
1529 break;
1530 }
1531 };
1532
1533 /* TODO(@fclem): Order the resources. */
1534 for (const auto &res : info.batch_resources_) {
1535 print_resource(res);
1536 }
1537 for (const auto &res : info.pass_resources_) {
1538 print_resource(res);
1539 }
1540 for (const auto &res : info.geometry_resources_) {
1541 print_resource(res);
1542 }
1543 return stream;
1544 }
1545
1547 {
1548 for (const auto &res : batch_resources_) {
1549 if (res.bind_type == bind_type) {
1550 return true;
1551 }
1552 }
1553 for (const auto &res : pass_resources_) {
1554 if (res.bind_type == bind_type) {
1555 return true;
1556 }
1557 }
1558 for (const auto &res : geometry_resources_) {
1559 if (res.bind_type == bind_type) {
1560 return true;
1561 }
1562 }
1563 return false;
1564 }
1565
1567 {
1569 }
1570
1572
1573# undef TEST_EQUAL
1574# undef TEST_VECTOR_EQUAL
1575};
1576
1577} // namespace blender::gpu::shader
1578
1579namespace blender {
1582 {
1583 uint64_t hash = 0;
1585 hash = hash * 33 ^ uint64_t(value.u);
1586 }
1587 return hash;
1588 }
1589};
1590} // namespace blender
1591
1592#endif
#define D
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
unsigned int uint
unsigned short ushort
#define UNUSED_VARS(...)
#define ENUM_OPERATORS(_type, _max)
GPUType
@ GPU_VEC2
@ GPU_MAT4
@ GPU_VEC4
@ GPU_CLOSURE
@ GPU_VEC3
@ GPU_MAT3
@ GPU_FLOAT
long long int int64_t
unsigned long long int uint64_t
static T Cube(const T &x)
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr int64_t find_first_of(StringRef chars, int64_t pos=0) const
constexpr int64_t size() const
constexpr const char * c_str() const
void extend(Span< T > array)
nullptr float
#define str(s)
#define SMOOTH(type, name)
#define TYPES_EXPAND(s)
#define TEST_VECTOR_EQUAL(a, b, _vector)
#define FLAT(type, name)
#define NO_PERSPECTIVE(type, name)
#define TEST_EQUAL(a, b, _member)
format
Vector< shader::GeneratedSource, 0 > GeneratedSourceList
static Type to_type(const GPUType type)
static std::ostream & operator<<(std::ostream &stream, const Type type)
static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res)
#define hash
Definition noise_c.cc:154
const char * name
static constexpr GPUSamplerState internal_sampler()
uint64_t operator()(const Vector< blender::gpu::shader::SpecializationConstant::Value > &key) const
constexpr ResourceString(const char *str, int64_t size)
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...
Vector< StageInterfaceInfo * > vertex_out_interfaces_
Self & mtl_max_total_threads_per_threadgroup(ushort max_total_threads_per_threadgroup)
Self & compute_source(StringRefNull filename)
Self & compilation_constant(Type type, StringRefNull name, double default_value)
Self & geometry_layout(PrimitiveIn prim_in, PrimitiveOut prim_out, int max_vertices, int invocations=-1)
Self & fragment_source(StringRefNull filename)
Vector< std::array< StringRefNull, 2 > > defines_
Vector< CompilationConstant, 0 > compilation_constants_
void validate_vertex_attributes(const ShaderCreateInfo *other_info=nullptr)
Vector< Resource > & resources_get_(Frequency freq)
Self & vertex_in(int slot, Type type, StringRefNull name)
void finalize(const bool recursive=false)
Self & push_constant(Type type, StringRefNull name, int array_size=0)
Self & geometry_out(StageInterfaceInfo &interface)
Self & shared_variable(Type type, StringRefNull name)
bool operator==(const ShaderCreateInfo &b) const
Self & vertex_function(StringRefNull function_name)
Self & additional_info(StringRefNull info_name)
Self & typedef_source(StringRefNull filename)
Self & fragment_out(int slot, Type type, StringRefNull name, DualBlend blend=DualBlend::NONE, int raster_order_group=-1)
Self & vertex_out(StageInterfaceInfo &interface)
Vector< StageInterfaceInfo * > geometry_out_interfaces_
Self & storage_buf(int slot, Qualifier qualifiers, StringRefNull type_name, StringRefNull name, Frequency freq=Frequency::PASS)
bool has_resource_type(Resource::BindType bind_type) const
Self & shared_resource_descriptor(void(*fn)(ShaderCreateInfo &))
Self & sampler(int slot, ImageType type, StringRefNull name, Frequency freq=Frequency::PASS, GPUSamplerState sampler=GPUSamplerState::internal_sampler())
Self & compute_function(StringRefNull function_name)
Self & image(int slot, TextureFormat format, Qualifier qualifiers, ImageReadWriteType type, StringRefNull name, Frequency freq=Frequency::PASS)
Self & additional_info(StringRefNull info_name, Args... args)
Self & uniform_buf(int slot, StringRefNull type_name, StringRefNull name, Frequency freq=Frequency::PASS)
Self & subpass_in(int slot, Type type, ImageType img_type, StringRefNull name, int raster_order_group=-1)
Self & specialization_constant(Type type, StringRefNull name, double default_value)
Self & fragment_function(StringRefNull function_name)
friend std::ostream & operator<<(std::ostream &stream, const ShaderCreateInfo &info)
Self & local_group_size(int local_size_x, int local_size_y=1, int local_size_z=1)
void validate_merge(const ShaderCreateInfo &other_info)
Self & define(StringRefNull name, StringRefNull value="")
void resource_guard_defines(std::string &defines) const
Vector< SpecializationConstant > specialization_constants_
Self & smooth(Type type, StringRefNull _name)
StageInterfaceInfo(const char *name_, const char *instance_name_="")
Self & no_perspective(Type type, StringRefNull _name)
Self & flat(Type type, StringRefNull _name)
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
uint8_t flag
Definition wm_window.cc:145