This one is fun! Apparently OpName is semantic, somehow, on Adreno drivers.
struct VertexOutput {
[[builtin(position)]] pos: vec4<f32>;
[[location(0)]] lighting: vec3<f32>;
};
[[stage(vertex)]]
fn vs_main_test(
[[location(0)]] pos: vec3<f32>,
[[location(1)]] lighting: vec3<f32>,
) -> VertexOutput {
return VertexOutput(vec4<f32>(pos, 1.0), lighting);
}
Adreno rejects this SPIR-V simply because the stage input lighting has the same OpName as the stage output lighting.
Renaming the input lighting to in_lighting resolves this issue, and a spirv-dis --raw-id diff shows that the only difference is the OpName for that field.
However, the pos/pos OpNames do not cause an issue, indicating it's only a problem with non-builtin stage inputs and outputs. This example is also OK:
struct VertexOutput {
[[builtin(position)]] pos: vec4<f32>;
[[location(0)]] vertex_index: u32;
};
[[stage(vertex)]]
fn vs_main_test(
[[builtin(vertex_index)]] vertex_index: u32,
[[location(0)]] pos: vec3<f32>,
) -> VertexOutput {
return VertexOutput(vec4<f32>(pos, 1.0), vertex_index);
}