shader: Split profile and runtime information in separate structs
This commit is contained in:
		| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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 {};" | ||||
|         header += fmt::format("TESS_MODE {};" | ||||
|                               "TESS_SPACING {};" | ||||
|                               "TESS_VERTEX_ORDER {};", | ||||
|                         GetTessMode(profile.tess_primitive), GetTessSpacing(profile.tess_spacing), | ||||
|                         profile.tess_clockwise ? "CW" : "CCW"); | ||||
|                               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: | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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"); | ||||
|         } | ||||
|   | ||||
| @@ -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{}; | ||||
|   | ||||
| @@ -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 | ||||
|         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) { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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()) { | ||||
|   | ||||
| @@ -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{}; | ||||
|   | ||||
| @@ -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); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user