diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b8844e44..ecab3e02d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,10 +16,6 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - add_compile_definitions(_DEBUG) -endif() - project(shadPS4) # Forcing PIE makes sure that the base address is high enough so that it doesn't clash with the PS4 memory. diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index dc332fa72..ad265e8f4 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -254,13 +254,8 @@ struct Info { } } - // TODO probably not needed - bool FoundTessConstantsSharp() const { - return tess_consts_dword_offset >= 0; - } - void ReadTessConstantBuffer(TessellationDataConstantBuffer& tess_constants) const { - ASSERT(FoundTessConstantsSharp()); + ASSERT(tess_consts_dword_offset >= 0); // We've already tracked the V# UD auto buf = ReadUdReg(static_cast(tess_consts_ptr_base), static_cast(tess_consts_dword_offset)); VAddr tess_constants_addr = buf.base_address; diff --git a/src/shader_recompiler/ir/passes/hull_shader_transform.cpp b/src/shader_recompiler/ir/passes/hull_shader_transform.cpp index 861360fbb..05724771a 100644 --- a/src/shader_recompiler/ir/passes/hull_shader_transform.cpp +++ b/src/shader_recompiler/ir/passes/hull_shader_transform.cpp @@ -392,15 +392,11 @@ void HullShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) { // The hull outputs tess factors in different formats depending on the shader. // For triangle domains, it seems to pack the entries into 4 consecutive floats, // with the 3 edge factors followed by the 1 interior factor. - // For quads, it does the expected 4 edge factors then 2 interior. + // For quads, it does 4 edge factors then 2 interior. // There is a tess factor stride member of the GNMX hull constants struct in // a hull program shader binary archive, but this doesn't seem to be - // communicated to the driver. The fixed function tessellator would need to know - // this somehow. It's probably implied by the type of the abstract domain. If - // this is causing problems, good idea to check the hs_regs argument to - // sceGnmSetHsShader. The memory containing the tess factor stride probably - // follows the memory for hs_regs if the app is providing a pointer into the - // program they loaded from disk + // communicated to the driver. + // The layout seems to be implied by the type of the abstract domain. switch (runtime_info.hs_info.tess_type) { case AmdGpu::TessellationType::Quad: ASSERT(gcn_factor_idx < 6); @@ -595,54 +591,63 @@ void DomainShaderTransform(IR::Program& program, RuntimeInfo& runtime_info) { } } -// Run before copy prop +// Run before either hull or domain transform void TessellationPreprocess(IR::Program& program, RuntimeInfo& runtime_info) { TessellationDataConstantBuffer tess_constants; Shader::Info& info = program.info; // Find the TessellationDataConstantBuffer V# for (IR::Block* block : program.blocks) { for (IR::Inst& inst : block->Instructions()) { - switch (inst.GetOpcode()) { - case IR::Opcode::LoadSharedU32: - case IR::Opcode::LoadSharedU64: - case IR::Opcode::LoadSharedU128: - case IR::Opcode::WriteSharedU32: - case IR::Opcode::WriteSharedU64: - case IR::Opcode::WriteSharedU128: { - IR::Value addr = inst.Arg(0); - auto read_const_buffer = IR::BreadthFirstSearch( - addr, [](IR::Inst* maybe_tess_const) -> std::optional { - if (maybe_tess_const->GetOpcode() == IR::Opcode::ReadConstBuffer) { - return maybe_tess_const; + auto found_tess_consts_sharp = [&]() -> bool { + switch (inst.GetOpcode()) { + case IR::Opcode::LoadSharedU32: + case IR::Opcode::LoadSharedU64: + case IR::Opcode::LoadSharedU128: + case IR::Opcode::WriteSharedU32: + case IR::Opcode::WriteSharedU64: + case IR::Opcode::WriteSharedU128: { + IR::Value addr = inst.Arg(0); + auto read_const_buffer = IR::BreadthFirstSearch( + addr, [](IR::Inst* maybe_tess_const) -> std::optional { + if (maybe_tess_const->GetOpcode() == IR::Opcode::ReadConstBuffer) { + return maybe_tess_const; + } + return std::nullopt; + }); + if (read_const_buffer) { + auto sharp_location = FindTessConstantSharp(read_const_buffer.value()); + if (sharp_location) { + if (info.tess_consts_dword_offset >= 0) { + // Its possible theres a readconstbuffer that contributes to an + // LDS address and isnt a TessConstant V# read. Could improve on + // this somehow + ASSERT_MSG(static_cast(sharp_location->dword_off) == + info.tess_consts_dword_offset && + sharp_location->ptr_base == + info.tess_consts_ptr_base, + "TessConstants V# is ambiguous"); + } + InitTessConstants(sharp_location->ptr_base, + static_cast(sharp_location->dword_off), info, + runtime_info, tess_constants); + return true; } - return std::nullopt; - }); - if (read_const_buffer) { - auto sharp_location = FindTessConstantSharp(read_const_buffer.value()); - if (sharp_location) { - if (info.FoundTessConstantsSharp()) { - ASSERT(static_cast(sharp_location->dword_off) == - info.tess_consts_dword_offset && - sharp_location->ptr_base == info.tess_consts_ptr_base); - } - InitTessConstants(sharp_location->ptr_base, - static_cast(sharp_location->dword_off), info, - runtime_info, tess_constants); - break; // break out of switch and loop + UNREACHABLE_MSG("Failed to match tess constant sharp"); } - UNREACHABLE_MSG("Failed to match tess constant sharp"); + return false; } - continue; - } - default: - continue; - } + default: + return false; + } + }(); - break; + if (found_tess_consts_sharp) { + break; + } } } - ASSERT(info.FoundTessConstantsSharp()); + ASSERT(info.tess_consts_dword_offset >= 0); TessConstantUseWalker walker; diff --git a/src/shader_recompiler/recompiler.cpp b/src/shader_recompiler/recompiler.cpp index 00e4ef83a..ad57adb6a 100644 --- a/src/shader_recompiler/recompiler.cpp +++ b/src/shader_recompiler/recompiler.cpp @@ -67,13 +67,15 @@ IR::Program TranslateProgram(std::span code, Pools& pools, Info& info Shader::Optimization::SsaRewritePass(program.post_order_blocks); Shader::Optimization::IdentityRemovalPass(program.blocks); - Shader::Optimization::ConstantPropagationPass( - program.post_order_blocks); // TODO const fold spam for now while testing if (info.l_stage == LogicalStage::TessellationControl) { + // Tess passes require previous const prop passes for now (for simplicity). TODO allow + // fine grained folding or opportunistic folding we set an operand to an immediate + Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::TessellationPreprocess(program, runtime_info); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::HullShaderTransform(program, runtime_info); } else if (info.l_stage == LogicalStage::TessellationEval) { + Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::TessellationPreprocess(program, runtime_info); Shader::Optimization::ConstantPropagationPass(program.post_order_blocks); Shader::Optimization::DomainShaderTransform(program, runtime_info); diff --git a/src/shader_recompiler/specialization.h b/src/shader_recompiler/specialization.h index 9b5dd8fa1..5799c4c95 100644 --- a/src/shader_recompiler/specialization.h +++ b/src/shader_recompiler/specialization.h @@ -127,6 +127,18 @@ struct StageSpecialization { [](auto& spec, const auto& desc, AmdGpu::Sampler sharp) { spec.force_unnormalized = sharp.force_unnormalized; }); + + // Initialize runtime_info fields that rely on analysis in tessellation passes + if (info->l_stage == LogicalStage::TessellationControl || + info->l_stage == LogicalStage::TessellationEval) { + Shader::TessellationDataConstantBuffer tess_constants; + info->ReadTessConstantBuffer(tess_constants); + if (info->l_stage == LogicalStage::TessellationControl) { + runtime_info.hs_info.InitFromTessConstants(tess_constants); + } else { + runtime_info.vs_info.InitFromTessConstants(tess_constants); + } + } } void ForEachSharp(auto& spec_list, auto& desc_list, auto&& func) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 705c72606..c4e654327 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -9,7 +9,6 @@ #include "common/path_util.h" #include "core/debug_state.h" #include "shader_recompiler/backend/spirv/emit_spirv.h" -#include "shader_recompiler/frontend/tessellation.h" #include "shader_recompiler/info.h" #include "shader_recompiler/recompiler.h" #include "shader_recompiler/runtime_info.h" @@ -533,15 +532,6 @@ PipelineCache::Result PipelineCache::GetProgram(Stage stage, LogicalStage l_stag auto& program = it_pgm.value(); auto& info = program->info; info.RefreshFlatBuf(); - if (l_stage == LogicalStage::TessellationControl || l_stage == LogicalStage::TessellationEval) { - Shader::TessellationDataConstantBuffer tess_constants; - info.ReadTessConstantBuffer(tess_constants); - if (l_stage == LogicalStage::TessellationControl) { - runtime_info.hs_info.InitFromTessConstants(tess_constants); - } else { - runtime_info.vs_info.InitFromTessConstants(tess_constants); - } - } const auto spec = Shader::StageSpecialization(info, runtime_info, profile, binding); size_t perm_idx = program->modules.size(); vk::ShaderModule module{};