diff options
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_spirv.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv.cpp | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv.cpp b/src/shader_recompiler/backend/spirv/emit_spirv.cpp index 4ce07c281..2519e446a 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv.cpp | |||
| @@ -14,8 +14,6 @@ | |||
| 14 | #include "shader_recompiler/frontend/ir/microinstruction.h" | 14 | #include "shader_recompiler/frontend/ir/microinstruction.h" |
| 15 | #include "shader_recompiler/frontend/ir/program.h" | 15 | #include "shader_recompiler/frontend/ir/program.h" |
| 16 | 16 | ||
| 17 | #pragma optimize("", off) | ||
| 18 | |||
| 19 | namespace Shader::Backend::SPIRV { | 17 | namespace Shader::Backend::SPIRV { |
| 20 | namespace { | 18 | namespace { |
| 21 | template <class Func> | 19 | template <class Func> |
| @@ -113,9 +111,61 @@ Id TypeId(const EmitContext& ctx, IR::Type type) { | |||
| 113 | throw NotImplementedException("Phi node type {}", type); | 111 | throw NotImplementedException("Phi node type {}", type); |
| 114 | } | 112 | } |
| 115 | } | 113 | } |
| 114 | |||
| 115 | void SetupDenormControl(const Profile& profile, const IR::Program& program, EmitContext& ctx, | ||
| 116 | Id main_func) { | ||
| 117 | if (!profile.support_float_controls) { | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | const Info& info{program.info}; | ||
| 121 | if (!info.uses_fp32_denorms_flush && !info.uses_fp32_denorms_preserve && | ||
| 122 | !info.uses_fp16_denorms_flush && !info.uses_fp16_denorms_preserve) { | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | ctx.AddExtension("SPV_KHR_float_controls"); | ||
| 126 | |||
| 127 | if (info.uses_fp32_denorms_flush && info.uses_fp32_denorms_preserve) { | ||
| 128 | // LOG_ERROR(HW_GPU, "Fp32 denorm flush and preserve on the same shader"); | ||
| 129 | } else if (info.uses_fp32_denorms_flush) { | ||
| 130 | if (profile.support_fp32_denorm_flush) { | ||
| 131 | ctx.AddCapability(spv::Capability::DenormFlushToZero); | ||
| 132 | ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U); | ||
| 133 | } else { | ||
| 134 | // Drivers will most likely flush denorms by default, no need to warn | ||
| 135 | } | ||
| 136 | } else if (info.uses_fp32_denorms_preserve) { | ||
| 137 | if (profile.support_fp32_denorm_preserve) { | ||
| 138 | ctx.AddCapability(spv::Capability::DenormPreserve); | ||
| 139 | ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 32U); | ||
| 140 | } else { | ||
| 141 | // LOG_WARNING(HW_GPU, "Fp32 denorm preserve used in shader without host support"); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | if (!profile.support_separate_denorm_behavior) { | ||
| 145 | // No separate denorm behavior | ||
| 146 | return; | ||
| 147 | } | ||
| 148 | if (info.uses_fp16_denorms_flush && info.uses_fp16_denorms_preserve) { | ||
| 149 | // LOG_ERROR(HW_GPU, "Fp16 denorm flush and preserve on the same shader"); | ||
| 150 | } else if (info.uses_fp16_denorms_flush) { | ||
| 151 | if (profile.support_fp16_denorm_flush) { | ||
| 152 | ctx.AddCapability(spv::Capability::DenormFlushToZero); | ||
| 153 | ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 16U); | ||
| 154 | } else { | ||
| 155 | // Same as fp32, no need to warn as most drivers will flush by default | ||
| 156 | } | ||
| 157 | } else if (info.uses_fp32_denorms_preserve) { | ||
| 158 | if (profile.support_fp16_denorm_preserve) { | ||
| 159 | ctx.AddCapability(spv::Capability::DenormPreserve); | ||
| 160 | ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 16U); | ||
| 161 | } else { | ||
| 162 | // LOG_WARNING(HW_GPU, "Fp16 denorm preserve used in shader without host support"); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 116 | } // Anonymous namespace | 166 | } // Anonymous namespace |
| 117 | 167 | ||
| 118 | std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { | 168 | std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program& program) { |
| 119 | EmitContext ctx{program}; | 169 | EmitContext ctx{program}; |
| 120 | const Id void_function{ctx.TypeFunction(ctx.void_id)}; | 170 | const Id void_function{ctx.TypeFunction(ctx.void_id)}; |
| 121 | // FIXME: Forward declare functions (needs sirit support) | 171 | // FIXME: Forward declare functions (needs sirit support) |
| @@ -131,10 +181,11 @@ std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { | |||
| 131 | ctx.OpFunctionEnd(); | 181 | ctx.OpFunctionEnd(); |
| 132 | } | 182 | } |
| 133 | boost::container::small_vector<Id, 32> interfaces; | 183 | boost::container::small_vector<Id, 32> interfaces; |
| 134 | if (program.info.uses_workgroup_id) { | 184 | const Info& info{program.info}; |
| 185 | if (info.uses_workgroup_id) { | ||
| 135 | interfaces.push_back(ctx.workgroup_id); | 186 | interfaces.push_back(ctx.workgroup_id); |
| 136 | } | 187 | } |
| 137 | if (program.info.uses_local_invocation_id) { | 188 | if (info.uses_local_invocation_id) { |
| 138 | interfaces.push_back(ctx.local_invocation_id); | 189 | interfaces.push_back(ctx.local_invocation_id); |
| 139 | } | 190 | } |
| 140 | const std::span interfaces_span(interfaces.data(), interfaces.size()); | 191 | const std::span interfaces_span(interfaces.data(), interfaces.size()); |
| @@ -144,6 +195,8 @@ std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { | |||
| 144 | ctx.AddExecutionMode(func, spv::ExecutionMode::LocalSize, workgroup_size[0], workgroup_size[1], | 195 | ctx.AddExecutionMode(func, spv::ExecutionMode::LocalSize, workgroup_size[0], workgroup_size[1], |
| 145 | workgroup_size[2]); | 196 | workgroup_size[2]); |
| 146 | 197 | ||
| 198 | SetupDenormControl(profile, program, ctx, func); | ||
| 199 | |||
| 147 | return ctx.Assemble(); | 200 | return ctx.Assemble(); |
| 148 | } | 201 | } |
| 149 | 202 | ||