Blender V4.3
mtl_shader_generator.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
9
164/* SSBO vertex fetch attribute uniform parameter names.
165 * These uniforms are used to pass the information
166 * required to perform manual vertex assembly within
167 * the vertex shader.
168 * Each vertex attribute requires a number of properties
169 * in order to correctly extract data from the bound vertex
170 * buffers. */
171#ifndef NDEBUG
172/* Global. */
173# define UNIFORM_SSBO_USES_INDEXED_RENDERING_STR "uniform_ssbo_uses_indexed_rendering"
174# define UNIFORM_SSBO_INDEX_MODE_U16_STR "uniform_ssbo_index_mode_u16"
175# define UNIFORM_SSBO_INPUT_PRIM_TYPE_STR "uniform_ssbo_input_prim_type"
176# define UNIFORM_SSBO_INPUT_VERT_COUNT_STR "uniform_ssbo_input_vert_count"
177# define UNIFORM_SSBO_INDEX_BASE_STR "uniform_ssbo_index_base_"
178/* Per-attribute. */
179# define UNIFORM_SSBO_OFFSET_STR "uniform_ssbo_offset_"
180# define UNIFORM_SSBO_STRIDE_STR "uniform_ssbo_stride_"
181# define UNIFORM_SSBO_FETCHMODE_STR "uniform_ssbo_fetchmode_"
182# define UNIFORM_SSBO_VBO_ID_STR "uniform_ssbo_vbo_id_"
183# define UNIFORM_SSBO_TYPE_STR "uniform_ssbo_type_"
184#else
185/* Global. */
186# define UNIFORM_SSBO_USES_INDEXED_RENDERING_STR "_ir"
187# define UNIFORM_SSBO_INDEX_MODE_U16_STR "_mu"
188# define UNIFORM_SSBO_INPUT_PRIM_TYPE_STR "_pt"
189# define UNIFORM_SSBO_INPUT_VERT_COUNT_STR "_vc"
190# define UNIFORM_SSBO_INDEX_BASE_STR "_ib"
191/* Per-attribute. */
192# define UNIFORM_SSBO_OFFSET_STR "_so"
193# define UNIFORM_SSBO_STRIDE_STR "_ss"
194# define UNIFORM_SSBO_FETCHMODE_STR "_sf"
195# define UNIFORM_SSBO_VBO_ID_STR "_sv"
196# define UNIFORM_SSBO_TYPE_STR "_st"
197#endif
198
199namespace blender::gpu {
200
203 std::string name;
207
209 std::string uniform_name,
210 bool is_array_type,
211 uint32_t num_elems = 1)
212 : type(uniform_type), name(uniform_name), is_array(is_array_type), array_elems(num_elems)
213 {
214 }
215
216 bool operator==(const MSLUniform &right) const
217 {
218 return (type == right.type && name == right.name && is_array == right.is_array &&
219 array_elems == right.array_elems);
220 }
221};
222
225 std::string name;
226
227 MSLConstant(shader::Type const_type, std::string const_name) : type(const_type), name(const_name)
228 {
229 }
230};
231
233 std::string type_name;
234 std::string name;
237 /* Resource index in buffer. */
241 /* Flag for use with texture atomic fallback. */
242 bool is_texture_buffer = false;
243
244 bool operator==(const MSLBufferBlock &right) const
245 {
246 return (type_name == right.type_name && name == right.name);
247 }
248};
249
257
261 std::string name;
263 /* Whether resource is a texture sampler or an image. */
265 /* Index in shader bind table `[[texture(N)]]`. */
267 /* Explicit bind index provided by ShaderCreateInfo. */
269
270 /* Atomic fallback buffer information. */
272
275
277
278 bool operator==(const MSLTextureResource &right) const
279 {
280 /* We do not compare stage as we want to avoid duplication of resources used across multiple
281 * stages. */
282 return (type == right.type && name == right.name && access == right.access);
283 }
284
285 std::string get_msl_access_str() const
286 {
287 switch (access) {
289 return "access::sample";
291 return "access::read";
293 return "access::write";
295 return "access::read_write";
296 default:
297 BLI_assert(false);
298 return "";
299 }
300 return "";
301 }
302
303 /* Get typestring for wrapped texture class members.
304 * wrapper struct type contains combined texture and sampler, templated
305 * against the texture type.
306 * See `COMBINED_SAMPLER_TYPE` in `mtl_shader_defines.msl`. */
307 std::string get_msl_typestring_wrapper(bool is_addr) const
308 {
309 std::string str;
310 str = this->get_msl_wrapper_type_str() + "<" + this->get_msl_return_type_str() + "," +
311 this->get_msl_access_str() + ">" + ((is_addr) ? "* " : " ") + this->name;
312 return str;
313 }
314
315 /* Get raw texture typestring -- used in entry-point function argument table. */
316 std::string get_msl_typestring(bool is_addr) const
317 {
318 std::string str;
319 str = this->get_msl_texture_type_str() + "<" + this->get_msl_return_type_str() + "," +
320 this->get_msl_access_str() + ">" + ((is_addr) ? "* " : " ") + this->name;
321 return str;
322 }
323
324 std::string get_msl_return_type_str() const;
325 std::string get_msl_texture_type_str() const;
326 std::string get_msl_wrapper_type_str() const;
327};
328
330 /* layout_location of -1 means unspecified and will
331 * be populated manually. */
334 std::string name;
335
336 bool operator==(const MSLVertexInputAttribute &right) const
337 {
338 return (layout_location == right.layout_location && type == right.type && name == right.name);
339 }
340};
341
343 std::string type;
344 std::string name;
345 /* Instance name specified if attributes belong to a struct. */
346 std::string instance_name;
347 /* Interpolation qualifier can be any of smooth (default), flat, no_perspective. */
351
352 bool operator==(const MSLVertexOutputAttribute &right) const
353 {
354 return (type == right.type && name == right.name &&
355 interpolation_qualifier == right.interpolation_qualifier &&
356 is_array == right.is_array && array_elems == right.array_elems);
357 }
359 {
360 if (interpolation_qualifier == "" || interpolation_qualifier == "smooth") {
361 return "";
362 }
363 else if (interpolation_qualifier == "flat") {
364 return " [[flat]]";
365 }
366 else if (interpolation_qualifier == "noperspective") {
367 return " [[center_no_perspective]]";
368 }
369 return "";
370 }
371};
372
374 /* Explicit output binding location N for [[color(N)]] -1 = unspecified. */
376 /* Output index for dual source blending. -1 = unspecified. */
379 std::string name;
380 /* Raster order group can be specified to synchronize pixel read and write operations between
381 * subsequent draws. If a subsequent draw requires reading data from a GBuffer, raster order
382 * groups should be used to ensure all writes occur before reading. */
384
385 bool operator==(const MSLFragmentOutputAttribute &right) const
386 {
387 return (layout_location == right.layout_location && type == right.type && name == right.name &&
388 layout_index == right.layout_index && raster_order_group == right.raster_order_group);
389 }
390};
391
392/* Fragment tile inputs match fragment output attribute layout. */
394
396 /* e.g. `shared vec4 color_cache[cache_size][cache_size];`. */
397 std::string type_name;
398 std::string varname;
400 std::string array_decl; /* String containing array declaration. e.g. [cache_size][cache_size]*/
401};
402
404 static char *msl_patch_default;
405
406 public:
415 /* Specialization Constants. */
417 /* Fragment tile inputs. */
420 /* Should match vertex outputs, but defined separately as
421 * some shader permutations will not utilize all inputs/outputs.
422 * Final shader uses the intersection between the two sets. */
425 /* Transform feedback interface. */
427 /* Clip Distances. */
429 /* Shared Memory Blocks. */
431 /* Max bind IDs. */
434 /* Whether GL position is used, or an alternative vertex output should be the default. */
436 /* Whether gl_FragColor is used, or whether an alternative fragment output
437 * should be the default. */
439 /* Whether gl_PointCoord is used in the fragment shader. If so,
440 * we define float2 gl_PointCoord [[point_coord]]. */
442 /* Writes out to gl_PointSize in the vertex shader output. */
449 /* Sets the output render target array index when using multilayered rendering. */
456 /* Compute shader global variables. */
463 /* Early fragment tests. */
465
466 /* Parameters. */
468
469 /* Bind index trackers. */
471
472 /* Shader buffer bind indices for argument buffers per shader stage.
473 * NOTE: Compute stage will re-use index 0. */
475
476 /*** SSBO Vertex fetch mode. ***/
477 /* Indicates whether to pass in Vertex Buffer's as a regular buffers instead of using vertex
478 * assembly in the PSO descriptor. Enabled with special pragma. */
480
481 private:
482 /* Parent shader instance. */
483 MTLShader &parent_shader_;
484
485 /* If prepared from Create info. */
486 const shader::ShaderCreateInfo *create_info_;
487
488 public:
489 MSLGeneratorInterface(MTLShader &shader) : parent_shader_(shader){};
490
493
494 /* When SSBO Vertex Fetch mode is used, uniforms are used to pass on the required information
495 * about vertex attribute bindings, in order to perform manual vertex assembly and random-access
496 * vertex lookup throughout the bound VBOs.
497 *
498 * Some parameters are global for the shader, others change with the currently bound
499 * VertexBuffers, and their format, as they do with regular gpu::Batch's.
500 *
501 * (Where ##attr is the attributes name)
502 * uniform_ssbo_stride_##attr -- Representing the stride between elements of attribute(attr)
503 * uniform_ssbo_offset_##attr -- Representing the base offset within the vertex
504 * uniform_ssbo_fetchmode_##attr -- Whether using per-vertex fetch or per-instance fetch
505 * (0=vert, 1=inst) uniform_ssbo_vbo_id_##attr -- index of the vertex buffer within which the
506 * data for this attribute is contained uniform_ssbo_type_##attr - The type of data in the
507 * currently bound buffer -- Could be a mismatch with the Officially reported type. */
509
510 /* Samplers. */
514
515 /* Returns the bind index, relative to
516 * MTL_uniform_buffer_base_index+MTL_storage_buffer_base_index. */
518
519 /* Code generation utility functions. */
520 std::string generate_msl_uniform_structs(ShaderStage shader_stage);
521 std::string generate_msl_vertex_in_struct();
522 std::string generate_msl_vertex_out_struct(ShaderStage shader_stage);
524 std::string generate_msl_fragment_struct(bool is_input);
528 std::string generate_msl_vertex_entry_stub();
542 std::string generate_msl_texture_vars(ShaderStage shader_stage);
543 void generate_msl_textures_input_string(std::stringstream &out,
545 bool &is_first_parameter);
546 void generate_msl_uniforms_input_string(std::stringstream &out,
548 bool &is_first_parameter);
549
550 /* Location is not always specified, so this will resolve outstanding locations. */
553
554 /* Create shader interface for converted GLSL shader. */
556 const shader::ShaderCreateInfo *info = nullptr);
557
558 /* Fetch combined shader source header. */
559 char *msl_patch_default_get();
560
561 MEM_CXX_CLASS_ALLOC_FUNCS("MSLGeneratorInterface");
562};
563
565{
566 switch (stage) {
568 return "MTLShaderVertexImpl";
570 return "MTLShaderFragmentImpl";
572 return "MTLShaderComputeImpl";
573 default:
575 return "";
576 }
577 return "";
578}
579
581{
582 switch (stage) {
584 return "vertex_shader_instance";
586 return "fragment_shader_instance";
588 return "compute_shader_instance";
589 default:
591 return "";
592 }
593 return "";
594}
595
596inline bool is_builtin_type(std::string type)
597{
598 /* Add Types as needed. */
599 /* TODO(Metal): Consider replacing this with a switch and `constexpr` hash and switch.
600 * Though most efficient and maintainable approach to be determined.
601 * NOTE: Some duplicate types exit for Metal and GLSL representations, as generated type-names
602 * from #shader::ShaderCreateInfo may use GLSL signature. */
603 static std::map<std::string, eMTLDataType> glsl_builtin_types = {
604 {"float", MTL_DATATYPE_FLOAT},
605 {"vec2", MTL_DATATYPE_FLOAT2},
606 {"vec3", MTL_DATATYPE_FLOAT3},
607 {"vec4", MTL_DATATYPE_FLOAT4},
608 {"int", MTL_DATATYPE_INT},
609 {"ivec2", MTL_DATATYPE_INT2},
610 {"ivec3", MTL_DATATYPE_INT3},
611 {"ivec4", MTL_DATATYPE_INT4},
612 {"int2", MTL_DATATYPE_INT2},
613 {"int3", MTL_DATATYPE_INT3},
614 {"int4", MTL_DATATYPE_INT4},
615 {"uint32_t", MTL_DATATYPE_UINT},
616 {"uvec2", MTL_DATATYPE_UINT2},
617 {"uvec3", MTL_DATATYPE_UINT3},
618 {"uvec4", MTL_DATATYPE_UINT4},
619 {"uint", MTL_DATATYPE_UINT},
620 {"uint2", MTL_DATATYPE_UINT2},
621 {"uint3", MTL_DATATYPE_UINT3},
622 {"uint4", MTL_DATATYPE_UINT4},
623 {"mat3", MTL_DATATYPE_FLOAT3x3},
624 {"mat4", MTL_DATATYPE_FLOAT4x4},
625 {"bool", MTL_DATATYPE_INT},
626 {"uchar", MTL_DATATYPE_UCHAR},
627 {"uchar2", MTL_DATATYPE_UCHAR2},
628 {"uchar2", MTL_DATATYPE_UCHAR3},
629 {"uchar4", MTL_DATATYPE_UCHAR4},
630 {"vec3_1010102_Unorm", MTL_DATATYPE_UINT1010102_NORM},
631 {"vec3_1010102_Inorm", MTL_DATATYPE_INT1010102_NORM},
632 };
633 return (glsl_builtin_types.find(type) != glsl_builtin_types.end());
634}
635
636inline bool is_matrix_type(const std::string &type)
637{
638 /* Matrix type support. Add types as necessary. */
639 return (type == "mat4");
640}
641
642inline bool is_matrix_type(const shader::Type &type)
643{
644 /* Matrix type support. Add types as necessary. */
645 return (type == shader::Type::MAT4 || type == shader::Type::MAT3);
646}
647
648inline int get_matrix_location_count(const std::string &type)
649{
650 /* Matrix type support. Add types as necessary. */
651 if (type == "mat4") {
652 return 4;
653 }
654 if (type == "mat3") {
655 return 3;
656 }
657 return 1;
658}
659
661{
662 /* Matrix type support. Add types as necessary. */
663 if (type == shader::Type::MAT4) {
664 return 4;
665 }
666 else if (type == shader::Type::MAT3) {
667 return 3;
668 }
669 return 1;
670}
671
672inline std::string get_matrix_subtype(const std::string &type)
673{
674 if (type == "mat4") {
675 return "vec4";
676 }
677 return type;
678}
679
681{
682 if (type == shader::Type::MAT4) {
683 return shader::Type::VEC4;
684 }
685 if (type == shader::Type::MAT3) {
686 return shader::Type::VEC3;
687 }
688 return type;
689}
690
691inline std::string get_attribute_conversion_function(bool *uses_conversion,
692 const shader::Type &type)
693{
694 /* NOTE(Metal): Add more attribute types as required. */
695 if (type == shader::Type::FLOAT) {
696 *uses_conversion = true;
697 return "internal_vertex_attribute_convert_read_float";
698 }
699 else if (type == shader::Type::VEC2) {
700 *uses_conversion = true;
701 return "internal_vertex_attribute_convert_read_float2";
702 }
703 else if (type == shader::Type::VEC3) {
704 *uses_conversion = true;
705 return "internal_vertex_attribute_convert_read_float3";
706 }
707 else if (type == shader::Type::VEC4) {
708 *uses_conversion = true;
709 return "internal_vertex_attribute_convert_read_float4";
710 }
711 *uses_conversion = false;
712 return "";
713}
714
715inline const char *to_string(const shader::PrimitiveOut &layout)
716{
717 switch (layout) {
719 return "points";
721 return "line_strip";
723 return "triangle_strip";
724 default:
725 BLI_assert(false);
726 return "unknown";
727 }
728}
729
730inline const char *to_string(const shader::PrimitiveIn &layout)
731{
732 switch (layout) {
734 return "points";
736 return "lines";
738 return "lines_adjacency";
740 return "triangles";
742 return "triangles_adjacency";
743 default:
744 BLI_assert(false);
745 return "unknown";
746 }
747}
748
749inline const char *to_string(const shader::Interpolation &interp)
750{
751 switch (interp) {
753 return "smooth";
755 return "flat";
757 return "noperspective";
758 default:
759 BLI_assert(false);
760 return "unkown";
761 }
762}
763
765{
766 switch (interp) {
768 return "[[center_perspective]]";
770 return "[[flat]]";
772 return "[[center_no_perspective]]";
773 default:
774 return "";
775 }
776}
777
778inline const char *to_string(const shader::Type &type)
779{
780 switch (type) {
782 return "float";
784 return "vec2";
786 return "vec3";
788 return "vec3_1010102_Inorm";
790 return "vec4";
792 return "mat3";
794 return "mat4";
796 return "uint32_t";
798 return "uvec2";
800 return "uvec3";
802 return "uvec4";
804 return "int";
806 return "ivec2";
808 return "ivec3";
810 return "ivec4";
812 return "bool";
814 return "uchar";
816 return "uchar2";
818 return "uchar3";
820 return "uchar4";
822 return "char";
824 return "char2";
826 return "char3";
828 return "char4";
830 return "ushort";
832 return "ushort2";
834 return "ushort3";
836 return "ushort4";
838 return "short";
840 return "short2";
842 return "short3";
844 return "short4";
845 default:
846 BLI_assert(false);
847 return "unkown";
848 }
849}
850
851inline char *next_symbol_in_range(char *begin, char *end, char symbol)
852{
853 for (char *a = begin; a < end; a++) {
854 if (*a == symbol) {
855 return a;
856 }
857 }
858 return nullptr;
859}
860
861inline char *next_word_in_range(char *begin, char *end)
862{
863 for (char *a = begin; a < end; a++) {
864 char chr = *a;
865 if ((chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') ||
866 (chr == '_'))
867 {
868 return a;
869 }
870 }
871 return nullptr;
872}
873
874} // namespace blender::gpu
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
unsigned int uint
std::string generate_msl_texture_vars(ShaderStage shader_stage)
std::string generate_msl_uniform_structs(ShaderStage shader_stage)
std::string generate_msl_global_uniform_population(ShaderStage stage)
MEM_CXX_CLASS_ALLOC_FUNCS("MSLGeneratorInterface")
blender::Vector< MSLBufferBlock > uniform_blocks
blender::Vector< MSLBufferBlock > storage_blocks
std::string generate_msl_uniform_block_population(ShaderStage stage)
blender::Vector< MSLFragmentTileInputAttribute > fragment_tile_inputs
std::string generate_msl_vertex_transform_feedback_out_struct(ShaderStage shader_stage)
blender::Vector< MSLVertexOutputAttribute > fragment_input_varyings
blender::Vector< MSLVertexOutputAttribute > vertex_output_varyings
uint32_t get_sampler_argument_buffer_bind_index(ShaderStage stage)
blender::Vector< MSLTextureResource > texture_samplers
blender::Vector< MSLVertexInputAttribute > vertex_input_attributes
std::string generate_msl_fragment_struct(bool is_input)
std::string generate_msl_uniform_undefs(ShaderStage stage)
void prepare_from_createinfo(const shader::ShaderCreateInfo *info)
std::string generate_ubo_block_undef_chain(ShaderStage stage)
uint32_t max_sampler_index_for_stage(ShaderStage stage) const
blender::Vector< MSLConstant > constants
std::string generate_msl_vertex_out_struct(ShaderStage shader_stage)
uint32_t num_samplers_for_stage(ShaderStage stage) const
void generate_msl_uniforms_input_string(std::stringstream &out, ShaderStage stage, bool &is_first_parameter)
blender::Vector< MSLFragmentOutputAttribute > fragment_outputs
std::string generate_ubo_block_macro_chain(MSLBufferBlock block)
blender::Vector< MSLVertexOutputAttribute > vertex_output_varyings_tf
MTLShaderInterface * bake_shader_interface(const char *name, const shader::ShaderCreateInfo *info=nullptr)
void generate_msl_textures_input_string(std::stringstream &out, ShaderStage stage, bool &is_first_parameter)
blender::Vector< MSLSharedMemoryBlock > shared_memory_blocks
blender::Vector< MSLUniform > uniforms
EvaluationStage stage
Definition deg_eval.cc:83
#define str(s)
ccl_device_inline float2 interp(const float2 a, const float2 b, float t)
@ MTL_DATATYPE_INT1010102_NORM
@ MTL_DATATYPE_UINT1010102_NORM
char * next_word_in_range(char *begin, char *end)
const char * to_string(ShaderStage stage)
Definition mtl_shader.mm:52
bool is_matrix_type(const std::string &type)
const char * get_shader_stage_instance_name(ShaderStage stage)
const char * to_string_msl(const shader::Interpolation &interp)
const char * get_stage_class_name(ShaderStage stage)
int get_matrix_location_count(const std::string &type)
std::string get_matrix_subtype(const std::string &type)
std::string get_attribute_conversion_function(bool *uses_conversion, const shader::Type &type)
bool is_builtin_type(std::string type)
char * next_symbol_in_range(char *begin, char *end, char symbol)
unsigned int uint32_t
Definition stdint.h:80
bool operator==(const MSLBufferBlock &right) const
MSLConstant(shader::Type const_type, std::string const_name)
bool operator==(const MSLFragmentOutputAttribute &right) const
eGPUSamplerFormat get_sampler_format() const
bool operator==(const MSLTextureResource &right) const
std::string get_msl_typestring_wrapper(bool is_addr) const
eGPUTextureType get_texture_binding_type() const
std::string get_msl_typestring(bool is_addr) const
bool operator==(const MSLUniform &right) const
MSLUniform(shader::Type uniform_type, std::string uniform_name, bool is_array_type, uint32_t num_elems=1)
bool operator==(const MSLVertexInputAttribute &right) const
bool operator==(const MSLVertexOutputAttribute &right) const
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...