[graphics] MERC (#1124)

* merc dma generation

* wip very early version of merc

* small fixes

* fix

* fix more merc bugs

* derp fixed min

* oops we did need something weird on max

* merc for everything

* program optimization 1

* more optimization

* windows

* windows 2

* clean up

* fix test

* BLERC
This commit is contained in:
water111
2022-02-03 22:45:41 -05:00
committed by GitHub
parent 3d7228ec77
commit 2342b6fb0f
41 changed files with 8811 additions and 111 deletions
+2 -3
View File
@@ -53,7 +53,7 @@ std::string VifCode::print() {
result = "FLUSHA";
break;
case Kind::MSCAL:
result = "MSCAL";
result = fmt::format("MSCAL 0x{:x}", immediate);
break;
case Kind::MSCNT:
result = "MSCNT";
@@ -109,10 +109,9 @@ std::string VifCode::print() {
default:
fmt::print("Unhandled vif code {}\n", (int)kind);
assert(false);
result = "???";
// assert(false);
assert(false);
break;
}
// TODO: the rest of the VIF code.
+42
View File
@@ -52,6 +52,48 @@ struct DmaTag {
std::string print();
};
inline void emulate_dma(const void* source_base, void* dest_base, u32 tadr, u32 dadr) {
const u8* src = (const u8*)source_base;
u8* dst = (u8*)dest_base;
u32 dest_offset = dadr;
while (true) {
u64 tag_data;
memcpy(&tag_data, src + tadr, 8);
DmaTag tag(tag_data);
switch (tag.kind) {
case DmaTag::Kind::CNT:
memcpy(dst + dest_offset, src + tadr, (1 + tag.qwc) * 16);
dest_offset += (1 + tag.qwc) * 16;
tadr += 16 + tag.qwc * 16;
break;
case DmaTag::Kind::REF: {
// tte
memcpy(dst + dest_offset, src + tadr, 16);
dest_offset += 16;
memcpy(dst + dest_offset, src + tag.addr, tag.qwc * 16);
dest_offset += tag.qwc * 16;
tadr += 16;
} break;
case DmaTag::Kind::REFE: {
// tte
memcpy(dst + dest_offset, src + tadr, 16);
dest_offset += 16;
memcpy(dst + dest_offset, src + tag.addr, tag.qwc * 16);
dest_offset += tag.qwc * 16;
tadr += 16;
return;
} break;
default:
printf("bad tag: %d\n", (int)tag.kind);
assert(false);
}
}
}
struct VifCode {
enum class Kind : u8 {
NOP = 0b0,
+369
View File
@@ -575,8 +575,286 @@ char bc_to_part(int x) {
return '?';
}
}
std::string mask_to_string(u8 val) {
std::string result;
if (val & 8) {
result += 'x';
}
if (val & 4) {
result += 'y';
}
if (val & 2) {
result += 'z';
}
if (val & 1) {
result += 'w';
}
return result;
}
} // namespace
int unk = 0;
std::string VuDisassembler::to_cpp(const VuInstruction& instr) const {
switch (instr.kind) {
case VuInstrK::NOP:
case VuInstrK::LOWER_NOP:
return "/* nop */";
case VuInstrK::LQ:
if (instr.src.at(1).is_int_reg(0)) {
return fmt::format("lq_buffer(Mask::{}, vu.{}, {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
} else if (instr.src.at(0).value() == 0) {
return fmt::format("lq_buffer(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
} else {
return fmt::format("lq_buffer(Mask::{}, vu.{}, vu.{} + {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(1).to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
}
goto unknown;
case VuInstrK::LQI:
return fmt::format("lq_buffer(Mask::{}, vu.{}, vu.{}++);", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::SQI:
return fmt::format("sq_buffer(Mask::{}, vu.{}, vu.{}++);", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::SQ:
if (instr.src.at(1).is_int_reg(0)) {
return fmt::format("sq_buffer(Mask::{}, vu.{}, {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
} else if (instr.src.at(0).value() == 0) {
return fmt::format("sq_buffer(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
} else {
return fmt::format("sq_buffer(Mask::{}, vu.{}, vu.{} + {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(1).to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
}
goto unknown;
case VuInstrK::IADDI:
if (instr.src.at(0).is_int_reg(0)) {
return fmt::format("vu.{} = {};", instr.dst->to_string(m_label_names),
(s16)instr.src.at(1).value());
} else {
return fmt::format("vu.{} = vu.{} + {};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names), (s16)instr.src.at(1).value());
}
case VuInstrK::IADDIU:
if (instr.src.at(0).is_int_reg(0)) {
return fmt::format("vu.{} = 0x{:x}; /* {} */\n", instr.dst->to_string(m_label_names),
(u16)instr.src.at(1).value(), instr.src.at(1).value());
} else {
return fmt::format("vu.{} = vu.{} + 0x{:x}; /* {} */", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names), (u16)instr.src.at(1).value(),
instr.src.at(1).value());
}
case VuInstrK::ISW:
if (instr.src.at(2).is_int_reg(0)) {
return fmt::format("isw_buffer(Mask::{}, vu.{}, {});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
} else {
return fmt::format("isw_buffer(Mask::{}, vu.{}, vu.{} + {});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(2).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
}
goto unknown;
case VuInstrK::ISWR:
return fmt::format("isw_buffer(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::ILWR:
return fmt::format("ilw_buffer(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::ILW:
if (instr.src.at(1).is_int_reg(0)) {
return fmt::format("ilw_buffer(Mask::{}, vu.{}, {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
} else {
return fmt::format("ilw_buffer(Mask::{}, vu.{}, vu.{} + {});", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(1).to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
}
case VuInstrK::ISUBIU:
if (instr.src.at(0).is_int_reg(0)) {
return fmt::format("vu.{} = -{};\n", instr.dst->to_string(m_label_names),
instr.src.at(1).value());
} else {
return fmt::format("vu.{} = vu.{} - 0x{:x}; /* {} */", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names), (u16)instr.src.at(1).value(),
instr.src.at(1).value());
}
case VuInstrK::MTIR:
return fmt::format("vu.{} = vu.{}.{}_as_u16();", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
bc_to_part(*instr.first_src_field));
case VuInstrK::MFIR:
return fmt::format("vu.{}.mfir(Mask::{}, vu.{});", instr.dst->to_string(m_label_names),
mask_to_string(*instr.mask), instr.src.at(0).to_string(m_label_names));
case VuInstrK::B:
return fmt::format("bc = true;", instr.src.at(0).to_string(m_label_names));
case VuInstrK::IBGTZ:
return fmt::format("bc = ((s16)vu.{}) > 0;", instr.src.at(0).to_string(m_label_names));
case VuInstrK::IBGEZ:
return fmt::format("bc = ((s16)vu.{}) >= 0;", instr.src.at(0).to_string(m_label_names));
case VuInstrK::IBEQ:
if (instr.src.at(0).is_int_reg(0)) {
return fmt::format("bc = (vu.{} == 0);", instr.src.at(1).to_string(m_label_names));
} else {
return fmt::format("bc = (vu.{} == vu.{});", instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
}
case VuInstrK::IBNE:
if (instr.src.at(0).is_int_reg(0)) {
return fmt::format("bc = (vu.{} != 0);", instr.src.at(1).to_string(m_label_names));
} else {
return fmt::format("bc = (vu.{} != vu.{});", instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
}
case VuInstrK::IADD:
return fmt::format("vu.{} = vu.{} + vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::ISUB:
return fmt::format("vu.{} = vu.{} - vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::IAND:
return fmt::format("vu.{} = vu.{} & vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::IOR:
if (instr.src.at(1).is_int_reg(0)) {
return fmt::format("vu.{} = vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
} else {
goto unknown;
}
case VuInstrK::MFP:
return fmt::format("vu.{}.mfp(Mask::{}, vu.P);", instr.dst->to_string(m_label_names),
mask_to_string(*instr.mask));
case VuInstrK::MULq:
return fmt::format("vu.{}.mul(Mask::{}, vu.{}, vu.Q); /* TODO mulq */",
instr.dst->to_string(m_label_names), mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::DIV:
return fmt::format(
"vu.Q = vu.{}.{}() / vu.{}.{}();\n", instr.src.at(0).to_string(m_label_names),
bc_to_part(*instr.first_src_field), instr.src.at(1).to_string(m_label_names),
bc_to_part(*instr.second_src_field));
case VuInstrK::ERLENG:
return fmt::format("vu.P = erleng(Mask::{}, vu.{}); /* TODO erleng */",
mask_to_string(*instr.mask), instr.src.at(0).to_string(m_label_names));
case VuInstrK::MR32:
case VuInstrK::MOVE:
case VuInstrK::ITOF0:
case VuInstrK::ITOF15:
case VuInstrK::FTOI0:
case VuInstrK::FTOI4:
return fmt::format("vu.{}.{}(Mask::{}, vu.{});", instr.dst->to_string(m_label_names),
info(instr.kind).name, mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::ADDbc:
case VuInstrK::MULbc:
case VuInstrK::MINIbc:
case VuInstrK::MAXbc:
return fmt::format("vu.{}.{}(Mask::{}, vu.{}, vu.{}.{}());",
instr.dst->to_string(m_label_names), info(instr.kind).name,
mask_to_string(*instr.mask), instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names), bc_to_part(*instr.bc));
case VuInstrK::FP_CONSTANT:
return fmt::format("vu.I = {};", float_to_string(instr.fp));
case VuInstrK::MINIi:
case VuInstrK::MAXi:
return fmt::format("vu.{}.{}(Mask::{}, vu.{}, vu.I);", instr.dst->to_string(m_label_names),
info(instr.kind).name, mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::MUL:
case VuInstrK::ADD:
case VuInstrK::MAX:
case VuInstrK::MINI:
return fmt::format("vu.{}.{}(Mask::{}, vu.{}, vu.{});", instr.dst->to_string(m_label_names),
info(instr.kind).name, mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::ADDAbc:
return fmt::format("vu.acc.adda(Mask::{}, vu.{}, vu.{}.{}());", mask_to_string(*instr.mask),
instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names), bc_to_part(*instr.bc));
case VuInstrK::MADDA:
return fmt::format("vu.acc.madda(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::MADDAbc:
return fmt::format("vu.acc.madda(Mask::{}, vu.{}, vu.{}.{}());", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names), bc_to_part(*instr.bc));
case VuInstrK::MADDbc:
return fmt::format("vu.acc.madd(Mask::{}, vu.{}, vu.{}, vu.{}.{}());",
mask_to_string(*instr.mask), instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names), bc_to_part(*instr.bc));
case VuInstrK::MULA:
return fmt::format("vu.acc.mula(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::MULAbc:
return fmt::format("vu.acc.mula(Mask::{}, vu.{}, vu.{}.{}());", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names), bc_to_part(*instr.bc));
case VuInstrK::XGKICK:
return fmt::format("xgkick(vu.{});", instr.src.at(0).to_string(m_label_names));
case VuInstrK::XTOP:
return fmt::format("vu.{} = xtop();", instr.src.at(0).to_string(m_label_names));
default:
unk++;
return "???";
}
unknown:
unk++;
return "???";
}
std::string VuDisassembler::to_string(const VuInstruction& instr) const {
if (instr.kind == VuInstrK::FP_CONSTANT) {
return float_to_string(instr.fp);
@@ -719,6 +997,11 @@ int VuDisassembler::add_label(int instr) {
}
}
void VuDisassembler::add_label_with_name(int instr, const std::string& name) {
add_label(instr);
m_user_named_instructions[instr] = name;
}
void VuDisassembler::name_labels() {
std::vector<int> instrs_with_labels;
for (auto [instr, label_idx] : m_labels) {
@@ -732,5 +1015,91 @@ void VuDisassembler::name_labels() {
auto label_idx = m_labels.at(instr);
m_label_names.at(label_idx) = fmt::format("L{}", idx++);
}
for (auto& kv : m_user_named_instructions) {
m_label_names.at(m_labels.at(kv.first)) = kv.second;
}
}
bool has_branch_delay(const VuInstructionPair& pair) {
switch (pair.lower.kind) {
case VuInstrK::JALR:
// case VuInstrK::JR: it does, but it's not supported
case VuInstrK::IBGTZ:
case VuInstrK::IBNE:
case VuInstrK::IBEQ:
case VuInstrK::B:
case VuInstrK::BAL:
case VuInstrK::IBLTZ:
case VuInstrK::IBLEZ:
case VuInstrK::IBGEZ:
return true;
default:
return false;
}
}
std::string get_label_name(const VuInstructionPair& pair,
const std::vector<std::string>& label_names) {
for (auto& arg : pair.lower.src) {
if (arg.kind() == VuInstructionAtom::Kind::LABEL) {
return arg.to_string(label_names);
}
}
assert(false);
}
std::string VuDisassembler::to_string_with_cpp(const VuProgram& prog) const {
std::string result;
for (int i = 0; i < (int)prog.instructions().size(); i++) {
auto lab = m_labels.find(i);
if (lab != m_labels.end()) {
result += m_label_names.at(lab->second);
result += ':';
result += '\n';
}
auto& pair = prog.instructions().at(i);
if (has_branch_delay(pair)) {
result += "// BRANCH!\n";
// set bc
result += to_string_with_cpp(prog.instructions().at(i));
result += "\n";
result += to_string_with_cpp(prog.instructions().at(i + 1));
result += "\n";
result += fmt::format("if (bc) {{ goto {}; }}\n", get_label_name(pair, m_label_names));
result += "\n\n";
i++;
} else {
result += to_string_with_cpp(prog.instructions().at(i));
result += '\n';
}
}
fmt::print("TOTAL unk: {}\n", unk);
return result;
}
namespace {
bool is_nop(const VuInstruction& i) {
return i.kind == VuInstrK::NOP || i.kind == VuInstrK::LOWER_NOP;
}
} // namespace
std::string VuDisassembler::to_string_with_cpp(const VuInstructionPair& pair) const {
std::string result;
result += fmt::format(" // {:25s} | {:30s}\n", to_string(pair.lower), to_string(pair.upper));
if (!is_nop(pair.lower) && !is_nop(pair.upper) && pair.lower.kind == VuInstrK::FP_CONSTANT) {
result += fmt::format(" {:25s}", to_cpp(pair.upper));
result += fmt::format(" {:25s}", to_cpp(pair.lower));
} else {
if (!is_nop(pair.upper)) {
result += fmt::format(" {:25s}", to_cpp(pair.upper));
}
if (!is_nop(pair.lower)) {
result += fmt::format(" {:25s}", to_cpp(pair.lower));
}
}
return result;
}
} // namespace decompiler
+6 -1
View File
@@ -57,8 +57,13 @@ class VuDisassembler {
VuDisassembler(VuKind kind);
VuProgram disassemble(void* data, int size_bytes, bool debug_print = false);
std::string to_string(const VuInstruction& instr) const;
std::string to_cpp(const VuInstruction& instr) const;
std::string to_string(const VuInstructionPair& pair) const;
std::string to_string_with_cpp(const VuInstructionPair& pair) const;
std::string to_string(const VuProgram& prog) const;
std::string to_string_with_cpp(const VuProgram& prog) const;
int add_label(int instr);
void add_label_with_name(int instr, const std::string& name);
private:
VuKind m_kind;
@@ -66,6 +71,7 @@ class VuDisassembler {
VuInstrK lower_kind(u32 in);
VuInstruction decode(VuInstrK kind, u32 data, int instr_idx);
s32 get_instruction_index_mask();
std::unordered_map<int, std::string> m_user_named_instructions;
struct VuUpperOp6 {
bool goto_11 = false;
@@ -225,7 +231,6 @@ class VuDisassembler {
std::unordered_map<int, int> m_labels;
std::vector<std::string> m_label_names;
int add_label(int instr);
void name_labels();
OpInfo& add_op(VuInstrK kind, const std::string& name);
+4
View File
@@ -45,6 +45,10 @@ VuInstructionAtom VuInstructionAtom::make_r() {
return {Kind::R};
}
bool VuInstructionAtom::is_int_reg(int idx) const {
return m_kind == Kind::VI && m_value == idx;
}
std::string VuInstructionAtom::to_string(const std::vector<std::string>& labels) const {
switch (m_kind) {
case Kind::VF:
+3
View File
@@ -178,8 +178,11 @@ class VuInstructionAtom {
static VuInstructionAtom make_p();
static VuInstructionAtom make_r();
bool is_int_reg(int idx) const;
std::string to_string(const std::vector<std::string>& labels) const;
Kind kind() const { return m_kind; }
s64 value() const { return m_value; }
private:
VuInstructionAtom(Kind kind, s64 idx = -1) : m_kind(kind), m_value(idx) {}
+5
View File
@@ -976,6 +976,7 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
case InstructionKind::DSRL:
case InstructionKind::SRL:
case InstructionKind::PSRAW:
case InstructionKind::PSRAH:
case InstructionKind::PSRLH:
return handle_generic_op2_u16(i0, instr_str);
case InstructionKind::SLL:
@@ -1002,8 +1003,10 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
case InstructionKind::PMINH:
case InstructionKind::MOVZ:
case InstructionKind::MULT3:
case InstructionKind::MULTU3:
case InstructionKind::PMINW:
case InstructionKind::PMAXW:
case InstructionKind::PMAXH:
case InstructionKind::SUBU:
case InstructionKind::DSRAV:
return handle_generic_op3(i0, instr_str, {});
@@ -1073,6 +1076,8 @@ Mips2C_Line handle_normal_instr(Mips2C_Output& output,
return handle_generic_op2(i0, instr_str, "sqrts");
case InstructionKind::PLZCW:
return handle_generic_op2(i0, instr_str, "plzcw");
case InstructionKind::PCPYH:
return handle_generic_op2(i0, instr_str, "pcpyh");
case InstructionKind::LUI:
return handle_lui(i0, instr_str);
case InstructionKind::CLTS:
+7 -5
View File
@@ -8040,7 +8040,7 @@
(defenum draw-status
:type uint8
:bitfield #t
(drwf00 0)
(needs-clip 0)
(drwf01 1)
(drwf02 2)
(drwf03 3)
@@ -8347,7 +8347,9 @@
)
;;effect-bits:
;; 1 - swap with last effect.
;; 0 - texture scroll
;; 1 - swap with last effect,
;; 2 - ripple
(deftype merc-effect (structure)
((frag-geo merc-fragment :offset-assert 0) ;; ?
@@ -16423,7 +16425,7 @@
;; - Functions
(define-extern setup-blerc-chains-for-one-fragment function)
(define-extern setup-blerc-chains-for-one-fragment (function object object object object object object object))
(define-extern setup-blerc-chains (function merc-ctrl (pointer int16) dma-buffer none))
(define-extern blerc-stats-init (function none))
(define-extern blerc-init (function none))
@@ -16448,7 +16450,7 @@
;; - Functions
(define-extern merc-vu1-init-buffer (function bucket-id gs-test int none))
(define-extern merc-vu1-initialize-chain (function dma-gif-packet none))
(define-extern merc-vu1-initialize-chain (function dma-gif-packet dma-packet))
(define-extern merc-vu1-add-vu-function (function dma-packet vu-function int dma-gif-packet))
(define-extern get-eye-block (function int int int))
(define-extern merc-stats-display (function merc-ctrl none))
@@ -16619,7 +16621,7 @@
(define-extern draw-bones-generic-merc (function draw-control object object int pointer))
(define-extern draw-bones-merc (function draw-control object object int int pointer))
(define-extern draw-bones-check-longest-edge (function draw-control float none))
(define-extern draw-bones-check-longest-edge-asm (function draw-control float none))
(define-extern draw-bones-check-longest-edge-asm (function draw-control float symbol))
(define-extern draw-bones (function draw-control dma-buffer float none))
(define-extern draw-bones-hud (function draw-control dma-buffer none))
@@ -127,8 +127,6 @@
"ripple-execute-init",
// bones
"draw-bones-check-longest-edge-asm",
"draw-bones-merc",
"bones-mtx-calc",
// generic-effect
@@ -499,7 +497,8 @@
"(anon-function 21 plant-boss)": [0, 1, 3, 4],
"(method 55 ram-boss)": [5],
"(method 60 ice-cube)": [8],
"(anon-function 2 snow-ball)": [22]
"(anon-function 2 snow-ball)": [22],
"draw-bones-merc": [1, 3, 5, 7, 8, 10, 11, 12, 13]
},
// Sometimes the game might use format strings that are fetched dynamically,
@@ -578,7 +577,11 @@
"calc-animation-from-spr",
"clear-frame-accumulator",
"bones-mtx-calc",
"cspace<-parented-transformq-joint!"
"cspace<-parented-transformq-joint!",
"draw-bones-merc",
"draw-bones-check-longest-edge-asm",
"setup-blerc-chains-for-one-fragment",
"blerc-execute"
],
"mips2c_jump_table_functions": {
@@ -7083,7 +7083,9 @@
[545, "s2", "int"],
[49, "a1", "bone-calculation"],
[262, "s2", "(pointer uint32)"],
[89, "at", "terrain-context"]
[89, "at", "terrain-context"],
[[312,334], "v1", "mei-envmap-tint"],
[363, "a0", "(pointer uint8)"]
],
"draw-bones-hud": [
@@ -7897,5 +7899,24 @@
[20, "a0", "process-drawable"]
],
"setup-blerc-chains": [
[43, "v1", "int"],
[80, "s0", "int"],
[83, "a0", "int"],
[[30,40], "s1", "merc-fragment-control"],
[41, "v1", "merc-fragment"],
[46, "v1", "(pointer uint8)"],
[59, "a0", "merc-blend-ctrl"],
[[64,76], "s1", "merc-fragment-control"],
[77, "a1", "merc-blend-ctrl"]
],
"blerc-execute": [
[20, "a0", "(pointer int32)"],
[26, "v1", "(pointer int32)"],
[59, "a2", "(pointer int32)"],
[65, "a1", "(pointer int32)"]
],
"placeholder-do-not-add-below": []
}
+3
View File
@@ -68,6 +68,7 @@ set(RUNTIME_SOURCE
mips2c/functions/collide_probe.cpp
mips2c/functions/draw_string.cpp
mips2c/functions/joint.cpp
mips2c/functions/merc_blend_shape.cpp
mips2c/functions/sky_tng.cpp
mips2c/functions/sparticle.cpp
mips2c/functions/sparticle_launcher.cpp
@@ -97,6 +98,8 @@ set(RUNTIME_SOURCE
graphics/opengl_renderer/DirectRenderer.cpp
graphics/opengl_renderer/dma_helpers.cpp
graphics/opengl_renderer/Loader.cpp
graphics/opengl_renderer/MercProgram.cpp
graphics/opengl_renderer/MercRenderer.cpp
graphics/opengl_renderer/OpenGLRenderer.cpp
graphics/opengl_renderer/Profiler.cpp
graphics/opengl_renderer/Shader.cpp
@@ -18,9 +18,11 @@ enum class BucketId {
TFRAG_TEX_LEVEL0 = 5,
TFRAG_LEVEL0 = 6,
TIE_LEVEL0 = 9,
MERC_TFRAG_TEX_LEVEL0 = 10,
TFRAG_TEX_LEVEL1 = 12,
TFRAG_LEVEL1 = 13,
TIE_LEVEL1 = 16,
MERC_TFRAG_TEX_LEVEL1 = 17,
SHRUB_TEX_LEVEL0 = 19,
SHRUB_TEX_LEVEL1 = 25,
ALPHA_TEX_LEVEL0 = 31,
@@ -31,10 +33,16 @@ enum class BucketId {
TFRAG_TRANS1_AND_SKY_BLEND_LEVEL1 = 39,
TFRAG_DIRT_LEVEL1 = 41,
TFRAG_ICE_LEVEL1 = 43,
MERC_AFTER_ALPHA = 45,
PRIS_TEX_LEVEL0 = 48,
MERC_PRIS_LEVEL0 = 49,
PRIS_TEX_LEVEL1 = 51,
MERC_PRIS_LEVEL1 = 52,
MERC_AFTER_PRIS = 55,
WATER_TEX_LEVEL0 = 57,
MERC_WATER_LEVEL0 = 58,
WATER_TEX_LEVEL1 = 60,
MERC_WATER_LEVEL1 = 61,
// ...
PRE_SPRITE_TEX = 65, // maybe it's just common textures?
SPRITE = 66,
@@ -69,6 +77,7 @@ struct SharedRenderState {
bool use_sky_cpu = true;
bool use_occlusion_culling = true;
bool render_debug = false;
void reset();
bool has_camera_planes = false;
@@ -244,7 +244,7 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
// currently gouraud is handled in setup.
const auto& state = m_prim_gl_state;
if (state.texture_enable) {
float alpha_reject = 0.;
float alpha_reject = 0.0;
if (m_test_state.alpha_test_enable) {
switch (m_test_state.alpha_test) {
case GsTest::AlphaTest::ALWAYS:
@@ -310,10 +310,11 @@ void DirectRenderer::update_gl_texture(SharedRenderState* render_state, int unit
if (!tex) {
// TODO Add back
fmt::print("Failed to find texture at {}, using random\n", state.texture_base_ptr);
tex = render_state->texture_pool->get_random_texture();
if (tex) {
// fmt::print("Successful texture lookup! {} {}\n", tex->page_name, tex->name);
if (state.texture_base_ptr >= 8160 && state.texture_base_ptr <= 8600) {
tex = render_state->texture_pool->get_random_texture();
} else {
fmt::print("Failed to find texture at {}, using random\n", state.texture_base_ptr);
tex = render_state->texture_pool->get_random_texture();
}
}
assert(tex);
@@ -367,6 +368,7 @@ void DirectRenderer::update_gl_blend() {
// (Cs - 0) * As + Cd
// Cs * As + (1) * Cd
// s, d
assert(state.fix == 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBlendEquation(GL_FUNC_ADD);
} else if (state.a == GsAlpha::BlendMode::ZERO_OR_FIXED &&
@@ -377,11 +379,19 @@ void DirectRenderer::update_gl_blend() {
// s, d
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
} else if (state.a == GsAlpha::BlendMode::SOURCE && state.b == GsAlpha::BlendMode::DEST &&
state.c == GsAlpha::BlendMode::ZERO_OR_FIXED &&
state.d == GsAlpha::BlendMode::DEST) {
// (Cs - Cd) * fix + Cd
// Cs * fix + (1 - fx) * Cd
glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA);
glBlendColor(0, 0, 0, state.fix / 127.f);
glBlendEquation(GL_FUNC_ADD);
} else {
// unsupported blend: a 0 b 2 c 2 d 1
lg::error("unsupported blend: a {} b {} c {} d {} NOTE THIS DOWN IMMEDIATELY!!", (int)state.a,
(int)state.b, (int)state.c, (int)state.d);
assert(false);
lg::error("unsupported blend: a {} b {} c {} d {}", (int)state.a, (int)state.b, (int)state.c,
(int)state.d);
// assert(false);
}
}
}
@@ -408,6 +418,7 @@ void DirectRenderer::update_gl_test() {
assert(false);
}
} else {
// you aren't supposed to turn off z test enable, the GS had some bugs
assert(false);
}
@@ -699,7 +710,6 @@ void DirectRenderer::handle_tex0_1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
GsTex0 reg(val);
// update tbp
if (current_texture_state()->current_register != reg) {
if (current_texture_state()->used) {
@@ -726,7 +736,8 @@ void DirectRenderer::handle_tex0_1(u64 val,
// tw: assume they got it right
// th: assume they got it right
assert(reg.tfx() == GsTex0::TextureFunction::MODULATE);
// MERC hack
// assert(reg.tfx() == GsTex0::TextureFunction::MODULATE);
// cbp: assume they got it right
// cpsm: assume they got it right
@@ -832,8 +843,8 @@ void DirectRenderer::handle_clamp1(u64 val,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) {
fmt::print("clamp: 0x{:x}\n", val);
assert(false);
// fmt::print("clamp: 0x{:x}\n", val);
// assert(false);
}
if (current_texture_state()->m_clamp_state.current_register != val) {
@@ -1089,8 +1100,6 @@ void DirectRenderer::BlendState::from_register(GsAlpha reg) {
c = reg.c_mode();
d = reg.d_mode();
fix = reg.fix();
assert(fix == 0);
}
void DirectRenderer::PrimGlState::from_register(GsPrim reg) {
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,346 @@
#include "MercRenderer.h"
#include "third-party/imgui/imgui.h"
MercRenderer::MercRenderer(const std::string& name, BucketId my_id)
: BucketRenderer(name, my_id),
m_direct(fmt::format("{}-dir", name), my_id, 0x30000, DirectRenderer::Mode::NORMAL) {
memset(m_buffer.data, 0, sizeof(m_buffer.data));
}
void MercRenderer::render(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_stats = Stats();
// skip if disabled
if (!m_enabled) {
while (dma.current_tag_offset() != render_state->next_bucket) {
dma.read_and_advance();
}
return;
}
// process the first tag. this is just jumping to the merc-specific dma.
auto data0 = dma.read_and_advance();
assert(data0.vif1() == 0);
assert(data0.vif0() == 0);
assert(data0.size_bytes == 0);
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
// renderer didn't run, let's just get out of here.
for (int i = 0; i < 4; i++) {
dma.read_and_advance();
}
assert(dma.current_tag_offset() == render_state->next_bucket);
return;
}
m_stats.had_data = true;
assert(data0.size_bytes == 0);
assert(data0.vif0() == 0);
assert(data0.vif1() == 0);
// if we reach here, there's stuff to draw
handle_setup(dma, render_state, prof);
m_direct.reset_state();
while (dma.current_tag_offset() != render_state->next_bucket) {
handle_merc_chain(dma, render_state, prof);
}
assert(dma.current_tag_offset() == render_state->next_bucket);
m_direct.flush_pending(render_state, prof);
}
bool tag_is_nothing_next(const DmaFollower& dma) {
return dma.current_tag().kind == DmaTag::Kind::NEXT && dma.current_tag().qwc == 0 &&
dma.current_tag_vif0() == 0 && dma.current_tag_vif1() == 0;
}
void MercRenderer::unpack32(const VifCodeUnpack& up, const u8* data, u32 imm) {
assert(!up.is_unsigned);
u32 addr = up.addr_qw;
assert(imm != 0);
assert(!m_vif.stmod);
if (up.use_tops_flag) {
addr += xitop();
}
u32 start_in_buff = (addr)*16;
u32 end_in_buff = start_in_buff + imm * 16;
assert(start_in_buff < sizeof(m_buffer.data));
assert(end_in_buff <= sizeof(m_buffer.data));
memcpy(m_buffer.data + start_in_buff, data, imm * 16);
}
void MercRenderer::unpack8(const VifCodeUnpack& up, const u8* data, u32 imm) {
// assert(m_vif.stmod);
assert(up.is_unsigned);
u32 addr = up.addr_qw;
if (up.use_tops_flag) {
addr += xitop();
}
assert(imm != 0);
u32 start_in_buff = (addr)*16;
u32 end_in_buff = start_in_buff + imm * 16;
assert(start_in_buff < sizeof(m_buffer.data));
assert(end_in_buff <= sizeof(m_buffer.data));
u8* out_ptr = m_buffer.data + start_in_buff;
if (m_vif.stmod) {
// use row
auto row = _mm_loadu_si128((const __m128i*)m_vif.row);
for (u32 qw = 0; qw < imm; qw++) {
_mm_storeu_si128((__m128i*)out_ptr,
_mm_add_epi32(row, _mm_cvtepu8_epi32(_mm_loadu_si64(data))));
data += 4;
out_ptr += 16;
}
} else {
// no row
for (u32 qw = 0; qw < imm; qw++) {
_mm_storeu_si128((__m128i*)out_ptr, _mm_cvtepu8_epi32(_mm_loadu_si64(data)));
data += 4;
out_ptr += 16;
}
}
/*
u32 row[4];
if (m_vif.stmod) {
memcpy(row, m_vif.row, 16);
} else {
memset(row, 0, 16);
}
u32 temp[4];
for (u32 i = 0; i < imm; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = row[j] + data[4 * i + j];
}
memcpy(m_buffer.data + start_in_buff + i * 16, temp, 16);
}
*/
}
void MercRenderer::handle_merc_chain(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// fmt::print("DMA: {}\n", dma.current_tag().print());
while (tag_is_nothing_next(dma)) {
auto nothing = dma.read_and_advance();
assert(nothing.size_bytes == 0);
}
if (dma.current_tag().kind == DmaTag::Kind::CALL) {
for (int i = 0; i < 4; i++) {
dma.read_and_advance();
}
return;
}
auto init = dma.read_and_advance();
assert(init.vifcode0().kind == VifCode::Kind::STROW);
assert(init.size_bytes == 16);
m_vif.row[0] = init.vif1();
memcpy(m_vif.row + 1, init.data, 12);
u32 extra;
memcpy(&extra, init.data + 12, 4);
assert(extra == 0);
DmaTransfer next;
bool setting_up = true;
u32 mscal_addr = -1;
while (setting_up) {
next = dma.read_and_advance();
u32 offset_in_data = 0;
// fmt::print("START {} : {} {}\n", next.size_bytes, next.vifcode0().print(),
// next.vifcode1().print());
auto vif0 = next.vifcode0();
switch (vif0.kind) {
case VifCode::Kind::NOP:
case VifCode::Kind::FLUSHE:
break;
case VifCode::Kind::STMOD:
assert(vif0.immediate == 0 || vif0.immediate == 1);
m_vif.stmod = vif0.immediate;
break;
default:
assert(false);
}
auto vif1 = next.vifcode1();
switch (vif1.kind) {
case VifCode::Kind::UNPACK_V4_8: {
// todo unpack
m_stats.unpack_count++;
m_stats.unpack_bytes += vif1.num * 4;
VifCodeUnpack up(vif1);
unpack8(up, next.data, vif1.num);
offset_in_data += 4 * vif1.num;
} break;
case VifCode::Kind::UNPACK_V4_32: {
// todo unpack
VifCodeUnpack up(vif1);
unpack32(up, next.data, vif1.num);
m_stats.unpack_bytes += vif1.num * 16;
offset_in_data += 16 * vif1.num;
} break;
case VifCode::Kind::MSCAL:
mscal_addr = vif1.immediate;
assert(next.size_bytes == 0);
setting_up = false;
break;
default:
assert(false);
}
assert(offset_in_data <= next.size_bytes);
if (offset_in_data < next.size_bytes) {
assert((offset_in_data % 4) == 0);
u32 leftover = next.size_bytes - offset_in_data;
if (leftover < 16) {
for (u32 i = 0; i < leftover; i++) {
assert(next.data[offset_in_data + i] == 0);
}
} else {
assert(false);
}
}
}
m_dbf = !m_dbf;
switch (mscal_addr) {
case 17:
m_stats.mscal_17++;
if (m_enable_prime_mscals) {
mscal(17, render_state, prof);
}
break;
case 32:
m_stats.mscal_32++;
if (m_enable_prime_mscals) {
mscal(32, render_state, prof);
}
break;
case 20:
m_stats.mscal_20++;
if (m_enable_normal_mscals) {
mscal(20, render_state, prof);
}
break;
case 35:
m_stats.mscal_35++;
if (m_enable_normal_mscals) {
mscal(35, render_state, prof);
}
break;
default:
fmt::print("unknown mscal: {}\n", mscal_addr);
assert(false);
}
// while (true) {
// next = dma.read_and_advance();
// if (next.vif0() == 0 && next.vifcode1().kind == VifCode::Kind::UNPACK_V4_8) {
//
// } else {
// fmt::print("{} : {} {}\n", next.size_bytes, next.vifcode0().print(),
// next.vifcode1().print()); assert(false);
// }
// }
}
/*!
* Handle the setup DMA data prepared by merc-vu1-init-buffer in GOAL
*/
void MercRenderer::handle_setup(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
auto first = dma.read_and_advance();
// 10 quadword setup packet
assert(first.size_bytes == 10 * 16);
// m_stats.str += fmt::format("Setup 0: {} {} {}", first.size_bytes / 16,
// first.vifcode0().print(), first.vifcode1().print());
// transferred vifcodes
{
auto vif0 = first.vifcode0();
auto vif1 = first.vifcode1();
// STCYCL 4, 4
assert(vif0.kind == VifCode::Kind::STCYCL);
auto vif0_st = VifCodeStcycl(vif0);
assert(vif0_st.cl == 4 && vif0_st.wl == 4);
// STMOD
assert(vif1.kind == VifCode::Kind::STMOD);
assert(vif1.immediate == 0);
}
// 1 qw with 4 vifcodes.
u32 vifcode_data[4];
memcpy(vifcode_data, first.data, 16);
{
auto vif0 = VifCode(vifcode_data[0]);
assert(vif0.kind == VifCode::Kind::BASE);
assert(vif0.immediate == MercDataMemory::BUFFER_BASE);
auto vif1 = VifCode(vifcode_data[1]);
assert(vif1.kind == VifCode::Kind::OFFSET);
assert((s16)vif1.immediate == MercDataMemory::BUFFER_OFFSET);
auto vif2 = VifCode(vifcode_data[2]);
assert(vif2.kind == VifCode::Kind::NOP);
auto vif3 = VifCode(vifcode_data[3]);
assert(vif3.kind == VifCode::Kind::UNPACK_V4_32);
VifCodeUnpack up(vif3);
assert(up.addr_qw == MercDataMemory::LOW_MEMORY);
assert(!up.use_tops_flag);
assert(vif3.num == 8);
}
// 8 qw's of low memory data
memcpy(&m_low_memory, first.data + 16, sizeof(LowMemory));
m_stats.str += fmt::format("Fog: {}\n", m_low_memory.fog.to_string_aligned());
// 1 qw with another 4 vifcodes.
u32 vifcode_final_data[4];
memcpy(vifcode_final_data, first.data + 16 + sizeof(LowMemory), 16);
{
assert(VifCode(vifcode_final_data[0]).kind == VifCode::Kind::FLUSHE);
assert(vifcode_final_data[1] == 0);
assert(vifcode_final_data[2] == 0);
VifCode mscal(vifcode_final_data[3]);
assert(mscal.kind == VifCode::Kind::MSCAL);
assert(mscal.immediate == 0);
}
// copy low memory into the VU "emulation" RAM.
memcpy(m_buffer.data, &m_low_memory, sizeof(LowMemory));
mscal(0, render_state, prof);
auto second = dma.read_and_advance();
assert(second.size_bytes == 32); // setting up test register.
m_direct.render_gif(second.data, 32, render_state, prof);
auto nothing = dma.read_and_advance();
assert(nothing.size_bytes == 0);
assert(nothing.vif0() == 0);
assert(nothing.vif1() == 0);
}
void MercRenderer::draw_debug_window() {
ImGui::Text("Ran? %d\n", m_stats.had_data);
ImGui::Text("%d unpacks, %d bytes\n", m_stats.unpack_count, m_stats.unpack_bytes);
ImGui::Text("MSCAL: [17] %d [20] %d [32] %d [35] %d \n", m_stats.mscal_17, m_stats.mscal_20,
m_stats.mscal_32, m_stats.mscal_35);
ImGui::Text("Debug:\n%s\n", m_stats.str.c_str());
ImGui::Checkbox("Normal MSCAL enable", &m_enable_normal_mscals);
ImGui::Checkbox("Prime MSCAL enable", &m_enable_prime_mscals);
ImGui::Checkbox("Send to direct", &m_enable_send_to_direct);
}
void MercRenderer::xgkick(u16 addr, SharedRenderState* render_state, ScopedProfilerNode& prof) {
if (m_enable_send_to_direct) {
m_direct.render_gif(m_buffer.data + (16 * addr), UINT32_MAX, render_state, prof);
}
}
@@ -0,0 +1,539 @@
#pragma once
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "common/math/Vector.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "immintrin.h"
enum class Mask {
NONE = 0,
x = 1,
y = 2,
xy = 3,
z = 4,
xz = 5,
yz = 6,
xyz = 7,
w = 8,
xw = 9,
yw = 10,
xyw = 11,
zw = 12,
xzw = 13,
yzw = 14,
xyzw = 15
};
#ifdef __linux__
#define REALLY_INLINE __attribute__((always_inline))
#else
#define REALLY_INLINE __forceinline
#endif
// note: must be aligned.
static inline REALLY_INLINE void copy_vector(void* dest, const void* src) {
__m128 val = _mm_load_ps((const float*)src);
_mm_store_ps((float*)dest, val);
}
inline float vu_max(float a, float b) {
return std::max(b, a);
// s32 ai, bi;
// memcpy(&ai, &a, 4);
// memcpy(&bi, &b, 4);
// bool flip = ai < 0 && bi < 0;
// if (ai > bi) {
// return flip ? b : a;
// } else {
// return flip ? a : b;
// }
}
inline float vu_min(float a, float b) {
s32 ai, bi;
memcpy(&ai, &a, 4);
memcpy(&bi, &b, 4);
bool flip = ai < 0 && bi < 0;
if (ai > bi) {
return flip ? a : b;
} else {
return flip ? b : a;
}
}
struct alignas(16) Vf {
REALLY_INLINE __m128 load() const { return _mm_load_ps(data); }
REALLY_INLINE void move_xyzw(const Vf& src) { copy_vector(data, src.data); }
float data[4];
float& x() { return data[0]; }
float& y() { return data[1]; }
float& z() { return data[2]; }
float& w() { return data[3]; }
const float& x() const { return data[0]; }
const float& y() const { return data[1]; }
const float& z() const { return data[2]; }
const float& w() const { return data[3]; }
u16 x_as_u16() const {
u16 result;
memcpy(&result, &data[0], 2);
return result;
}
u16 y_as_u16() const {
u16 result;
memcpy(&result, &data[1], 2);
return result;
}
u16 z_as_u16() const {
u16 result;
memcpy(&result, &data[2], 2);
return result;
}
u16 w_as_u16() const {
u16 result;
memcpy(&result, &data[3], 2);
return result;
}
u32 x_as_u32() const {
u32 result;
memcpy(&result, &data[0], 4);
return result;
}
u32 y_as_u32() const {
u32 result;
memcpy(&result, &data[1], 4);
return result;
}
u32 z_as_u32() const {
u32 result;
memcpy(&result, &data[2], 4);
return result;
}
u32 w_as_u32() const {
u32 result;
memcpy(&result, &data[3], 4);
return result;
}
Vf() = default;
Vf(const math::Vector4f& vec) { memcpy(data, vec.data(), 16); }
Vf(float a, float b, float c, float d) {
data[0] = a;
data[1] = b;
data[2] = c;
data[3] = d;
}
std::string str_float() const { return fmt::format("{} {} {} {}", x(), y(), z(), w()); }
float& operator[](int i) { return data[i]; }
float operator[](int i) const { return data[i]; }
void mr32(Mask mask, const Vf& other) {
float temp[4];
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
temp[i] = other[(i + 1) % 4];
}
}
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = temp[i];
}
}
}
REALLY_INLINE void mr32_z(const Vf& other) { data[2] = other.data[3]; }
void mfir(Mask mask, s16 in) {
s32 sext = in;
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
memcpy(data + i, &sext, 4);
}
}
}
void maxi(Mask mask, const Vf& other, float I) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = vu_max(other[i], I);
}
}
}
void max(Mask mask, const Vf& other, float I) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = vu_max(other[i], I);
}
}
}
void max(Mask mask, const Vf& other, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = vu_max(other[i], b[i]);
}
}
}
REALLY_INLINE void max_xyzw(const Vf& a, const Vf& b) {
_mm_store_ps(data, _mm_max_ps(_mm_load_ps(a.data), _mm_load_ps(b.data)));
}
REALLY_INLINE void max_xyzw(const Vf& a, float b) {
_mm_store_ps(data, _mm_max_ps(_mm_load_ps(a.data), _mm_set1_ps(b)));
}
REALLY_INLINE void mini_xyzw(const Vf& a, const Vf& b) {
_mm_store_ps(data, _mm_min_ps(_mm_load_ps(a.data), _mm_load_ps(b.data)));
}
REALLY_INLINE void mini_xyzw(const Vf& a, float b) {
_mm_store_ps(data, _mm_min_ps(_mm_load_ps(a.data), _mm_set1_ps(b)));
}
void minii(Mask mask, const Vf& other, float I) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = vu_min(other[i], I);
}
}
}
void mini(Mask mask, const Vf& other, float I) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = vu_min(other[i], I);
}
}
}
void move(Mask mask, const Vf& other) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = other[i];
}
}
}
void mfp(Mask mask, float other) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = other;
}
}
}
void add(Mask mask, const Vf& a, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] + b[i];
}
}
}
REALLY_INLINE void add_xyzw(const Vf& a, const Vf& b) {
_mm_store_ps(data, _mm_add_ps(_mm_load_ps(a.data), _mm_load_ps(b.data)));
}
void add(Mask mask, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] + b;
}
}
}
REALLY_INLINE void mul_xyzw(const Vf& a, const Vf& b) {
_mm_store_ps(data, _mm_mul_ps(_mm_load_ps(a.data), _mm_load_ps(b.data)));
}
REALLY_INLINE void mul_xyzw(const Vf& a, float b) {
_mm_store_ps(data, _mm_mul_ps(_mm_load_ps(a.data), _mm_set1_ps(b)));
}
void mul(Mask mask, const Vf& a, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] * b[i];
}
}
}
void mul(Mask mask, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] * b;
}
}
}
void itof0(Mask mask, const Vf& a) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
s32 val;
memcpy(&val, &a.data[i], 4);
data[i] = val;
}
}
}
void itof15(Mask mask, const Vf& a) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
s32 val;
memcpy(&val, &a.data[i], 4);
data[i] = ((float)val) * (1.f / 32768.f);
;
}
}
}
void ftoi4(Mask mask, const Vf& a) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
s32 val = a.data[i] * 16.f;
memcpy(&data[i], &val, 4);
}
}
}
void ftoi0(Mask mask, const Vf& a) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
s32 val = a.data[i];
memcpy(&data[i], &val, 4);
}
}
}
};
struct alignas(16) Accumulator {
float data[4];
void adda(Mask mask, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] + b;
}
}
}
void madda(Mask mask, const Vf& a, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] += a[i] * b[i];
}
}
}
void madda(Mask mask, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] += a[i] * b;
}
}
}
REALLY_INLINE void madda_xyzw(const Vf& _a, float _b) {
auto b = _mm_set1_ps(_b);
auto a = _mm_load_ps(_a.data);
auto acc = _mm_load_ps(data);
_mm_store_ps(data, _mm_fmadd_ps(a, b, acc));
}
REALLY_INLINE void madda_xyzw(const Vf& _a, const Vf& _b) {
auto b = _mm_load_ps(_b.data);
auto a = _mm_load_ps(_a.data);
auto acc = _mm_load_ps(data);
_mm_store_ps(data, _mm_fmadd_ps(a, b, acc));
}
void madd(Mask mask, Vf& dest, const Vf& a, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
dest[i] = data[i] + a[i] * b[i];
}
}
}
REALLY_INLINE void madd_xyzw(Vf& dest, const Vf& _a, float _b) {
auto b = _mm_set1_ps(_b);
auto a = _mm_load_ps(_a.data);
auto acc = _mm_load_ps(data);
_mm_store_ps(dest.data, _mm_fmadd_ps(a, b, acc));
}
REALLY_INLINE void madd_xyz(Vf& dest, const Vf& _a, float _b) {
auto b = _mm_set1_ps(_b);
auto a = _mm_load_ps(_a.data);
auto acc = _mm_load_ps(data);
auto prod = _mm_fmadd_ps(a, b, acc);
prod = _mm_blend_ps(prod, _mm_load_ps(dest.data), 0b1000);
_mm_store_ps(dest.data, prod);
}
void madd(Mask mask, Vf& dest, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
dest[i] = data[i] + a[i] * b;
}
}
}
void mula(Mask mask, const Vf& a, const Vf& b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] * b[i];
}
}
}
void mula(Mask mask, const Vf& a, float b) {
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
data[i] = a[i] * b;
}
}
}
REALLY_INLINE void mula_xyzw(const Vf& _a, float _b) {
auto b = _mm_set1_ps(_b);
auto a = _mm_load_ps(_a.data);
_mm_store_ps(data, _mm_mul_ps(a, b));
}
REALLY_INLINE void mula_xyzw(const Vf& _a, const Vf& _b) {
auto b = _mm_load_ps(_b.data);
auto a = _mm_load_ps(_a.data);
_mm_store_ps(data, _mm_mul_ps(a, b));
}
};
class MercRenderer : public BucketRenderer {
public:
MercRenderer(const std::string& name, BucketId my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
private:
void handle_setup(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_merc_chain(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void unpack8(const VifCodeUnpack& up, const u8* data, u32 imm);
void unpack32(const VifCodeUnpack& up, const u8* data, u32 imm);
void mscal(int enter_address, SharedRenderState* render_state, ScopedProfilerNode& prof);
template <bool DEBUG>
void mscal_impl(int enter_address, SharedRenderState* render_state, ScopedProfilerNode& prof);
void xgkick(u16 addr, SharedRenderState* render_state, ScopedProfilerNode& prof);
enum MercDataMemory {
LOW_MEMORY = 0,
BUFFER_BASE = 442,
// this negative offset is what broke jak graphics in Dobiestation for a long time.
BUFFER_OFFSET = -442
};
struct LowMemory {
u8 tri_strip_tag[16];
u8 ad_gif_tag[16];
math::Vector4f hvdf_offset;
math::Vector4f perspective[4];
math::Vector4f fog;
} m_low_memory;
static_assert(sizeof(LowMemory) == 0x80);
struct alignas(16) BufferMemory {
u8 data[1024 * 16];
} m_buffer;
void sq_buffer(Mask mask, const Vf& data, u32 qw) {
// if (data.x_as_u32() == 0x80000000 && data.y_as_u32() == 0x80000000) {
// fmt::print("big store line {}: {} : {} {} {} {}\n", line_number, qw, data.x(), data.y(),
// data.z(), data.w());
// }
// sketchy...
// qw &= 1023;
assert(qw * 16 < sizeof(m_buffer.data));
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
memcpy(m_buffer.data + qw * 16 + i * 4, data.data + i, 4);
}
}
}
void lq_buffer(Mask mask, Vf& dest, u16 addr);
template <bool DEBUG>
void lq_buffer_xyzw(Vf& dest, u16 addr);
template <bool DEBUG>
void lq_buffer_xyz(Vf& dest, u16 addr);
template <bool DEBUG>
void sq_buffer_xyzw(const Vf& src, u16 addr);
void isw_buffer(Mask mask, u16 val, u16 addr);
void ilw_buffer(Mask mask, u16& dest, u16 addr);
u16 xtop();
u16 xitop();
DirectRenderer m_direct;
struct {
u32 row[4] = {0, 0, 0, 0};
bool stmod = false;
} m_vif;
struct Stats {
int unpack_count = 0;
int unpack_bytes = 0;
int mscal_35 = 0;
int mscal_20 = 0;
int mscal_17 = 0;
int mscal_32 = 0;
bool had_data = false;
std::string str;
} m_stats;
bool m_dbf = false;
bool m_enable_prime_mscals = true;
bool m_enable_normal_mscals = true;
bool m_enable_send_to_direct = true;
struct Vu {
Vf vf01, vf02, vf03, vf04, vf05, vf06, vf07, vf08, vf09, vf10, vf11, vf12, vf13, vf14, vf15,
vf16, vf17, vf18, vf19, vf20, vf21, vf22, vf23, vf24, vf25, vf26, vf27, vf28, vf29, vf30,
vf31;
const Vf vf00;
u16 vi01, vi02, vi03, vi04, vi05, vi06, vi07, vi09, vi08, vi11, vi12, vi13, vi10, vi14, vi15;
float I, P, Q;
Accumulator acc;
const u16 vi00 = 0;
u16 hack_old_vi15 = 0;
Vu() : vf00(0, 0, 0, 1) {}
} vu;
};
+118 -24
View File
@@ -11,6 +11,7 @@
#include "game/graphics/opengl_renderer/Sprite3.h"
#include "game/graphics/opengl_renderer/tfrag/TFragment.h"
#include "game/graphics/opengl_renderer/tfrag/Tie3.h"
#include "game/graphics/opengl_renderer/MercRenderer.h"
// for the vif callback
#include "game/kernel/kmachine.h"
@@ -68,44 +69,136 @@ void OpenGLRenderer::init_bucket_renderers() {
tfrag3::TFragmentTreeKind::LOWRES};
std::vector<tfrag3::TFragmentTreeKind> dirt_tfrags = {tfrag3::TFragmentTreeKind::DIRT};
std::vector<tfrag3::TFragmentTreeKind> ice_tfrags = {tfrag3::TFragmentTreeKind::ICE};
init_bucket_renderer<EmptyBucketRenderer>("bucket0", BucketId::BUCKET0);
init_bucket_renderer<SkyRenderer>("sky", BucketId::SKY_DRAW);
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-0", BucketId::TFRAG_TEX_LEVEL0);
init_bucket_renderer<TFragment>("tfrag-0", BucketId::TFRAG_LEVEL0, normal_tfrags, false, 0);
init_bucket_renderer<Tie3>("tie-0", BucketId::TIE_LEVEL0, 0);
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-1", BucketId::TFRAG_TEX_LEVEL1);
init_bucket_renderer<TFragment>("tfrag-1", BucketId::TFRAG_LEVEL1, normal_tfrags, false, 1);
init_bucket_renderer<Tie3>("tie-1", BucketId::TIE_LEVEL1, 1);
init_bucket_renderer<TextureUploadHandler>("shrub-tex-0", BucketId::SHRUB_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("shrub-tex-1", BucketId::SHRUB_TEX_LEVEL1);
init_bucket_renderer<TextureUploadHandler>("alpha-tex-0", BucketId::ALPHA_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("alpha-tex-1", BucketId::ALPHA_TEX_LEVEL1);
auto sky_gpu_blender = std::make_shared<SkyBlendGPU>();
auto sky_cpu_blender = std::make_shared<SkyBlendCPU>();
//-------------
// PRE TEXTURE
//-------------
// 0
// 1
// 2
init_bucket_renderer<SkyRenderer>("sky", BucketId::SKY_DRAW); // 3
// 4
//-----------------------
// LEVEL 0 tfrag texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-0", BucketId::TFRAG_TEX_LEVEL0); // 5
init_bucket_renderer<TFragment>("tfrag-0", BucketId::TFRAG_LEVEL0, normal_tfrags, false, 0); // 6
// 7
// 8
init_bucket_renderer<Tie3>("tie-0", BucketId::TIE_LEVEL0, 0); // 9
init_bucket_renderer<MercRenderer>("merc-tf-0", BucketId::MERC_TFRAG_TEX_LEVEL0); // 10
// 11
//-----------------------
// LEVEL 1 tfrag texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("tfrag-tex-1", BucketId::TFRAG_TEX_LEVEL1); // 12
init_bucket_renderer<TFragment>("tfrag-1", BucketId::TFRAG_LEVEL1, normal_tfrags, false, 1);
// 14
// 15
init_bucket_renderer<Tie3>("tie-1", BucketId::TIE_LEVEL1, 1);
init_bucket_renderer<MercRenderer>("merc-tf-1", BucketId::MERC_TFRAG_TEX_LEVEL1); // 17
// 18??
//-----------------------
// LEVEL 0 shrub texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("shrub-tex-0", BucketId::SHRUB_TEX_LEVEL0); // 19
// 20
// 21
// 22
// 23
// 24
//-----------------------
// LEVEL 1 shrub texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("shrub-tex-1", BucketId::SHRUB_TEX_LEVEL1); // 25
// 26
// 27
// 28
// 29
// 30
//-----------------------
// LEVEL 0 alpha texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("alpha-tex-0", BucketId::ALPHA_TEX_LEVEL0); // 31
init_bucket_renderer<SkyBlendHandler>("sky-blend-and-tfrag-trans-0",
BucketId::TFRAG_TRANS0_AND_SKY_BLEND_LEVEL0, 0,
sky_gpu_blender, sky_cpu_blender);
sky_gpu_blender, sky_cpu_blender); // 32
// 33
init_bucket_renderer<TFragment>("tfrag-dirt-0", BucketId::TFRAG_DIRT_LEVEL0, dirt_tfrags, false,
0);
0); // 34
// 35
init_bucket_renderer<TFragment>("tfrag-ice-0", BucketId::TFRAG_ICE_LEVEL0, ice_tfrags, false, 0);
// 37
//-----------------------
// LEVEL 1 alpha texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("alpha-tex-1", BucketId::ALPHA_TEX_LEVEL1); // 38
init_bucket_renderer<SkyBlendHandler>("sky-blend-and-tfrag-trans-1",
BucketId::TFRAG_TRANS1_AND_SKY_BLEND_LEVEL1, 1,
sky_gpu_blender, sky_cpu_blender);
sky_gpu_blender, sky_cpu_blender); // 39
// 40
init_bucket_renderer<TFragment>("tfrag-dirt-1", BucketId::TFRAG_DIRT_LEVEL1, dirt_tfrags, false,
1);
1); // 41
// 42
init_bucket_renderer<TFragment>("tfrag-ice-1", BucketId::TFRAG_ICE_LEVEL1, ice_tfrags, false, 1);
init_bucket_renderer<TextureUploadHandler>("pris-tex-0", BucketId::PRIS_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("pris-tex-1", BucketId::PRIS_TEX_LEVEL1);
init_bucket_renderer<TextureUploadHandler>("water-tex-0", BucketId::WATER_TEX_LEVEL0);
init_bucket_renderer<TextureUploadHandler>("water-tex-1", BucketId::WATER_TEX_LEVEL1);
init_bucket_renderer<TextureUploadHandler>("pre-sprite-tex", BucketId::PRE_SPRITE_TEX);
// 44
init_bucket_renderer<MercRenderer>("merc-after-alpha", BucketId::MERC_AFTER_ALPHA);
// 46?
// 47?
//-----------------------
// LEVEL 0 pris texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("pris-tex-0", BucketId::PRIS_TEX_LEVEL0); // 48
init_bucket_renderer<MercRenderer>("merc-pris-0", BucketId::MERC_PRIS_LEVEL0); // 49
// 50
//-----------------------
// LEVEL 1 pris texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("pris-tex-1", BucketId::PRIS_TEX_LEVEL1); // 51
init_bucket_renderer<MercRenderer>("merc-pris-1", BucketId::MERC_PRIS_LEVEL1); // 52
// 53
// 54?
init_bucket_renderer<MercRenderer>("merc-after-pris", BucketId::MERC_AFTER_PRIS); // 55
// 56?
//-----------------------
// LEVEL 0 water texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("water-tex-0", BucketId::WATER_TEX_LEVEL0); // 57
init_bucket_renderer<MercRenderer>("merc-water-0", BucketId::MERC_WATER_LEVEL0); // 58
// 59
//-----------------------
// LEVEL 1 water texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("water-tex-1", BucketId::WATER_TEX_LEVEL1); // 60
init_bucket_renderer<MercRenderer>("merc-water-1", BucketId::MERC_WATER_LEVEL1); // 61
// 62
// 63?
// 64?
//-----------------------
// COMMON texture
//-----------------------
init_bucket_renderer<TextureUploadHandler>("pre-sprite-tex", BucketId::PRE_SPRITE_TEX); // 65
std::vector<std::unique_ptr<BucketRenderer>> sprite_renderers;
sprite_renderers.push_back(std::make_unique<SpriteRenderer>("sprite-renderer", BucketId::SPRITE));
sprite_renderers.push_back(std::make_unique<Sprite3>("sprite-3", BucketId::SPRITE));
init_bucket_renderer<RenderMux>("sprite", BucketId::SPRITE, std::move(sprite_renderers)); // 66
init_bucket_renderer<RenderMux>("sprite", BucketId::SPRITE, std::move(sprite_renderers));
init_bucket_renderer<DirectRenderer>("debug-draw-0", BucketId::DEBUG_DRAW_0, 0x20000,
DirectRenderer::Mode::NORMAL);
init_bucket_renderer<DirectRenderer>("debug-draw-1", BucketId::DEBUG_DRAW_1, 0x8000,
@@ -184,6 +277,7 @@ void OpenGLRenderer::draw_renderer_selection_window() {
ImGui::Checkbox("Sky CPU", &m_render_state.use_sky_cpu);
ImGui::Checkbox("Occlusion Cull", &m_render_state.use_occlusion_culling);
ImGui::Checkbox("Render Debug (slower)", &m_render_state.render_debug);
for (size_t i = 0; i < m_bucket_renderers.size(); i++) {
auto renderer = m_bucket_renderers[i].get();
@@ -12,5 +12,5 @@ void main() {
gl_Position = vec4((position_in.x - 0.5) * 16., -(position_in.y - 0.5) * 32, position_in.z * 2 - 1., 1.0);
// scissoring area adjust
gl_Position.y *= 512.0/448.0;
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w + 0.5);
fragment_color = vec4(rgba_in.x, rgba_in.y, rgba_in.z, rgba_in.w * 2.);
}
@@ -41,7 +41,7 @@ void main() {
T0.w = 1.0;
}
color = fragment_color * T0 * 2.0;
if (color.a <= alpha_reject) {
if (color.a < alpha_reject) {
discard;
}
}
@@ -114,7 +114,7 @@ DoubleDraw setup_opengl_from_draw_mode(DrawMode mode, u32 tex_unit, bool mipmap)
}
}
if (mode.get_depth_write_enable()) {
if (mode.get_depth_write_enable() && !alpha_hack_to_disable_z_write) {
glDepthMask(GL_TRUE);
} else {
glDepthMask(GL_FALSE);
+587
View File
@@ -689,3 +689,590 @@ void link() {
} // namespace bones_mtx_calc
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/kscheme.h"
namespace Mips2C {
namespace draw_bones_merc {
struct Cache {
void* merc_bucket_info; // *merc-bucket-info*
void* merc_global_stats; // *merc-global-stats*
void* fake_scratchpad_data;
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
c->daddiu(sp, sp, -128); // daddiu sp, sp, -128
c->sd(ra, 0, sp); // sd ra, 0(sp)
c->sq(s0, 16, sp); // sq s0, 16(sp)
c->sq(s1, 32, sp); // sq s1, 32(sp)
c->sq(s2, 48, sp); // sq s2, 48(sp)
c->sq(s3, 64, sp); // sq s3, 64(sp)
c->sq(s4, 80, sp); // sq s4, 80(sp)
c->sq(s5, 96, sp); // sq s5, 96(sp)
c->sq(gp, 112, sp); // sq gp, 112(sp)
c->mov64(t8, a3); // or t8, a3, r0
c->mov64(v1, t0); // or v1, t0, r0
c->lui(t0, 4096); // lui t0, 4096
c->lui(t1, 18304); // lui t1, 18304
c->daddiu(t0, t0, 1); // daddiu t0, t0, 1
c->dsll32(t1, t1, 0); // dsll32 t1, t1, 0
c->lui(a3, 12288); // lui a3, 12288
c->lui(t7, 19201); // lui t7, 19201
c->pcpyld(t0, a3, t0); // pcpyld t0, a3, t0
c->lbu(a3, 58, a0); // lbu a3, 58(a0)
c->pcpyld(t1, t7, t1); // pcpyld t1, t7, t1
c->lui(t2, 28160); // lui t2, 28160
c->addiu(t7, r0, 8); // addiu t7, r0, 8
c->multu3(a3, a3, t7); // multu3 a3, a3, t7
c->lui(t3, 1280); // lui t3, 1280
c->lui(t4, 27648); // lui t4, 27648
c->dsll32(t2, t2, 0); // dsll32 t2, t2, 0
c->dsll32(t4, t4, 0); // dsll32 t4, t4, 0
c->daddu(t4, t4, t3); // daddu t4, t4, t3
c->daddu(t3, t2, t3); // daddu t3, t2, t3
c->daddiu(t3, t3, 1); // daddiu t3, t3, 1
c->daddu(a0, a3, a0); // daddu a0, a3, a0
c->pcpyld(t2, t2, r0); // pcpyld t2, t2, r0
c->lw(t7, 24, a0); // lw t7, 24(a0)
c->pcpyld(t3, t3, r0); // pcpyld t3, t3, r0
c->pcpyld(t4, t4, r0); // pcpyld t4, t4, r0
c->mov64(a0, a2); // or a0, a2, r0
c->lui(t5, 12288); // lui t5, 12288
c->lui(t6, 4096); // lui t6, 4096
c->daddiu(t5, t5, 7); // daddiu t5, t5, 7
c->lui(t9, 5120); // lui t9, 5120
c->lui(a3, 27655); // lui a3, 27655
c->daddu(t8, t9, t8); // daddu t8, t9, t8
c->dsll32(a3, a3, 0); // dsll32 a3, a3, 0
c->dsll32(t9, t8, 0); // dsll32 t9, t8, 0
c->pcpyld(t5, a3, t5); // pcpyld t5, a3, t5
c->lwu(t8, 52, t7); // lwu t8, 52(t7)
c->pcpyld(t6, t9, t6); // pcpyld t6, t9, t6
c->daddiu(t9, t7, 108); // daddiu t9, t7, 108
c->load_symbol(a3, cache.merc_bucket_info); // lw a3, *merc-bucket-info*(s7)
c->daddiu(ra, a3, 124); // daddiu ra, a3, 124
block_1:
c->lbu(gp, 4, ra); // lbu gp, 4(ra)
c->load_symbol(a3, cache.merc_global_stats); // lw a3, *merc-global-stats*(s7)
c->daddu(a3, r0, a3); // daddu a3, r0, a3
bc = c->sgpr64(gp) != 0; // bne gp, r0, L77
c->lhu(s4, 2, a3); // lhu s4, 2(a3)
if (bc) {goto block_11;} // branch non-likely
c->lhu(s3, 18, t9); // lhu s3, 18(t9)
c->lwu(gp, 4, a3); // lwu gp, 4(a3)
c->lhu(s5, 22, t9); // lhu s5, 22(t9)
c->daddu(s4, s4, s3); // daddu s4, s4, s3
c->lwu(s3, 8, a3); // lwu s3, 8(a3)
c->lhu(s2, 24, t9); // lhu s2, 24(t9)
c->daddu(gp, gp, s5); // daddu gp, gp, s5
c->sh(s4, 2, a3); // sh s4, 2(a3)
c->sw(gp, 4, a3); // sw gp, 4(a3)
c->daddu(s5, s3, s2); // daddu s5, s3, s2
c->lwu(t2, 0, t9); // lwu t2, 0(t9)
c->lwu(gp, 4, t9); // lwu gp, 4(t9)
c->lui(s4, 12288); // lui s4, 12288
c->dsll32(t2, t2, 0); // dsll32 t2, t2, 0
c->sw(s5, 8, a3); // sw s5, 8(a3)
c->or_(t2, t2, s4); // or t2, t2, s4
c->addiu(s5, r0, 0); // addiu s5, r0, 0
c->lhu(s4, 18, t9); // lhu s4, 18(t9)
block_3:
c->lbu(s0, 0, gp); // lbu s0, 0(gp)
// nop // sll r0, r0, 0
c->lbu(s2, 1, gp); // lbu s2, 1(gp)
c->xori(s1, r0, 49292); // xori s1, r0, 49292
c->lbu(s3, 2, gp); // lbu s3, 2(gp)
c->daddiu(v0, s0, 3); // daddiu v0, s0, 3
c->lw(a3, 44, t7); // lw a3, 44(t7)
c->srl(v0, v0, 2); // srl v0, v0, 2
c->sq(t0, 0, a2); // sq t0, 0(a2)
c->xor_(t2, t2, v0); // xor t2, t2, v0
c->sq(t2, 32, a2); // sq t2, 32(a2)
c->xor_(t2, t2, v0); // xor t2, t2, v0
c->sh(s1, 44, a2); // sh s1, 44(a2)
c->daddu(s1, s1, s0); // daddu s1, s1, s0
c->sb(s0, 46, a2); // sb s0, 46(a2)
c->dsll32(s0, v0, 4); // dsll32 s0, v0, 4
c->daddu(t3, t2, s0); // daddu t3, t2, s0
c->daddiu(s0, s2, 3); // daddiu s0, s2, 3
c->sw(a3, 12, a2); // sw a3, 12(a2)
c->srl(s0, s0, 2); // srl s0, s0, 2
c->sq(t1, 16, a2); // sq t1, 16(a2)
c->xor_(t3, t3, s0); // xor t3, t3, s0
c->sq(t3, 48, a2); // sq t3, 48(a2)
c->xor_(t3, t3, s0); // xor t3, t3, s0
c->sh(s1, 60, a2); // sh s1, 60(a2)
c->daddu(s1, s1, s2); // daddu s1, s1, s2
c->sb(s2, 62, a2); // sb s2, 62(a2)
c->dsll32(s2, s0, 4); // dsll32 s2, s0, 4
c->sw(a3, 16, a2); // sw a3, 16(a2)
c->daddu(t4, t3, s2); // daddu t4, t3, s2
c->xor_(t4, t4, s3); // xor t4, t4, s3
c->xori(a3, s1, 16384); // xori a3, s1, 16384
c->sq(t4, 64, a2); // sq t4, 64(a2)
c->xor_(t4, t4, s3); // xor t4, t4, s3
c->sb(s3, 78, a2); // sb s3, 78(a2)
c->dsll32(s3, s3, 4); // dsll32 s3, s3, 4
c->sh(a3, 76, a2); // sh a3, 76(a2)
c->daddu(t2, t4, s3); // daddu t2, t4, s3
c->lbu(s3, 3, gp); // lbu s3, 3(gp)
c->daddiu(gp, gp, 4); // daddiu gp, gp, 4
bc = c->sgpr64(s5) != 0; // bne s5, r0, L73
c->daddiu(a2, a2, 80); // daddiu a2, a2, 80
if (bc) {goto block_5;} // branch non-likely
c->sd(t6, 0, a2); // sd t6, 0(a2)
c->addiu(s2, r0, 8); // addiu s2, r0, 8
c->sd(t6, 8, a2); // sd t6, 8(a2)
c->lui(a3, 27656); // lui a3, 27656
c->sb(s2, 0, a2); // sb s2, 0(a2)
c->daddiu(a3, a3, 132); // daddiu a3, a3, 132
c->load_symbol(s2, cache.merc_bucket_info); // lw s2, *merc-bucket-info*(s7)
c->daddu(s2, r0, s2); // daddu s2, r0, s2
c->sw(a3, 12, a2); // sw a3, 12(a2)
c->lq(a3, 0, s2); // lq a3, 0(s2)
c->lq(s1, 16, s2); // lq s1, 16(s2)
c->lq(s0, 32, s2); // lq s0, 32(s2)
c->lq(v0, 48, s2); // lq v0, 48(s2)
c->sq(a3, 16, a2); // sq a3, 16(a2)
c->sq(s1, 32, a2); // sq s1, 32(a2)
c->sq(s0, 48, a2); // sq s0, 48(a2)
c->sq(v0, 64, a2); // sq v0, 64(a2)
c->lq(a3, 64, s2); // lq a3, 64(s2)
c->lq(s1, 80, s2); // lq s1, 80(s2)
c->lq(s0, 96, s2); // lq s0, 96(s2)
c->lui(v0, 16261); // lui v0, 16261
c->lq(s2, 28, t7); // lq s2, 28(t7)
c->daddiu(v0, v0, 619); // daddiu v0, v0, 619
c->sq(a3, 80, a2); // sq a3, 80(a2)
c->lbu(a3, 5, ra); // lbu a3, 5(ra)
c->sq(s1, 96, a2); // sq s1, 96(a2)
c->sq(s0, 112, a2); // sq s0, 112(a2)
c->dsubu(a3, v0, a3); // dsubu a3, v0, a3
c->sq(s2, 128, a2); // sq s2, 128(a2)
c->sw(a3, 28, a2); // sw a3, 28(a2)
c->daddiu(a2, a2, 144); // daddiu a2, a2, 144
block_5:
bc = c->sgpr64(s3) == 0; // beq s3, r0, L75
c->addiu(s2, r0, 128); // addiu s2, r0, 128
if (bc) {goto block_8;} // branch non-likely
c->lbu(a3, 0, gp); // lbu a3, 0(gp)
block_7:
c->multu3(s1, a3, s2); // multu3 s1, a3, s2
c->sq(t5, 0, a2); // sq t5, 0(a2)
c->lbu(s0, 1, gp); // lbu s0, 1(gp)
c->daddiu(gp, gp, 2); // daddiu gp, gp, 2
c->lbu(a3, 0, gp); // lbu a3, 0(gp)
c->daddiu(s3, s3, -1); // daddiu s3, s3, -1
c->sb(s0, 12, a2); // sb s0, 12(a2)
c->daddiu(a2, a2, 16); // daddiu a2, a2, 16
c->daddu(s1, s1, a1); // daddu s1, s1, a1
// nop // sll r0, r0, 0
bc = c->sgpr64(s3) != 0; // bne s3, r0, L74
c->sw(s1, -12, a2); // sw s1, -12(a2)
if (bc) {goto block_7;} // branch non-likely
block_8:
c->sq(t6, 0, a2); // sq t6, 0(a2)
c->daddiu(a2, a2, 16); // daddiu a2, a2, 16
bc = c->sgpr64(s5) != 0; // bne s5, r0, L76
c->daddiu(s5, s5, 1); // daddiu s5, s5, 1
if (bc) {goto block_10;} // branch non-likely
c->mov64(a3, v1); // or a3, v1, r0
c->sb(a3, -4, a2); // sb a3, -4(a2)
block_10:
bc = c->sgpr64(s5) != c->sgpr64(s4); // bne s5, s4, L72
// nop // sll r0, r0, 0
if (bc) {goto block_3;} // branch non-likely
block_11:
c->daddiu(t9, t9, 32); // daddiu t9, t9, 32
c->daddiu(ra, ra, 8); // daddiu ra, ra, 8
c->daddiu(t8, t8, -1); // daddiu t8, t8, -1
bc = c->sgpr64(t8) != 0; // bne t8, r0, L71
// c->lui(a3, 28672); // lui a3, 28672
get_fake_spad_addr(a3, cache.fake_scratchpad_data, 0, c);
if (bc) {goto block_1;} // branch non-likely
c->lw(v1, 220, a3); // lw v1, 220(a3)
bc = c->sgpr64(v1) != 0; // bne v1, r0, L78
// nop // sll r0, r0, 0
if (bc) {goto block_15;} // branch non-likely
bc = c->sgpr64(a2) == c->sgpr64(a0); // beq a2, a0, L78
// nop // sll r0, r0, 0
if (bc) {goto block_15;} // branch non-likely
c->sw(a0, 220, a3); // sw a0, 220(a3)
block_15:
c->mov64(v0, a2); // or v0, a2, r0
c->ld(ra, 0, sp); // ld ra, 0(sp)
c->lq(gp, 112, sp); // lq gp, 112(sp)
c->lq(s5, 96, sp); // lq s5, 96(sp)
c->lq(s4, 80, sp); // lq s4, 80(sp)
c->lq(s3, 64, sp); // lq s3, 64(sp)
c->lq(s2, 48, sp); // lq s2, 48(sp)
c->lq(s1, 32, sp); // lq s1, 32(sp)
c->lq(s0, 16, sp); // lq s0, 16(sp)
//jr ra // jr ra
c->daddiu(sp, sp, 128); // daddiu sp, sp, 128
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
cache.merc_bucket_info = intern_from_c("*merc-bucket-info*").c();
cache.merc_global_stats = intern_from_c("*merc-global-stats*").c();
cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("draw-bones-merc", execute, 512);
}
} // namespace draw_bones_merc
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/kscheme.h"
namespace Mips2C {
namespace draw_bones_check_longest_edge_asm {
struct Cache {
void* math_camera; // *math-camera*
void* fake_scratchpad_data;
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
bool cop1_bc = false;
float acc;
c->daddiu(sp, sp, -16); // daddiu sp, sp, -16
c->sd(fp, 8, sp); // sd fp, 8(sp)
c->mov64(fp, t9); // or fp, t9, r0
// c->lui(at, 28672); // lui at, 28672
get_fake_spad_addr(at, cache.fake_scratchpad_data, 0, c);
c->mov64(v0, s7); // or v0, s7, r0
c->load_symbol(v1, cache.math_camera); // lw v1, *math-camera*(s7)
c->lwc1(f0, 64, a0); // lwc1 f0, 64(a0)
c->lwc1(f7, 176, at); // lwc1 f7, 176(at)
c->lwc1(f3, 180, at); // lwc1 f3, 180(at)
c->lwc1(f6, 184, at); // lwc1 f6, 184(at)
c->lwc1(f4, 136, a0); // lwc1 f4, 136(a0)
c->lwc1(f12, 0, v1); // lwc1 f12, 0(v1)
c->lwc1(f11, 64, v1); // lwc1 f11, 64(v1)
c->mtc1(f1, a1); // mtc1 f1, a1
c->mtc1(f9, r0); // mtc1 f9, r0
c->mtc1(f10, r0); // mtc1 f10, r0
c->mtc1(f2, r0); // mtc1 f2, r0
c->mtc1(f2, r0); // mtc1 f2, r0
c->mtc1(f5, r0); // mtc1 f5, r0
c->mtc1(f8, r0); // mtc1 f8, r0
c->lw_float_constant(a0, 0x3f800000); // lw a0, L168(fp) 1.0
c->mtc1(f5, a0); // mtc1 f5, a0
cop1_bc = c->fprs[f1] < c->fprs[f11]; // c.lt.s f1, f11
bc = cop1_bc; // bc1t L69
// nop // sll r0, r0, 0
if (bc) {goto block_37;} // branch non-likely
c->lwc1(f11, 12, v1); // lwc1 f11, 12(v1)
c->lwc1(f13, 16, v1); // lwc1 f13, 16(v1)
c->muls(f11, f11, f12); // mul.s f11, f11, f12
c->muls(f13, f13, f12); // mul.s f13, f13, f12
c->subs(f14, f6, f4); // sub.s f14, f6, f4
cop1_bc = c->fprs[f12] < c->fprs[f14]; // c.lt.s f12, f14
bc = !cop1_bc; // bc1f L53
c->lwc1(f12, 60, v1); // lwc1 f12, 60(v1)
if (bc) {goto block_3;} // branch non-likely
c->muls(f12, f14, f12); // mul.s f12, f14, f12
cop1_bc = c->fprs[f0] < c->fprs[f12]; // c.lt.s f0, f12
bc = cop1_bc; // bc1t L68
// nop // sll r0, r0, 0
if (bc) {
// fmt::print("pass 1 due to {} {}\n", c->fprs[f0], c->fprs[f12]);
goto block_36;} // branch non-likely
block_3:
c->subs(f14, f3, f4); // sub.s f14, f3, f4
cop1_bc = c->fprs[f13] < c->fprs[f14]; // c.lt.s f13, f14
bc = !cop1_bc; // bc1f L54
c->lwc1(f12, 56, v1); // lwc1 f12, 56(v1)
if (bc) {goto block_5;} // branch non-likely
//beq r0, r0, L55 // beq r0, r0, L55
c->muls(f10, f14, f12); // mul.s f10, f14, f12
goto block_7; // branch always
block_5:
c->adds(f14, f3, f4); // add.s f14, f3, f4
c->negs(f13, f13); // neg.s f13, f13
cop1_bc = c->fprs[f14] < c->fprs[f13]; // c.lt.s f14, f13
bc = !cop1_bc; // bc1f L55
c->negs(f13, f14); // neg.s f13, f14
if (bc) {goto block_7;} // branch non-likely
c->muls(f10, f13, f12); // mul.s f10, f13, f12
block_7:
cop1_bc = c->fprs[f0] < c->fprs[f10]; // c.lt.s f0, f10
bc = cop1_bc; // bc1t L68
// nop // sll r0, r0, 0
if (bc) {
// fmt::print("pass 2 due to {} {}\n", c->fprs[f0], c->fprs[f10]);
goto block_36;} // branch non-likely
c->subs(f12, f7, f4); // sub.s f12, f7, f4
cop1_bc = c->fprs[f11] < c->fprs[f12]; // c.lt.s f11, f12
bc = !cop1_bc; // bc1f L56
c->lwc1(f10, 52, v1); // lwc1 f10, 52(v1)
if (bc) {goto block_10;} // branch non-likely
//beq r0, r0, L57 // beq r0, r0, L57
c->muls(f9, f12, f10); // mul.s f9, f12, f10
goto block_12; // branch always
block_10:
c->adds(f12, f7, f4); // add.s f12, f7, f4
c->negs(f11, f11); // neg.s f11, f11
cop1_bc = c->fprs[f12] < c->fprs[f11]; // c.lt.s f12, f11
bc = !cop1_bc; // bc1f L57
c->negs(f11, f12); // neg.s f11, f12
if (bc) {goto block_12;} // branch non-likely
c->muls(f9, f11, f10); // mul.s f9, f11, f10
block_12:
cop1_bc = c->fprs[f0] < c->fprs[f9]; // c.lt.s f0, f9
bc = cop1_bc; // bc1t L68
// nop // sll r0, r0, 0
if (bc) {
// fmt::print("pass 3 due to {} {}\n", c->fprs[f0], c->fprs[f9]);
goto block_36;} // branch non-likely
c->abss(f14, f7);// Unknown instr: abs.s f14, f7
c->movs(f12, f6); // mov.s f12, f6
acc = c->fprs[f14] * c->fprs[f14]; // Unknown instr: mula.s f14, f14
c->fprs[f15] = acc + c->fprs[f12] * c->fprs[f12]; // Unknown instr: madd.s f15, f12, f12
c->lwc1(f9, 76, v1); // lwc1 f9, 76(v1)
c->lwc1(f13, 80, v1); // lwc1 f13, 80(v1)
c->lwc1(f10, 84, v1); // lwc1 f10, 84(v1)
c->lwc1(f11, 88, v1); // lwc1 f11, 88(v1)
c->fprs[f16] = c->fprs[f5] / (std::sqrt(std::abs(c->fprs[f15]))); // Unknown instr: rsqrt.s f16, f5, f15
c->muls(f15, f14, f16); // mul.s f15, f14, f16
c->muls(f16, f12, f16); // mul.s f16, f12, f16
acc = c->fprs[f9] * c->fprs[f16]; // Unknown instr: mula.s f9, f16
c->fprs[f12] = acc - c->fprs[f13] * c->fprs[f15]; // Unknown instr: msub.s f12, f13, f15
acc = c->fprs[f10] * c->fprs[f16]; // Unknown instr: mula.s f10, f16
c->fprs[f14] = acc - c->fprs[f11] * c->fprs[f15];// Unknown instr: msub.s f14, f11, f15
acc = c->fprs[f9] * c->fprs[f15];// Unknown instr: mula.s f9, f15
c->fprs[f9] = acc + c->fprs[f13] * c->fprs[f16];// Unknown instr: madd.s f9, f13, f16
acc = c->fprs[f10] * c->fprs[f15];// Unknown instr: mula.s f10, f15
c->fprs[f10] = acc + c->fprs[f11] * c->fprs[f16];// Unknown instr: madd.s f10, f11, f16
cop1_bc = c->fprs[f8] < c->fprs[f12]; // c.lt.s f8, f12
bc = cop1_bc; // bc1t L58
// nop // sll r0, r0, 0
if (bc) {goto block_17;} // branch non-likely
cop1_bc = c->fprs[f8] < c->fprs[f14]; // c.lt.s f8, f14
bc = cop1_bc; // bc1t L59
// nop // sll r0, r0, 0
if (bc) {goto block_18;} // branch non-likely
cop1_bc = c->fprs[f8] < c->fprs[f9]; // c.lt.s f8, f9
bc = cop1_bc; // bc1t L60
// nop // sll r0, r0, 0
if (bc) {goto block_19;} // branch non-likely
//beq r0, r0, L62 // beq r0, r0, L62
// nop // sll r0, r0, 0
goto block_23; // branch always
block_17:
//beq r0, r0, L62 // beq r0, r0, L62
c->divs(f2, f1, f10); // div.s f2, f1, f10
goto block_23; // branch always
block_18:
c->negs(f2, f12); // neg.s f2, f12
c->divs(f2, f2, f9); // div.s f2, f2, f9
c->divs(f7, f14, f10); // div.s f7, f14, f10
c->adds(f2, f7, f2); // add.s f2, f7, f2
//beq r0, r0, L62 // beq r0, r0, L62
c->muls(f2, f2, f1); // mul.s f2, f2, f1
goto block_23; // branch always
block_19:
c->subs(f8, f7, f4); // sub.s f8, f7, f4
c->adds(f10, f7, f4); // add.s f10, f7, f4
c->negs(f11, f7); // neg.s f11, f7
cop1_bc = c->fprs[f7] < c->fprs[f8]; // c.lt.s f7, f8
bc = cop1_bc; // bc1t L61
// nop // sll r0, r0, 0
if (bc) {goto block_22;} // branch non-likely
cop1_bc = c->fprs[f10] < c->fprs[f11]; // c.lt.s f10, f11
bc = cop1_bc; // bc1t L61
// nop // sll r0, r0, 0
if (bc) {goto block_22;} // branch non-likely
//beq r0, r0, L62 // beq r0, r0, L62
// nop // sll r0, r0, 0
goto block_23; // branch always
block_22:
c->negs(f2, f12); // neg.s f2, f12
c->muls(f2, f1, f2); // mul.s f2, f1, f2
c->divs(f2, f2, f9); // div.s f2, f2, f9
block_23:
cop1_bc = c->fprs[f0] < c->fprs[f2]; // c.lt.s f0, f2
bc = cop1_bc; // bc1t L68
// nop // sll r0, r0, 0
if (bc) {
// fmt::print("pass 4 due to {} {}\n", c->fprs[f0], c->fprs[f2]);
goto block_36;} // branch non-likely
c->abss(f10, f3);// Unknown instr: abs.s f10, f3
c->movs(f12, f6); // mov.s f12, f6
acc = c->fprs[f10] * c->fprs[f10];// Unknown instr: mula.s f10, f10
c->fprs[f9] = acc + c->fprs[f12] * c->fprs[f12];// Unknown instr: madd.s f9, f12, f12
c->lwc1(f7, 96, v1); // lwc1 f7, 96(v1)
c->lwc1(f8, 100, v1); // lwc1 f8, 100(v1)
c->lwc1(f6, 104, v1); // lwc1 f6, 104(v1)
c->fprs[f5] = c->fprs[f5] / std::sqrt(std::abs(c->fprs[f9])); // Unknown instr: rsqrt.s f5, f5, f9
c->lwc1(f11, 108, v1); // lwc1 f11, 108(v1)
c->mtc1(f9, r0); // mtc1 f9, r0
c->muls(f13, f10, f5); // mul.s f13, f10, f5
c->muls(f14, f12, f5); // mul.s f14, f12, f5
acc = c->fprs[f7] * c->fprs[f14];// Unknown instr: mula.s f7, f14
c->fprs[f10] = acc - c->fprs[f8] * c->fprs[f13];// Unknown instr: msub.s f10, f8, f13
acc = c->fprs[f6] * c->fprs[f14];// Unknown instr: mula.s f6, f14
c->fprs[f12] = acc - c->fprs[f11] * c->fprs[f13];// Unknown instr: msub.s f12, f11, f13
acc = c->fprs[f7] * c->fprs[f13];// Unknown instr: mula.s f7, f13
c->fprs[f5] = acc + c->fprs[f8] * c->fprs[f14];// Unknown instr: madd.s f5, f8, f14
acc = c->fprs[f6] * c->fprs[f13];// Unknown instr: mula.s f6, f13
c->fprs[f6] = acc + c->fprs[f11] * c->fprs[f14];// Unknown instr: madd.s f6, f11, f14
cop1_bc = c->fprs[f9] < c->fprs[f10]; // c.lt.s f9, f10
bc = cop1_bc; // bc1t L63
// nop // sll r0, r0, 0
if (bc) {goto block_28;} // branch non-likely
cop1_bc = c->fprs[f9] < c->fprs[f12]; // c.lt.s f9, f12
bc = cop1_bc; // bc1t L64
// nop // sll r0, r0, 0
if (bc) {goto block_29;} // branch non-likely
cop1_bc = c->fprs[f9] < c->fprs[f5]; // c.lt.s f9, f5
bc = cop1_bc; // bc1t L65
// nop // sll r0, r0, 0
if (bc) {goto block_30;} // branch non-likely
//beq r0, r0, L67 // beq r0, r0, L67
// nop // sll r0, r0, 0
goto block_34; // branch always
block_28:
//beq r0, r0, L67 // beq r0, r0, L67
c->divs(f1, f1, f6); // div.s f1, f1, f6
goto block_34; // branch always
block_29:
c->negs(f3, f10); // neg.s f3, f10
c->divs(f3, f3, f5); // div.s f3, f3, f5
c->divs(f4, f12, f6); // div.s f4, f12, f6
c->adds(f3, f4, f3); // add.s f3, f4, f3
//beq r0, r0, L67 // beq r0, r0, L67
c->muls(f1, f3, f1); // mul.s f1, f3, f1
goto block_34; // branch always
block_30:
c->subs(f6, f3, f4); // sub.s f6, f3, f4
c->adds(f4, f3, f4); // add.s f4, f3, f4
c->negs(f7, f3); // neg.s f7, f3
cop1_bc = c->fprs[f3] < c->fprs[f6]; // c.lt.s f3, f6
bc = cop1_bc; // bc1t L66
// nop // sll r0, r0, 0
if (bc) {goto block_33;} // branch non-likely
cop1_bc = c->fprs[f4] < c->fprs[f7]; // c.lt.s f4, f7
bc = cop1_bc; // bc1t L66
// nop // sll r0, r0, 0
if (bc) {goto block_33;} // branch non-likely
//beq r0, r0, L67 // beq r0, r0, L67
// nop // sll r0, r0, 0
goto block_34; // branch always
block_33:
c->negs(f3, f10); // neg.s f3, f10
c->muls(f1, f1, f3); // mul.s f1, f1, f3
c->divs(f1, f1, f5); // div.s f1, f1, f5
block_34:
//fmt::print("check: {} {}\n", c->fprs[f0], c->fprs[f2]);
cop1_bc = c->fprs[f0] < c->fprs[f2]; // c.lt.s f0, f2
bc = cop1_bc; // bc1t L68
// nop // sll r0, r0, 0
if (bc) {
// fmt::print("pass 5 due to {} {}\n", c->fprs[f0], c->fprs[f2]);
goto block_36;} // branch non-likely
//beq r0, r0, L69 // beq r0, r0, L69
// nop // sll r0, r0, 0
goto block_37; // branch always
block_36:
// fmt::print("pass!\n");
c->daddiu(v0, s7, 8); // daddiu v0, s7, #t
block_37:
c->ld(fp, 8, sp); // ld fp, 8(sp)
//jr ra // jr ra
c->daddiu(sp, sp, 16); // daddiu sp, sp, 16
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
cache.math_camera = intern_from_c("*math-camera*").c();
gLinkedFunctionTable.reg("draw-bones-check-longest-edge-asm", execute, 128);
cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
}
} // namespace draw_bones_check_longest_edge_asm
} // namespace Mips2C
+588
View File
@@ -0,0 +1,588 @@
// clang-format off
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/kscheme.h"
namespace Mips2C {
namespace blerc_execute {
struct Cache {
void* blerc_globals; // *blerc-globals*
void* gsf_buffer; // *gsf-buffer*
void* stats_blerc; // *stats-blerc*
void* flush_cache; // flush-cache
void* fake_scratchpad_data; // *fake-scratchpad-data*
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
u32 call_addr = 0;
u32 madr, sadr, qwc, tadr;
c->daddiu(sp, sp, -96); // daddiu sp, sp, -96
c->sd(ra, 0, sp); // sd ra, 0(sp)
c->sq(s2, 16, sp); // sq s2, 16(sp)
c->sq(s3, 32, sp); // sq s3, 32(sp)
c->sq(s4, 48, sp); // sq s4, 48(sp)
c->sq(s5, 64, sp); // sq s5, 64(sp)
c->sq(gp, 80, sp); // sq gp, 80(sp)
c->load_symbol(v1, cache.blerc_globals); // lw v1, *blerc-globals*(s7)
c->lwu(s5, 0, v1); // lwu s5, 0(v1)
bc = c->sgpr64(s5) == 0; // beq s5, r0, L46
c->mov64(v1, s7); // or v1, s7, r0
if (bc) {goto block_33;} // branch non-likely
c->addiu(v1, r0, 0); // addiu v1, r0, 0
c->addiu(gp, r0, 0); // addiu gp, r0, 0
c->addiu(v1, r0, 0); // addiu v1, r0, 0
c->load_symbol(v1, cache.gsf_buffer); // lw v1, *gsf-buffer*(s7)
c->load_symbol(t9, cache.flush_cache); // lw t9, flush-cache(s7)
c->addiu(a0, r0, 0); // addiu a0, r0, 0
call_addr = c->gprs[t9].du32[0]; // function call:
c->sll(v0, ra, 0); // sll v0, ra, 0
c->jalr(call_addr); // jalr ra, t9
c->addiu(v1, r0, 848); // addiu v1, r0, 848
// c->lui(a0, 28672); // lui a0, 28672
get_fake_spad_addr(a0, cache.fake_scratchpad_data, 0, c);
c->daddu(a1, v1, a0); // daddu a1, v1, a0
c->load_symbol(v1, cache.blerc_globals); // lw v1, *blerc-globals*(s7)
c->daddu(v1, r0, v1); // daddu v1, r0, v1
// nop // sll r0, r0, 0
c->lui(a0, 4096); // lui a0, 4096
// nop // sll r0, r0, 0
c->ori(a0, a0, 54272); // ori a0, a0, 54272 // spr to
c->andi(a1, a1, 16383); // andi a1, a1, 16383
/*
block_2:
c->lw(a2, 0, a0); // lw a2, 0(a0)
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->andi(a2, a2, 256); // andi a2, a2, 256
// nop // sll r0, r0, 0
bc = c->sgpr64(a2) != 0; // bne a2, r0, L28
c->lw(a2, 0, v1); // lw a2, 0(v1)
if (bc) {goto block_2;} // branch non-likely
*/
c->lw(a2, 0, v1);
bc = c->sgpr64(a2) == 0; // beq a2, r0, L29
//c->sw(a1, 128, a0); // sw a1, 128(a0)
sadr = c->sgpr64(a1);
if (bc) {goto block_5;} // branch non-likely
c->addiu(v1, r0, 324); // addiu v1, r0, 324
//c->sw(a2, 48, a0); // sw a2, 48(a0)
tadr = c->sgpr64(a2);
//c->sw(r0, 32, a0); // sw r0, 32(a0)
// Unknown instr: sync.l
//c->sw(v1, 0, a0); // sw v1, 0(a0)
spad_to_dma_blerc_chain(cache.fake_scratchpad_data, sadr, tadr);
// Unknown instr: sync.l
block_5:
c->gprs[v1].du64[0] = 0; // or v1, r0, r0
//beq r0, r0, L45 // beq r0, r0, L45
// nop // sll r0, r0, 0
goto block_31; // branch always
block_6:
bc = c->sgpr64(gp) != 0; // bne gp, r0, L31
// nop // sll r0, r0, 0
if (bc) {goto block_8;} // branch non-likely
//c->lui(v1, 28672); // lui v1, 28672
get_fake_spad_addr(v1, cache.fake_scratchpad_data, 0, c);
c->daddu(a0, r0, v1); // daddu a0, r0, v1
//beq r0, r0, L32 // beq r0, r0, L32
// nop // sll r0, r0, 0
goto block_9; // branch always
block_8:
c->addiu(v1, r0, 8192); // addiu v1, r0, 8192
// c->lui(a0, 28672); // lui a0, 28672
get_fake_spad_addr(a0, cache.fake_scratchpad_data, 0, c);
c->daddu(a0, v1, a0); // daddu a0, v1, a0
block_9:
bc = c->sgpr64(gp) != 0; // bne gp, r0, L33
// nop // sll r0, r0, 0
if (bc) {goto block_11;} // branch non-likely
c->addiu(v1, r0, 8192); // addiu v1, r0, 8192
// c->lui(a1, 28672); // lui a1, 28672
get_fake_spad_addr(a1, cache.fake_scratchpad_data, 0, c);
c->daddu(a1, v1, a1); // daddu a1, v1, a1
//beq r0, r0, L34 // beq r0, r0, L34
// nop // sll r0, r0, 0
goto block_12; // branch always
block_11:
// c->lui(v1, 28672); // lui v1, 28672
get_fake_spad_addr(v1, cache.fake_scratchpad_data, 0, c);
c->daddu(a1, r0, v1); // daddu a1, r0, v1
block_12:
c->daddiu(v1, a0, 848); // daddiu v1, a0, 848
c->daddu(a2, r0, a0); // daddu a2, r0, a0
c->daddiu(a3, a1, 848); // daddiu a3, a1, 848
c->daddiu(a1, v1, 12); // daddiu a1, v1, 12
// nop // sll r0, r0, 0
c->lui(a2, 4096); // lui a2, 4096
// nop // sll r0, r0, 0
c->ori(a2, a2, 54272); // ori a2, a2, 54272
c->andi(a3, a3, 16383); // andi a3, a3, 16383
/*
block_13:
c->lw(t0, 0, a2); // lw t0, 0(a2)
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->andi(t0, t0, 256); // andi t0, t0, 256
// nop // sll r0, r0, 0
bc = c->sgpr64(t0) != 0; // bne t0, r0, L35
c->lw(t0, 0, a1); // lw t0, 0(a1)
if (bc) {goto block_13;} // branch non-likely
*/
c->lw(t0, 0, a1);
bc = c->sgpr64(t0) == 0; // beq t0, r0, L36
// c->sw(a3, 128, a2); // sw a3, 128(a2)
sadr = c->sgpr64(a3);
if (bc) {goto block_16;} // branch non-likely
c->addiu(a1, r0, 324); // addiu a1, r0, 324
// c->sw(t0, 48, a2); // sw t0, 48(a2)
tadr = c->sgpr64(t0);
// c->sw(r0, 32, a2); // sw r0, 32(a2)
// Unknown instr: sync.l
//c->sw(a1, 0, a2); // sw a1, 0(a2)
// tadr here is bogus, it's reading something uploaded by the other transfer.
spad_to_dma_blerc_chain(cache.fake_scratchpad_data, sadr, tadr);
// Unknown instr: sync.l
block_16:
c->gprs[a1].du64[0] = 0; // or a1, r0, r0
c->mov64(a2, a0); // or a2, a0, r0
c->load_symbol(a3, cache.gsf_buffer); // lw a3, *gsf-buffer*(s7)
c->daddiu(t2, a2, 880); // daddiu t2, a2, 880
c->lb(t1, 0, t2); // lb t1, 0(t2)
// nop // sll r0, r0, 0
c->mov64(t0, a2); // or t0, a2, r0
c->lw(a1, 868, a2); // lw a1, 868(a2)
c->daddiu(t3, t1, 1); // daddiu t3, t1, 1
c->mov64(t1, a3); // or t1, a3, r0
c->sll(t8, t3, 4); // sll t8, t3, 4
c->sll(t3, a1, 4); // sll t3, a1, 4
c->daddu(t9, t3, a3); // daddu t9, t3, a3
c->daddu(t3, t2, t8); // daddu t3, t2, t8
bc = c->sgpr64(a1) == 0; // beq a1, r0, L39
c->daddiu(ra, t2, 16); // daddiu ra, t2, 16
if (bc) {goto block_21;} // branch non-likely
c->lh(t5, 12, t3); // lh t5, 12(t3)
c->daddu(t2, t3, t8); // daddu t2, t3, t8
//beq r0, r0, L38 // beq r0, r0, L38
// nop // sll r0, r0, 0
goto block_19; // branch always
block_18:
c->lh(t5, 12, t2); // lh t5, 12(t2)
c->daddu(t2, t2, t8); // daddu t2, t2, t8
c->sq(t6, 0, t1); // sq t6, 0(t1)
c->daddiu(t1, t1, 16); // daddiu t1, t1, 16
block_19:
c->pcpyh(t5, t5); // pcpyh t5, t5
c->mfc1(r0, f31); // mfc1 r0, f31
//fmt::print("loop: {:x} {:x}\n", c->sgpr64(t1), c->sgpr64(t9));
bc = c->sgpr64(t1) != c->sgpr64(t9); // bne t1, t9, L37
c->pcpyld(t6, t5, t5); // pcpyld t6, t5, t5
if (bc) {goto block_18;} // branch non-likely
c->dsubu(t3, t2, t8); // dsubu t3, t2, t8
// nop // sll r0, r0, 0
block_21:
c->addiu(t1, r0, 255); // addiu t1, r0, 255
c->addiu(t2, r0, 8192); // addiu t2, r0, 8192
c->lb(s5, 0, t3); // lb s5, 0(t3)
c->daddiu(s4, t3, 16); // daddiu s4, t3, 16
c->pcpyh(t1, t1); // pcpyh t1, t1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(t1, t1, t1); // pcpyld t1, t1, t1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyh(t2, t2); // pcpyh t2, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(t2, t2, t2); // pcpyld t2, t2, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->mov128_gpr_gpr(t3, t1); // por t3, t1, r0
c->mfc1(r0, f31); // mfc1 r0, f31
c->mov128_gpr_gpr(t4, r0); // por t4, r0, r0
c->mfc1(r0, f31); // mfc1 r0, f31
block_22:
c->ld(t6, 0, ra); // ld t6, 0(ra)
c->daddu(s2, ra, t8); // daddu s2, ra, t8
c->daddiu(ra, ra, 8); // daddiu ra, ra, 8
c->mov64(s3, a3); // or s3, a3, r0
c->pextlb(t6, r0, t6); // pextlb t6, r0, t6
c->mfc1(r0, f31); // mfc1 r0, f31
c->pmulth(t7, t6, t2); // pmulth t7, t6, t2
c->ld(t5, 0, s2); // ld t5, 0(s2)
c->daddiu(s5, s5, -1); // daddiu s5, s5, -1
// nop // sll r0, r0, 0
//beq r0, r0, L42 // beq r0, r0, L42
c->daddu(s2, s2, t8); // daddu s2, s2, t8
goto block_24; // branch always
block_23:
c->pmaddh(t7, t5, t6); // pmaddh t7, t5, t6
c->ld(t5, 0, s2); // ld t5, 0(s2)
c->daddu(s2, s2, t8); // daddu s2, s2, t8
c->daddiu(s3, s3, 16); // daddiu s3, s3, 16
block_24:
c->lq(t6, 0, s3); // lq t6, 0(s3)
c->pextlb(t5, t5, r0); // pextlb t5, t5, r0
bc = c->sgpr64(s3) != c->sgpr64(t9); // bne s3, t9, L41
c->psrah(t5, t5, 8); // psrah t5, t5, 8
if (bc) {goto block_23;} // branch non-likely
//todo // Unknown instr: pmfhl.uw t5
c->gprs[t5].du32[0] = c->lo.du32[1];
c->gprs[t5].du32[1] = c->hi.du32[1];
c->gprs[t5].du32[2] = c->lo.du32[3];
c->gprs[t5].du32[3] = c->hi.du32[3];
c->mfc1(r0, f31); // mfc1 r0, f31
c->psraw(t7, t7, 13); // psraw t7, t7, 13
c->mfc1(r0, f31); // mfc1 r0, f31
c->psraw(t5, t5, 13); // psraw t5, t5, 13
c->mfc1(r0, f31); // mfc1 r0, f31
c->pinteh(t5, t5, t7); // pinteh t5, t5, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->pminh(t3, t3, t5); // pminh t3, t3, t5
c->mfc1(r0, f31); // mfc1 r0, f31
c->pmaxh(t4, t4, t5); // pmaxh t4, t4, t5
c->mfc1(r0, f31); // mfc1 r0, f31
c->pminh(t5, t5, t1); // pminh t5, t5, t1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pmaxh(t5, t5, r0); // pmaxh t5, t5, r0
c->lq(t7, 0, s4); // lq t7, 0(s4)
c->ppacb(t5, r0, t5); // ppacb t5, r0, t5
c->mfc1(r0, f31); // mfc1 r0, f31
c->ppach(t7, r0, t7); // ppach t7, r0, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlh(t5, t5, t7); // pextlh t5, t5, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->sq(t5, 0, t0); // sq t5, 0(t0)
c->daddiu(t0, t0, 16); // daddiu t0, t0, 16
bc = c->sgpr64(s5) != 0; // bne s5, r0, L40
c->daddiu(s4, s4, 16); // daddiu s4, s4, 16
if (bc) {goto block_22;} // branch non-likely
c->load_symbol(a3, cache.stats_blerc); // lw a3, *stats-blerc*(s7)
bc = c->sgpr64(a3) == c->sgpr64(s7); // beq a3, s7, L43
c->load_symbol(a3, cache.blerc_globals); // lw a3, *blerc-globals*(s7)
if (bc) {goto block_28;} // branch non-likely
c->lw(t2, 12, a3); // lw t2, 12(a3)
c->lw(t1, 16, a3); // lw t1, 16(a3)
c->lw(t0, 20, a3); // lw t0, 20(a3)
c->lw(a2, 864, a2); // lw a2, 864(a2)
c->multu3(a1, a1, a2); // multu3 a1, a1, a2
c->daddiu(t2, t2, 1); // daddiu t2, t2, 1
c->daddu(a2, t1, a2); // daddu a2, t1, a2
c->daddu(a1, t0, a1); // daddu a1, t0, a1
c->sw(t2, 12, a3); // sw t2, 12(a3)
c->sw(a2, 16, a3); // sw a2, 16(a3)
c->sw(a1, 20, a3); // sw a1, 20(a3)
c->pcpyud(a1, t3, r0); // pcpyud a1, t3, r0
c->pminh(t3, t3, a1); // pminh t3, t3, a1
c->dsrl32(a1, t3, 0); // dsrl32 a1, t3, 0
c->pminh(t3, t3, a1); // pminh t3, t3, a1
c->dsrl(t3, t3, 16); // dsrl t3, t3, 16
c->lh(a1, 8, a3); // lh a1, 8(a3)
c->pminh(t3, t3, a1); // pminh t3, t3, a1
c->sh(t3, 8, a3); // sh t3, 8(a3)
c->pcpyud(a1, t4, r0); // pcpyud a1, t4, r0
c->pmaxh(t4, t4, a1); // pmaxh t4, t4, a1
c->dsrl32(a1, t4, 0); // dsrl32 a1, t4, 0
c->pmaxh(t4, t4, a1); // pmaxh t4, t4, a1
c->dsrl(t4, t4, 16); // dsrl t4, t4, 16
c->lh(a1, 10, a3); // lh a1, 10(a3)
c->pmaxh(t4, t4, a1); // pmaxh t4, t4, a1
c->sh(t4, 10, a3); // sh t4, 10(a3)
block_28:
c->gprs[a1].du64[0] = 0; // or a1, r0, r0
c->lwu(a1, 872, a0); // lwu a1, 872(a0)
c->mov64(a3, a0); // or a3, a0, r0
c->lwu(a0, 876, a0); // lwu a0, 876(a0)
c->lui(a2, 4096); // lui a2, 4096
// nop // sll r0, r0, 0
c->ori(a2, a2, 53248); // ori a2, a2, 53248
c->andi(a3, a3, 16383); // andi a3, a3, 16383
/*
block_29:
c->lw(t0, 0, a2); // lw t0, 0(a2)
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->andi(t0, t0, 256); // andi t0, t0, 256
// nop // sll r0, r0, 0
bc = c->sgpr64(t0) != 0; // bne t0, r0, L44
// nop // sll r0, r0, 0
if (bc) {goto block_29;} // branch non-likely
*/
// c->sw(a3, 128, a2); // sw a3, 128(a2)
sadr = c->sgpr64(a3);
c->addiu(a3, r0, 256); // addiu a3, r0, 256
// c->sw(a1, 16, a2); // sw a1, 16(a2)
madr = c->sgpr64(a1);
// nop // sll r0, r0, 0
// c->sw(a0, 32, a2); // sw a0, 32(a2)
qwc = c->sgpr64(a0);
// Unknown instr: sync.l
// c->sw(a3, 0, a2); // sw a3, 0(a2)
spad_from_dma_no_sadr_off(cache.fake_scratchpad_data, madr, sadr, qwc);
// Unknown instr: sync.l
c->gprs[a0].du64[0] = 0; // or a0, r0, r0
c->addiu(a0, r0, 1); // addiu a0, r0, 1
c->dsubu(gp, a0, gp); // dsubu gp, a0, gp
c->lwu(s5, 12, v1); // lwu s5, 12(v1)
c->mov64(v1, s5); // or v1, s5, r0
block_31:
bc = c->sgpr64(s5) != 0; // bne s5, r0, L30
// nop // sll r0, r0, 0
if (bc) {goto block_6;} // branch non-likely
c->mov64(v1, s7); // or v1, s7, r0
block_33:
c->gprs[v0].du64[0] = 0; // or v0, r0, r0
c->ld(ra, 0, sp); // ld ra, 0(sp)
c->lq(gp, 80, sp); // lq gp, 80(sp)
c->lq(s5, 64, sp); // lq s5, 64(sp)
c->lq(s4, 48, sp); // lq s4, 48(sp)
c->lq(s3, 32, sp); // lq s3, 32(sp)
c->lq(s2, 16, sp); // lq s2, 16(sp)
//jr ra // jr ra
c->daddiu(sp, sp, 96); // daddiu sp, sp, 96
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
cache.blerc_globals = intern_from_c("*blerc-globals*").c();
cache.gsf_buffer = intern_from_c("*gsf-buffer*").c();
cache.stats_blerc = intern_from_c("*stats-blerc*").c();
cache.flush_cache = intern_from_c("flush-cache").c();
cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("blerc-execute", execute, 256);
}
} // namespace blerc_execute
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
#include "game/kernel/kscheme.h"
namespace Mips2C {
namespace setup_blerc_chains_for_one_fragment {
struct Cache {
void* blerc_globals; // *blerc-globals*
void* fake_scratchpad_data; // *fake-scratchpad-data*
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
c->daddiu(sp, sp, -128); // daddiu sp, sp, -128
c->sd(ra, 0, sp); // sd ra, 0(sp)
c->sq(s0, 16, sp); // sq s0, 16(sp)
c->sq(s1, 32, sp); // sq s1, 32(sp)
c->sq(s2, 48, sp); // sq s2, 48(sp)
c->sq(s3, 64, sp); // sq s3, 64(sp)
c->sq(s4, 80, sp); // sq s4, 80(sp)
c->sq(s5, 96, sp); // sq s5, 96(sp)
c->sq(gp, 112, sp); // sq gp, 112(sp)
c->lb(v1, 0, t0); // lb v1, 0(t0)
c->addiu(t2, r0, 0); // addiu t2, r0, 0
c->mov128_gpr_gpr(t7, r0); // por t7, r0, r0
c->load_symbol(t3, cache.blerc_globals); // lw t3, *blerc-globals*(s7)
c->lw(t3, 4, t3); // lw t3, 4(t3)
c->mov64(t4, v1); // or t4, v1, r0
block_1:
c->lui(t7, 4096); // lui t7, 4096
// nop // sll r0, r0, 0
c->daddiu(t7, t7, 1); // daddiu t7, t7, 1
// nop // sll r0, r0, 0
bc = c->sgpr64(t3) == 0; // beq t3, r0, L11
c->sq(t7, 0, a2); // sq t7, 0(a2)
if (bc) {goto block_3;} // branch non-likely
c->sw(a2, 12, t3); // sw a2, 12(t3)
// nop // sll r0, r0, 0
block_3:
c->mov64(t3, a2); // or t3, a2, r0
c->daddu(t6, t4, t4); // daddu t6, t4, t4
c->daddu(t5, v1, v1); // daddu t5, v1, v1
c->daddu(t6, t6, t4); // daddu t6, t6, t4
c->daddu(t7, t5, v1); // daddu t7, t5, v1
c->daddu(t5, t6, t6); // daddu t5, t6, t6
c->daddu(t6, t7, t7); // daddu t6, t7, t7
c->daddu(t7, t5, t5); // daddu t7, t5, t5
c->daddiu(t6, t6, 15); // daddiu t6, t6, 15
c->daddiu(t5, t5, 15); // daddiu t5, t5, 15
c->andi(t6, t6, 65520); // andi t6, t6, 65520
c->dsrl(t5, t5, 4); // dsrl t5, t5, 4
c->daddu(t8, t2, t2); // daddu t8, t2, t2
c->daddiu(t7, t7, 15); // daddiu t7, t7, 15
c->daddu(t9, t8, t2); // daddu t9, t8, t2
c->dsrl(t8, t7, 4); // dsrl t8, t7, 4
c->daddu(ra, t9, t9); // daddu ra, t9, t9
c->addiu(t9, r0, 0); // addiu t9, r0, 0
c->daddu(t7, ra, ra); // daddu t7, ra, ra
c->daddiu(s3, a2, 32); // daddiu s3, a2, 32
c->daddu(s2, ra, a3); // daddu s2, ra, a3
c->daddu(ra, t7, t1); // daddu ra, t7, t1
c->lui(t7, 12288); // lui t7, 12288
c->daddiu(gp, a0, -1); // daddiu gp, a0, -1
c->daddu(t7, t7, t5); // daddu t7, t7, t5
c->mov64(s5, a1); // or s5, a1, r0
c->sq(t7, 0, s3); // sq t7, 0(s3)
c->daddiu(s4, t0, 2); // daddiu s4, t0, 2
c->sw(s2, 4, s3); // sw s2, 4(s3)
c->daddu(s2, s2, t6); // daddu s2, s2, t6
c->daddiu(s3, s3, 16); // daddiu s3, s3, 16
// nop // sll r0, r0, 0
block_4:
c->lb(s1, 0, s4); // lb s1, 0(s4)
c->daddiu(s4, s4, 1); // daddiu s4, s4, 1
c->lh(s0, 0, s5); // lh s0, 0(s5)
c->daddiu(s5, s5, 2); // daddiu s5, s5, 2
bc = c->sgpr64(s1) == 0; // beq s1, r0, L13
c->sq(t7, 0, s3); // sq t7, 0(s3)
if (bc) {goto block_7;} // branch non-likely
c->sw(s2, 4, s3); // sw s2, 4(s3)
c->daddu(s2, s2, t6); // daddu s2, s2, t6
bc = c->sgpr64(s0) == 0; // beq s0, r0, L13
c->sw(s0, 12, s3); // sw s0, 12(s3) no
if (bc) {goto block_7;} // branch non-likely
c->daddiu(s3, s3, 16); // daddiu s3, s3, 16
c->daddiu(t9, t9, 1); // daddiu t9, t9, 1
block_7:
bc = c->sgpr64(gp) != 0; // bne gp, r0, L12
c->daddiu(gp, gp, -1); // daddiu gp, gp, -1
if (bc) {goto block_4;} // branch non-likely
c->sq(t7, 0, s3); // sq t7, 0(s3)
c->mov128_gpr_gpr(t6, r0); // por t6, r0, r0
c->sw(ra, 4, s3); // sw ra, 4(s3)
// c->lui(t6, 28672); // lui t6, 28672
get_fake_spad_addr(t6, cache.fake_scratchpad_data, 0, c);
c->sb(t8, 0, s3); // sb t8, 0(s3)
// nop // sll r0, r0, 0
c->sq(t6, 16, s3); // sq t6, 16(s3)
c->daddiu(t6, s3, 32); // daddiu t6, s3, 32
c->sw(t9, 20, a2); // sw t9, 20(a2)
// nop // sll r0, r0, 0
c->sw(t4, 16, a2); // sw t4, 16(a2)
// nop // sll r0, r0, 0
c->sw(ra, 24, a2); // sw ra, 24(a2)
// nop // sll r0, r0, 0
c->sw(t8, 28, a2); // sw t8, 28(a2)
// nop // sll r0, r0, 0
bc = c->sgpr64(t4) != c->sgpr64(v1); // bne t4, v1, L14
c->daddiu(t5, t5, 1); // daddiu t5, t5, 1
if (bc) {goto block_11;} // branch non-likely
c->daddiu(t7, t9, 3); // daddiu t7, t9, 3
c->multu3(t5, t5, t7); // multu3 t5, t5, t7
c->daddiu(t5, t5, -457); // daddiu t5, t5, -457
// nop // sll r0, r0, 0
bc = ((s64)c->sgpr64(t5)) <= 0; // blez t5, L14
// nop // sll r0, r0, 0
if (bc) {goto block_11;} // branch non-likely
//beq r0, r0, L10 // beq r0, r0, L10
c->addiu(t4, r0, 24); // addiu t4, r0, 24
goto block_1; // branch always
block_11:
c->mov64(a2, t6); // or a2, t6, r0
c->daddu(t2, t2, t4); // daddu t2, t2, t4
bc = c->sgpr64(t2) == c->sgpr64(v1); // beq t2, v1, L15
c->daddu(t5, t2, t4); // daddu t5, t2, t4
if (bc) {goto block_14;} // branch non-likely
c->dsubu(t5, t5, v1); // dsubu t5, t5, v1
// nop // sll r0, r0, 0
bc = ((s64)c->sgpr64(t5)) <= 0; // blez t5, L10
// nop // sll r0, r0, 0
if (bc) {goto block_1;} // branch non-likely
//beq r0, r0, L10 // beq r0, r0, L10
c->dsubu(t4, v1, t2); // dsubu t4, v1, t2
goto block_1; // branch always
block_14:
c->load_symbol(v1, cache.blerc_globals); // lw v1, *blerc-globals*(s7)
c->sw(t3, 4, v1); // sw t3, 4(v1)
c->mov64(v0, a2); // or v0, a2, r0
c->ld(ra, 0, sp); // ld ra, 0(sp)
c->lq(gp, 112, sp); // lq gp, 112(sp)
c->lq(s5, 96, sp); // lq s5, 96(sp)
c->lq(s4, 80, sp); // lq s4, 80(sp)
c->lq(s3, 64, sp); // lq s3, 64(sp)
c->lq(s2, 48, sp); // lq s2, 48(sp)
c->lq(s1, 32, sp); // lq s1, 32(sp)
c->lq(s0, 16, sp); // lq s0, 16(sp)
//jr ra // jr ra
c->daddiu(sp, sp, 128); // daddiu sp, sp, 128
goto end_of_function; // return
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
cache.blerc_globals = intern_from_c("*blerc-globals*").c();
gLinkedFunctionTable.reg("setup-blerc-chains-for-one-fragment", execute, 256);
cache.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
}
} // namespace setup_blerc_chains_for_one_fragment
} // namespace Mips2C
+59 -6
View File
@@ -8,6 +8,7 @@
#include "common/util/BitUtils.h"
#include "third-party/fmt/core.h"
#include "common/util/assert.h"
#include "common/dma/dma.h"
// This file contains utility functions for code generated by the mips2c pass.
// This is only useful for
@@ -485,7 +486,7 @@ struct ExecutionContext {
}
void pmulth(int rd, int rs, int rt) {
assert(rd == 0);
// assert(rd == 0);
s32 temp;
auto s = gpr_src(rs);
@@ -493,59 +494,70 @@ struct ExecutionContext {
temp = (s32)s.ds16[0] * (s32)t.ds16[0];
lo.du32[0] = temp;
/*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[0] = temp;*/
if (rd)
gprs[rd].du32[0] = temp;
temp = (s32)s.ds16[1] * (s32)t.ds16[1];
lo.du32[1] = temp;
temp = (s32)s.ds16[2] * (s32)t.ds16[2];
hi.du32[0] = temp;
/*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[1] = temp;*/
if (rd)
gprs[rd].du32[1] = temp;
temp = (s32)s.ds16[3] * (s32)t.ds16[3];
hi.du32[1] = temp;
temp = (s32)s.ds16[4] * (s32)t.ds16[4];
lo.du32[2] = temp;
/*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[2] = temp;*/
if (rd)
gprs[rd].du32[2] = temp;
temp = (s32)s.ds16[5] * (s32)t.ds16[5];
lo.du32[3] = temp;
temp = (s32)s.ds16[6] * (s32)t.ds16[6];
hi.du32[2] = temp;
/*if (_Rd_) cpuRegs.GPR.r[_Rd_].UL[3] = temp;*/
if (rd)
gprs[rd].du32[3] = temp;
temp = (s32)s.ds16[7] * (s32)t.ds16[7];
hi.du32[3] = temp;
}
void pmaddh(int rd, int rs, int rt) {
assert(rd == 0);
s32 temp;
auto s = gpr_src(rs);
auto t = gpr_src(rt);
temp = lo.du32[0] + (s32)s.ds16[0] * (s32)t.ds16[0];
lo.du32[0] = temp;
if (rd)
gprs[rd].du32[0] = temp;
temp = lo.du32[1] + (s32)s.ds16[1] * (s32)t.ds16[1];
lo.du32[1] = temp;
temp = hi.du32[0] + (s32)s.ds16[2] * (s32)t.ds16[2];
hi.du32[0] = temp;
if (rd)
gprs[rd].du32[1] = temp;
temp = hi.du32[1] + (s32)s.ds16[3] * (s32)t.ds16[3];
hi.du32[1] = temp;
temp = lo.du32[2] + (s32)s.ds16[4] * (s32)t.ds16[4];
lo.du32[2] = temp;
if (rd)
gprs[rd].du32[2] = temp;
temp = lo.du32[3] + (s32)s.ds16[5] * (s32)t.ds16[5];
lo.du32[3] = temp;
temp = hi.du32[2] + (s32)s.ds16[6] * (s32)t.ds16[6];
hi.du32[2] = temp;
if (rd)
gprs[rd].du32[3] = temp;
temp = hi.du32[3] + (s32)s.ds16[7] * (s32)t.ds16[7];
hi.du32[3] = temp;
@@ -858,6 +870,12 @@ struct ExecutionContext {
}
void mult3(int dst, int src0, int src1) {
u32 result = gpr_src(src0).ds32[0] * gpr_src(src1).ds32[0];
s32 sresult = result;
gprs[dst].ds64[0] = sresult;
}
void multu3(int dst, int src0, int src1) {
u32 result = gpr_src(src0).du32[0] * gpr_src(src1).du32[0];
s32 sresult = result;
gprs[dst].ds64[0] = sresult;
@@ -942,6 +960,33 @@ struct ExecutionContext {
}
}
void pmaxh(int dst, int src0, int src1) {
auto s0 = gpr_src(src0);
auto s1 = gpr_src(src1);
for (int i = 0; i < 8; i++) {
gprs[dst].ds16[i] = std::max(s0.ds16[i], s1.ds16[i]);
}
}
void pcpyh(int dst, int src) {
auto s0 = gpr_src(src);
gprs[dst].du16[0] = s0.du16[0];
gprs[dst].du16[1] = s0.du16[0];
gprs[dst].du16[2] = s0.du16[0];
gprs[dst].du16[3] = s0.du16[0];
gprs[dst].du16[4] = s0.du16[4];
gprs[dst].du16[5] = s0.du16[4];
gprs[dst].du16[6] = s0.du16[4];
gprs[dst].du16[7] = s0.du16[4];
}
void psrah(int dest, int src, int sa) {
auto s = gpr_src(src);
for (int i = 0; i < 8; i++) {
gprs[dest].ds16[i] = s.ds16[i] >> (sa & 0xf);
}
}
void mov128_vf_gpr(int dst, int src) { vfs[dst] = gpr_src(src); }
void mov128_gpr_vf(int dst, int src) { gprs[dst] = vf_src(src); }
void mov128_gpr_gpr(int dst, int src) { gprs[dst] = gpr_src(src); }
@@ -1026,6 +1071,7 @@ struct ExecutionContext {
}
void movs(int dst, int src) { fprs[dst] = fprs[src]; }
void abss(int dst, int src) { fprs[dst] = std::abs(fprs[src]); }
void cvtws(int dst, int src) {
// float to int
@@ -1167,4 +1213,11 @@ inline void load_vfs_from_tf_regs(const void* tf_regs_sym, ExecutionContext* c)
u8* c_addr_of_vf1 = g_ee_main_mem + goal_addr_of_vf1;
memcpy(&c->vfs[1], c_addr_of_vf1, 31 * 16);
}
inline void spad_to_dma_blerc_chain(void* spad_sym_addr, u32 sadr, u32 tadr) {
u32 spad_addr_goal;
memcpy(&spad_addr_goal, spad_sym_addr, 4);
void* spad_addr_c = g_ee_main_mem + spad_addr_goal;
emulate_dma(g_ee_main_mem, spad_addr_c, tadr, sadr);
}
} // namespace Mips2C
+15 -1
View File
@@ -212,6 +212,18 @@ extern void link();
namespace cspace_parented_transformq_joint {
extern void link();
}
namespace draw_bones_merc {
extern void link();
}
namespace draw_bones_check_longest_edge_asm {
extern void link();
}
namespace blerc_execute {
extern void link();
}
namespace setup_blerc_chains_for_one_fragment {
extern void link();
}
LinkedFunctionTable gLinkedFunctionTable;
Rng gRng;
std::unordered_map<std::string, std::vector<void (*)()>> gMips2CLinkCallbacks = {
@@ -245,7 +257,9 @@ std::unordered_map<std::string, std::vector<void (*)()>> gMips2CLinkCallbacks =
{method_16_collide_edge_work::link, method_15_collide_edge_work::link,
method_10_collide_edge_hold_list::link, method_18_collide_edge_work::link}},
{"joint", {calc_animation_from_spr::link, cspace_parented_transformq_joint::link}},
{"bones", {bones_mtx_calc::link}}};
{"bones",
{bones_mtx_calc::link, draw_bones_merc::link, draw_bones_check_longest_edge_asm::link}},
{"merc-blend-shape", {blerc_execute::link, setup_blerc_chains_for_one_fragment::link}}};
void LinkedFunctionTable::reg(const std::string& name, u64 (*exec)(void*), u32 stack_size) {
const auto& it = m_executes.insert({name, {exec, Ptr<u8>()}});
+432 -4
View File
@@ -656,10 +656,16 @@
)
)
(define-extern draw-bones (function draw-control dma-buffer float none))
;; draw-bones-shadow
;; draw-bones-generic-merc
;; draw-boes-merc
;; draw-bones-check-longest-edge
;; draw-bones-check-longest-edgei-asm
;; draw-bones
;; draw-bones-hud
;; HACK incomplete:
(defun draw-bones ((arg0 draw-control) (arg1 dma-buffer) (arg2 float))
(defun draw-bones-hack ((arg0 draw-control) (arg1 dma-buffer) (arg2 float))
(local-vars
(at-0 object)
(a0-16 int)
@@ -749,8 +755,430 @@
)))
(none))
(def-mips2c draw-bones-merc (function draw-control object object int int pointer))
(def-mips2c draw-bones-check-longest-edge-asm (function draw-control float symbol))
(defun draw-bones ((arg0 draw-control) (dma-buf dma-buffer) (arg2 float))
"Main draw function for all bone-related renderers. Will set up merc, generic and shadow.
and also add the bones to the calculation list."
(local-vars (a0-16 int) (a0-17 int) (a0-62 int) (a2-10 int) (a2-12 int)
(used-merc int) (used-mercneric int) (effect-idx int) (sv-144 ripple-control))
(rlet ((vf1 :class vf) (vf2 :class vf) (vf3 :class vf) (vf4 :class vf) (vf5 :class vf) (vf6 :class vf)
(vf7 :class vf) (vf8 :class vf) (vf9 :class vf) (acc :class vf))
;; compute the number of bones. I believe this num-joints doesn't count align/prejoint/main, so each needs a bone
(let* ((num-bones (+ (-> arg0 mgeo num-joints) 3))
;; we'll use 128-bytes/bone.
(bone-data-size (* num-bones 128))
;; temp work
(spr-work (scratchpad-object terrain-context))
)
;;;;;;;;;;;;;;;;;;;;;;;;;
;; BONE CALC SETUP
;;;;;;;;;;;;;;;;;;;;;;;;;
;; next, grab some DMA data.
;; we'll also use this for storing bone calculation entries.
(let* ((dma-data-start (-> dma-buf base))
;; first qw is the tag, stash the bone-calc-entry right after that.
(bone-calc-entry (the-as bone-calculation (&+ dma-data-start 16)))
;; after that we'll use the space for storing bone matrices.
;; we won't calculate them now, but instead we'll tell the *bone-calculation-list* to put them here later.
(matrix-data (the-as object (&+ dma-data-start 64)))
)
;; align the matrix data to 64 bytes (we know it is at least 16 byte aligned)
(let ((a2-1 (logand (the-as int matrix-data) 48)))
(b! (zero? a2-1) cfg-2 :delay (nop!))
(set! matrix-data (&- (&+ (the-as pointer matrix-data) 64) (the-as uint a2-1)))
)
(label cfg-2)
;; start recording perf stats.
;; this just counts the stats for adding the calculation to the linked list.
;; which is really fast and not worth profiling.
;; I suspect the bone calculation originally was here,
;; but they moved it and forgot to move the performance counters too.
(reset! (-> *perf-stats* data (perf-stat-bucket bones)))
;; figure out where everything will be
(let ((a2-6 (the-as bone-regs (+ 240 (scratchpad-object int)))))
;; the joints are stored in the static art data
(set! (-> a2-6 joint-ptr) (the-as (inline-array joint) (-> arg0 jgeo data 0)))
;; the final bones output used by the rest of the engine is stored in
;; the process-drawable's skeleton
(set! (-> a2-6 bone-ptr) (-> arg0 skeleton bones))
(set! (-> a2-6 num-bones) (the-as uint num-bones))
)
;; Add the bone calculation to the list, to be done later.
;; this will write to both the "matrix data" and the bones array.
(let ((t0-2 matrix-data)
(t1-0 0)
(t4-0 (the-as bone-memory (+ 16 (scratchpad-object int))))
(a2-8 *bone-calculation-list*)
(a3-8 bone-calc-entry)
)
(let ((t2-0 (-> t4-0 work regs joint-ptr))
(t3-0 (-> t4-0 work regs bone-ptr))
(t4-1 (-> t4-0 work regs num-bones))
(t5-0 a3-8)
)
(set! (-> t5-0 flags) (the-as bone-calc-flags t1-0))
(set! (-> t5-0 num-bones) t4-1)
(set! (-> t5-0 matrix-area) (the-as (inline-array matrix) t0-2))
(set! (-> t5-0 joints) t2-0)
(set! (-> t5-0 bones) t3-0)
(set! (-> t5-0 next) (the-as bone-calculation 0))
)
(if (nonzero? (-> a2-8 next))
(set! (-> a2-8 next next) a3-8)
)
(if (zero? (-> a2-8 first))
(set! (-> a2-8 first) a3-8)
)
(set! (-> a2-8 next) a3-8)
)
(&+ bone-calc-entry 48)
;; end stat collection
(read! (-> *perf-stats* data (perf-stat-bucket bones)))
;; set up the dma buffer
(let ((s2-0 (the-as object (+ (the-as uint matrix-data) bone-data-size))))
(let ((a0-2 (shl (the-as int s2-0) 32)))
(set! (-> (the-as (pointer uint128) dma-data-start))
(logior (-> spr-work work foreground bone-mem work next-tag quad) a0-2)
)
;; NOTE: does this work correctly for the upper 64 bits??
)
;; only data-format 1 is supported.
(when (= (-> arg0 data-format) 1)
;; lights should be converted to a single vu-lights already, by the drawing code.
;; it stashes lights on the scratchpad. We'll load these here and transform them.
;; the result goes in the merc-bucke-info.
(let ((v1-6 (the-as vu-lights (+ 64 (scratchpad-object int))))
(a0-7 (-> *merc-bucket-info* light))
)
(let ((a1-8 (-> *math-camera* inv-camera-rot)))
(.lvf vf4 (&-> a1-8 vector 0 quad))
(.lvf vf5 (&-> a1-8 vector 1 quad))
(.lvf vf6 (&-> a1-8 vector 2 quad))
)
(.lvf vf1 (&-> v1-6 direction 0 quad))
(.lvf vf2 (&-> v1-6 direction 1 quad))
(.lvf vf3 (&-> v1-6 direction 2 quad))
;;(.vcallms 54)
;; TODO!
;mulax.xyzw ACC, vf01, vf04
(.mul.x.vf acc vf1 vf4)
;madday.xyzw ACC, vf02, vf04
(.add.mul.y.vf acc vf2 vf4 acc)
;maddz.xyzw vf07, vf03, vf04
(.add.mul.z.vf vf7 vf3 vf4 acc)
;mulax.xyzw ACC, vf01, vf05
(.mul.x.vf acc vf1 vf5)
;madday.xyzw ACC, vf02, vf05
(.add.mul.y.vf acc vf2 vf5 acc)
;maddz.xyzw vf08, vf03, vf05
(.add.mul.z.vf vf8 vf3 vf5 acc)
;mulax.xyzw ACC, vf01, vf06
(.mul.x.vf acc vf1 vf6)
;madday.xyzw ACC, vf02, vf06 :e
(.add.mul.y.vf acc vf2 vf6 acc)
;maddz.xyzw vf09, vf03, vf06
(.add.mul.z.vf vf9 vf3 vf6 acc)
(let ((a1-9 (-> v1-6 color 0 quad)))
(let ((a2-14 (-> v1-6 color 1 quad)))
(let ((a3-11 (-> v1-6 color 2 quad)))
(let ((v1-7 (-> v1-6 ambient quad)))
(set! (-> a0-7 color 0 quad) a1-9)
(set! (-> a0-7 color 1 quad) a2-14)
(set! (-> a0-7 color 2 quad) a3-11)
(set! (-> a0-7 ambient quad) v1-7)
)
)
)
)
(.svf (&-> a0-7 direction 0 quad) vf7)
(.svf (&-> a0-7 direction 1 quad) vf8)
(.svf (&-> a0-7 direction 2 quad) vf9)
(set! (-> a0-7 direction 1 w) (the-as float 0))
)
;; the drawable system's culling already knows if we need clipping or not,
;; we just trust it.
(set! (-> *merc-bucket-info* needs-clip)
(if (logtest? (-> arg0 status) (draw-status needs-clip))
1
0
)
)
;; Now, we need to decide on merc settings. Default to nothing.
(set! used-merc 0)
(set! used-mercneric 0)
(set! (-> *merc-bucket-info* need-mercprime-if-merc) 0)
(set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 0)
(when (logtest? (-> arg0 status) (draw-status needs-clip))
;; we can either clip with "mercprime" (part of merc), or fall back to generic.
;; the generic approach always works, but is slower, so we try to use mercprime.
;; the user must provide a longest edge length, and we must pass an edge check (fails if close to camera)
(cond
((nonzero? (-> arg0 longest-edge))
;; TODO this makes close up things bad...
(if (draw-bones-check-longest-edge-asm arg0 arg2)
(set! (-> *merc-bucket-info* need-mercprime-if-merc) 1) ;; clip with mercprime!
(set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 1) ;; failed, use generic
)
)
(else
(set! (-> *merc-bucket-info* must-use-mercneric-for-clip) 1) ;; no longest edge info, use generic.
)
)
)
;; grab the geometry at the appropriate level of detail.
(let ((geom (-> arg0 lod-set lod (-> arg0 cur-lod) geo)))
;; loop over effects, and set them up/pick renderers.
(set! effect-idx 0)
(while (< effect-idx (the-as int (-> geom header effect-count)))
;; try texture scroll
(when (logtest? (-> geom effect effect-idx effect-bits) 1)
(let* ((v1-35 (-> geom effect effect-idx extra-info))
(v1-36 (the-as mei-texture-scroll (+ (the-as uint v1-35) (* (-> v1-35 texture-scroll-offset) 16))))
)
(if (< arg2 (-> v1-36 max-dist))
;; just add to texscroll list.
(texscroll-make-request (-> geom effect effect-idx))
)
)
)
;; try ripple
(when (logtest? (-> geom effect effect-idx effect-bits) 4)
;; TODO.
; (when (-> arg0 ripple)
; (set! sv-144 (-> arg0 ripple))
; (let* ((f1-4 (/ (- (-> sv-144 far-fade-dist) arg2) (- (-> sv-144 far-fade-dist) (-> sv-144 close-fade-dist))))
; (f1-6 (fmax 0.0 (fmin 1.0 f1-4)))
; (f0-4 f1-6)
; (f30-0 (* f1-6 (-> sv-144 global-scale)))
; )
; (set! (-> sv-144 faded-scale) f30-0)
; (let ((f1-9 (/ f30-0 (* 128.0 (-> geom header xyz-scale)))))
; 0
; (.sll a0-16 num-bones 7)
; (let ((v1-56 #x20000000))
; (.addu a0-17 a0-16 s2-0)
; (s.q! s2-0 v1-56)
; )
; (let ((v1-57 (+ a0-17 16)))
; (s.w! (+ s2-0 4) v1-57)
; )
; (.addiu matrix-data s2-0 16)
; (let ((v1-59 (-> *bone-calculation-list* next)))
; (logior! (-> v1-59 flags) (bone-calc-flags bncfl00))
; (set! (-> v1-59 ripple-scale) f30-0)
; (set! (-> v1-59 ripple-y-scale) f1-9)
; (set! (-> v1-59 ripple-normal-scale) (* f0-4 (-> sv-144 individual-normal-scale)))
; (set! (-> v1-59 ripple-area) (the-as (inline-array vector) matrix-data))
; )
; )
; (set! (-> dma-buf base) (the-as pointer (-> (the-as (pointer uint32) s2-0) 1)))
; (set! s2-0 (-> dma-buf base))
; (if (not (and (= f30-0 0.0) (= (-> sv-144 last-frame-scale) 0.0)))
; (ripple-make-request (the-as ripple-wave (-> sv-144 waveform)) (-> geom effect effect-idx))
; )
; (set! (-> sv-144 last-frame-scale) f30-0)
; )
; )
)
(cond
((nonzero? (-> arg0 death-timer))
;; if using hte death effect, use mercneric always!
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1))
(set! used-mercneric 1)
used-mercneric
)
((nonzero? (-> geom effect effect-idx envmap-usage))
;; if we need envmap, set it up.
(let* ((v1-83 (-> geom effect effect-idx extra-info))
;; pointer to envmap tint data
(v1-84 (the-as structure (+ (the-as uint v1-83) (* (-> v1-83 envmap-tint-offset) 16))))
;; the envmap effect fades away at a certain distance
(f1-12 (-> (the-as mei-envmap-tint v1-84) fade0))
(f0-8 (-> (the-as mei-envmap-tint v1-84) fade1))
)
;; compute and saturate the envmap effect strength
(let ((f0-9 (+ (* f1-12 arg2) f0-8)))
(if (< 1.0 f0-9)
(set! f0-9 1.0)
)
(if (< f0-9 0.0)
(set! f0-9 0.0)
)
(cond
;; do envmap stuff if we are using generic anyway, or our strength is > 0.
((or (nonzero? (-> *merc-bucket-info* must-use-mercneric-for-clip)) (< 0.0 f0-9))
;; multiply colors by sun tint.
(let ((v1-85 (&-> (the-as merc-extra-info v1-84) dummy 4))
(a0-36 (the-as object (-> *merc-bucket-info* effect effect-idx)))
)
(let ((a1-16 (-> *time-of-day-context* current-sun env-color))
(f0-10 (* 0.0078125 f0-9))
)
(dotimes (a2-15 3)
(set! (-> (the-as (pointer int8) a0-36) a2-15)
(the int (* f0-10 (-> a1-16 data a2-15) (the float (-> v1-85 a2-15))))
)
)
)
(set! (-> (the-as (pointer uint8) a0-36) 3) (the-as uint 0))
)
;; env mapping, so use mercneric.
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1))
(set! used-mercneric 1)
used-mercneric
)
(else
;; no env map, don't use mercneric.
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0))
(set! (-> *merc-bucket-info* effect effect-idx ignore-alpha) (the-as uint 1))
(set! used-merc 1)
;; note sure what this is exactly...
(when (logtest? (-> geom effect effect-idx effect-bits) 2)
(let ((v1-102 (-> *merc-bucket-info* light)))
(set! (-> v1-102 direction 1 w) 0.000000000000000000000000000000000000011755039)
)
)
)
)
)
)
)
;; final two cases are for all other effects that don't matter generic/normal
((nonzero? (-> *merc-bucket-info* must-use-mercneric-for-clip))
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 1))
(set! used-mercneric 1)
used-mercneric
)
(else
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0))
(set! (-> *merc-bucket-info* effect effect-idx ignore-alpha) (the-as uint 0))
(set! used-merc 1)
used-merc
)
)
;; HACK just use merc.
(when (logtest? *vu1-enable-user* (vu1-renderer-mask generic))
(unless (logtest? (-> arg0 status) (draw-status needs-clip))
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0))
)
(when (and (logtest? (-> arg0 status) (draw-status needs-clip)) ;; we need to clip
;;(nonzero? (-> arg0 longest-edge)) ;; we known the longest edge
;;(draw-bones-check-longest-edge-asm arg0 arg2) ;; it's ok to use percprime.
)
(set! (-> *merc-bucket-info* effect effect-idx use-mercneric) (the-as uint 0))
(set! (-> *merc-bucket-info* need-mercprime-if-merc) 1)
)
)
(set! effect-idx (+ effect-idx 1))
) ;; end effect loop
;; draw generic!
;; note: this doesn't do the fully draw, there's some other stuff in process-drawable.gc to actually execute.
;; TODO!!
; (when (nonzero? used-mercneric)
; (when (logtest? *vu1-enable-user* (vu1-renderer-mask generic))
; (set! (-> dma-buf base) (draw-bones-generic-merc arg0 matrix-data s2-0 0))
; (set! s2-0 (-> dma-buf base))
; )
; )
;; draw shadow!
;; TODO
; (when (-> arg0 shadow)
; (when #t
; (set! s2-0 (draw-bones-shadow arg0 matrix-data s2-0))
; (set! (-> dma-buf base) (the-as pointer s2-0))
; )
; )
;; draw merc!
(set! used-merc 1)
(when (nonzero? used-merc)
(when (logtest? *vu1-enable-user* (vu1-renderer-mask merc))
(when (= (-> arg0 cur-lod) (-> arg0 lod-set max-lod))
(let ((f0-13 (- (-> arg0 lod-set lod (-> arg0 cur-lod) dist) arg2)))
(when (< f0-13 81920.0)
(when (zero? (logand (-> geom effect 0 effect-bits) 2))
(let* ((a1-25 (the int (* 0.0015625 f0-13)))
(v1-147 (min 128 (max 0 a1-25)))
(a0-56 (-> *merc-bucket-info* light))
)
(set! (-> a0-56 direction 1 w) 0.000000000000000000000000000000000000011755084)
(set! (-> a0-56 direction 2 w) (the-as float v1-147))
)
0
)
)
)
)
(if (nonzero? (-> *merc-bucket-info* need-mercprime-if-merc))
(set! (-> dma-buf base) (draw-bones-merc arg0 matrix-data s2-0 32 17))
(set! (-> dma-buf base) (draw-bones-merc arg0 matrix-data s2-0 35 20))
)
(set! s2-0 (-> dma-buf base))
)
)
) ;; end geom processing
;; advance death timer.
(when (nonzero? (-> arg0 death-timer))
(when (not (paused?))
(+! (-> arg0 death-timer) -1)
(if (>= (the-as uint 1) (-> arg0 death-timer))
(send-event (-> arg0 process) 'death-end arg0)
)
)
)
)
(let ((v1-164 (logand (the-as int s2-0) 48)))
0
(b! (zero? v1-164) cfg-83 :delay (set! a0-62 #x20000000))
;;(s.q! s2-0 a0-62)
(set! (-> (the (pointer uint128) s2-0) 0) (the uint128 a0-62))
(let ((a0-63 s2-0))
(set! s2-0 (+ (- (the-as int s2-0) v1-164) 64))
;;(s.w! (+ a0-63 4) (the-as int s2-0))
(set! (-> (the (pointer int32) (+ (the-as uint a0-63) 4))) (the-as int s2-0))
)
)
(label cfg-83)
(set! (-> dma-buf base) (the-as pointer (logand (the-as uint s2-0) (the-as uint #xfffffff))))
)
)
)
0
(none)
)
)
(defun draw-bones-hud ((arg0 draw-control) (arg1 dma-buffer))
;; hack
(none)
)
(define-extern draw-bones-hud (function draw-control dma-buffer none))
(define-extern draw-bones-hud (function draw-control dma-buffer none))
+1 -1
View File
@@ -246,7 +246,7 @@
(defenum draw-status
:type uint8
:bitfield #t
(drwf00 0)
(needs-clip 0)
(drwf01 1)
(drwf02 2)
(drwf03 3)
+8 -10
View File
@@ -222,9 +222,7 @@
(tfrag-near-0 7)
(tie-near-0 8)
(tie-0 9)
;; merc0 10
;; generic0 11
(bucket-10 10)
(bucket-10 10) ;; merc
(bucket-11 11)
(tfrag-tex1 12)
@@ -234,7 +232,7 @@
(tie-1 16)
;; merc1 17
;; generic1 18
(bucket-17 17)
(bucket-17 17) ;; merc
(bucket-18 18)
(shrub-tex0 19)
@@ -259,31 +257,31 @@
(tfrag-ice-near-1 44)
(bucket-45 45)
(bucket-45 45) ;; merc
(bucket-46 46)
(pris-tex0 48)
(bucket-49 49)
(bucket-49 49) ;; merc
(bucket-50 50)
;; merc0 49
;; generic0 50
(pris-tex1 51)
(bucket-52 52)
(bucket-52 52) ;; merc
(bucket-53 53)
;; merc1 52
;; generic1 53
(bucket-55 55)
(bucket-55 55) ;; merc
(bucket-56 56)
(water-tex0 57)
(bucket-58 58)
(bucket-58 58) ;; merc
(bucket-59 59)
;; merc0 58 (+ default)
;; generic0 59 (+ default)
(water-tex1 60)
(bucket-61 61)
(bucket-61 61) ;; merc
(bucket-62 62)
(bucket-63 63) ; ocean
;; merc1 61
+33 -6
View File
@@ -11,8 +11,35 @@
)
(defun guard-band-cull ((arg0 vector))
#t
;; todo
(local-vars (v1-0 uint128) (v1-1 uint128) (v1-2 uint128))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf10 :class vf)
(vf20 :class vf)
(vf21 :class vf)
(vf22 :class vf)
(vf23 :class vf)
(vf9 :class vf)
)
(init-vf0-vector)
;; NOTE: manually added
(let ((at-0 *math-camera*))
(.lvf vf20 (&-> at-0 guard-plane 0 quad))
(.lvf vf21 (&-> at-0 guard-plane 1 quad))
(.lvf vf22 (&-> at-0 guard-plane 2 quad))
(.lvf vf23 (&-> at-0 guard-plane 3 quad))
)
(.lvf vf10 (&-> arg0 quad))
(.mul.x.vf acc vf20 vf10)
(.add.mul.y.vf acc vf21 vf10 acc)
(.add.mul.z.vf acc vf22 vf10 acc)
(.sub.mul.w.vf vf9 vf23 vf0 acc)
(.sub.w.vf vf9 vf9 vf10)
(.mov v1-0 vf9)
(.pcgtw v1-1 0 v1-0)
(.ppach v1-2 (the-as uint128 0) v1-1)
(nonzero? (the-as int v1-2))
)
)
(defun sphere-in-view-frustum? ((arg0 sphere))
@@ -714,8 +741,8 @@
)
)
(if (or (guard-band-cull s4-0) (< cam-dist (* 1.2 (-> *math-camera* d))))
(logior! (-> arg1 status) (draw-status drwf00))
(logclear! (-> arg1 status) (draw-status drwf00))
(logior! (-> arg1 status) (draw-status needs-clip))
(logclear! (-> arg1 status) (draw-status needs-clip))
)
(logior! (-> arg1 status) (draw-status drwf03))
(if (logtest? (-> arg1 status) (draw-status drwf05))
@@ -903,7 +930,7 @@
;; tfrag
;; note: PC port uses preconverted tfrag textures.
(#unless PC_PORT
; (#unless PC_PORT
(when (logtest? *texture-enable-user* 1)
(dotimes (gp-1 (-> *level* length))
(let ((a1-2 (-> *level* level gp-1)))
@@ -913,7 +940,7 @@
)
)
)
)
; )
;; pris
+4 -4
View File
@@ -361,7 +361,7 @@
)
)
)
(draw-bone-lines obj)
; (draw-bone-lines obj)
;; (draw-joint-spheres obj)
0
@@ -949,9 +949,9 @@
(logior! (-> obj draw status) (draw-status drwf02))
)
)
; (if (logtest? (-> obj skel status) 72)
; (merc-blend-shape obj)
; )
(if (logtest? (-> obj skel status) 72)
(merc-blend-shape obj)
)
; (if (logtest? (-> obj skel status) 384)
; (merc-eye-anim obj)
; )
+4 -4
View File
@@ -583,7 +583,7 @@
(display-sync disp)
(swap-display disp)
(free-all-prim-nodes *touching-list*)
;; bler init
(blerc-init)
;; collide dma
(suspend)
@@ -592,9 +592,9 @@
;; start immediately after all process updates finish.
;; drawing effects to be used in foreground drawing.
; (blerc-execute)
; (blerc-init)
; (texscroll-execute)
(blerc-execute)
(blerc-init)
(texscroll-execute)
; (ripple-execute)
;;;;;;;;;;;;;;;;;;;;
+138 -3
View File
@@ -116,10 +116,145 @@
;; todo merc-dma-chain-to-spr (unused)
;; todo blerc-execute
(def-mips2c blerc-execute (function none))
(define-extern setup-blerc-chains (function merc-ctrl (pointer int16) dma-buffer none))
;; todo merc-blend-shape
(defun merc-blend-shape ((a process-drawable))
(the object #f)
(defun merc-blend-shape ((arg0 process-drawable))
(let* ((v1-2 (-> arg0 skel root-channel 0))
(a3-0 (-> v1-2 frame-group))
)
(when (and a3-0
(> (-> arg0 skel active-channels) 0)
(zero? (-> arg0 draw cur-lod))
(logtest? (-> arg0 skel status) 8)
)
(let ((a1-4 (-> a3-0 blerc-data)))
(when a1-4
(let* ((a0-10 (-> arg0 draw mgeo))
(a2-0 (-> a0-10 header blend-target-count))
(t0-0 (-> v1-2 frame-num))
(t1-0 (the int t0-0))
(v1-4 (&+ a1-4 (* (the-as uint t1-0) a2-0)))
(a1-5 (new 'stack-no-clear 'array 'int16 128))
)
(let ((a2-1 (-> a0-10 header blend-target-count)))
(cond
((< t1-0 (+ (-> a3-0 data 0 length) -1))
(let* ((a3-5 (&+ v1-4 a2-1))
(t0-1 (* 64.0 (- t0-0 (the float t1-0))))
(t1-1 (- 64.0 t0-1))
)
(dotimes (t2-0 (the-as int a2-1))
(set! (-> a1-5 t2-0)
(the int (+ (* (the float (+ (-> v1-4 t2-0) -64)) t1-1) (* (the float (+ (-> a3-5 t2-0) -64)) t0-1)))
)
)
)
)
(else
(dotimes (a3-6 (the-as int a2-1))
(set! (-> a1-5 a3-6) (the-as int (* (+ (-> v1-4 a3-6) -64) 64)))
)
)
)
)
(setup-blerc-chains a0-10 a1-5 (-> *display* frames (-> *display* on-screen) frame global-buf))
)
(logior! (-> arg0 skel status) 64)
(return (the-as object #f))
)
)
)
)
(when (logtest? (-> arg0 skel status) 64)
(set! (-> arg0 skel status) (logand -65 (-> arg0 skel status)))
(setup-blerc-chains
(-> arg0 draw lod-set lod 0 geo)
(new 'static 'array int16 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
(-> *display* frames (-> *display* on-screen) frame global-buf)
)
)
0
)
;; todo setup-blerc-chains
;; TODO setup-blerc-chains-for-one-fragment
(def-mips2c setup-blerc-chains-for-one-fragment (function object object object object object object object))
(defun setup-blerc-chains ((arg0 merc-ctrl) (arg1 (pointer int16)) (arg2 dma-buffer))
(local-vars
(sv-16 uint)
(sv-20 pointer)
(sv-24 merc-effect)
(sv-28 uint)
(sv-32 object)
(sv-48 int)
(sv-64 int)
)
;; (format 0 "chain setup ctrl ~X array ~X~%" arg0 arg1)
(set! sv-16 (-> arg0 header effect-count))
(let ((s3-0 (-> arg0 header blend-target-count))
(v1-1 (-> arg2 base))
)
(set! sv-20 (&+ v1-1 0))
(let ((a2-1 (the-as object (&+ v1-1 16))))
(if (zero? (-> *blerc-globals* first))
(set! (-> *blerc-globals* first) (the-as uint a2-1))
)
(dotimes (s2-0 (the-as int sv-16))
; (format 0 "BLERC CHAIN AT ~X~%" a2-1)
(set! sv-24 (-> arg0 effect s2-0))
(set! sv-28 (-> sv-24 blend-frag-count))
;; (format 0 " blend frags: ~D~%" sv-28)
(when (nonzero? sv-28)
(let ((v1-15 (the-as object (-> sv-24 frag-geo)))
(s1-0 (the-as structure (-> sv-24 frag-ctrl)))
(s0-0 (the-as object (-> sv-24 blend-data)))
)
(set! sv-32 (-> sv-24 blend-ctrl))
(set! sv-48 0)
(while (< sv-48 (the-as int sv-28))
;; (format 0 " [~D] loc: ~X~%" sv-48 s0-0)
(set! sv-64 (+ (the-as int v1-15)
(logand (* (+ (-> (the-as merc-fragment-control s1-0) unsigned-four-count) 3) 4) #xfff0)
)
)
(if (nonzero? (-> (the-as (pointer uint8) sv-32) 0))
(set! a2-1 (setup-blerc-chains-for-one-fragment s3-0 arg1 a2-1 s0-0 sv-32 sv-64))
)
(let ((a0-14 (logand (+ (* (the-as uint 6) (-> (the-as merc-blend-ctrl sv-32) blend-vtx-count)) 15) #xfff0)))
(set! v1-15
(+ sv-64
(logand (* (+ (-> (the-as merc-fragment-control s1-0) lump-four-count) 3) 4) #xfff0)
(* (-> (the-as merc-fragment-control s1-0) fp-qwc) 16)
)
)
(set! s1-0 (&+ s1-0 (* (-> (the-as merc-fragment-control s1-0) mat-xfer-count) 2) 4))
(set! s0-0
(+ (the-as int s0-0) (* (the-as uint a0-14) (+ (-> (the-as merc-blend-ctrl sv-32) nonzero-index-count) 1)))
)
)
(set! sv-32 (+ (the-as int sv-32) s3-0 2))
(the-as int sv-32)
(set! sv-48 (+ sv-48 1))
;; (format 0 "~%")
)
)
)
)
(set! (-> (the-as (pointer int64) sv-20)) (logior #x20000000 (shr (shl (the-as int a2-1) 33) 1)))
(let ((v1-33 (the-as (pointer uint32) sv-20)))
(set! (-> (&+ v1-33 8)) 0)
)
(let ((v1-34 (the-as (pointer uint32) sv-20)))
(set! (-> (&+ v1-34 12)) 0)
)
(set! (-> arg2 base) (the-as pointer a2-1))
)
)
0
(none)
)
+1 -2
View File
@@ -499,7 +499,6 @@
(&+ v1-20 16)
)
)
(none)
)
@@ -520,7 +519,7 @@
)
;; set the beginning to be the merc init stuff.
(set! (-> dma-buf base)
(the-as pointer (merc-vu1-initialize-chain (the-as dma-gif-packet (-> dma-buf base))) )
(the-as pointer (merc-vu1-initialize-chain (the-as dma-gif-packet (-> dma-buf base))))
)
;; some other merc setup for the GS.
(let* ((v1-8 dma-buf)
+7
View File
@@ -1065,6 +1065,13 @@
(dma-buffer-add-gs-set dma-buf
(texflush 1)
)
(#when PC_PORT
(dma-buffer-add-cnt-vif2 dma-buf 1 (new 'static 'vif-tag :cmd (vif-cmd pc-port)) (the-as vif-tag 3))
(dma-buffer-add-uint64 dma-buf page)
(dma-buffer-add-uint64 dma-buf -1)
)
)
(shl total-upload-size 14)
)
+3 -3
View File
@@ -287,7 +287,7 @@
(set! (-> arg0 sky) #f)
(set! (-> arg0 target-interp) 0.0)
;; TODO re-enable
#|
(when *target*
(set! (-> *target* draw light-index) (the-as uint 0))
(when (-> *target* sidekick)
@@ -295,7 +295,7 @@
0
)
)
|#
;; see if either level gives us a sky.
(dotimes (v1-12 (-> *level* length))
@@ -573,7 +573,7 @@
(set! (-> *math-camera* fog-min) (-> arg0 current-fog fog-dists w))
;; interp target lights.
(let* ((v1-195 0 #|(-> *target* draw light-index)|#) ;; TODO
(let* ((v1-195 0 (-> *target* draw light-index)) ;; TODO
(f30-1 (-> arg0 target-interp))
(s4-6 (-> arg0 light-group))
(s5-2 (-> arg0 light-group v1-195))
-2
View File
@@ -2104,8 +2104,6 @@
(set! *target* #f)
)
)
;; hack added.
(set! *display-target-marks* #t)
*target*
)
+3 -3
View File
@@ -208,9 +208,9 @@
(TODO-RENAME-9 a0-26)
)
)
; (if (logtest? (-> self skel status) 72)
; (merc-blend-shape self)
; )
(if (logtest? (-> self skel status) 72)
(merc-blend-shape self)
)
; (if (logtest? (-> self skel status) 384)
; (merc-eye-anim self)
; )
+2 -2
View File
@@ -792,8 +792,8 @@
)
)
(if (or (guard-band-cull s4-0) (< cam-dist (* 1.2 (-> *math-camera* d))))
(logior! (-> arg1 status) (draw-status drwf00))
(logclear! (-> arg1 status) (draw-status drwf00))
(logior! (-> arg1 status) (draw-status needs-clip))
(logclear! (-> arg1 status) (draw-status needs-clip))
)
(logior! (-> arg1 status) (draw-status drwf03))
(if (logtest? (-> arg1 status) (draw-status drwf05))
+1 -1
View File
@@ -1061,7 +1061,7 @@
)
)
(when (and *display-actor-vis* *display-actor-anim*)
(let ((s5-3 (entity-by-name (the-as string *display-actor-anim*))))
(let ((s5-3 (entity-by-name *display-actor-anim*)))
(when s5-3
(let ((v0-35 (res-lump-data s5-3 'visvol pointer))
(a1-31 (-> s5-3 extra vis-id))
+2 -2
View File
@@ -193,8 +193,8 @@
;; definition for symbol *display-water-marks*, type symbol
(define *display-water-marks* #f)
;; definition for symbol *display-actor-anim*, type symbol
(define *display-actor-anim* #f)
;; definition for symbol *display-actor-anim*, type string
(define *display-actor-anim* (the-as string #f))
;; definition for symbol *display-process-anim*, type (pointer process)
(define *display-process-anim* (the-as (pointer process) #f))
-2
View File
@@ -385,7 +385,6 @@
)
;; definition for function merc-vu1-initialize-chain
;; INFO: Return type mismatch dma-packet vs none.
;; Used lq/sq
(defun merc-vu1-initialize-chain ((arg0 dma-gif-packet))
(let ((gp-0 (the-as object (merc-vu1-add-vu-function (the-as dma-packet arg0) merc-vu1-block 1))))
@@ -421,7 +420,6 @@
(&+ v1-20 16)
)
)
(none)
)
;; definition for function merc-vu1-init-buffer
+14
View File
@@ -159,4 +159,18 @@ TEST(VuDisasm, Merc) {
VuDisassembler disasm(VuDisassembler::VuKind::VU1);
auto prog = disasm.disassemble(data.data(), data.size() * 4, false);
EXPECT_EQ(disasm.to_string(prog), get_expected("merc"));
}
TEST(VuDisasm, MercToC) {
auto data = get_test_data("merc");
VuDisassembler disasm(VuDisassembler::VuKind::VU1);
disasm.add_label_with_name(0x1a1, "JUMP_1A1");
disasm.add_label_with_name(0x48e, "JUMP_48E");
disasm.add_label_with_name(0x539, "JUMP_539");
disasm.add_label_with_name(0x243, "JUMP_243");
disasm.add_label_with_name(20, "ENTER_20");
disasm.add_label_with_name(35, "ENTER_35");
auto prog = disasm.disassemble(data.data(), data.size() * 4, false);
// fmt::print("{}\n", disasm.to_string_with_cpp(prog));
// EXPECT_EQ(disasm.to_string_with_cpp(prog), get_expected("merc"));
}