mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
Fix Windows Clang SPIR-V serialization with typed operands
This commit is contained in:
@@ -1603,30 +1603,29 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
|
||||
Builder b;
|
||||
const auto void_type = b.Type(spv::OpTypeVoid);
|
||||
const auto uint_type = b.Type(spv::OpTypeInt, {32, 0});
|
||||
const auto int_type = b.Type(spv::OpTypeInt, {32, 1});
|
||||
const auto float_type = b.Type(spv::OpTypeFloat, {32});
|
||||
const auto vec2_type = b.Type(spv::OpTypeVector, {float_type, 2});
|
||||
const auto vec4_type = b.Type(spv::OpTypeVector, {float_type, 4});
|
||||
const auto uint_type = b.Type(spv::OpTypeInt, 32, 0);
|
||||
const auto int_type = b.Type(spv::OpTypeInt, 32, 1);
|
||||
const auto float_type = b.Type(spv::OpTypeFloat, 32);
|
||||
const auto vec2_type = b.Type(spv::OpTypeVector, float_type, 2);
|
||||
const auto vec4_type = b.Type(spv::OpTypeVector, float_type, 4);
|
||||
const auto per_vertex_type =
|
||||
b.DecoratedType(spv::OpTypeStruct, {vec4_type},
|
||||
{{spv::OpDecorate, {spv::DecorationBlock}},
|
||||
b.DecoratedType(spv::OpTypeStruct, {{spv::OpDecorate, {spv::DecorationBlock}},
|
||||
{spv::OpMemberDecorate,
|
||||
{0, spv::DecorationBuiltIn, spv::BuiltInPosition}}});
|
||||
{0, spv::DecorationBuiltIn, spv::BuiltInPosition}}}, vec4_type);
|
||||
const auto ptr_input_vec2 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, vec2_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, vec2_type);
|
||||
const auto ptr_input_vec4 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, vec4_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, vec4_type);
|
||||
const auto ptr_output_vec4 =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, vec4_type});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, vec4_type);
|
||||
const auto ptr_output_per_vertex =
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, per_vertex_type});
|
||||
const auto func_type = b.Type(spv::OpTypeFunction, {void_type});
|
||||
const auto const_u32_0 = b.Constant(spv::OpConstant, uint_type, {0});
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, per_vertex_type);
|
||||
const auto func_type = b.Type(spv::OpTypeFunction, void_type);
|
||||
const auto const_u32_0 = b.Constant(spv::OpConstant, uint_type, 0);
|
||||
const auto const_f32_0 =
|
||||
b.Constant(spv::OpConstant, float_type, {0x00000000u});
|
||||
b.Constant(spv::OpConstant, float_type, 0x00000000u);
|
||||
const auto const_f32_w =
|
||||
b.Constant(spv::OpConstant, float_type, {std::bit_cast<u32>(clip_w)});
|
||||
b.Constant(spv::OpConstant, float_type, std::bit_cast<u32>(clip_w));
|
||||
const auto in_pos =
|
||||
b.DefineGlobalVariable(ptr_input_vec2, spv::StorageClassInput);
|
||||
const auto in_color =
|
||||
@@ -1640,15 +1639,14 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
std::vector<u32> interfaces = {in_pos, in_color, per_vertex, out_color};
|
||||
if (layered) {
|
||||
instance = b.DefineGlobalVariable(
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassInput, int_type}),
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassInput, int_type),
|
||||
spv::StorageClassInput);
|
||||
layer = b.DefineGlobalVariable(
|
||||
b.Type(spv::OpTypePointer, {spv::StorageClassOutput, int_type}),
|
||||
b.Type(spv::OpTypePointer, spv::StorageClassOutput, int_type),
|
||||
spv::StorageClassOutput);
|
||||
b.AddAnnotation({spv::OpDecorate, instance, spv::DecorationBuiltIn,
|
||||
spv::BuiltInInstanceIndex});
|
||||
b.AddAnnotation(
|
||||
{spv::OpDecorate, layer, spv::DecorationBuiltIn, spv::BuiltInLayer});
|
||||
b.AddAnnotation(spv::OpDecorate, instance, spv::DecorationBuiltIn,
|
||||
spv::BuiltInInstanceIndex);
|
||||
b.AddAnnotation(spv::OpDecorate, layer, spv::DecorationBuiltIn, spv::BuiltInLayer);
|
||||
b.RequireVersion(0x00010500u);
|
||||
b.RequireCapability(spv::CapabilityShaderLayer);
|
||||
interfaces.insert(interfaces.end(), {instance, layer});
|
||||
@@ -1663,32 +1661,32 @@ std::vector<u32> MakePassthroughVertexSpirv(bool layered, float clip_w = 1.0f) {
|
||||
const auto position_ptr = b.AllocateId();
|
||||
|
||||
b.RequireCapability(spv::CapabilityShader);
|
||||
b.AddMemoryModel({spv::AddressingModelLogical, spv::MemoryModelGLSL450});
|
||||
b.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
b.AddEntryPoint(spv::ExecutionModelVertex, main, "main", interfaces);
|
||||
b.AddAnnotation({spv::OpDecorate, in_pos, spv::DecorationLocation, 0});
|
||||
b.AddAnnotation({spv::OpDecorate, in_color, spv::DecorationLocation, 1});
|
||||
b.AddAnnotation({spv::OpDecorate, out_color, spv::DecorationLocation, 0});
|
||||
b.AddAnnotation(spv::OpDecorate, in_pos, spv::DecorationLocation, 0);
|
||||
b.AddAnnotation(spv::OpDecorate, in_color, spv::DecorationLocation, 1);
|
||||
b.AddAnnotation(spv::OpDecorate, out_color, spv::DecorationLocation, 0);
|
||||
|
||||
b.AddFunction({spv::OpFunction, void_type, main, spv::FunctionControlMaskNone,
|
||||
func_type});
|
||||
b.AddFunction({spv::OpLabel, label});
|
||||
b.AddFunction({spv::OpLoad, vec2_type, pos2, in_pos});
|
||||
b.AddFunction({spv::OpLoad, vec4_type, color4, in_color});
|
||||
b.AddFunction({spv::OpCompositeExtract, float_type, pos_x, pos2, 0});
|
||||
b.AddFunction({spv::OpCompositeExtract, float_type, pos_y, pos2, 1});
|
||||
b.AddFunction({spv::OpCompositeConstruct, vec4_type, position, pos_x, pos_y,
|
||||
const_f32_0, const_f32_w});
|
||||
b.AddFunction({spv::OpAccessChain, ptr_output_vec4, position_ptr, per_vertex,
|
||||
const_u32_0});
|
||||
b.AddFunction({spv::OpStore, position_ptr, position});
|
||||
b.AddFunction({spv::OpStore, out_color, color4});
|
||||
b.AddFunction(spv::OpFunction, void_type, main, spv::FunctionControlMaskNone,
|
||||
func_type);
|
||||
b.AddFunction(spv::OpLabel, label);
|
||||
b.AddFunction(spv::OpLoad, vec2_type, pos2, in_pos);
|
||||
b.AddFunction(spv::OpLoad, vec4_type, color4, in_color);
|
||||
b.AddFunction(spv::OpCompositeExtract, float_type, pos_x, pos2, 0);
|
||||
b.AddFunction(spv::OpCompositeExtract, float_type, pos_y, pos2, 1);
|
||||
b.AddFunction(spv::OpCompositeConstruct, vec4_type, position, pos_x, pos_y,
|
||||
const_f32_0, const_f32_w);
|
||||
b.AddFunction(spv::OpAccessChain, ptr_output_vec4, position_ptr, per_vertex,
|
||||
const_u32_0);
|
||||
b.AddFunction(spv::OpStore, position_ptr, position);
|
||||
b.AddFunction(spv::OpStore, out_color, color4);
|
||||
if (layered) {
|
||||
const auto index = b.AllocateId();
|
||||
b.AddFunction({spv::OpLoad, int_type, index, instance});
|
||||
b.AddFunction({spv::OpStore, layer, index});
|
||||
b.AddFunction(spv::OpLoad, int_type, index, instance);
|
||||
b.AddFunction(spv::OpStore, layer, index);
|
||||
}
|
||||
b.AddFunction({spv::OpReturn});
|
||||
b.AddFunction({spv::OpFunctionEnd});
|
||||
b.AddFunction(spv::OpReturn);
|
||||
b.AddFunction(spv::OpFunctionEnd);
|
||||
return b.Build();
|
||||
}
|
||||
|
||||
|
||||
+126
-15
@@ -10025,11 +10025,120 @@ void TestNewShaderRecompilerAuxPositionExports() {
|
||||
"PA_CL_VS_OUT_CNTL is absent from the vertex shader cache key");
|
||||
}
|
||||
|
||||
void TestTypedSpirvSerialization() {
|
||||
// Parameters exercise runtime enums, which cannot narrow implicitly to a
|
||||
// uint32_t initializer list when the enum uses the Windows signed ABI.
|
||||
const auto check_serialization = [](spv::StorageClass storage_class,
|
||||
spv::FunctionControlMask control,
|
||||
spv::Decoration decoration,
|
||||
GLSLstd450 glsl_opcode,
|
||||
int32_t signed_literal,
|
||||
uint32_t high_bit_literal) {
|
||||
ShaderRecompiler::Spirv::Builder builder;
|
||||
builder.RequireCapability(spv::CapabilityShader);
|
||||
const auto glsl = builder.Import("GLSL.std.450");
|
||||
builder.AddMemoryModel(spv::AddressingModelLogical, spv::MemoryModelGLSL450);
|
||||
const auto void_type = builder.Type(spv::OpTypeVoid);
|
||||
const std::vector<uint32_t> uint_operands{32u, 0u};
|
||||
const auto uint_type = builder.Type(spv::OpTypeInt, uint_operands);
|
||||
Check(uint_type == builder.Type(spv::OpTypeInt, 32u, 0u) &&
|
||||
uint_type == builder.Type(spv::OpTypeInt,
|
||||
std::span<const uint32_t>{uint_operands}),
|
||||
"typed, vector and span type operands produced different declarations");
|
||||
const auto float_type = builder.Type(spv::OpTypeFloat, 32u);
|
||||
const auto vector_type = builder.Type(spv::OpTypeVector, uint_type, 2u);
|
||||
const auto pointer_type =
|
||||
builder.Type(spv::OpTypePointer, storage_class, uint_type);
|
||||
const auto function_type = builder.Type(spv::OpTypeFunction, void_type);
|
||||
const auto all_bits =
|
||||
builder.Constant(spv::OpConstant, uint_type, signed_literal);
|
||||
Check(all_bits == builder.Constant(spv::OpConstant, uint_type, UINT32_MAX),
|
||||
"signed and unsigned constant operands produced different declarations");
|
||||
const auto high_bit =
|
||||
builder.Constant(spv::OpConstant, uint_type, high_bit_literal);
|
||||
const auto one = builder.Constant(spv::OpConstant, float_type, 0x3f800000u);
|
||||
const std::vector<uint32_t> components{all_bits, high_bit};
|
||||
const auto constant_vector = builder.Constant(
|
||||
spv::OpConstantComposite, vector_type,
|
||||
std::span<const uint32_t>{components});
|
||||
Check(constant_vector == builder.Constant(spv::OpConstantComposite,
|
||||
vector_type, components),
|
||||
"vector and span constant operands produced different declarations");
|
||||
const auto variable =
|
||||
builder.DefineGlobalVariable(pointer_type, storage_class);
|
||||
const auto function = builder.AllocateId();
|
||||
const auto label = builder.AllocateId();
|
||||
const auto absolute = builder.AllocateId();
|
||||
const auto constructed = builder.AllocateId();
|
||||
const auto shuffled = builder.AllocateId();
|
||||
const auto loaded = builder.AllocateId();
|
||||
builder.AddEntryPoint(spv::ExecutionModelGLCompute, function, "main", {});
|
||||
builder.AddExecutionMode(function, spv::ExecutionModeLocalSize, 1u, 2u, 3u);
|
||||
builder.AddAnnotation(spv::OpDecorate, one, decoration);
|
||||
builder.AddFunction(spv::OpFunction, void_type, function, control,
|
||||
function_type);
|
||||
const std::vector<uint32_t> label_words{248u, label};
|
||||
builder.AddFunction(label_words);
|
||||
builder.AddFunction(spv::OpExtInst, float_type, absolute, glsl, glsl_opcode,
|
||||
one);
|
||||
builder.AddFunction(spv::OpCompositeConstruct, vector_type, constructed,
|
||||
components);
|
||||
const std::array<uint32_t, 2> selectors{1u, 2u};
|
||||
builder.AddFunction(spv::OpVectorShuffle, vector_type, shuffled,
|
||||
constant_vector, constructed,
|
||||
std::span<const uint32_t>{selectors});
|
||||
builder.AddFunction(spv::OpLoad, uint_type, loaded, variable,
|
||||
spv::MemoryAccessAlignedMask, 4u);
|
||||
builder.AddFunction(std::vector<uint32_t>{});
|
||||
const std::array<uint32_t, 1> return_words{253u};
|
||||
builder.AddFunction(std::span<const uint32_t>{return_words});
|
||||
builder.AddFunction(spv::OpFunctionEnd);
|
||||
|
||||
// Literal headers and enum values keep this independent of the builder's
|
||||
// instruction word counts, operand conversion and range flattening.
|
||||
const std::vector<uint32_t> expected{
|
||||
0x07230203u, 0x00010300u, 0u, loaded + 1u, 0u,
|
||||
0x00020011u, 1u, // OpCapability Shader
|
||||
0x0006000bu, glsl, 0x4c534c47u, 0x6474732eu, 0x3035342eu, 0u,
|
||||
0x0003000eu, 0u, 1u, // OpMemoryModel Logical GLSL450
|
||||
0x0005000fu, 5u, function, 0x6e69616du, 0u,
|
||||
0x00060010u, function, 17u, 1u, 2u, 3u,
|
||||
0x00030047u, one, 0u, // OpDecorate RelaxedPrecision
|
||||
0x00020013u, void_type,
|
||||
0x00040015u, uint_type, 32u, 0u,
|
||||
0x00030016u, float_type, 32u,
|
||||
0x00040017u, vector_type, uint_type, 2u,
|
||||
0x00040020u, pointer_type, 6u, uint_type,
|
||||
0x00030021u, function_type, void_type,
|
||||
0x0004002bu, uint_type, all_bits, 0xffffffffu,
|
||||
0x0004002bu, uint_type, high_bit, 0x80000000u,
|
||||
0x0004002bu, float_type, one, 0x3f800000u,
|
||||
0x0005002cu, vector_type, constant_vector, all_bits, high_bit,
|
||||
0x0004003bu, pointer_type, variable, 6u,
|
||||
0x00050036u, void_type, function, 0u, function_type,
|
||||
0x000200f8u, label,
|
||||
0x0006000cu, float_type, absolute, glsl, 4u, one,
|
||||
0x00050050u, vector_type, constructed, all_bits, high_bit,
|
||||
0x0007004fu, vector_type, shuffled, constant_vector, constructed, 1u, 2u,
|
||||
0x0006003du, uint_type, loaded, variable, 2u, 4u,
|
||||
0x000100fdu,
|
||||
0x00010038u,
|
||||
};
|
||||
const auto binary = builder.Build();
|
||||
Check(binary == expected,
|
||||
"typed SPIR-V serialization changed instruction words or operand order");
|
||||
CheckSpirvBinaryValidates(binary);
|
||||
};
|
||||
check_serialization(spv::StorageClassPrivate, spv::FunctionControlMaskNone,
|
||||
spv::DecorationRelaxedPrecision, GLSLstd450FAbs, -1,
|
||||
0x80000000u);
|
||||
}
|
||||
|
||||
void TestDeferredSpirvPhiPatching() {
|
||||
ShaderRecompiler::Spirv::Builder builder;
|
||||
const auto type = builder.Type(spv::OpTypeInt, {32u, 0u});
|
||||
const auto zero = builder.Constant(spv::OpConstant, type, {0u});
|
||||
const auto one = builder.Constant(spv::OpConstant, type, {1u});
|
||||
const auto type = builder.Type(spv::OpTypeInt, 32u, 0u);
|
||||
const auto zero = builder.Constant(spv::OpConstant, type, 0u);
|
||||
const auto one = builder.Constant(spv::OpConstant, type, 1u);
|
||||
const auto left = builder.AllocateId();
|
||||
const auto right = builder.AllocateId();
|
||||
const auto result = builder.AllocateId();
|
||||
@@ -10080,35 +10189,36 @@ void TestDemandDrivenSpirvDeclarations() {
|
||||
using ShaderRecompiler::Spirv::Builder;
|
||||
|
||||
Builder declarations;
|
||||
const auto uint_type = declarations.Type(spv::OpTypeInt, {32u, 0u});
|
||||
Check(uint_type == declarations.Type(spv::OpTypeInt, {32u, 0u}),
|
||||
const auto uint_type = declarations.Type(spv::OpTypeInt, 32u, 0u);
|
||||
Check(uint_type == declarations.Type(spv::OpTypeInt, 32u, 0u),
|
||||
"structural type interning returned different IDs");
|
||||
const auto zero = declarations.Constant(spv::OpConstant, uint_type, {0u});
|
||||
Check(zero == declarations.Constant(spv::OpConstant, uint_type, {0u}),
|
||||
const auto zero = declarations.Constant(spv::OpConstant, uint_type, 0u);
|
||||
Check(zero == declarations.Constant(spv::OpConstant, uint_type, 0u),
|
||||
"constant interning returned different IDs");
|
||||
Check(declarations.Import("GLSL.std.450") ==
|
||||
declarations.Import("GLSL.std.450"),
|
||||
"extended-instruction import was duplicated");
|
||||
declarations.RequireCapability(spv::CapabilityShader);
|
||||
declarations.RequireCapability(spv::CapabilityShader);
|
||||
const auto plain_array =
|
||||
declarations.Type(spv::OpTypeArray, {uint_type, zero});
|
||||
const auto plain_array = declarations.Type(spv::OpTypeArray, uint_type, zero);
|
||||
const auto decorated_array = declarations.DecoratedType(
|
||||
spv::OpTypeArray, {uint_type, zero},
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}});
|
||||
spv::OpTypeArray,
|
||||
{{spv::OpDecorate, {spv::DecorationArrayStride, sizeof(uint32_t)}}},
|
||||
uint_type, zero);
|
||||
Check(decorated_array ==
|
||||
declarations.DecoratedType(
|
||||
spv::OpTypeArray, {uint_type, zero},
|
||||
spv::OpTypeArray,
|
||||
{{spv::OpDecorate,
|
||||
{spv::DecorationArrayStride, sizeof(uint32_t)}}}),
|
||||
{spv::DecorationArrayStride, sizeof(uint32_t)}}},
|
||||
uint_type, zero),
|
||||
"decorated type interning returned different IDs");
|
||||
Check(plain_array != decorated_array,
|
||||
"decorated and undecorated aggregate types were aliased");
|
||||
Check(declarations.DecoratedType(spv::OpTypeArray, {uint_type, zero}, {}) ==
|
||||
Check(declarations.DecoratedType(spv::OpTypeArray, {}, uint_type, zero) ==
|
||||
plain_array,
|
||||
"empty decorated type request bypassed structural interning");
|
||||
const auto ptr = declarations.Type(spv::OpTypePointer,
|
||||
{spv::StorageClassFunction, uint_type});
|
||||
spv::StorageClassFunction, uint_type);
|
||||
Check(declarations.DefineGlobalVariable(ptr, spv::StorageClassFunction) !=
|
||||
declarations.DefineGlobalVariable(ptr, spv::StorageClassFunction),
|
||||
"distinct variables were structurally interned");
|
||||
@@ -13020,6 +13130,7 @@ int main() {
|
||||
TestNativeShaderResourceDependencies();
|
||||
TestNormalizedImageContracts();
|
||||
TestSpirvRequirementsAnalysis();
|
||||
TestTypedSpirvSerialization();
|
||||
TestDeferredSpirvPhiPatching();
|
||||
TestCompilerStageInputOwnership();
|
||||
TestSpirvEmissionOwnsRequirements();
|
||||
|
||||
Reference in New Issue
Block a user