mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-10 13:48:40 +00:00
shader_recompiler: Implement linear interpolation support (#3055)
This commit is contained in:
@@ -605,11 +605,12 @@ public:
|
||||
Info& info_, const RuntimeInfo& runtime_info_, const Profile& profile_)
|
||||
: stmt_pool{stmt_pool_}, inst_pool{inst_pool_}, block_pool{block_pool_},
|
||||
syntax_list{syntax_list_}, inst_list{inst_list_}, info{info_},
|
||||
runtime_info{runtime_info_}, profile{profile_} {
|
||||
runtime_info{runtime_info_}, profile{profile_},
|
||||
translator{info_, runtime_info_, profile_} {
|
||||
Visit(root_stmt, nullptr, nullptr);
|
||||
|
||||
IR::Block& first_block{*syntax_list.front().data.block};
|
||||
Translator{&first_block, info, runtime_info, profile}.EmitPrologue();
|
||||
IR::Block* first_block = syntax_list.front().data.block;
|
||||
translator.EmitPrologue(first_block);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -637,8 +638,8 @@ private:
|
||||
current_block->has_multiple_predecessors = stmt.block->num_predecessors > 1;
|
||||
const u32 start = stmt.block->begin_index;
|
||||
const u32 size = stmt.block->end_index - start + 1;
|
||||
Translate(current_block, stmt.block->begin, inst_list.subspan(start, size),
|
||||
info, runtime_info, profile);
|
||||
translator.Translate(current_block, stmt.block->begin,
|
||||
inst_list.subspan(start, size));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -820,6 +821,7 @@ private:
|
||||
Info& info;
|
||||
const RuntimeInfo& runtime_info;
|
||||
const Profile& profile;
|
||||
Translator translator;
|
||||
};
|
||||
} // Anonymous namespace
|
||||
|
||||
|
||||
@@ -21,16 +21,60 @@
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
static u32 next_vgpr_num;
|
||||
static std::unordered_map<u32, IR::VectorReg> vgpr_map;
|
||||
|
||||
Translator::Translator(IR::Block* block_, Info& info_, const RuntimeInfo& runtime_info_,
|
||||
const Profile& profile_)
|
||||
: ir{*block_, block_->begin()}, info{info_}, runtime_info{runtime_info_}, profile{profile_} {
|
||||
next_vgpr_num = vgpr_map.empty() ? runtime_info.num_allocated_vgprs : next_vgpr_num;
|
||||
Translator::Translator(Info& info_, const RuntimeInfo& runtime_info_, const Profile& profile_)
|
||||
: info{info_}, runtime_info{runtime_info_}, profile{profile_},
|
||||
next_vgpr_num{runtime_info.num_allocated_vgprs} {
|
||||
if (info.l_stage == LogicalStage::Fragment) {
|
||||
dst_frag_vreg = GatherInterpQualifiers();
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::EmitPrologue() {
|
||||
IR::VectorReg Translator::GatherInterpQualifiers() {
|
||||
u32 dst_vreg{};
|
||||
if (runtime_info.fs_info.addr_flags.persp_sample_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveSample; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveSample; // J
|
||||
info.has_perspective_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_center_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCenter; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCenter; // J
|
||||
info.has_perspective_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_centroid_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCentroid; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::PerspectiveCentroid; // J
|
||||
info.has_perspective_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_pull_model_ena) {
|
||||
++dst_vreg; // I/W
|
||||
++dst_vreg; // J/W
|
||||
++dst_vreg; // 1/W
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_sample_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearSample; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearSample; // J
|
||||
info.has_linear_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_center_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCenter; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCenter; // J
|
||||
info.has_linear_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_centroid_ena) {
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCentroid; // I
|
||||
vgpr_to_interp[dst_vreg++] = IR::Interpolation::LinearCentroid; // J
|
||||
info.has_linear_interp = true;
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.line_stipple_tex_ena) {
|
||||
++dst_vreg;
|
||||
}
|
||||
return IR::VectorReg(dst_vreg);
|
||||
}
|
||||
|
||||
void Translator::EmitPrologue(IR::Block* first_block) {
|
||||
ir = IR::IREmitter(*first_block, first_block->begin());
|
||||
|
||||
ir.Prologue();
|
||||
ir.SetExec(ir.Imm1(true));
|
||||
|
||||
@@ -60,39 +104,7 @@ void Translator::EmitPrologue() {
|
||||
}
|
||||
break;
|
||||
case LogicalStage::Fragment:
|
||||
dst_vreg = IR::VectorReg::V0;
|
||||
if (runtime_info.fs_info.addr_flags.persp_sample_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_center_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_centroid_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.persp_pull_model_ena) {
|
||||
++dst_vreg; // I/W
|
||||
++dst_vreg; // J/W
|
||||
++dst_vreg; // 1/W
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_sample_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_center_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.linear_centroid_ena) {
|
||||
++dst_vreg; // I
|
||||
++dst_vreg; // J
|
||||
}
|
||||
if (runtime_info.fs_info.addr_flags.line_stipple_tex_ena) {
|
||||
++dst_vreg;
|
||||
}
|
||||
dst_vreg = dst_frag_vreg;
|
||||
if (runtime_info.fs_info.addr_flags.pos_x_float_ena) {
|
||||
if (runtime_info.fs_info.en_flags.pos_x_float_ena) {
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttribute(IR::Attribute::FragCoord, 0));
|
||||
@@ -543,6 +555,26 @@ void Translator::LogMissingOpcode(const GcnInst& inst) {
|
||||
info.translation_failed = true;
|
||||
}
|
||||
|
||||
void Translator::Translate(IR::Block* block, u32 pc, std::span<const GcnInst> inst_list) {
|
||||
if (inst_list.empty()) {
|
||||
return;
|
||||
}
|
||||
ir = IR::IREmitter{*block, block->begin()};
|
||||
for (const auto& inst : inst_list) {
|
||||
pc += inst.length;
|
||||
|
||||
// Special case for emitting fetch shader.
|
||||
if (inst.opcode == Opcode::S_SWAPPC_B64) {
|
||||
ASSERT(info.stage == Stage::Vertex || info.stage == Stage::Export ||
|
||||
info.stage == Stage::Local);
|
||||
EmitFetch(inst);
|
||||
continue;
|
||||
}
|
||||
|
||||
TranslateInstruction(inst, pc);
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::TranslateInstruction(const GcnInst& inst, const u32 pc) {
|
||||
// Emit instructions for each category.
|
||||
switch (inst.category) {
|
||||
@@ -577,25 +609,4 @@ void Translator::TranslateInstruction(const GcnInst& inst, const u32 pc) {
|
||||
}
|
||||
}
|
||||
|
||||
void Translate(IR::Block* block, u32 pc, std::span<const GcnInst> inst_list, Info& info,
|
||||
const RuntimeInfo& runtime_info, const Profile& profile) {
|
||||
if (inst_list.empty()) {
|
||||
return;
|
||||
}
|
||||
Translator translator{block, info, runtime_info, profile};
|
||||
for (const auto& inst : inst_list) {
|
||||
pc += inst.length;
|
||||
|
||||
// Special case for emitting fetch shader.
|
||||
if (inst.opcode == Opcode::S_SWAPPC_B64) {
|
||||
ASSERT(info.stage == Stage::Vertex || info.stage == Stage::Export ||
|
||||
info.stage == Stage::Local);
|
||||
translator.EmitFetch(inst);
|
||||
continue;
|
||||
}
|
||||
|
||||
translator.TranslateInstruction(inst, pc);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
||||
|
||||
@@ -53,15 +53,17 @@ enum class NegateMode : u32 {
|
||||
Result,
|
||||
};
|
||||
|
||||
static constexpr size_t MaxInterpVgpr = 16;
|
||||
|
||||
class Translator {
|
||||
public:
|
||||
explicit Translator(IR::Block* block_, Info& info, const RuntimeInfo& runtime_info,
|
||||
const Profile& profile);
|
||||
explicit Translator(Info& info, const RuntimeInfo& runtime_info, const Profile& profile);
|
||||
|
||||
void Translate(IR::Block* block, u32 pc, std::span<const GcnInst> inst_list);
|
||||
void TranslateInstruction(const GcnInst& inst, u32 pc);
|
||||
|
||||
// Instruction categories
|
||||
void EmitPrologue();
|
||||
void EmitPrologue(IR::Block* first_block);
|
||||
void EmitFetch(const GcnInst& inst);
|
||||
void EmitExport(const GcnInst& inst);
|
||||
void EmitFlowControl(u32 pc, const GcnInst& inst);
|
||||
@@ -326,16 +328,18 @@ private:
|
||||
void LogMissingOpcode(const GcnInst& inst);
|
||||
|
||||
IR::VectorReg GetScratchVgpr(u32 offset);
|
||||
IR::VectorReg GatherInterpQualifiers();
|
||||
|
||||
private:
|
||||
IR::IREmitter ir;
|
||||
Info& info;
|
||||
const RuntimeInfo& runtime_info;
|
||||
const Profile& profile;
|
||||
u32 next_vgpr_num;
|
||||
std::unordered_map<u32, IR::VectorReg> vgpr_map;
|
||||
std::array<IR::Interpolation, MaxInterpVgpr> vgpr_to_interp{};
|
||||
IR::VectorReg dst_frag_vreg{};
|
||||
bool opcode_missing = false;
|
||||
};
|
||||
|
||||
void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_list, Info& info,
|
||||
const RuntimeInfo& runtime_info, const Profile& profile);
|
||||
|
||||
} // namespace Shader::Gcn
|
||||
|
||||
@@ -22,13 +22,14 @@ void Translator::EmitVectorInterpolation(const GcnInst& inst) {
|
||||
// VINTRP
|
||||
|
||||
void Translator::V_INTERP_P2_F32(const GcnInst& inst) {
|
||||
auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr);
|
||||
const auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr);
|
||||
info.interp_qualifiers[attr.param_index] = vgpr_to_interp[inst.src[0].code];
|
||||
const IR::Attribute attrib{IR::Attribute::Param0 + attr.param_index};
|
||||
SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan));
|
||||
}
|
||||
|
||||
void Translator::V_INTERP_MOV_F32(const GcnInst& inst) {
|
||||
auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr);
|
||||
const auto& attr = runtime_info.fs_info.inputs.at(inst.control.vintrp.attr);
|
||||
const IR::Attribute attrib{IR::Attribute::Param0 + attr.param_index};
|
||||
SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user