mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-17 17:05:02 +00:00
video: Import new shader recompiler + display a triangle (#142)
This commit is contained in:
parent
8cf64a33b2
commit
8730968385
103 changed files with 17793 additions and 729 deletions
44
src/shader_recompiler/frontend/translate/data_share.cpp
Normal file
44
src/shader_recompiler/frontend/translate/data_share.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::DS_READ(int bit_size, bool is_signed, bool is_pair, const GcnInst& inst) {
|
||||
const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
if (is_pair) {
|
||||
const IR::U32 addr0 = ir.IAdd(addr, ir.Imm32(u32(inst.control.ds.offset0)));
|
||||
ir.SetVectorReg(dst_reg, ir.ReadShared(32, is_signed, addr0));
|
||||
const IR::U32 addr1 = ir.IAdd(addr, ir.Imm32(u32(inst.control.ds.offset1)));
|
||||
ir.SetVectorReg(dst_reg + 1, ir.ReadShared(32, is_signed, addr1));
|
||||
} else if (bit_size == 64) {
|
||||
const IR::Value data = ir.UnpackUint2x32(ir.ReadShared(bit_size, is_signed, addr));
|
||||
ir.SetVectorReg(dst_reg, IR::U32{ir.CompositeExtract(data, 0)});
|
||||
ir.SetVectorReg(dst_reg + 1, IR::U32{ir.CompositeExtract(data, 1)});
|
||||
} else {
|
||||
const IR::U32 data = ir.ReadShared(bit_size, is_signed, addr);
|
||||
ir.SetVectorReg(dst_reg, data);
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::DS_WRITE(int bit_size, bool is_signed, bool is_pair, const GcnInst& inst) {
|
||||
const IR::U32 addr{ir.GetVectorReg(IR::VectorReg(inst.src[0].code))};
|
||||
const IR::VectorReg data0{inst.src[1].code};
|
||||
const IR::VectorReg data1{inst.src[2].code};
|
||||
if (is_pair) {
|
||||
const IR::U32 addr0 = ir.IAdd(addr, ir.Imm32(u32(inst.control.ds.offset0)));
|
||||
ir.WriteShared(32, ir.GetVectorReg(data0), addr0);
|
||||
const IR::U32 addr1 = ir.IAdd(addr, ir.Imm32(u32(inst.control.ds.offset1)));
|
||||
ir.WriteShared(32, ir.GetVectorReg(data1), addr1);
|
||||
} else if (bit_size == 64) {
|
||||
const IR::U64 data = ir.PackUint2x32(
|
||||
ir.CompositeConstruct(ir.GetVectorReg(data0), ir.GetVectorReg(data0 + 1)));
|
||||
ir.WriteShared(bit_size, data, addr);
|
||||
} else {
|
||||
ir.WriteShared(bit_size, ir.GetVectorReg(data0), addr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
49
src/shader_recompiler/frontend/translate/export.cpp
Normal file
49
src/shader_recompiler/frontend/translate/export.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::EXP(const GcnInst& inst) {
|
||||
const auto& exp = inst.control.exp;
|
||||
const IR::Attribute attrib{exp.target};
|
||||
const std::array vsrc = {
|
||||
IR::VectorReg(inst.src[0].code),
|
||||
IR::VectorReg(inst.src[1].code),
|
||||
IR::VectorReg(inst.src[2].code),
|
||||
IR::VectorReg(inst.src[3].code),
|
||||
};
|
||||
|
||||
const auto unpack = [&](u32 idx) {
|
||||
const IR::Value value = ir.UnpackHalf2x16(ir.GetVectorReg(vsrc[idx]));
|
||||
const IR::F32 r = IR::F32{ir.CompositeExtract(value, 0)};
|
||||
const IR::F32 g = IR::F32{ir.CompositeExtract(value, 1)};
|
||||
ir.SetAttribute(attrib, r, idx * 2);
|
||||
ir.SetAttribute(attrib, g, idx * 2 + 1);
|
||||
};
|
||||
|
||||
// Components are float16 packed into a VGPR
|
||||
if (exp.compr) {
|
||||
// Export R, G
|
||||
if (exp.en & 1) {
|
||||
unpack(0);
|
||||
}
|
||||
// Export B, A
|
||||
if ((exp.en >> 2) & 1) {
|
||||
unpack(1);
|
||||
}
|
||||
} else {
|
||||
// Components are float32 into separate VGPRS
|
||||
u32 mask = exp.en;
|
||||
for (u32 i = 0; i < 4; i++, mask >>= 1) {
|
||||
if ((mask & 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
const IR::F32 comp = ir.GetVectorReg<IR::F32>(vsrc[i]);
|
||||
ir.SetAttribute(attrib, comp, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
0
src/shader_recompiler/frontend/translate/flat_memory.cpp
Normal file
0
src/shader_recompiler/frontend/translate/flat_memory.cpp
Normal file
38
src/shader_recompiler/frontend/translate/scalar_alu.cpp
Normal file
38
src/shader_recompiler/frontend/translate/scalar_alu.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::S_MOV(const GcnInst& inst) {
|
||||
SetDst(inst.dst[0], GetSrc(inst.src[0]));
|
||||
}
|
||||
|
||||
void Translator::S_MUL_I32(const GcnInst& inst) {
|
||||
SetDst(inst.dst[0], ir.IMul(GetSrc(inst.src[0]), GetSrc(inst.src[1])));
|
||||
}
|
||||
|
||||
void Translator::S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst) {
|
||||
const IR::U32 lhs = GetSrc(inst.src[0]);
|
||||
const IR::U32 rhs = GetSrc(inst.src[1]);
|
||||
const IR::U1 result = [&] {
|
||||
switch (cond) {
|
||||
case ConditionOp::EQ:
|
||||
return ir.IEqual(lhs, rhs);
|
||||
case ConditionOp::LG:
|
||||
return ir.INotEqual(lhs, rhs);
|
||||
case ConditionOp::GT:
|
||||
return ir.IGreaterThan(lhs, rhs, is_signed);
|
||||
case ConditionOp::GE:
|
||||
return ir.IGreaterThanEqual(lhs, rhs, is_signed);
|
||||
case ConditionOp::LT:
|
||||
return ir.ILessThan(lhs, rhs, is_signed);
|
||||
case ConditionOp::LE:
|
||||
return ir.ILessThanEqual(lhs, rhs, is_signed);
|
||||
}
|
||||
}();
|
||||
// ir.SetScc(result);
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
45
src/shader_recompiler/frontend/translate/scalar_memory.cpp
Normal file
45
src/shader_recompiler/frontend/translate/scalar_memory.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Load(IR::IREmitter& ir, int num_dwords, const IR::Value& handle, IR::ScalarReg dst_reg,
|
||||
const IR::U32U64& address) {
|
||||
for (u32 i = 0; i < num_dwords; i++) {
|
||||
const IR::U32 value = handle.IsEmpty() ? ir.ReadConst(address, ir.Imm32(i))
|
||||
: ir.ReadConstBuffer(handle, address, ir.Imm32(i));
|
||||
ir.SetScalarReg(dst_reg++, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::S_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
||||
const auto& smrd = inst.control.smrd;
|
||||
const IR::ScalarReg sbase = IR::ScalarReg(inst.src[0].code * 2);
|
||||
const IR::U32 offset =
|
||||
smrd.imm ? ir.Imm32(smrd.offset * 4)
|
||||
: IR::U32{ir.ShiftLeftLogical(ir.GetScalarReg(IR::ScalarReg(smrd.offset)),
|
||||
ir.Imm32(2))};
|
||||
const IR::U64 base =
|
||||
ir.PackUint2x32(ir.CompositeConstruct(ir.GetScalarReg(sbase), ir.GetScalarReg(sbase + 1)));
|
||||
const IR::U64 address = ir.IAdd(base, offset);
|
||||
const IR::ScalarReg dst_reg{inst.dst[0].code};
|
||||
Load(ir, num_dwords, {}, dst_reg, address);
|
||||
}
|
||||
|
||||
void Translator::S_BUFFER_LOAD_DWORD(int num_dwords, const GcnInst& inst) {
|
||||
const auto& smrd = inst.control.smrd;
|
||||
const IR::ScalarReg sbase = IR::ScalarReg(inst.src[0].code * 2);
|
||||
const IR::U32 offset =
|
||||
smrd.imm ? ir.Imm32(smrd.offset * 4)
|
||||
: IR::U32{ir.ShiftLeftLogical(ir.GetScalarReg(IR::ScalarReg(smrd.offset)),
|
||||
ir.Imm32(2))};
|
||||
const IR::Value vsharp =
|
||||
ir.CompositeConstruct(ir.GetScalarReg(sbase), ir.GetScalarReg(sbase + 1),
|
||||
ir.GetScalarReg(sbase + 2), ir.GetScalarReg(sbase + 3));
|
||||
const IR::ScalarReg dst_reg{inst.dst[0].code};
|
||||
Load(ir, num_dwords, vsharp, dst_reg, offset);
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
152
src/shader_recompiler/frontend/translate/translate.cpp
Normal file
152
src/shader_recompiler/frontend/translate/translate.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
Translator::Translator(IR::Block* block_, Stage stage) : block{block_}, ir{*block} {
|
||||
IR::VectorReg dst_vreg = IR::VectorReg::V0;
|
||||
switch (stage) {
|
||||
case Stage::Vertex:
|
||||
// https://github.com/chaotic-cx/mesa-mirror/blob/72326e15/src/amd/vulkan/radv_shader_args.c#L146C1-L146C23
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttributeU32(IR::Attribute::VertexId));
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttributeU32(IR::Attribute::InstanceId));
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttributeU32(IR::Attribute::PrimitiveId));
|
||||
break;
|
||||
case Stage::Fragment:
|
||||
// https://github.com/chaotic-cx/mesa-mirror/blob/72326e15/src/amd/vulkan/radv_shader_args.c#L258
|
||||
// The first two VGPRs are used for i/j barycentric coordinates. In the vast majority of
|
||||
// cases it will be only those two, but if shader is using both e.g linear and perspective
|
||||
// inputs it can be more For now assume that this isn't the case.
|
||||
dst_vreg = IR::VectorReg::V2;
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttribute(IR::Attribute::FragCoord, i));
|
||||
}
|
||||
ir.SetVectorReg(dst_vreg++, ir.GetAttributeU32(IR::Attribute::IsFrontFace));
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException("Unknown shader stage");
|
||||
}
|
||||
|
||||
// Initialize user data.
|
||||
IR::ScalarReg dst_sreg = IR::ScalarReg::S0;
|
||||
for (u32 i = 0; i < 16; i++) {
|
||||
ir.SetScalarReg(dst_sreg++, ir.Imm32(0U));
|
||||
}
|
||||
}
|
||||
|
||||
IR::U32F32 Translator::GetSrc(const InstOperand& operand, bool force_flt) {
|
||||
switch (operand.field) {
|
||||
case OperandField::ScalarGPR:
|
||||
if (operand.type == ScalarType::Float32 || force_flt) {
|
||||
return ir.GetScalarReg<IR::F32>(IR::ScalarReg(operand.code));
|
||||
} else {
|
||||
return ir.GetScalarReg<IR::U32>(IR::ScalarReg(operand.code));
|
||||
}
|
||||
case OperandField::VectorGPR:
|
||||
if (operand.type == ScalarType::Float32 || force_flt) {
|
||||
return ir.GetVectorReg<IR::F32>(IR::VectorReg(operand.code));
|
||||
} else {
|
||||
return ir.GetVectorReg<IR::U32>(IR::VectorReg(operand.code));
|
||||
}
|
||||
case OperandField::ConstZero:
|
||||
if (force_flt) {
|
||||
return ir.Imm32(0.f);
|
||||
} else {
|
||||
return ir.Imm32(0U);
|
||||
}
|
||||
case OperandField::SignedConstIntPos:
|
||||
ASSERT(!force_flt);
|
||||
return ir.Imm32(operand.code - SignedConstIntPosMin + 1);
|
||||
case OperandField::SignedConstIntNeg:
|
||||
ASSERT(!force_flt);
|
||||
return ir.Imm32(-s32(operand.code) + SignedConstIntNegMin - 1);
|
||||
case OperandField::LiteralConst:
|
||||
ASSERT(!force_flt);
|
||||
return ir.Imm32(operand.code);
|
||||
case OperandField::ConstFloatPos_1_0:
|
||||
return ir.Imm32(1.f);
|
||||
case OperandField::ConstFloatPos_0_5:
|
||||
return ir.Imm32(0.5f);
|
||||
case OperandField::ConstFloatNeg_0_5:
|
||||
return ir.Imm32(-0.5f);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::SetDst(const InstOperand& operand, const IR::U32F32& value) {
|
||||
switch (operand.field) {
|
||||
case OperandField::ScalarGPR:
|
||||
return ir.SetScalarReg(IR::ScalarReg(operand.code), value);
|
||||
case OperandField::VectorGPR:
|
||||
return ir.SetVectorReg(IR::VectorReg(operand.code), value);
|
||||
case OperandField::VccHi:
|
||||
case OperandField::M0:
|
||||
break; // Ignore for now
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Translate(IR::Block* block, Stage stage, std::span<const GcnInst> inst_list) {
|
||||
if (inst_list.empty()) {
|
||||
return;
|
||||
}
|
||||
Translator translator{block, stage};
|
||||
for (const auto& inst : inst_list) {
|
||||
switch (inst.opcode) {
|
||||
case Opcode::S_MOV_B32:
|
||||
translator.S_MOV(inst);
|
||||
break;
|
||||
case Opcode::S_MUL_I32:
|
||||
translator.S_MUL_I32(inst);
|
||||
break;
|
||||
case Opcode::V_MOV_B32:
|
||||
translator.V_MOV(inst);
|
||||
break;
|
||||
case Opcode::V_MAC_F32:
|
||||
translator.V_MAC_F32(inst);
|
||||
break;
|
||||
case Opcode::V_MUL_F32:
|
||||
translator.V_MUL_F32(inst);
|
||||
break;
|
||||
case Opcode::S_SWAPPC_B64:
|
||||
case Opcode::S_WAITCNT:
|
||||
break; // Ignore for now.
|
||||
case Opcode::S_BUFFER_LOAD_DWORDX16:
|
||||
translator.S_BUFFER_LOAD_DWORD(16, inst);
|
||||
break;
|
||||
case Opcode::EXP:
|
||||
translator.EXP(inst);
|
||||
break;
|
||||
case Opcode::V_INTERP_P2_F32:
|
||||
translator.V_INTERP_P2_F32(inst);
|
||||
break;
|
||||
case Opcode::V_CVT_PKRTZ_F16_F32:
|
||||
translator.V_CVT_PKRTZ_F16_F32(inst);
|
||||
break;
|
||||
case Opcode::IMAGE_SAMPLE:
|
||||
translator.IMAGE_SAMPLE(inst);
|
||||
break;
|
||||
case Opcode::V_CMP_EQ_U32:
|
||||
translator.V_CMP_EQ_U32(inst);
|
||||
break;
|
||||
case Opcode::V_CNDMASK_B32:
|
||||
translator.V_CNDMASK_B32(inst);
|
||||
break;
|
||||
case Opcode::S_MOV_B64:
|
||||
case Opcode::S_WQM_B64:
|
||||
case Opcode::V_INTERP_P1_F32:
|
||||
case Opcode::S_ENDPGM:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown opcode {}", u32(inst.opcode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
73
src/shader_recompiler/frontend/translate/translate.h
Normal file
73
src/shader_recompiler/frontend/translate/translate.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include "shader_recompiler/frontend/instruction.h"
|
||||
#include "shader_recompiler/ir/basic_block.h"
|
||||
#include "shader_recompiler/ir/ir_emitter.h"
|
||||
|
||||
namespace Shader {
|
||||
enum class Stage : u32;
|
||||
}
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
enum class ConditionOp : u32 {
|
||||
EQ,
|
||||
LG,
|
||||
GT,
|
||||
GE,
|
||||
LT,
|
||||
LE,
|
||||
};
|
||||
|
||||
class Translator {
|
||||
public:
|
||||
explicit Translator(IR::Block* block_, Stage stage);
|
||||
|
||||
// Scalar ALU
|
||||
void S_MOV(const GcnInst& inst);
|
||||
void S_MUL_I32(const GcnInst& inst);
|
||||
void S_CMP(ConditionOp cond, bool is_signed, const GcnInst& inst);
|
||||
|
||||
// Scalar Memory
|
||||
void S_LOAD_DWORD(int num_dwords, const GcnInst& inst);
|
||||
void S_BUFFER_LOAD_DWORD(int num_dwords, const GcnInst& inst);
|
||||
|
||||
// Vector ALU
|
||||
void V_MOV(const GcnInst& inst);
|
||||
void V_SAD(const GcnInst& inst);
|
||||
void V_MAC_F32(const GcnInst& inst);
|
||||
void V_CVT_PKRTZ_F16_F32(const GcnInst& inst);
|
||||
void V_MUL_F32(const GcnInst& inst);
|
||||
void V_CMP_EQ_U32(const GcnInst& inst);
|
||||
void V_CNDMASK_B32(const GcnInst& inst);
|
||||
|
||||
// Vector interpolation
|
||||
void V_INTERP_P2_F32(const GcnInst& inst);
|
||||
|
||||
// Data share
|
||||
void DS_READ(int bit_size, bool is_signed, bool is_pair, const GcnInst& inst);
|
||||
void DS_WRITE(int bit_size, bool is_signed, bool is_pair, const GcnInst& inst);
|
||||
|
||||
// MIMG
|
||||
void IMAGE_GET_RESINFO(const GcnInst& inst);
|
||||
void IMAGE_SAMPLE(const GcnInst& inst);
|
||||
|
||||
// Export
|
||||
void EXP(const GcnInst& inst);
|
||||
|
||||
private:
|
||||
IR::U32F32 GetSrc(const InstOperand& operand, bool flt_zero = false);
|
||||
void SetDst(const InstOperand& operand, const IR::U32F32& value);
|
||||
|
||||
private:
|
||||
IR::Block* block;
|
||||
IR::IREmitter ir;
|
||||
};
|
||||
|
||||
void Translate(IR::Block* block, Stage stage, std::span<const GcnInst> inst_list);
|
||||
|
||||
} // namespace Shader::Gcn
|
65
src/shader_recompiler/frontend/translate/vector_alu.cpp
Normal file
65
src/shader_recompiler/frontend/translate/vector_alu.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#pragma clang optimize off
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::V_MOV(const GcnInst& inst) {
|
||||
SetDst(inst.dst[0], GetSrc(inst.src[0]));
|
||||
}
|
||||
|
||||
void Translator::V_SAD(const GcnInst& inst) {
|
||||
const IR::U32 abs_diff = ir.IAbs(ir.ISub(GetSrc(inst.src[0]), GetSrc(inst.src[1])));
|
||||
SetDst(inst.dst[0], ir.IAdd(abs_diff, GetSrc(inst.src[2])));
|
||||
}
|
||||
|
||||
void Translator::V_MAC_F32(const GcnInst& inst) {
|
||||
SetDst(inst.dst[0], ir.FPFma(GetSrc(inst.src[0]), GetSrc(inst.src[1]), GetSrc(inst.dst[0])));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_PKRTZ_F16_F32(const GcnInst& inst) {
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
const IR::Value vec_f32 = ir.CompositeConstruct(ir.FPConvert(16, GetSrc(inst.src[0])),
|
||||
ir.FPConvert(16, GetSrc(inst.src[1])));
|
||||
ir.SetVectorReg(dst_reg, ir.PackFloat2x16(vec_f32));
|
||||
}
|
||||
|
||||
void Translator::V_MUL_F32(const GcnInst& inst) {
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, ir.FPMul(GetSrc(inst.src[0]), GetSrc(inst.src[1])));
|
||||
}
|
||||
|
||||
void Translator::V_CMP_EQ_U32(const GcnInst& inst) {
|
||||
const IR::U1 result = ir.IEqual(GetSrc(inst.src[0]), GetSrc(inst.src[1]));
|
||||
if (inst.dst[1].field == OperandField::VccLo) {
|
||||
return ir.SetVcc(result);
|
||||
} else if (inst.dst[1].field == OperandField::ScalarGPR) {
|
||||
const IR::ScalarReg dst_reg{inst.dst[1].code};
|
||||
return ir.SetScalarReg(dst_reg, IR::U32{ir.Select(result, ir.Imm32(1U), ir.Imm32(0U))});
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Translator::V_CNDMASK_B32(const GcnInst& inst) {
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
const IR::ScalarReg flag_reg{inst.src[2].code};
|
||||
const IR::U1 flag = inst.src[2].field == OperandField::ScalarGPR
|
||||
? ir.INotEqual(ir.GetScalarReg(flag_reg), ir.Imm32(0U))
|
||||
: ir.GetVcc();
|
||||
|
||||
// We can treat the instruction as integer most of the time, but when a source is
|
||||
// a floating point constant we will force the other as float for better readability
|
||||
// The other operand is also higly likely to be float as well.
|
||||
const auto is_float_const = [](OperandField field) {
|
||||
return field >= OperandField::ConstFloatPos_0_5 && field <= OperandField::ConstFloatNeg_4_0;
|
||||
};
|
||||
const bool has_flt_source =
|
||||
is_float_const(inst.src[0].field) || is_float_const(inst.src[1].field);
|
||||
const IR::U32F32 src0 = GetSrc(inst.src[0], has_flt_source);
|
||||
const IR::U32F32 src1 = GetSrc(inst.src[1], has_flt_source);
|
||||
const IR::Value result = ir.Select(flag, src1, src0);
|
||||
ir.SetVectorReg(dst_reg, IR::U32F32{result});
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
|
@ -0,0 +1,14 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::V_INTERP_P2_F32(const GcnInst& inst) {
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
const IR::Attribute attrib{IR::Attribute::Param0 + inst.control.vintrp.attr};
|
||||
ir.SetVectorReg(dst_reg, ir.GetAttribute(attrib, inst.control.vintrp.chan));
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
103
src/shader_recompiler/frontend/translate/vector_memory.cpp
Normal file
103
src/shader_recompiler/frontend/translate/vector_memory.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "shader_recompiler/frontend/translate/translate.h"
|
||||
|
||||
namespace Shader::Gcn {
|
||||
|
||||
void Translator::IMAGE_GET_RESINFO(const GcnInst& inst) {
|
||||
IR::VectorReg dst_reg{inst.src[1].code};
|
||||
const IR::ScalarReg tsharp_reg{inst.src[2].code};
|
||||
const auto flags = ImageResFlags(inst.control.mimg.dmask);
|
||||
const IR::U32 lod = ir.GetVectorReg(IR::VectorReg(inst.src[0].code));
|
||||
const IR::Value tsharp =
|
||||
ir.CompositeConstruct(ir.GetScalarReg(tsharp_reg), ir.GetScalarReg(tsharp_reg + 1),
|
||||
ir.GetScalarReg(tsharp_reg + 2), ir.GetScalarReg(tsharp_reg + 3));
|
||||
const IR::Value size = ir.ImageQueryDimension(tsharp, lod, ir.Imm1(false));
|
||||
|
||||
if (flags.test(ImageResComponent::Width)) {
|
||||
ir.SetVectorReg(dst_reg++, IR::U32{ir.CompositeExtract(size, 0)});
|
||||
}
|
||||
if (flags.test(ImageResComponent::Height)) {
|
||||
ir.SetVectorReg(dst_reg++, IR::U32{ir.CompositeExtract(size, 1)});
|
||||
}
|
||||
if (flags.test(ImageResComponent::Depth)) {
|
||||
ir.SetVectorReg(dst_reg++, IR::U32{ir.CompositeExtract(size, 2)});
|
||||
}
|
||||
if (flags.test(ImageResComponent::MipCount)) {
|
||||
ir.SetVectorReg(dst_reg++, IR::U32{ir.CompositeExtract(size, 3)});
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::IMAGE_SAMPLE(const GcnInst& inst) {
|
||||
const auto& mimg = inst.control.mimg;
|
||||
ASSERT(!mimg.da);
|
||||
|
||||
IR::VectorReg addr_reg{inst.src[0].code};
|
||||
IR::VectorReg dest_reg{inst.dst[0].code};
|
||||
const IR::ScalarReg tsharp_reg{inst.src[2].code * 4};
|
||||
const IR::ScalarReg sampler_reg{inst.src[3].code * 4};
|
||||
const auto flags = MimgModifierFlags(mimg.mod);
|
||||
|
||||
// Load first dword of T# and S#. We will use them as the handle that will guide resource
|
||||
// tracking pass where to read the sharps. This will later also get patched to the SPIRV texture
|
||||
// binding index.
|
||||
const IR::Value handle =
|
||||
ir.CompositeConstruct(ir.GetScalarReg(tsharp_reg), ir.GetScalarReg(sampler_reg));
|
||||
|
||||
// Load first address components as denoted in 8.2.4 VGPR Usage Sea Islands Series Instruction
|
||||
// Set Architecture
|
||||
const IR::Value offset =
|
||||
flags.test(MimgModifier::Offset) ? ir.GetVectorReg(addr_reg++) : IR::Value{};
|
||||
const IR::F32 bias =
|
||||
flags.test(MimgModifier::LodBias) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
||||
const IR::F32 dref =
|
||||
flags.test(MimgModifier::Pcf) ? ir.GetVectorReg<IR::F32>(addr_reg++) : IR::F32{};
|
||||
|
||||
// Derivatives are tricky because their number depends on the texture type which is located in
|
||||
// T#. We don't have access to T# though until resource tracking pass. For now assume no
|
||||
// derivatives are present, otherwise we don't know where coordinates are placed in the address
|
||||
// stream.
|
||||
ASSERT_MSG(!flags.test(MimgModifier::Derivative), "Derivative image instruction");
|
||||
|
||||
// Now we can load body components as noted in Table 8.9 Image Opcodes with Sampler
|
||||
// Since these are at most 4 dwords, we load them into a single uvec4 and place them
|
||||
// in coords field of the instruction. Then the resource tracking pass will patch the
|
||||
// IR instruction to fill in lod_clamp field. The vector can also be used
|
||||
// as coords directly as SPIR-V will ignore any extra parameters.
|
||||
const IR::Value body =
|
||||
ir.CompositeConstruct(ir.GetVectorReg(addr_reg++), ir.GetVectorReg(addr_reg++),
|
||||
ir.GetVectorReg(addr_reg++), ir.GetVectorReg(addr_reg++));
|
||||
|
||||
// Issue IR instruction, leaving unknown fields blank to patch later.
|
||||
const IR::Value texel = [&]() -> IR::Value {
|
||||
const IR::F32 lod = flags.test(MimgModifier::Level0) ? ir.Imm32(0.f) : IR::F32{};
|
||||
const bool explicit_lod = flags.any(MimgModifier::Level0, MimgModifier::Lod);
|
||||
if (!flags.test(MimgModifier::Pcf)) {
|
||||
if (explicit_lod) {
|
||||
return ir.ImageSampleExplicitLod(handle, body, lod, offset, {});
|
||||
} else {
|
||||
return ir.ImageSampleImplicitLod(handle, body, bias, offset, {}, {});
|
||||
}
|
||||
}
|
||||
if (explicit_lod) {
|
||||
return ir.ImageSampleDrefExplicitLod(handle, body, dref, lod, offset, {});
|
||||
}
|
||||
return ir.ImageSampleDrefImplicitLod(handle, body, dref, bias, offset, {}, {});
|
||||
}();
|
||||
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
if (((mimg.dmask >> i) & 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
IR::F32 value;
|
||||
if (flags.test(MimgModifier::Pcf)) {
|
||||
value = i < 3 ? IR::F32{texel} : ir.Imm32(1.0f);
|
||||
} else {
|
||||
value = IR::F32{ir.CompositeExtract(texel, i)};
|
||||
}
|
||||
ir.SetVectorReg(dest_reg++, value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Gcn
|
Loading…
Add table
Add a link
Reference in a new issue