Skip to content

Commit 9ef5f50

Browse files
Merge pull request #2536 from strandborg/metal-bool-spec-constants
MSL: Fix boolean spec const as_type<> invalid output
2 parents 0a88b2d + 7a261b4 commit 9ef5f50

File tree

2 files changed

+61
-5
lines changed

2 files changed

+61
-5
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
; SPIR-V
2+
; Option A test: same SpecId used for bool and uint
3+
OpCapability Shader
4+
OpMemoryModel Logical GLSL450
5+
OpEntryPoint Fragment %main "main" %outColor
6+
OpExecutionMode %main OriginUpperLeft
7+
8+
OpDecorate %outColor Location 0
9+
OpDecorate %specBool SpecId 0
10+
OpDecorate %specUint SpecId 0
11+
12+
%void = OpTypeVoid
13+
%fn = OpTypeFunction %void
14+
%float = OpTypeFloat 32
15+
%v4float = OpTypeVector %float 4
16+
%uint = OpTypeInt 32 0
17+
%bool = OpTypeBool
18+
19+
%float_0 = OpConstant %float 0
20+
%float_1 = OpConstant %float 1
21+
22+
%specBool = OpSpecConstantTrue %bool
23+
%specUint = OpSpecConstant %uint 0
24+
25+
%ptr_Output_v4float = OpTypePointer Output %v4float
26+
%outColor = OpVariable %ptr_Output_v4float Output
27+
28+
%main = OpFunction %void None %fn
29+
%entry = OpLabel
30+
%u_to_f = OpConvertUToF %float %specUint
31+
%sel = OpSelect %float %specBool %float_1 %float_0
32+
%sum = OpFAdd %float %u_to_f %sel
33+
%vec = OpCompositeConstruct %v4float %sum %sum %sum %sum
34+
OpStore %outColor %vec
35+
OpReturn
36+
OpFunctionEnd
37+
38+

spirv_msl.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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<...>.
1745017467
string 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

Comments
 (0)