@@ -8411,9 +8411,22 @@ void CompilerMSL::emit_specialization_constants_and_structs()
84118411 if (unique_func_constants[constant_id] == c.self)
84128412 statement("constant ", sc_type_name, " ", sc_tmp_name, " [[function_constant(", constant_id,
84138413 ")]];");
8414- statement("constant ", sc_type_name, " ", sc_name, " = is_function_constant_defined(", sc_tmp_name,
8415- ") ? ", bitcast_expression(type, sc_tmp_type, sc_tmp_name), " : ", constant_expression(c),
8416- ";");
8414+ // RenderDoc and other instrumentation may reuse the same SpecId with different base types.
8415+ // We deduplicate to one [[function_constant(id)]] temp and then initialize all variants from it.
8416+ // Metal forbids as_type to/from 'bool', so if either side is Boolean, avoid bitcasting here and
8417+ // prefer a value cast via a constructor instead (e.g. uint(tmp) / float(tmp) / bool(tmp)).
8418+ // This preserves expected toggle semantics and prevents illegal MSL like as_type<uint>(bool_tmp).
8419+ {
8420+ string sc_true_expr;
8421+ if (sc_tmp_type == type.basetype)
8422+ sc_true_expr = sc_tmp_name;
8423+ else if (sc_tmp_type == SPIRType::Boolean || type.basetype == SPIRType::Boolean)
8424+ sc_true_expr = join(sc_type_name, "(", sc_tmp_name, ")");
8425+ else
8426+ sc_true_expr = bitcast_expression(type, sc_tmp_type, sc_tmp_name);
8427+ statement("constant ", sc_type_name, " ", sc_name, " = is_function_constant_defined(", sc_tmp_name,
8428+ ") ? ", sc_true_expr, " : ", constant_expression(c), ";");
8429+ }
84178430 }
84188431 else if (has_decoration(c.self, DecorationSpecId))
84198432 {
@@ -17447,13 +17460,18 @@ void CompilerMSL::emit_subgroup_cluster_op_cast(uint32_t result_type, uint32_t r
1744717460 inherit_expression_dependencies(result_id, op0);
1744817461}
1744917462
17463+ // Note: Metal forbids bitcasting to/from 'bool' using as_type. This function is used widely
17464+ // for generating casts in the backend. To avoid generating illegal MSL when the canonical
17465+ // function constant type (from deduplicated SpecId) is Boolean, fall back to value-cast in
17466+ // that case by returning type_to_glsl(out_type) instead of as_type<...>.
1745017467string CompilerMSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
1745117468{
1745217469 if (out_type.basetype == in_type.basetype)
1745317470 return "";
1745417471
17455- assert(out_type.basetype != SPIRType::Boolean);
17456- assert(in_type.basetype != SPIRType::Boolean);
17472+ // Avoid bitcasting to/from booleans in MSL; use value cast instead.
17473+ if (out_type.basetype == SPIRType::Boolean || in_type.basetype == SPIRType::Boolean)
17474+ return type_to_glsl(out_type);
1745717475
1745817476 bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type) && (out_type.vecsize == in_type.vecsize);
1745917477 bool same_size_cast = (out_type.width * out_type.vecsize) == (in_type.width * in_type.vecsize);
0 commit comments