Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/metal/mtl_shader_generator.mm
| Show First 20 Lines • Show All 330 Lines • ▼ Show 20 Lines | static bool extract_ssbo_pragma_info(const MTLShader *shader, | ||||
| const MSLGeneratorInterface &, | const MSLGeneratorInterface &, | ||||
| const std::string &in_vertex_src, | const std::string &in_vertex_src, | ||||
| MTLPrimitiveType &out_prim_tye, | MTLPrimitiveType &out_prim_tye, | ||||
| uint32_t &out_num_output_verts) | uint32_t &out_num_output_verts) | ||||
| { | { | ||||
| /* SSBO Vertex-fetch parameter extraction. */ | /* SSBO Vertex-fetch parameter extraction. */ | ||||
| static std::regex use_ssbo_fetch_mode_find( | static std::regex use_ssbo_fetch_mode_find( | ||||
| "#pragma " | "#pragma " | ||||
| "USE_SSBO_VERTEX_FETCH\\(\\s*(TriangleList|LineList|\\w+)\\s*,\\s*([0-9]+)\\s*\\)"); | "USE_SSBO_VERTEX_FETCH\\(\\s*(TriangleList|LineList|TriangleStrip|\\w+)\\s*,\\s*([0-9]+)\\s*" | ||||
| "\\)"); | |||||
| /* Perform regex search if pragma string found. */ | /* Perform regex search if pragma string found. */ | ||||
| std::smatch vertex_shader_ssbo_flags; | std::smatch vertex_shader_ssbo_flags; | ||||
| bool uses_ssbo_fetch = false; | bool uses_ssbo_fetch = false; | ||||
| if (in_vertex_src.find("#pragma USE_SSBO_VERTEX_FETCH") != std::string::npos) { | if (in_vertex_src.find("#pragma USE_SSBO_VERTEX_FETCH") != std::string::npos) { | ||||
| uses_ssbo_fetch = std::regex_search( | uses_ssbo_fetch = std::regex_search( | ||||
| in_vertex_src, vertex_shader_ssbo_flags, use_ssbo_fetch_mode_find); | in_vertex_src, vertex_shader_ssbo_flags, use_ssbo_fetch_mode_find); | ||||
| } | } | ||||
| if (uses_ssbo_fetch) { | if (uses_ssbo_fetch) { | ||||
| /* Extract Expected output primitive type: | /* Extract Expected output primitive type: | ||||
| * #pragma USE_SSBO_VERTEX_FETCH(Output Prim Type, num output vertices per input primitive) | * #pragma USE_SSBO_VERTEX_FETCH(Output Prim Type, num output vertices per input primitive) | ||||
| * | * | ||||
| * Supported Primitive Types (Others can be added if needed, but List types for efficiency): | * Supported Primitive Types (Others can be added if needed, but List types for efficiency): | ||||
| * - TriangleList | * - TriangleList | ||||
| * - LineList | * - LineList | ||||
| * - TriangleStrip (To be used with caution). | |||||
| * | * | ||||
| * Output vertex count is determined by calculating the number of input primitives, and | * Output vertex count is determined by calculating the number of input primitives, and | ||||
| * multiplying that by the number of output vertices specified. */ | * multiplying that by the number of output vertices specified. */ | ||||
| std::string str_output_primitive_type = vertex_shader_ssbo_flags[1].str(); | std::string str_output_primitive_type = vertex_shader_ssbo_flags[1].str(); | ||||
| std::string str_output_prim_count_per_vertex = vertex_shader_ssbo_flags[2].str(); | std::string str_output_prim_count_per_vertex = vertex_shader_ssbo_flags[2].str(); | ||||
| /* Ensure output primitive type is valid. */ | /* Ensure output primitive type is valid. */ | ||||
| if (str_output_primitive_type == "TriangleList") { | if (str_output_primitive_type == "TriangleList") { | ||||
| out_prim_tye = MTLPrimitiveTypeTriangle; | out_prim_tye = MTLPrimitiveTypeTriangle; | ||||
| } | } | ||||
| else if (str_output_primitive_type == "LineList") { | else if (str_output_primitive_type == "LineList") { | ||||
| out_prim_tye = MTLPrimitiveTypeLine; | out_prim_tye = MTLPrimitiveTypeLine; | ||||
| } | } | ||||
| else if (str_output_primitive_type == "TriangleStrip") { | |||||
| out_prim_tye = MTLPrimitiveTypeTriangleStrip; | |||||
| } | |||||
| else { | else { | ||||
| MTL_LOG_ERROR("Unsupported output primitive type for SSBO VERTEX FETCH MODE. Shader: %s", | MTL_LOG_ERROR("Unsupported output primitive type for SSBO VERTEX FETCH MODE. Shader: %s", | ||||
| shader->name_get()); | shader->name_get()); | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Assign output num vertices per primitive. */ | /* Assign output num vertices per primitive. */ | ||||
| out_num_output_verts = std::stoi( | out_num_output_verts = std::stoi( | ||||
| ▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info) | ||||
| msl_iface.prepare_from_createinfo(info); | msl_iface.prepare_from_createinfo(info); | ||||
| /* Verify Source sizes are greater than zero. */ | /* Verify Source sizes are greater than zero. */ | ||||
| BLI_assert(shd_builder_->glsl_vertex_source_.size() > 0); | BLI_assert(shd_builder_->glsl_vertex_source_.size() > 0); | ||||
| if (!msl_iface.uses_transform_feedback) { | if (!msl_iface.uses_transform_feedback) { | ||||
| BLI_assert(shd_builder_->glsl_fragment_source_.size() > 0); | BLI_assert(shd_builder_->glsl_fragment_source_.size() > 0); | ||||
| } | } | ||||
| /** Determine use of Transform Feedback. **/ | |||||
| msl_iface.uses_transform_feedback = false; | |||||
| if (transform_feedback_type_ != GPU_SHADER_TFB_NONE) { | if (transform_feedback_type_ != GPU_SHADER_TFB_NONE) { | ||||
| /* Ensure #TransformFeedback is configured correctly. */ | /* Ensure #TransformFeedback is configured correctly. */ | ||||
| BLI_assert(tf_output_name_list_.size() > 0); | BLI_assert(tf_output_name_list_.size() > 0); | ||||
| msl_iface.uses_transform_feedback = true; | msl_iface.uses_transform_feedback = true; | ||||
| } | } | ||||
| /* Concatenate msl_shader_defines to provide functionality mapping | /* Concatenate msl_shader_defines to provide functionality mapping | ||||
| * from GLSL to MSL. Also include additional GPU defines for | * from GLSL to MSL. Also include additional GPU defines for | ||||
| ▲ Show 20 Lines • Show All 697 Lines • ▼ Show 20 Lines | for (const ShaderCreateInfo::Resource &res : resources) { | ||||
| } | } | ||||
| else if (bool(res.image.qualifiers & Qualifier::WRITE)) { | else if (bool(res.image.qualifiers & Qualifier::WRITE)) { | ||||
| access = MSLTextureSamplerAccess::TEXTURE_ACCESS_WRITE; | access = MSLTextureSamplerAccess::TEXTURE_ACCESS_WRITE; | ||||
| } | } | ||||
| else { | else { | ||||
| access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READ; | access = MSLTextureSamplerAccess::TEXTURE_ACCESS_READ; | ||||
| } | } | ||||
| BLI_assert(used_slot >= 0 && used_slot < MTL_MAX_TEXTURE_SLOTS); | BLI_assert(used_slot >= 0 && used_slot < MTL_MAX_TEXTURE_SLOTS); | ||||
| /* Writeable image targets only assigned to Fragment shader. */ | |||||
| MSLTextureSampler msl_tex( | MSLTextureSampler msl_tex( | ||||
| ShaderStage::BOTH, res.image.type, res.image.name, access, used_slot); | ShaderStage::FRAGMENT, res.image.type, res.image.name, access, used_slot); | ||||
| texture_samplers.append(msl_tex); | texture_samplers.append(msl_tex); | ||||
| } break; | } break; | ||||
| case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: { | case shader::ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER: { | ||||
| MSLUniformBlock ubo; | MSLUniformBlock ubo; | ||||
| BLI_assert(res.uniformbuf.type_name.size() > 0); | BLI_assert(res.uniformbuf.type_name.size() > 0); | ||||
| BLI_assert(res.uniformbuf.name.size() > 0); | BLI_assert(res.uniformbuf.name.size() > 0); | ||||
| int64_t array_offset = res.uniformbuf.name.find_first_of("["); | int64_t array_offset = res.uniformbuf.name.find_first_of("["); | ||||
| ▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | for (const shader::ShaderCreateInfo::FragOut &frag_out : create_info_->fragment_outputs_) { | ||||
| mtl_frag_out.layout_index = (frag_out.blend != DualBlend::NONE) ? | mtl_frag_out.layout_index = (frag_out.blend != DualBlend::NONE) ? | ||||
| ((frag_out.blend == DualBlend::SRC_0) ? 0 : 1) : | ((frag_out.blend == DualBlend::SRC_0) ? 0 : 1) : | ||||
| -1; | -1; | ||||
| mtl_frag_out.type = frag_out.type; | mtl_frag_out.type = frag_out.type; | ||||
| mtl_frag_out.name = frag_out.name; | mtl_frag_out.name = frag_out.name; | ||||
| fragment_outputs.append(mtl_frag_out); | fragment_outputs.append(mtl_frag_out); | ||||
| } | } | ||||
| /* Transform feedback. */ | |||||
| uses_transform_feedback = (create_info_->tf_type_ != GPU_SHADER_TFB_NONE) && | |||||
| (create_info_->tf_names_.size() > 0); | |||||
| } | } | ||||
| bool MSLGeneratorInterface::use_argument_buffer_for_samplers() const | bool MSLGeneratorInterface::use_argument_buffer_for_samplers() const | ||||
| { | { | ||||
| /* We can only use argument buffers IF sampler count exceeds static limit of 16, | /* We can only use argument buffers IF sampler count exceeds static limit of 16, | ||||
| * AND we can support more samplers with an argument buffer. */ | * AND we can support more samplers with an argument buffer. */ | ||||
| return texture_samplers.size() >= 16 && GPU_max_samplers() > 16; | return texture_samplers.size() >= 16 && GPU_max_samplers() > 16; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | #endif | ||||
| /* Copy vertex attributes into local variable.s */ | /* Copy vertex attributes into local variable.s */ | ||||
| out << this->generate_msl_fragment_input_population(); | out << this->generate_msl_fragment_input_population(); | ||||
| /* Barycentrics. */ | /* Barycentrics. */ | ||||
| if (this->uses_barycentrics) { | if (this->uses_barycentrics) { | ||||
| /* Main barycentrics. */ | /* Main barycentrics. */ | ||||
| out << "fragment_shader_instance.gpu_BaryCoord = mtl_barycentric_coord.xyz;"; | out << "fragment_shader_instance.gpu_BaryCoord = mtl_barycentric_coord.xyz;" << std::endl; | ||||
| /* barycentricDist represents the world-space distance from the current world-space position | /* barycentricDist represents the world-space distance from the current world-space position | ||||
| * to the opposite edge of the vertex. */ | * to the opposite edge of the vertex. */ | ||||
| out << "float3 worldPos = fragment_shader_instance.worldPosition.xyz;" << std::endl; | out << "float3 worldPos = fragment_shader_instance.worldPosition.xyz;" << std::endl; | ||||
| out << "float3 wpChange = (length(dfdx(worldPos))+length(dfdy(worldPos)));" << std::endl; | out << "float3 wpChange = (length(dfdx(worldPos))+length(dfdy(worldPos)));" << std::endl; | ||||
| out << "float3 bcChange = " | out << "float3 bcChange = " | ||||
| "(length(dfdx(mtl_barycentric_coord))+length(dfdy(mtl_barycentric_coord)));" | "(length(dfdx(mtl_barycentric_coord))+length(dfdy(mtl_barycentric_coord)));" | ||||
| << std::endl; | << std::endl; | ||||
| ▲ Show 20 Lines • Show All 850 Lines • ▼ Show 20 Lines | if (bool(this->texture_samplers[i].stage & shader_stage)) { | ||||
| << this->texture_samplers[i].name << ".texture = &" << this->texture_samplers[i].name | << this->texture_samplers[i].name << ".texture = &" << this->texture_samplers[i].name | ||||
| << ";" << std::endl; | << ";" << std::endl; | ||||
| /* Assign sampler reference. */ | /* Assign sampler reference. */ | ||||
| if (this->use_argument_buffer_for_samplers()) { | if (this->use_argument_buffer_for_samplers()) { | ||||
| out << "\t" | out << "\t" | ||||
| << ((shader_stage == ShaderStage::VERTEX) ? "vertex_shader_instance." : | << ((shader_stage == ShaderStage::VERTEX) ? "vertex_shader_instance." : | ||||
| "fragment_shader_instance.") | "fragment_shader_instance.") | ||||
| << this->texture_samplers[i].name << ".samp = &samplers.sampler_args[" << i << "];" | << this->texture_samplers[i].name << ".samp = &samplers.sampler_args[" | ||||
| << std::endl; | << this->texture_samplers[i].location << "];" << std::endl; | ||||
| } | } | ||||
| else { | else { | ||||
| out << "\t" | out << "\t" | ||||
| << ((shader_stage == ShaderStage::VERTEX) ? "vertex_shader_instance." : | << ((shader_stage == ShaderStage::VERTEX) ? "vertex_shader_instance." : | ||||
| "fragment_shader_instance.") | "fragment_shader_instance.") | ||||
| << this->texture_samplers[i].name << ".samp = &" << this->texture_samplers[i].name | << this->texture_samplers[i].name << ".samp = &" << this->texture_samplers[i].name | ||||
| << "_sampler;" << std::endl; | << "_sampler;" << std::endl; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 214 Lines • ▼ Show 20 Lines | MTLShaderInterface *MSLGeneratorInterface::bake_shader_interface(const char *name) | ||||
| /* Texture/sampler bindings to interface. */ | /* Texture/sampler bindings to interface. */ | ||||
| for (const MSLTextureSampler &texture_sampler : this->texture_samplers) { | for (const MSLTextureSampler &texture_sampler : this->texture_samplers) { | ||||
| interface->add_texture(name_buffer_copystr(&interface->name_buffer_, | interface->add_texture(name_buffer_copystr(&interface->name_buffer_, | ||||
| texture_sampler.name.c_str(), | texture_sampler.name.c_str(), | ||||
| name_buffer_size, | name_buffer_size, | ||||
| name_buffer_offset), | name_buffer_offset), | ||||
| texture_sampler.location, | texture_sampler.location, | ||||
| texture_sampler.get_texture_binding_type(), | texture_sampler.get_texture_binding_type(), | ||||
| texture_sampler.get_sampler_format(), | |||||
| texture_sampler.stage); | texture_sampler.stage); | ||||
| } | } | ||||
| /* Sampler Parameters. */ | /* Sampler Parameters. */ | ||||
| interface->set_sampler_properties( | interface->set_sampler_properties( | ||||
| this->use_argument_buffer_for_samplers(), | this->use_argument_buffer_for_samplers(), | ||||
| this->get_sampler_argument_buffer_bind_index(ShaderStage::VERTEX), | this->get_sampler_argument_buffer_bind_index(ShaderStage::VERTEX), | ||||
| this->get_sampler_argument_buffer_bind_index(ShaderStage::FRAGMENT)); | this->get_sampler_argument_buffer_bind_index(ShaderStage::FRAGMENT)); | ||||
| ▲ Show 20 Lines • Show All 382 Lines • ▼ Show 20 Lines | switch (this->type) { | ||||
| } | } | ||||
| default: { | default: { | ||||
| BLI_assert_unreachable(); | BLI_assert_unreachable(); | ||||
| return GPU_TEXTURE_2D; | return GPU_TEXTURE_2D; | ||||
| } | } | ||||
| }; | }; | ||||
| } | } | ||||
| eGPUSamplerFormat MSLTextureSampler::get_sampler_format() const | |||||
| { | |||||
| switch (this->type) { | |||||
| case ImageType::FLOAT_BUFFER: | |||||
| case ImageType::FLOAT_1D: | |||||
| case ImageType::FLOAT_1D_ARRAY: | |||||
| case ImageType::FLOAT_2D: | |||||
| case ImageType::FLOAT_2D_ARRAY: | |||||
| case ImageType::FLOAT_3D: | |||||
| case ImageType::FLOAT_CUBE: | |||||
| case ImageType::FLOAT_CUBE_ARRAY: | |||||
| return GPU_SAMPLER_TYPE_FLOAT; | |||||
| case ImageType::INT_BUFFER: | |||||
| case ImageType::INT_1D: | |||||
| case ImageType::INT_1D_ARRAY: | |||||
| case ImageType::INT_2D: | |||||
| case ImageType::INT_2D_ARRAY: | |||||
| case ImageType::INT_3D: | |||||
| case ImageType::INT_CUBE: | |||||
| case ImageType::INT_CUBE_ARRAY: | |||||
| return GPU_SAMPLER_TYPE_INT; | |||||
| case ImageType::UINT_BUFFER: | |||||
| case ImageType::UINT_1D: | |||||
| case ImageType::UINT_1D_ARRAY: | |||||
| case ImageType::UINT_2D: | |||||
| case ImageType::UINT_2D_ARRAY: | |||||
| case ImageType::UINT_3D: | |||||
| case ImageType::UINT_CUBE: | |||||
| case ImageType::UINT_CUBE_ARRAY: | |||||
| return GPU_SAMPLER_TYPE_UINT; | |||||
| case ImageType::SHADOW_2D: | |||||
| case ImageType::SHADOW_2D_ARRAY: | |||||
| case ImageType::SHADOW_CUBE: | |||||
| case ImageType::SHADOW_CUBE_ARRAY: | |||||
| case ImageType::DEPTH_2D: | |||||
| case ImageType::DEPTH_2D_ARRAY: | |||||
| case ImageType::DEPTH_CUBE: | |||||
| case ImageType::DEPTH_CUBE_ARRAY: | |||||
| return GPU_SAMPLER_TYPE_DEPTH; | |||||
| default: | |||||
| BLI_assert_unreachable(); | |||||
| } | |||||
| return GPU_SAMPLER_TYPE_FLOAT; | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| } // namespace blender::gpu | } // namespace blender::gpu | ||||