Sfoglia il codice sorgente

spirv: Fixes and Intel specific workarounds

ReinUsesLisp 5 anni fa
parent
commit
274897dfd5

+ 2 - 1
src/shader_recompiler/backend/spirv/emit_context.cpp

@@ -25,7 +25,8 @@ void VectorTypes::Define(Sirit::Module& sirit_ctx, Id base_type, std::string_vie
     }
 }
 
-EmitContext::EmitContext(IR::Program& program) : Sirit::Module(0x00010000) {
+EmitContext::EmitContext(const Profile& profile_, IR::Program& program)
+    : Sirit::Module(0x00010000), profile{profile_} {
     AddCapability(spv::Capability::Shader);
     DefineCommonTypes(program.info);
     DefineCommonConstants();

+ 4 - 1
src/shader_recompiler/backend/spirv/emit_context.h

@@ -11,6 +11,7 @@
 
 #include "shader_recompiler/frontend/ir/program.h"
 #include "shader_recompiler/shader_info.h"
+#include "shader_recompiler/profile.h"
 
 namespace Shader::Backend::SPIRV {
 
@@ -30,11 +31,13 @@ private:
 
 class EmitContext final : public Sirit::Module {
 public:
-    explicit EmitContext(IR::Program& program);
+    explicit EmitContext(const Profile& profile, IR::Program& program);
     ~EmitContext();
 
     [[nodiscard]] Id Def(const IR::Value& value);
 
+    const Profile& profile;
+
     Id void_id{};
     Id U1{};
     Id U16{};

+ 3 - 3
src/shader_recompiler/backend/spirv/emit_spirv.cpp

@@ -150,11 +150,11 @@ void SetupDenormControl(const Profile& profile, const IR::Program& program, Emit
     } 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);
+            ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormFlushToZero, 16U);
         } else {
             // Same as fp32, no need to warn as most drivers will flush by default
         }
-    } else if (info.uses_fp32_denorms_preserve) {
+    } else if (info.uses_fp16_denorms_preserve) {
         if (profile.support_fp16_denorm_preserve) {
             ctx.AddCapability(spv::Capability::DenormPreserve);
             ctx.AddExecutionMode(main_func, spv::ExecutionMode::DenormPreserve, 16U);
@@ -166,7 +166,7 @@ void SetupDenormControl(const Profile& profile, const IR::Program& program, Emit
 } // Anonymous namespace
 
 std::vector<u32> EmitSPIRV(const Profile& profile, Environment& env, IR::Program& program) {
-    EmitContext ctx{program};
+    EmitContext ctx{profile, program};
     const Id void_function{ctx.TypeFunction(ctx.void_id)};
     // FIXME: Forward declare functions (needs sirit support)
     Id func{};

+ 4 - 4
src/shader_recompiler/backend/spirv/emit_spirv.h

@@ -202,10 +202,10 @@ Id EmitUGreaterThan(EmitContext& ctx, Id lhs, Id rhs);
 Id EmitINotEqual(EmitContext& ctx, Id lhs, Id rhs);
 Id EmitSGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs);
 Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs);
-void EmitLogicalOr(EmitContext& ctx);
-void EmitLogicalAnd(EmitContext& ctx);
-void EmitLogicalXor(EmitContext& ctx);
-void EmitLogicalNot(EmitContext& ctx);
+Id EmitLogicalOr(EmitContext& ctx, Id a, Id b);
+Id EmitLogicalAnd(EmitContext& ctx, Id a, Id b);
+Id EmitLogicalXor(EmitContext& ctx, Id a, Id b);
+Id EmitLogicalNot(EmitContext& ctx, Id value);
 Id EmitConvertS16F16(EmitContext& ctx, Id value);
 Id EmitConvertS16F32(EmitContext& ctx, Id value);
 Id EmitConvertS16F64(EmitContext& ctx, Id value);

+ 10 - 3
src/shader_recompiler/backend/spirv/emit_spirv_floating_point.cpp

@@ -15,6 +15,13 @@ Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
     return op;
 }
 
