up to generic-effect

This commit is contained in:
water111
2026-08-23 15:26:48 -07:00
parent 02fef1fe63
commit 717354893b
22 changed files with 522 additions and 1879 deletions
+49
View File
@@ -2964,6 +2964,51 @@ void SimpleExpressionElement::update_from_stack(const Env& env,
// SetVarElement
///////////////////
namespace {
bool try_rewrite_string_format_load(SetVarElement& set,
const Env& env,
FormPool& pool,
FormStack& stack) {
// string-format expands to
// (begin (format (clear *temp-string*) args...) *temp-string*)
//
// Recognize the reload only when the matching format call is the immediately preceding active
// expression. Keeping the resulting value at the reload's position is important: normal stack
// popping can then inline it only where doing so preserves argument evaluation order, or leave a
// temporary when an intervening argument was evaluated after the format call.
if (!set.src()->to_form(env).is_symbol("*temp-string*")) {
return false;
}
const auto* previous = stack.active_back();
if (!previous || previous->destination || !previous->elt) {
return false;
}
auto* format_call = dynamic_cast<GenericElement*>(previous->elt);
if (!format_call || !format_call->op().is_func() ||
!format_call->op().func()->to_form(env).is_symbol("format") || format_call->elts().empty()) {
return false;
}
auto* clear_call = format_call->elts().front()->try_as_element<GenericElement>();
if (!clear_call || !clear_call->op().is_func() ||
!clear_call->op().func()->to_form(env).is_symbol("clear") || clear_call->elts().size() != 1 ||
!clear_call->elts().front()->to_form(env).is_symbol("*temp-string*")) {
return false;
}
std::vector<Form*> format_args(format_call->elts().begin() + 1, format_call->elts().end());
auto string_format = pool.form<GenericElement>(
GenericOperator::make_function(pool.form<ConstantTokenElement>("string-format")),
format_args);
stack.pop_active_back();
stack.push_value_to_reg(set.dst(), string_format, true, set.src_type(), set.info());
return true;
}
} // namespace
void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
mark_popped();
for (auto x : m_src->elts()) {
@@ -2977,6 +3022,10 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
return;
}
if (try_rewrite_string_format_load(*this, env, pool, stack)) {
return;
}
// if we are a reg-reg move that consumes the original, push it without popping from stack.
// it is the Stack's responsibility to untangle these later on.
if (m_src->is_single_element()) {
+22 -11
View File
@@ -929,7 +929,7 @@ FormElement* rewrite_set_vector(LetElement* in, const Env& env, FormPool& pool)
FormElement* rewrite_set_vector_sequence(const std::array<FormElement*, 4>& elts,
const Env& env,
FormPool& pool) {
std::optional<RegisterAccess> vector_access;
std::optional<RegisterAccess> root_access;
Form* vector_form = nullptr;
std::vector<Form*> sources;
@@ -940,26 +940,37 @@ FormElement* rewrite_set_vector_sequence(const std::array<FormElement*, 4>& elts
}
auto* deref = set->dst()->try_as_element<DerefElement>();
Matcher dst_matcher = Matcher::deref(Matcher::any_reg(0), false,
{DerefTokenMatcher::string(std::string(1, "xyzw"[i]))});
auto mr = match(dst_matcher, set->dst());
if (!deref || !mr.matched) {
if (!deref || deref->is_addr_of() || deref->tokens().empty() ||
!deref->tokens().back().is_field_name(std::string(1, "xyzw"[i]))) {
return nullptr;
}
const auto this_access = *mr.maps.regs.at(0);
if (vector_access &&
env.get_program_var_id(*vector_access) != env.get_program_var_id(this_access)) {
const auto root_atom = form_as_atom(deref->base());
if (!root_atom || !root_atom->is_var()) {
return nullptr;
}
const auto this_root = root_atom->var();
if (root_access && env.get_program_var_id(*root_access) != env.get_program_var_id(this_root)) {
return nullptr;
}
root_access = this_root;
auto target_tokens = deref->tokens();
target_tokens.pop_back();
Form* this_vector_form = deref->base();
if (!target_tokens.empty()) {
this_vector_form = pool.form<DerefElement>(deref->base(), false, std::move(target_tokens));
}
if (vector_form && vector_form->to_form(env) != this_vector_form->to_form(env)) {
return nullptr;
}
vector_access = this_access;
if (!vector_form) {
vector_form = deref->base();
vector_form = this_vector_form;
}
sources.push_back(set->src());
}
ASSERT(vector_access);
ASSERT(root_access);
std::vector<Form*> args = {vector_form};
args.insert(args.end(), sources.begin(), sources.end());
auto op = GenericOperator::make_function(
+2 -2
View File
@@ -20518,7 +20518,7 @@ framebuffer on alpha failure."
;; - Types
(deftype ripple-request (structure)
((waveform ripple-wave :offset-assert 0)
((waveform ripple-wave-set :offset-assert 0)
(effect merc-effect :offset-assert 4)
)
:pack-me
@@ -20564,7 +20564,7 @@ bytes. Fragment geometry, query, and control streams advance according to their
(define-extern ripple-make-request
"Queue an effect to receive a waveform during this frame. Ignore duplicate effects and requests
beyond the sixteen-entry buffer."
(function ripple-wave merc-effect none))
(function ripple-wave-set merc-effect none))
(define-extern ripple-execute
"Build each requested waveform table once, apply it to every queued effect that shares that
waveform, and clear the request list."
+54
View File
@@ -326,6 +326,15 @@
"rewrite":
"(dma-buffer-add-gif-tag $buf $tag $regs)"
},
{
// &-> produces the address of the selected value. Immediately dereferencing element zero
// cancels that address operation and can be expressed as an ordinary value access.
"name": "deref-zero-of-addressed-field",
"match":
"(-> (&-> $base $*tokens) 0)",
"rewrite":
"(-> $base $*tokens)"
},
{
"name": "dma-buffer-add-two-uint128",
"match":
@@ -333,6 +342,33 @@
"rewrite":
"(dma-buffer-add-uint128 $buf $value0 $value1)"
},
{
// The cursor binding can retain an inferred storage view while the casts on both stores
// establish the actual flat uint128 layout.
"name": "dma-buffer-add-two-uint128-cast-stores",
"match":
"(let* (($alias $buf) ($data (the-as $storage-type (-> $alias base)))) (set! (-> (the-as (pointer uint128) $data) 0) $value0) (set! (-> (the-as (pointer uint128) $data) 1) $value1) (set! (-> $alias base) (&+ (the-as pointer $data) 32)))",
"rewrite":
"(dma-buffer-add-uint128 $buf $value0 $value1)"
},
{
// Four qwords may be reconstructed through an aggregate containing two pairs instead of as
// a flat uint128 pointer. The field sequence and 64-byte advance identify the same append.
"name": "dma-buffer-add-four-uint128-pairs",
"match":
"(let* (($alias $buf) ($data (the-as (inline-array vector4w-2) (-> $alias base)))) (set! (-> $data 0 quad 0) $value0) (set! (-> $data 0 quad 1) $value1) (set! (-> $data 1 quad 0) $value2) (set! (-> $data 1 quad 1) $value3) (set! (-> $alias base) (&+ (the-as pointer $data) 64)))",
"rewrite":
"(dma-buffer-add-uint128 $buf $value0 $value1 $value2 $value3)"
},
{
// A storage view may remain on the cursor binding, but explicit uint128 casts on all six
// indexed stores make their flat contiguous layout independent of that inferred view.
"name": "dma-buffer-add-six-uint128-cast-stores",
"match":
"(let* (($alias $buf) ($data (the-as $storage-type (-> $alias base)))) (set! (-> (the-as (pointer uint128) $data) 0) $value0) (set! (-> (the-as (pointer uint128) $data) 1) $value1) (set! (-> (the-as (pointer uint128) $data) 2) $value2) (set! (-> (the-as (pointer uint128) $data) 3) $value3) (set! (-> (the-as (pointer uint128) $data) 4) $value4) (set! (-> (the-as (pointer uint128) $data) 5) $value5) (set! (-> $alias base) (&+ (the-as pointer $data) 96)))",
"rewrite":
"(dma-buffer-add-uint128 $buf $value0 $value1 $value2 $value3 $value4 $value5)"
},
{
// Four sequential eight-byte stores are the common expansion of dma-buffer-add-uint64.
// Their individual pointer types reflect the value types; the 32-byte advance fixes the width.
@@ -350,6 +386,24 @@
"rewrite":
"(with-cnt-vif-block ($buf) $*body)"
},
{
// Variant emitted when the saved tag is inferred as a uint64 pointer. The pointer-form
// subtraction and direct uint64 stores are equivalent to the typed dma-tag expansion.
"name": "with-cnt-vif-block-uint64-tag",
"match":
"(let (($start (the-as (pointer uint64) (-> $buf base)))) (dma-buffer-add-cnt-vif2 $buf 0 (new 'static 'vif-tag) (new 'static 'vif-tag :cmd (vif-cmd direct) :msk #x1)) $*body (let (($qwc (/ (the-as int (+ (&- (the-as pointer -16) (the-as uint $start)) (the-as int (-> $buf base)))) 16))) (cond ((nonzero? $qwc) (logior! (-> $start 0) (shr (shl $qwc 48) 48)) (logior! (-> $start 1) (shl (shr (shl $qwc 48) 48) 32))) (else (set! (-> $buf base) $start)))))",
"rewrite":
"(with-cnt-vif-block ($buf) $*body)"
},
{
// gif-prim sets exactly IIP and ABE in addition to the primitive kind. Keep the complete
// constructor in the match so primitives with any other flag combination remain explicit.
"name": "gif-prim",
"match":
"(new 'static 'gs-prim :prim (gs-prim-type $prim-type) :iip #x1 :abe #x1)",
"rewrite":
"(gif-prim $prim-type)"
},
{
// Let insertion may merge the saved tag pointer into a caller's surrounding let*.
"name": "with-cnt-vif-block-merged-bindings",
@@ -652,7 +652,7 @@
"add-debug-flat-triangle": [
[[55, 61], "a3", "dma-packet"],
[[64, 70], "a3", "gs-gif-tag"],
[[93, 112], "a3", "(inline-array vector4w-3)"],
[[93, 112], "a3", "(pointer uint128)"],
[[53, 133], "a0", "(pointer uint64)"],
[115, "a1", "pointer"],
[[135, 140], "a0", "dma-packet"]
@@ -660,12 +660,13 @@
"add-debug-line2d": [
[[58, 64], "a2", "dma-packet"],
[[67, 73], "a2", "gs-gif-tag"],
[[76, 81], "a2", "(inline-array vector4w)"],
[[84, 89], "a2", "(inline-array vector4w)"],
[[76, 81], "a2", "(pointer uint128)"],
[[84, 89], "a2", "(pointer uint128)"],
[[56, 110], "a0", "(pointer uint64)"],
[92, "a1", "pointer"],
[[112, 117], "v1", "dma-packet"]
],
"add-debug-light": [[82, "s1", "rgba"]],
"debug-percent-bar": [[[32, 43], "v1", "dma-packet"]],
"debug-pad-display": [[[70, 75], "v1", "dma-packet"]],
"internal-draw-debug-text-3d": [[[54, 59], "v1", "dma-packet"]],
@@ -22160,7 +22160,10 @@
"label"
],
"vars": {
"s1-0": "packed-color",
"s1-0": [
"packed-color",
"rgba"
],
"s2-1": "position",
"t0-2": "text"
}
-1
View File
@@ -169,7 +169,6 @@ set(RUNTIME_SOURCE
mips2c/jak1_functions/merc_blend_shape.cpp
mips2c/jak1_functions/ocean_vu0.cpp
mips2c/jak1_functions/ocean.cpp
mips2c/jak1_functions/ripple.cpp
mips2c/jak1_functions/shadow.cpp
mips2c/jak1_functions/sky_tng.cpp
mips2c/jak1_functions/sparticle_launcher.cpp
@@ -122,894 +122,6 @@ void vcallms48(ExecutionContext* c) {
}
namespace generic_envmap_dproc {
struct Cache {
void* fake_scratchpad_data; // *fake-scratchpad-data*
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
// nop // sll r0, r0, 0
get_fake_spad_addr(at, cache.fake_scratchpad_data, 0, c);// lui at, 28672
c->lui(v1, 16256); // lui v1, 16256
c->mtc1(f0, v1); // mtc1 f0, v1
c->lwu(a1, 60, at); // lwu a1, 60(at)
// nop // sll r0, r0, 0
c->lw(v1, 12048, at); // lw v1, 12048(at)
// nop // sll r0, r0, 0
c->lw(a2, 4, a1); // lw a2, 4(a1)
c->mov64(a0, a2); // or a0, a2, r0
c->lhu(a1, 20, a1); // lhu a1, 20(a1)
// nop // sll r0, r0, 0
c->lwc1(f4, 24, a2); // lwc1 f4, 24(a2)
c->daddiu(a1, a1, -4); // daddiu a1, a1, -4
c->lwc1(f3, 56, a2); // lwc1 f3, 56(a2)
// nop // sll r0, r0, 0
c->lwc1(f2, 88, a2); // lwc1 f2, 88(a2)
// nop // sll r0, r0, 0
c->lwc1(f1, 120, a2); // lwc1 f1, 120(a2)
// nop // sll r0, r0, 0
c->lq(t2, 16, a2); // lq t2, 16(a2)
c->subs(f4, f4, f0); // sub.s f4, f4, f0
c->lq(t3, 48, a2); // lq t3, 48(a2)
c->divs(f4, f0, f4); // div.s f4, f0, f4
c->lq(t4, 80, a2); // lq t4, 80(a2)
// nop // sll r0, r0, 0
c->lq(t5, 112, a2); // lq t5, 112(a2)
// nop // sll r0, r0, 0
c->lqc2(vf31, 12016, at); // lqc2 vf31, 12016(at)
// nop // sll r0, r0, 0
c->lq(t6, 0, a2); // lq t6, 0(a2)
// nop // sll r0, r0, 0
c->lq(a3, 32, a2); // lq a3, 32(a2)
// nop // sll r0, r0, 0
c->lq(t0, 64, a2); // lq t0, 64(a2)
// nop // sll r0, r0, 0
c->lq(t1, 96, a2); // lq t1, 96(a2)
c->muls(f4, f4, f0); // mul.s f4, f4, f0
c->mov128_vf_gpr(vf21, t2); // qmtc2.i vf21, t2
c->subs(f3, f3, f0); // sub.s f3, f3, f0
c->mov128_vf_gpr(vf22, t3); // qmtc2.ni vf22, t3
c->divs(f3, f0, f3); // div.s f3, f0, f3
c->mov128_vf_gpr(vf23, t4); // qmtc2.ni vf23, t4
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf24, t5); // qmtc2.ni vf24, t5
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf9, t6); // qmtc2.ni vf9, t6
c->subs(f2, f2, f0); // sub.s f2, f2, f0
c->mfc1(t2, f4); // mfc1 t2, f4
c->subs(f1, f1, f0); // sub.s f1, f1, f0
c->mov128_vf_gpr(vf10, a3); // qmtc2.ni vf10, a3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf11, t0); // qmtc2.ni vf11, t0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf12, t1); // qmtc2.ni vf12, t1
c->muls(f3, f3, f0); // mul.s f3, f3, f0
// nop // sll r0, r0, 0
c->divs(f2, f0, f2); // div.s f2, f0, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(a3, f3); // mfc1 a3, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f2, f2, f0); // mul.s f2, f2, f0
// nop // sll r0, r0, 0
c->divs(f1, f0, f1); // div.s f1, f0, f1
// nop // sll r0, r0, 0
c->pextlw(a3, a3, t2); // pextlw a3, a3, t2
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t0, f2); // mfc1 t0, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->daddiu(a2, a2, 128); // daddiu a2, a2, 128
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t1, f1); // mfc1 t1, f1
c->pextlw(t0, t1, t0); // pextlw t0, t1, t0
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(a3, t0, a3); // pcpyld a3, t0, a3
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf27, a3); // qmtc2.ni vf27, a3
// nop // sll r0, r0, 0
// Unknown instr: vcallms 48
vcallms48(c);
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->lwc1(f4, 24, a2); // lwc1 f4, 24(a2)
// nop // sll r0, r0, 0
c->lwc1(f3, 56, a2); // lwc1 f3, 56(a2)
// nop // sll r0, r0, 0
c->lwc1(f2, 88, a2); // lwc1 f2, 88(a2)
// nop // sll r0, r0, 0
c->lwc1(f1, 120, a2); // lwc1 f1, 120(a2)
// nop // sll r0, r0, 0
c->lq(a3, 16, a2); // lq a3, 16(a2)
c->subs(f4, f4, f0); // sub.s f4, f4, f0
// nop // sll r0, r0, 0
c->subs(f3, f3, f0); // sub.s f3, f3, f0
// nop // sll r0, r0, 0
c->subs(f2, f2, f0); // sub.s f2, f2, f0
// nop // sll r0, r0, 0
c->subs(f1, f1, f0); // sub.s f1, f1, f0
// nop // sll r0, r0, 0
c->divs(f4, f0, f4); // div.s f4, f0, f4
c->lq(t0, 48, a2); // lq t0, 48(a2)
// nop // sll r0, r0, 0
c->lq(t1, 80, a2); // lq t1, 80(a2)
// nop // sll r0, r0, 0
c->lq(t2, 112, a2); // lq t2, 112(a2)
// nop // sll r0, r0, 0
c->lq(t3, 0, a2); // lq t3, 0(a2)
// nop // sll r0, r0, 0
c->lq(t4, 32, a2); // lq t4, 32(a2)
// nop // sll r0, r0, 0
c->lq(t5, 64, a2); // lq t5, 64(a2)
// nop // sll r0, r0, 0
c->lq(t6, 96, a2); // lq t6, 96(a2)
c->muls(f4, f4, f0); // mul.s f4, f4, f0
// nop // sll r0, r0, 0
c->divs(f3, f0, f3); // div.s f3, f0, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t7, f4); // mfc1 t7, f4
// nop // sll r0, r0, 0
c->daddiu(a2, a2, 128); // daddiu a2, a2, 128
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f3, f3, f0); // mul.s f3, f3, f0
// nop // sll r0, r0, 0
c->divs(f2, f0, f2); // div.s f2, f0, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t8, f3); // mfc1 t8, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f2, f2, f0); // mul.s f2, f2, f0
// nop // sll r0, r0, 0
c->divs(f1, f0, f1); // div.s f1, f0, f1
// nop // sll r0, r0, 0
c->pextlw(t7, t8, t7); // pextlw t7, t8, t7
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t8, f2); // mfc1 t8, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t9, f1); // mfc1 t9, f1
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf21, a3); // qmtc2.ni vf21, a3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf9, t3); // qmtc2.ni vf9, t3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf10, t4); // qmtc2.ni vf10, t4
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf11, t5); // qmtc2.ni vf11, t5
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf12, t6); // qmtc2.ni vf12, t6
c->pextlw(a3, t9, t8); // pextlw a3, t9, t8
// nop // sll r0, r0, 0
c->pcpyld(a3, a3, t7); // pcpyld a3, a3, t7
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf22, t0); // qmtc2.ni vf22, t0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf23, t1); // qmtc2.ni vf23, t1
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf24, t2); // qmtc2.ni vf24, t2
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf27, a3); // qmtc2.ni vf27, a3
// nop // sll r0, r0, 0
// Unknown instr: vcallms 48
vcallms48(c);
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->lwc1(f1, 24, a2); // lwc1 f1, 24(a2)
c->subs(f1, f1, f0); // sub.s f1, f1, f0
c->lwc1(f2, 56, a2); // lwc1 f2, 56(a2)
c->divs(f3, f0, f1); // div.s f3, f0, f1
c->lwc1(f5, 88, a2); // lwc1 f5, 88(a2)
// nop // sll r0, r0, 0
c->lwc1(f1, 120, a2); // lwc1 f1, 120(a2)
// nop // sll r0, r0, 0
c->lq(a3, 16, a2); // lq a3, 16(a2)
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->subs(f4, f2, f0); // sub.s f4, f2, f0
// nop // sll r0, r0, 0
c->subs(f2, f5, f0); // sub.s f2, f5, f0
// nop // sll r0, r0, 0
c->subs(f1, f1, f0); // sub.s f1, f1, f0
// nop // sll r0, r0, 0
c->muls(f3, f3, f0); // mul.s f3, f3, f0
c->lq(t0, 48, a2); // lq t0, 48(a2)
c->divs(f4, f0, f4); // div.s f4, f0, f4
c->lq(t1, 80, a2); // lq t1, 80(a2)
// nop // sll r0, r0, 0
c->lq(t2, 112, a2); // lq t2, 112(a2)
// nop // sll r0, r0, 0
c->lq(t3, 0, a2); // lq t3, 0(a2)
// nop // sll r0, r0, 0
c->lq(t4, 32, a2); // lq t4, 32(a2)
// nop // sll r0, r0, 0
c->lq(t5, 64, a2); // lq t5, 64(a2)
// nop // sll r0, r0, 0
c->lq(t6, 96, a2); // lq t6, 96(a2)
// nop // sll r0, r0, 0
c->mfc1(t7, f3); // mfc1 t7, f3
c->muls(f3, f4, f0); // mul.s f3, f4, f0
// nop // sll r0, r0, 0
c->divs(f2, f0, f2); // div.s f2, f0, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->daddiu(a2, a2, 128); // daddiu a2, a2, 128
// nop // sll r0, r0, 0
c->mfc1(t8, f3); // mfc1 t8, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f2, f2, f0); // mul.s f2, f2, f0
// nop // sll r0, r0, 0
c->divs(f1, f0, f1); // div.s f1, f0, f1
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t9, f2); // mfc1 t9, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->pextlw(t7, t8, t7); // pextlw t7, t8, t7
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t8, f1); // mfc1 t8, f1
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->pextlw(t8, t8, t9); // pextlw t8, t8, t9
// nop // sll r0, r0, 0
c->pcpyld(t7, t8, t7); // pcpyld t7, t8, t7
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf21, a3); // qmtc2.ni vf21, a3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf22, t0); // qmtc2.ni vf22, t0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf23, t1); // qmtc2.ni vf23, t1
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf24, t2); // qmtc2.ni vf24, t2
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf9, t3); // qmtc2.ni vf9, t3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf10, t4); // qmtc2.ni vf10, t4
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf11, t5); // qmtc2.ni vf11, t5
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf12, t6); // qmtc2.ni vf12, t6
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf27, t7); // qmtc2.ni vf27, t7
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t1, vf17); // qmfc2.ni t1, vf17
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t2, vf18); // qmfc2.ni t2, vf18
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t0, vf19); // qmfc2.ni t0, vf19
bc = ((s64)c->sgpr64(a1)) <= 0; // blez a1, L47
c->mov128_gpr_vf(a3, vf20); // qmfc2.ni a3, vf20
if (bc) {goto block_2;} // branch non-likely
block_1:
c->ppach(t1, r0, t1); // ppach t1, r0, t1
// Unknown instr: vcallms 48
vcallms48(c);
c->ppach(t2, r0, t2); // ppach t2, r0, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->ppach(t0, r0, t0); // ppach t0, r0, t0
c->mfc1(r0, f31); // mfc1 r0, f31
c->ppach(a3, r0, a3); // ppach a3, r0, a3
c->mfc1(r0, f31); // mfc1 r0, f31
// nop // sll r0, r0, 0
c->sw(t1, 16, a0); // sw t1, 16(a0)
// nop // sll r0, r0, 0
c->sw(t2, 48, a0); // sw t2, 48(a0)
// nop // sll r0, r0, 0
c->sw(t0, 80, a0); // sw t0, 80(a0)
// nop // sll r0, r0, 0
c->sw(a3, 112, a0); // sw a3, 112(a0)
// nop // sll r0, r0, 0
c->lwc1(f4, 24, a2); // lwc1 f4, 24(a2)
// nop // sll r0, r0, 0
c->lwc1(f3, 56, a2); // lwc1 f3, 56(a2)
// nop // sll r0, r0, 0
c->lwc1(f2, 88, a2); // lwc1 f2, 88(a2)
// nop // sll r0, r0, 0
c->lwc1(f1, 120, a2); // lwc1 f1, 120(a2)
// nop // sll r0, r0, 0
c->lq(a3, 16, a2); // lq a3, 16(a2)
c->subs(f4, f4, f0); // sub.s f4, f4, f0
c->sw(v1, 20, a0); // sw v1, 20(a0)
c->subs(f3, f3, f0); // sub.s f3, f3, f0
c->sw(v1, 52, a0); // sw v1, 52(a0)
c->subs(f2, f2, f0); // sub.s f2, f2, f0
c->sw(v1, 84, a0); // sw v1, 84(a0)
c->subs(f1, f1, f0); // sub.s f1, f1, f0
c->sw(v1, 116, a0); // sw v1, 116(a0)
c->divs(f4, f0, f4); // div.s f4, f0, f4
c->lq(t3, 48, a2); // lq t3, 48(a2)
// nop // sll r0, r0, 0
c->lq(t4, 80, a2); // lq t4, 80(a2)
// nop // sll r0, r0, 0
c->lq(t5, 112, a2); // lq t5, 112(a2)
// nop // sll r0, r0, 0
c->lq(t6, 0, a2); // lq t6, 0(a2)
// nop // sll r0, r0, 0
c->lq(t2, 32, a2); // lq t2, 32(a2)
// nop // sll r0, r0, 0
c->lq(t0, 64, a2); // lq t0, 64(a2)
// nop // sll r0, r0, 0
c->lq(t1, 96, a2); // lq t1, 96(a2)
c->daddiu(a1, a1, -4); // daddiu a1, a1, -4
c->daddiu(a0, a0, 128); // daddiu a0, a0, 128
c->muls(f4, f4, f0); // mul.s f4, f4, f0
// nop // sll r0, r0, 0
c->divs(f3, f0, f3); // div.s f3, f0, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t7, f4); // mfc1 t7, f4
// nop // sll r0, r0, 0
c->daddiu(a2, a2, 128); // daddiu a2, a2, 128
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f3, f3, f0); // mul.s f3, f3, f0
// nop // sll r0, r0, 0
c->divs(f2, f0, f2); // div.s f2, f0, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t8, f3); // mfc1 t8, f3
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->muls(f2, f2, f0); // mul.s f2, f2, f0
// nop // sll r0, r0, 0
c->divs(f1, f0, f1); // div.s f1, f0, f1
// nop // sll r0, r0, 0
c->pextlw(t7, t8, t7); // pextlw t7, t8, t7
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t8, f2); // mfc1 t8, f2
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
c->mfc1(t9, f1); // mfc1 t9, f1
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf21, a3); // qmtc2.ni vf21, a3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf22, t3); // qmtc2.ni vf22, t3
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf23, t4); // qmtc2.ni vf23, t4
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf24, t5); // qmtc2.ni vf24, t5
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf9, t6); // qmtc2.ni vf9, t6
c->pextlw(a3, t9, t8); // pextlw a3, t9, t8
c->mov128_vf_gpr(vf10, t2); // qmtc2.ni vf10, t2
c->pcpyld(a3, a3, t7); // pcpyld a3, a3, t7
c->mov128_vf_gpr(vf11, t0); // qmtc2.ni vf11, t0
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf12, t1); // qmtc2.ni vf12, t1
// nop // sll r0, r0, 0
c->mov128_vf_gpr(vf27, a3); // qmtc2.ni vf27, a3
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t1, vf17); // qmfc2.ni t1, vf17
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t2, vf18); // qmfc2.ni t2, vf18
// nop // sll r0, r0, 0
c->mov128_gpr_vf(t0, vf19); // qmfc2.ni t0, vf19
bc = ((s64)c->sgpr64(a1)) > 0; // bgtz a1, L46
c->mov128_gpr_vf(a3, vf20); // qmfc2.ni a3, vf20
if (bc) {goto block_1;} // branch non-likely
block_2:
c->ppach(a1, r0, t1); // ppach a1, r0, t1
c->sw(v1, 20, a0); // sw v1, 20(a0)
c->ppach(a2, r0, t2); // ppach a2, r0, t2
c->sw(v1, 52, a0); // sw v1, 52(a0)
c->ppach(t0, r0, t0); // ppach t0, r0, t0
c->sw(a1, 16, a0); // sw a1, 16(a0)
c->ppach(a1, r0, a3); // ppach a1, r0, a3
c->sw(a2, 48, a0); // sw a2, 48(a0)
// nop // sll r0, r0, 0
c->sw(t0, 80, a0); // sw t0, 80(a0)
// nop // sll r0, r0, 0
c->sw(a1, 112, a0); // sw a1, 112(a0)
// nop // sll r0, r0, 0
c->sw(v1, 84, a0); // sw v1, 84(a0)
// nop // sll r0, r0, 0
c->sw(v1, 116, a0); // sw v1, 116(a0)
c->gprs[v0].du64[0] = 0; // or v0, r0, r0
//jr ra // jr ra
c->daddu(sp, sp, r0); // daddu sp, sp, r0
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.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("generic-envmap-dproc", execute, 256);
}
} // namespace generic_envmap_dproc
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
namespace Mips2C::jak1 {
namespace generic_interp_dproc {
struct Cache {
void* fake_scratchpad_data; // *fake-scratchpad-data*
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
get_fake_spad_addr(at, cache.fake_scratchpad_data, 0, c);// lui at, 28672
// nop // sll r0, r0, 0
c->lw(v1, 80, at); // lw v1, 80(at)
// nop // sll r0, r0, 0
c->lw(a0, 60, at); // lw a0, 60(at)
bc = c->sgpr64(v1) == 0; // beq v1, r0, L44
// nop // sll r0, r0, 0
if (bc) {goto block_7;} // branch non-likely
// nop // sll r0, r0, 0
c->lw(t0, 8, v1); // lw t0, 8(v1)
// nop // sll r0, r0, 0
c->lw(a2, 4, a0); // lw a2, 4(a0)
// nop // sll r0, r0, 0
c->lh(a0, 0, v1); // lh a0, 0(v1)
// nop // sll r0, r0, 0
c->lh(a1, 2, v1); // lh a1, 2(v1)
bc = c->sgpr64(a0) != 0; // bne a0, r0, L44
c->lh(a0, 4, v1); // lh a0, 4(v1)
if (bc) {goto block_7;} // branch non-likely
c->dsll(t1, a0, 5); // dsll t1, a0, 5
c->lh(a0, 12, v1); // lh a0, 12(v1)
c->daddiu(a3, a1, 7); // daddiu a3, a1, 7
c->lh(a1, 14, v1); // lh a1, 14(v1)
bc = c->sgpr64(a1) == 0; // beq a1, r0, L44
c->daddu(v1, t1, a2); // daddu v1, t1, a2
if (bc) {goto block_7;} // branch non-likely
c->pextlh(a0, a0, a0); // pextlh a0, a0, a0
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlw(a0, a0, a0); // pextlw a0, a0, a0
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(a0, a0, a0); // pcpyld a0, a0, a0
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlh(a1, a1, a1); // pextlh a1, a1, a1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlw(a1, a1, a1); // pextlw a1, a1, a1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(a1, a1, a1); // pcpyld a1, a1, a1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlw(a2, a2, a2); // pextlw a2, a2, a2
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(a2, a2, a2); // pcpyld a2, a2, a2
c->mfc1(r0, f31); // mfc1 r0, f31
c->dsra(a3, a3, 3); // dsra a3, a3, 3
// nop // sll r0, r0, 0
c->dsll(a3, a3, 4); // dsll a3, a3, 4
c->ld(t1, 0, t0); // ld t1, 0(t0)
c->daddu(a3, t0, a3); // daddu a3, t0, a3
c->daddiu(t0, t0, 8); // daddiu t0, t0, 8
c->pextlb(t1, r0, t1); // pextlb t1, r0, t1
c->mfc1(r0, f31); // mfc1 r0, f31
c->psllh(t2, t1, 5); // psllh t2, t1, 5
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextuh(t1, r0, t2); // pextuh t1, r0, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlh(t2, r0, t2); // pextlh t2, r0, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->paddw(t2, t2, a2); // paddw t2, t2, a2
c->mfc1(r0, f31); // mfc1 r0, f31
//beq r0, r0, L43 // beq r0, r0, L43
c->pcpyud(t5, t2, r0); // pcpyud t5, t2, r0
goto block_5; // branch always
block_4:
c->dsrl32(t5, t6, 0); // dsrl32 t5, t6, 0
c->dsrl32(t4, t3, 0); // dsrl32 t4, t3, 0
c->pextuh(t1, r0, t2); // pextuh t1, r0, t2
c->sw(t6, 16, v1); // sw t6, 16(v1)
c->pextlh(t2, r0, t2); // pextlh t2, r0, t2
c->sw(t5, 48, v1); // sw t5, 48(v1)
c->paddw(t2, t2, a2); // paddw t2, t2, a2
c->sw(t3, 80, v1); // sw t3, 80(v1)
c->pcpyud(t5, t2, r0); // pcpyud t5, t2, r0
c->sw(t4, 112, v1); // sw t4, 112(v1)
c->daddiu(t0, t0, 8); // daddiu t0, t0, 8
c->daddiu(v1, v1, 128); // daddiu v1, v1, 128
block_5:
c->paddw(t1, t1, a2); // paddw t1, t1, a2
c->lwu(t3, 16, t2); // lwu t3, 16(t2)
c->pcpyud(t6, t1, r0); // pcpyud t6, t1, r0
c->lwu(t4, 16, t5); // lwu t4, 16(t5)
c->dsrl32(t8, t2, 0); // dsrl32 t8, t2, 0
c->lwu(t2, 16, t1); // lwu t2, 16(t1)
c->dsrl32(t9, t5, 0); // dsrl32 t9, t5, 0
c->lwu(t5, 16, t6); // lwu t5, 16(t6)
c->dsrl32(t7, t1, 0); // dsrl32 t7, t1, 0
c->lwu(t1, 16, t8); // lwu t1, 16(t8)
c->dsrl32(t8, t6, 0); // dsrl32 t8, t6, 0
c->lwu(t6, 16, t9); // lwu t6, 16(t9)
c->pextlw(t4, t4, t3); // pextlw t4, t4, t3
c->lwu(t3, 16, t7); // lwu t3, 16(t7)
c->pextlw(t2, t5, t2); // pextlw t2, t5, t2
c->lwu(t5, 16, t8); // lwu t5, 16(t8)
c->pcpyld(t2, t2, t4); // pcpyld t2, t2, t4
c->lwu(t4, 16, v1); // lwu t4, 16(v1)
c->pextlw(t6, t6, t1); // pextlw t6, t6, t1
c->lwu(t1, 48, v1); // lwu t1, 48(v1)
c->pextlw(t3, t5, t3); // pextlw t3, t5, t3
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(t3, t3, t6); // pcpyld t3, t3, t6
c->lwu(t5, 80, v1); // lwu t5, 80(v1)
c->pextlw(t1, t1, t4); // pextlw t1, t1, t4
c->lwu(t4, 112, v1); // lwu t4, 112(v1)
c->pmulth(r0, t2, a1); // pmulth r0, t2, a1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlw(t2, t4, t5); // pextlw t2, t4, t5
c->mfc1(r0, f31); // mfc1 r0, f31
c->pmaddh(r0, t3, a1); // pmaddh r0, t3, a1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(t1, t2, t1); // pcpyld t1, t2, t1
c->ld(t2, 0, t0); // ld t2, 0(t0)
c->pmaddh(r0, t1, a0); // pmaddh r0, t1, a0
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlb(t1, r0, t2); // pextlb t1, r0, t2
c->mfc1(r0, f31); // mfc1 r0, f31
c->psllh(t2, t1, 5); // psllh t2, t1, 5
c->mfc1(r0, f31); // mfc1 r0, f31
// Unknown instr: pmfhl.lw t3
c->pmfhl_lw(t3);
c->mfc1(r0, f31); // mfc1 r0, f31
// Unknown instr: pmfhl.uw t1
c->pmfhl_uw(t1);
c->mfc1(r0, f31); // mfc1 r0, f31
c->psraw(t3, t3, 8); // psraw t3, t3, 8
c->mfc1(r0, f31); // mfc1 r0, f31
c->psraw(t1, t1, 8); // psraw t1, t1, 8
c->mfc1(r0, f31); // mfc1 r0, f31
c->pinteh(t6, t1, t3); // pinteh t6, t1, t3
c->mfc1(r0, f31); // mfc1 r0, f31
bc = c->sgpr64(t0) != c->sgpr64(a3); // bne t0, a3, L42
c->pcpyud(t3, t6, r0); // pcpyud t3, t6, r0
if (bc) {goto block_4;} // branch non-likely
c->dsrl32(a0, t6, 0); // dsrl32 a0, t6, 0
c->sw(t6, 16, v1); // sw t6, 16(v1)
c->dsrl32(a1, t3, 0); // dsrl32 a1, t3, 0
c->sw(a0, 48, v1); // sw a0, 48(v1)
// nop // sll r0, r0, 0
c->sw(t3, 80, v1); // sw t3, 80(v1)
// nop // sll r0, r0, 0
c->sw(a1, 112, v1); // sw a1, 112(v1)
block_7:
//jr ra // jr ra
c->daddu(sp, sp, r0); // daddu sp, sp, r0
goto end_of_function; // return
// nop // sll r0, r0, 0
// 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.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("generic-interp-dproc", execute, 128);
}
} // namespace generic_interp_dproc
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
namespace Mips2C::jak1 {
namespace generic_no_light_dproc {
struct Cache {
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, 12432, at); // sd ra, 12432(at)
c->sq(s0, 12448, at); // sq s0, 12448(at)
c->sq(s1, 12464, at); // sq s1, 12464(at)
c->sq(s2, 12480, at); // sq s2, 12480(at)
c->sq(s3, 12496, at); // sq s3, 12496(at)
c->sq(s4, 12512, at); // sq s4, 12512(at)
c->sq(s5, 12528, at); // sq s5, 12528(at)
c->sq(gp, 12544, at); // sq gp, 12544(at)
get_fake_spad_addr(at, cache.fake_scratchpad_data, 0, c);// lui at, 28672
// nop // sll r0, r0, 0
c->lw(a1, 60, at); // lw a1, 60(at)
// nop // sll r0, r0, 0
c->lw(a0, 52, at); // lw a0, 52(at)
// nop // sll r0, r0, 0
c->lw(v1, 0, a1); // lw v1, 0(a1)
// nop // sll r0, r0, 0
c->lw(a2, 4, a1); // lw a2, 4(a1)
c->daddiu(a0, a0, 3); // daddiu a0, a0, 3
// nop // sll r0, r0, 0
c->dsra(a0, a0, 2); // dsra a0, a0, 2
// nop // sll r0, r0, 0
c->dsll(a0, a0, 3); // dsll a0, a0, 3
c->addiu(a3, r0, 255); // addiu a3, r0, 255
c->lui(a1, -2); // lui a1, -2
c->addiu(t1, r0, 256); // addiu t1, r0, 256
c->ori(a1, a1, 65534); // ori a1, a1, 65534
c->daddu(a0, v1, a0); // daddu a0, v1, a0
c->pextlw(a1, a1, a1); // pextlw a1, a1, a1
c->lw(t2, 20, at); // lw t2, 20(at)
c->pextlw(a1, a1, a1); // pextlw a1, a1, a1
c->lw(t3, 24, at); // lw t3, 24(at)
c->pextlw(a2, a2, a2); // pextlw a2, a2, a2
c->lw(t5, 28, at); // lw t5, 28(at)
c->pextlw(a2, a2, a2); // pextlw a2, a2, a2
c->lw(t4, 32, at); // lw t4, 32(at)
c->pcpyh(a3, a3); // pcpyh a3, a3
c->lw(t6, 36, at); // lw t6, 36(at)
c->pcpyld(a3, a3, a3); // pcpyld a3, a3, a3
c->lq(t0, 12160, at); // lq t0, 12160(at)
c->pcpyh(t1, t1); // pcpyh t1, t1
c->ld(t7, 0, v1); // ld t7, 0(v1)
c->pcpyld(t1, t1, t1); // pcpyld t1, t1, t1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlh(t8, r0, t7); // pextlh t8, r0, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->pand(t7, t8, a3); // pand t7, t8, a3
c->mfc1(r0, f31); // mfc1 r0, f31
c->psllw(t7, t7, 5); // psllw t7, t7, 5
c->mfc1(r0, f31); // mfc1 r0, f31
c->daddiu(t2, t2, -48); // daddiu t2, t2, -48
c->daddiu(t3, t3, -16); // daddiu t3, t3, -16
c->daddiu(t4, t4, -16); // daddiu t4, t4, -16
c->daddiu(t5, t5, -16); // daddiu t5, t5, -16
//beq r0, r0, L34 // beq r0, r0, L34
c->daddiu(t6, t6, -16); // daddiu t6, t6, -16
goto block_3; // branch always
// nop // sll r0, r0, 0
block_2:
c->pextlh(t8, r0, gp); // pextlh t8, r0, gp
c->sq(t7, 0, t2); // sq t7, 0(t2)
c->pand(t7, t8, a3); // pand t7, t8, a3
c->sq(t9, 16, t2); // sq t9, 16(t2)
c->psllw(t7, t7, 5); // psllw t7, t7, 5
c->sq(ra, 32, t2); // sq ra, 32(t2)
block_3:
c->paddw(s3, t7, a2); // paddw s3, t7, a2
c->mfc1(r0, f31); // mfc1 r0, f31
c->dsrl32(s2, s3, 0); // dsrl32 s2, s3, 0
c->daddiu(t2, t2, 48); // daddiu t2, t2, 48
c->pcpyud(s5, s3, r0); // pcpyud s5, s3, r0
c->lq(t7, 0, s3); // lq t7, 0(s3)
c->dsrl32(s4, s5, 0); // dsrl32 s4, s5, 0
c->daddiu(t3, t3, 16); // daddiu t3, t3, 16
c->pand(t8, t8, t1); // pand t8, t8, t1
c->lq(t9, 0, s2); // lq t9, 0(s2)
c->psraw(gp, t8, 8); // psraw gp, t8, 8
c->lq(t8, 0, s5); // lq t8, 0(s5)
c->pextuw(s1, t9, t7); // pextuw s1, t9, t7
c->lq(ra, 0, s4); // lq ra, 0(s4)
c->daddiu(t5, t5, 16); // daddiu t5, t5, 16
c->daddiu(v1, v1, 8); // daddiu v1, v1, 8
c->daddiu(t4, t4, 16); // daddiu t4, t4, 16
c->daddiu(t6, t6, 16); // daddiu t6, t6, 16
c->pextuw(s0, ra, t8); // pextuw s0, ra, t8
c->lq(s3, 16, s3); // lq s3, 16(s3)
c->pcpyud(s1, s1, s0); // pcpyud s1, s1, s0
c->lq(s2, 16, s2); // lq s2, 16(s2)
c->paddh(s0, s1, t0); // paddh s0, s1, t0
c->lq(s1, 16, s5); // lq s1, 16(s5)
c->pand(s5, s0, a1); // pand s5, s0, a1
c->lq(s0, 16, s4); // lq s0, 16(s4)
c->pextlw(s4, s2, s3); // pextlw s4, s2, s3
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextuw(s3, s2, s3); // pextuw s3, s2, s3
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextlw(s2, s0, s1); // pextlw s2, s0, s1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextuw(s0, s0, s1); // pextuw s0, s0, s1
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(s1, s2, s4); // pcpyld s1, s2, s4
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyud(s4, s4, s2); // pcpyud s4, s4, s2
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyud(s3, s3, s0); // pcpyud s3, s3, s0
c->sq(s4, 0, t4); // sq s4, 0(t4)
c->pand(s4, s1, a1); // pand s4, s1, a1
c->sq(s3, 0, t3); // sq s3, 0(t3)
c->por(s4, s4, gp); // por s4, s4, gp
c->mfc1(r0, f31); // mfc1 r0, f31
c->por(gp, s5, gp); // por gp, s5, gp
c->sq(s4, 0, t6); // sq s4, 0(t6)
c->prot3w(ra, ra); // prot3w ra, ra
c->sq(gp, 0, t5); // sq gp, 0(t5)
c->prot3w(t9, t9); // prot3w t9, t9
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextuw(s5, t9, t7); // pextuw s5, t9, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->pcpyld(t9, t8, t9); // pcpyld t9, t8, t9
c->ld(gp, 0, v1); // ld gp, 0(v1)
c->pcpyld(t7, s5, t7); // pcpyld t7, s5, t7
c->mfc1(r0, f31); // mfc1 r0, f31
c->pextuw(t8, ra, t8); // pextuw t8, ra, t8
c->mfc1(r0, f31); // mfc1 r0, f31
bc = c->sgpr64(v1) != c->sgpr64(a0); // bne v1, a0, L33
c->pcpyld(ra, ra, t8); // pcpyld ra, ra, t8
if (bc) {goto block_2;} // branch non-likely
// nop // sll r0, r0, 0
c->sq(t7, 0, t2); // sq t7, 0(t2)
// nop // sll r0, r0, 0
c->sq(t9, 16, t2); // sq t9, 16(t2)
// nop // sll r0, r0, 0
c->sq(ra, 32, t2); // sq ra, 32(t2)
c->gprs[v0].du64[0] = 0; // or v0, r0, r0
c->ld(ra, 12432, at); // ld ra, 12432(at)
c->lq(gp, 12544, at); // lq gp, 12544(at)
c->lq(s5, 12528, at); // lq s5, 12528(at)
c->lq(s4, 12512, at); // lq s4, 12512(at)
c->lq(s3, 12496, at); // lq s3, 12496(at)
c->lq(s2, 12480, at); // lq s2, 12480(at)
c->lq(s1, 12464, at); // lq s1, 12464(at)
c->lq(s0, 12448, at); // lq s0, 12448(at)
//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.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("generic-no-light-dproc", execute, 256);
}
} // namespace generic_no_light_dproc
} // namespace Mips2C
+3 -13
View File
@@ -114,16 +114,6 @@ namespace generic_prepare_dma_double {
extern u64 execute(void* ctxt);
}
namespace generic_envmap_dproc {
extern u64 execute(void* ctxt);
}
namespace generic_interp_dproc {
extern u64 execute(void* ctxt);
}
namespace generic_no_light_dproc {
extern u64 execute(void* ctxt);
}
namespace generic_tie_convert {
struct Cache {
void* fake_scratchpad_data; // *fake-scratchpad-data*
@@ -2092,17 +2082,17 @@ u64 execute(void* ctxt) {
call_addr = c->gprs[v1].du32[0]; // function call:
// Unknown instr: sllv v0, ra, r0
// c->jalr(call_addr); // jalr ra, v1
generic_envmap_dproc::execute(c);
// generic_envmap_dproc::execute(c);
c->lw(v1, 756, at); // lw v1, 756(at)
call_addr = c->gprs[v1].du32[0]; // function call:
// Unknown instr: sllv v0, ra, r0
// c->jalr(call_addr); // jalr ra, v1
generic_interp_dproc::execute(c);
// generic_interp_dproc::execute(c);
c->lw(v1, 760, at); // lw v1, 760(at)
call_addr = c->gprs[v1].du32[0]; // function call:
// Unknown instr: sllv v0, ra, r0
// c->jalr(call_addr); // jalr ra, v1
generic_no_light_dproc::execute(c);
// generic_no_light_dproc::execute(c);
c->lw(v1, 40, at); // lw v1, 40(at)
c->lw(a0, 56, at); // lw a0, 56(at)
c->mov64(a3, v1); // or a3, v1, r0
-581
View File
@@ -1,581 +0,0 @@
//--------------------------MIPS2C---------------------
#include "game/kernel/jak1/kscheme.h"
#include "game/mips2c/mips2c_private.h"
using namespace jak1;
namespace Mips2C::jak1 {
struct RippleVu0 {
Vf data_mem[256];
void sq(const Vf& reg, u16 addr) {
ASSERT(addr < 256);
data_mem[addr] = reg;
}
Vf lq(u16 addr) {
ASSERT(addr < 256);
return data_mem[addr];
}
} gRippleVu0;
namespace ripple_execute_init {
struct Cache {
void* cos_poly_vec; // *cos-poly-vec*
} cache;
// clang-format off
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
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->load_symbol(v1, cache.cos_poly_vec); // lw v1, *cos-poly-vec*(s7)
c->lqc2(vf7, 0, v1); // lqc2 vf7, 0(v1)
c->fprs[f0] = 0.024543691; // lwc1 f0, L50(fp)
c->mfc1(v1, f0); // mfc1 v1, f0
c->mov128_vf_gpr(vf6, v1); // qmtc2.i vf6, v1
c->mov128_gpr_vf(v1, vf6); // qmfc2.i v1, vf6
c->addiu(v1, r0, 128); // addiu v1, r0, 128
u16 vi2 = c->gpr_src(v1).du16[0]; // ctc2.i vi2, v1
c->gprs[v1].du64[0] = vi2; // cfc2.i v1, vi2
c->fprs[f0] = 1.0; // lwc1 f0, L61(fp)
c->mfc1(v1, f0); // mfc1 v1, f0
c->mov128_vf_gpr(vf9, v1); // qmtc2.i vf9, v1
c->mov128_gpr_vf(v1, vf9); // qmfc2.i v1, vf9
u16 vi1 = 0; // viaddi vi1, vi0, 0
c->addiu(v1, r0, 128); // addiu v1, r0, 128
c->vmove(DEST::xyzw, vf5, vf6); // vmove.xyzw vf5, vf6
block_1:
c->vmul(DEST::xyzw, vf1, vf5, vf5); // vmul.xyzw vf1, vf5, vf5
c->vadda_bc(DEST::xyzw, BC::w, vf0, vf0); // vaddaw.xyzw acc, vf0, vf0
c->vadd(DEST::x, vf5, vf5, vf6); // vadd.x vf5, vf5, vf6
c->vsub_bc(DEST::y, BC::x, vf9, vf0, vf9); // vsubx.y vf9, vf0, vf9
c->vmul(DEST::xyzw, vf2, vf1, vf1); // vmul.xyzw vf2, vf1, vf1
c->vmadda_bc(DEST::xyzw, BC::x, vf1, vf7); // vmaddax.xyzw acc, vf1, vf7
c->vmul(DEST::xyzw, vf3, vf2, vf1); // vmul.xyzw vf3, vf2, vf1
c->vmadda_bc(DEST::xyzw, BC::y, vf2, vf7); // vmadday.xyzw acc, vf2, vf7
c->vmul(DEST::xyzw, vf4, vf2, vf2); // vmul.xyzw vf4, vf2, vf2
c->vmadda_bc(DEST::xyzw, BC::z, vf3, vf7); // vmaddaz.xyzw acc, vf3, vf7
c->daddiu(v1, v1, -1); // daddiu v1, v1, -1
c->vmadd_bc(DEST::xyzw, BC::w, vf8, vf4, vf7); // vmaddw.xyzw vf8, vf4, vf7
c->vadd_bc(DEST::y, BC::x, vf9, vf9, vf8); // vaddx.y vf9, vf9, vf8
c->vsub(DEST::xyzw, vf10, vf0, vf9); // vsub.xyzw vf10, vf0, vf9
gRippleVu0.sq(c->vfs[vf9].vf, vi1++); // vsqi.xyzw vf9, vi1
c->vmove(DEST::xyzw, vf9, vf8); // vmove.xyzw vf9, vf8
bc = c->sgpr64(v1) != 0; // bne v1, r0, L39
gRippleVu0.sq(c->vfs[vf10].vf, vi2++); // vsqi.xyzw vf10, vi2
if (bc) {goto block_1;} // branch non-likely
c->gprs[v0].du64[0] = 0; // or v0, r0, r0
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
end_of_function:
return c->gprs[v0].du64[0];
}
void link() {
cache.cos_poly_vec = intern_from_c("*cos-poly-vec*").c();
gLinkedFunctionTable.reg("ripple-execute-init", execute, 32);
}
} // namespace ripple_execute_init
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
namespace Mips2C::jak1 {
namespace ripple_create_wave_table {
struct Cache {
void* fake_scratchpad_data; // *fake-scratchpad-data*
void* setting_control; // *setting-control*
void* atan; // atan
void* cos; // cos
void* ntsc; // ntsc
void* pal; // pal
void* ripple_update_waveform_offs; // ripple-update-waveform-offs
void* sin; // sin
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
u16 vi1, vi2;
u32 call_addr = 0;
c->daddiu(sp, sp, -80); // daddiu sp, sp, -80
c->sd(ra, 0, sp); // sd ra, 0(sp)
c->sd(fp, 8, sp); // sd fp, 8(sp)
c->mov64(fp, t9); // or fp, t9, r0
c->sq(s4, 16, sp); // sq s4, 16(sp)
c->sq(s5, 32, sp); // sq s5, 32(sp)
c->sq(gp, 48, sp); // sq gp, 48(sp)
c->swc1(f28, 64, sp); // swc1 f28, 64(sp)
c->swc1(f30, 68, sp); // swc1 f30, 68(sp)
c->mov64(gp, a0); // or gp, a0, r0
c->lwu(v1, 4, gp); // lwu v1, 4(gp)
bc = c->sgpr64(s7) != c->sgpr64(v1); // bne s7, v1, L30
c->mov64(v1, s7); // or v1, s7, r0
if (bc) {goto block_9;} // branch non-likely
c->addiu(s5, r0, 0); // addiu s5, r0, 0
//beq r0, r0, L29 // beq r0, r0, L29
// nop // sll r0, r0, 0
goto block_7; // branch always
block_2:
c->addiu(v1, r0, 28); // addiu v1, r0, 28
c->mult3(v1, v1, s5); // mult3 v1, v1, s5
c->daddiu(v1, v1, 16); // daddiu v1, v1, 16
c->daddu(s4, v1, gp); // daddu s4, v1, gp
c->load_symbol(t9, cache.atan); // lw t9, atan(s7)
c->lh(v1, 10, s4); // lh v1, 10(s4)
c->mtc1(f0, v1); // mtc1 f0, v1
c->cvtsw(f0, f0); // cvt.s.w f0, f0
c->mfc1(a0, f0); // mfc1 a0, f0
c->lh(v1, 8, s4); // lh v1, 8(s4)
c->mtc1(f0, v1); // mtc1 f0, v1
c->cvtsw(f0, f0); // cvt.s.w f0, f0
c->mfc1(a1, f0); // mfc1 a1, f0
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->mtc1(f28, v0); // mtc1 f28, v0
c->fprs[f0] = 16.0; // lwc1 f0, L60(fp)
c->lh(v1, 8, s4); // lh v1, 8(s4)
c->lh(a0, 8, s4); // lh a0, 8(s4)
c->mult3(v1, v1, a0); // mult3 v1, v1, a0
c->lh(a0, 10, s4); // lh a0, 10(s4)
c->lh(a1, 10, s4); // lh a1, 10(s4)
c->mult3(a0, a0, a1); // mult3 a0, a0, a1
c->daddu(v1, v1, a0); // daddu v1, v1, a0
c->mtc1(f1, v1); // mtc1 f1, v1
c->cvtsw(f1, f1); // cvt.s.w f1, f1
c->sqrts(f1, f1); // sqrt.s f1, f1
c->divs(f30, f0, f1); // div.s f30, f0, f1
c->load_symbol(t9, cache.cos); // lw t9, cos(s7)
c->mfc1(a0, f28); // mfc1 a0, f28
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->mtc1(f0, v0); // mtc1 f0, v0
c->fprs[f1] = 65536.0; // lwc1 f1, L52(fp)
c->divs(f1, f1, f30); // div.s f1, f1, f30
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->swc1(f0, 16, s4); // swc1 f0, 16(s4)
c->load_symbol(t9, cache.sin); // lw t9, sin(s7)
c->mfc1(a0, f28); // mfc1 a0, f28
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->mtc1(f0, v0); // mtc1 f0, v0
c->fprs[f1] = 65536.0; // lwc1 f1, L52(fp)
c->divs(f1, f1, f30); // div.s f1, f1, f30
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->swc1(f0, 20, s4); // swc1 f0, 20(s4)
c->load_symbol(v1, cache.setting_control); // lw v1, *setting-control*(s7)
c->lwu(v1, 80, v1); // lwu v1, 80(v1)
c->load_symbol_addr(a0, cache.ntsc); // daddiu a0, s7, ntsc
bc = c->sgpr64(v1) != c->sgpr64(a0); // bne v1, a0, L27
c->mov64(a0, s7); // or a0, s7, r0
if (bc) {goto block_4;} // branch non-likely
c->fprs[f0] = 0.016666668; // lwc1 f0, L55(fp)
c->fprs[f1] = -65536.0; // lwc1 f1, L53(fp)
c->divs(f1, f1, f30); // div.s f1, f1, f30
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->lwc1(f1, 12, s4); // lwc1 f1, 12(s4)
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->swc1(f0, 24, s4); // swc1 f0, 24(s4)
c->mfc1(v1, f0); // mfc1 v1, f0
//beq r0, r0, L28 // beq r0, r0, L28
// nop // sll r0, r0, 0
goto block_6; // branch always
block_4:
c->load_symbol_addr(a0, cache.pal); // daddiu a0, s7, pal
bc = c->sgpr64(v1) != c->sgpr64(a0); // bne v1, a0, L28
c->mov64(v1, s7); // or v1, s7, r0
if (bc) {goto block_6;} // branch non-likely
c->fprs[f0] = 0.02; // lwc1 f0, L51(fp)
c->fprs[f1] = -65536.0; // lwc1 f1, L53(fp)
c->divs(f1, f1, f30); // div.s f1, f1, f30
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->lwc1(f1, 12, s4); // lwc1 f1, 12(s4)
c->muls(f0, f0, f1); // mul.s f0, f0, f1
c->swc1(f0, 24, s4); // swc1 f0, 24(s4)
c->mfc1(v1, f0); // mfc1 v1, f0
block_6:
c->daddiu(s5, s5, 1); // daddiu s5, s5, 1
block_7:
c->lw(v1, 0, gp); // lw v1, 0(gp)
c->slt(v1, s5, v1); // slt v1, s5, v1
bc = c->sgpr64(v1) != 0; // bne v1, r0, L26
// nop // sll r0, r0, 0
if (bc) {goto block_2;} // branch non-likely
c->mov64(v1, s7); // or v1, s7, r0
c->mov64(v1, s7); // or v1, s7, r0
c->daddiu(v1, s7, 8); // daddiu v1, s7, #t
c->sw(v1, 4, gp); // sw v1, 4(gp)
block_9:
c->load_symbol(t9, cache.ripple_update_waveform_offs);// lw t9, ripple-update-waveform-offs(s7)
c->mov64(a0, gp); // or a0, gp, r0
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
get_fake_spad_addr(v1, cache.fake_scratchpad_data, 0, c);// lui v1, 28672
c->addiu(a0, r0, 64); // addiu a0, r0, 64
c->mov64(a1, v1); // or a1, v1, r0
block_10:
c->daddiu(a0, a0, -1); // daddiu a0, a0, -1
c->sq(r0, 0, a1); // sq r0, 0(a1)
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
// nop // sll r0, r0, 0
bc = c->sgpr64(a0) != 0; // bne a0, r0, L31
c->daddiu(a1, a1, 16); // daddiu a1, a1, 16
if (bc) {goto block_10;} // branch non-likely
c->addiu(a0, r0, 0); // addiu a0, r0, 0
//beq r0, r0, L35 // beq r0, r0, L35
// nop // sll r0, r0, 0
goto block_17; // branch always
block_12:
c->addiu(a1, r0, 28); // addiu a1, r0, 28
c->mult3(a1, a1, a0); // mult3 a1, a1, a0
c->daddiu(a1, a1, 16); // daddiu a1, a1, 16
c->daddu(a1, a1, gp); // daddu a1, a1, gp
c->fprs[f0] = 16384.0; // lwc1 f0, L54(fp)
c->fprs[f1] = 0.00390625; // lwc1 f1, L63(fp)
c->lwc1(f2, 4, a1); // lwc1 f2, 4(a1)
c->muls(f1, f1, f2); // mul.s f1, f1, f2
c->adds(f0, f0, f1); // add.s f0, f0, f1
c->fprs[f1] = 0.00390625; // lwc1 f1, L63(fp)
c->lwc1(f2, 16, a1); // lwc1 f2, 16(a1)
c->muls(f1, f1, f2); // mul.s f1, f1, f2
c->fprs[f2] = 0.00390625; // lwc1 f2, L63(fp)
c->lwc1(f3, 20, a1); // lwc1 f3, 20(a1)
c->muls(f2, f2, f3); // mul.s f2, f2, f3
c->lwc1(f3, 0, a1); // lwc1 f3, 0(a1)
c->addiu(a1, r0, 255); // addiu a1, r0, 255
c->mfc1(a2, f0); // mfc1 a2, f0
c->mov128_vf_gpr(vf1, a2); // qmtc2.i vf1, a2
c->mfc1(a2, f1); // mfc1 a2, f1
c->mov128_vf_gpr(vf2, a2); // qmtc2.i vf2, a2
c->mfc1(a2, f2); // mfc1 a2, f2
c->mov128_vf_gpr(vf3, a2); // qmtc2.i vf3, a2
c->mfc1(a2, f3); // mfc1 a2, f3
c->mov128_vf_gpr(vf4, a2); // qmtc2.i vf4, a2
vi1 = c->gpr_src(a1).du16[0]; // ctc2.i vi1, a1
c->mov64(a1, v1); // or a1, v1, r0
c->addiu(a2, r0, 16); // addiu a2, r0, 16
c->vmove(DEST::xyzw, vf6, vf0); // vmove.xyzw vf6, vf0
block_13:
c->addiu(a3, r0, 16); // addiu a3, r0, 16
c->vmove(DEST::xyzw, vf5, vf0); // vmove.xyzw vf5, vf0
block_14:
c->lw(at, 0, a1); // lw at, 0(a1)
c->vadda_bc(DEST::xyzw, BC::x, vf1, vf0); // vaddax.xyzw acc, vf1, vf0
c->vmadda(DEST::xyzw, vf2, vf5); // vmadda.xyzw acc, vf2, vf5
c->vmadd(DEST::xyzw, vf7, vf3, vf6); // vmadd.xyzw vf7, vf3, vf6
c->mov128_vf_gpr(vf10, at); // qmtc2.i vf10, at
c->vadd_bc(DEST::xyzw, BC::w, vf5, vf5, vf0); // vaddw.xyzw vf5, vf5, vf0
c->vftoi0(DEST::xyzw, vf8, vf7); // vftoi0.xyzw vf8, vf7
vi2 = c->vfs[vf8].vf.x_as_u16(); // vmtirx vi2, vf8
c->vitof0(DEST::xyzw, vf8, vf8); // vitof0.xyzw vf8, vf8
vi2 &= vi1; // Unknown instr: viand vi2, vi2, vi1
c->vfs[vf9].vf = gRippleVu0.lq(vi2++); // Unknown instr: vlqi.xyzw vf9, vi2
c->vsub(DEST::xyzw, vf7, vf7, vf8); // vsub.xyzw vf7, vf7, vf8
c->vadda_bc(DEST::xyzw, BC::x, vf0, vf9); // vaddax.xyzw acc, vf0, vf9
c->vmadd_bc(DEST::xyzw, BC::y, vf9, vf7, vf9); // vmaddy.xyzw vf9, vf7, vf9
c->vadda_bc(DEST::xyzw, BC::x, vf10, vf0); // vaddax.xyzw acc, vf10, vf0
c->vmadd(DEST::xyzw, vf10, vf9, vf4); // vmadd.xyzw vf10, vf9, vf4
c->mov128_gpr_vf(at, vf10); // qmfc2.i at, vf10
c->sw(at, 0, a1); // sw at, 0(a1)
c->daddiu(a3, a3, -1); // daddiu a3, a3, -1
bc = c->sgpr64(a3) != 0; // bne a3, r0, L34
c->daddiu(a1, a1, 4); // daddiu a1, a1, 4
if (bc) {goto block_14;} // branch non-likely
c->daddiu(a2, a2, -1); // daddiu a2, a2, -1
bc = c->sgpr64(a2) != 0; // bne a2, r0, L33
c->vadd_bc(DEST::xyzw, BC::w, vf6, vf6, vf0); // vaddw.xyzw vf6, vf6, vf0
if (bc) {goto block_13;} // branch non-likely
c->mov128_gpr_vf(a1, vf6); // qmfc2.i a1, vf6
c->daddiu(a0, a0, 1); // daddiu a0, a0, 1
block_17:
c->lw(a1, 0, gp); // lw a1, 0(gp)
c->slt(a1, a0, a1); // slt a1, a0, a1
bc = c->sgpr64(a1) != 0; // bne a1, r0, L32
// nop // sll r0, r0, 0
if (bc) {goto block_12;} // branch non-likely
c->mov64(a0, s7); // or a0, s7, r0
c->mov64(a0, s7); // or a0, s7, r0
c->fprs[f1] = 128.0; // lwc1 f1, L57(fp)
c->fprs[f0] = 255.0; // lwc1 f0, L56(fp)
c->lwc1(f2, 12, gp); // lwc1 f2, 12(gp)
c->mfc1(a0, f2); // mfc1 a0, f2
c->mov128_vf_gpr(vf16, a0); // qmtc2.i vf16, a0
c->mfc1(a0, f1); // mfc1 a0, f1
c->mov128_vf_gpr(vf14, a0); // qmtc2.i vf14, a0
c->mfc1(a0, f0); // mfc1 a0, f0
c->mov128_vf_gpr(vf15, a0); // qmtc2.i vf15, a0
c->vmax_bc(DEST::xyzw, BC::x, vf16, vf0, vf16); // vmaxx.xyzw vf16, vf0, vf16
c->vmini_bc(DEST::w, BC::x, vf16, vf0, vf0); // vminix.w vf16, vf0, vf0
c->mov64(v1, v1); // or v1, v1, r0
c->addiu(v0, r0, 15); // addiu v0, r0, 15
block_19:
c->addiu(a0, r0, 15); // addiu a0, r0, 15
// nop // sll r0, r0, 0
block_20:
c->addiu(a2, r0, 4); // addiu a2, r0, 4
c->addiu(at, r0, -60); // addiu at, r0, -60
c->movz(a2, at, a0); // movz a2, at, a0
c->addiu(a1, r0, 64); // addiu a1, r0, 64
c->addiu(at, r0, -960); // addiu at, r0, -960
c->daddu(a2, a2, v1); // daddu a2, a2, v1
c->movz(a1, at, v0); // movz a1, at, v0
c->lw(at, 0, v1); // lw at, 0(v1)
c->lw(a2, 0, a2); // lw a2, 0(a2)
c->daddu(a1, a1, v1); // daddu a1, a1, v1
c->lw(a1, 0, a1); // lw a1, 0(a1)
c->mov128_vf_gpr(vf11, at); // qmtc2.i vf11, at
c->mov128_vf_gpr(vf12, a2); // qmtc2.i vf12, a2
c->mov128_vf_gpr(vf13, a1); // qmtc2.i vf13, a1
c->vadd_bc(DEST::xyzw, BC::x, vf11, vf0, vf11); // vaddx.xyzw vf11, vf0, vf11
c->vsub_bc(DEST::y, BC::x, vf11, vf11, vf12); // vsubx.y vf11, vf11, vf12
c->vsub_bc(DEST::z, BC::x, vf11, vf11, vf13); // vsubx.z vf11, vf11, vf13
c->vmul(DEST::yzw, vf11, vf11, vf16); // vmul.yzw vf11, vf11, vf16
c->vadd_bc(DEST::xyzw, BC::x, vf11, vf11, vf14); // vaddx.xyzw vf11, vf11, vf14
c->vmax_bc(DEST::xyzw, BC::x, vf11, vf11, vf0); // vmaxx.xyzw vf11, vf11, vf0
c->vmini_bc(DEST::xyzw, BC::x, vf11, vf11, vf15); // vminix.xyzw vf11, vf11, vf15
c->vftoi0(DEST::xyzw, vf11, vf11); // vftoi0.xyzw vf11, vf11
c->mov128_gpr_vf(at, vf11); // qmfc2.i at, vf11
c->ppach(at, at, at); // ppach at, at, at
c->ppacb(at, at, at); // ppacb at, at, at
c->sw(at, 1024, v1); // sw at, 1024(v1)
c->daddiu(v1, v1, 4); // daddiu v1, v1, 4
bc = c->sgpr64(a0) != 0; // bne a0, r0, L37
c->daddiu(a0, a0, -1); // daddiu a0, a0, -1
if (bc) {goto block_20;} // branch non-likely
bc = c->sgpr64(v0) != 0; // bne v0, r0, L36
c->daddiu(v0, v0, -1); // daddiu v0, v0, -1
if (bc) {goto block_19;} // branch non-likely
c->ld(ra, 0, sp); // ld ra, 0(sp)
c->ld(fp, 8, sp); // ld fp, 8(sp)
c->lwc1(f30, 68, sp); // lwc1 f30, 68(sp)
c->lwc1(f28, 64, sp); // lwc1 f28, 64(sp)
c->lq(gp, 48, sp); // lq gp, 48(sp)
c->lq(s5, 32, sp); // lq s5, 32(sp)
c->lq(s4, 16, sp); // lq s4, 16(sp)
//jr ra // jr ra
c->daddiu(sp, sp, 80); // daddiu sp, sp, 80
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.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
cache.setting_control = intern_from_c("*setting-control*").c();
cache.atan = intern_from_c("atan").c();
cache.cos = intern_from_c("cos").c();
cache.ntsc = intern_from_c("ntsc").c();
cache.pal = intern_from_c("pal").c();
cache.ripple_update_waveform_offs = intern_from_c("ripple-update-waveform-offs").c();
cache.sin = intern_from_c("sin").c();
gLinkedFunctionTable.reg("ripple-create-wave-table", execute, 128);
}
} // namespace ripple_create_wave_table
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
namespace Mips2C::jak1 {
namespace ripple_apply_wave_table {
struct Cache {
void* fake_scratchpad_data; // *fake-scratchpad-data*
} cache;
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
get_fake_spad_addr(v1, cache.fake_scratchpad_data, 0, c);// lui v1, 28672
c->daddiu(v1, v1, 1024); // daddiu v1, v1, 1024
c->lwu(a1, 4, a0); // lwu a1, 4(a0)
c->lwu(t2, 0, a0); // lwu t2, 0(a0)
c->lwu(a2, 8, a0); // lwu a2, 8(a0)
c->lwu(a3, 12, a0); // lwu a3, 12(a0)
c->lhu(a0, 18, a0); // lhu a0, 18(a0)
c->addiu(t0, r0, 0); // addiu t0, r0, 0
//beq r0, r0, L24 // beq r0, r0, L24
// nop // sll r0, r0, 0
goto block_4; // branch always
block_1:
c->lbu(t1, 0, a3); // lbu t1, 0(a3)
c->lbu(t3, 0, a1); // lbu t3, 0(a1)
c->daddiu(t3, t3, 3); // daddiu t3, t3, 3
c->dsrl(t3, t3, 2); // dsrl t3, t3, 2
c->dsll(t3, t3, 4); // dsll t3, t3, 4
c->daddu(t2, t2, t3); // daddu t2, t2, t3
c->mov64(t4, t2); // or t4, t2, r0
c->mov64(t3, t1); // or t3, t1, r0
c->mov64(t5, t4); // or t5, t4, r0
c->mov64(t4, a2); // or t4, a2, r0
block_2:
c->lb(t6, 0, t4); // lb t6, 0(t4)
c->lb(t7, 1, t4); // lb t7, 1(t4)
c->andi(t6, t6, 15); // andi t6, t6, 15
c->andi(t7, t7, 15); // andi t7, t7, 15
c->sll(t7, t7, 4); // sll t7, t7, 4
c->daddu(t6, t6, t7); // daddu t6, t6, t7
c->sll(t6, t6, 2); // sll t6, t6, 2
c->daddu(t8, t6, v1); // daddu t8, t6, v1
c->lb(t6, 0, t8); // lb t6, 0(t8)
c->lb(t7, 1, t8); // lb t7, 1(t8)
c->lb(t8, 2, t8); // lb t8, 2(t8)
c->sb(t6, 7, t5); // sb t6, 7(t5)
c->sb(t7, 2, t5); // sb t7, 2(t5)
c->sb(t8, 10, t5); // sb t8, 10(t5)
c->daddiu(t3, t3, -1); // daddiu t3, t3, -1
c->daddiu(t4, t4, 2); // daddiu t4, t4, 2
bc = c->sgpr64(t3) != 0; // bne t3, r0, L23
c->daddiu(t5, t5, 12); // daddiu t5, t5, 12
if (bc) {goto block_2;} // branch non-likely
c->lbu(t3, 2, a1); // lbu t3, 2(a1)
c->lbu(t4, 1, a1); // lbu t4, 1(a1)
c->daddiu(t4, t4, 3); // daddiu t4, t4, 3
c->dsrl(t4, t4, 2); // dsrl t4, t4, 2
c->daddu(t3, t3, t4); // daddu t3, t3, t4
c->dsll(t3, t3, 4); // dsll t3, t3, 4
c->daddu(t2, t2, t3); // daddu t2, t2, t3
c->lbu(t3, 3, a1); // lbu t3, 3(a1)
c->dsll(t3, t3, 1); // dsll t3, t3, 1
c->daddiu(t3, t3, 4); // daddiu t3, t3, 4
c->daddu(a1, a1, t3); // daddu a1, a1, t3
c->dsll(t1, t1, 1); // dsll t1, t1, 1
c->daddiu(t1, t1, 15); // daddiu t1, t1, 15
c->andi(t1, t1, 65520); // andi t1, t1, 65520
c->daddu(a2, a2, t1); // daddu a2, a2, t1
c->daddiu(a3, a3, 2); // daddiu a3, a3, 2
c->mov64(t1, a3); // or t1, a3, r0
c->daddiu(t0, t0, 1); // daddiu t0, t0, 1
block_4:
c->slt(t1, t0, a0); // slt t1, t0, a0
bc = c->sgpr64(t1) != 0; // bne t1, r0, L22
// nop // sll r0, r0, 0
if (bc) {goto block_1;} // branch non-likely
c->mov64(v1, s7); // or v1, s7, r0
c->mov64(v0, s7); // or v0, s7, r0
//jr ra // jr ra
c->daddu(sp, sp, r0); // daddu sp, sp, r0
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.fake_scratchpad_data = intern_from_c("*fake-scratchpad-data*").c();
gLinkedFunctionTable.reg("ripple-apply-wave-table", execute, 128);
}
} // namespace ripple_apply_wave_table
} // namespace Mips2C
//--------------------------MIPS2C---------------------
#include "game/mips2c/mips2c_private.h"
namespace Mips2C::jak1 {
namespace ripple_matrix_scale {
u64 execute(void* ctxt) {
auto* c = (ExecutionContext*)ctxt;
bool bc = false;
c->mov128_vf_gpr(vf1, a3); // qmtc2.i vf1, a3
c->mov128_vf_gpr(vf2, a2); // qmtc2.i vf2, a2
c->mov128_vf_gpr(vf3, t0); // qmtc2.i vf3, t0
c->mov64(v1, t1); // or v1, t1, r0
block_1:
c->lqc2(vf5, 16, a0); // lqc2 vf5, 16(a0)
c->lqc2(vf6, 48, a0); // lqc2 vf6, 48(a0)
c->lqc2(vf7, 64, a0); // lqc2 vf7, 64(a0)
c->lqc2(vf8, 96, a0); // lqc2 vf8, 96(a0)
c->vmul_bc(DEST::xyzw, BC::x, vf4, vf5, vf2); // vmulx.xyzw vf4, vf5, vf2
c->vmul_bc(DEST::xyzw, BC::x, vf5, vf5, vf1); // vmulx.xyzw vf5, vf5, vf1
c->lq(a2, 0, a0); // lq a2, 0(a0)
c->vmul_bc(DEST::xyzw, BC::x, vf7, vf7, vf3); // vmulx.xyzw vf7, vf7, vf3
c->lq(v1, 32, a0); // lq v1, 32(a0)
c->vmul_bc(DEST::xyzw, BC::x, vf8, vf8, vf3); // vmulx.xyzw vf8, vf8, vf3
c->sq(a2, 0, t1); // sq a2, 0(t1)
c->lq(a2, 80, a0); // lq a2, 80(a0)
c->vsub(DEST::xyzw, vf6, vf6, vf4); // vsub.xyzw vf6, vf6, vf4
c->sq(v1, 32, t1); // sq v1, 32(t1)
c->sqc2(vf5, 16, t1); // sqc2 vf5, 16(t1)
c->sq(a2, 80, t1); // sq a2, 80(t1)
c->daddiu(a1, a1, -1); // daddiu a1, a1, -1
c->sqc2(vf7, 64, t1); // sqc2 vf7, 64(t1)
c->addiu(a0, a0, 128); // addiu a0, a0, 128
c->sqc2(vf6, 48, t1); // sqc2 vf6, 48(t1)
c->addiu(t1, t1, 128); // addiu t1, t1, 128
bc = c->sgpr64(a1) != 0; // bne a1, r0, L12
c->sqc2(vf8, -32, t1); // sqc2 vf8, -32(t1)
if (bc) {goto block_1;} // branch non-likely
c->gprs[v0].du64[0] = 0; // or v0, r0, r0
//jr ra // jr ra
c->daddu(sp, sp, r0); // daddu sp, sp, r0
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() {
gLinkedFunctionTable.reg("ripple-matrix-scale", execute, 128);
}
} // namespace ripple_matrix_scale
} // namespace Mips2C
+1 -13
View File
@@ -81,10 +81,6 @@ namespace generic_light_proc { extern void link(); }
namespace generic_envmap_proc { extern void link(); }
namespace high_speed_reject { extern void link(); }
namespace generic_prepare_dma_single { extern void link(); }
namespace ripple_create_wave_table { extern void link(); }
namespace ripple_execute_init { extern void link(); }
namespace ripple_apply_wave_table { extern void link(); }
namespace ripple_matrix_scale { extern void link(); }
namespace init_ocean_far_regs { extern void link(); }
namespace render_ocean_quad { extern void link(); }
namespace draw_large_polygon_ocean { extern void link(); }
@@ -108,9 +104,6 @@ namespace shadow_xform_verts { extern void link(); }
namespace draw_inline_array_instance_tie { extern void link(); }
namespace draw_inline_array_prototype_tie_generic_asm { extern void link(); }
namespace generic_tie_dma_to_spad_sync { extern void link(); }
namespace generic_envmap_dproc { extern void link(); }
namespace generic_interp_dproc { extern void link(); }
namespace generic_no_light_dproc { extern void link(); }
namespace generic_tie_convert { extern void link(); }
} // namespace jak1
@@ -437,12 +430,7 @@ PerGameVersion<std::unordered_map<std::string, std::vector<void (*)()>>> gMips2C
jak1::mercneric_convert::link, jak1::high_speed_reject::link}},
{"generic-effect",
{jak1::generic_prepare_dma_double::link, jak1::generic_light_proc::link,
jak1::generic_envmap_proc::link, jak1::generic_prepare_dma_single::link,
jak1::generic_envmap_dproc::link, jak1::generic_interp_dproc::link,
jak1::generic_no_light_dproc::link}},
{"ripple",
{jak1::ripple_execute_init::link, jak1::ripple_create_wave_table::link,
jak1::ripple_apply_wave_table::link, jak1::ripple_matrix_scale::link}},
jak1::generic_envmap_proc::link, jak1::generic_prepare_dma_single::link}},
{"ocean",
{jak1::init_ocean_far_regs::link, jak1::render_ocean_quad::link,
jak1::draw_large_polygon_ocean::link}},
+68 -100
View File
@@ -19,23 +19,34 @@
(defun transform-float-point ((in vector) (out vector4w))
"Transform in with the cached camera registers, perform perspective division and GS offset and
depth clamping, convert to 28.4 fixed point, store the result in out, and return out. The input
precedes the output, unlike most destructive vector functions."
precedes the output, unlike most destructive vector functions.
This requires VU0 registers set up by init-for-transform"
(with-vf0
(with-vf (vf4 vf1 vf2 vf3 vf9 vf8 vf6)
(rlet ((acc :class vf)
(Q :class vf)
(vf5 :class vf))
(.lvf vf5 (&-> in quad))
;; set vf5 = vf * model-matrix
(.mul.w.vf acc vf4 vf5)
(.add.mul.x.vf acc vf1 vf5 acc)
(.add.mul.y.vf acc vf2 vf5 acc)
(.add.mul.z.vf vf5 vf3 vf5 acc)
;; perspective divide and apply vf9.x (fog scale)
(.div.vf Q vf9 vf5 :fsf #b0 :ftf #b11)
(.wait.vf)
(.mul.vf.xyz vf5 vf5 Q)
;; add hvdf offset
(.add.vf vf5 vf5 vf8)
;; clamp fog 0 - 255
(.max.x.vf.w vf5 vf5 vf0)
(.min.x.vf.w vf5 vf5 vf6)
;; convert to GS fixed point
(vftoi4.xyzw vf5 vf5)
(.svf (&-> out quad) vf5)
out))))
@@ -508,32 +519,17 @@
(defun-debug add-debug-matrix ((enable-draw symbol) (bucket bucket-id) (xform matrix))
"Draw the three two-meter basis axes of xform at its translation, using red for x, green for y,
and blue for z. Return xform."
(add-debug-vector enable-draw
bucket
(-> xform vector 3)
(-> xform vector 0)
(meters 2)
(new 'static 'rgba :r #xff :a #x80))
(add-debug-vector enable-draw
bucket
(-> xform vector 3)
(-> xform vector 1)
(meters 2)
(new 'static 'rgba :g #xff :a #x80))
(add-debug-vector enable-draw
bucket
(-> xform vector 3)
(-> xform vector 2)
(meters 2)
(new 'static 'rgba :b #xff :a #x80))
(add-debug-vector enable-draw bucket (-> xform vector 3) (-> xform vector 0) (meters 2) (static-rgba #xff 0 0 #x80))
(add-debug-vector enable-draw bucket (-> xform vector 3) (-> xform vector 1) (meters 2) (static-rgba 0 #xff 0 #x80))
(add-debug-vector enable-draw bucket (-> xform vector 3) (-> xform vector 2) (meters 2) (static-rgba 0 0 #xff #x80))
xform)
(defun-debug add-debug-rot-matrix ((enable-draw symbol) (bucket bucket-id) (rotation matrix) (origin vector))
"Draw the three two-meter basis axes of rotation at origin, using red for x, green for y, and blue
for z. Return rotation."
(add-debug-vector enable-draw bucket origin (-> rotation vector 0) (meters 2) (new 'static 'rgba :r #xff :a #x80))
(add-debug-vector enable-draw bucket origin (-> rotation vector 1) (meters 2) (new 'static 'rgba :g #xff :a #x80))
(add-debug-vector enable-draw bucket origin (-> rotation vector 2) (meters 2) (new 'static 'rgba :b #xff :a #x80))
(add-debug-vector enable-draw bucket origin (-> rotation vector 0) (meters 2) (static-rgba #xff 0 0 #x80))
(add-debug-vector enable-draw bucket origin (-> rotation vector 1) (meters 2) (static-rgba 0 #xff 0 #x80))
(add-debug-vector enable-draw bucket origin (-> rotation vector 2) (meters 2) (static-rgba 0 0 #xff #x80))
rotation)
;; WARN: Stack slot load at 32 mismatch: defined as size 4, got size 16
@@ -564,31 +560,27 @@
lines at both ends. An optional orientation rotates the local xz plane before translation."
(if (not enable-draw) (return #f))
(let ((angle start-angle)
(start-point (new 'stack-no-clear 'vector)))
(set! (-> start-point quad) (the-as uint128 0))
(let ((end-point (new 'stack-no-clear 'vector)))
(set! (-> end-point quad) (the-as uint128 0))
(let ((i 0))
(while (< i 12)
(set! (-> start-point x) (* radius (sin angle)))
(set! (-> start-point y) 0.0)
(set! (-> start-point z) (* radius (cos angle)))
(set! (-> start-point w) 1.0)
(+! angle (the float (/ (the int (- end-angle start-angle)) 12)))
(set! (-> end-point x) (* radius (sin angle)))
(set! (-> end-point y) 0.0)
(set! (-> end-point z) (* radius (cos angle)))
(set! (-> end-point w) 1.0)
(when orientation
(vector-matrix*! start-point start-point orientation)
(vector-matrix*! end-point end-point orientation))
(vector+! start-point start-point center)
(vector+! end-point end-point center)
(add-debug-line #t bucket start-point end-point color #f (the-as rgba -1))
(cond
((zero? i) (add-debug-line #t bucket start-point center color #f (the-as rgba -1)))
((= i 11) (add-debug-line #t bucket end-point center color #f (the-as rgba -1))))
(+! i 1)))))
(start-point (new-stack-vector0))
(end-point (new-stack-vector0))
(i 0))
(while (< i 12)
(let ((start start-point))
(set-vector! start (* radius (sin angle)) 0.0 (* radius (cos angle)) 1.0))
(+! angle (the float (/ (the int (- end-angle start-angle)) 12)))
(let ((end end-point))
(set-vector! end (* radius (sin angle)) 0.0 (* radius (cos angle)) 1.0))
(when orientation
(vector-matrix*! start-point start-point orientation)
(vector-matrix*! end-point end-point orientation))
(vector+! start-point start-point center)
(vector+! end-point end-point center)
(add-debug-line #t bucket start-point end-point color #f (the-as rgba -1))
(cond
((zero? i)
(add-debug-line #t bucket start-point center color #f (the-as rgba -1)))
((= i 11)
(add-debug-line #t bucket end-point center color #f (the-as rgba -1))))
(+! i 1)))
#f)
(defun-debug add-debug-curve ((enable-draw symbol)
@@ -602,16 +594,15 @@
vertex over normalized progress from zero through one."
(if (not enable-draw) (return #f))
(let ((previous (new-stack-vector0))
(current (new 'stack-no-clear 'vector)))
(set! (-> current quad) (the-as uint128 0))
(let ((segment-count (* num-cverts 4)))
(curve-evaluate! current (-> knots 0) cverts num-cverts knots num-knots)
(let ((i 0))
(while (< i segment-count)
(set! (-> previous quad) (-> current quad))
(curve-evaluate! current (/ (the float (+ i 1)) (the float segment-count)) cverts num-cverts knots num-knots)
(add-debug-line #t bucket previous current color #f (the-as rgba -1))
(+! i 1)))))
(current (new-stack-vector0))
(segment-count (* num-cverts 4)))
(curve-evaluate! current (-> knots 0) cverts num-cverts knots num-knots)
(let ((i 0))
(while (< i segment-count)
(set! (-> previous quad) (-> current quad))
(curve-evaluate! current (/ (the float (+ i 1)) (the float segment-count)) cverts num-cverts knots num-knots)
(add-debug-line #t bucket previous current color #f (the-as rgba -1))
(+! i 1))))
#f)
(defun-debug add-debug-curve2 ((enable-draw symbol) (bucket bucket-id) (curve-data curve) (color rgba) (unused-option symbol))
@@ -637,23 +628,21 @@
highlight-index is drawn white while the remaining points use color."
(when enable-draw
(dotimes (i count)
(let ((point (new 'stack-no-clear 'vector)))
(set! (-> point quad) (the-as uint128 0))
(let ((point (new-stack-vector0)))
(set! (-> point quad) (-> points i quad))
(if (!= fixed-y 0.0) (set! (-> point y) fixed-y))
(let ((draw-text add-debug-text-3d)
(draw-enabled #t)
(draw-bucket bucket))
(format (clear *temp-string*) "~d" i)
(draw-text draw-enabled draw-bucket *temp-string* point (font-color white) (the-as vector2h #f)))
(add-debug-x #t bucket point (if (= i highlight-index) (new 'static 'rgba :r #xff :g #xff :b #xff :a #x80) color)))))
(if (!= fixed-y 0.0)
(set! (-> point y) fixed-y))
(add-debug-text-3d #t bucket (string-format "~d" i) point (font-color white) (the-as vector2h #f))
(add-debug-x #t bucket point (if (= i highlight-index) (static-rgba #xff #xff #xff #x80) color)))))
#f)
(defun-debug debug-percent-bar ((enable-draw symbol) (bucket bucket-id) (x int) (y int) (fraction float) (color rgba))
"Draw a 255-pixel background bar and a ten-pixel-high colored fill at screen position x,y. The
fill width is 255 times fraction."
(if (not enable-draw) (return #f))
(with-dma-buffer-add-bucket ((dma-buff (-> *display* frames (-> *display* on-screen) frame debug-buf)) bucket) :bucket-group (-> *display* frames (-> *display* on-screen) frame bucket-group) (draw-sprite2d-xy dma-buff x y 255 14 (new 'static 'rgba :a #x40)) (draw-sprite2d-xy dma-buff x (+ y 2) (the int (* 255.0 fraction)) 10 color))
(with-dma-buffer-add-bucket ((dma-buff (-> (current-frame) debug-buf)) bucket)
(draw-sprite2d-xy dma-buff x y 255 14 (static-rgba 0 0 0 #x40))
(draw-sprite2d-xy dma-buff x (+ y 2) (the int (* 255.0 fraction)) 10 color))
#f)
(defun-debug debug-pad-display ((pad cpad-info))
@@ -716,20 +705,14 @@
the level-scaled endpoint. The sphere color is derived from the light color."
(if (not enable-draw) (return #f))
(when (!= (-> light-data levels x) 0.0)
(add-debug-vector enable-draw
bucket
origin
(-> light-data direction)
(meters 3)
(new 'static 'rgba :r #xff :g #xff :b #xff :a #x80))
(add-debug-vector enable-draw bucket origin (-> light-data direction) (meters 3) (static-rgba #xff #xff #xff #x80))
(let ((position (vector+*! (new-stack-vector0) origin (-> light-data direction) (* 12288.0 (-> light-data levels x))))
(packed-color (logior (logior (logior (shr (shl (the int (* 128.0 (-> light-data color w))) 56) 32)
(shr (shl (the int (* 128.0 (-> light-data color z))) 56) 40))
(shr (shl (the int (* 128.0 (-> light-data color y))) 56) 48))
(shr (shl (the int (* 128.0 (-> light-data color x))) 56) 56))))
(format (clear *temp-string*) "~S ~,,2f" label (-> light-data levels x))
(let ((text *temp-string*))
(add-debug-text-sphere enable-draw bucket position (* 2048.0 (-> light-data levels x)) text (the-as rgba packed-color)))))
(packed-color (static-rgba (the int (* 128.0 (-> light-data color x)))
(the int (* 128.0 (-> light-data color y)))
(the int (* 128.0 (-> light-data color z)))
(the int (* 128.0 (-> light-data color w)))))
(text (string-format "~S ~,,2f" label (-> light-data levels x))))
(add-debug-text-sphere enable-draw bucket position (* 2048.0 (-> light-data levels x)) text packed-color)))
#f)
(defun-debug add-debug-lights ((enable-draw symbol) (bucket bucket-id) (lights (inline-array light)) (origin vector))
@@ -809,26 +792,11 @@
"Set the debug camera to the fixed position and rotation used to investigate DMA timeouts."
(let ((position (new-stack-vector0))
(rotation (new-stack-matrix0)))
(set! (-> position x) -666764.4)
(set! (-> position y) 21102.984)
(set! (-> position z) 51613.348)
(set! (-> position w) 1.0)
(set! (-> rotation vector 0 x) -0.911)
(set! (-> rotation vector 0 y) 0.0)
(set! (-> rotation vector 0 z) 0.4122)
(set! (-> rotation vector 0 w) 0.0)
(set! (-> rotation vector 1 x) -0.0984)
(set! (-> rotation vector 1 y) 0.971)
(set! (-> rotation vector 1 z) -0.2174)
(set! (-> rotation vector 1 w) 0.0)
(set! (-> rotation vector 2 x) -0.4003)
(set! (-> rotation vector 2 y) -0.2387)
(set! (-> rotation vector 2 z) -0.8847)
(set! (-> rotation vector 2 w) 0.0)
(set! (-> rotation vector 3 x) 0.0)
(set! (-> rotation vector 3 y) 0.0)
(set! (-> rotation vector 3 z) 0.0)
(set! (-> rotation vector 3 w) 1.0)
(set-vector! position -666764.4 21102.984 51613.348 1.0)
(set-vector! (-> rotation vector 0) -0.911 0.0 0.4122 0.0)
(set-vector! (-> rotation vector 1) -0.0984 0.971 -0.2174 0.0)
(set-vector! (-> rotation vector 2) -0.4003 -0.2387 -0.8847 0.0)
(set-vector! (-> rotation vector 3) 0.0 0.0 0.0 1.0)
(debug-set-camera-pos-rot! position rotation)))
(defun-debug display-file-info ()
+19 -52
View File
@@ -15,15 +15,17 @@
;; note: changed for high fps
;; Bones.
;; This file is a bit of a mess.
;; It calculates skinning matrices for rendering, but also handles
;; renderer-specific DMA generation for foreground rendering.
;; For bone calculations:
;; There are 4 main functions used by the outside world:
;; - bones-init. Call this before doing process-drawable DMA building.
;; - draw-bones. Call this once for each process-drawable during DMA building.
;; - bones-wrapup. Call this after all calls to draw-bones.
;; the above 3 functions are done separate for different levels.
;; - bones-mtx-calc-execute. Call this after all that.
;; It's more than just bones in here - submitting to merc is done from here.
;; the above 3 functions are done separately for different levels.
;; - bones-mtx-calc-execute then computes all bone matrices
(defglobalconstant BACKWARD_COMPAT_MERC_CLIP #f)
@@ -36,24 +38,11 @@
:bitfield #t
;; Write per-bone ripple deformation data after calculating the skinning matrices.
(write-ripple-data 0)
;; Use identity instead of camera rotation for screen-space bones. HUD draw paths set this.
(no-cam-rot 1)
(bncfl02 2) ;; bits 2-15 are unused in Jak 1
(bncfl03 3)
(bncfl04 4)
(bncfl05 5)
(bncfl06 6)
(bncfl07 7)
(bncfl08 8)
(bncfl09 9)
(bncfl10 10)
(bncfl11 11)
(bncfl12 12)
(bncfl13 13)
(bncfl14 14)
(bncfl15 15))
;; Use identity instead of camera rotation for screen-space bones. For HUD drawing.
(no-cam-rot 1))
;; this type represents a "calculation" that will be performed at later time.
;; this type represents a "calculation" that will be performed at later time,
;; it computes all skinning matrices for a single geometry.
(deftype bone-calculation (structure)
((flags bone-calc-flags :offset-assert 0)
(num-bones uint16 :offset-assert 2)
@@ -203,15 +192,11 @@
;; VU / DMA
;;;;;;;;;;;;;;;;
;; The scratchpad holds a terrain-context: a short header naming the level and its mood, then a work
;; area each renderer overlays with its own record. The bone calculator's is bone-mem, and that is
;; where the sixteen in every scratchpad address below comes from.
;; Address helper for scratchpad access
(defmacro bones-spr-offset (&rest path)
`(+ (offset-of terrain-context work) (offset-of bone-memory ,@path)))
;; Two banks, each holding sixteen joints' bind poses, sixteen bone transforms, and sixteen finished
;; 128-byte pris-mtx records. Only the first two arrays are declared in bone-buffer; the output area is
;; the third field the type comments out, and it begins where the bone array ends.
;; double-buffered output, holds 16 bones.
(defmacro bones-spr-bank-output (bank)
`(+ (bones-spr-offset buffer ,bank bone 0) (* 16 (type-size bone))))
@@ -222,28 +207,12 @@
(defconstant BONES-SPR-BONE-B (bones-spr-offset buffer 1 bone 0))
(defconstant BONES-SPR-OUTPUT-B (bones-spr-bank-output 1))
;; Sixteen bones per bank is what the two 4608-byte buffers hold, and it is also the unroll of the
;; bank loop below.
(defconstant BONES-PER-BANK 16)
;; Only the 64-byte bind-pose matrix of each 80-byte joint is wanted, so the joint transfer runs in
;; DMA interleave mode with SQWC set to "copy four quadwords, skip one" -- see bones-set-sqwc. That is
;; why the joint transfer's chcr differs from the bone and output transfers.
;; Interleave copy is used to extract the bind-pose matrix (64 bytes) from each joint (80 bytes)
(defconstant DMA-CHCR-START-INTERLEAVE (new 'static 'dma-chcr :mod 2 :str 1))
;; Poll an SPR channel until it stops. Twenty instructions, in this order:
;;
;; (label poll) 1 l.w of chcr
;; ... 2..4 three no-ops, the load-delay gap plus slack
;; ... 5 and.i against the start bit
;; ... 6 no-op
;; ... 7,8 b.z to ready with a no-op delay slot
;; ... 9..18 ten no-ops
;; ... 19,20 b back to poll with a no-op delay slot
;; (label ready)
;;
;; The ten no-ops in the not-taken path are the point: a busy channel is re-read at a fixed, generous
;; interval instead of hammering the bus, and the whole thing is branch-free on the ready path.
;; Poll an SPR channel until it stops.
(defmacro dma-wait-spr! (poll-label ready-label channel status)
`(begin
(label ,poll-label)
@@ -259,10 +228,9 @@
(#when PC_PORT
(define bones-vu0-block (new 'static 'vu-function :length 63 :qlength 32)))
;; Entry 0 composes one bone transform with its inverse bind pose, derives the inverse-transpose
;; normal matrix, applies camera rotation, and leaves transformed position rows in vf13-vf16 and
;; normal rows in vf9-vf11. Entry 54 rotates three light directions in vf4-vf6 by vf1-vf3 and
;; returns them in vf7-vf9.
;; Entry 0: compute one bone transform, including normal matrix (writes mtx vf13-vf16, ntmx vf9-vf11)
;; Entry 54: rotate light directions in vf4-vf6 by vf1-vf3, return in vf7-vf9
(#unless PC_PORT
(defvu0 bones-vu0-block
(vu-pair (nop) (mulax.xyzw ACC vf05 vf01)) ;; 0: transform * bind-pose columns
@@ -350,7 +318,6 @@
(set! (-> (the-as dma-bank-control #x1000e000) sqwc) (new 'static 'dma-sqwc :sqwc #x1 :tqwc #x1)))
(none))
;; ?? used by generic merc
(define *merc-global-array* (new 'global 'merc-global-array))
(defun vu-lights<-light-group! ((arg0 vu-lights) (arg1 light-group))
@@ -2570,7 +2537,7 @@
(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)))
(ripple-make-request (-> sv-144 waveform) (-> geom effect effect-idx)))
(set! (-> sv-144 last-frame-scale) f30-0))))
;; additional check on PC to force mercneric for blend shapes
(#when PC_PORT
+167 -13
View File
@@ -13,7 +13,7 @@
;; DECOMP BEGINS
(deftype ripple-request (structure)
((waveform ripple-wave)
((waveform ripple-wave-set)
(effect merc-effect))
:pack-me)
@@ -23,7 +23,7 @@
(define *ripple-globals* (new 'global 'ripple-globals))
(defun ripple-make-request ((waveform ripple-wave) (effect merc-effect))
(defun ripple-make-request ((waveform ripple-wave-set) (effect merc-effect))
"Queue an effect to receive a waveform during this frame. Ignore duplicate effects and requests
beyond the sixteen-entry buffer."
(let ((request-count (-> *ripple-globals* count))
@@ -31,7 +31,8 @@
(already-queued 0))
(when (< request-count 16)
(dotimes (i request-count)
(if (= effect (-> requests i effect)) (set! already-queued 1)))
(if (= effect (-> requests i effect))
(set! already-queued 1)))
(when (zero? already-queued)
(set! (-> requests request-count effect) effect)
(set! (-> requests request-count waveform) waveform)
@@ -54,11 +55,6 @@
0
(none))
(#when PC_PORT
(def-mips2c ripple-execute-init (function none))
(def-mips2c ripple-create-wave-table (function ripple-wave-set int))
(def-mips2c ripple-apply-wave-table (function merc-effect symbol)))
;; Ripple generation uses VU0 data memory for its cosine interpolation table and the scratchpad for
;; the 16 by 16 height/normal field. The EE versions retain the vector pipeline and packed vertex
;; writes used by the renderer.
@@ -504,6 +500,167 @@
(nop!)
(nop!))))
;; Plain-GOAL ripple implementation.
(deftype ripple-cosine-table (structure)
((entry vector 256 :inline)))
(define *ripple-cosine-table* (new 'global 'ripple-cosine-table))
(defun ripple-cosine-table-init ((table ripple-cosine-table))
"Build the cosine interpolation table used by the plain-GOAL ripple generator. The first half
covers zero through pi; negated copies in the second half complete the cycle."
(let ((phase-step 0.024543691)
(phase 0.024543691)
(sample 1.0))
(dotimes (i 128)
;; Match the original degree-eight cosine polynomial. Keeping the delta beside each sample
;; lets the table generator linearly interpolate the low eight phase bits.
(let* ((phase-squared (square phase))
(phase-fourth (square phase-squared))
(phase-sixth (* phase-fourth phase-squared))
(phase-eighth (square phase-fourth))
(next-sample (+ 1.0
(* phase-squared (-> *cos-poly-vec* x))
(* phase-fourth (-> *cos-poly-vec* y))
(* phase-sixth (-> *cos-poly-vec* z))
(* phase-eighth (-> *cos-poly-vec* w))))
(delta (- next-sample sample))
(positive-entry (-> table entry i))
(negative-entry (-> table entry (+ i 128))))
(set! (-> positive-entry x) sample)
(set! (-> positive-entry y) delta)
(set! (-> negative-entry x) (- sample))
(set! (-> negative-entry y) (- delta))
(set! sample next-sample)
(+! phase phase-step))))
(none))
(ripple-cosine-table-init *ripple-cosine-table*)
(defun ripple-execute-init ()
;; nothing to initialize in the re-written ripple implementation.
(none))
(defun ripple-create-wave-table ((wave-set ripple-wave-set))
"Sum the wave set into a 16 by 16 height grid, then pack height and x/z slopes into the
scratchpad table consumed by MERC vertices. The grid wraps in both directions so it tiles."
;; Build wave deltas
(when (not (-> wave-set converted))
(dotimes (i (-> wave-set count))
(let* ((wave (-> wave-set wave i))
(direction (atan (the float (-> wave zdiv)) (the float (-> wave xdiv))))
(wavelength (/ 16.0
(sqrtf (the float (+ (square (the int (-> wave xdiv)))
(square (the int (-> wave zdiv))))))))
(phase-per-cell (/ 65536.0 wavelength)))
(set! (-> wave xmul) (* (cos direction) phase-per-cell))
(set! (-> wave zmul) (* (sin direction) phase-per-cell))
(cond
((= (-> *setting-control* current video-mode) 'ntsc)
(set! (-> wave delta) (* 0.016666668 (- phase-per-cell) (-> wave speed))))
((= (-> *setting-control* current video-mode) 'pal)
(set! (-> wave delta) (* 0.02 (- phase-per-cell) (-> wave speed)))))))
(set! (-> wave-set converted) #t))
;; update wave phases
(ripple-update-waveform-offs wave-set)
(let ((heights (scratchpad-ptr float))
(packed-table (scratchpad-ptr uint8 :offset 1024)))
;; initialize heights to zero
(dotimes (grid-index 256)
(set! (-> heights grid-index) 0.0))
;; Add each wave to the height table
(dotimes (wave-index (-> wave-set count))
(let* ((wave (-> wave-set wave wave-index))
(phase-base (+ 16384.0 (* 0.00390625 (-> wave offs))))
(phase-x-step (* 0.00390625 (-> wave xmul)))
(phase-z-step (* 0.00390625 (-> wave zmul))))
(dotimes (grid-z 16)
(dotimes (grid-x 16)
(let* ((grid-index (+ grid-x (* grid-z 16)))
(phase (+ phase-base
(* (the float grid-x) phase-x-step)
(* (the float grid-z) phase-z-step)))
(table-index (the int phase))
(fraction (- phase (the float table-index)))
(entry (-> *ripple-cosine-table* entry (logand table-index #xff)))
(sample (+ (-> entry x) (* fraction (-> entry y)))))
(+! (-> heights grid-index) (* sample (-> wave scale))))))))
;; Create packed vertex data in MERC vertex format [pos-y, nrm-x, nrm-z, PAD]
(dotimes (grid-z 16)
(dotimes (grid-x 16)
(let* ((grid-index (+ grid-x (* grid-z 16)))
(right-index (+ (mod (+ grid-x 1) 16) (* grid-z 16)))
(down-index (+ grid-x (* (mod (+ grid-z 1) 16) 16)))
(height (-> heights grid-index))
(normal-scale (fmax 0.0 (-> wave-set normal-scale)))
(packed-index (* grid-index 4)))
;; height
(set! (-> packed-table packed-index)
(the-as uint (the int (fmax 0.0 (fmin 255.0 (+ 128.0 height))))))
;; finite difference to get normal X
(set! (-> packed-table (+ packed-index 1))
(the-as uint
(the int
(fmax 0.0
(fmin 255.0
(+ 128.0 (* normal-scale (- height (-> heights right-index)))))))))
;; finite difference to get normal Y
(set! (-> packed-table (+ packed-index 2))
(the-as uint
(the int
(fmax 0.0
(fmin 255.0
(+ 128.0 (* normal-scale (- height (-> heights down-index)))))))))
(set! (-> packed-table (+ packed-index 3)) 128))))
0))
(defun ripple-apply-wave-table ((effect merc-effect))
"Patch the packed height and normal bytes of every rippled MERC vertex. Each two-byte query uses
its low nibbles as x/z coordinates in the 16 by 16 table."
(let ((packed-table (scratchpad-ptr uint8 :offset 1024))
(fragment (-> effect frag-geo))
(fragment-control (-> effect frag-ctrl))
(queries (the-as (pointer uint8) (-> effect blend-data)))
(blend-control (-> effect blend-ctrl)))
(dotimes (fragment-index (the-as int (-> effect frag-count)))
(let* ((vertex-count (-> blend-control blend-vtx-count))
;; Unsigned-four data is qword-aligned immediately before the packed vertices.
(vertex-data (the-as merc-vtx
(&+ (the-as pointer fragment)
(logand (* (+ (-> fragment-control unsigned-four-count) 3) 4)
#xfff0)))))
(dotimes (vertex-index (the-as int vertex-count))
(let* ((table-x (logand (-> queries (* vertex-index 2)) #xf))
(table-z (logand (-> queries (+ (* vertex-index 2) 1)) #xf))
(table-index (* (+ table-x (* table-z 16)) 4))
(vertex (the-as merc-vtx
(&+ (the-as pointer vertex-data) (* vertex-index 12)))))
(set! (-> vertex pos-y) (-> packed-table table-index))
(set! (-> vertex nrm-x) (-> packed-table (+ table-index 1)))
(set! (-> vertex nrm-z) (-> packed-table (+ table-index 2)))))
;; Advance the four packed streams independently; their fragment records have different
;; alignment and variable-length tails.
(set! fragment
(the-as merc-fragment
(&+ (the-as pointer vertex-data)
(* (+ (-> fragment-control fp-qwc)
(/ (+ (-> fragment-control lump-four-count) 3) 4))
16))))
(set! fragment-control
(the-as merc-fragment-control
(&+ (the-as pointer fragment-control)
(+ 4 (* (-> fragment-control mat-xfer-count) 2)))))
(set! queries
(the-as (pointer uint8)
(&+ queries (logand (+ (* vertex-count 2) 15) #xfff0))))
(set! blend-control (the-as merc-blend-ctrl (&+ (the-as pointer blend-control) 2))))))
#f)
(defun ripple-execute ()
"Build each requested waveform table once, apply it to every queued effect that shares that
waveform, and clear the request list."
@@ -520,10 +677,10 @@
(protect ((-> *setting-control* current video-mode))
(when (= (-> *setting-control* current video-mode) 'custom)
(set! (-> *setting-control* current video-mode) 'ntsc))
(ripple-create-wave-table (the-as ripple-wave-set waveform)))
(ripple-create-wave-table waveform))
(while (!= match-index request-count)
(when (= waveform (-> requests match-index waveform))
(ripple-apply-wave-table (-> requests match-index effect))
(ripple-apply-wave-table (-> requests match-index effect))
(set! (-> requests match-index waveform) #f))
(+! match-index 1))))
(+! request-index 1)))
@@ -531,9 +688,6 @@
0)
(none))
(#when PC_PORT
(def-mips2c ripple-matrix-scale (function pointer int float float float pointer none)))
(defun-debug ripple-add-debug-sphere ((drawable process-drawable) (grid-point vector) (x-slope float) (z-slope float))
"Transform one local ripple-grid point by the drawable's inverse yaw and root translation, then
draw a debug sphere at the resulting world position. x-slope and z-slope displace the local x/z
@@ -4874,7 +4874,4 @@
(def-mips2c generic-prepare-dma-single (function none))
(def-mips2c generic-prepare-dma-double (function none))
(def-mips2c generic-light-proc (function none))
(def-mips2c generic-envmap-proc (function none))
(def-mips2c generic-envmap-dproc (function none))
(def-mips2c generic-interp-dproc (function none))
(def-mips2c generic-no-light-dproc (function none)))
(def-mips2c generic-envmap-proc (function none)))
@@ -6,19 +6,6 @@
;; Generic conversion calls this library at several entry points. Entry 0 lights four vertices,
;; entry 48 calculates four environment-map coordinates, and entries 104 through 292 stage and
;; transform packed TIE vertices in VU0 data memory.
;;
;; This is a library, not a pipeline: no main loop, eighteen independently callable entries, and no
;; constants of its own beyond what the EE crosses in. It is uploaded at program address zero, so a
;; callms immediate is an index into the instruction pairs below.
;;
;; Both of the four-vertex entries run a group behind the caller, so the values the EE collects after a
;; call belong to the group it submitted on the previous call. The caller therefore stores results from
;; before the loop body's own call, and the drain entries exist purely to publish the last group. The
;; two get there differently, though. Entry 0 opens by copying vf17-vf20 into vf21-vf24 outright. Entry
;; 48 has no such copy: its last two pairs start the fourth vertex's arithmetic and the first thirteen
;; pairs of the next call finish it, with vf05-vf08, vf29 and vf30 carrying the pipeline across the call
;; boundary. Two consequences of that for a caller - its first call's output is garbage, so it must call
;; twice before reading anything, and no other VU0 entry may be used between two entry-48 calls.
(defconstant GENERIC-VU0-LIGHT 0) ;; light four vertices
(defconstant GENERIC-VU0-ENVMAP 48) ;; four reflected environment-map coordinates
+22 -62
View File
@@ -1322,29 +1322,17 @@
"Fill the Generic VU1 constant block from the active camera and select alpha blending for its
triangle-strip GIF tag."
(let ((camera *math-camera*))
(set-vector!
(-> constants fog)
(-> camera pfog0)
(-> camera fog-min)
(-> camera fog-max)
3071.0))
(set-vector! (-> constants fog) (-> camera pfog0) (-> camera fog-min) (-> camera fog-max) 3071.0))
(set! (-> constants adgif tag) (new 'static 'gif-tag64 :nloop #x7 :nreg #x1))
(set! (-> constants adgif regs) (new 'static 'gif-tag-regs :regs0 (gif-reg-id a+d)))
(set! (-> constants adgif regs) (gs-reg-list a+d))
(set! (-> constants giftag tag)
(new 'static
'gif-tag64
:pre #x1
:nreg #x3
:prim
(new 'static
'gs-prim
:prim (gs-prim-type tri-strip)
:iip #x1
:tme #x1
:fge #x1
:abe alpha-blend)))
(set! (-> constants giftag regs)
(new 'static 'gif-tag-regs :regs0 (gif-reg-id st) :regs1 (gif-reg-id rgbaq) :regs2 (gif-reg-id xyzf2)))
(new 'static 'gs-prim :prim (gs-prim-type tri-strip) :iip #x1 :tme #x1 :fge #x1 :abe alpha-blend)))
(set! (-> constants giftag regs) (gs-reg-list st rgbaq xyzf2))
(vector-copy! (-> constants hvdf-offset) (-> *math-camera* hvdf-off))
(vector-copy! (-> constants hmge-scale) (-> *math-camera* hmge-scale))
(vector-copy! (-> constants invh-scale) (-> *math-camera* inv-hmge-scale))
@@ -1382,65 +1370,37 @@
(upload-packet (the-as dma-packet (-> buffer base))))
(set! (-> upload-packet dma) (new 'static 'dma-tag :qwc #x3 :id (dma-tag-id cnt)))
(set! (-> upload-packet vif0) (new 'static 'vif-tag))
(set! (-> upload-packet vif1)
(new 'static 'vif-tag :imm #x3 :cmd (vif-cmd direct) :msk #x1))
(set! (-> upload-packet vif1) (new 'static 'vif-tag :imm #x3 :cmd (vif-cmd direct) :msk #x1))
(set! (-> buffer base) (the-as pointer (&+ upload-packet 16))))
(let* ((buffer dma-buf)
(direct-tag (the-as gs-gif-tag (-> buffer base))))
(set! (-> direct-tag tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x2))
(set! (-> direct-tag regs)
(new 'static
'gif-tag-regs
:regs0 (gif-reg-id a+d)
:regs1 (gif-reg-id a+d)
:regs2 (gif-reg-id a+d)
:regs3 (gif-reg-id a+d)
:regs4 (gif-reg-id a+d)
:regs5 (gif-reg-id a+d)
:regs6 (gif-reg-id a+d)
:regs7 (gif-reg-id a+d)
:regs8 (gif-reg-id a+d)
:regs9 (gif-reg-id a+d)
:regs10 (gif-reg-id a+d)
:regs11 (gif-reg-id a+d)
:regs12 (gif-reg-id a+d)
:regs13 (gif-reg-id a+d)
:regs14 (gif-reg-id a+d)
:regs15 (gif-reg-id a+d)))
(set! (-> direct-tag regs) GIF_REGS_ALL_AD)
(set! (-> buffer base) (the-as pointer (&+ direct-tag 16))))
(let* ((buffer dma-buf)
(gs-registers (-> buffer base)))
(set! (-> (the-as (pointer gs-test) gs-registers) 0)
(new 'static
'gs-test
:ate #x1
:atst (gs-atest greater-equal)
:aref #x26
:afail #x1
:zte #x1
:ztst (gs-ztest greater-equal)))
(set! (-> (the-as (pointer uint64) gs-registers) 1) (the-as uint (gs-reg test-1)))
(set! (-> (the-as (pointer gs-zbuf) gs-registers) 2) zbuf)
(set! (-> (the-as (pointer uint64) gs-registers) 3) (the-as uint (gs-reg zbuf-1)))
(set! (-> buffer base) (&+ gs-registers 32)))
(dma-buffer-add-uint64 dma-buf
(new 'static
'gs-test
:ate #x1
:atst (gs-atest greater-equal)
:aref #x26
:afail #x1
:zte #x1
:ztst (gs-ztest greater-equal))
(the-as uint (gs-reg test-1))
zbuf
(the-as uint (gs-reg zbuf-1)))
(generic-add-constants dma-buf alpha-blend)
;; MSCALF with a zero immediate: entry GENERIC-VU1-INIT, which loads the constant block we just
;; uploaded and then falls through into the reset entry.
(let* ((buffer dma-buf)
(start-packet (the-as dma-packet (-> buffer base))))
(set! (-> start-packet dma) (new 'static 'dma-tag :qwc #x2 :id (dma-tag-id cnt)))
(set! (-> start-packet vif0)
(new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1))
(set! (-> start-packet vif0) (new 'static 'vif-tag :cmd (vif-cmd mscalf) :msk #x1))
(set! (-> start-packet vif1) (new 'static 'vif-tag :cmd (vif-cmd stmod)))
(set! (-> buffer base) (the-as pointer (&+ start-packet 16))))
(let ((vif-state (the-as (pointer int32) (-> dma-buf base))))
(set! (-> (the-as (pointer vif-tag) vif-state) 0)
(new 'static 'vif-tag :cmd (vif-cmd base)))
(set! (-> (the-as (pointer vif-tag) vif-state) 1)
(new 'static 'vif-tag :cmd (vif-cmd offset)))
(set! (-> (the-as (pointer vif-tag) vif-state) 0) (new 'static 'vif-tag :cmd (vif-cmd base)))
(set! (-> (the-as (pointer vif-tag) vif-state) 1) (new 'static 'vif-tag :cmd (vif-cmd offset)))
(set! (-> (the-as (pointer vif-tag) vif-state) 2) (new 'static 'vif-tag))
(set! (-> (the-as (pointer vif-tag) vif-state) 3)
(new 'static 'vif-tag :cmd (vif-cmd strow) :msk #x1))
(set! (-> (the-as (pointer vif-tag) vif-state) 3) (new 'static 'vif-tag :cmd (vif-cmd strow) :msk #x1))
(set! (-> vif-state 4) 0)
(set! (-> vif-state 5) 0)
(set! (-> vif-state 6) 0)
+4 -9
View File
@@ -6,30 +6,25 @@
(require "engine/gfx/lights.gc")
(require "engine/gfx/generic/generic-h.gc")
;; A generic sink is a bucket plus the VU1 buffer rotation belonging to that bucket. There is one per
;; place in the draw order where converted foreground geometry can be inserted: level 0, level 1, and
;; default each contribute a tfrag sink and a pris sink, then shrub, then the two level water sinks.
;; A sink outlives a single conversion pass - MERC and TIE can both feed the same bucket in one frame
;; - which is why the buffer addresses are kept here and not in the scratchpad work area.
;; A generic sink is a bucket plus the VU1 buffer rotation belonging to that bucket.
;; There's one per level x texture-group pair, plus one for shrub.
;; Both MERC and TIE can submit to these and VU1 buffer state must be consistent,
;; so these are stored globally instead of in rendering code like normal.
(define *generic-foreground-sinks*
(new 'static 'boxed-array :type generic-dma-foreground-sink :length 0 :allocated-length 9))
(set! (-> *generic-foreground-sinks* 0) (-> *level* level0 tfrag-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 1) (-> *level* level0 pris-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 2) (-> *level* level1 tfrag-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 3) (-> *level* level1 pris-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 4) (-> *level* level-default tfrag-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 5) (-> *level* level-default pris-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 6) (new 'static 'generic-dma-foreground-sink :bucket (bucket-id shrub-generic1)))
(set! (-> *generic-foreground-sinks* 7) (-> *level* level0 water-tex-foreground-sink-group generic-sink))
(set! (-> *generic-foreground-sinks* 8) (-> *level* level1 water-tex-foreground-sink-group generic-sink))
(defun generic-dma-foreground-sink-init ((sink generic-dma-foreground-sink))
@@ -7,37 +7,33 @@
(require "kernel/gstring-h.gc")
(require "engine/game/game-h.gc")
;; BLERC applies animated blend targets to packed MERC vertices. It is used heavily for facial
;; expressions, but the format can deform any marked vertices. Animation data supplies one signed
;; coefficient per target; the active target deltas are accumulated with the base vertex and the
;; result is clamped back into MERC's packed byte layout.
;; BLERC applies animated blend targets to packed MERC vertices for facial animation.
;; The animation data specifies a weight for each target and the BLERC code modifies
;; the MERC vertices in place, overwriting them with interpolated targets from BLERC
;; data.
;;
;; Work is gathered into one DMA chain during drawable updates. blerc-execute streams that chain
;; through the two 8 KiB scratchpad halves, computes one block while the next is arriving, and
;; copies completed vertices back to the fragment's lump data. The MERC renderer therefore sees the
;; updated positions and normals without needing a second geometry format.
;; Work is gathered into one DMA chain during drawable updates. A later call to blerc-execute
;; DMAs the chain to the scratchpad where the vertices are modified, then copied back.
;;
;; BLERC vertex modification races MERC rendering. It's unclear exactly how this worked,
;; but it's likely that DMA bus arbitration prevented rednering from seeing half-updated frags.
;; DECOMP BEGINS
(define *stats-blerc* #f)
;; Control data appended to one scratchpad output block. tag links the queued work blocks. overlap is
;; the number of target rows that follow the base row, which is the same thing as the number of
;; targets whose coefficient came out nonzero for this frame -- setup-blerc-chains-for-one-fragment
;; counts exactly those, and blerc-a-fragment uses it as the length of the replicated-coefficient
;; table and nothing else.
;; control info for a single block
(deftype blerc-block-header (structure)
((tag generic-merc-tag :inline :offset-assert 0)
(vtx-count uint32 :offset-assert 16)
(overlap uint32 :offset-assert 20)
(lump-dest uint32 :offset-assert 24)
(lump-qwc uint32 :offset-assert 28))
((tag generic-merc-tag :inline :offset-assert 0) ;; DMA chain of work blocks
(vtx-count uint32 :offset-assert 16) ;; vertex count in block
(overlap uint32 :offset-assert 20) ;; number of blend targets to use
(lump-dest uint32 :offset-assert 24) ;; EE address of MERC fragment to modify
(lump-qwc uint32 :offset-assert 28)) ;; number of quadwords in MERC data
:method-count-assert 9
:size-assert #x20
:flag-assert #x900000020)
;; One scratchpad work block. output holds at most 53 packed 16-byte vertex records. The DMA chain
;; that describes its base and target rows begins immediately after header, outside this type.
;; single block of vertex data to process + control info.
(deftype blerc-block (structure)
((output uint8 848 :offset-assert 0)
(header blerc-block-header :inline :offset-assert 848))
@@ -45,9 +41,8 @@
:size-assert #x370
:flag-assert #x900000370)
;; One quadword per active blend target, each holding that target's signed coefficient replicated into
;; all eight halfword lanes so PMADDH can take it directly. blerc-a-fragment builds it in *gsf-buffer*
;; at the start of every block; forty is the most targets a MERC asset declares.
;; cache of broadcasted target weights. repl-mult[i] stores the 16-bit weight replicated 8 times for
;; target i.
(deftype blerc-dcache (structure)
((repl-mult vector 40 :inline :offset-assert 0))
:method-count-assert 9
@@ -56,22 +51,20 @@
;; Per-frame chain endpoints and optional range/workload statistics.
(deftype blerc-globals (structure)
((first uint32 :offset-assert 0)
(next uint32 :offset-assert 4)
(min-val int16 :offset-assert 8)
((first uint32 :offset-assert 0) ;; DMA chain start
(next uint32 :offset-assert 4) ;; DMA chain current pointer
(min-val int16 :offset-assert 8) ;; min/max value seen, used for debug
(max-val int16 :offset-assert 10)
(fragment-count int32 :offset-assert 12)
(vtx-count int32 :offset-assert 16)
(target-vtx-count int32 :offset-assert 20))
(fragment-count int32 :offset-assert 12) ;; merc fragments
(vtx-count int32 :offset-assert 16) ;; output vertices written
(target-vtx-count int32 :offset-assert 20));; blend target vertices read
:method-count-assert 9
:size-assert #x18
:flag-assert #x900000018)
(define *blerc-globals* (new 'global 'blerc-globals))
;; BLERC assigns block-a to scratchpad address 0 and block-b to address 8192. dummy is the first
;; half's variable DMA-chain area. The second half's chain likewise continues beyond block-b and
;; therefore past the declared end of this type into the remainder of the 16 KiB scratchpad.
;; Scratchpad memory layout. dummy, and the data after block-b are used for DMA memory.
(deftype blerc-context (structure)
((block-a blerc-block :inline :offset-assert 0)
(dummy uint8 7312 :offset-assert 880)
@@ -80,32 +73,23 @@
:size-assert #x2370
:flag-assert #x900002370)
;; Both halves of the scratchpad hold a blerc-block, and the second one is reached by adding this.
;; Nothing else in blerc-context is addressed, so the offset comes from the type.
(defconstant BLERC-BLOCK-B (offset-of blerc-context block-b))
;; The DMA payload for a block is appended immediately after its header, and DMAtag transfer is on,
;; so the source chain's tags land in the scratchpad too. The first tag quadword is therefore always
;; here, and the index row it introduces at +16.
;; Offset of transferred data (after header)
(defconstant BLERC-SPR-CHAIN (+ (offset-of blerc-block header) (type-size blerc-block-header)))
;; chcr's start bit stays set while a channel is running, so it is both the poll mask and, on its
;; own, "go" for an ordinary transfer.
;; og:preserve-this these three want to live in dma-h.gc: shadow-cpu and the generic renderers all
;; define or use the same values, and merc is simply the first file in load order that needs them.
;; constant to write to DMA register to start chain transfer
(defconstant DMA-CHCR-START-SPR-CHAIN (new 'static 'dma-chcr :mod 1 :tte 1 :str 1))
;; A scratchpad address is only meaningful modulo 16 KiB to the SPR channels; the #x70000000 the EE
;; uses to reach the same memory has to come off first.
;; Mask to get scratchpad offsets from the EE scratchpad addresses starting at #x70000000
(defconstant SPR-ADDRESS-MASK #x3fff)
;; The packed accumulator runs in 13 fractional bits: a base vertex byte is multiplied by 8192 and
;; each target's signed byte delta by that target's signed coefficient, then the sum is shifted back
;; down. blerc-data coefficients are built as +/- 64 * 64, so a coefficient of 64 * 64 is 1.0 here.
;; BLERC uses integer math. When accumulating, uses 13-bit fixed-point, so 8192 == 1
(defconstant BLERC-FRACTION-BITS 13)
(defconstant BLERC-ONE 8192)
(defconstant BLERC-FRACTION-BITS 13)
(defun-debug blerc-stats-init ()
"Print the preceding BLERC frame's optional range and workload statistics, then reset them."
@@ -117,8 +101,10 @@
" ~D blend target computations (~F average)~%"
(-> *blerc-globals* target-vtx-count)
(/ (the float (-> *blerc-globals* target-vtx-count)) (the float (-> *blerc-globals* vtx-count))))
(if (< (-> *blerc-globals* min-val) 0) (format *stdcon* "MINIMUM OUT OF RANGE: ~D~%" (-> *blerc-globals* min-val)))
(if (< 255 (-> *blerc-globals* max-val)) (format *stdcon* "MAXIMUM OUT OF RANGE: ~D~%" (-> *blerc-globals* max-val))))
(if (< (-> *blerc-globals* min-val) 0)
(format *stdcon* "MINIMUM OUT OF RANGE: ~D~%" (-> *blerc-globals* min-val)))
(if (< 255 (-> *blerc-globals* max-val))
(format *stdcon* "MAXIMUM OUT OF RANGE: ~D~%" (-> *blerc-globals* max-val))))
(let ((stats *blerc-globals*))
(set! (-> stats min-val) 255)
(set! (-> stats max-val) 0)
@@ -131,7 +117,9 @@
(defun blerc-init ()
"Begin a BLERC frame by clearing the queued-chain head and tail after resetting statistics."
(blerc-stats-init)
(let ((state *blerc-globals*)) (set! (-> state first) (the-as uint 0)) (set! (-> state next) (the-as uint 0)))
(let ((state *blerc-globals*))
(set! (-> state first) (the-as uint 0))
(set! (-> state next) (the-as uint 0)))
0
(none))
@@ -223,8 +211,7 @@
;; ... the tag's fourth word
;; BLERC-SPR-CHAIN + n*stride [tag][index row] the packed matrix/destination halfwords
;;
;; where n is header.overlap and stride is (tag qwc + 1) * 16 -- the row plus its own tag. Because
;; every row is the same length the stride is read once, out of the first tag's low byte.
;; where n is header.overlap and stride is (tag qwc + 1) * 16 -- the row plus its own tag.
;;
;; *gsf-buffer* is borrowed as the replicated-coefficient table, and the finished vertices are
;; written to output at block + 0 for the caller to send back to header.lump-dest.
@@ -412,8 +399,7 @@
;; fromSPR copy that returns it -- so at steady state one block is arriving, one is being blended,
;; and one is going back to main memory.
;;
;; The blend kernel in the middle is blerc-a-fragment inlined, because the whole point is to keep
;; both DMA channels live across it.
;; The blend kernel in the middle is blerc-a-fragment inlined.
(rlet ((block :reg a0 :type blerc-block) ;; the half being blended
(work :reg a2 :type blerc-block) ;; ... and the copy of that pointer the kernel uses
(to-spr-a :reg a0 :type dma-bank-spr) ;; the toSPR channel, while block A is being seeded
@@ -701,12 +687,16 @@
"Interpolate the drawable's signed blend-target weights for its current animation frame and queue
its level-zero MERC geometry. After BLERC is disabled, queue one zero-weight pass to restore the
base vertices."
;; this function is what generates BLERC weights from animation data.
;; first, check if animation is valid and blerc is enabled
(let* ((root-channel (-> drawable skel root-channel 0))
(anim-group (-> root-channel frame-group)))
(when (and anim-group
(> (-> drawable skel active-channels) 0)
(zero? (-> drawable draw cur-lod))
(logtest? (-> drawable skel status) (janim-status blerc)))
;; find weights
(let ((frame-weights (-> anim-group blerc-data)))
(when frame-weights
(let* ((merc-geo (-> drawable draw mgeo))
@@ -717,7 +707,7 @@
(target-weights (new 'stack-no-clear 'array 'int16 128)))
(let ((target-count (-> merc-geo header blend-target-count)))
(cond
((< frame-index (+ (-> anim-group data 0 length) -1))
((< frame-index (+ (-> anim-group data 0 length) -1)) ;; interpolation needed
(let* ((next-frame-weights (&+ current-frame-weights target-count))
(next-frame-scale (* 64.0 (- frame (the float frame-index))))
(current-frame-scale (- 64.0 next-frame-scale)))
@@ -727,16 +717,19 @@
(+ (* (the float (+ (-> current-frame-weights i) -64)) current-frame-scale)
(* (the float (+ (-> next-frame-weights i) -64)) next-frame-scale)))))))
(else
;; at end of animation, just grab last frame's weights
(dotimes (i (the-as int target-count))
(set! (-> target-weights i) (the-as int (* (+ (-> current-frame-weights i) -64) 64)))))))
(setup-blerc-chains merc-geo target-weights (-> *display* frames (-> *display* on-screen) frame global-buf)))
(setup-blerc-chains merc-geo target-weights (-> (current-frame) global-buf)))
(logior! (-> drawable skel status) (janim-status blerc-done))
(return (the-as object #f))))))
;; when disabling blerc, restore vertices to default.
(when (logtest? (-> drawable skel status) (janim-status blerc-done))
(logclear! (-> drawable skel status) (janim-status blerc-done))
(setup-blerc-chains (-> drawable 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)))
(-> (current-frame) global-buf)))
0)
;; PC uses the ported chain builder so scratchpad references target its mirror.
+15 -23
View File
@@ -36,7 +36,8 @@
((and eye-ctrl (= (logand (the-as texture-id -256) (-> shader texture-id)) #x1cf06f00))
;; eye slot 0
(adgif-shader-login shader)
(let ((eye-texture-block (get-eye-block (-> eye-ctrl eye-slot) 0))) (set! (-> shader tex0 tbp0) eye-texture-block))
(let ((eye-texture-block (get-eye-block (-> eye-ctrl eye-slot) 0)))
(set! (-> shader tex0 tbp0) eye-texture-block))
(set! (-> shader tex0 tw) 5)
(set! (-> shader tex0 th) 5)
(set! (-> shader tex0 tcc) 1)
@@ -48,7 +49,8 @@
((and eye-ctrl (= (logand (the-as texture-id -256) (-> shader texture-id)) #x1cf07000))
;; eye slot 1
(adgif-shader-login shader)
(let ((eye-texture-block (get-eye-block (-> eye-ctrl eye-slot) 1))) (set! (-> shader tex0 tbp0) eye-texture-block))
(let ((eye-texture-block (get-eye-block (-> eye-ctrl eye-slot) 1)))
(set! (-> shader tex0 tbp0) eye-texture-block))
(set! (-> shader tex0 tw) 5)
(set! (-> shader tex0 th) 5)
(set! (-> shader tex0 tcc) 1)
@@ -122,7 +124,8 @@
"Account for the base art data, packed fragment control and geometry, blend targets, and eye
animation owned by this MERC asset."
;; do extra
(if (-> this extra) (mem-usage (-> this extra) usage flags))
(if (-> this extra)
(mem-usage (-> this extra) usage flags))
;; do merc ctrls in each effect:
(let ((ctrl-mem (+ 32 80 (* (-> this header effect-count) 32))))
(dotimes (effect-idx (the-as int (-> this header effect-count)))
@@ -158,7 +161,7 @@
(defmethod login ((this merc-ctrl))
"Log in every effect and eye shader, collect texture masks, and move the effect marked
translucent to the final effect slot. Discard an unrelocated low-address eye-control value."
translucent to the final effect slot."
;; so we can find it
(set! *merc-ctrl-header* (-> this header))
;; clear masks. logging in will set these for textures we need.
@@ -168,6 +171,7 @@
(dotimes (effect-idx (the-as int (-> this header effect-count)))
(login-adgifs (-> this effect effect-idx)))
;; Translucent geometry occupies the final effect slot expected by the MERC submission code.
;; This code swaps the last slot with the translucent geometry.
(let ((translucent-effect-index -1)
(effect-count (-> this header effect-count)))
(dotimes (effect-index (the-as int effect-count))
@@ -184,7 +188,7 @@
;; login eye.
(cond
((not (logtest? -65536 (the-as int (-> this header eye-ctrl))))
;; A linked eye-control pointer must not fit in the unrelocated low 16-bit form.
;; Set eye-ctrl to 0 if it's not a valid pointer
(set! (-> this header eye-ctrl) (the-as merc-eye-ctrl 0))
0)
(else
@@ -314,16 +318,11 @@
(defun merc-vu1-init-buffer ((dma-bucket bucket-id) (test gs-test) (unused int))
"If bucket-id received drawing commands, prepend a MERC VU1/GS initialization chain using test
and link it to the bucket's previous head. The third argument is reserved and currently unused."
;; Drawing has already filled the buckets, so this can skip empty ones and splice initialization
;; only in front of work that will run. display-frame-finish calls this after the previous DMA is
;; synchronized.
(let ((bucket (-> *display* frames (-> *display* on-screen) frame bucket-group dma-bucket)))
and link it to the bucket's previous head."
(let ((bucket (-> (current-frame) bucket-group dma-bucket)))
(when (!= bucket (-> bucket last))
(let* ((dma-buf (-> *display* frames (-> *display* on-screen) frame global-buf))
(draw-data-start (-> dma-buf base)) ;; remember old beginning
)
;; Upload and initialize MERC, then send the bucket's GS TEST value through VIF DIRECT.
(let* ((dma-buf (-> (current-frame) global-buf))
(draw-data-start (-> dma-buf base)))
(set! (-> dma-buf base) (the-as pointer (merc-vu1-initialize-chain (the-as dma-gif-packet (-> dma-buf base)))))
(let* ((buffer-for-vif-tag dma-buf)
(vif-packet (the-as object (-> buffer-for-vif-tag base))))
@@ -331,18 +330,12 @@
(set! (-> (the-as dma-packet vif-packet) vif0) (new 'static 'vif-tag))
(set! (-> (the-as dma-packet vif-packet) vif1) (new 'static 'vif-tag :imm #x2 :cmd (vif-cmd direct) :msk #x1))
(set! (-> buffer-for-vif-tag base) (&+ (the-as pointer vif-packet) 16)))
(let* ((buffer-for-gif-tag dma-buf)
(gif-packet (the-as object (-> buffer-for-gif-tag base))))
(set! (-> (the-as gs-gif-tag gif-packet) tag) (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x1))
(set! (-> (the-as gs-gif-tag gif-packet) regs) GIF_REGS_ALL_AD)
(set! (-> buffer-for-gif-tag base) (&+ (the-as pointer gif-packet) 16)))
(dma-buffer-add-gif-tag dma-buf (new 'static 'gif-tag64 :nloop #x1 :eop #x1 :nreg #x1) GIF_REGS_ALL_AD)
(let* ((buffer-for-test dma-buf)
(test-packet (-> buffer-for-test base)))
(set! (-> (the-as (pointer gs-test) test-packet) 0) test)
(set! (-> (the-as (pointer gs-reg64) test-packet) 1) (gs-reg64 test-1))
(set! (-> buffer-for-test base) (&+ test-packet 16)))
;; The new prefix jumps to the bucket's previous head; the bucket now starts at the saved
;; global-buffer cursor.
(let ((chain-tail (the-as object (-> dma-buf base))))
(set! (-> (the-as dma-packet chain-tail) dma) (new 'static 'dma-tag :id (dma-tag-id next) :addr (-> bucket next)))
(set! (-> (the-as dma-packet chain-tail) vif0) (new 'static 'vif-tag))
@@ -354,8 +347,7 @@
(defun merc-vu1-init-buffers ()
"After drawing has filled the MERC buckets, prepend initialization chains to each nonempty
enabled bucket. Ordinary buckets use alpha reference #x26; water uses #x80 and preserves the
framebuffer on alpha failure."
enabled bucket."
(when (logtest? *vu1-enable-user* (vu1-renderer-mask merc))
(merc-vu1-init-buffer (bucket-id merc-tfrag-tex0)
(new 'static 'gs-test :ate #x1 :atst (gs-atest greater-equal) :aref #x26 :zte #x1 :ztst (gs-ztest greater-equal))
@@ -4,15 +4,28 @@
(require "engine/gfx/sprite/sprite.gc")
(require "engine/gfx/math-camera.gc")
;; The sprite distortion renderer draws circular warps by sampling the current framebuffer around
;; projected particle positions. The particle's turn count selects the radial mesh resolution, and
;; its RGB lanes are reused as two radial scales and a framebuffer-sample displacement.
;; Draws the heat-haze/water-warp particles. These distort
;; a roughly circular area underneath the particle.
;; The mesh contains two conentric rings of vertices. Both rings have `turns` vertices.
;; So `turns = 3` would be a triangle, turns = 4 is a square, etc.
;; There is a triangle fan at the center, using the vertices of the inner ring,
;; and a triangle strip in between the inner and outer rings.
;; The center and outer ring sample the framebuffer at their current position and
;; the inner ring samples at an offset. This makes the center and edge of the distort sprite
;; have no distortion, eliminating discontinuities and making the effect clearly centered around
;; the sprite's center.
;; This geometry is controlled by the color: red controls the outer ring radius, g the inner,
;; and b the sampling location of the inner ring. Setting g = b will effectively disable the effect,
;; increasing the difference will increase the strength.
;; DECOMP BEGINS
;; For every turn count from 3 through 11, entry stores alternating screen-space directions and
;; framebuffer texture-coordinate offsets. ientry maps a turn count to its first direction pair in
;; VU1 memory. The final angle-zero pair closes the eleven-turn table.
;; Unit spokes for every supported side count. Each spoke is stored twice: once in projected screen
;; units for the mesh, then in framebuffer ST units for sampling. ientry points VU1 at the right set
;; for a given `turns`; the last angle-zero pair closes the 11-sided set.
(deftype sprite-distorter-sine-tables (basic)
((aspx float)
(aspy float)
@@ -51,10 +64,8 @@
(define *sprite-distorter-sine-tables* (new 'global 'sprite-distorter-sine-tables))
(defun sprite-distorter-generate-tables ()
"Rebuild the radial warp direction tables for the current projection. For each turn count from
3 through 11, store one screen-space direction and one framebuffer-texture offset per segment;
adjacent tables share the angle-zero closing pair. These values are generated at runtime because
both the on-screen directions and framebuffer sampling offsets depend on the active projection."
"Build the spoke tables used by the distortion mesh. Each spoke has matching screen-space and
framebuffer-ST directions, and the tables are rebuilt when the projection changes."
(let ((tables *sprite-distorter-sine-tables*))
(let ((entry-index 0)
(turn-table-index 0)
@@ -75,7 +86,7 @@
(let ((angle (* 65536.0 (/ (the float i) (the float turns)))))
(set-vector! (-> tables entry entry-index) (* (sin angle) aspect-x) (* (cos angle) aspect-y) 0.0 0.0)
(let ((next-entry-index (+ entry-index 1)))
;; The framebuffer is sampled on the 512 by 256 render grid.
;; Same spoke as above, converted to the framebuffer's 512x256 ST grid.
(set-vector! (-> tables entry next-entry-index)
(* (/ aspect-x 512) (sin angle))
(* (/ aspect-y 256) (cos angle))
@@ -116,8 +127,8 @@
(define sprite-distort-vu1-block (new 'static 'vu-function)))
(defun sprite-init-distorter ((dma-buff dma-buffer) (frame-base-pointer uint))
"Configure the GS to sample the current framebuffer without writing depth, upload the radial warp
tables, and load the sprite-distortion VU1 program."
"Set up framebuffer sampling for the distortion pass, upload the spoke tables, and load its VU1
program."
;;(format #t "distorter: ~d~%" (-> *sprite-aux-list* entry))
;; set up GS registers
(dma-buffer-add-gs-set dma-buff
@@ -165,10 +176,8 @@
(none))
(defun sprite-draw-distorters ((dma-buff dma-buffer))
"Project each enabled warp sprite with its selected camera or screen matrix, discard clipped
sprites, replace an invalid radial turn count with 11, and shrink warps that cross the lower
screen edge. Pack visible sprites into VU1 batches of at most 170 and draw each as radial
framebuffer-texture strips."
"Project the distortion particles, clip them, and send the visible discs to VU1 in batches of at
most 170. Bad side counts fall back to 11, and discs are shrunk to stay on the framebuffer."
(local-vars (clip-flags int) (warp-sprite sprite-vec-data-2d) (center-st pointer) (warp-params pointer))
(rlet ((acc :class vf)
(Q :class vf)
@@ -226,8 +235,8 @@
(set! clip-flags (vu-clip vf10 0)) ;; safe to just drop the higher bits.
(b! (logtest? clip-flags 63) cfg-21 :delay (.add.vf vf1 vf1 vf9))
(.max.x.vf.w vf1 vf1 vf0)
;; Pack the projected center, its framebuffer ST coordinate, and the three warp scales
;; consumed by one VU1 invocation.
;; VU1 gets the projected centre, its matching framebuffer ST, and the particle's RGB:
;; red = seamless outer radius, green = warp-ring radius, blue = sample radius there.
(.svf (&-> (the-as vector packed-sprite) quad) vf1)
(.svf (&-> (the-as vector warp-params) quad) vf2)
(set! (-> (the-as vector packed-sprite) w) 255.0)
@@ -244,9 +253,8 @@
(bottom-t (+ center-t (* (-> (the-as (pointer float) warp-params)) projection-y)))
(visible-scale 256.0)
(warp-scale (-> (the-as (pointer float) warp-params))))
;; Keep the warp inside the lower edge of the visible framebuffer and cap its radius at
;; 128 pixels. Scale all three parameters together so the two radii and sampling
;; displacement retain their proportions.
;; Keep the outer edge inside the bottom of the framebuffer and cap it at 128 pixels.
;; Scale all three radii together so the shape of the warp does not change.
(if (< (the float (-> *video-parms* screen-sy)) bottom-t)
(set! visible-scale (/ (- (the float (-> *video-parms* screen-sy)) center-t) projection-y)))
(if (< 128.0 visible-scale) (set! visible-scale 128.0))
+6 -10
View File
@@ -56,9 +56,9 @@
;; aux list
;;;;;;;;;;;;;;;;;;;;;;;;;;
;; The sparticle callback records a four-byte reference to each submitted CPU particle's 2D warp
;; sprite here. The one-element data field is the start of trailing variable-length reference
;; storage consumed by the framebuffer-distortion renderer.
;; The aux list stores distortion particles that are handled by the separate
;; sprite-distort renderer. Distorion sprites use the add-to-sprite-aux-list
;; callback to add themselves to the aux list on each frame.
(deftype sprite-aux-list (basic)
((num-entries int32) ;; capacity
@@ -102,7 +102,7 @@
0
(none))
;; The sprite-frame-data is data transferred to VU1 and remains there for all chunks of sprites.
;; Uploaded to VU1 once per frame
(deftype sprite-frame-data (structure)
((cdata vector 16 :inline)
(hmge-scale vector :inline)
@@ -145,9 +145,6 @@
;; 904 its HVDF offset, or the first of the screen-space table
;; 905 - 979 75 user HVDF offsets, uploaded only for the screen-space pass
;; 980 - 1020 sprite-frame-data
;;
;; The chunk limit falls out of the input buffer: eight quadwords per sprite plus the header must fit
;; in 400, and 48 is what the exporter and the sparticle system were built around.
(defconstant SPRITE-VU-HEADER 0)
(defconstant SPRITE-VU-VEC-DATA (+ SPRITE-VU-HEADER 1))
@@ -322,8 +319,7 @@
(set! (-> data fog-clamp z) 2048.0)
(none))
;; The original 854-pair VU1 program is documented in sprite-vu1.gc. PC rendering does not execute
;; it, but the DMA-list builder still requires a valid object.
;; The original 854-pair VU1 program is documented in sprite-vu1.gc.
(#when PC_PORT
(define sprite-vu1-block (new 'static 'vu-function)))
@@ -332,7 +328,7 @@
;;;;;;;;;;;;;;;;;;
;; There are two global sprite arrays, one for 2D and one for 3D. Each has two groups, although 3D
;; sprites only use group 0. Each sprite occupies three vector quadwords and five shader quadwords.
;; sprites only use group 0.
(defmethod new sprite-array-2d ((allocation symbol) (type-to-make type) (group-0-size int) (group-1-size int))
"Allocate a 2D sprite array with the requested capacity for its world and screen groups."