Browse Source

shader: Split profile and runtime information in separate structs

ReinUsesLisp 5 years ago
parent
commit
9e7b6622c2

+ 21 - 19
src/shader_recompiler/backend/glasm/emit_context.cpp

@@ -23,23 +23,25 @@ std::string_view InterpDecorator(Interpolation interp) {
 }
 } // Anonymous namespace
 
-EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_)
-    : info{program.info}, profile{profile_} {
+EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
+                         const RuntimeInfo& runtime_info_)
+    : profile{profile_}, runtime_info{runtime_info_} {
     // FIXME: Temporary partial implementation
+    const auto& info{program.info};
     u32 cbuf_index{};
-    for (const auto& desc : program.info.constant_buffer_descriptors) {
+    for (const auto& desc : info.constant_buffer_descriptors) {
         if (desc.count != 1) {
             throw NotImplementedException("Constant buffer descriptor array");
         }
         Add("CBUFFER c{}[]={{program.buffer[{}]}};", desc.index, cbuf_index);
         ++cbuf_index;
     }
-    for (const auto& desc : program.info.storage_buffers_descriptors) {
+    for (const auto& desc : info.storage_buffers_descriptors) {
         if (desc.count != 1) {
             throw NotImplementedException("Storage buffer descriptor array");
         }
     }
-    if (const size_t num = program.info.storage_buffers_descriptors.size(); num > 0) {
+    if (const size_t num = info.storage_buffers_descriptors.size(); num > 0) {
         Add("PARAM c[{}]={{program.local[0..{}]}};", num, num - 1);
     }
     stage = program.stage;
@@ -67,8 +69,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
         break;
     }
     const std::string_view attr_stage{stage == Stage::Fragment ? "fragment" : "vertex"};
-    for (size_t index = 0; index < program.info.input_generics.size(); ++index) {
-        const auto& generic{program.info.input_generics[index]};
+    for (size_t index = 0; index < info.input_generics.size(); ++index) {
+        const auto& generic{info.input_generics[index]};
         if (generic.used) {
             Add("{}ATTRIB in_attr{}[]={{{}.attrib[{}..{}]}};",
                 InterpDecorator(generic.interpolation), index, attr_stage, index, index);
@@ -101,8 +103,8 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
                 index, index);
         }
     }
-    for (size_t index = 0; index < program.info.stores_frag_color.size(); ++index) {
-        if (!program.info.stores_frag_color[index]) {
+    for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
+        if (!info.stores_frag_color[index]) {
             continue;
         }
         if (index == 0) {
@@ -111,28 +113,28 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
             Add("OUTPUT frag_color{}=result.color[{}];", index, index);
         }
     }
-    for (size_t index = 0; index < program.info.stores_generics.size(); ++index) {
-        if (program.info.stores_generics[index]) {
+    for (size_t index = 0; index < info.stores_generics.size(); ++index) {
+        if (info.stores_generics[index]) {
             Add("OUTPUT out_attr{}[]={{result.attrib[{}..{}]}};", index, index, index);
         }
     }
-    image_buffer_bindings.reserve(program.info.image_buffer_descriptors.size());
-    for (const auto& desc : program.info.image_buffer_descriptors) {
+    image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
+    for (const auto& desc : info.image_buffer_descriptors) {
         image_buffer_bindings.push_back(bindings.image);
         bindings.image += desc.count;
     }
-    image_bindings.reserve(program.info.image_descriptors.size());
-    for (const auto& desc : program.info.image_descriptors) {
+    image_bindings.reserve(info.image_descriptors.size());
+    for (const auto& desc : info.image_descriptors) {
         image_bindings.push_back(bindings.image);
         bindings.image += desc.count;
     }
-    texture_buffer_bindings.reserve(program.info.texture_buffer_descriptors.size());
-    for (const auto& desc : program.info.texture_buffer_descriptors) {
+    texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
+    for (const auto& desc : info.texture_buffer_descriptors) {
         texture_buffer_bindings.push_back(bindings.texture);
         bindings.texture += desc.count;
     }
-    texture_bindings.reserve(program.info.texture_descriptors.size());
-    for (const auto& desc : program.info.texture_descriptors) {
+    texture_bindings.reserve(info.texture_descriptors.size());
+    for (const auto& desc : info.texture_descriptors) {
         texture_bindings.push_back(bindings.texture);
         bindings.texture += desc.count;
     }

+ 4 - 2
src/shader_recompiler/backend/glasm/emit_context.h

@@ -16,6 +16,7 @@
 namespace Shader {
 struct Info;
 struct Profile;
+struct RuntimeInfo;
 } // namespace Shader
 
 namespace Shader::Backend {
@@ -31,7 +32,8 @@ namespace Shader::Backend::GLASM {
 
 class EmitContext {
 public:
-    explicit EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_);
+    explicit EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_,
+                         const RuntimeInfo& runtime_info_);
 
     template <typename... Args>
     void Add(const char* format_str, IR::Inst& inst, Args&&... args) {
@@ -56,8 +58,8 @@ public:
 
     std::string code;
     RegAlloc reg_alloc{*this};
-    const Info& info;
     const Profile& profile;
+    const RuntimeInfo& runtime_info;
 
     std::vector<u32> texture_buffer_bindings;
     std::vector<u32> image_buffer_bindings;

+ 10 - 9
src/shader_recompiler/backend/glasm/emit_glasm.cpp

@@ -374,8 +374,9 @@ std::string_view GetTessSpacing(TessSpacing spacing) {
 }
 } // Anonymous namespace
 
-std::string EmitGLASM(const Profile& profile, IR::Program& program, Bindings& bindings) {
-    EmitContext ctx{program, bindings, profile};
+std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info, IR::Program& program,
+                      Bindings& bindings) {
+    EmitContext ctx{program, bindings, profile, runtime_info};
     Precolor(ctx, program);
     EmitCode(ctx, program);
     std::string header{StageHeader(program.stage)};
@@ -385,18 +386,18 @@ std::string EmitGLASM(const Profile& profile, IR::Program& program, Bindings& bi
         header += fmt::format("VERTICES_OUT {};", program.invocations);
         break;
     case Stage::TessellationEval:
-        header +=
-            fmt::format("TESS_MODE {};"
-                        "TESS_SPACING {};"
-                        "TESS_VERTEX_ORDER {};",
-                        GetTessMode(profile.tess_primitive), GetTessSpacing(profile.tess_spacing),
-                        profile.tess_clockwise ? "CW" : "CCW");
+        header += fmt::format("TESS_MODE {};"
+                              "TESS_SPACING {};"
+                              "TESS_VERTEX_ORDER {};",
+                              GetTessMode(runtime_info.tess_primitive),
+                              GetTessSpacing(runtime_info.tess_spacing),
+                              runtime_info.tess_clockwise ? "CW" : "CCW");
         break;
     case Stage::Geometry:
         header += fmt::format("PRIMITIVE_IN {};"
                               "PRIMITIVE_OUT {};"
                               "VERTICES_OUT {};",
-                              InputPrimitive(profile.input_topology),
+                              InputPrimitive(runtime_info.input_topology),
                               OutputPrimitive(program.output_topology), program.output_vertices);
         break;
     case Stage::Compute:

+ 3 - 3
src/shader_recompiler/backend/glasm/emit_glasm.h

@@ -12,12 +12,12 @@
 
 namespace Shader::Backend::GLASM {
 
-[[nodiscard]] std::string EmitGLASM(const Profile& profile, IR::Program& program,
-                                    Bindings& binding);
+[[nodiscard]] std::string EmitGLASM(const Profile& profile, const RuntimeInfo& runtime_info,
+                                    IR::Program& program, Bindings& bindings);
 
 [[nodiscard]] inline std::string EmitGLASM(const Profile& profile, IR::Program& program) {
     Bindings binding;
-    return EmitGLASM(profile, program, binding);
+    return EmitGLASM(profile, {}, program, binding);
 }
 
 } // namespace Shader::Backend::GLASM

+ 14 - 12
src/shader_recompiler/backend/spirv/emit_context.cpp

@@ -136,7 +136,7 @@ Id DefineInput(EmitContext& ctx, Id type, bool per_invocation,
         break;
     case Stage::Geometry:
         if (per_invocation) {
-            const u32 num_vertices{NumVertices(ctx.profile.input_topology)};
+            const u32 num_vertices{NumVertices(ctx.runtime_info.input_topology)};
             type = ctx.TypeArray(type, ctx.Const(num_vertices));
         }
         break;
@@ -161,8 +161,8 @@ void DefineGenericOutput(EmitContext& ctx, size_t index, std::optional<u32> invo
     while (element < 4) {
         const u32 remainder{4 - element};
         const TransformFeedbackVarying* xfb_varying{};
-        if (!ctx.profile.xfb_varyings.empty()) {
-            xfb_varying = &ctx.profile.xfb_varyings[base_attr_index + element];
+        if (!ctx.runtime_info.xfb_varyings.empty()) {
+            xfb_varying = &ctx.runtime_info.xfb_varyings[base_attr_index + element];
             xfb_varying = xfb_varying && xfb_varying->components > 0 ? xfb_varying : nullptr;
         }
         const u32 num_components{xfb_varying ? xfb_varying->components : remainder};
@@ -208,7 +208,7 @@ Id GetAttributeType(EmitContext& ctx, AttributeType type) {
 }
 
 std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
-    const AttributeType type{ctx.profile.generic_input_types.at(index)};
+    const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
     switch (type) {
     case AttributeType::Float:
         return AttrInfo{ctx.input_f32, ctx.F32[1], false};
@@ -441,13 +441,15 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
     }
 }
 
-EmitContext::EmitContext(const Profile& profile_, IR::Program& program, Bindings& binding)
-    : Sirit::Module(profile_.supported_spirv), profile{profile_}, stage{program.stage} {
+EmitContext::EmitContext(const Profile& profile_, const RuntimeInfo& runtime_info_,
+                         IR::Program& program, Bindings& bindings)
+    : Sirit::Module(profile_.supported_spirv), profile{profile_},
+      runtime_info{runtime_info_}, stage{program.stage} {
     const bool is_unified{profile.unified_descriptor_binding};
-    u32& uniform_binding{is_unified ? binding.unified : binding.uniform_buffer};
-    u32& storage_binding{is_unified ? binding.unified : binding.storage_buffer};
-    u32& texture_binding{is_unified ? binding.unified : binding.texture};
-    u32& image_binding{is_unified ? binding.unified : binding.image};
+    u32& uniform_binding{is_unified ? bindings.unified : bindings.uniform_buffer};
+    u32& storage_binding{is_unified ? bindings.unified : bindings.storage_buffer};
+    u32& texture_binding{is_unified ? bindings.unified : bindings.texture};
+    u32& image_binding{is_unified ? bindings.unified : bindings.image};
     AddCapability(spv::Capability::Shader);
     DefineCommonTypes(program.info);
     DefineCommonConstants();
@@ -1211,7 +1213,7 @@ void EmitContext::DefineInputs(const Info& info) {
         if (!generic.used) {
             continue;
         }
-        const AttributeType input_type{profile.generic_input_types[index]};
+        const AttributeType input_type{runtime_info.generic_input_types[index]};
         if (input_type == AttributeType::Disabled) {
             continue;
         }
@@ -1256,7 +1258,7 @@ void EmitContext::DefineOutputs(const IR::Program& program) {
     if (info.stores_position || stage == Stage::VertexB) {
         output_position = DefineOutput(*this, F32[4], invocations, spv::BuiltIn::Position);
     }
-    if (info.stores_point_size || profile.fixed_state_point_size) {
+    if (info.stores_point_size || runtime_info.fixed_state_point_size) {
         if (stage == Stage::Fragment) {
             throw NotImplementedException("Storing PointSize in fragment stage");
         }

+ 3 - 1
src/shader_recompiler/backend/spirv/emit_context.h

@@ -103,7 +103,8 @@ struct GenericElementInfo {
 
 class EmitContext final : public Sirit::Module {
 public:
-    explicit EmitContext(const Profile& profile, IR::Program& program, Bindings& binding);
+    explicit EmitContext(const Profile& profile, const RuntimeInfo& runtime_info,
+                         IR::Program& program, Bindings& binding);
     ~EmitContext();
 
     [[nodiscard]] Id Def(const IR::Value& value);
@@ -150,6 +151,7 @@ public:
     }
 
     const Profile& profile;
+    const RuntimeInfo& runtime_info;
     Stage stage{};
 
     Id void_id{};

+ 11 - 9
src/shader_recompiler/backend/spirv/emit_spirv.cpp

@@ -226,16 +226,17 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
     case Stage::TessellationEval:
         execution_model = spv::ExecutionModel::TessellationEvaluation;
         ctx.AddCapability(spv::Capability::Tessellation);
-        ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_primitive));
-        ctx.AddExecutionMode(main, ExecutionMode(ctx.profile.tess_spacing));
-        ctx.AddExecutionMode(main, ctx.profile.tess_clockwise ? spv::ExecutionMode::VertexOrderCw
-                                                              : spv::ExecutionMode::VertexOrderCcw);
+        ctx.AddExecutionMode(main, ExecutionMode(ctx.runtime_info.tess_primitive));
+        ctx.AddExecutionMode(main, ExecutionMode(ctx.runtime_info.tess_spacing));
+        ctx.AddExecutionMode(main, ctx.runtime_info.tess_clockwise
+                                       ? spv::ExecutionMode::VertexOrderCw
+                                       : spv::ExecutionMode::VertexOrderCcw);
         break;
     case Stage::Geometry:
         execution_model = spv::ExecutionModel::Geometry;
         ctx.AddCapability(spv::Capability::Geometry);
         ctx.AddCapability(spv::Capability::GeometryStreams);
-        switch (ctx.profile.input_topology) {
+        switch (ctx.runtime_info.input_topology) {
         case InputTopology::Points:
             ctx.AddExecutionMode(main, spv::ExecutionMode::InputPoints);
             break;
@@ -279,7 +280,7 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) {
         if (program.info.stores_frag_depth) {
             ctx.AddExecutionMode(main, spv::ExecutionMode::DepthReplacing);
         }
-        if (ctx.profile.force_early_z) {
+        if (ctx.runtime_info.force_early_z) {
             ctx.AddExecutionMode(main, spv::ExecutionMode::EarlyFragmentTests);
         }
         break;
@@ -402,7 +403,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
     if (info.uses_sample_id) {
         ctx.AddCapability(spv::Capability::SampleRateShading);
     }
-    if (!ctx.profile.xfb_varyings.empty()) {
+    if (!ctx.runtime_info.xfb_varyings.empty()) {
         ctx.AddCapability(spv::Capability::TransformFeedback);
     }
     if (info.uses_derivatives) {
@@ -433,8 +434,9 @@ void PatchPhiNodes(IR::Program& program, EmitContext& ctx) {
 }
 } // Anonymous namespace
 
-std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program, Bindings& binding) {
-    EmitContext ctx{profile, program, binding};
+std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
+                           IR::Program& program, Bindings& bindings) {
+    EmitContext ctx{profile, runtime_info, program, bindings};
     const Id main{DefineMain(ctx, program)};
     DefineEntryPoint(program, ctx, main);
     if (profile.support_float_controls) {

+ 3 - 3
src/shader_recompiler/backend/spirv/emit_spirv.h

@@ -16,12 +16,12 @@
 
 namespace Shader::Backend::SPIRV {
 
-[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program,
-                                         Bindings& binding);
+[[nodiscard]] std::vector<u32> EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_info,
+                                         IR::Program& program, Bindings& bindings);
 
 [[nodiscard]] inline std::vector<u32> EmitSPIRV(const Profile& profile, IR::Program& program) {
     Bindings binding;
-    return EmitSPIRV(profile, program, binding);
+    return EmitSPIRV(profile, {}, program, binding);
 }
 
 } // namespace Shader::Backend::SPIRV

+ 2 - 2
src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp

@@ -17,7 +17,7 @@ struct AttrInfo {
 };
 
 std::optional<AttrInfo> AttrTypes(EmitContext& ctx, u32 index) {
-    const AttributeType type{ctx.profile.generic_input_types.at(index)};
+    const AttributeType type{ctx.runtime_info.generic_input_types.at(index)};
     switch (type) {
     case AttributeType::Float:
         return AttrInfo{ctx.input_f32, ctx.F32[1], false};
@@ -468,7 +468,7 @@ Id EmitIsHelperInvocation(EmitContext& ctx) {
 }
 
 Id EmitYDirection(EmitContext& ctx) {
-    return ctx.Const(ctx.profile.y_negate ? -1.0f : 1.0f);
+    return ctx.Const(ctx.runtime_info.y_negate ? -1.0f : 1.0f);
 }
 
 Id EmitLoadLocal(EmitContext& ctx, Id word_offset) {

+ 9 - 6
src/shader_recompiler/backend/spirv/emit_spirv_special.cpp

@@ -18,8 +18,8 @@ void ConvertDepthMode(EmitContext& ctx) {
 }
 
 void SetFixedPipelinePointSize(EmitContext& ctx) {
-    if (ctx.profile.fixed_state_point_size) {
-        const float point_size{*ctx.profile.fixed_state_point_size};
+    if (ctx.runtime_info.fixed_state_point_size) {
+        const float point_size{*ctx.runtime_info.fixed_state_point_size};
         ctx.OpStore(ctx.output_point_size, ctx.Const(point_size));
     }
 }
@@ -62,7 +62,10 @@ Id ComparisonFunction(EmitContext& ctx, CompareFunction comparison, Id operand_1
 }
 
 void AlphaTest(EmitContext& ctx) {
-    const auto comparison{*ctx.profile.alpha_test_func};
+    if (!ctx.runtime_info.alpha_test_func) {
+        return;
+    }
+    const auto comparison{*ctx.runtime_info.alpha_test_func};
     if (comparison == CompareFunction::Always) {
         return;
     }
@@ -76,7 +79,7 @@ void AlphaTest(EmitContext& ctx) {
 
     const Id true_label{ctx.OpLabel()};
     const Id discard_label{ctx.OpLabel()};
-    const Id alpha_reference{ctx.Const(ctx.profile.alpha_test_reference)};
+    const Id alpha_reference{ctx.Const(ctx.runtime_info.alpha_test_reference)};
     const Id condition{ComparisonFunction(ctx, comparison, alpha, alpha_reference)};
 
     ctx.OpSelectionMerge(true_label, spv::SelectionControlMask::MaskNone);
@@ -113,7 +116,7 @@ void EmitPrologue(EmitContext& ctx) {
 }
 
 void EmitEpilogue(EmitContext& ctx) {
-    if (ctx.stage == Stage::VertexB && ctx.profile.convert_depth_mode) {
+    if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) {
         ConvertDepthMode(ctx);
     }
     if (ctx.stage == Stage::Fragment) {
@@ -122,7 +125,7 @@ void EmitEpilogue(EmitContext& ctx) {
 }
 
 void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
-    if (ctx.profile.convert_depth_mode) {
+    if (ctx.runtime_info.convert_depth_mode) {
         ConvertDepthMode(ctx);
     }
     if (stream.IsImmediate()) {

+ 8 - 5
src/shader_recompiler/profile.h

@@ -81,19 +81,22 @@ struct Profile {
     bool support_viewport_mask{};
     bool support_typeless_image_loads{};
     bool support_demote_to_helper_invocation{};
-    bool warp_size_potentially_larger_than_guest{};
     bool support_int64_atomics{};
+
+    bool warp_size_potentially_larger_than_guest{};
     bool lower_left_origin_mode{};
 
-    // FClamp is broken and OpFMax + OpFMin should be used instead
+    /// OpFClamp is broken and OpFMax + OpFMin should be used instead
     bool has_broken_spirv_clamp{};
-    // Offset image operands with an unsigned type do not work
+    /// Offset image operands with an unsigned type do not work
     bool has_broken_unsigned_image_offsets{};
-    // Signed instructions with unsigned data types are misinterpreted
+    /// Signed instructions with unsigned data types are misinterpreted
     bool has_broken_signed_operations{};
-    // Ignores SPIR-V ordered vs unordered using GLSL semantics
+    /// Ignores SPIR-V ordered vs unordered using GLSL semantics
     bool ignore_nan_fp_comparisons{};
+};
 
+struct RuntimeInfo {
     std::array<AttributeType, 32> generic_input_types{};
     bool convert_depth_mode{};
     bool force_early_z{};

+ 4 - 22
src/video_core/renderer_opengl/gl_shader_cache.cpp

@@ -61,33 +61,15 @@ const Shader::Profile profile{
     .support_viewport_mask = true,
     .support_typeless_image_loads = true,
     .support_demote_to_helper_invocation = false,
-    .warp_size_potentially_larger_than_guest = true,
     .support_int64_atomics = false,
+
+    .warp_size_potentially_larger_than_guest = true,
     .lower_left_origin_mode = true,
 
     .has_broken_spirv_clamp = true,
     .has_broken_unsigned_image_offsets = true,
     .has_broken_signed_operations = true,
     .ignore_nan_fp_comparisons = true,
-
-    .generic_input_types = {},
-    .convert_depth_mode = false,
-    .force_early_z = false,
-
-    .tess_primitive = {},
-    .tess_spacing = {},
-    .tess_clockwise = false,
-
-    .input_topology = Shader::InputTopology::Triangles,
-
-    .fixed_state_point_size = std::nullopt,
-
-    .alpha_test_func = Shader::CompareFunction::Always,
-    .alpha_test_reference = 0.0f,
-
-    .y_negate = false,
-
-    .xfb_varyings = {},
 };
 
 using Shader::Backend::GLASM::EmitGLASM;
@@ -302,10 +284,10 @@ std::unique_ptr<GraphicsProgram> ShaderCache::CreateGraphicsProgram(
         const size_t stage_index{index - 1};
         infos[stage_index] = &program.info;
         if (device.UseAssemblyShaders()) {
-            const std::string code{EmitGLASM(profile, program, binding)};
+            const std::string code{EmitGLASM(profile, {}, program, binding)};
             assembly_programs[stage_index] = CompileProgram(code, AssemblyStage(stage_index));
         } else {
-            const std::vector<u32> code{EmitSPIRV(profile, program, binding)};
+            const std::vector<u32> code{EmitSPIRV(profile, {}, program, binding)};
             AddShader(Stage(stage_index), source_program.handle, code);
         }
     }

+ 207 - 211
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp

@@ -89,6 +89,208 @@ Shader::CompareFunction MaxwellToCompareFunction(Maxwell::ComparisonOp compariso
     UNIMPLEMENTED_MSG("Unimplemented comparison op={}", comparison);
     return {};
 }
+
+static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) {
+    if (attr.enabled == 0) {
+        return Shader::AttributeType::Disabled;
+    }
+    switch (attr.Type()) {
+    case Maxwell::VertexAttribute::Type::SignedNorm:
+    case Maxwell::VertexAttribute::Type::UnsignedNorm:
+    case Maxwell::VertexAttribute::Type::UnsignedScaled:
+    case Maxwell::VertexAttribute::Type::SignedScaled:
+    case Maxwell::VertexAttribute::Type::Float:
+        return Shader::AttributeType::Float;
+    case Maxwell::VertexAttribute::Type::SignedInt:
+        return Shader::AttributeType::SignedInt;
+    case Maxwell::VertexAttribute::Type::UnsignedInt:
+        return Shader::AttributeType::UnsignedInt;
+    }
+    return Shader::AttributeType::Float;
+}
+
+std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings(
+    const GraphicsPipelineCacheKey& key) {
+    static constexpr std::array VECTORS{
+        28,  // gl_Position
+        32,  // Generic 0
+        36,  // Generic 1
+        40,  // Generic 2
+        44,  // Generic 3
+        48,  // Generic 4
+        52,  // Generic 5
+        56,  // Generic 6
+        60,  // Generic 7
+        64,  // Generic 8
+        68,  // Generic 9
+        72,  // Generic 10
+        76,  // Generic 11
+        80,  // Generic 12
+        84,  // Generic 13
+        88,  // Generic 14
+        92,  // Generic 15
+        96,  // Generic 16
+        100, // Generic 17
+        104, // Generic 18
+        108, // Generic 19
+        112, // Generic 20
+        116, // Generic 21
+        120, // Generic 22
+        124, // Generic 23
+        128, // Generic 24
+        132, // Generic 25
+        136, // Generic 26
+        140, // Generic 27
+        144, // Generic 28
+        148, // Generic 29
+        152, // Generic 30
+        156, // Generic 31
+        160, // gl_FrontColor
+        164, // gl_FrontSecondaryColor
+        160, // gl_BackColor
+        164, // gl_BackSecondaryColor
+        192, // gl_TexCoord[0]
+        196, // gl_TexCoord[1]
+        200, // gl_TexCoord[2]
+        204, // gl_TexCoord[3]
+        208, // gl_TexCoord[4]
+        212, // gl_TexCoord[5]
+        216, // gl_TexCoord[6]
+        220, // gl_TexCoord[7]
+    };
+    std::vector<Shader::TransformFeedbackVarying> xfb(256);
+    for (size_t buffer = 0; buffer < Maxwell::NumTransformFeedbackBuffers; ++buffer) {
+        const auto& locations = key.state.xfb_state.varyings[buffer];
+        const auto& layout = key.state.xfb_state.layouts[buffer];
+        const u32 varying_count = layout.varying_count;
+        u32 highest = 0;
+        for (u32 offset = 0; offset < varying_count; ++offset) {
+            const u32 base_offset = offset;
+            const u8 location = locations[offset];
+
+            Shader::TransformFeedbackVarying varying;
+            varying.buffer = layout.stream;
+            varying.stride = layout.stride;
+            varying.offset = offset * 4;
+            varying.components = 1;
+
+            if (std::ranges::find(VECTORS, Common::AlignDown(location, 4)) != VECTORS.end()) {
+                UNIMPLEMENTED_IF_MSG(location % 4 != 0, "Unaligned TFB");
+
+                const u8 base_index = location / 4;
+                while (offset + 1 < varying_count && base_index == locations[offset + 1] / 4) {
+                    ++offset;
+                    ++varying.components;
+                }
+            }
+            xfb[location] = varying;
+            highest = std::max(highest, (base_offset + varying.components) * 4);
+        }
+        UNIMPLEMENTED_IF(highest != layout.stride);
+    }
+    return xfb;
+}
+
+Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineCacheKey& key,
+                                    const Shader::IR::Program& program) {
+    Shader::RuntimeInfo info;
+
+    const Shader::Stage stage{program.stage};
+    const bool has_geometry{key.unique_hashes[4] != 0};
+    const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
+    const float point_size{Common::BitCast<float>(key.state.point_size)};
+    switch (stage) {
+    case Shader::Stage::VertexB:
+        if (!has_geometry) {
+            if (key.state.topology == Maxwell::PrimitiveTopology::Points) {
+                info.fixed_state_point_size = point_size;
+            }
+            if (key.state.xfb_enabled != 0) {
+                info.xfb_varyings = MakeTransformFeedbackVaryings(key);
+            }
+            info.convert_depth_mode = gl_ndc;
+        }
+        std::ranges::transform(key.state.attributes, info.generic_input_types.begin(),
+                               &CastAttributeType);
+        break;
+    case Shader::Stage::TessellationEval:
+        // We have to flip tessellation clockwise for some reason...
+        info.tess_clockwise = key.state.tessellation_clockwise == 0;
+        info.tess_primitive = [&key] {
+            const u32 raw{key.state.tessellation_primitive.Value()};
+            switch (static_cast<Maxwell::TessellationPrimitive>(raw)) {
+            case Maxwell::TessellationPrimitive::Isolines:
+                return Shader::TessPrimitive::Isolines;
+            case Maxwell::TessellationPrimitive::Triangles:
+                return Shader::TessPrimitive::Triangles;
+            case Maxwell::TessellationPrimitive::Quads:
+                return Shader::TessPrimitive::Quads;
+            }
+            UNREACHABLE();
+            return Shader::TessPrimitive::Triangles;
+        }();
+        info.tess_spacing = [&] {
+            const u32 raw{key.state.tessellation_spacing};
+            switch (static_cast<Maxwell::TessellationSpacing>(raw)) {
+            case Maxwell::TessellationSpacing::Equal:
+                return Shader::TessSpacing::Equal;
+            case Maxwell::TessellationSpacing::FractionalOdd:
+                return Shader::TessSpacing::FractionalOdd;
+            case Maxwell::TessellationSpacing::FractionalEven:
+                return Shader::TessSpacing::FractionalEven;
+            }
+            UNREACHABLE();
+            return Shader::TessSpacing::Equal;
+        }();
+        break;
+    case Shader::Stage::Geometry:
+        if (program.output_topology == Shader::OutputTopology::PointList) {
+            info.fixed_state_point_size = point_size;
+        }
+        if (key.state.xfb_enabled != 0) {
+            info.xfb_varyings = MakeTransformFeedbackVaryings(key);
+        }
+        info.convert_depth_mode = gl_ndc;
+        break;
+    case Shader::Stage::Fragment:
+        info.alpha_test_func = MaxwellToCompareFunction(
+            key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
+        info.alpha_test_reference = Common::BitCast<float>(key.state.alpha_test_ref);
+        break;
+    default:
+        break;
+    }
+    switch (key.state.topology) {
+    case Maxwell::PrimitiveTopology::Points:
+        info.input_topology = Shader::InputTopology::Points;
+        break;
+    case Maxwell::PrimitiveTopology::Lines:
+    case Maxwell::PrimitiveTopology::LineLoop:
+    case Maxwell::PrimitiveTopology::LineStrip:
+        info.input_topology = Shader::InputTopology::Lines;
+        break;
+    case Maxwell::PrimitiveTopology::Triangles:
+    case Maxwell::PrimitiveTopology::TriangleStrip:
+    case Maxwell::PrimitiveTopology::TriangleFan:
+    case Maxwell::PrimitiveTopology::Quads:
+    case Maxwell::PrimitiveTopology::QuadStrip:
+    case Maxwell::PrimitiveTopology::Polygon:
+    case Maxwell::PrimitiveTopology::Patches:
+        info.input_topology = Shader::InputTopology::Triangles;
+        break;
+    case Maxwell::PrimitiveTopology::LinesAdjacency:
+    case Maxwell::PrimitiveTopology::LineStripAdjacency:
+        info.input_topology = Shader::InputTopology::LinesAdjacency;
+        break;
+    case Maxwell::PrimitiveTopology::TrianglesAdjacency:
+    case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
+        info.input_topology = Shader::InputTopology::TrianglesAdjacency;
+        break;
+    }
+    info.force_early_z = key.state.early_z != 0;
+    info.y_negate = key.state.y_negate != 0;
+    return info;
+}
 } // Anonymous namespace
 
 size_t ComputePipelineCacheKey::Hash() const noexcept {
@@ -124,7 +326,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
       serialization_thread(1, "yuzu:PipelineSerialization") {
     const auto& float_control{device.FloatControlProperties()};
     const VkDriverIdKHR driver_id{device.GetDriverID()};
-    base_profile = Shader::Profile{
+    profile = Shader::Profile{
         .supported_spirv = device.IsKhrSpirv1_4Supported() ? 0x00010400U : 0x00010000U,
         .unified_descriptor_binding = true,
         .support_descriptor_aliasing = true,
@@ -153,14 +355,10 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
         .support_viewport_mask = device.IsNvViewportArray2Supported(),
         .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
         .support_demote_to_helper_invocation = true,
-        .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
         .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
+        .warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
         .has_broken_spirv_clamp = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR,
         .has_broken_unsigned_image_offsets = false,
-        .generic_input_types{},
-        .fixed_state_point_size{},
-        .alpha_test_func{},
-        .xfb_varyings{},
     };
 }
 
@@ -329,8 +527,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
         const size_t stage_index{index - 1};
         infos[stage_index] = &program.info;
 
-        const Shader::Profile profile{MakeProfile(key, program)};
-        const std::vector<u32> code{EmitSPIRV(profile, program, binding)};
+        const Shader::RuntimeInfo runtime_info{MakeRuntimeInfo(key, program)};
+        const std::vector<u32> code{EmitSPIRV(profile, runtime_info, program, binding)};
         device.SaveShader(code);
         modules[stage_index] = BuildShader(device, code);
         if (device.HasDebuggingToolAttached()) {
@@ -391,7 +589,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
 
     Shader::Maxwell::Flow::CFG cfg{env, pools.flow_block, env.StartAddress()};
     Shader::IR::Program program{TranslateProgram(pools.inst, pools.block, env, cfg)};
-    const std::vector<u32> code{EmitSPIRV(base_profile, program)};
+    const std::vector<u32> code{EmitSPIRV(profile, program)};
     device.SaveShader(code);
     vk::ShaderModule spv_module{BuildShader(device, code)};
     if (device.HasDebuggingToolAttached()) {
@@ -403,206 +601,4 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
                                              thread_worker, program.info, std::move(spv_module));
 }
 
-static Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribute& attr) {
-    if (attr.enabled == 0) {
-        return Shader::AttributeType::Disabled;
-    }
-    switch (attr.Type()) {
-    case Maxwell::VertexAttribute::Type::SignedNorm:
-    case Maxwell::VertexAttribute::Type::UnsignedNorm:
-    case Maxwell::VertexAttribute::Type::UnsignedScaled:
-    case Maxwell::VertexAttribute::Type::SignedScaled:
-    case Maxwell::VertexAttribute::Type::Float:
-        return Shader::AttributeType::Float;
-    case Maxwell::VertexAttribute::Type::SignedInt:
-        return Shader::AttributeType::SignedInt;
-    case Maxwell::VertexAttribute::Type::UnsignedInt:
-        return Shader::AttributeType::UnsignedInt;
-    }
-    return Shader::AttributeType::Float;
-}
-
-static std::vector<Shader::TransformFeedbackVarying> MakeTransformFeedbackVaryings(
-    const GraphicsPipelineCacheKey& key) {
-    static constexpr std::array VECTORS{
-        28,  // gl_Position
-        32,  // Generic 0
-        36,  // Generic 1
-        40,  // Generic 2
-        44,  // Generic 3
-        48,  // Generic 4
-        52,  // Generic 5
-        56,  // Generic 6
-        60,  // Generic 7
-        64,  // Generic 8
-        68,  // Generic 9
-        72,  // Generic 10
-        76,  // Generic 11
-        80,  // Generic 12
-        84,  // Generic 13
-        88,  // Generic 14
-        92,  // Generic 15
-        96,  // Generic 16
-        100, // Generic 17
-        104, // Generic 18
-        108, // Generic 19
-        112, // Generic 20
-        116, // Generic 21
-        120, // Generic 22
-        124, // Generic 23
-        128, // Generic 24
-        132, // Generic 25
-        136, // Generic 26
-        140, // Generic 27
-        144, // Generic 28
-        148, // Generic 29
-        152, // Generic 30
-        156, // Generic 31
-        160, // gl_FrontColor
-        164, // gl_FrontSecondaryColor
-        160, // gl_BackColor
-        164, // gl_BackSecondaryColor
-        192, // gl_TexCoord[0]
-        196, // gl_TexCoord[1]
-        200, // gl_TexCoord[2]
-        204, // gl_TexCoord[3]
-        208, // gl_TexCoord[4]
-        212, // gl_TexCoord[5]
-        216, // gl_TexCoord[6]
-        220, // gl_TexCoord[7]
-    };
-    std::vector<Shader::TransformFeedbackVarying> xfb(256);
-    for (size_t buffer = 0; buffer < Maxwell::NumTransformFeedbackBuffers; ++buffer) {
-        const auto& locations = key.state.xfb_state.varyings[buffer];
-        const auto& layout = key.state.xfb_state.layouts[buffer];
-        const u32 varying_count = layout.varying_count;
-        u32 highest = 0;
-        for (u32 offset = 0; offset < varying_count; ++offset) {
-            const u32 base_offset = offset;
-            const u8 location = locations[offset];
-
-            Shader::TransformFeedbackVarying varying;
-            varying.buffer = layout.stream;
-            varying.stride = layout.stride;
-            varying.offset = offset * 4;
-            varying.components = 1;
-
-            if (std::ranges::find(VECTORS, Common::AlignDown(location, 4)) != VECTORS.end()) {
-                UNIMPLEMENTED_IF_MSG(location % 4 != 0, "Unaligned TFB");
-
-                const u8 base_index = location / 4;
-                while (offset + 1 < varying_count && base_index == locations[offset + 1] / 4) {
-                    ++offset;
-                    ++varying.components;
-                }
-            }
-            xfb[location] = varying;
-            highest = std::max(highest, (base_offset + varying.components) * 4);
-        }
-        UNIMPLEMENTED_IF(highest != layout.stride);
-    }
-    return xfb;
-}
-
-Shader::Profile PipelineCache::MakeProfile(const GraphicsPipelineCacheKey& key,
-                                           const Shader::IR::Program& program) {
-    Shader::Profile profile{base_profile};
-
-    const Shader::Stage stage{program.stage};
-    const bool has_geometry{key.unique_hashes[4] != 0};
-    const bool gl_ndc{key.state.ndc_minus_one_to_one != 0};
-    const float point_size{Common::BitCast<float>(key.state.point_size)};
-    switch (stage) {
-    case Shader::Stage::VertexB:
-        if (!has_geometry) {
-            if (key.state.topology == Maxwell::PrimitiveTopology::Points) {
-                profile.fixed_state_point_size = point_size;
-            }
-            if (key.state.xfb_enabled != 0) {
-                profile.xfb_varyings = MakeTransformFeedbackVaryings(key);
-            }
-            profile.convert_depth_mode = gl_ndc;
-        }
-        std::ranges::transform(key.state.attributes, profile.generic_input_types.begin(),
-                               &CastAttributeType);
-        break;
-    case Shader::Stage::TessellationEval:
-        // We have to flip tessellation clockwise for some reason...
-        profile.tess_clockwise = key.state.tessellation_clockwise == 0;
-        profile.tess_primitive = [&key] {
-            const u32 raw{key.state.tessellation_primitive.Value()};
-            switch (static_cast<Maxwell::TessellationPrimitive>(raw)) {
-            case Maxwell::TessellationPrimitive::Isolines:
-                return Shader::TessPrimitive::Isolines;
-            case Maxwell::TessellationPrimitive::Triangles:
-                return Shader::TessPrimitive::Triangles;
-            case Maxwell::TessellationPrimitive::Quads:
-                return Shader::TessPrimitive::Quads;
-            }
-            UNREACHABLE();
-            return Shader::TessPrimitive::Triangles;
-        }();
-        profile.tess_spacing = [&] {
-            const u32 raw{key.state.tessellation_spacing};
-            switch (static_cast<Maxwell::TessellationSpacing>(raw)) {
-            case Maxwell::TessellationSpacing::Equal:
-                return Shader::TessSpacing::Equal;
-            case Maxwell::TessellationSpacing::FractionalOdd:
-                return Shader::TessSpacing::FractionalOdd;
-            case Maxwell::TessellationSpacing::FractionalEven:
-                return Shader::TessSpacing::FractionalEven;
-            }
-            UNREACHABLE();
-            return Shader::TessSpacing::Equal;
-        }();
-        break;
-    case Shader::Stage::Geometry:
-        if (program.output_topology == Shader::OutputTopology::PointList) {
-            profile.fixed_state_point_size = point_size;
-        }
-        if (key.state.xfb_enabled != 0) {
-            profile.xfb_varyings = MakeTransformFeedbackVaryings(key);
-        }
-        profile.convert_depth_mode = gl_ndc;
-        break;
-    case Shader::Stage::Fragment:
-        profile.alpha_test_func = MaxwellToCompareFunction(
-            key.state.UnpackComparisonOp(key.state.alpha_test_func.Value()));
-        profile.alpha_test_reference = Common::BitCast<float>(key.state.alpha_test_ref);
-        break;
-    default:
-        break;
-    }
-    switch (key.state.topology) {
-    case Maxwell::PrimitiveTopology::Points:
-        profile.input_topology = Shader::InputTopology::Points;
-        break;
-    case Maxwell::PrimitiveTopology::Lines:
-    case Maxwell::PrimitiveTopology::LineLoop:
-    case Maxwell::PrimitiveTopology::LineStrip:
-        profile.input_topology = Shader::InputTopology::Lines;
-        break;
-    case Maxwell::PrimitiveTopology::Triangles:
-    case Maxwell::PrimitiveTopology::TriangleStrip:
-    case Maxwell::PrimitiveTopology::TriangleFan:
-    case Maxwell::PrimitiveTopology::Quads:
-    case Maxwell::PrimitiveTopology::QuadStrip:
-    case Maxwell::PrimitiveTopology::Polygon:
-    case Maxwell::PrimitiveTopology::Patches:
-        profile.input_topology = Shader::InputTopology::Triangles;
-        break;
-    case Maxwell::PrimitiveTopology::LinesAdjacency:
-    case Maxwell::PrimitiveTopology::LineStripAdjacency:
-        profile.input_topology = Shader::InputTopology::LinesAdjacency;
-        break;
-    case Maxwell::PrimitiveTopology::TrianglesAdjacency:
-    case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
-        profile.input_topology = Shader::InputTopology::TrianglesAdjacency;
-        break;
-    }
-    profile.force_early_z = key.state.early_z != 0;
-    profile.y_negate = key.state.y_negate != 0;
-    return profile;
-}
-
 } // namespace Vulkan

+ 1 - 4
src/video_core/renderer_vulkan/vk_pipeline_cache.h

@@ -129,9 +129,6 @@ private:
                                                            Shader::Environment& env,
                                                            bool build_in_parallel);
 
-    Shader::Profile MakeProfile(const GraphicsPipelineCacheKey& key,
-                                const Shader::IR::Program& program);
-
     const Device& device;
     VKScheduler& scheduler;
     DescriptorPool& descriptor_pool;
@@ -148,7 +145,7 @@ private:
 
     ShaderPools main_pools;
 
-    Shader::Profile base_profile;
+    Shader::Profile profile;
     std::filesystem::path pipeline_cache_filename;
 
     Common::ThreadWorker workers;