+Id Saturate(EmitContext& ctx, Id type, Id value, Id zero, Id one) {
+    if (ctx.profile.has_broken_spirv_clamp) {
+        return ctx.OpFMin(type, ctx.OpFMax(type, value, zero), one);
+    } else {
+        return ctx.OpFClamp(type, value, zero, one);
+    }
+}
 } // Anonymous namespace
 
 Id EmitFPAbs16(EmitContext& ctx, Id value) {
@@ -144,19 +151,19 @@ void EmitFPLog2(EmitContext&) {
 Id EmitFPSaturate16(EmitContext& ctx, Id value) {
     const Id zero{ctx.Constant(ctx.F16[1], u16{0})};
     const Id one{ctx.Constant(ctx.F16[1], u16{0x3c00})};
-    return ctx.OpFClamp(ctx.F32[1], value, zero, one);
+    return Saturate(ctx, ctx.F16[1], value, zero, one);
 }
 
 Id EmitFPSaturate32(EmitContext& ctx, Id value) {
     const Id zero{ctx.Constant(ctx.F32[1], f32{0.0})};
     const Id one{ctx.Constant(ctx.F32[1], f32{1.0})};
-    return ctx.OpFClamp(ctx.F32[1], value, zero, one);
+    return Saturate(ctx, ctx.F32[1], value, zero, one);
 }
 
 Id EmitFPSaturate64(EmitContext& ctx, Id value) {
     const Id zero{ctx.Constant(ctx.F64[1], f64{0.0})};
     const Id one{ctx.Constant(ctx.F64[1], f64{1.0})};
-    return ctx.OpFClamp(ctx.F64[1], value, zero, one);
+    return Saturate(ctx, ctx.F64[1], value, zero, one);
 }
 
 Id EmitFPRoundEven16(EmitContext& ctx, Id value) {

+ 8 - 8
src/shader_recompiler/backend/spirv/emit_spirv_logical.cpp

@@ -6,20 +6,20 @@
 
 namespace Shader::Backend::SPIRV {
 
-void EmitLogicalOr(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitLogicalOr(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpLogicalOr(ctx.U1, a, b);
 }
 
-void EmitLogicalAnd(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitLogicalAnd(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpLogicalAnd(ctx.U1, a, b);
 }
 
-void EmitLogicalXor(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitLogicalXor(EmitContext& ctx, Id a, Id b) {
+    return ctx.OpLogicalNotEqual(ctx.U1, a, b);
 }
 
-void EmitLogicalNot(EmitContext&) {
-    throw NotImplementedException("SPIR-V Instruction");
+Id EmitLogicalNot(EmitContext& ctx, Id value) {
+    return ctx.OpLogicalNot(ctx.U1, value);
 }
 
 } // namespace Shader::Backend::SPIRV

+ 0 - 3
src/shader_recompiler/frontend/ir/structured_control_flow.cpp

@@ -272,11 +272,9 @@ public:
     explicit GotoPass(std::span<Block* const> blocks, ObjectPool<Statement>& stmt_pool)
         : pool{stmt_pool} {
         std::vector gotos{BuildUnorderedTreeGetGotos(blocks)};
-        fmt::print(stdout, "BEFORE\n{}\n", DumpTree(root_stmt.children));
         for (const Node& goto_stmt : gotos | std::views::reverse) {
             RemoveGoto(goto_stmt);
         }
-        fmt::print(stdout, "AFTER\n{}\n", DumpTree(root_stmt.children));
     }
 
     Statement& RootStatement() noexcept {
@@ -548,7 +546,6 @@ private:
     size_t Offset(ConstNode stmt) const {
         size_t offset{0};
         if (!SearchNode(root_stmt.children, stmt, offset)) {
-            fmt::print(stdout, "{}\n", DumpTree(root_stmt.children));
             throw LogicError("Node not found in tree");
         }
         return offset;

+ 0 - 3
src/shader_recompiler/frontend/maxwell/program.cpp

@@ -56,7 +56,6 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
             .post_order_blocks{},
         });
     }
-    fmt::print(stdout, "{}\n", IR::DumpProgram(program));
     Optimization::LowerFp16ToFp32(program);
     for (IR::Function& function : functions) {
         function.post_order_blocks = PostOrder(function.blocks);
@@ -70,8 +69,6 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
         Optimization::VerificationPass(function);
     }
     Optimization::CollectShaderInfoPass(program);
-
-    fmt::print(stdout, "{}\n", IR::DumpProgram(program));
     return program;
 }
 

+ 9 - 6
src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp

@@ -83,9 +83,12 @@ IR::U32 TranslatorVisitor::GetImm20(u64 insn) {
         BitField<20, 19, u64> value;
         BitField<56, 1, u64> is_negative;
     } const imm{insn};
-    const s32 positive_value{static_cast<s32>(imm.value)};
-    const s32 value{imm.is_negative != 0 ? -positive_value : positive_value};
-    return ir.Imm32(value);
+    if (imm.is_negative != 0) {
+        const s64 raw{static_cast<s64>(imm.value)};
+        return ir.Imm32(static_cast<s32>(-(1LL << 19) + raw));
+    } else {
+        return ir.Imm32(static_cast<u32>(imm.value));
+    }
 }
 
 IR::F32 TranslatorVisitor::GetFloatImm20(u64 insn) {
@@ -94,9 +97,9 @@ IR::F32 TranslatorVisitor::GetFloatImm20(u64 insn) {
         BitField<20, 19, u64> value;
         BitField<56, 1, u64> is_negative;
     } const imm{insn};
-    const f32 positive_value{Common::BitCast<f32>(static_cast<u32>(imm.value) << 12)};
-    const f32 value{imm.is_negative != 0 ? -positive_value : positive_value};
-    return ir.Imm32(value);
+    const u32 sign_bit{imm.is_negative != 0 ? (1ULL << 31) : 0};
+    const u32 value{static_cast<u32>(imm.value) << 12};
+    return ir.Imm32(Common::BitCast<f32>(value | sign_bit));
 }
 
 IR::U32 TranslatorVisitor::GetImm32(u64 insn) {

+ 3 - 0
src/shader_recompiler/profile.h

@@ -15,6 +15,9 @@ struct Profile {
     bool support_fp32_denorm_preserve{};
     bool support_fp16_denorm_flush{};
     bool support_fp32_denorm_flush{};
+
+    // FClamp is broken and OpFMax + OpFMin should be used instead
+    bool has_broken_spirv_clamp{};
 };
 
 } // namespace Shader

+ 1 - 0
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp

@@ -189,6 +189,7 @@ ComputePipeline PipelineCache::CreateComputePipeline(ShaderInfo* shader_info) {
         .support_fp32_denorm_preserve = float_control.shaderDenormPreserveFloat32 != VK_FALSE,
         .support_fp16_denorm_flush = float_control.shaderDenormFlushToZeroFloat16 != VK_FALSE,
         .support_fp32_denorm_flush = float_control.shaderDenormFlushToZeroFloat32 != VK_FALSE,
+        .has_broken_spirv_clamp = true, // TODO: is_intel
     };
     const auto [info, code]{Shader::RecompileSPIRV(profile, env, qmd.program_start)};
     /*