recompiler: added support for discard on export with masked EXEC
This commit is contained in:
parent
1b94f07a6a
commit
f041276b04
|
@ -45,6 +45,7 @@ void EmitSetVccHi(EmitContext& ctx);
|
||||||
void EmitPrologue(EmitContext& ctx);
|
void EmitPrologue(EmitContext& ctx);
|
||||||
void EmitEpilogue(EmitContext& ctx);
|
void EmitEpilogue(EmitContext& ctx);
|
||||||
void EmitDiscard(EmitContext& ctx);
|
void EmitDiscard(EmitContext& ctx);
|
||||||
|
void EmitDiscardCond(EmitContext& ctx, Id condition);
|
||||||
void EmitBarrier(EmitContext& ctx);
|
void EmitBarrier(EmitContext& ctx);
|
||||||
void EmitWorkgroupMemoryBarrier(EmitContext& ctx);
|
void EmitWorkgroupMemoryBarrier(EmitContext& ctx);
|
||||||
void EmitDeviceMemoryBarrier(EmitContext& ctx);
|
void EmitDeviceMemoryBarrier(EmitContext& ctx);
|
||||||
|
|
|
@ -14,6 +14,17 @@ void EmitDiscard(EmitContext& ctx) {
|
||||||
ctx.OpDemoteToHelperInvocationEXT();
|
ctx.OpDemoteToHelperInvocationEXT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitDiscardCond(EmitContext& ctx, Id condition) {
|
||||||
|
const Id kill_label{ctx.OpLabel()};
|
||||||
|
const Id merge_label{ctx.OpLabel()};
|
||||||
|
ctx.OpSelectionMerge(merge_label, spv::SelectionControlMask::MaskNone);
|
||||||
|
ctx.OpBranchConditional(condition, kill_label, merge_label);
|
||||||
|
ctx.AddLabel(kill_label);
|
||||||
|
ctx.OpDemoteToHelperInvocationEXT();
|
||||||
|
ctx.OpBranch(merge_label);
|
||||||
|
ctx.AddLabel(merge_label);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
|
void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
|
||||||
throw NotImplementedException("Geometry streams");
|
throw NotImplementedException("Geometry streams");
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ void CFG::EmitBlocks() {
|
||||||
|
|
||||||
void CFG::LinkBlocks() {
|
void CFG::LinkBlocks() {
|
||||||
const auto get_block = [this](u32 address) {
|
const auto get_block = [this](u32 address) {
|
||||||
const auto it = blocks.find(address, Compare{});
|
auto it = blocks.find(address, Compare{});
|
||||||
ASSERT_MSG(it != blocks.end() && it->begin == address);
|
ASSERT_MSG(it != blocks.end() && it->begin == address);
|
||||||
return &*it;
|
return &*it;
|
||||||
};
|
};
|
||||||
|
@ -131,7 +131,10 @@ void CFG::LinkBlocks() {
|
||||||
// If the block doesn't end with a branch we simply
|
// If the block doesn't end with a branch we simply
|
||||||
// need to link with the next block.
|
// need to link with the next block.
|
||||||
if (!end_inst.IsTerminateInstruction()) {
|
if (!end_inst.IsTerminateInstruction()) {
|
||||||
block.branch_true = get_block(block.end);
|
auto* next_block = get_block(block.end);
|
||||||
|
++next_block->num_predecessors;
|
||||||
|
|
||||||
|
block.branch_true = next_block;
|
||||||
block.end_class = EndClass::Branch;
|
block.end_class = EndClass::Branch;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -141,11 +144,20 @@ void CFG::LinkBlocks() {
|
||||||
const u32 branch_pc = block.end - end_inst.length;
|
const u32 branch_pc = block.end - end_inst.length;
|
||||||
const u32 target_pc = end_inst.BranchTarget(branch_pc);
|
const u32 target_pc = end_inst.BranchTarget(branch_pc);
|
||||||
if (end_inst.IsUnconditionalBranch()) {
|
if (end_inst.IsUnconditionalBranch()) {
|
||||||
block.branch_true = get_block(target_pc);
|
auto* target_block = get_block(target_pc);
|
||||||
|
++target_block->num_predecessors;
|
||||||
|
|
||||||
|
block.branch_true = target_block;
|
||||||
block.end_class = EndClass::Branch;
|
block.end_class = EndClass::Branch;
|
||||||
} else if (end_inst.IsConditionalBranch()) {
|
} else if (end_inst.IsConditionalBranch()) {
|
||||||
block.branch_true = get_block(target_pc);
|
auto* target_block = get_block(target_pc);
|
||||||
block.branch_false = get_block(block.end);
|
++target_block->num_predecessors;
|
||||||
|
|
||||||
|
auto* end_block = get_block(block.end);
|
||||||
|
++end_block->num_predecessors;
|
||||||
|
|
||||||
|
block.branch_true = target_block;
|
||||||
|
block.branch_false = end_block;
|
||||||
block.end_class = EndClass::Branch;
|
block.end_class = EndClass::Branch;
|
||||||
} else if (end_inst.opcode == Opcode::S_ENDPGM) {
|
} else if (end_inst.opcode == Opcode::S_ENDPGM) {
|
||||||
const auto& prev_inst = inst_list[block.end_index - 1];
|
const auto& prev_inst = inst_list[block.end_index - 1];
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct Block : Hook {
|
||||||
u32 end;
|
u32 end;
|
||||||
u32 begin_index;
|
u32 begin_index;
|
||||||
u32 end_index;
|
u32 end_index;
|
||||||
|
u32 num_predecessors{};
|
||||||
IR::Condition cond{};
|
IR::Condition cond{};
|
||||||
GcnInst end_inst{};
|
GcnInst end_inst{};
|
||||||
EndClass end_class{};
|
EndClass end_class{};
|
||||||
|
|
|
@ -631,6 +631,7 @@ private:
|
||||||
case StatementType::Code: {
|
case StatementType::Code: {
|
||||||
ensure_block();
|
ensure_block();
|
||||||
if (!stmt.block->is_dummy) {
|
if (!stmt.block->is_dummy) {
|
||||||
|
current_block->has_multiple_predecessors = stmt.block->num_predecessors > 1;
|
||||||
const u32 start = stmt.block->begin_index;
|
const u32 start = stmt.block->begin_index;
|
||||||
const u32 size = stmt.block->end_index - start + 1;
|
const u32 size = stmt.block->end_index - start + 1;
|
||||||
Translate(current_block, stmt.block->begin, inst_list.subspan(start, size),
|
Translate(current_block, stmt.block->begin, inst_list.subspan(start, size),
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
#include "shader_recompiler/frontend/translate/translate.h"
|
#include "shader_recompiler/frontend/translate/translate.h"
|
||||||
|
|
||||||
namespace Shader::Gcn {
|
namespace Shader::Gcn {
|
||||||
|
|
||||||
void Translator::EXP(const GcnInst& inst) {
|
void Translator::EXP(const GcnInst& inst) {
|
||||||
|
if (ir.block->has_multiple_predecessors) {
|
||||||
|
LOG_WARNING(Render_Recompiler, "An ambiguous export appeared in translation");
|
||||||
|
ir.Discard(ir.LogicalNot(ir.GetExec()));
|
||||||
|
}
|
||||||
|
|
||||||
const auto& exp = inst.control.exp;
|
const auto& exp = inst.control.exp;
|
||||||
const IR::Attribute attrib{exp.target};
|
const IR::Attribute attrib{exp.target};
|
||||||
const std::array vsrc = {
|
const std::array vsrc = {
|
||||||
|
|
|
@ -149,6 +149,8 @@ public:
|
||||||
std::array<Value, NumScalarRegs> ssa_sreg_values;
|
std::array<Value, NumScalarRegs> ssa_sreg_values;
|
||||||
std::array<Value, NumVectorRegs> ssa_vreg_values;
|
std::array<Value, NumVectorRegs> ssa_vreg_values;
|
||||||
|
|
||||||
|
bool has_multiple_predecessors{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Memory pool for instruction list
|
/// Memory pool for instruction list
|
||||||
ObjectPool<Inst>* inst_pool;
|
ObjectPool<Inst>* inst_pool;
|
||||||
|
|
|
@ -115,6 +115,10 @@ void IREmitter::Discard() {
|
||||||
Inst(Opcode::Discard);
|
Inst(Opcode::Discard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IREmitter::Discard(const U1& cond) {
|
||||||
|
Inst(Opcode::DiscardCond, cond);
|
||||||
|
}
|
||||||
|
|
||||||
void IREmitter::Barrier() {
|
void IREmitter::Barrier() {
|
||||||
Inst(Opcode::Barrier);
|
Inst(Opcode::Barrier);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
void Prologue();
|
void Prologue();
|
||||||
void Epilogue();
|
void Epilogue();
|
||||||
void Discard();
|
void Discard();
|
||||||
|
void Discard(const U1& cond);
|
||||||
|
|
||||||
void Barrier();
|
void Barrier();
|
||||||
void WorkgroupMemoryBarrier();
|
void WorkgroupMemoryBarrier();
|
||||||
|
|
|
@ -49,6 +49,7 @@ bool Inst::MayHaveSideEffects() const noexcept {
|
||||||
case Opcode::Prologue:
|
case Opcode::Prologue:
|
||||||
case Opcode::Epilogue:
|
case Opcode::Epilogue:
|
||||||
case Opcode::Discard:
|
case Opcode::Discard:
|
||||||
|
case Opcode::DiscardCond:
|
||||||
case Opcode::SetAttribute:
|
case Opcode::SetAttribute:
|
||||||
case Opcode::StoreBufferF32:
|
case Opcode::StoreBufferF32:
|
||||||
case Opcode::StoreBufferF32x2:
|
case Opcode::StoreBufferF32x2:
|
||||||
|
|
|
@ -13,6 +13,7 @@ OPCODE(PhiMove, Void, Opaq
|
||||||
OPCODE(Prologue, Void, )
|
OPCODE(Prologue, Void, )
|
||||||
OPCODE(Epilogue, Void, )
|
OPCODE(Epilogue, Void, )
|
||||||
OPCODE(Discard, Void, )
|
OPCODE(Discard, Void, )
|
||||||
|
OPCODE(DiscardCond, Void, U1, )
|
||||||
|
|
||||||
// Constant memory operations
|
// Constant memory operations
|
||||||
OPCODE(ReadConst, U32, U32x2, U32, )
|
OPCODE(ReadConst, U32, U32x2, U32, )
|
||||||
|
|
|
@ -37,6 +37,7 @@ void Visit(Info& info, IR::Inst& inst) {
|
||||||
info.uses_group_quad = true;
|
info.uses_group_quad = true;
|
||||||
break;
|
break;
|
||||||
case IR::Opcode::Discard:
|
case IR::Opcode::Discard:
|
||||||
|
case IR::Opcode::DiscardCond:
|
||||||
info.has_discard = true;
|
info.has_discard = true;
|
||||||
break;
|
break;
|
||||||
case IR::Opcode::ImageGather:
|
case IR::Opcode::ImageGather:
|
||||||
|
|
Loading…
Reference in New Issue