|
|
|
@ -14,8 +14,6 @@ |
|
|
|
#include "shader_recompiler/frontend/ir/microinstruction.h"
|
|
|
|
#include "shader_recompiler/frontend/ir/program.h"
|
|
|
|
|
|
|
|
#pragma optimize("", off)
|
|
|
|
|
|
|
|
namespace Shader::Backend::SPIRV { |
|
|
|
namespace { |
|
|
|
template <class Func> |
|
|
|
@ -113,9 +111,61 @@ Id TypeId(const EmitContext& ctx, IR::Type type) { |
|
|
|
throw NotImplementedException("Phi node type {}", type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void SetupDenormControl(const Profile& profile, const IR::Program& program, EmitContext& ctx, |
|
|
|
Id main_func) { |
|
|
|
if (!profile.support_float_controls) { |
|
|
|
return; |
|
|
|
} |
|
|
|
const Info& info{program.info}; |
|
|
|
if (!info.uses_fp32_denorms_flush && !info.uses_fp32_denorms_preserve && |
|
|
|
!info.uses_fp16_denorms_flush && !info.uses_fp16_denorms_preserve) { |
|
|
|
return; |
|
|
|
} |
|
|
|
ctx.AddExtension("SPV_KHR_float_controls"); |
|
|
|
|
|
|
|
if (info.uses_fp32_denorms_flush && info.uses_fp32_denorms_preserve) { |
|
|
|
// LOG_ERROR(HW_GPU, "Fp32 denorm flush and preserve on the same shader");
|
|
|
|
} else if (info.uses_fp32_denorms_flush) { |
|
|
|
if (profile.support_fp32_denorm_flush) { |
|
|
|
ctx.AddCapability(spv::Capability::DenormFlushToZero); |
|
|
|
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 32U); |
|
|
|
} else { |
|
|
|
// Drivers will most likely flush denorms by default, no need to warn
|
|
|
|
} |
|
|
|
} else if (info.uses_fp32_denorms_preserve) { |
|
|
|
if (profile.support_fp32_denorm_preserve) { |
|
|
|
ctx.AddCapability(spv::Capability::DenormPreserve); |
|
|
|
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 32U); |
|
|
|
} else { |
|
|
|
// LOG_WARNING(HW_GPU, "Fp32 denorm preserve used in shader without host support");
|
|
|
|
} |
|
|
|
} |
|
|
|
if (!profile.support_separate_denorm_behavior) { |
|
|
|
// No separate denorm behavior
|
|
|
|
return; |
|
|
|
} |
|
|
|
if (info.uses_fp16_denorms_flush && info.uses_fp16_denorms_preserve) { |
|
|
|
// LOG_ERROR(HW_GPU, "Fp16 denorm flush and preserve on the same shader");
|
|
|
|
} else if (info.uses_fp16_denorms_flush) { |
|
|
|
if (profile.support_fp16_denorm_flush) { |
|
|
|
ctx.AddCapability(spv::Capability::DenormFlushToZero); |
|
|
|
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 16U); |
|
|
|
} else { |
|
|
|
// Same as fp32, no need to warn as most drivers will flush by default
|
|
|
|
} |
|
|
|
} else if (info.uses_fp32_denorms_preserve) { |
|
|
|
if (profile.support_fp16_denorm_preserve) { |
|
|
|
ctx.AddCapability(spv::Capability::DenormPreserve); |
|
|
|
ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 16U); |
|
|
|
} else { |
|
|
|
// LOG_WARNING(HW_GPU, "Fp16 denorm preserve used in shader without host support");
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
|
|
std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { |
|
|
|
std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program& program) { |
|
|
|
EmitContext ctx{program}; |
|
|
|
const Id void_function{ctx.TypeFunction(ctx.void_id)}; |
|
|
|
// FIXME: Forward declare functions (needs sirit support)
|
|
|
|
@ -131,10 +181,11 @@ std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { |
|
|
|
ctx.OpFunctionEnd(); |
|
|
|
} |
|
|
|
boost::container::small_vector<Id, 32> interfaces; |
|
|
|
if (program.info.uses_workgroup_id) { |
|
|
|
const Info& info{program.info}; |
|
|
|
if (info.uses_workgroup_id) { |
|
|
|
interfaces.push_back(ctx.workgroup_id); |
|
|
|
} |
|
|
|
if (program.info.uses_local_invocation_id) { |
|
|
|
if (info.uses_local_invocation_id) { |
|
|
|
interfaces.push_back(ctx.local_invocation_id); |
|
|
|
} |
|
|
|
const std::span interfaces_span(interfaces.data(), interfaces.size()); |
|
|
|
@ -144,6 +195,8 @@ std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) { |
|
|
|
ctx.AddExecutionMode(func, spv::ExecutionMode::LocalSize, workgroup_size[0], workgroup_size[1], |
|
|
|
workgroup_size[2]); |
|
|
|
|
|
|
|
SetupDenormControl(profile, program, ctx, func); |
|
|
|
|
|
|
|
return ctx.Assemble(); |
|
|
|
} |
|
|
|
|
|
|
|
|