Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/metal/mtl_shader.mm
| Show All 23 Lines | |||||
| #include "mtl_common.hh" | #include "mtl_common.hh" | ||||
| #include "mtl_context.hh" | #include "mtl_context.hh" | ||||
| #include "mtl_debug.hh" | #include "mtl_debug.hh" | ||||
| #include "mtl_pso_descriptor_state.hh" | #include "mtl_pso_descriptor_state.hh" | ||||
| #include "mtl_shader.hh" | #include "mtl_shader.hh" | ||||
| #include "mtl_shader_generator.hh" | #include "mtl_shader_generator.hh" | ||||
| #include "mtl_shader_interface.hh" | #include "mtl_shader_interface.hh" | ||||
| #include "mtl_texture.hh" | #include "mtl_texture.hh" | ||||
| #include "mtl_vertex_buffer.hh" | |||||
| extern char datatoc_mtl_shader_common_msl[]; | extern char datatoc_mtl_shader_common_msl[]; | ||||
| using namespace blender; | using namespace blender; | ||||
| using namespace blender::gpu; | using namespace blender::gpu; | ||||
| using namespace blender::gpu::shader; | using namespace blender::gpu::shader; | ||||
| namespace blender::gpu { | namespace blender::gpu { | ||||
| ▲ Show 20 Lines • Show All 302 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| bool MTLShader::transform_feedback_enable(GPUVertBuf *buf) | bool MTLShader::transform_feedback_enable(GPUVertBuf *buf) | ||||
| { | { | ||||
| BLI_assert(transform_feedback_type_ != GPU_SHADER_TFB_NONE); | BLI_assert(transform_feedback_type_ != GPU_SHADER_TFB_NONE); | ||||
| BLI_assert(buf); | BLI_assert(buf); | ||||
| transform_feedback_active_ = true; | transform_feedback_active_ = true; | ||||
| transform_feedback_vertbuf_ = buf; | transform_feedback_vertbuf_ = buf; | ||||
| /* TODO(Metal): Enable this assertion once #MTLVertBuf lands. */ | BLI_assert(static_cast<MTLVertBuf *>(unwrap(transform_feedback_vertbuf_))->get_usage_type() == | ||||
| // BLI_assert(static_cast<MTLVertBuf *>(unwrap(transform_feedback_vertbuf_))->get_usage_type() == | GPU_USAGE_DEVICE_ONLY); | ||||
| // GPU_USAGE_DEVICE_ONLY); | |||||
| return true; | return true; | ||||
| } | } | ||||
| void MTLShader::transform_feedback_disable() | void MTLShader::transform_feedback_disable() | ||||
| { | { | ||||
| transform_feedback_active_ = false; | transform_feedback_active_ = false; | ||||
| transform_feedback_vertbuf_ = nullptr; | transform_feedback_vertbuf_ = nullptr; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | void MTLShader::shader_source_from_msl(NSString *input_vertex_source, | ||||
| shd_builder_->msl_source_vert_ = input_vertex_source; | shd_builder_->msl_source_vert_ = input_vertex_source; | ||||
| shd_builder_->msl_source_frag_ = input_fragment_source; | shd_builder_->msl_source_frag_ = input_fragment_source; | ||||
| shd_builder_->source_from_msl_ = true; | shd_builder_->source_from_msl_ = true; | ||||
| } | } | ||||
| void MTLShader::set_interface(MTLShaderInterface *interface) | void MTLShader::set_interface(MTLShaderInterface *interface) | ||||
| { | { | ||||
| /* Assign gpu::Shader super-class interface. */ | /* Assign gpu::Shader super-class interface. */ | ||||
| BLI_assert(Shader::interface == nullptr); | |||||
| Shader::interface = interface; | Shader::interface = interface; | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Bake Pipeline State Objects | /** \name Bake Pipeline State Objects | ||||
| * \{ */ | * \{ */ | ||||
| ▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | if (this->get_uses_ssbo_vertex_fetch()) { | ||||
| desc.vertexDescriptor = nil; | desc.vertexDescriptor = nil; | ||||
| desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassUnspecified; | desc.inputPrimitiveTopology = MTLPrimitiveTopologyClassUnspecified; | ||||
| /* We want to offset the uniform buffer base to allow for sufficient VBO binding slots - We | /* We want to offset the uniform buffer base to allow for sufficient VBO binding slots - We | ||||
| * also require +1 slot for the Index buffer. */ | * also require +1 slot for the Index buffer. */ | ||||
| MTL_uniform_buffer_base_index = MTL_SSBO_VERTEX_FETCH_IBO_INDEX + 1; | MTL_uniform_buffer_base_index = MTL_SSBO_VERTEX_FETCH_IBO_INDEX + 1; | ||||
| } | } | ||||
| else { | else { | ||||
| for (const uint i : IndexRange(current_state.vertex_descriptor.num_attributes)) { | for (const uint i : IndexRange(current_state.vertex_descriptor.max_attribute_value + 1)) { | ||||
| /* Metal back-end attribute descriptor state. */ | /* Metal back-end attribute descriptor state. */ | ||||
| MTLVertexAttributeDescriptorPSO &attribute_desc = | MTLVertexAttributeDescriptorPSO &attribute_desc = | ||||
| current_state.vertex_descriptor.attributes[i]; | current_state.vertex_descriptor.attributes[i]; | ||||
| /* Flag format conversion */ | /* Flag format conversion */ | ||||
| /* In some cases, Metal cannot implicitly convert between data types. | /* In some cases, Metal cannot implicitly convert between data types. | ||||
| * In these instances, the fetch mode #GPUVertFetchMode as provided in the vertex format | * In these instances, the fetch mode #GPUVertFetchMode as provided in the vertex format | ||||
| * is passed in, and used to populate function constants named: MTL_AttributeConvert0..15. | * is passed in, and used to populate function constants named: MTL_AttributeConvert0..15. | ||||
| * | * | ||||
| * It is then the responsibility of the vertex shader to perform any necessary type | * It is then the responsibility of the vertex shader to perform any necessary type | ||||
| * casting. | * casting. | ||||
| * | * | ||||
| * See `mtl_shader.hh` for more information. Relevant Metal API documentation: | * See `mtl_shader.hh` for more information. Relevant Metal API documentation: | ||||
| * https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc | * https://developer.apple.com/documentation/metal/mtlvertexattributedescriptor/1516081-format?language=objc | ||||
| */ | */ | ||||
| if (attribute_desc.format == MTLVertexFormatInvalid) { | if (attribute_desc.format == MTLVertexFormatInvalid) { | ||||
| /* If attributes are non-contiguous, we can skip over gaps. */ | |||||
| MTL_LOG_WARNING( | MTL_LOG_WARNING( | ||||
| "MTLShader: baking pipeline state for '%s'- expected input attribute at " | "MTLShader: baking pipeline state for '%s'- skipping input attribute at " | ||||
| "index '%d' but none was specified in the current vertex state\n", | "index '%d' but none was specified in the current vertex state\n", | ||||
| mtl_interface->get_name(), | mtl_interface->get_name(), | ||||
| i); | i); | ||||
| /* Write out null conversion constant if attribute unused. */ | /* Write out null conversion constant if attribute unused. */ | ||||
| int MTL_attribute_conversion_mode = 0; | int MTL_attribute_conversion_mode = 0; | ||||
| [values setConstantValue:&MTL_attribute_conversion_mode | [values setConstantValue:&MTL_attribute_conversion_mode | ||||
| type:MTLDataTypeInt | type:MTLDataTypeInt | ||||
| Show All 32 Lines | else { | ||||
| MTLVertexBufferLayoutDescriptor *mtl_buf_layout = desc.vertexDescriptor.layouts[i]; | MTLVertexBufferLayoutDescriptor *mtl_buf_layout = desc.vertexDescriptor.layouts[i]; | ||||
| mtl_buf_layout.stepFunction = buf_layout.step_function; | mtl_buf_layout.stepFunction = buf_layout.step_function; | ||||
| mtl_buf_layout.stepRate = buf_layout.step_rate; | mtl_buf_layout.stepRate = buf_layout.step_rate; | ||||
| mtl_buf_layout.stride = buf_layout.stride; | mtl_buf_layout.stride = buf_layout.stride; | ||||
| } | } | ||||
| /* Mark empty attribute conversion. */ | /* Mark empty attribute conversion. */ | ||||
| for (int i = current_state.vertex_descriptor.num_attributes; i < GPU_VERT_ATTR_MAX_LEN; | for (int i = current_state.vertex_descriptor.max_attribute_value + 1; | ||||
| i < GPU_VERT_ATTR_MAX_LEN; | |||||
| i++) { | i++) { | ||||
| int MTL_attribute_conversion_mode = 0; | int MTL_attribute_conversion_mode = 0; | ||||
| [values setConstantValue:&MTL_attribute_conversion_mode | [values setConstantValue:&MTL_attribute_conversion_mode | ||||
| type:MTLDataTypeInt | type:MTLDataTypeInt | ||||
| withName:[NSString stringWithFormat:@"MTL_AttributeConvert%d", i]]; | withName:[NSString stringWithFormat:@"MTL_AttributeConvert%d", i]]; | ||||
| } | } | ||||
| /* DEBUG: Missing/empty attributes. */ | /* DEBUG: Missing/empty attributes. */ | ||||
| /* Attributes are normally mapped as part of the state setting based on the used | /* Attributes are normally mapped as part of the state setting based on the used | ||||
| * #GPUVertFormat, however, if attributes have not been set, we can sort them out here. */ | * #GPUVertFormat, however, if attributes have not been set, we can sort them out here. */ | ||||
| for (const uint i : IndexRange(mtl_interface->get_total_attributes())) { | for (const uint i : IndexRange(mtl_interface->get_total_attributes())) { | ||||
| const MTLShaderInputAttribute &attribute = mtl_interface->get_attribute(i); | const MTLShaderInputAttribute &attribute = mtl_interface->get_attribute(i); | ||||
| MTLVertexAttributeDescriptor *current_attribute = desc.vertexDescriptor.attributes[i]; | MTLVertexAttributeDescriptor *current_attribute = | ||||
| desc.vertexDescriptor.attributes[attribute.location]; | |||||
| if (current_attribute.format == MTLVertexFormatInvalid) { | if (current_attribute.format == MTLVertexFormatInvalid) { | ||||
| #if MTL_DEBUG_SHADER_ATTRIBUTES == 1 | #if MTL_DEBUG_SHADER_ATTRIBUTES == 1 | ||||
| MTL_LOG_INFO("-> Filling in unbound attribute '%s' for shader PSO '%s' \n", | printf("-> Filling in unbound attribute '%s' for shader PSO '%s' with location: %u\n", | ||||
| attribute.name, | mtl_interface->get_name_at_offset(attribute.name_offset), | ||||
| mtl_interface->name); | mtl_interface->get_name(), | ||||
| attribute.location); | |||||
| #endif | #endif | ||||
| current_attribute.format = attribute.format; | current_attribute.format = attribute.format; | ||||
| current_attribute.offset = 0; | current_attribute.offset = 0; | ||||
| current_attribute.bufferIndex = null_buffer_index; | current_attribute.bufferIndex = null_buffer_index; | ||||
| /* Add Null vert buffer binding for invalid attributes. */ | /* Add Null vert buffer binding for invalid attributes. */ | ||||
| if (!using_null_buffer) { | if (!using_null_buffer) { | ||||
| MTLVertexBufferLayoutDescriptor *null_buf_layout = | MTLVertexBufferLayoutDescriptor *null_buf_layout = | ||||
| Show All 15 Lines | |||||
| #if MTL_DEBUG_SHADER_ATTRIBUTES == 1 | #if MTL_DEBUG_SHADER_ATTRIBUTES == 1 | ||||
| MTL_LOG_INFO("Setting up buffer binding for null attribute with buffer index %d\n", | MTL_LOG_INFO("Setting up buffer binding for null attribute with buffer index %d\n", | ||||
| null_buffer_index); | null_buffer_index); | ||||
| #endif | #endif | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Primitive Topology */ | /* Primitive Topology. */ | ||||
| desc.inputPrimitiveTopology = pipeline_descriptor.vertex_descriptor.prim_topology_class; | desc.inputPrimitiveTopology = pipeline_descriptor.vertex_descriptor.prim_topology_class; | ||||
| } | } | ||||
| /* Update constant value for 'MTL_uniform_buffer_base_index' */ | /* Update constant value for 'MTL_uniform_buffer_base_index'. */ | ||||
| [values setConstantValue:&MTL_uniform_buffer_base_index | [values setConstantValue:&MTL_uniform_buffer_base_index | ||||
| type:MTLDataTypeInt | type:MTLDataTypeInt | ||||
| withName:@"MTL_uniform_buffer_base_index"]; | withName:@"MTL_uniform_buffer_base_index"]; | ||||
| /* Transform feedback constant */ | /* Transform feedback constant. | ||||
| * Ensure buffer is placed after existing buffers, including default buffers. */ | |||||
| int MTL_transform_feedback_buffer_index = (this->transform_feedback_type_ != | int MTL_transform_feedback_buffer_index = (this->transform_feedback_type_ != | ||||
| GPU_SHADER_TFB_NONE) ? | GPU_SHADER_TFB_NONE) ? | ||||
| MTL_uniform_buffer_base_index + | MTL_uniform_buffer_base_index + | ||||
| mtl_interface->get_total_uniform_blocks() : | mtl_interface->get_max_ubo_index() + 2 : | ||||
| -1; | -1; | ||||
| if (this->transform_feedback_type_ != GPU_SHADER_TFB_NONE) { | if (this->transform_feedback_type_ != GPU_SHADER_TFB_NONE) { | ||||
| [values setConstantValue:&MTL_transform_feedback_buffer_index | [values setConstantValue:&MTL_transform_feedback_buffer_index | ||||
| type:MTLDataTypeInt | type:MTLDataTypeInt | ||||
| withName:@"MTL_transform_feedback_buffer_index"]; | withName:@"MTL_transform_feedback_buffer_index"]; | ||||
| } | } | ||||
| /* gl_PointSize constant */ | /* gl_PointSize constant. */ | ||||
| bool null_pointsize = true; | bool null_pointsize = true; | ||||
| float MTL_pointsize = pipeline_descriptor.point_size; | float MTL_pointsize = pipeline_descriptor.point_size; | ||||
| if (pipeline_descriptor.vertex_descriptor.prim_topology_class == | if (pipeline_descriptor.vertex_descriptor.prim_topology_class == | ||||
| MTLPrimitiveTopologyClassPoint) { | MTLPrimitiveTopologyClassPoint) { | ||||
| /* `if pointsize is > 0.0`, PROGRAM_POINT_SIZE is enabled, and `gl_PointSize` shader keyword | /* `if pointsize is > 0.0`, PROGRAM_POINT_SIZE is enabled, and `gl_PointSize` shader keyword | ||||
| * overrides the value. Otherwise, if < 0.0, use global constant point size. */ | * overrides the value. Otherwise, if < 0.0, use global constant point size. */ | ||||
| if (MTL_pointsize < 0.0) { | if (MTL_pointsize < 0.0) { | ||||
| MTL_pointsize = fabsf(MTL_pointsize); | MTL_pointsize = fabsf(MTL_pointsize); | ||||
| ▲ Show 20 Lines • Show All 390 Lines • Show Last 20 Lines | |||||