From 0b12e22331951be45043b87a65ae2984d9c35ebf Mon Sep 17 00:00:00 2001 From: Samuliak Date: Sat, 5 Oct 2024 19:28:27 +0200 Subject: [PATCH] emit vertex attributes --- .../backend/msl/msl_emit_context.cpp | 26 ++-- .../backend/msl/msl_emit_context.h | 2 +- .../renderer_metal/mtl_pipeline_cache.cpp | 125 +++++++++++++++++- 3 files changed, 137 insertions(+), 16 deletions(-) diff --git a/src/shader_recompiler/backend/msl/msl_emit_context.cpp b/src/shader_recompiler/backend/msl/msl_emit_context.cpp index 4f13d732a5..995f6378a6 100644 --- a/src/shader_recompiler/backend/msl/msl_emit_context.cpp +++ b/src/shader_recompiler/backend/msl/msl_emit_context.cpp @@ -49,6 +49,7 @@ std::string_view InputArrayDecorator(Stage stage) { */ // TODO +/* std::string OutputDecorator(Stage stage, u32 size) { switch (stage) { case Stage::TessellationControl: @@ -57,6 +58,7 @@ std::string OutputDecorator(Stage stage, u32 size) { return ""; } } +*/ /* // TODO @@ -240,13 +242,13 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile stage_name = "vertex"; break; case Stage::TessellationControl: - stage_name = "kernel"; + stage_name = "INVALID"; break; case Stage::TessellationEval: - stage_name = "vertex"; + stage_name = "INVALID"; break; case Stage::Geometry: - stage_name = "vertex"; + stage_name = "INVALID"; break; case Stage::Fragment: stage_name = "fragment"; @@ -275,7 +277,11 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile if (!info.loads.Generic(index) || !runtime_info.previous_stage_stores.Generic(index)) { continue; } - DefineStageInOut(index, program.invocations, true); + const std::string qualifier{(stage == Stage::VertexA || stage == Stage::VertexB) ? "attribute(" : "user(locn"}; + // TODO: uncomment + header += fmt::format("float4 attr{} [[{}{})]];\n"/*, + InterpDecorator(info.interpolation[index])*/, index/*, + InputArrayDecorator(stage)*/, qualifier, index); has_stage_input = true; } for (size_t index = 0; index < info.uses_patches.size(); ++index) { @@ -319,7 +325,7 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile } for (size_t index = 0; index < IR::NUM_GENERICS; ++index) { if (info.stores.Generic(index)) { - DefineStageInOut(index, program.invocations, false); + DefineStageOut(index, program.invocations); } } header += "};\n"; @@ -437,14 +443,13 @@ void EmitContext::DefineInputs(Bindings& bindings) { } // TODO -void EmitContext::DefineStageInOut(size_t index, u32 invocations, bool is_input) { - const auto type{fmt::format("float{}", 4)}; +void EmitContext::DefineStageOut(size_t index, u32 invocations) { std::string name{fmt::format("attr{}", index)}; - header += fmt::format("{} {}{} [[user(locn{})]];\n", type, name, - OutputDecorator(stage, invocations), index); + header += fmt::format("float4 {} [[user(locn{})]];\n", name/*, + OutputDecorator(stage, invocations)*/, index); const GenericElementInfo element_info{ - .name = (is_input ? "__in." : "__out.") + name, + .name = "__out." + name, .first_element = 0, .num_components = 4, }; @@ -452,6 +457,7 @@ void EmitContext::DefineStageInOut(size_t index, u32 invocations, bool is_input) } void EmitContext::DefineHelperFunctions() { + // TODO: use MSL's extract_bits instead header += "uint bitfieldExtract(uint value, int offset, int bits) {\nreturn (value >> offset) & " "((1 << bits) - 1);\n}\n"; diff --git a/src/shader_recompiler/backend/msl/msl_emit_context.h b/src/shader_recompiler/backend/msl/msl_emit_context.h index df00489cc2..20caa2df0b 100644 --- a/src/shader_recompiler/backend/msl/msl_emit_context.h +++ b/src/shader_recompiler/backend/msl/msl_emit_context.h @@ -162,7 +162,7 @@ public: private: // TODO: break down into smaller functions void DefineInputs(Bindings& bindings); - void DefineStageInOut(size_t index, u32 invocations, bool is_input); + void DefineStageOut(size_t index, u32 invocations); void DefineHelperFunctions(); void DefineConstants(); std::string DefineGlobalMemoryFunctions(); diff --git a/src/video_core/renderer_metal/mtl_pipeline_cache.cpp b/src/video_core/renderer_metal/mtl_pipeline_cache.cpp index 3ae03289e3..80786e1d1c 100644 --- a/src/video_core/renderer_metal/mtl_pipeline_cache.cpp +++ b/src/video_core/renderer_metal/mtl_pipeline_cache.cpp @@ -56,9 +56,124 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span program const GraphicsPipelineCacheKey& key, const Shader::IR::Program& program, const Shader::IR::Program* previous_program) { - Shader::RuntimeInfo info{}; - - // TODO: fill in the runtime info + Shader::RuntimeInfo info; + if (previous_program) { + info.previous_stage_stores = previous_program->info.stores; + info.previous_stage_legacy_stores_mapping = previous_program->info.legacy_stores_mapping; + if (previous_program->is_geometry_passthrough) { + info.previous_stage_stores.mask |= previous_program->info.passthrough.mask; + } + } else { + info.previous_stage_stores.mask.set(); + } + // TODO: uncomment + /* + const Shader::Stage stage{program.stage}; + const bool has_geometry{key.unique_hashes[4] != 0 && !programs[4].is_geometry_passthrough}; + const bool gl_ndc{key.state.ndc_minus_one_to_one != 0}; + const float point_size{Common::BitCast(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) { + auto [varyings, count] = + VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + info.xfb_varyings = varyings; + info.xfb_count = count; + } + info.convert_depth_mode = gl_ndc; + } + if (key.state.dynamic_vertex_input) { + for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) { + info.generic_input_types[index] = AttributeType(key.state, index); + } + } else { + std::ranges::transform(key.state.attributes, info.generic_input_types.begin(), + &CastAttributeType); + } + break; + case Shader::Stage::TessellationEval: + info.tess_clockwise = key.state.tessellation_clockwise != 0; + info.tess_primitive = [&key] { + const u32 raw{key.state.tessellation_primitive.Value()}; + switch (static_cast(raw)) { + case Maxwell::Tessellation::DomainType::Isolines: + return Shader::TessPrimitive::Isolines; + case Maxwell::Tessellation::DomainType::Triangles: + return Shader::TessPrimitive::Triangles; + case Maxwell::Tessellation::DomainType::Quads: + return Shader::TessPrimitive::Quads; + } + ASSERT(false); + return Shader::TessPrimitive::Triangles; + }(); + info.tess_spacing = [&] { + const u32 raw{key.state.tessellation_spacing}; + switch (static_cast(raw)) { + case Maxwell::Tessellation::Spacing::Integer: + return Shader::TessSpacing::Equal; + case Maxwell::Tessellation::Spacing::FractionalOdd: + return Shader::TessSpacing::FractionalOdd; + case Maxwell::Tessellation::Spacing::FractionalEven: + return Shader::TessSpacing::FractionalEven; + } + ASSERT(false); + 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) { + auto [varyings, count] = + VideoCommon::MakeTransformFeedbackVaryings(key.state.xfb_state); + info.xfb_varyings = varyings; + info.xfb_count = count; + } + 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(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; } @@ -231,7 +346,7 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( auto hash = key.Hash(); LOG_INFO(Render_Metal, "0x{:016x}", hash); - // Translate shaders to spirv + // Translate shaders size_t env_index{0}; std::array programs; @@ -268,7 +383,7 @@ std::unique_ptr PipelineCache::CreateGraphicsPipeline( ConvertLegacyToGeneric(program, runtime_info); const std::string code{EmitMSL(profile, runtime_info, program, binding)}; // HACK - std::cout << "SHADER INDEX: " << index - 1 << std::endl; + std::cout << "SHADER INDEX: " << stage_index << std::endl; std::cout << code << std::endl; MTL::CompileOptions* compile_options = MTL::CompileOptions::alloc()->init(); NS::Error* error = nullptr;