From 100036aecfaf49cc00566035740f450f381d7994 Mon Sep 17 00:00:00 2001 From: TheTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:47:39 +0300 Subject: [PATCH 1/8] spirv: Flush denormals if possible (#1302) --- .../backend/spirv/emit_spirv.cpp | 50 ++++++++++------ .../backend/spirv/spirv_emit_context.cpp | 7 +-- .../frontend/copy_shader.cpp | 2 +- src/shader_recompiler/frontend/copy_shader.h | 2 +- src/shader_recompiler/info.h | 4 +- .../ir/passes/ring_access_elimination.cpp | 15 +++-- src/shader_recompiler/ir/reg.h | 21 ------- src/shader_recompiler/profile.h | 5 -- src/shader_recompiler/runtime_info.h | 34 ++++++----- src/video_core/amdgpu/liverpool.h | 6 ++ src/video_core/amdgpu/types.h | 16 +++++- .../renderer_vulkan/vk_instance.cpp | 3 +- src/video_core/renderer_vulkan/vk_instance.h | 6 ++ .../renderer_vulkan/vk_pipeline_cache.cpp | 57 ++++++++++--------- 14 files changed, 130 insertions(+), 98 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index f90e9db77..e84908a57 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp @@ -206,10 +206,7 @@ Id DefineMain(EmitContext& ctx, const IR::Program& program) { return main; } -void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { - const auto& info = program.info; - const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); - spv::ExecutionModel execution_model{}; +void SetupCapabilities(const Info& info, EmitContext& ctx) { ctx.AddCapability(spv::Capability::Image1D); ctx.AddCapability(spv::Capability::Sampled1D); ctx.AddCapability(spv::Capability::ImageQuery); @@ -247,6 +244,19 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { if (info.uses_group_ballot) { ctx.AddCapability(spv::Capability::GroupNonUniformBallot); } + if (info.stage == Stage::Export || info.stage == Stage::Vertex) { + ctx.AddExtension("SPV_KHR_shader_draw_parameters"); + ctx.AddCapability(spv::Capability::DrawParameters); + } + if (info.stage == Stage::Geometry) { + ctx.AddCapability(spv::Capability::Geometry); + } +} + +void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { + const auto& info = program.info; + const std::span interfaces(ctx.interfaces.data(), ctx.interfaces.size()); + spv::ExecutionModel execution_model{}; switch (program.info.stage) { case Stage::Compute: { const std::array workgroup_size{ctx.runtime_info.cs_info.workgroup_size}; @@ -290,6 +300,24 @@ void DefineEntryPoint(const IR::Program& program, EmitContext& ctx, Id main) { ctx.AddEntryPoint(execution_model, main, "main", interfaces); } +void SetupFloatMode(EmitContext& ctx, const Profile& profile, const RuntimeInfo& runtime_info, + Id main_func) { + ctx.AddExtension("SPV_KHR_float_controls"); + const auto fp_denorm_mode = runtime_info.fp_denorm_mode32; + if (fp_denorm_mode == AmdGpu::FpDenormMode::InOutFlush) { + if (profile.support_fp32_denorm_flush) { + ctx.AddCapability(spv::Capability::DenormFlushToZero); + ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U); + } + } else { + LOG_WARNING(Render_Vulkan, "Unknown FP denorm mode {}", u32(fp_denorm_mode)); + } + const auto fp_round_mode = runtime_info.fp_round_mode32; + if (fp_round_mode != AmdGpu::FpRoundMode::NearestEven) { + LOG_WARNING(Render_Vulkan, "Unknown FP rounding mode {}", u32(fp_round_mode)); + } +} + void PatchPhiNodes(const IR::Program& program, EmitContext& ctx) { auto inst{program.blocks.front()->begin()}; size_t block_index{0}; @@ -314,18 +342,8 @@ std::vector EmitSPIRV(const Profile& profile, const RuntimeInfo& runtime_in EmitContext ctx{profile, runtime_info, program.info, binding}; const Id main{DefineMain(ctx, program)}; DefineEntryPoint(program, ctx, main); - switch (program.info.stage) { - case Stage::Export: - case Stage::Vertex: - ctx.AddExtension("SPV_KHR_shader_draw_parameters"); - ctx.AddCapability(spv::Capability::DrawParameters); - break; - case Stage::Geometry: - ctx.AddCapability(spv::Capability::Geometry); - break; - default: - break; - } + SetupCapabilities(program.info, ctx); + SetupFloatMode(ctx, profile, runtime_info, main); PatchPhiNodes(program, ctx); binding.user_data += program.info.ud_mask.NumRegs(); return ctx.Assemble(); diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 5eee656dd..6581a7a56 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -284,7 +284,8 @@ void EmitContext::DefineInputs() { frag_coord = DefineVariable(F32[4], spv::BuiltIn::FragCoord, spv::StorageClass::Input); frag_depth = DefineVariable(F32[1], spv::BuiltIn::FragDepth, spv::StorageClass::Output); front_facing = DefineVariable(U1[1], spv::BuiltIn::FrontFacing, spv::StorageClass::Input); - for (const auto& input : runtime_info.fs_info.inputs) { + for (s32 i = 0; i < runtime_info.fs_info.num_inputs; i++) { + const auto& input = runtime_info.fs_info.inputs[i]; const u32 semantic = input.param_index; ASSERT(semantic < IR::NumParams); if (input.is_default && !input.is_flat) { @@ -333,7 +334,6 @@ void EmitContext::DefineInputs() { const auto num_params = runtime_info.gs_info.in_vertex_data_size / 4 - 1u; for (int param_id = 0; param_id < num_params; ++param_id) { - const IR::Attribute param{IR::Attribute::Param0 + param_id}; const Id type{TypeArray(F32[4], ConstU32(num_verts_in))}; const Id id{DefineInput(type, param_id)}; Name(id, fmt::format("in_attr{}", param_id)); @@ -394,8 +394,7 @@ void EmitContext::DefineOutputs() { case Stage::Geometry: { output_position = DefineVariable(F32[4], spv::BuiltIn::Position, spv::StorageClass::Output); - for (u32 attr_id = 0; attr_id < runtime_info.gs_info.copy_data.num_attrs; attr_id++) { - const IR::Attribute param{IR::Attribute::Param0 + attr_id}; + for (u32 attr_id = 0; attr_id < info.gs_copy_data.num_attrs; attr_id++) { const Id id{DefineOutput(F32[4], attr_id)}; Name(id, fmt::format("out_attr{}", attr_id)); output_params[attr_id] = {id, output_f32, F32[1], 4u}; diff --git a/src/shader_recompiler/frontend/copy_shader.cpp b/src/shader_recompiler/frontend/copy_shader.cpp index 363c1c821..b2c795667 100644 --- a/src/shader_recompiler/frontend/copy_shader.cpp +++ b/src/shader_recompiler/frontend/copy_shader.cpp @@ -7,7 +7,7 @@ namespace Shader { -CopyShaderData ParseCopyShader(const std::span& code) { +CopyShaderData ParseCopyShader(std::span code) { Gcn::GcnCodeSlice code_slice{code.data(), code.data() + code.size()}; Gcn::GcnDecodeContext decoder; diff --git a/src/shader_recompiler/frontend/copy_shader.h b/src/shader_recompiler/frontend/copy_shader.h index ca3e1ac3e..55cc31ebd 100644 --- a/src/shader_recompiler/frontend/copy_shader.h +++ b/src/shader_recompiler/frontend/copy_shader.h @@ -16,6 +16,6 @@ struct CopyShaderData { u32 num_attrs{0}; }; -CopyShaderData ParseCopyShader(const std::span& code); +CopyShaderData ParseCopyShader(std::span code); } // namespace Shader diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index 78a6805fd..e727c8a08 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -3,12 +3,12 @@ #pragma once #include -#include #include #include #include "common/assert.h" #include "common/types.h" #include "shader_recompiler/backend/bindings.h" +#include "shader_recompiler/frontend/copy_shader.h" #include "shader_recompiler/ir/attribute.h" #include "shader_recompiler/ir/reg.h" #include "shader_recompiler/ir/type.h" @@ -170,6 +170,8 @@ struct Info { }; UserDataMask ud_mask{}; + CopyShaderData gs_copy_data; + s8 vertex_offset_sgpr = -1; s8 instance_offset_sgpr = -1; diff --git a/src/shader_recompiler/ir/passes/ring_access_elimination.cpp b/src/shader_recompiler/ir/passes/ring_access_elimination.cpp index 857921b1f..eb1be2967 100644 --- a/src/shader_recompiler/ir/passes/ring_access_elimination.cpp +++ b/src/shader_recompiler/ir/passes/ring_access_elimination.cpp @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "shader_recompiler/frontend/translate/translate.h" +#include "shader_recompiler/ir/ir_emitter.h" #include "shader_recompiler/ir/opcodes.h" #include "shader_recompiler/ir/program.h" #include "shader_recompiler/ir/reg.h" @@ -11,6 +11,8 @@ namespace Shader::Optimization { void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtime_info, Stage stage) { + auto& info = program.info; + const auto& ForEachInstruction = [&](auto func) { for (IR::Block* block : program.blocks) { for (IR::Inst& inst : block->Instructions()) { @@ -52,6 +54,9 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim break; } case Stage::Geometry: { + const auto& gs_info = runtime_info.gs_info; + info.gs_copy_data = Shader::ParseCopyShader(gs_info.vs_copy); + ForEachInstruction([&](IR::IREmitter& ir, IR::Inst& inst) { const auto opcode = inst.GetOpcode(); switch (opcode) { @@ -81,12 +86,12 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim const auto offset = inst.Flags().inst_offset.Value(); const auto data = ir.BitCast(IR::U32{inst.Arg(2)}); - const auto comp_ofs = runtime_info.gs_info.output_vertices * 4u; - const auto output_size = comp_ofs * runtime_info.gs_info.out_vertex_data_size; + const auto comp_ofs = gs_info.output_vertices * 4u; + const auto output_size = comp_ofs * gs_info.out_vertex_data_size; const auto vc_read_ofs = (((offset / comp_ofs) * comp_ofs) % output_size) * 16u; - const auto& it = runtime_info.gs_info.copy_data.attr_map.find(vc_read_ofs); - ASSERT(it != runtime_info.gs_info.copy_data.attr_map.cend()); + const auto& it = info.gs_copy_data.attr_map.find(vc_read_ofs); + ASSERT(it != info.gs_copy_data.attr_map.cend()); const auto& [attr, comp] = it->second; inst.ReplaceOpcode(IR::Opcode::SetAttribute); diff --git a/src/shader_recompiler/ir/reg.h b/src/shader_recompiler/ir/reg.h index 9ec77e5f0..5facaf5c7 100644 --- a/src/shader_recompiler/ir/reg.h +++ b/src/shader_recompiler/ir/reg.h @@ -10,20 +10,6 @@ namespace Shader::IR { -enum class FpRoundMode : u32 { - NearestEven = 0, - PlusInf = 1, - MinInf = 2, - ToZero = 3, -}; - -enum class FpDenormMode : u32 { - InOutFlush = 0, - InAllowOutFlush = 1, - InFlushOutAllow = 2, - InOutAllow = 3, -}; - enum class FloatClassFunc : u32 { SignalingNan = 1 << 0, QuietNan = 1 << 1, @@ -41,13 +27,6 @@ enum class FloatClassFunc : u32 { }; DECLARE_ENUM_FLAG_OPERATORS(FloatClassFunc) -union Mode { - BitField<0, 4, FpRoundMode> fp_round; - BitField<4, 2, FpDenormMode> fp_denorm_single; - BitField<6, 2, FpDenormMode> fp_denorm_double; - BitField<8, 1, u32> dx10_clamp; -}; - union TextureInstInfo { u32 raw; BitField<0, 1, u32> is_depth; diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h index badd54554..bbda731e0 100644 --- a/src/shader_recompiler/profile.h +++ b/src/shader_recompiler/profile.h @@ -19,13 +19,8 @@ struct Profile { bool support_float_controls{}; bool support_separate_denorm_behavior{}; bool support_separate_rounding_mode{}; - bool support_fp16_denorm_preserve{}; bool support_fp32_denorm_preserve{}; - bool support_fp16_denorm_flush{}; bool support_fp32_denorm_flush{}; - bool support_fp16_signed_zero_nan_preserve{}; - bool support_fp32_signed_zero_nan_preserve{}; - bool support_fp64_signed_zero_nan_preserve{}; bool support_explicit_workgroup_layout{}; bool has_broken_spirv_clamp{}; bool lower_left_origin_mode{}; diff --git a/src/shader_recompiler/runtime_info.h b/src/shader_recompiler/runtime_info.h index 8c0838c96..4d15c2072 100644 --- a/src/shader_recompiler/runtime_info.h +++ b/src/shader_recompiler/runtime_info.h @@ -4,11 +4,9 @@ #pragma once #include +#include #include - -#include "common/assert.h" #include "common/types.h" -#include "frontend/copy_shader.h" #include "video_core/amdgpu/types.h" namespace Shader { @@ -62,7 +60,8 @@ enum class VsOutput : u8 { using VsOutputMap = std::array; struct VertexRuntimeInfo { - boost::container::static_vector outputs; + u32 num_outputs; + std::array outputs; bool emulate_depth_negative_one_to_one{}; bool operator==(const VertexRuntimeInfo& other) const noexcept { @@ -79,13 +78,13 @@ struct GeometryRuntimeInfo { u32 out_vertex_data_size{}; AmdGpu::PrimitiveType in_primitive; GsOutputPrimTypes out_primitive; - CopyShaderData copy_data; + std::span vs_copy; + u64 vs_copy_hash; bool operator==(const GeometryRuntimeInfo& other) const noexcept { return num_invocations && other.num_invocations && output_vertices == other.output_vertices && in_primitive == other.in_primitive && - std::ranges::equal(out_primitive, other.out_primitive) && - std::ranges::equal(copy_data.attr_map, other.copy_data.attr_map); + std::ranges::equal(out_primitive, other.out_primitive); } }; @@ -106,7 +105,8 @@ struct FragmentRuntimeInfo { auto operator<=>(const PsInput&) const noexcept = default; }; - boost::container::static_vector inputs; + u32 num_inputs; + std::array inputs; struct PsColorBuffer { AmdGpu::NumberFormat num_format; MrtSwizzle mrt_swizzle; @@ -117,7 +117,9 @@ struct FragmentRuntimeInfo { bool operator==(const FragmentRuntimeInfo& other) const noexcept { return std::ranges::equal(color_buffers, other.color_buffers) && - std::ranges::equal(inputs, other.inputs); + num_inputs == other.num_inputs && + std::ranges::equal(inputs.begin(), inputs.begin() + num_inputs, other.inputs.begin(), + other.inputs.begin() + num_inputs); } }; @@ -141,11 +143,15 @@ struct RuntimeInfo { u32 num_user_data; u32 num_input_vgprs; u32 num_allocated_vgprs; - ExportRuntimeInfo es_info; - VertexRuntimeInfo vs_info; - GeometryRuntimeInfo gs_info; - FragmentRuntimeInfo fs_info; - ComputeRuntimeInfo cs_info; + AmdGpu::FpDenormMode fp_denorm_mode32; + AmdGpu::FpRoundMode fp_round_mode32; + union { + ExportRuntimeInfo es_info; + VertexRuntimeInfo vs_info; + GeometryRuntimeInfo gs_info; + FragmentRuntimeInfo fs_info; + ComputeRuntimeInfo cs_info; + }; RuntimeInfo(Stage stage_) : stage{stage_} {} diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 508420bca..1c994d0a0 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -92,6 +92,12 @@ struct Liverpool { union { BitField<0, 6, u64> num_vgprs; BitField<6, 4, u64> num_sgprs; + BitField<10, 2, u64> priority; + BitField<12, 2, FpRoundMode> fp_round_mode32; + BitField<14, 2, FpRoundMode> fp_round_mode64; + BitField<16, 2, FpDenormMode> fp_denorm_mode32; + BitField<18, 2, FpDenormMode> fp_denorm_mode64; + BitField<12, 8, u64> float_mode; BitField<24, 2, u64> vgpr_comp_cnt; // SPI provided per-thread inputs BitField<33, 5, u64> num_user_regs; } settings; diff --git a/src/video_core/amdgpu/types.h b/src/video_core/amdgpu/types.h index 8cc023a79..6b95ed910 100644 --- a/src/video_core/amdgpu/types.h +++ b/src/video_core/amdgpu/types.h @@ -7,6 +7,20 @@ namespace AmdGpu { +enum class FpRoundMode : u32 { + NearestEven = 0, + PlusInf = 1, + MinInf = 2, + ToZero = 3, +}; + +enum class FpDenormMode : u32 { + InOutFlush = 0, + InAllowOutFlush = 1, + InFlushOutAllow = 2, + InOutAllow = 3, +}; + // See `VGT_PRIMITIVE_TYPE` description in [Radeon Sea Islands 3D/Compute Register Reference Guide] enum class PrimitiveType : u32 { None = 0, @@ -103,4 +117,4 @@ enum class NumberFormat : u32 { Ubscaled = 13, }; -} // namespace AmdGpu \ No newline at end of file +} // namespace AmdGpu diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 21941b8e9..dda4e0d9f 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -217,9 +217,10 @@ bool Instance::CreateDevice() { const vk::StructureChain properties_chain = physical_device.getProperties2< vk::PhysicalDeviceProperties2, vk::PhysicalDevicePortabilitySubsetPropertiesKHR, vk::PhysicalDeviceExternalMemoryHostPropertiesEXT, vk::PhysicalDeviceVulkan11Properties, - vk::PhysicalDevicePushDescriptorPropertiesKHR>(); + vk::PhysicalDevicePushDescriptorPropertiesKHR, vk::PhysicalDeviceVulkan12Properties>(); subgroup_size = properties_chain.get().subgroupSize; push_descriptor_props = properties_chain.get(); + vk12_props = properties_chain.get(); LOG_INFO(Render_Vulkan, "Physical device subgroup size {}", subgroup_size); features = feature_chain.get().features; diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index d77d0c20f..474b86e9a 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -242,6 +242,11 @@ public: return push_descriptor_props.maxPushDescriptors; } + /// Returns the vulkan 1.2 physical device properties. + const vk::PhysicalDeviceVulkan12Properties& GetVk12Properties() const noexcept { + return vk12_props; + } + /// Returns true if shaders can declare the ClipDistance attribute bool IsShaderClipDistanceSupported() const { return features.shaderClipDistance; @@ -279,6 +284,7 @@ private: vk::UniqueDevice device; vk::PhysicalDeviceProperties properties; vk::PhysicalDevicePushDescriptorPropertiesKHR push_descriptor_props; + vk::PhysicalDeviceVulkan12Properties vk12_props; vk::PhysicalDeviceFeatures features; vk::DriverIdKHR driver_id; vk::UniqueDebugUtilsMessengerEXT debug_callback{}; diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 929fa9cc1..a06d82eb3 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -7,7 +7,6 @@ #include "common/io_file.h" #include "common/path_util.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" -#include "shader_recompiler/frontend/copy_shader.h" #include "shader_recompiler/info.h" #include "shader_recompiler/recompiler.h" #include "shader_recompiler/runtime_info.h" @@ -41,7 +40,7 @@ void GatherVertexOutputs(Shader::VertexRuntimeInfo& info, const auto add_output = [&](VsOutput x, VsOutput y, VsOutput z, VsOutput w) { if (x != VsOutput::None || y != VsOutput::None || z != VsOutput::None || w != VsOutput::None) { - info.outputs.emplace_back(Shader::VsOutputMap{x, y, z, w}); + info.outputs[info.num_outputs++] = Shader::VsOutputMap{x, y, z, w}; } }; // VS_OUT_MISC_VEC @@ -84,18 +83,21 @@ void GatherVertexOutputs(Shader::VertexRuntimeInfo& info, Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Shader::Stage stage) { auto info = Shader::RuntimeInfo{stage}; const auto& regs = liverpool->regs; + const auto BuildCommon = [&](const auto& program) { + info.num_user_data = program.settings.num_user_regs; + info.num_input_vgprs = program.settings.vgpr_comp_cnt; + info.num_allocated_vgprs = program.settings.num_vgprs * 4; + info.fp_denorm_mode32 = program.settings.fp_denorm_mode32; + info.fp_round_mode32 = program.settings.fp_round_mode32; + }; switch (stage) { case Shader::Stage::Export: { - info.num_user_data = regs.es_program.settings.num_user_regs; - info.num_input_vgprs = regs.es_program.settings.vgpr_comp_cnt; - info.num_allocated_vgprs = regs.es_program.settings.num_vgprs * 4; + BuildCommon(regs.es_program); info.es_info.vertex_data_size = regs.vgt_esgs_ring_itemsize; break; } case Shader::Stage::Vertex: { - info.num_user_data = regs.vs_program.settings.num_user_regs; - info.num_input_vgprs = regs.vs_program.settings.vgpr_comp_cnt; - info.num_allocated_vgprs = regs.vs_program.settings.num_vgprs * 4; + BuildCommon(regs.vs_program); GatherVertexOutputs(info.vs_info, regs.vs_output_control); info.vs_info.emulate_depth_negative_one_to_one = !instance.IsDepthClipControlSupported() && @@ -103,39 +105,35 @@ Shader::RuntimeInfo PipelineCache::BuildRuntimeInfo(Shader::Stage stage) { break; } case Shader::Stage::Geometry: { - info.num_user_data = regs.gs_program.settings.num_user_regs; - info.num_input_vgprs = regs.gs_program.settings.vgpr_comp_cnt; - info.num_allocated_vgprs = regs.gs_program.settings.num_vgprs * 4; - info.gs_info.output_vertices = regs.vgt_gs_max_vert_out; - info.gs_info.num_invocations = + BuildCommon(regs.gs_program); + auto& gs_info = info.gs_info; + gs_info.output_vertices = regs.vgt_gs_max_vert_out; + gs_info.num_invocations = regs.vgt_gs_instance_cnt.IsEnabled() ? regs.vgt_gs_instance_cnt.count : 1; - info.gs_info.in_primitive = regs.primitive_type; + gs_info.in_primitive = regs.primitive_type; for (u32 stream_id = 0; stream_id < Shader::GsMaxOutputStreams; ++stream_id) { - info.gs_info.out_primitive[stream_id] = + gs_info.out_primitive[stream_id] = regs.vgt_gs_out_prim_type.GetPrimitiveType(stream_id); } - info.gs_info.in_vertex_data_size = regs.vgt_esgs_ring_itemsize; - info.gs_info.out_vertex_data_size = regs.vgt_gs_vert_itemsize[0]; - - // Extract semantics offsets from a copy shader - const auto vc_stage = Shader::Stage::Vertex; - const auto* pgm_vc = regs.ProgramForStage(static_cast(vc_stage)); - const auto params_vc = Liverpool::GetParams(*pgm_vc); - DumpShader(params_vc.code, params_vc.hash, Shader::Stage::Vertex, 0, "copy.bin"); - info.gs_info.copy_data = Shader::ParseCopyShader(params_vc.code); + gs_info.in_vertex_data_size = regs.vgt_esgs_ring_itemsize; + gs_info.out_vertex_data_size = regs.vgt_gs_vert_itemsize[0]; + const auto params_vc = Liverpool::GetParams(regs.vs_program); + gs_info.vs_copy = params_vc.code; + gs_info.vs_copy_hash = params_vc.hash; + DumpShader(gs_info.vs_copy, gs_info.vs_copy_hash, Shader::Stage::Vertex, 0, "copy.bin"); break; } case Shader::Stage::Fragment: { - info.num_user_data = regs.ps_program.settings.num_user_regs; - info.num_allocated_vgprs = regs.ps_program.settings.num_vgprs * 4; + BuildCommon(regs.ps_program); const auto& ps_inputs = regs.ps_inputs; + info.fs_info.num_inputs = regs.num_interp; for (u32 i = 0; i < regs.num_interp; i++) { - info.fs_info.inputs.push_back({ + info.fs_info.inputs[i] = { .param_index = u8(ps_inputs[i].input_offset.Value()), .is_default = bool(ps_inputs[i].use_default), .is_flat = bool(ps_inputs[i].flat_shade), .default_value = u8(ps_inputs[i].default_value), - }); + }; } for (u32 i = 0; i < Shader::MaxColorBuffers; i++) { info.fs_info.color_buffers[i] = { @@ -166,9 +164,12 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, AmdGpu::Liverpool* liverpool_) : instance{instance_}, scheduler{scheduler_}, liverpool{liverpool_}, desc_heap{instance, scheduler.GetMasterSemaphore(), DescriptorHeapSizes} { + const auto& vk12_props = instance.GetVk12Properties(); profile = Shader::Profile{ .supported_spirv = instance.ApiVersion() >= VK_API_VERSION_1_3 ? 0x00010600U : 0x00010500U, .subgroup_size = instance.SubgroupSize(), + .support_fp32_denorm_preserve = bool(vk12_props.shaderDenormPreserveFloat32), + .support_fp32_denorm_flush = bool(vk12_props.shaderDenormFlushToZeroFloat32), .support_explicit_workgroup_layout = true, }; auto [cache_result, cache] = instance.GetDevice().createPipelineCacheUnique({}); From 0a12ba4120bdbb49940a898d866798386eb9e4bc Mon Sep 17 00:00:00 2001 From: "Daniel R." <47796739+polybiusproxy@users.noreply.github.com> Date: Thu, 10 Oct 2024 16:51:23 +0200 Subject: [PATCH 2/8] core/libraries: Initial fiber implementation (#1255) --- CMakeLists.txt | 5 + src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + src/core/libraries/error_codes.h | 10 +- src/core/libraries/fiber/fiber.cpp | 284 +++++++++++++++++++++++++++++ src/core/libraries/fiber/fiber.h | 83 +++++++++ src/core/libraries/libs.cpp | 2 + src/emulator.cpp | 3 +- 8 files changed, 387 insertions(+), 2 deletions(-) create mode 100644 src/core/libraries/fiber/fiber.cpp create mode 100644 src/core/libraries/fiber/fiber.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eeca274ef..8a41e1ac9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,6 +324,10 @@ set(USBD_LIB src/core/libraries/usbd/usbd.cpp src/core/libraries/usbd/usbd.h ) +set(FIBER_LIB src/core/libraries/fiber/fiber.cpp + src/core/libraries/fiber/fiber.h +) + set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp src/core/libraries/np_manager/np_manager.h src/core/libraries/np_score/np_score.cpp @@ -464,6 +468,7 @@ set(CORE src/core/aerolib/stubs.cpp ${USBD_LIB} ${MISC_LIBS} ${DIALOGS_LIB} + ${FIBER_LIB} ${DEV_TOOLS} src/core/debug_state.cpp src/core/debug_state.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index c3088f926..2ff2a9003 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -114,6 +114,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, AvPlayer) \ SUB(Lib, Ngs2) \ SUB(Lib, Audio3d) \ + SUB(Lib, Fiber) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 749568da1..54388e590 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -81,6 +81,7 @@ enum class Class : u8 { Lib_AvPlayer, ///< The LibSceAvPlayer implementation. Lib_Ngs2, ///< The LibSceNgs2 implementation. Lib_Audio3d, ///< The LibSceAudio3d implementation. + Lib_Fiber, ///< The LibSceFiber implementation. Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/error_codes.h b/src/core/libraries/error_codes.h index b9896b6c3..041870ed7 100644 --- a/src/core/libraries/error_codes.h +++ b/src/core/libraries/error_codes.h @@ -498,4 +498,12 @@ constexpr int ORBIS_AVPLAYER_ERROR_INFO_OTHER_ENCRY = 0x806A00BF; // AppContent library constexpr int ORBIS_APP_CONTENT_ERROR_PARAMETER = 0x80D90002; constexpr int ORBIS_APP_CONTENT_ERROR_DRM_NO_ENTITLEMENT = 0x80D90007; -constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005; \ No newline at end of file +constexpr int ORBIS_APP_CONTENT_ERROR_NOT_FOUND = 0x80D90005; + +// Fiber library +constexpr int ORBIS_FIBER_ERROR_NULL = 0x80590001; +constexpr int ORBIS_FIBER_ERROR_ALIGNMENT = 0x80590002; +constexpr int ORBIS_FIBER_ERROR_RANGE = 0x80590003; +constexpr int ORBIS_FIBER_ERROR_INVALID = 0x80590004; +constexpr int ORBIS_FIBER_ERROR_PERMISSION = 0x80590005; +constexpr int ORBIS_FIBER_ERROR_STATE = 0x80590006; \ No newline at end of file diff --git a/src/core/libraries/fiber/fiber.cpp b/src/core/libraries/fiber/fiber.cpp new file mode 100644 index 000000000..bd1575dda --- /dev/null +++ b/src/core/libraries/fiber/fiber.cpp @@ -0,0 +1,284 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "fiber.h" + +#include "common/logging/log.h" +#include "common/singleton.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "core/linker.h" + +#ifdef _WIN64 +#include +#endif + +namespace Libraries::Fiber { + +constexpr static u64 kFiberSignature = 0x054ad954; + +thread_local SceFiber* gCurrentFiber = nullptr; +thread_local void* gFiberThread = nullptr; + +void FiberEntry(void* param) { + SceFiber* fiber = static_cast(param); + u64 argRun = 0; + u64 argRet = 0; + + gCurrentFiber = fiber; + + if (fiber->pArgRun != nullptr) { + argRun = *fiber->pArgRun; + } + + const auto* linker = Common::Singleton::Instance(); + linker->ExecuteGuest(fiber->entry, fiber->argOnInitialize, argRun); + + UNREACHABLE(); +} + +s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry, + u64 argOnInitialize, void* addrContext, u64 sizeContext, + const SceFiberOptParam* optParam) { + LOG_INFO(Lib_Fiber, "called: name = {}", name); + + if (!fiber || !name || !entry) { + return ORBIS_FIBER_ERROR_NULL; + } + + fiber->signature = kFiberSignature; + + fiber->entry = entry; + fiber->argOnInitialize = argOnInitialize; + + fiber->argRun = 0; + fiber->pArgRun = &fiber->argRun; + fiber->argReturn = 0; + fiber->pArgReturn = &fiber->argReturn; + + fiber->sizeContext = sizeContext; + + fiber->state = FiberState::Init; +#ifdef _WIN64 + fiber->handle = CreateFiber(sizeContext, FiberEntry, fiber); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH); + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam) { + LOG_ERROR(Lib_Fiber, "called"); + + if (!optParam) { + return ORBIS_FIBER_ERROR_NULL; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber) { + LOG_TRACE(Lib_Fiber, "called"); + + if (!fiber) { + return ORBIS_FIBER_ERROR_NULL; + } + if ((u64)fiber % 8 != 0) { + return ORBIS_FIBER_ERROR_ALIGNMENT; + } + if (fiber->signature != kFiberSignature) { + return ORBIS_FIBER_ERROR_INVALID; + } + if (fiber->state != FiberState::Run) { + return ORBIS_FIBER_ERROR_STATE; + } + + fiber->signature = 0; + fiber->state = FiberState::None; + +#ifdef _WIN64 + DeleteFiber(fiber->handle); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn) { + LOG_TRACE(Lib_Fiber, "called"); + + if (!fiber) { + return ORBIS_FIBER_ERROR_NULL; + } + if ((u64)fiber % 8 != 0) { + return ORBIS_FIBER_ERROR_ALIGNMENT; + } + if (fiber->signature != kFiberSignature) { + return ORBIS_FIBER_ERROR_INVALID; + } + if (fiber->state == FiberState::Run) { + return ORBIS_FIBER_ERROR_STATE; + } + + if (gFiberThread == nullptr) { +#ifdef _WIN64 + gFiberThread = ConvertThreadToFiber(nullptr); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + } + + gCurrentFiber = fiber; + + if (fiber->pArgRun != nullptr) { + *fiber->pArgRun = argOnRunTo; + } + + fiber->pArgReturn = argOnReturn; + fiber->state = FiberState::Run; +#ifdef _WIN64 + SwitchToFiber(fiber->handle); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun) { + LOG_TRACE(Lib_Fiber, "called"); + + if (!fiber) { + return ORBIS_FIBER_ERROR_NULL; + } + if ((u64)fiber % 8 != 0) { + return ORBIS_FIBER_ERROR_ALIGNMENT; + } + if (fiber->signature != kFiberSignature) { + return ORBIS_FIBER_ERROR_INVALID; + } + if (gCurrentFiber == nullptr) { + return ORBIS_FIBER_ERROR_PERMISSION; + } + if (fiber->state == FiberState::Run) { + return ORBIS_FIBER_ERROR_STATE; + } + + gCurrentFiber->state = FiberState::Suspend; + + // TODO: argOnRun + + *fiber->pArgRun = argOnRunTo; + fiber->state = FiberState::Run; + + gCurrentFiber = fiber; +#ifdef _WIN64 + SwitchToFiber(fiber->handle); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber) { + LOG_TRACE(Lib_Fiber, "called"); + + if (!fiber || !gCurrentFiber) { + return ORBIS_FIBER_ERROR_NULL; + } + if (gCurrentFiber->signature != kFiberSignature) { + return ORBIS_FIBER_ERROR_PERMISSION; + } + + *fiber = gCurrentFiber; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun) { + LOG_TRACE(Lib_Fiber, "called"); + + if (gCurrentFiber->signature != kFiberSignature) { + return ORBIS_FIBER_ERROR_PERMISSION; + } + + if (gCurrentFiber->pArgReturn != nullptr) { + *gCurrentFiber->pArgReturn = argOnReturn; + } + + // TODO: argOnRun + gCurrentFiber->state = FiberState::Suspend; + gCurrentFiber = nullptr; +#ifdef _WIN64 + SwitchToFiber(gFiberThread); +#else + UNREACHABLE_MSG("Missing implementation"); +#endif + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo) { + LOG_INFO(Lib_Fiber, "called"); + + if (!fiber || !fiberInfo) { + return ORBIS_FIBER_ERROR_NULL; + } + + fiberInfo->entry = fiber->entry; + fiberInfo->argOnInitialize = fiber->argOnInitialize; + fiberInfo->addrContext = nullptr; + fiberInfo->sizeContext = fiber->sizeContext; + fiberInfo->sizeContextMargin = 0; + + strncpy(fiberInfo->name, fiber->name, ORBIS_FIBER_MAX_NAME_LENGTH); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags) { + LOG_ERROR(Lib_Fiber, "called"); + + if (flags != 0) { + return ORBIS_FIBER_ERROR_INVALID; + } + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck() { + LOG_ERROR(Lib_Fiber, "called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name) { + LOG_INFO(Lib_Fiber, "called, name = {}", name); + + if (!fiber || !name) { + return ORBIS_FIBER_ERROR_NULL; + } + if ((u64)fiber % 8 != 0) { + return ORBIS_FIBER_ERROR_ALIGNMENT; + } + + strncpy(fiber->name, name, ORBIS_FIBER_MAX_NAME_LENGTH); + return ORBIS_OK; +} + +void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("hVYD7Ou2pCQ", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberInitialize); + LIB_FUNCTION("asjUJJ+aa8s", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberOptParamInitialize); + LIB_FUNCTION("JeNX5F-NzQU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberFinalize); + + LIB_FUNCTION("a0LLrZWac0M", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRun); + LIB_FUNCTION("PFT2S-tJ7Uk", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberSwitch); + LIB_FUNCTION("p+zLIOg27zU", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetSelf); + LIB_FUNCTION("B0ZX2hx9DMw", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberReturnToThread); + + LIB_FUNCTION("uq2Y5BFz0PE", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberGetInfo); + LIB_FUNCTION("Lcqty+QNWFc", "libSceFiber", 1, "libSceFiber", 1, 1, + sceFiberStartContextSizeCheck); + LIB_FUNCTION("Kj4nXMpnM8Y", "libSceFiber", 1, "libSceFiber", 1, 1, + sceFiberStopContextSizeCheck); + LIB_FUNCTION("JzyT91ucGDc", "libSceFiber", 1, "libSceFiber", 1, 1, sceFiberRename); +} + +} // namespace Libraries::Fiber \ No newline at end of file diff --git a/src/core/libraries/fiber/fiber.h b/src/core/libraries/fiber/fiber.h new file mode 100644 index 000000000..930409caa --- /dev/null +++ b/src/core/libraries/fiber/fiber.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/assert.h" +#include "common/types.h" + +namespace Core::Loader { +class SymbolsResolver; +} +namespace Libraries::Fiber { + +#define ORBIS_FIBER_MAX_NAME_LENGTH (31) + +typedef void PS4_SYSV_ABI (*SceFiberEntry)(u64 argOnInitialize, u64 argOnRun); + +enum FiberState : u32 { + None = 0u, + Init = 1u, + Run = 2u, + Suspend = 3u, +}; + +struct SceFiber { + u64 signature; + FiberState state; + SceFiberEntry entry; + + u64 argOnInitialize; + + u64 argRun; + u64* pArgRun; + + u64 argReturn; + u64* pArgReturn; + + u64 sizeContext; + + char name[ORBIS_FIBER_MAX_NAME_LENGTH]; + void* handle; +}; +static_assert(sizeof(SceFiber) <= 256); + +struct SceFiberInfo { + u64 size; + SceFiberEntry entry; + u64 argOnInitialize; + void* addrContext; + u64 sizeContext; + char name[ORBIS_FIBER_MAX_NAME_LENGTH + 1]; + u64 sizeContextMargin; +}; +static_assert(sizeof(SceFiberInfo) <= 128); + +typedef void* SceFiberOptParam; + +s32 PS4_SYSV_ABI sceFiberInitialize(SceFiber* fiber, const char* name, SceFiberEntry entry, + u64 argOnInitialize, void* addrContext, u64 sizeContext, + const SceFiberOptParam* optParam); + +s32 PS4_SYSV_ABI sceFiberOptParamInitialize(SceFiberOptParam* optParam); + +s32 PS4_SYSV_ABI sceFiberFinalize(SceFiber* fiber); + +s32 PS4_SYSV_ABI sceFiberRun(SceFiber* fiber, u64 argOnRunTo, u64* argOnReturn); + +s32 PS4_SYSV_ABI sceFiberSwitch(SceFiber* fiber, u64 argOnRunTo, u64* argOnRun); + +s32 PS4_SYSV_ABI sceFiberGetSelf(SceFiber** fiber); + +s32 PS4_SYSV_ABI sceFiberReturnToThread(u64 argOnReturn, u64* argOnRun); + +s32 PS4_SYSV_ABI sceFiberGetInfo(SceFiber* fiber, SceFiberInfo* fiberInfo); + +s32 PS4_SYSV_ABI sceFiberStartContextSizeCheck(u32 flags); + +s32 PS4_SYSV_ABI sceFiberStopContextSizeCheck(void); + +s32 PS4_SYSV_ABI sceFiberRename(SceFiber* fiber, const char* name); + +void RegisterlibSceFiber(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Fiber \ No newline at end of file diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index 5b6c17b10..86f9fcf9d 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -11,6 +11,7 @@ #include "core/libraries/dialogs/error_dialog.h" #include "core/libraries/dialogs/ime_dialog.h" #include "core/libraries/disc_map/disc_map.h" +#include "core/libraries/fiber/fiber.h" #include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/kernel/libkernel.h" #include "core/libraries/libc_internal/libc_internal.h" @@ -77,6 +78,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::ImeDialog::RegisterlibSceImeDialog(sym); Libraries::AvPlayer::RegisterlibSceAvPlayer(sym); Libraries::Audio3d::RegisterlibSceAudio3d(sym); + Libraries::Fiber::RegisterlibSceFiber(sym); } } // namespace Libraries diff --git a/src/emulator.cpp b/src/emulator.cpp index 9f801fb83..67aaa0492 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -26,6 +26,7 @@ #include "core/file_format/trp.h" #include "core/file_sys/fs.h" #include "core/libraries/disc_map/disc_map.h" +#include "core/libraries/fiber/fiber.h" #include "core/libraries/kernel/thread_management.h" #include "core/libraries/libc_internal/libc_internal.h" #include "core/libraries/libs.h" @@ -258,7 +259,7 @@ void Emulator::Run(const std::filesystem::path& file) { void Emulator::LoadSystemModules(const std::filesystem::path& file) { constexpr std::array ModulesToLoad{ {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, - {"libSceFiber.sprx", nullptr}, + {"libSceFiber.sprx", &Libraries::Fiber::RegisterlibSceFiber}, {"libSceUlt.sprx", nullptr}, {"libSceJson.sprx", nullptr}, {"libSceJson2.sprx", nullptr}, From 299a29e243bb49378e2264889cc168ce8ea2fef3 Mon Sep 17 00:00:00 2001 From: ElBread3 <92335081+ElBread3@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:52:20 -0500 Subject: [PATCH 3/8] Fix Multiple Install Folders (#1328) * attempt to fix pr * clang format --- src/common/config.cpp | 7 ++++++- src/qt_gui/settings_dialog.cpp | 36 +++++++++++++++++++++++++--------- src/qt_gui/translations/en.ts | 15 ++++++++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 55cf29428..eedb69105 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -534,7 +534,12 @@ void load(const std::filesystem::path& path) { const auto install_dir_array = toml::find_or>(gui, "installDirs", {}); for (const auto& dir : install_dir_array) { - settings_install_dirs.emplace_back(std::filesystem::path{dir}); + bool not_already_included = + std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) == + settings_install_dirs.end(); + if (not_already_included) { + settings_install_dirs.emplace_back(std::filesystem::path{dir}); + } } settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {}); diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index a6fe6a265..cf64660f8 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -222,21 +222,17 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge // PATH TAB { - for (const auto& dir : Config::getGameInstallDirs()) { - QString path_string; - Common::FS::PathToQString(path_string, dir); - QListWidgetItem* item = new QListWidgetItem(path_string); - ui->gameFoldersListWidget->addItem(item); - } - ui->removeFolderButton->setEnabled(false); connect(ui->addFolderButton, &QPushButton::clicked, this, [this]() { + const auto config_dir = Config::getGameInstallDirs(); QString file_path_string = QFileDialog::getExistingDirectory(this, tr("Directory to install games")); auto file_path = Common::FS::PathFromQString(file_path_string); - if (!file_path.empty()) { - std::vector install_dirs = Config::getGameInstallDirs(); + bool not_already_included = + std::find(config_dir.begin(), config_dir.end(), file_path) == config_dir.end(); + if (!file_path.empty() && not_already_included) { + std::vector install_dirs = config_dir; install_dirs.push_back(file_path); Config::setGameInstallDirs(install_dirs); QListWidgetItem* item = new QListWidgetItem(file_path_string); @@ -307,6 +303,12 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge ui->dumpShadersCheckBox->installEventFilter(this); ui->nullGpuCheckBox->installEventFilter(this); + // Paths + ui->gameFoldersGroupBox->installEventFilter(this); + ui->gameFoldersListWidget->installEventFilter(this); + ui->addFolderButton->installEventFilter(this); + ui->removeFolderButton->installEventFilter(this); + // Debug ui->debugDump->installEventFilter(this); ui->vkValidationCheckBox->installEventFilter(this); @@ -357,6 +359,13 @@ void SettingsDialog::LoadValuesFromConfig() { } ui->updateComboBox->setCurrentText(QString::fromStdString(updateChannel)); + for (const auto& dir : Config::getGameInstallDirs()) { + QString path_string; + Common::FS::PathToQString(path_string, dir); + QListWidgetItem* item = new QListWidgetItem(path_string); + ui->gameFoldersListWidget->addItem(item); + } + QString backButtonBehavior = QString::fromStdString(Config::getBackButtonBehavior()); int index = ui->backButtonBehaviorComboBox->findData(backButtonBehavior); ui->backButtonBehaviorComboBox->setCurrentIndex(index != -1 ? index : 0); @@ -452,6 +461,15 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) { text = tr("nullGpuCheckBox"); } + // Path + if (elementName == "gameFoldersGroupBox" || elementName == "gameFoldersListWidget") { + text = tr("gameFoldersBox"); + } else if (elementName == "addFolderButton") { + text = tr("addFolderButton"); + } else if (elementName == "removeFolderButton") { + text = tr("removeFolderButton"); + } + // Debug if (elementName == "debugDump") { text = tr("debugDump"); diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index 8ac683804..efbc48fff 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -1083,6 +1083,21 @@ nullGpuCheckBox Enable Null GPU:\nFor the sake of technical debugging, disables game rendering as if there were no graphics card. + + + gameFoldersBox + Game Folders: The list of folders to check for installed games. + + + + addFolderButton + Add: Add a folder to the list. + + + + removeFolderButton + Remove: Remove a folder from the list. + debugDump From 87f8f3a59e7fa53f76d2bbb42b6e15e5b4c4b192 Mon Sep 17 00:00:00 2001 From: Exhigh Date: Thu, 10 Oct 2024 18:52:39 +0400 Subject: [PATCH 4/8] qt_gui: Organize settings page (#1316) * Wire up translations and descriptions for the cursor settings. * Move controller settings to input tab and rename it to controller (to inline it with how other settings are shown). * Fixed unnecessary double initialization of the back button setting. * Organize statements and functions w/ respect to their tabs and some minor QOL changes for the settings UI in general. --- src/common/config.cpp | 8 +- src/common/config.h | 13 +- src/qt_gui/settings_dialog.cpp | 50 +-- src/qt_gui/settings_dialog.ui | 590 ++++++++++++++++++++++----------- src/qt_gui/translations/en.ts | 80 ++++- 5 files changed, 499 insertions(+), 242 deletions(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index eedb69105..37e51c655 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -473,7 +473,6 @@ void load(const std::filesystem::path& path) { } isShowSplash = toml::find_or(general, "showSplash", true); isAutoUpdate = toml::find_or(general, "autoUpdate", false); - backButtonBehavior = toml::find_or(general, "backButtonBehavior", "left"); } if (data.contains("Input")) { @@ -481,6 +480,7 @@ void load(const std::filesystem::path& path) { cursorState = toml::find_or(input, "cursorState", HideCursorState::Idle); cursorHideTimeout = toml::find_or(input, "cursorHideTimeout", 5); + backButtonBehavior = toml::find_or(input, "backButtonBehavior", "left"); useSpecialPad = toml::find_or(input, "useSpecialPad", false); specialPadClass = toml::find_or(input, "specialPadClass", 1); } @@ -594,7 +594,7 @@ void save(const std::filesystem::path& path) { data["General"]["autoUpdate"] = isAutoUpdate; data["Input"]["cursorState"] = cursorState; data["Input"]["cursorHideTimeout"] = cursorHideTimeout; - data["General"]["backButtonBehavior"] = backButtonBehavior; + data["Input"]["backButtonBehavior"] = backButtonBehavior; data["Input"]["useSpecialPad"] = useSpecialPad; data["Input"]["specialPadClass"] = specialPadClass; data["GPU"]["screenWidth"] = screenWidth; @@ -650,8 +650,6 @@ void setDefaultValues() { playBGM = false; BGMvolume = 50; enableDiscordRPC = true; - cursorState = HideCursorState::Idle; - cursorHideTimeout = 5; screenWidth = 1280; screenHeight = 720; logFilter = ""; @@ -662,6 +660,8 @@ void setDefaultValues() { } else { updateChannel = "Nightly"; } + cursorState = HideCursorState::Idle; + cursorHideTimeout = 5; backButtonBehavior = "left"; useSpecialPad = false; specialPadClass = 1; diff --git a/src/common/config.h b/src/common/config.h index e76f389c2..8e799b55d 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -20,15 +20,14 @@ bool getPlayBGM(); int getBGMvolume(); bool getEnableDiscordRPC(); -s16 getCursorState(); -int getCursorHideTimeout(); - std::string getLogFilter(); std::string getLogType(); std::string getUserName(); std::string getUpdateChannel(); -std::string getBackButtonBehavior(); +s16 getCursorState(); +int getCursorHideTimeout(); +std::string getBackButtonBehavior(); bool getUseSpecialPad(); int getSpecialPadClass(); @@ -59,14 +58,14 @@ void setFullscreenMode(bool enable); void setPlayBGM(bool enable); void setBGMvolume(int volume); void setEnableDiscordRPC(bool enable); -void setCursorState(s16 cursorState); -void setCursorHideTimeout(int newcursorHideTimeout); void setLanguage(u32 language); void setNeoMode(bool enable); void setUserName(const std::string& type); void setUpdateChannel(const std::string& type); -void setBackButtonBehavior(const std::string& type); +void setCursorState(s16 cursorState); +void setCursorHideTimeout(int newcursorHideTimeout); +void setBackButtonBehavior(const std::string& type); void setUseSpecialPad(bool use); void setSpecialPadClass(int type); diff --git a/src/qt_gui/settings_dialog.cpp b/src/qt_gui/settings_dialog.cpp index cf64660f8..1cc5a85e4 100644 --- a/src/qt_gui/settings_dialog.cpp +++ b/src/qt_gui/settings_dialog.cpp @@ -47,8 +47,6 @@ QStringList languageNames = {"Arabic", const QVector languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 24, 29, 5, 0, 9, 15, 16, 17, 7, 26, 8, 11, 20, 3, 13, 27, 10, 19, 28}; -QStringList hideCursorStates = {"Never", "Idle", "Always"}; - SettingsDialog::SettingsDialog(std::span physical_devices, QWidget* parent) : QDialog(parent), ui(new Ui::SettingsDialog) { ui->setupUi(this); @@ -69,7 +67,14 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge completer->setCaseSensitivity(Qt::CaseInsensitive); ui->consoleLanguageComboBox->setCompleter(completer); - ui->hideCursorComboBox->addItems(hideCursorStates); + ui->hideCursorComboBox->addItem(tr("Never")); + ui->hideCursorComboBox->addItem(tr("Idle")); + ui->hideCursorComboBox->addItem(tr("Always")); + + ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Left"), "left"); + ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Center"), "center"); + ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Right"), "right"); + ui->backButtonBehaviorComboBox->addItem(tr("None"), "none"); InitializeEmulatorLanguages(); LoadValuesFromConfig(); @@ -102,15 +107,6 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setText(tr("Restore Defaults")); ui->buttonBox->button(QDialogButtonBox::Close)->setText(tr("Close")); - ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Left"), "left"); - ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Center"), "center"); - ui->backButtonBehaviorComboBox->addItem(tr("Touchpad Right"), "right"); - ui->backButtonBehaviorComboBox->addItem(tr("None"), "none"); - - QString currentBackButtonBehavior = QString::fromStdString(Config::getBackButtonBehavior()); - int index = ui->backButtonBehaviorComboBox->findData(currentBackButtonBehavior); - ui->backButtonBehaviorComboBox->setCurrentIndex(index != -1 ? index : 0); - connect(ui->tabWidgetSettings, &QTabWidget::currentChanged, this, [this]() { ui->buttonBox->button(QDialogButtonBox::Close)->setFocus(); }); @@ -175,14 +171,6 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge rpc->shutdown(); } }); - - connect(ui->backButtonBehaviorComboBox, QOverload::of(&QComboBox::currentIndexChanged), - this, [this](int index) { - if (index >= 0 && index < ui->backButtonBehaviorComboBox->count()) { - QString data = ui->backButtonBehaviorComboBox->itemData(index).toString(); - Config::setBackButtonBehavior(data.toStdString()); - } - }); } // Input TAB @@ -195,6 +183,14 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge connect(ui->idleTimeoutSpinBox, &QSpinBox::valueChanged, this, [](int index) { Config::setCursorHideTimeout(index); }); + + connect(ui->backButtonBehaviorComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, [this](int index) { + if (index >= 0 && index < ui->backButtonBehaviorComboBox->count()) { + QString data = ui->backButtonBehaviorComboBox->itemData(index).toString(); + Config::setBackButtonBehavior(data.toStdString()); + } + }); } // GPU TAB @@ -293,6 +289,11 @@ SettingsDialog::SettingsDialog(std::span physical_devices, QWidge ui->logFilter->installEventFilter(this); ui->updaterGroupBox->installEventFilter(this); ui->GUIgroupBox->installEventFilter(this); + + // Input + ui->cursorGroupBox->installEventFilter(this); + ui->hideCursorGroupBox->installEventFilter(this); + ui->idleTimeoutGroupBox->installEventFilter(this); ui->backButtonBehaviorGroupBox->installEventFilter(this); // Graphics @@ -442,6 +443,15 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) { text = tr("updaterGroupBox"); } else if (elementName == "GUIgroupBox") { text = tr("GUIgroupBox"); + } + + // Input + if (elementName == "cursorGroupBox") { + text = tr("cursorGroupBox"); + } else if (elementName == "hideCursorGroupBox") { + text = tr("hideCursorGroupBox"); + } else if (elementName == "idleTimeoutGroupBox") { + text = tr("idleTimeoutGroupBox"); } else if (elementName == "backButtonBehaviorGroupBox") { text = tr("backButtonBehaviorGroupBox"); } diff --git a/src/qt_gui/settings_dialog.ui b/src/qt_gui/settings_dialog.ui index e1c064d5a..9743e51bd 100644 --- a/src/qt_gui/settings_dialog.ui +++ b/src/qt_gui/settings_dialog.ui @@ -274,6 +274,9 @@ + + QLayout::SizeConstraint::SetDefaultConstraint + 0 @@ -286,8 +289,157 @@ 0 - + + + + 0 + 0 + + + + + 275 + 0 + + + + + 16777215 + 16777215 + + + + Update + + + + 5 + + + 1 + + + 11 + + + 11 + + + + + + 0 + 0 + + + + + 0 + 75 + + + + + 16777215 + 16777215 + + + + Update Channel + + + + 7 + + + 11 + + + 11 + + + 11 + + + 11 + + + + + + 0 + 0 + + + + + Release + + + + + Nightly + + + + + + + + + + + + 0 + 0 + + + + + 197 + 28 + + + + + 16777215 + 16777215 + + + + Check for Updates + + + + + + + + 0 + 0 + + + + + 11 + false + + + + Check for Updates at Startup + + + + + + + + + + + + 0 @@ -296,204 +448,141 @@ - 265 + 0 0 - - Update - - - - - 10 - 130 - 261 - 22 - - - - Check for Updates at Startup - - - - - - 12 - 30 - 241 - 65 - - - - Update Channel - - - - - 12 - 30 - 217 - 28 - - - - - Release - - - - - Nightly - - - - - - - - 25 - 100 - 215 - 24 - - - - Check for Updates - - - - - - - - - - - - - 0 - 0 - - GUI Settings - - - - 10 - 30 - 241 - 92 - + + + 1 - - - - - - 0 - 0 - - - - Play title music - - - - - - - - - - - Volume - - - - - - - Set the volume of the background music. - - - 100 - - - 10 - - - 20 - - - 50 - - - Qt::Orientation::Horizontal - - - false - - - false - - - QSlider::TickPosition::NoTicks - - - 10 - - - - - - - - - + + 11 + + + + + 1 + + + 0 + + + + + + 0 + 0 + + + + Play title music + + + + + + + Qt::Orientation::Vertical + + + QSizePolicy::Policy::Fixed + + + + 20 + 2 + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Volume + + + + + + + Set the volume of the background music. + + + 100 + + + 10 + + + 20 + + + 50 + + + Qt::Orientation::Horizontal + + + false + + + false + + + QSlider::TickPosition::NoTicks + + + 10 + + + + + + + + + + 0 + 61 + + + + + - + - - - - 0 - 0 - + + + Qt::Orientation::Horizontal - - Controller Settings + + + 40 + 20 + - - - - 12 - 30 - 241 - 65 - - - - Back Button Behavior - - - - - 12 - 30 - 217 - 28 - - - - - + @@ -510,18 +599,48 @@ - - + + 7 + + + 0 + + + Cursor + + 0 + + + 11 + + + 11 + + + true + + + + 0 + 0 + + Hide Cursor + + 7 + + + 11 + @@ -533,10 +652,16 @@ true + + + 0 + 0 + + 0 - 85 + 0 @@ -549,19 +674,28 @@ false + + 6 + 70 - 11 + 5 - + + 5 + + + 5 + + true - + 0 0 @@ -620,26 +754,80 @@ - + - - - Qt::Orientation::Horizontal + + + + 0 + 0 + - - - 40 - 20 - + + Controller - + + + 0 + + + 11 + + + 11 + + + + + true + + + + 0 + 0 + + + + + 237 + 0 + + + + Back Button Behavior + + + + 11 + + + + + + + + + + + true + + + + 0 + 0 + + + + + + - + Qt::Orientation::Horizontal diff --git a/src/qt_gui/translations/en.ts b/src/qt_gui/translations/en.ts index efbc48fff..974045de1 100644 --- a/src/qt_gui/translations/en.ts +++ b/src/qt_gui/translations/en.ts @@ -434,6 +434,41 @@ Log Filter Log Filter + + + Input + Input + + + + Cursor + Cursor + + + + Hide Cursor + Hide Cursor + + + + Hide Cursor Idle Timeout + Hide Cursor Idle Timeout + + + + Input + Input + + + + Controller + Controller + + + + Back Button Behavior + Back Button Behavior + Graphics @@ -534,16 +569,6 @@ Volume Volume - - - Controller Settings - Controller Settings - - - - Back Button Behavior - Back Button Behavior - MainWindow @@ -1033,6 +1058,41 @@ GUIgroupBox Play Title Music:\nIf a game supports it, enable playing special music when selecting the game in the GUI. + + + cursorGroupBox + Cursor:\nChange settings related to the cursor. + + + + hideCursorGroupBox + Hide Cursor:\nSet cursor hiding behavior. + + + + idleTimeoutGroupBox + Hide Idle Cursor Timeout:\nThe duration (seconds) after which the cursor that has been idle hides itself. + + + + Never + Never + + + + Idle + Idle + + + + Always + Always + + + + backButtonBehaviorGroupBox + Back Button Behavior:\nAllows setting which part of the touchpad the back button will emulate a touch on. + backButtonBehaviorGroupBox From ab6901ae6a93c80ee864756f3a4f811dd73308c9 Mon Sep 17 00:00:00 2001 From: robyn-dressler Date: Thu, 10 Oct 2024 09:53:18 -0500 Subject: [PATCH 5/8] Using a more standard data directory for linux (#1227) * Using a more standard data directory for linux * Fixing format * Using XDG_DATA_HOME by default --- src/common/path_util.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 27098e2d1..7551d3b05 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -95,6 +95,18 @@ static auto UserPaths = [] { user_dir = std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4"; } +#elif defined(__linux__) + auto user_dir = std::filesystem::current_path() / PORTABLE_DIR; + // Check if the "user" directory exists in the current path: + if (!std::filesystem::exists(user_dir)) { + // If it doesn't exist, use XDG_DATA_HOME if it is set, and provide a standard default + const char* xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) { + user_dir = std::filesystem::path(xdg_data_home) / "shadPS4"; + } else { + user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4"; + } + } #else const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR; #endif From 0e0de5a2a01b25a00217a7b0a175242713b36e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Thu, 10 Oct 2024 15:54:07 +0100 Subject: [PATCH 6/8] Stub return value of sceNpCreateRequest (#1209) --- src/core/libraries/np_manager/np_manager.cpp | 9 +++++---- src/core/libraries/np_manager/np_manager.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/libraries/np_manager/np_manager.cpp b/src/core/libraries/np_manager/np_manager.cpp index 28d28cc93..e1aaee814 100644 --- a/src/core/libraries/np_manager/np_manager.cpp +++ b/src/core/libraries/np_manager/np_manager.cpp @@ -902,12 +902,13 @@ int PS4_SYSV_ABI sceNpCreateAsyncRequest() { } int PS4_SYSV_ABI sceNpCreateRequest() { - LOG_ERROR(Lib_NpManager, "(STUBBED) called"); - return ORBIS_OK; + LOG_ERROR(Lib_NpManager, "(DUMMY) called"); + static int id = 0; + return ++id; } -int PS4_SYSV_ABI sceNpDeleteRequest() { - LOG_ERROR(Lib_NpManager, "(STUBBED) called"); +int PS4_SYSV_ABI sceNpDeleteRequest(int reqId) { + LOG_ERROR(Lib_NpManager, "(DUMMY) called reqId = {}", reqId); return ORBIS_OK; } diff --git a/src/core/libraries/np_manager/np_manager.h b/src/core/libraries/np_manager/np_manager.h index 43ea49ce4..861d91e39 100644 --- a/src/core/libraries/np_manager/np_manager.h +++ b/src/core/libraries/np_manager/np_manager.h @@ -218,7 +218,7 @@ int PS4_SYSV_ABI sceNpCheckNpReachability(); int PS4_SYSV_ABI sceNpCheckPlus(); int PS4_SYSV_ABI sceNpCreateAsyncRequest(); int PS4_SYSV_ABI sceNpCreateRequest(); -int PS4_SYSV_ABI sceNpDeleteRequest(); +int PS4_SYSV_ABI sceNpDeleteRequest(int reqId); int PS4_SYSV_ABI sceNpGetAccountAge(); int PS4_SYSV_ABI sceNpGetAccountCountry(); int PS4_SYSV_ABI sceNpGetAccountCountryA(); From 3982ef7188a7fcfa16f5d884ac1a08c703940b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quang=20Ng=C3=B4?= Date: Thu, 10 Oct 2024 21:54:32 +0700 Subject: [PATCH 7/8] ci: add missing libs to enable Wayland backend for SDL (#1184) --- .github/linux-appimage-qt.sh | 2 ++ .github/workflows/build.yml | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/linux-appimage-qt.sh b/.github/linux-appimage-qt.sh index fe77c678c..06d5cbc11 100755 --- a/.github/linux-appimage-qt.sh +++ b/.github/linux-appimage-qt.sh @@ -9,6 +9,8 @@ fi export Qt6_DIR="/usr/lib/qt6" export PATH="$Qt6_DIR/bin:$PATH" +export EXTRA_QT_PLUGINS="waylandcompositor" +export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" # Prepare Tools for building the AppImage wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7950084cd..ee09163fd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -287,7 +287,7 @@ jobs: submodules: recursive - name: Install dependencies - run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev + run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev - name: Cache CMake Configuration uses: actions/cache@v4 @@ -343,7 +343,7 @@ jobs: submodules: recursive - name: Install dependencies - run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev + run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev - name: Cache CMake Configuration uses: actions/cache@v4 From 6e986f81335129db728cc9270caeef9e781f4fd7 Mon Sep 17 00:00:00 2001 From: korenkonder Date: Thu, 10 Oct 2024 18:03:12 +0300 Subject: [PATCH 8/8] video_core: Implement sceGnmInsertPushColorMarker (#989) --- src/core/libraries/gnmdriver/gnmdriver.cpp | 24 ++++++++++++++++--- src/core/libraries/gnmdriver/gnmdriver.h | 2 +- src/video_core/amdgpu/liverpool.cpp | 11 +++++++++ .../renderer_vulkan/vk_rasterizer.cpp | 13 ++++++++++ .../renderer_vulkan/vk_rasterizer.h | 1 + 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 7e2153efa..ce30895ca 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -1076,9 +1076,27 @@ s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size) { return -1; } -int PS4_SYSV_ABI sceGnmInsertPushColorMarker() { - LOG_ERROR(Lib_GnmDriver, "(STUBBED) called"); - return ORBIS_OK; +s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color) { + LOG_TRACE(Lib_GnmDriver, "called"); + + if (cmdbuf && marker) { + const auto len = std::strlen(marker); + const u32 packet_size = ((len + 0xc) >> 2) + ((len + 0x10) >> 3) * 2; + if (packet_size + 2 == size) { + auto* nop = reinterpret_cast(cmdbuf); + nop->header = + PM4Type3Header{PM4ItOpcode::Nop, packet_size, PM4ShaderType::ShaderGraphics}; + nop->data_block[0] = PM4CmdNop::PayloadType::DebugColorMarkerPush; + const auto marker_len = len + 1; + std::memcpy(&nop->data_block[1], marker, marker_len); + *reinterpret_cast(reinterpret_cast(&nop->data_block[1]) + marker_len + 8) = + color; + std::memset(reinterpret_cast(&nop->data_block[1]) + marker_len + 8 + sizeof(u32), + 0, packet_size * 4 - marker_len - 8 - sizeof(u32)); + return ORBIS_OK; + } + } + return -1; } s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker) { diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 55a70cbf3..33bccf427 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -105,7 +105,7 @@ int PS4_SYSV_ABI sceGnmGpuPaDebugEnter(); int PS4_SYSV_ABI sceGnmGpuPaDebugLeave(); int PS4_SYSV_ABI sceGnmInsertDingDongMarker(); s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size); -int PS4_SYSV_ABI sceGnmInsertPushColorMarker(); +s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color); s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker); int PS4_SYSV_ABI sceGnmInsertSetColorMarker(); int PS4_SYSV_ABI sceGnmInsertSetMarker(); diff --git a/src/video_core/amdgpu/liverpool.cpp b/src/video_core/amdgpu/liverpool.cpp index 3dce871fe..b3b718836 100644 --- a/src/video_core/amdgpu/liverpool.cpp +++ b/src/video_core/amdgpu/liverpool.cpp @@ -226,6 +226,17 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span dcb, std::spanheader.count.Value() * 2; + const std::string_view label{reinterpret_cast(&nop->data_block[1]), + marker_sz}; + const u32 color = *reinterpret_cast( + reinterpret_cast(&nop->data_block[1]) + marker_sz); + if (rasterizer) { + rasterizer->ScopedMarkerInsertColor(label, color); + } + break; + } case PM4CmdNop::PayloadType::DebugMarkerPop: { if (rasterizer) { rasterizer->ScopeMarkerEnd(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 6088d99cf..293dfbe6a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -459,4 +459,17 @@ void Rasterizer::ScopedMarkerInsert(const std::string_view& str) { }); } +void Rasterizer::ScopedMarkerInsertColor(const std::string_view& str, const u32 color) { + if (Config::nullGpu() || !Config::vkMarkersEnabled()) { + return; + } + + const auto cmdbuf = scheduler.CommandBuffer(); + cmdbuf.insertDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{ + .pLabelName = str.data(), + .color = std::array( + {(f32)((color >> 16) & 0xff) / 255.0f, (f32)((color >> 8) & 0xff) / 255.0f, + (f32)(color & 0xff) / 255.0f, (f32)((color >> 24) & 0xff) / 255.0f})}); +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 82e8fc0c0..bc14f39a4 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -40,6 +40,7 @@ public: void ScopeMarkerBegin(const std::string_view& str); void ScopeMarkerEnd(); void ScopedMarkerInsert(const std::string_view& str); + void ScopedMarkerInsertColor(const std::string_view& str, const u32 color); void InlineDataToGds(u32 gds_offset, u32 value); u32 ReadDataFromGds(u32 gsd_offset);