[jak2] float patch for bogus collide frags (#2686)

Should fix https://github.com/open-goal/jak-project/issues/2679

Here's a test program that will trigger the bug when near these guards:
```lisp
(define *cquery* (new 'global 'collide-query))

(defun test-bad-collide ()
  (let ((lower (new 'static 'vector  :x 1681893.8750  :y 61314.2031 :z 345208.6562 :w 1.))
        (upper (new 'static 'vector :x 1701603.8750 :y  67624.0625 :z 357881.0312 :w 1.))
        ;(cquery (new 'stack-no-clear 'collide-query))
        )
    (set! (-> *cquery* collide-with) (the-as collide-spec 1))
    (set! (-> *cquery* ignore-process0) #f)
    (set! (-> *cquery* ignore-process1) #f)
    (set! (-> *cquery* ignore-pat) (new 'static 'pat-surface :noentity #x1 :nojak #x1 :probe #x1 :noendlessfall #x1))
    (set! (-> *cquery* action-mask) (collide-action solid))
    (set! (-> *cquery* bbox min quad) (-> lower quad))
    (set! (-> *cquery* bbox max quad) (-> upper quad))
    (format 0 "doing collide...~%")
    (fill-using-bounding-box *collide-cache* *cquery*)
    (format 0 "have ~d and ~d~%" (-> *collide-cache* num-tris) (-> *collide-cache* num-prims))
    )
  (none)
  )
```

As far as I can tell, there's a totally invalid collide-hash with an
inside `axis-scale.z`. On the PS2, it gets ignore because of how
float->int works for floats that are too big. On PC, it ends up using a
negative value and loop forever.
This commit is contained in:
water111 2023-06-04 15:19:08 -04:00 committed by GitHub
parent 6eaa95608e
commit 08741f0a42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 27 deletions

View File

@ -405,6 +405,8 @@ L20:
mtir vi07, vf29.z | nop
b L19 | nop
mtir vi02, vf29.x | nop
;;;;;;;;;; WEIRD TRIANGLES
L21:
iaddiu vi03, vi00, 0x158 | nop
ilwr.x vi08, vi03 | nop

View File

@ -639,40 +639,42 @@ u64 execute(void* ctxt) {
c->sq(s5, 96, sp); // sq s5, 96(sp)
c->sq(gp, 112, sp); // sq gp, 112(sp)
// nop // sll r0, r0, 0
c->lw(v1, 40, a1); // lw v1, 40(a1)
c->lw(v1, 40, a1); // lw v1, 40(a1) v1 = frag.dimension_array;
// nop // sll r0, r0, 0
c->lqc2(vf1, 44, a1); // lqc2 vf1, 44(a1)
c->lui(a3, 1); // lui a3, 1
c->lqc2(vf2, 128, a2); // lqc2 vf2, 128(a2)
c->ori(a3, a3, 257); // ori a3, a3, 257
c->lqc2(vf3, 144, a2); // lqc2 vf3, 144(a2)
c->dsubu(v1, v1, a3); // dsubu v1, v1, a3
c->lqc2(vf6, 60, a1); // lqc2 vf6, 60(a1)
c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1
c->lq(a3, 160, a2); // lq a3, 160(a2)
c->vsub(DEST::xyzw, vf3, vf3, vf1); // vsub.xyzw vf3, vf3, vf1
c->lq(t0, 176, a2); // lq t0, 176(a2)
c->lqc2(vf1, 44, a1); // lqc2 vf1, 44(a1) vf1 = frag.bbox.min
c->lui(a3, 1); // lui a3, 1 a3 = 0x10000
c->lqc2(vf2, 128, a2); // lqc2 vf2, 128(a2) vf2 = query.bbox.min
c->ori(a3, a3, 257); // ori a3, a3, 257 a3=0x10101
c->lqc2(vf3, 144, a2); // lqc2 vf3, 144(a2) vf3 = query.bbox.max
c->dsubu(v1, v1, a3); // dsubu v1, v1, a3 some math on the dim array
c->lqc2(vf6, 60, a1); // lqc2 vf6, 60(a1) vf6 = frag.axis_scale;
c->vsub(DEST::xyzw, vf2, vf2, vf1); // vsub.xyzw vf2, vf2, vf1 vf2 = query.min - frag.min
c->lq(a3, 160, a2); // lq a3, 160(a2) a3 = query.bbox.min.i
c->vsub(DEST::xyzw, vf3, vf3, vf1); // vsub.xyzw vf3, vf3, vf1 vf3 = query.max - frag.min
c->lq(t0, 176, a2); // lq t0, 176(a2) t0 = query.bbox.max.i
c->pextlb(v1, r0, v1); // pextlb v1, r0, v1
c->lq(t1, 76, a1); // lq t1, 76(a1)
c->pextlh(v1, r0, v1); // pextlh v1, r0, v1
c->lq(t2, 92, a1); // lq t2, 92(a1)
c->pcgtw(t0, t1, t0); // pcgtw t0, t1, t0
c->vftoi0(DEST::xyzw, vf4, vf2); // vftoi0.xyzw vf4, vf2
c->pcgtw(a3, a3, t2); // pcgtw a3, a3, t2
c->vftoi0(DEST::xyzw, vf5, vf3); // vftoi0.xyzw vf5, vf3
c->por(a3, t0, a3); // por a3, t0, a3
c->vmul(DEST::xyzw, vf2, vf2, vf6); // vmul.xyzw vf2, vf2, vf6
c->ppach(a3, r0, a3); // ppach a3, r0, a3
c->vmul(DEST::xyzw, vf3, vf3, vf6); // vmul.xyzw vf3, vf3, vf6
c->lq(t1, 76, a1); // lq t1, 76(a1) t1 = frag.bbox.min.i
c->pextlh(v1, r0, v1); // pextlh v1, r0, v1 v1 = dimensions, int.
c->lq(t2, 92, a1); // lq t2, 92(a1) t2 = frag.bbox.max.i
c->pcgtw(t0, t1, t0); // pcgtw t0, t1, t0 check for bbox miss.
c->vftoi0(DEST::xyzw, vf4, vf2); // vftoi0.xyzw vf4, vf2 vf4 = int(q.min - f.min)
c->pcgtw(a3, a3, t2); // pcgtw a3, a3, t2 check for bbox miss.
c->vftoi0(DEST::xyzw, vf5, vf3); // vftoi0.xyzw vf5, vf3 vf5 = int(q.max - f.min)
c->por(a3, t0, a3); // por a3, t0, a3 or miss
c->vmul(DEST::xyzw, vf2, vf2, vf6); // vmul.xyzw vf2, vf2, vf6 axis scale
c->ppach(a3, r0, a3); // ppach a3, r0, a3 or stuff
c->vmul(DEST::xyzw, vf3, vf3, vf6); // vmul.xyzw vf3, vf3, vf6 axis scale
c->dsll(t0, a3, 16); // dsll t0, a3, 16
c->mov128_gpr_vf(a3, vf4); // qmfc2.i a3, vf4
c->mov128_gpr_vf(a3, vf4); // qmfc2.i a3, vf4 a3 = int(q.min - f.min)
bc = c->sgpr64(t0) != 0; // bne t0, r0, L75
c->mov128_gpr_vf(t0, vf5); // qmfc2.i t0, vf5
c->mov128_gpr_vf(t0, vf5); // qmfc2.i t0, vf5 t0 = int(q.max - f.min)
if (bc) {goto block_17;} // branch non-likely
c->vftoi0(DEST::xyzw, vf2, vf2); // vftoi0.xyzw vf2, vf2
// patch because there's a totally bogus collide fragment with an axis scale of
// 0.00012207031, 0.00012207031, 1807931
c->vftoi0_sat(DEST::xyzw, vf2, vf2); // vftoi0.xyzw vf2, vf2
c->psraw(a3, a3, 4); // psraw a3, a3, 4
c->vftoi0(DEST::xyzw, vf3, vf3); // vftoi0.xyzw vf3, vf3
c->vftoi0_sat(DEST::xyzw, vf3, vf3); // vftoi0.xyzw vf3, vf3
c->psraw(t0, t0, 4); // psraw t0, t0, 4
// nop // sll r0, r0, 0
c->sq(a3, 368, a2); // sq a3, 368(a2)

View File

@ -1344,6 +1344,15 @@ struct ExecutionContext {
}
}
void vftoi0_sat(DEST mask, int dst, int src) {
auto s = vf_src(src);
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
vfs[dst].ds32[i] = float_to_int_sat(s.f[i]);
}
}
}
void mfc1(int dst, int src) {
s32 val;
memcpy(&val, &fprs[src], 4);