Blender V5.0
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
11
127
128namespace blender::gpu {
129
132 std::string name;
136
138 std::string uniform_name,
139 bool is_array_type,
140 uint32_t num_elems = 1)
141 : type(uniform_type), name(uniform_name), is_array(is_array_type), array_elems(num_elems)
142 {
143 }
144
145 bool operator==(const MSLUniform &right) const
146 {
147 return (type == right.type && name == right.name && is_array == right.is_array &&
148 array_elems == right.array_elems);
149 }
150};
151
154 std::string name;
155
156 MSLConstant(shader::Type const_type, std::string const_name) : type(const_type), name(const_name)
157 {
158 }
159};
160
162 std::string type_name;
163 std::string name;
166 /* Resource index in buffer. */
170 /* Flag for use with texture atomic fallback. */
171 bool is_texture_buffer = false;
172
173 bool operator==(const MSLBufferBlock &right) const
174 {
175 return (type_name == right.type_name && name == right.name);
176 }
177};
178
186
190 std::string name;
192 /* Whether resource is a texture sampler or an image. */
194 /* Index in shader bind table `[[texture(N)]]`. */
196 /* Explicit bind index provided by ShaderCreateInfo. */
198
199 /* Atomic fallback buffer information. */
201
204
206
207 bool operator==(const MSLTextureResource &right) const
208 {
209 /* We do not compare stage as we want to avoid duplication of resources used across multiple
210 * stages. */
211 return (type == right.type && name == right.name && access == right.access);
212 }
213
214 std::string get_msl_access_str() const
215 {
216 switch (access) {
218 return "access::sample";
220 return "access::read";
222 return "access::write";
224 return "access::read_write";
225 default:
226 BLI_assert(false);
227 return "";
228 }
229 return "";
230 }
231
232 /* Get typestring for wrapped texture class members.
233 * wrapper struct type contains combined texture and sampler, templated
234 * against the texture type.
235 * See `COMBINED_SAMPLER_TYPE` in `mtl_shader_defines.msl`. */
236 std::string get_msl_typestring_wrapper(bool is_addr) const
237 {
238 std::string str;
239 str = this->get_msl_wrapper_type_str() + "<" + this->get_msl_return_type_str() + "," +
240 this->get_msl_access_str() + ">" + ((is_addr) ? "* " : " ") + this->name;
241 return str;
242 }
243
244 /* Get raw texture typestring -- used in entry-point function argument table. */
245 std::string get_msl_typestring(bool is_addr) const
246 {
247 std::string str;
248 str = this->get_msl_texture_type_str() + "<" + this->get_msl_return_type_str() + "," +
249 this->get_msl_access_str() + ">" + ((is_addr) ? "* " : " ") + this->name;
250 return str;
251 }
252
253 std::string get_msl_return_type_str() const;
254 std::string get_msl_texture_type_str() const;
255 std::string get_msl_wrapper_type_str() const;
256};
257
259 /* layout_location of -1 means unspecified and will
260 * be populated manually. */
263 std::string name;
264
265 bool operator==(const MSLVertexInputAttribute &right) const
266 {
267 return (layout_location == right.layout_location && type == right.type && name == right.name);
268 }
269};
270
272 std::string type;
273 std::string name;
274 /* Instance name specified if attributes belong to a struct. */
275 std::string instance_name;
276 /* Interpolation qualifier can be any of smooth (default), flat, no_perspective. */
280
281 bool operator==(const MSLVertexOutputAttribute &right) const
282 {
283 return (type == right.type && name == right.name &&
285 is_array == right.is_array && array_elems == right.array_elems);
286 }
288 {
289 if (interpolation_qualifier.empty() || interpolation_qualifier == "smooth") {
290 return "";
291 }
292 if (interpolation_qualifier == "flat") {
293 return " [[flat]]";
294 }
295 if (interpolation_qualifier == "noperspective") {
296 return " [[center_no_perspective]]";
297 }
298 return "";
299 }
300};
301
303 /* Explicit output binding location N for [[color(N)]] -1 = unspecified. */
305 /* Output index for dual source blending. -1 = unspecified. */
308 std::string name;
309 /* Raster order group can be specified to synchronize pixel read and write operations between
310 * subsequent draws. If a subsequent draw requires reading data from a GBuffer, raster order
311 * groups should be used to ensure all writes occur before reading. */
313 /* Used for lack of ROG support workaround. */
315
316 bool operator==(const MSLFragmentOutputAttribute &right) const
317 {
318 return (layout_location == right.layout_location && type == right.type && name == right.name &&
320 }
321};
322
323/* Fragment tile inputs match fragment output attribute layout. */
325
327 /* e.g. `shared vec4 color_cache[cache_size][cache_size];`. */
328 std::string type_name;
329 std::string varname;
331 std::string array_decl; /* String containing array declaration. e.g. [cache_size][cache_size]. */
332};
333
335 static char *msl_patch_default;
336
337 public:
346 /* Specialization Constants. */
348 /* Fragment tile inputs. */
350 /* Should match vertex outputs, but defined separately as
351 * some shader permutations will not utilize all inputs/outputs.
352 * Final shader uses the intersection between the two sets. */
355 /* Clip Distances. */
357 /* Max bind IDs. */
360 /* Whether GL position is used, or an alternative vertex output should be the default. */
362 /* Whether gl_FragColor is used, or whether an alternative fragment output
363 * should be the default. */
365 /* Whether gl_PointCoord is used in the fragment shader. If so,
366 * we define float2 gl_PointCoord [[point_coord]]. */
368 /* Writes out to gl_PointSize in the vertex shader output. */
375 /* Sets the output render target array index when using multilayered rendering. */
381 /* Compute shader global variables. */
388 /* Early fragment tests. */
390
391 /* Parameters. */
393
394 /* Bind index trackers. */
396
397 /* Shader buffer bind indices for argument buffers per shader stage.
398 * NOTE: Compute stage will re-use index 0. */
400
401 private:
402 /* Parent shader instance. */
403 MTLShader &parent_shader_;
404
405 /* If prepared from Create info. */
406 const shader::ShaderCreateInfo *create_info_;
407
408 public:
410
413
414 /* Samplers. */
416 uint32_t num_samplers_for_stage(ShaderStage stage) const;
417 uint32_t max_sampler_index_for_stage(ShaderStage stage) const;
418
419 /* Returns the bind index, relative to
420 * MTL_uniform_buffer_base_index+MTL_storage_buffer_base_index. */
422
423 /* Code generation utility functions. */
424 std::string generate_msl_uniform_structs(ShaderStage shader_stage);
425 std::string generate_msl_vertex_in_struct();
426 std::string generate_msl_vertex_out_struct(ShaderStage shader_stage);
427 std::string generate_msl_fragment_struct(bool is_input);
431 std::string generate_msl_vertex_entry_stub();
442 std::string generate_msl_uniform_undefs(ShaderStage stage);
444 std::string generate_msl_texture_vars(ShaderStage shader_stage);
445 void generate_msl_textures_input_string(std::stringstream &out,
446 ShaderStage stage,
447 bool &is_first_parameter);
448 void generate_msl_uniforms_input_string(std::stringstream &out,
449 ShaderStage stage,
450 bool &is_first_parameter);
451
452 /* Location is not always specified, so this will resolve outstanding locations. */
455
456 /* Create shader interface for converted GLSL shader. */
458 const shader::ShaderCreateInfo *info = nullptr);
459
460 /* Fetch combined shader source header. */
461 char *msl_patch_default_get();
462
463 MEM_CXX_CLASS_ALLOC_FUNCS("MSLGeneratorInterface");
464};
465
466inline const char *get_stage_class_name(ShaderStage stage)
467{
468 switch (stage) {
470 return "MTLShaderVertexImpl";
472 return "MTLShaderFragmentImpl";
474 return "MTLShaderComputeImpl";
475 default:
477 return "";
478 }
479 return "";
480}
481
483{
484 switch (stage) {
486 return "vertex_shader_instance";
488 return "fragment_shader_instance";
490 return "compute_shader_instance";
491 default:
493 return "";
494 }
495 return "";
496}
497
498inline bool is_builtin_type(std::string type)
499{
500 /* Add Types as needed. */
501 /* TODO(Metal): Consider replacing this with a switch and `constexpr` hash and switch.
502 * Though most efficient and maintainable approach to be determined.
503 * NOTE: Some duplicate types exit for Metal and GLSL representations, as generated type-names
504 * from #shader::ShaderCreateInfo may use GLSL signature. */
505 static std::map<std::string, MTLInterfaceDataType> glsl_builtin_types = {
506 {"float", MTL_DATATYPE_FLOAT},
507 {"vec2", MTL_DATATYPE_FLOAT2},
508 {"vec3", MTL_DATATYPE_FLOAT3},
509 {"vec4", MTL_DATATYPE_FLOAT4},
510 {"float2", MTL_DATATYPE_FLOAT2},
511 {"float3", MTL_DATATYPE_FLOAT3},
512 {"float4", MTL_DATATYPE_FLOAT4},
513 {"int", MTL_DATATYPE_INT},
514 {"ivec2", MTL_DATATYPE_INT2},
515 {"ivec3", MTL_DATATYPE_INT3},
516 {"ivec4", MTL_DATATYPE_INT4},
517 {"int2", MTL_DATATYPE_INT2},
518 {"int3", MTL_DATATYPE_INT3},
519 {"int4", MTL_DATATYPE_INT4},
520 {"uint32_t", MTL_DATATYPE_UINT},
521 {"uvec2", MTL_DATATYPE_UINT2},
522 {"uvec3", MTL_DATATYPE_UINT3},
523 {"uvec4", MTL_DATATYPE_UINT4},
524 {"uint", MTL_DATATYPE_UINT},
525 {"uint2", MTL_DATATYPE_UINT2},
526 {"uint3", MTL_DATATYPE_UINT3},
527 {"uint4", MTL_DATATYPE_UINT4},
528 {"mat3", MTL_DATATYPE_FLOAT3x3},
529 {"mat4", MTL_DATATYPE_FLOAT4x4},
530 {"float3x3", MTL_DATATYPE_FLOAT3x3},
531 {"float4x4", MTL_DATATYPE_FLOAT4x4},
532 {"bool", MTL_DATATYPE_INT},
533 {"uchar", MTL_DATATYPE_UCHAR},
534 {"uchar2", MTL_DATATYPE_UCHAR2},
535 {"uchar2", MTL_DATATYPE_UCHAR3},
536 {"uchar4", MTL_DATATYPE_UCHAR4},
537 {"vec3_1010102_Unorm", MTL_DATATYPE_UINT1010102_NORM},
538 {"vec3_1010102_Inorm", MTL_DATATYPE_INT1010102_NORM},
539 {"packed_float2", MTL_DATATYPE_PACKED_FLOAT2},
540 {"packed_float3", MTL_DATATYPE_PACKED_FLOAT3},
541 };
542 return (glsl_builtin_types.find(type) != glsl_builtin_types.end());
543}
544
545inline bool is_matrix_type(const std::string &type)
546{
547 /* Matrix type support. Add types as necessary. */
548 return (type == "mat4");
549}
550
551inline bool is_matrix_type(const shader::Type &type)
552{
553 /* Matrix type support. Add types as necessary. */
554 return (type == shader::Type::float4x4_t || type == shader::Type::float3x3_t);
555}
556
557inline int get_matrix_location_count(const std::string &type)
558{
559 /* Matrix type support. Add types as necessary. */
560 if (type == "mat4") {
561 return 4;
562 }
563 if (type == "mat3") {
564 return 3;
565 }
566 return 1;
567}
568
570{
571 /* Matrix type support. Add types as necessary. */
572 if (type == shader::Type::float4x4_t) {
573 return 4;
574 }
575 if (type == shader::Type::float3x3_t) {
576 return 3;
577 }
578 return 1;
579}
580
581inline std::string get_matrix_subtype(const std::string &type)
582{
583 if (type == "mat4") {
584 return "vec4";
585 }
586 return type;
587}
588
590{
591 if (type == shader::Type::float4x4_t) {
593 }
594 if (type == shader::Type::float3x3_t) {
596 }
597 return type;
598}
599
600inline std::string get_attribute_conversion_function(bool *uses_conversion,
601 const shader::Type &type)
602{
603 /* NOTE(Metal): Add more attribute types as required. */
604 if (type == shader::Type::float_t) {
605 *uses_conversion = true;
606 return "internal_vertex_attribute_convert_read_float";
607 }
608 if (type == shader::Type::float2_t) {
609 *uses_conversion = true;
610 return "internal_vertex_attribute_convert_read_float2";
611 }
612 if (type == shader::Type::float3_t) {
613 *uses_conversion = true;
614 return "internal_vertex_attribute_convert_read_float3";
615 }
616 if (type == shader::Type::float4_t) {
617 *uses_conversion = true;
618 return "internal_vertex_attribute_convert_read_float4";
619 }
620 *uses_conversion = false;
621 return "";
622}
623
624inline const char *to_string(const shader::PrimitiveOut &layout)
625{
626 switch (layout) {
628 return "points";
630 return "line_strip";
632 return "triangle_strip";
633 default:
634 BLI_assert(false);
635 return "unknown";
636 }
637}
638
639inline const char *to_string(const shader::PrimitiveIn &layout)
640{
641 switch (layout) {
643 return "points";
645 return "lines";
647 return "lines_adjacency";
649 return "triangles";
651 return "triangles_adjacency";
652 default:
653 BLI_assert(false);
654 return "unknown";
655 }
656}
657
658inline const char *to_string(const shader::Interpolation &interp)
659{
660 switch (interp) {
662 return "smooth";
664 return "flat";
666 return "noperspective";
667 default:
668 BLI_assert(false);
669 return "unknown";
670 }
671}
672
674{
675 switch (interp) {
677 return "[[center_perspective]]";
679 return "[[flat]]";
681 return "[[center_no_perspective]]";
682 default:
683 return "";
684 }
685}
686
687inline const char *to_string(const shader::Type &type)
688{
689 switch (type) {
691 return "float";
693 return "vec2";
695 return "vec3";
697 return "vec3_1010102_Inorm";
699 return "vec4";
701 return "mat3";
703 return "mat4";
705 return "uint32_t";
707 return "uvec2";
709 return "uvec3";
711 return "uvec4";
713 return "int";
715 return "ivec2";
717 return "ivec3";
719 return "ivec4";
721 return "bool";
723 return "uchar";
725 return "uchar2";
727 return "uchar3";
729 return "uchar4";
731 return "char";
733 return "char2";
735 return "char3";
737 return "char4";
739 return "ushort";
741 return "ushort2";
743 return "ushort3";
745 return "ushort4";
747 return "short";
749 return "short2";
751 return "short3";
753 return "short4";
754 default:
755 BLI_assert(false);
756 return "unknown";
757 }
758}
759
760inline char *next_symbol_in_range(char *begin, const char *end, char symbol)
761{
762 for (char *a = begin; a < end; a++) {
763 if (*a == symbol) {
764 return a;
765 }
766 }
767 return nullptr;
768}
769
770inline char *next_word_in_range(char *begin, const char *end)
771{
772 for (char *a = begin; a < end; a++) {
773 char chr = *a;
774 if ((chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') ||
775 (chr == '_'))
776 {
777 return a;
778 }
779 }
780 return nullptr;
781}
782
783} // namespace blender::gpu
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
unsigned int uint
iter begin(iter)
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
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)
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< MSLUniform > uniforms
std::string generate_msl_compute_entry_stub(const shader::ShaderCreateInfo &info)
#define str(s)
#define out
ccl_device_inline float interp(const float a, const float b, const float t)
Definition math_base.h:502
@ MTL_DATATYPE_INT1010102_NORM
@ MTL_DATATYPE_PACKED_FLOAT2
@ MTL_DATATYPE_UINT1010102_NORM
@ MTL_DATATYPE_PACKED_FLOAT3
const char * to_string(ShaderStage stage)
Definition mtl_shader.mm:51
bool is_matrix_type(const std::string &type)
MSLFragmentOutputAttribute MSLFragmentTileInputAttribute
char * next_word_in_range(char *begin, const char *end)
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)
char * next_symbol_in_range(char *begin, const char *end, char symbol)
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)
const char * name
bool operator==(const MSLBufferBlock &right) const
MSLConstant(shader::Type const_type, std::string const_name)
bool operator==(const MSLFragmentOutputAttribute &right) const
bool operator==(const MSLTextureResource &right) const
std::string get_msl_typestring_wrapper(bool is_addr) const
GPUTextureType get_texture_binding_type() const
GPUSamplerFormat get_sampler_format() 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...