266 bool is_compute =
false;
267 if (shd_builder_->glsl_compute_source_.empty() ==
false) {
268 BLI_assert_msg(info !=
nullptr,
"Compute shaders must use CreateInfo.\n");
269 BLI_assert_msg(!shd_builder_->source_from_msl_,
"Compute shaders must compile from GLSL.");
275 if (!shd_builder_->source_from_msl_) {
276 bool success = generate_msl_from_glsl(info);
280 BLI_assert_msg(
false,
"Shader translation from GLSL to MSL has failed. \n");
288 shd_builder_ =
nullptr;
296 int threadgroup_tuning_param = info->mtl_max_threads_per_threadgroup_;
297 if (threadgroup_tuning_param > 0) {
298 maxTotalThreadsPerThreadgroup_Tuning_ = threadgroup_tuning_param;
308 id<MTLDevice> device = context_->device;
326 MTLCompileOptions *
options = [[[MTLCompileOptions alloc]
init] autorelease];
327 options.languageVersion = MTLLanguageVersion2_2;
329 options.preserveInvariance = YES;
335 options.languageVersion = MTLLanguageVersion2_3;
337#if defined(MAC_OS_VERSION_14_0)
338 if (@available(macOS 14.00, *)) {
341 options.languageVersion = MTLLanguageVersion3_1;
346 NSString *source_to_compile = shd_builder_->msl_source_vert_;
352 uint8_t total_stages = (is_compute) ? 1 : 2;
354 for (
int stage_count = 0; stage_count < total_stages; stage_count++) {
357 shd_builder_->msl_source_vert_ :
359 shd_builder_->msl_source_compute_ :
360 shd_builder_->msl_source_frag_);
364 NSString *source_with_header_a = [
str stringByAppendingString:source_to_compile];
368 NSString *source_with_header = source_with_header_a;
369 [source_with_header retain];
372 NSError *
error =
nullptr;
373 id<MTLLibrary> library = [device newLibraryWithSource:source_with_header
378 if ([[
error localizedDescription] rangeOfString:
@"Compilation succeeded"].location ==
381 const char *errors_c_str = [[
error localizedDescription] UTF8String];
382 const StringRefNull source = (is_compute) ? shd_builder_->glsl_compute_source_ :
383 shd_builder_->glsl_fragment_source_;
390 shd_builder_ =
nullptr;
400 shader_library_vert_ = library;
401 shader_library_vert_.label = [NSString stringWithUTF8String:this->
name];
405 shader_library_frag_ = library;
406 shader_library_frag_.label = [NSString stringWithUTF8String:this->
name];
410 shader_library_compute_ = library;
411 shader_library_compute_.label = [NSString stringWithUTF8String:this->
name];
419 [source_with_header autorelease];
434 pso_descriptor_ = [[MTLRenderPipelineDescriptor alloc]
init];
435 pso_descriptor_.label = [NSString stringWithUTF8String:this->
name];
443 if (push_constant_block.
size > 0) {
448 push_constant_data_ =
nullptr;
463 shd_builder_ =
nullptr;
900 MTLPrimitiveTopologyClass prim_type,
909 pso_cache_lock_.lock();
912 pso_cache_lock_.unlock();
914 if (pipeline_state !=
nullptr) {
915 return pipeline_state;
931 MTLFunctionConstantValues *values = [[MTLFunctionConstantValues
new] autorelease];
938 MTLRenderPipelineDescriptor *desc = pso_descriptor_;
940 pso_descriptor_.label = [NSString stringWithUTF8String:this->
name];
956 bool using_null_buffer =
false;
978 if (attribute_desc.
format == MTLVertexFormatInvalid) {
981 "MTLShader: baking pipeline state for '%s'- skipping input attribute at "
982 "index '%d' but none was specified in the current vertex state",
987 int MTL_attribute_conversion_mode = 0;
988 [values setConstantValue:&MTL_attribute_conversion_mode
990 withName:[NSString stringWithFormat:
@"MTL_AttributeConvert%d",
i]];
995 [values setConstantValue:&MTL_attribute_conversion_mode
997 withName:[NSString stringWithFormat:
@"MTL_AttributeConvert%d",
i]];
1000 "TODO(Metal): Shader %s needs to support internal format conversion\n",
1007 MTLVertexAttributeDescriptor *mtl_attribute = desc.vertexDescriptor.attributes[
i];
1009 mtl_attribute.format = attribute_desc.
format;
1010 mtl_attribute.offset = attribute_desc.
offset;
1011 mtl_attribute.bufferIndex = attribute_desc.
buffer_index;
1021 MTLVertexBufferLayoutDescriptor *mtl_buf_layout = desc.vertexDescriptor.layouts[
i];
1024 mtl_buf_layout.stepRate = buf_layout.
step_rate;
1025 mtl_buf_layout.stride = buf_layout.
stride;
1033 int MTL_attribute_conversion_mode = 0;
1034 [values setConstantValue:&MTL_attribute_conversion_mode
1036 withName:[NSString stringWithFormat:
@"MTL_AttributeConvert%d",
i]];
1044 MTLVertexAttributeDescriptor *current_attribute =
1045 desc.vertexDescriptor.attributes[attribute.
location];
1047 if (current_attribute.format == MTLVertexFormatInvalid) {
1048#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
1049 printf(
"-> Filling in unbound attribute '%s' for shader PSO '%s' with location: %u\n",
1054 current_attribute.format = attribute.
format;
1055 current_attribute.offset = 0;
1056 current_attribute.bufferIndex = null_buffer_index;
1059 if (!using_null_buffer) {
1060 MTLVertexBufferLayoutDescriptor *null_buf_layout =
1061 desc.vertexDescriptor.layouts[null_buffer_index];
1065 null_buf_layout.stepFunction = MTLVertexStepFunctionConstant;
1066 null_buf_layout.stepRate = 0;
1067 null_buf_layout.stride =
max_ii(null_buf_layout.stride, attribute.
size);
1072 if (null_buffer_index >= MTL_uniform_buffer_base_index) {
1073 MTL_uniform_buffer_base_index = null_buffer_index + 1;
1075 using_null_buffer =
true;
1076#if MTL_DEBUG_SHADER_ATTRIBUTES == 1
1077 MTL_LOG_INFO(
"Setting up buffer binding for null attribute with buffer index %d",
1089 [values setConstantValue:&MTL_uniform_buffer_base_index
1091 withName:
@"MTL_uniform_buffer_base_index"];
1098 int MTL_storage_buffer_base_index = MTL_uniform_buffer_base_index + 1 +
1102 [values setConstantValue:&MTL_storage_buffer_base_index
1104 withName:
@"MTL_storage_buffer_base_index"];
1111 [values setConstantValue:&MTL_clip_distances_enabled
1113 withName:
@"MTL_clip_distances_enabled"];
1115 if (MTL_clip_distances_enabled > 0) {
1120 if (plane_enabled) {
1122 setConstantValue:&plane_enabled
1124 withName:[NSString stringWithFormat:
@"MTL_clip_distance_enabled%d", plane]];
1130 bool null_pointsize =
true;
1131 float MTL_pointsize = pipeline_descriptor.
point_size;
1133 MTLPrimitiveTopologyClassPoint)
1137 if (MTL_pointsize < 0.0) {
1138 MTL_pointsize =
fabsf(MTL_pointsize);
1139 [values setConstantValue:&MTL_pointsize
1140 type:MTLDataTypeFloat
1141 withName:
@"MTL_global_pointsize"];
1142 null_pointsize =
false;
1146 if (null_pointsize) {
1147 MTL_pointsize = 0.0f;
1148 [values setConstantValue:&MTL_pointsize
1149 type:MTLDataTypeFloat
1150 withName:
@"MTL_global_pointsize"];
1154 NSError *
error =
nullptr;
1155 desc.vertexFunction = [shader_library_vert_ newFunctionWithName:vertex_function_name_
1156 constantValues:values
1160 [[
error localizedDescription] rangeOfString:
@"Compilation succeeded"].location ==
1163 const char *errors_c_str = [[
error localizedDescription] UTF8String];
1167 print_log({source}, errors_c_str,
"VertShader", has_error, &parser);
1175 desc.fragmentFunction = [shader_library_frag_ newFunctionWithName:fragment_function_name_
1176 constantValues:values
1180 [[
error localizedDescription] rangeOfString:
@"Compilation succeeded"].location ==
1183 const char *errors_c_str = [[
error localizedDescription] UTF8String];
1184 const StringRefNull source = shd_builder_->glsl_fragment_source_;
1187 print_log({source}, errors_c_str,
"FragShader", has_error, &parser);
1202 MTLRenderPipelineColorAttachmentDescriptor *col_attachment =
1203 desc.colorAttachments[color_attachment];
1205 col_attachment.pixelFormat = pixel_format;
1206 if (pixel_format != MTLPixelFormatInvalid) {
1211 format_supports_blending;
1213 col_attachment.alphaBlendOperation = pipeline_descriptor.
alpha_blend_op;
1214 col_attachment.rgbBlendOperation = pipeline_descriptor.
rgb_blend_op;
1223 "[Warning] Attempting to Bake PSO, but MTLPixelFormat %d does not support "
1225 *((
int *)&pixel_format));
1238 BLI_assert_msg((MTL_uniform_buffer_base_index + get_max_ubo_index() + 2) <
1240 "UBO and SSBO bindings exceed the fragment bind table limit.");
1245 "Argument buffer binding exceeds the fragment bind table limit.");
1250 MTLAutoreleasedRenderPipelineReflection reflection_data;
1251 id<MTLRenderPipelineState> pso = [ctx->
device
1252 newRenderPipelineStateWithDescriptor:desc
1253 options:MTLPipelineOptionBufferTypeInfo
1254 reflection:&reflection_data
1257 NSLog(
@"Failed to create PSO for shader: %s error %@\n", this->
name,
error);
1262 NSLog(
@"Failed to create PSO for shader: %s, but no error was provided!\n", this->
name);
1268 NSLog(
@"Successfully compiled PSO for shader: %s (Metal Context: %p)\n", this->
name, ctx);
1274 pso_inst->
vert = desc.vertexFunction;
1275 pso_inst->
frag = desc.fragmentFunction;
1276 pso_inst->
pso = pso;
1283 if (reflection_data != nil) {
1292 NSArray<MTLArgument *> *vert_args = [reflection_data vertexArguments];
1295 int buffer_binding_max_ind = 0;
1297 for (
int i = 0;
i < [vert_args
count];
i++) {
1298 MTLArgument *arg = [vert_args objectAtIndex:
i];
1299 if ([arg type] == MTLArgumentTypeBuffer) {
1300 int buf_index = [arg index] - MTL_uniform_buffer_base_index;
1301 if (buf_index >= 0) {
1302 buffer_binding_max_ind =
max_ii(buffer_binding_max_ind, buf_index);
1307 for (
int i = 0;
i < buffer_binding_max_ind + 1;
i++) {
1311 for (
int i = 0;
i < [vert_args
count];
i++) {
1312 MTLArgument *arg = [vert_args objectAtIndex:
i];
1313 if ([arg type] == MTLArgumentTypeBuffer) {
1314 int buf_index = [arg index] - MTL_uniform_buffer_base_index;
1316 if (buf_index >= 0) {
1318 (uint32_t)([arg index]),
1319 (uint32_t)([arg bufferDataSize]),
1320 (uint32_t)([arg bufferAlignment]),
1321 ([arg
isActive] == YES) ?
true :
false};
1326 NSArray<MTLArgument *> *frag_args = [reflection_data fragmentArguments];
1329 buffer_binding_max_ind = 0;
1331 for (
int i = 0;
i < [frag_args
count];
i++) {
1332 MTLArgument *arg = [frag_args objectAtIndex:
i];
1333 if ([arg type] == MTLArgumentTypeBuffer) {
1334 int buf_index = [arg index] - MTL_uniform_buffer_base_index;
1335 if (buf_index >= 0) {
1336 buffer_binding_max_ind =
max_ii(buffer_binding_max_ind, buf_index);
1341 for (
int i = 0;
i < buffer_binding_max_ind + 1;
i++) {
1345 for (
int i = 0;
i < [frag_args
count];
i++) {
1346 MTLArgument *arg = [frag_args objectAtIndex:
i];
1347 if ([arg type] == MTLArgumentTypeBuffer) {
1348 int buf_index = [arg index] - MTL_uniform_buffer_base_index;
1350 if (buf_index >= 0) {
1352 (uint32_t)([arg index]),
1353 (uint32_t)([arg bufferDataSize]),
1354 (uint32_t)([arg bufferAlignment]),
1355 ([arg
isActive] == YES) ?
true :
false};
1362 pso_cache_lock_.lock();
1364 pso_cache_.add(pipeline_descriptor, pso_inst);
1365 pso_cache_lock_.unlock();
1367 "PSO CACHE: Stored new variant in PSO cache for shader '%s' Hash: '%llu'\n",
1369 pipeline_descriptor.
hash());
1385 pso_cache_lock_.lock();
1387 compute_pipeline_descriptor);
1389 pso_cache_lock_.unlock();
1391 if (pipeline_state !=
nullptr) {
1394 return pipeline_state;
1401 MTLFunctionConstantValues *values = [[MTLFunctionConstantValues
new] autorelease];
1415 int MTL_uniform_buffer_base_index = 0;
1416 [values setConstantValue:&MTL_uniform_buffer_base_index
1418 withName:
@"MTL_uniform_buffer_base_index"];
1425 int MTL_storage_buffer_base_index = MTL_uniform_buffer_base_index + 1 +
1430 [values setConstantValue:&MTL_storage_buffer_base_index
1432 withName:
@"MTL_storage_buffer_base_index"];
1435 NSError *
error =
nullptr;
1436 id<MTLFunction> compute_function = [shader_library_compute_
1437 newFunctionWithName:compute_function_name_
1438 constantValues:values
1440 compute_function.label = [NSString stringWithUTF8String:this->
name];
1443 NSLog(
@"Compile Error - Metal Shader compute function, error %@",
error);
1446 if ([[
error localizedDescription] rangeOfString:
@"Compilation succeeded"].location ==
1455 MTLComputePipelineDescriptor *desc = [[MTLComputePipelineDescriptor alloc]
init];
1456 desc.label = [NSString stringWithUTF8String:this->
name];
1457 desc.computeFunction = compute_function;
1469 if (maxTotalThreadsPerThreadgroup_Tuning_ > 0) {
1470 desc.maxTotalThreadsPerThreadgroup = this->maxTotalThreadsPerThreadgroup_Tuning_;
1471 MTL_LOG_INFO(
"Using custom parameter for shader %s value %u\n",
1473 maxTotalThreadsPerThreadgroup_Tuning_);
1477 id<MTLComputePipelineState> pso = [ctx->
device
1478 newComputePipelineStateWithDescriptor:desc
1490 uint num_required_threads_per_threadgroup = compute_pso_common_state_.threadgroup_x_len *
1491 compute_pso_common_state_.threadgroup_y_len *
1492 compute_pso_common_state_.threadgroup_z_len;
1493 if (pso.maxTotalThreadsPerThreadgroup < num_required_threads_per_threadgroup) {
1495 "Shader '%s' requires %u threads per threadgroup, but PSO limit is: %lu. Recompiling "
1496 "with increased limit on descriptor.\n",
1498 num_required_threads_per_threadgroup,
1499 (
unsigned long)pso.maxTotalThreadsPerThreadgroup);
1502 desc.maxTotalThreadsPerThreadgroup = 1024;
1503 pso = [ctx->
device newComputePipelineStateWithDescriptor:desc
1511 NSLog(
@"Failed to create PSO for compute shader: %s error %@\n", this->
name,
error);
1516 NSLog(
@"Failed to create PSO for compute shader: %s, but no error was provided!\n",
1523 NSLog(
@"Successfully compiled compute PSO for shader: %s (Metal Context: %p)\n",
1533 compute_pso_instance->
compute = compute_function;
1534 compute_pso_instance->
pso = pso;
1537 pso_cache_lock_.lock();
1539 compute_pso_cache_.add(compute_pipeline_descriptor, compute_pso_instance);
1540 pso_cache_lock_.unlock();
1542 return compute_pso_instance;