jak2: ocean renderer (#2142)

Initial implementation of the `ocean-mid`, `ocean-far` and `ocean-near`
renderers for Jak 2.

There's still a few things to sort out, mainly:

- [x] ~Backwards compatibility with Jak 1. The only thing that currently
stands in the way of that is figuring out a clean way to "un-hardcode"
the texture base pointer in C++ without creating a completely separate
`OceanTexture` class for Jak 2. One thing I thought of would be
modifying `BucketRenderer`'s virtual `init_textures` method to also pass
the `GameVersion`, but I'm not sure if there's a better way.~
- [x] ~The sudden transition from `ocean-near` to `ocean-mid`. Not sure
why it's happening or how to fix it.~
- [x] The ocean has two new methods in Jak 2, `ocean::89` and
`ocean::79`, one of which seems to be related to time of day sky colors.
~Even without them implemented, the end result looks quite close, so we
may be able to skip them?~ `ocean::89` generates `ocean-mid` envmap
textures, so it will likely be required, but will not be handled right
now.

Reverted the VU prologue removals because it made the tests fail.
This commit is contained in:
Hat Kid
2023-01-23 00:07:46 +01:00
committed by GitHub
parent 40867fc086
commit 3d08d079c9
25 changed files with 3961 additions and 54 deletions
+2 -2
View File
@@ -2724,7 +2724,7 @@
(bucket-3 3) ;; blit displays
(tex-lcom-sky-pre 4) ;; tex
(sky-draw 5) ;; sky
(bucket-6 6) ;; ocean
(ocean-mid-far 6) ;; ocean
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; All levels with tfrag tpage
@@ -3080,7 +3080,7 @@
(tex-lcom-sky-post 309)
(bucket-310 310) ;; ocean
(ocean-near 310) ;; ocean
(bucket-311 311) ;; depth-cue
(tex-all-sprite 312)
@@ -99,9 +99,9 @@ void RenderMux::draw_debug_window() {
m_renderers[m_render_idx]->draw_debug_window();
}
void RenderMux::init_textures(TexturePool& tp) {
void RenderMux::init_textures(TexturePool& tp, GameVersion version) {
for (auto& rend : m_renderers) {
rend->init_textures(tp);
rend->init_textures(tp, version);
}
}
@@ -95,7 +95,7 @@ class BucketRenderer {
virtual bool empty() const { return false; }
virtual void draw_debug_window() = 0;
virtual void init_shaders(ShaderLibrary&) {}
virtual void init_textures(TexturePool&) {}
virtual void init_textures(TexturePool&, GameVersion) {}
protected:
std::string m_name;
@@ -111,7 +111,7 @@ class RenderMux : public BucketRenderer {
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
void init_shaders(ShaderLibrary&) override;
void init_textures(TexturePool&) override;
void init_textures(TexturePool&, GameVersion) override;
void set_idx(u32 i) { m_render_idx = i; };
private:
@@ -11,7 +11,7 @@
/////////////////////////
EyeRenderer::EyeRenderer(const std::string& name, int id) : BucketRenderer(name, id) {}
void EyeRenderer::init_textures(TexturePool& texture_pool) {
void EyeRenderer::init_textures(TexturePool& texture_pool, GameVersion) {
// set up eyes
for (int pair_idx = 0; pair_idx < NUM_EYE_PAIRS; pair_idx++) {
for (int lr = 0; lr < 2; lr++) {
+1 -1
View File
@@ -16,7 +16,7 @@ class EyeRenderer : public BucketRenderer {
~EyeRenderer();
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void draw_debug_window() override;
void init_textures(TexturePool& texture_pool) override;
void init_textures(TexturePool& texture_pool, GameVersion) override;
void handle_eye_dma2(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
@@ -93,8 +93,8 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-pre", BucketCategory::TEX,
BucketId::TEX_LCOM_SKY_PRE);
init_bucket_renderer<DirectRenderer>("sky-draw", BucketCategory::OTHER, BucketId::SKY_DRAW, 1024);
init_bucket_renderer<SkipRenderer>("ocean-mid-far", BucketCategory::OCEAN,
BucketId::OCEAN_MID_FAR);
init_bucket_renderer<OceanMidAndFar>("ocean-mid-far", BucketCategory::OCEAN,
BucketId::OCEAN_MID_FAR);
init_bucket_renderer<TextureUploadHandler>("tex-l0-tfrag", BucketCategory::TEX,
BucketId::TEX_L0_TFRAG);
init_bucket_renderer<TFragment>("tfrag-l0-tfrag", BucketCategory::TFRAG, BucketId::TFRAG_L0_TFRAG,
@@ -279,7 +279,7 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
init_bucket_renderer<TextureUploadHandler>("tex-lcom-sky-post", BucketCategory::TEX,
BucketId::TEX_LCOM_SKY_POST);
// 310
init_bucket_renderer<SkipRenderer>("bucket-310", BucketCategory::OCEAN, BucketId::OCEAN_NEAR);
init_bucket_renderer<OceanNear>("ocean-near", BucketCategory::OCEAN, BucketId::OCEAN_NEAR);
init_bucket_renderer<TextureUploadHandler>("tex-all-sprite", BucketCategory::TEX,
BucketId::TEX_ALL_SPRITE);
init_bucket_renderer<Sprite3>("particles", BucketCategory::SPRITE, BucketId::PARTICLES);
@@ -309,7 +309,7 @@ void OpenGLRenderer::init_bucket_renderers_jak2() {
}
m_bucket_renderers[i]->init_shaders(m_render_state.shaders);
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool);
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool, GameVersion::Jak2);
}
m_render_state.loader->load_common(*m_render_state.texture_pool, "GAME");
}
@@ -534,7 +534,7 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
}
m_bucket_renderers[i]->init_shaders(m_render_state.shaders);
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool);
m_bucket_renderers[i]->init_textures(*m_render_state.texture_pool, GameVersion::Jak1);
}
sky_cpu_blender->init_textures(*m_render_state.texture_pool);
sky_gpu_blender->init_textures(*m_render_state.texture_pool);
@@ -2,6 +2,9 @@
#include "common/log/log.h"
constexpr int OCEAN_TEX_TBP_JAK1 = 8160; // todo
constexpr int OCEAN_TEX_TBP_JAK2 = 672;
CommonOceanRenderer::CommonOceanRenderer() {
m_vertices.resize(4096 * 10); // todo decrease
for (auto& buf : m_indices) {
@@ -244,8 +247,14 @@ void CommonOceanRenderer::handle_near_adgif(const u8* data, u32 offset, u32 coun
most_recent_tbp = reg.tbp0();
} break;
case GsRegisterAddress::ALPHA_1: {
// ignore, we've hardcoded alphas.
GsAlpha reg(value);
if (reg.a_mode() == GsAlpha::BlendMode::SOURCE &&
reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED &&
reg.c_mode() == GsAlpha::BlendMode::DEST && reg.d_mode() == GsAlpha::BlendMode::DEST) {
m_current_bucket = VertexBucket::ENV_MAP;
}
} break;
case GsRegisterAddress::FRAME_1: {
u32 mask = value >> 32;
if (mask) {
@@ -290,7 +299,9 @@ void CommonOceanRenderer::flush_near(SharedRenderState* render_state, ScopedProf
case 0: {
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
glBlendEquation(GL_FUNC_ADD);
auto tex = render_state->texture_pool->lookup(8160);
auto tbp =
render_state->version == GameVersion::Jak1 ? OCEAN_TEX_TBP_JAK1 : OCEAN_TEX_TBP_JAK2;
auto tex = render_state->texture_pool->lookup(tbp);
if (!tex) {
tex = render_state->texture_pool->get_placeholder_texture();
}
@@ -419,7 +430,7 @@ void CommonOceanRenderer::handle_mid_adgif(const u8* data, u32 offset) {
}
}
if (most_recent_tbp != 8160) {
if (most_recent_tbp != OCEAN_TEX_TBP_JAK2) {
m_envmap_tex = most_recent_tbp;
}
@@ -482,7 +493,9 @@ void CommonOceanRenderer::flush_mid(SharedRenderState* render_state, ScopedProfi
for (int bucket = 0; bucket < 2; bucket++) {
switch (bucket) {
case 0: {
auto tex = render_state->texture_pool->lookup(8160);
auto tbp =
render_state->version == GameVersion::Jak1 ? OCEAN_TEX_TBP_JAK1 : OCEAN_TEX_TBP_JAK2;
auto tex = render_state->texture_pool->lookup(tbp);
if (!tex) {
tex = render_state->texture_pool->get_placeholder_texture();
}
@@ -133,6 +133,127 @@ void OceanMid::run(DmaFollower& dma, SharedRenderState* render_state, ScopedProf
m_common_ocean_renderer.flush_mid(render_state, prof);
}
void OceanMid::run_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
m_common_ocean_renderer.init_for_mid();
// first is setting base and offset
{
auto base_offset_tag = dma.read_and_advance();
ASSERT(base_offset_tag.size_bytes == 0);
auto base = base_offset_tag.vifcode0();
ASSERT(base.kind == VifCode::Kind::BASE);
ASSERT(base.immediate == VU1_INPUT_BUFFER_BASE);
auto offset = base_offset_tag.vifcode1();
ASSERT(offset.kind == VifCode::Kind::OFFSET);
ASSERT(offset.immediate == VU1_INPUT_BUFFER_OFFSET);
}
// next is constants
{
auto constants = dma.read_and_advance();
ASSERT(constants.size_bytes == sizeof(Constants));
ASSERT(constants.vifcode0().kind == VifCode::Kind::STCYCL); // for whatever reason they do this
auto unpack = constants.vifcode1();
ASSERT(VifCodeUnpack(unpack).addr_qw == Vu1Data::CONSTANTS);
memcpy(&m_constants, constants.data, sizeof(Constants));
memcpy(m_vu_data + Vu1Data::CONSTANTS, &m_constants, sizeof(Constants));
}
// next is call 0
{
auto call0 = dma.read_and_advance();
ASSERT(call0.vifcode0().kind == VifCode::Kind::STCYCL);
auto c = call0.vifcode1();
ASSERT(c.kind == VifCode::Kind::MSCALF);
ASSERT(c.immediate == 0);
run_call0();
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vif0(), dma.current_tag_vif1())) {
auto data = dma.read_and_advance();
auto v0 = data.vifcode0();
auto v1 = data.vifcode1();
if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_32) {
auto up = VifCodeUnpack(v1);
// ASSERT(up.use_tops_flag);
u16 addr = up.addr_qw + (up.use_tops_flag ? get_upload_buffer() : 0);
ASSERT(addr + v1.num <= 1024);
memcpy(m_vu_data + addr, data.data, 16 * v1.num);
ASSERT(16 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
memcpy(m_vu_data + addr + i, temp, 16);
}
ASSERT(4 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x204 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
// cl = 4
// wl = 2
u32 addr_off = 4 * (i / 2) + i % 2;
memcpy(m_vu_data + addr + addr_off, temp, 16);
}
ASSERT(8 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::MSCALF) {
switch (v1.immediate) {
case 46:
run_call46_vu2c();
break;
case 73:
run_call73_vu2c_jak2();
break;
case 107:
run_call107_vu2c_jak2();
break;
case 275:
run_call275_vu2c_jak2();
break;
default:
lg::warn("unknown call1: {}", v1.immediate);
}
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::FLUSHA) {
switch (v0.immediate) {
case 41:
run_call41_vu2c();
break;
case 43:
run_call43_vu2c();
break;
default:
ASSERT_MSG(false, fmt::format("unknown call2: {}", v0.immediate));
}
} else {
ASSERT_MSG(false, fmt::format("{} {}", data.vifcode0().print(), data.vifcode1().print()));
}
}
m_common_ocean_renderer.flush_mid(render_state, prof);
}
void OceanMid::run_call0() {
run_call0_vu2c();
}
@@ -9,6 +9,7 @@ class OceanMid {
public:
OceanMid();
void run(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void run_jak2(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
private:
void run_call0();
@@ -17,13 +18,18 @@ class OceanMid {
void run_call43_vu2c();
void run_call46_vu2c();
void run_call73_vu2c();
void run_call73_vu2c_jak2();
void run_call107_vu2c();
void run_call107_vu2c_jak2();
void run_call275_vu2c();
void run_call275_vu2c_jak2();
void xgkick(u16 addr);
void run_L26_vu2c();
void run_L32_vu2c();
void run_L32_vu2c_jak2();
void run_L38_vu2c();
void run_L38_vu2c_jak2();
void run_L43_vu2c();
void run_L45_vu2c();
@@ -10,8 +10,8 @@ void OceanMidAndFar::draw_debug_window() {
m_direct.draw_debug_window();
}
void OceanMidAndFar::init_textures(TexturePool& pool) {
m_texture_renderer.init_textures(pool);
void OceanMidAndFar::init_textures(TexturePool& pool, GameVersion version) {
m_texture_renderer.init_textures(pool, version);
}
void OceanMidAndFar::render(DmaFollower& dma,
@@ -25,6 +25,19 @@ void OceanMidAndFar::render(DmaFollower& dma,
return;
}
switch (render_state->version) {
case GameVersion::Jak1:
render_jak1(dma, render_state, prof);
break;
case GameVersion::Jak2:
render_jak2(dma, render_state, prof);
break;
}
}
void OceanMidAndFar::render_jak1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// jump to bucket
auto data0 = dma.read_and_advance();
ASSERT(data0.vif1() == 0);
@@ -44,7 +57,7 @@ void OceanMidAndFar::render(DmaFollower& dma,
{
auto p = prof.make_scoped_child("texture");
m_texture_renderer.handle_ocean_texture(dma, render_state, p);
m_texture_renderer.handle_ocean_texture_jak1(dma, render_state, p);
}
handle_ocean_far(dma, render_state, prof);
@@ -65,6 +78,73 @@ void OceanMidAndFar::render(DmaFollower& dma,
m_direct.set_mipmap(false);
}
void advance_and_print_dma(DmaFollower& dma) {
auto data = dma.read_and_advance();
printf(
"dma transfer:\n%ssize: %d\nvif0: %s, data: %d\nvif1: %s, data: %d, imm: "
"%d\n\n",
dma.current_tag().print().c_str(), data.size_bytes, data.vifcode0().print().c_str(),
data.vif0(), data.vifcode1().print().c_str(), data.vifcode1().num, data.vifcode1().immediate);
}
void OceanMidAndFar::render_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// jump to bucket
auto data0 = dma.read_and_advance();
ASSERT(data0.vif1() == 0 || data0.vifcode1().kind == VifCode::Kind::NOP);
ASSERT(data0.vif0() == 0 || data0.vifcode0().kind == VifCode::Kind::MARK);
ASSERT(data0.size_bytes == 0);
// see if bucket is empty or not
if (dma.current_tag_offset() == render_state->next_bucket) {
// fmt::print("ocean-mid-far: early exit!\n");
return;
}
m_direct.reset_state();
// TODO handle ocean::89 and ocean::79
// handle_ocean_89_jak2(dma, render_state, prof);
{
auto p = prof.make_scoped_child("texture");
m_texture_renderer.handle_ocean_texture_jak2(dma, render_state, p);
}
// handle_ocean_79_jak2(dma, render_state, prof);
handle_ocean_far(dma, render_state, prof);
m_direct.flush_pending(render_state, prof);
m_direct.set_mipmap(true);
handle_ocean_mid(dma, render_state, prof);
auto final_next = dma.read_and_advance();
ASSERT(final_next.vifcode0().kind == VifCode::Kind::NOP &&
final_next.vifcode1().kind == VifCode::Kind::NOP && final_next.size_bytes == 0);
for (int i = 0; i < 2; i++) {
dma.read_and_advance();
}
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
// auto transfers = 0;
// // print the entire chain
// printf("START OCEAN MID FAR DMA!!!!!!!\n");
// while (dma.current_tag_offset() != render_state->next_bucket) {
// auto data = dma.read_and_advance();
// printf(
// "dma transfer %d:\n%ssize: %d\nvif0: %s, data: %d\nvif1: %s, data: %d, imm: "
// "%d\n\n",
// transfers, dma.current_tag().print().c_str(), data.size_bytes,
// data.vifcode0().print().c_str(), data.vif0(), data.vifcode1().print().c_str(),
// data.vifcode1().num, data.vifcode1().immediate);
// transfers++;
// }
// printf("transfers: %d\n\n", transfers);
m_direct.flush_pending(render_state, prof);
m_direct.set_mipmap(false);
}
void OceanMidAndFar::handle_ocean_far(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
@@ -98,7 +178,13 @@ void OceanMidAndFar::handle_ocean_mid(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (dma.current_tag_vifcode0().kind == VifCode::Kind::BASE) {
m_mid_renderer.run(dma, render_state, prof);
switch (render_state->version) {
case GameVersion::Jak1:
m_mid_renderer.run(dma, render_state, prof);
break;
case GameVersion::Jak2:
m_mid_renderer.run_jak2(dma, render_state, prof);
}
} else {
// not drawing
return;
@@ -107,4 +193,12 @@ void OceanMidAndFar::handle_ocean_mid(DmaFollower& dma,
while (!is_end_tag(dma.current_tag(), dma.current_tag_vifcode0(), dma.current_tag_vifcode1())) {
dma.read_and_advance();
}
}
}
void handle_ocean_89_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {}
void handle_ocean_79_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {}
@@ -17,8 +17,10 @@ class OceanMidAndFar : public BucketRenderer {
public:
OceanMidAndFar(const std::string& name, int my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void render_jak1(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void render_jak2(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void draw_debug_window() override;
void init_textures(TexturePool& pool) override;
void init_textures(TexturePool& pool, GameVersion version) override;
private:
void handle_ocean_far(DmaFollower& dma,
@@ -27,6 +29,12 @@ class OceanMidAndFar : public BucketRenderer {
void handle_ocean_mid(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_ocean_89_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_ocean_79_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
DirectRenderer m_direct;
OceanTexture m_texture_renderer;
File diff suppressed because it is too large Load Diff
@@ -13,8 +13,8 @@ OceanNear::OceanNear(const std::string& name, int my_id)
void OceanNear::draw_debug_window() {}
void OceanNear::init_textures(TexturePool& pool) {
m_texture_renderer.init_textures(pool);
void OceanNear::init_textures(TexturePool& pool, GameVersion version) {
m_texture_renderer.init_textures(pool, version);
}
static bool is_end_tag(const DmaTag& tag, const VifCode& v0, const VifCode& v1) {
@@ -33,6 +33,19 @@ void OceanNear::render(DmaFollower& dma,
return;
}
switch (render_state->version) {
case GameVersion::Jak1:
render_jak1(dma, render_state, prof);
break;
case GameVersion::Jak2:
render_jak2(dma, render_state, prof);
break;
}
}
void OceanNear::render_jak1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// jump to bucket
auto data0 = dma.read_and_advance();
ASSERT(data0.vif1() == 0);
@@ -52,7 +65,7 @@ void OceanNear::render(DmaFollower& dma,
{
auto p = prof.make_scoped_child("texture");
// TODO: this looks the same as the previous ocean renderer to me... why do it again?
m_texture_renderer.handle_ocean_texture(dma, render_state, p);
m_texture_renderer.handle_ocean_texture_jak1(dma, render_state, p);
}
if (dma.current_tag().qwc != 2) {
@@ -117,6 +130,88 @@ void OceanNear::render(DmaFollower& dma,
m_common_ocean_renderer.flush_near(render_state, prof);
}
void OceanNear::render_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// jump to bucket
auto data0 = dma.read_and_advance();
ASSERT(data0.vif1() == 0 || data0.vifcode1().kind == VifCode::Kind::NOP);
ASSERT(data0.vif0() == 0 || data0.vifcode0().kind == VifCode::Kind::MARK);
ASSERT(data0.size_bytes == 0);
// see if bucket is empty or not
if (dma.current_tag_offset() == render_state->next_bucket) {
// fmt::print("ocean-near: early exit!\n");
return;
}
{
auto p = prof.make_scoped_child("texture");
m_texture_renderer.handle_ocean_texture_jak2(dma, render_state, p);
}
if (dma.current_tag().qwc != 2) {
lg::error("abort OceanNear::render!");
while (dma.current_tag_offset() != render_state->next_bucket) {
dma.read_and_advance();
}
return;
}
// direct setup
{
m_common_ocean_renderer.init_for_near();
auto setup = dma.read_and_advance();
ASSERT(setup.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(setup.vifcode1().kind == VifCode::Kind::DIRECT);
ASSERT(setup.size_bytes == 32);
}
// offset and base
{
auto ob = dma.read_and_advance();
ASSERT(ob.size_bytes == 0);
auto base = ob.vifcode0();
auto off = ob.vifcode1();
ASSERT(base.kind == VifCode::Kind::BASE);
ASSERT(off.kind == VifCode::Kind::OFFSET);
ASSERT(base.immediate == VU1_INPUT_BUFFER_BASE);
ASSERT(off.immediate == VU1_INPUT_BUFFER_OFFSET);
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vif0(), dma.current_tag_vif1())) {
auto data = dma.read_and_advance();
auto v0 = data.vifcode0();
auto v1 = data.vifcode1();
if (v0.kind == VifCode::Kind::STCYCL && v1.kind == VifCode::Kind::UNPACK_V4_32) {
ASSERT(v0.immediate == 0x404);
auto up = VifCodeUnpack(v1);
u16 addr = up.addr_qw + (up.use_tops_flag ? get_upload_buffer() : 0);
ASSERT(addr + v1.num <= 1024);
memcpy(m_vu_data + addr, data.data, 16 * v1.num);
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::STMOD) {
ASSERT(v1.immediate == 0);
switch (v0.immediate) {
case 0:
run_call0_vu2c_jak2();
break;
case 39:
run_call39_vu2c_jak2();
break;
default:
ASSERT_MSG(false, fmt::format("unknown ocean near call: {}", v0.immediate));
}
}
}
while (dma.current_tag_offset() != render_state->next_bucket) {
dma.read_and_advance();
}
m_common_ocean_renderer.flush_near(render_state, prof);
}
void OceanNear::xgkick(u16 addr) {
m_common_ocean_renderer.kick_from_near((const u8*)&m_vu_data[addr]);
}
@@ -9,16 +9,23 @@ class OceanNear : public BucketRenderer {
public:
OceanNear(const std::string& name, int my_id);
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override;
void render_jak1(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void render_jak2(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof);
void draw_debug_window() override;
void init_textures(TexturePool& pool) override;
void init_textures(TexturePool& pool, GameVersion version) override;
private:
void run_call0_vu2c();
void run_call0_vu2c_jak2();
void run_call39_vu2c();
void run_call39_vu2c_jak2();
void run_L15_vu2c();
void run_L15_vu2c_jak2();
void run_L21_vu2c();
void run_L21_vu2c_jak2();
void run_L23_vu2c();
void run_L25_vu2c();
void run_L25_vu2c_jak2();
void run_L30_vu2c();
void run_L32_vu2c();
File diff suppressed because it is too large Load Diff
@@ -4,7 +4,9 @@
#include "third-party/imgui/imgui.h"
constexpr int OCEAN_TEX_TBP = 8160; // todo
constexpr int OCEAN_TEX_TBP_JAK1 = 8160; // todo
constexpr int OCEAN_TEX_TBP_JAK2 = 672;
OceanTexture::OceanTexture(bool generate_mipmaps)
: m_generate_mipmaps(generate_mipmaps),
m_result_texture(TEX0_SIZE,
@@ -53,7 +55,7 @@ OceanTexture::~OceanTexture() {
destroy_pc();
}
void OceanTexture::init_textures(TexturePool& pool) {
void OceanTexture::init_textures(TexturePool& pool, GameVersion version) {
TextureInput in;
in.gpu_texture = m_result_texture.texture();
in.w = TEX0_SIZE;
@@ -61,7 +63,14 @@ void OceanTexture::init_textures(TexturePool& pool) {
in.debug_page_name = "PC-OCEAN";
in.debug_name = fmt::format("pc-ocean-mip-{}", m_generate_mipmaps);
in.id = pool.allocate_pc_port_texture();
m_tex0_gpu = pool.give_texture_and_load_to_vram(in, OCEAN_TEX_TBP);
switch (version) {
case GameVersion::Jak1:
m_tex0_gpu = pool.give_texture_and_load_to_vram(in, OCEAN_TEX_TBP_JAK1);
break;
case GameVersion::Jak2:
m_tex0_gpu = pool.give_texture_and_load_to_vram(in, OCEAN_TEX_TBP_JAK2);
break;
}
}
void OceanTexture::draw_debug_window() {
@@ -70,9 +79,9 @@ void OceanTexture::draw_debug_window() {
}
}
void OceanTexture::handle_ocean_texture(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
void OceanTexture::handle_ocean_texture_jak1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// if we're doing mipmaps, render to temp.
// otherwise, render directly to target.
FramebufferTexturePairContext ctxt(m_generate_mipmaps ? m_temp_texture : m_result_texture);
@@ -224,7 +233,169 @@ void OceanTexture::handle_ocean_texture(DmaFollower& dma,
}
// give to gpu!
render_state->texture_pool->move_existing_to_vram(m_tex0_gpu, OCEAN_TEX_TBP);
render_state->texture_pool->move_existing_to_vram(m_tex0_gpu, OCEAN_TEX_TBP_JAK1);
}
void OceanTexture::handle_ocean_texture_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
// if we're doing mipmaps, render to temp.
// otherwise, render directly to target.
FramebufferTexturePairContext ctxt(m_generate_mipmaps ? m_temp_texture : m_result_texture);
// render to the first texture
{
// (set-display-gs-state arg0 21 128 128 0 0)
auto data = dma.read_and_advance();
(void)data;
}
// set up GS for envmap texture drawing
{
// (ocean-texture-add-envmap arg0)
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == sizeof(AdGifData) + 16); // 16 for the giftag.
ASSERT(data.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(data.vifcode1().kind == VifCode::Kind::DIRECT);
memcpy(&m_envmap_adgif, data.data + 16, sizeof(AdGifData));
// HACK
setup_renderer();
}
// set up VIF
{
// (new 'static 'vif-tag)
// (new 'static 'vif-tag :imm #x4 :cmd (vif-cmd offset))
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == 64);
ASSERT(data.vifcode0().kind == VifCode::Kind::NOP);
ASSERT(data.vifcode1().kind == VifCode::Kind::DIRECT);
ASSERT(data.vifcode0().immediate == 0);
ASSERT(data.vifcode1().immediate == 0x4);
}
// (dma-buffer-add-vu-function arg0 ocean-texture-vu1-block 1)
dma.read_and_advance();
{
// (ocean-texture-add-constants obj arg0)
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == sizeof(OceanTextureConstants));
ASSERT(data.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(data.vifcode0().immediate == 0x404);
ASSERT(data.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
ASSERT(data.vifcode1().num == data.size_bytes / 16);
ASSERT(data.vifcode1().immediate == TexVu1Data::CONSTANTS);
memcpy(&m_texture_constants, data.data, sizeof(OceanTextureConstants));
}
// vertices are uploaded double buffered
m_texture_vertices_loading = m_texture_vertices_a;
m_texture_vertices_drawing = m_texture_vertices_b;
// add first group of vertices
{
// (ocean-texture-add-verts arg0 sv-16)
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == sizeof(m_texture_vertices_a));
ASSERT(data.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(data.vifcode0().immediate == 0x404);
ASSERT(data.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
ASSERT(data.vifcode1().num == data.size_bytes / 16);
VifCodeUnpack up(data.vifcode1());
ASSERT(up.addr_qw == 0);
ASSERT(up.use_tops_flag == true);
memcpy(m_texture_vertices_loading, data.data, sizeof(m_texture_vertices_a));
}
// first call
{
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == 0);
ASSERT(data.vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(data.vifcode0().immediate == TexVu1Prog::START);
ASSERT(data.vifcode1().kind == VifCode::Kind::STMOD); // not sure why...
run_L1_PC_jak2();
}
// loop over vertex groups
for (int i = 0; i < NUM_FRAG_LOOPS; i++) {
auto verts = dma.read_and_advance();
ASSERT(verts.size_bytes == sizeof(m_texture_vertices_a));
ASSERT(verts.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(verts.vifcode0().immediate == 0x404);
ASSERT(verts.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
ASSERT(verts.vifcode1().num == verts.size_bytes / 16);
VifCodeUnpack up(verts.vifcode1());
ASSERT(up.addr_qw == 0);
ASSERT(up.use_tops_flag == true);
memcpy(m_texture_vertices_loading, verts.data, sizeof(m_texture_vertices_a));
auto call = dma.read_and_advance();
ASSERT(call.size_bytes == 0);
ASSERT(call.vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(call.vifcode0().immediate == TexVu1Prog::REST);
ASSERT(call.vifcode1().kind == VifCode::Kind::STMOD); // not sure why...
run_L2_PC_jak2();
}
// last upload does something weird...
{
// (ocean-texture-add-verts-last arg0 (the-as (inline-array vector) sv-48) sv-64)
auto data0 = dma.read_and_advance();
ASSERT(data0.size_bytes == 128 * 16);
ASSERT(data0.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(data0.vifcode0().immediate == 0x404);
ASSERT(data0.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
ASSERT(data0.vifcode1().num == data0.size_bytes / 16);
VifCodeUnpack up0(data0.vifcode1());
ASSERT(up0.addr_qw == 0);
ASSERT(up0.use_tops_flag == true);
memcpy(m_texture_vertices_loading, data0.data, 128 * 16);
auto data1 = dma.read_and_advance();
ASSERT(data1.size_bytes == 64 * 16);
ASSERT(data1.vifcode0().kind == VifCode::Kind::STCYCL);
ASSERT(data1.vifcode0().immediate == 0x404);
ASSERT(data1.vifcode1().kind == VifCode::Kind::UNPACK_V4_32);
ASSERT(data1.vifcode1().num == data1.size_bytes / 16);
VifCodeUnpack up1(data1.vifcode1());
ASSERT(up1.addr_qw == 128);
ASSERT(up1.use_tops_flag == true);
memcpy(m_texture_vertices_loading + 128, data1.data, 64 * 16);
}
// last rest call
{
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == 0);
ASSERT(data.vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(data.vifcode0().immediate == TexVu1Prog::REST);
ASSERT(data.vifcode1().kind == VifCode::Kind::STMOD); // not sure why...
run_L2_PC_jak2();
}
// last call
{
auto data = dma.read_and_advance();
ASSERT(data.size_bytes == 0);
ASSERT(data.vifcode0().kind == VifCode::Kind::MSCALF);
ASSERT(data.vifcode0().immediate == TexVu1Prog::DONE);
ASSERT(data.vifcode1().kind == VifCode::Kind::STMOD); // not sure why...
// this program does nothing.
}
flush(render_state, prof);
if (m_generate_mipmaps) {
// if we did mipmaps, the above code rendered to temp, and now we need to generate mipmaps
// in the real output
make_texture_with_mipmaps(render_state, prof);
}
// (reset-display-gs-state *display* arg0)
// dma.read_and_advance();
// give to gpu!
render_state->texture_pool->move_existing_to_vram(m_tex0_gpu, OCEAN_TEX_TBP_JAK2);
}
/*!
@@ -8,10 +8,13 @@
class OceanTexture {
public:
OceanTexture(bool generate_mipmaps);
void handle_ocean_texture(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void init_textures(TexturePool& pool);
void handle_ocean_texture_jak1(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void handle_ocean_texture_jak2(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof);
void init_textures(TexturePool& pool, GameVersion version);
void draw_debug_window();
~OceanTexture();
@@ -22,6 +25,10 @@ class OceanTexture {
void run_L5_PC();
void xgkick_PC(Vf* src);
void run_L1_PC_jak2();
void run_L2_PC_jak2();
void run_L3_PC_jak2();
void setup_renderer();
void flush(SharedRenderState* render_state, ScopedProfilerNode& prof);
@@ -394,6 +394,240 @@ void OceanTexture::xgkick_PC(Vf* src) {
}
}
void OceanTexture::run_L1_PC_jak2() {
// L1:
// lq.xyzw vf14_startx, 988(vi00) | maxw.xyzw vf01_ones, vf00, vf00
vu.startx = Vf(m_texture_constants.start);
// lq.xyzw vf02_offset, 989(vi00)
// lq.xyzw vf03_tbuf, 986(vi00)
// lq.xyzw vf04_dbuf, 987(vi00)
// lq.xyzw vf05_giftag, 985(vi00)
// lq.xyzw vf06_cam_nrm, 991(vi00)
// lq.xyzw vf07_constants, 990(vi00)
// iaddiu vi11_0x80, vi00, 0x80
// mtir vi08_tptr, vf03_tbuf.x
vu.tptr = get_tbuf();
// mtir vi09_tbase, vf03_tbuf.x
vu.tbase = get_tbuf();
// mr32.xyzw vf03_tbuf, vf03_tbuf
swap_tbuf();
// xtop vi05_in_ptr
vu.in_ptr = swap_vu_upload_buffers();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi03_dbuf_read_a, vf04_dbuf.x
vu.dbuf_read_a = get_dbuf();
// bal vi12_ra, L5
// mtir vi04_dbuf_read_b, vf04_dbuf.y
vu.dbuf_read_b = get_dbuf_other();
run_L5_PC();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi03_dbuf_read_a, vf04_dbuf.x
vu.dbuf_read_a = get_dbuf();
// bal vi12_ra, L5
// mtir vi04_dbuf_read_b, vf04_dbuf.y
vu.dbuf_read_b = get_dbuf_other();
run_L5_PC();
// nop :e
// nop
}
void OceanTexture::run_L2_PC_jak2() {
// L2:
// xtop vi05_in_ptr
vu.in_ptr = swap_vu_upload_buffers();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi03_dbuf_read_a, vf04_dbuf.x
vu.dbuf_read_a = get_dbuf();
// bal vi12_ra, L5
// mtir vi04_dbuf_read_b, vf04_dbuf.y
vu.dbuf_read_b = get_dbuf_other();
run_L5_PC();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi03_dbuf_read_a, vf04_dbuf.x
vu.dbuf_read_a = get_dbuf();
// bal vi12_ra, L5
// mtir vi04_dbuf_read_b, vf04_dbuf.y
vu.dbuf_read_b = get_dbuf_other();
run_L5_PC();
// mtir vi06_dbuf_write, vf04_dbuf.x
vu.dbuf_write = get_dbuf();
// bal vi12_ra, L3
// mr32.xyzw vf04_dbuf, vf04_dbuf
swap_dbuf();
run_L3_PC_jak2();
// mtir vi03_dbuf_read_a, vf04_dbuf.x
vu.dbuf_read_a = get_dbuf();
// bal vi12_ra, L5
// mtir vi04_dbuf_read_b, vf04_dbuf.y
vu.dbuf_read_b = get_dbuf_other();
run_L5_PC();
// nop :e
// nop
}
void OceanTexture::run_L3_PC_jak2() {
Vf base_pos; // vf15
u16 loop_idx;
Vf vtx0; // vf16
Vf vtx1; // vf17
Vf vtx2; // vf18
Vf vtx3; // vf19
Vf res0; // vf20
Vf res1; // vf21
Vf res2; // vf22
Vf res3; // vf23
Vf nrm0; // vf24
Vf nrm1; // vf25
Vf nrm2; // vf26
Vf reflect; // vf27
Vf cout0; // vf28
Vf cout1; // vf29
Vf cout2; // vf30
Vf cout3; // vf31
Accumulator acc;
const Vf ones(1, 1, 1, 1);
const Vf vf00(0, 0, 0, 1);
const u16 vi11 = 0x80;
bool bc;
// clang-format off
// L3:
// ior vi07, vi06, vi00 | nop 56
vu.dbuf_write_base = vu.dbuf_write;
// move.xyzw vf15, vf14 | nop 57
base_pos.move(Mask::xyzw, vu.startx);
// iaddi vi01, vi00, 0x8 | nop 58
loop_idx = 8;
// lq.xyzw vf24, 1(vi05) | mulw.xyzw vf20, vf15, vf00 59 (?? what are they doing here)
res0.mul(Mask::xyzw, base_pos, 1.f); lq_buffer(Mask::xyzw, nrm0, vu.in_ptr + 1);
// lq.xyzw vf26, 3(vi05) | mulw.xyzw vf21, vf15, vf00 60
res1.mul(Mask::xyzw, base_pos, 1.f); lq_buffer(Mask::xyzw, nrm2, vu.in_ptr + 5);
// nop | mulw.xyzw vf22, vf15, vf00 61
lq_buffer(Mask::xyzw, nrm2, vu.in_ptr + 5);
// nop | mulw.xyzw vf23, vf15, vf00 62
res3.mul(Mask::xyzw, base_pos, 1.f);
// nop | addx.x vf21, vf21, vf02 63
res1.add(Mask::x, res1, m_texture_constants.offsets.x());
// nop | addy.x vf22, vf22, vf02 64
res2.add(Mask::x, res2, m_texture_constants.offsets.y());
L4:
// nop | addz.x vf23, vf23, vf02 65
res3.add(Mask::x, res3, m_texture_constants.offsets.z());
// nop | addw.x vf15, vf15, vf02 66
base_pos.add(Mask::x, base_pos, m_texture_constants.offsets.w());
// sq.xyzw vf20, 2(vi06) | mulx.x vf28, vf01, vf24 67
cout0.mul(Mask::x, ones, nrm0.x()); sq_buffer(Mask::xyzw, res0, vu.dbuf_write + 2);
// sq.xyzw vf21, 5(vi06) | muly.x vf29, vf01, vf24 68
cout1.mul(Mask::x, ones, nrm0.y()); sq_buffer(Mask::xyzw, res1, vu.dbuf_write + 5);
// sq.xyzw vf22, 8(vi06) | mulz.x vf30, vf01, vf24 69
cout2.mul(Mask::x, ones, nrm0.z()); sq_buffer(Mask::xyzw, res2, vu.dbuf_write + 8);
// sq.xyzw vf23, 11(vi06) | mulw.x vf31, vf01, vf24 70
cout3.mul(Mask::x, ones, nrm0.w()); sq_buffer(Mask::xyzw, res3, vu.dbuf_write + 11);
// lq.xyzw vf16, 0(vi05) | mulx.y vf28, vf01, vf26 71
cout0.mul(Mask::y, ones, nrm2.x()); lq_buffer(Mask::xyzw, vtx0, vu.in_ptr);
// lq.xyzw vf17, 2(vi05) | muly.y vf29, vf01, vf26 72
cout1.mul(Mask::y, ones, nrm2.y()); lq_buffer(Mask::xyzw, vtx1, vu.in_ptr + 2);
// lq.xyzw vf18, 4(vi05) | mulz.y vf30, vf01, vf26 73
cout2.mul(Mask::y, ones, nrm2.z()); lq_buffer(Mask::xyzw, vtx2, vu.in_ptr + 4);
// lq.xyzw vf19, 6(vi05) | mulw.y vf31, vf01, vf26 74
cout3.mul(Mask::y, ones, nrm2.w()); lq_buffer(Mask::xyzw, vtx3, vu.in_ptr + 6);
// iaddi vi05, vi05, 0x8 | ftoi0.xyzw vf16, vf16 75
vtx0.ftoi0(Mask::xyzw, vtx0); vu.in_ptr = vu.in_ptr + 8;
// nop | ftoi0.xyzw vf17, vf17 76
vtx1.ftoi0(Mask::xyzw, vtx1);
// nop | ftoi0.xyzw vf18, vf18 77
vtx2.ftoi0(Mask::xyzw, vtx2);
// iaddi vi01, vi01, -0x1 | ftoi0.xyzw vf19, vf19 78
vtx3.ftoi0(Mask::xyzw, vtx3); loop_idx = loop_idx + -1;
// sq.xyzw vf16, 1(vi06) | add.xyzw vf28, vf28, vf07 79
cout0.add(Mask::xyzw, cout0, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx0, vu.dbuf_write + 1);
// sq.xyzw vf17, 4(vi06) | add.xyzw vf29, vf29, vf07 80
cout1.add(Mask::xyzw, cout1, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx1, vu.dbuf_write + 4);
// sq.xyzw vf18, 7(vi06) | add.xyzw vf30, vf30, vf07 81
cout2.add(Mask::xyzw, cout2, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx2, vu.dbuf_write + 7);
// sq.xyzw vf19, 10(vi06) | add.xyzw vf31, vf31, vf07 82
cout3.add(Mask::xyzw, cout3, m_texture_constants.cam_nrm); sq_buffer(Mask::xyzw, vtx3, vu.dbuf_write + 10);
// lq.xyzw vf24, 1(vi05) | sub.zw vf28, vf01, vf00 83
cout0.sub(Mask::zw, ones, vf00); lq_buffer(Mask::xyzw, nrm0, vu.in_ptr + 1);
// lq.xyzw vf26, 5(vi05) | sub.zw vf29, vf01, vf00 84
cout1.sub(Mask::zw, ones, vf00); lq_buffer(Mask::xyzw, nrm2, vu.in_ptr + 5);
// nop | sub.zw vf30, vf01, vf00 85
cout2.sub(Mask::zw, ones, vf00);
// nop | sub.zw vf31, vf01, vf00 86
cout3.sub(Mask::zw, ones, vf00);
// sq.xyzw vf28, 0(vi06) | mulw.xyzw vf20, vf15, vf00 87
res0.mul(Mask::xyzw, base_pos, 1.f); sq_buffer(Mask::xyzw, cout0, vu.dbuf_write);
// sq.xyzw vf29, 3(vi06) | mulw.xyzw vf21, vf15, vf00 88
res1.mul(Mask::xyzw, base_pos, 1.f); sq_buffer(Mask::xyzw, cout1, vu.dbuf_write + 3);
// sq.xyzw vf30, 6(vi06) | mulw.xyzw vf22, vf15, vf00 89
res2.mul(Mask::xyzw, base_pos, 1.f); sq_buffer(Mask::xyzw, cout2, vu.dbuf_write + 6);
// sq.xyzw vf31, 9(vi06) | mulw.xyzw vf23, vf15, vf00 90
res3.mul(Mask::xyzw, base_pos, 1.f); sq_buffer(Mask::xyzw, cout3, vu.dbuf_write + 9);
// BRANCH!
// ibgtz vi01, L4 | addx.x vf21, vf21, vf02 91
res1.add(Mask::x, res1, m_texture_constants.offsets.x()); bc = ((s16)loop_idx) > 0;
// iaddi vi06, vi06, 0xc | addy.x vf22, vf22, vf02 92
res2.add(Mask::x, res2, m_texture_constants.offsets.y()); vu.dbuf_write = vu.dbuf_write + 12;
if (bc) { goto L4; }
// lq.xyzw vf28, 0(vi07) | addx.y vf14, vf14, vf02 93
vu.startx.add(Mask::y, vu.startx, m_texture_constants.offsets.x()); lq_buffer(Mask::xyzw, cout0, vu.dbuf_write_base);
// lq.xyzw vf16, 1(vi07) | nop 94
lq_buffer(Mask::xyzw, vtx0, vu.dbuf_write_base + 1);
// sq.xyzw vf20, 2(vi06) | nop 95
sq_buffer(Mask::xyzw, res0, vu.dbuf_write + 2);
// sq.xyzw vf28, 0(vi06) | nop 96
sq_buffer(Mask::xyzw, cout0, vu.dbuf_write);
// jr vi12 | nop 97
// sq.xyzw vf16, 1(vi06) | nop 98
sq_buffer(Mask::xyzw, vtx0, vu.dbuf_write + 1);
// clang-format on
}
void OceanTexture::setup_renderer() {
m_pc.vtx_idx = 0;
}
@@ -9,7 +9,7 @@ out vec4 fragment_color;
out vec3 tex_coord;
out float fog;
const float SCISSOR_ADJUST = 512.0/448.0;
const float SCISSOR_ADJUST = HEIGHT_SCALE * 512.0/448.0;
uniform int bucket;
+1 -1
View File
@@ -7,7 +7,7 @@
;; DECOMP BEGINS
(define ocean-mid-block (new 'static 'vu-function :length #x490 :qlength #x248))
(define ocean-mid-block (new 'static 'vu-function #|:length #x490 :qlength #x248|#))
(defmethod ocean-mid-setup-constants ocean ((obj ocean) (arg0 ocean-mid-constants))
(let ((v1-0 *math-camera*))
+1 -1
View File
@@ -7,7 +7,7 @@
;; DECOMP BEGINS
(define ocean-near-block (new 'static 'vu-function :length #x3dd :qlength #x1ef))
(define ocean-near-block (new 'static 'vu-function #|:length #x3dd :qlength #x1ef|#))
(defmethod ocean-near-add-call ocean ((obj ocean) (arg0 dma-buffer) (arg1 int))
(let* ((v1-0 arg0)
@@ -7,7 +7,7 @@
;; DECOMP BEGINS
(define ocean-texture-vu1-block (new 'static 'vu-function :length #x7c :qlength 62))
(define ocean-texture-vu1-block (new 'static 'vu-function #|:length #x7c :qlength 62|#))
(defmethod ocean-texture-setup-constants ocean ((obj ocean) (arg0 ocean-texture-constants))
(set! (-> arg0 giftag tag)
@@ -203,8 +203,8 @@
)
(ocean-texture-add-call-rest obj arg0)
(ocean-texture-add-call-done obj arg0)
(ocean-method-81 obj arg0)
(reset-display-gs-state *display* arg0)
;; (ocean-method-81 obj arg0)
;; (reset-display-gs-state *display* arg0)
0
(none)
)
+9 -6
View File
@@ -1207,11 +1207,14 @@
(let* ((s4-0 (-> *display* frames (-> *display* on-screen) global-buf))
(s5-2 (-> s4-0 base))
)
(if (-> *time-of-day-context* sky)
(ocean-method-89 obj s4-0)
)
;; TODO handle ocean::79 and ocean::89
;; diasble tod ocean stuff
;; (if (-> *time-of-day-context* sky)
;; (ocean-method-89 obj s4-0)
;; )
(draw-ocean-texture obj s4-0 (the-as int (-> obj verts)))
(ocean-method-79 obj s4-0)
;; disable whatever this is
;; (ocean-method-79 obj s4-0)
(init-buffer! obj s4-0)
(if (-> obj far-on)
(draw-ocean-far obj s4-0)
@@ -1230,7 +1233,7 @@
)
(dma-bucket-insert-tag
(-> *display* frames (-> *display* on-screen) bucket-group)
(bucket-id bucket-6)
(bucket-id ocean-mid-far)
s5-2
(the-as (pointer dma-tag) a3-3)
)
@@ -1256,7 +1259,7 @@
)
(dma-bucket-insert-tag
(-> *display* frames (-> *display* on-screen) bucket-group)
(bucket-id bucket-310)
(bucket-id ocean-near)
s5-3
(the-as (pointer dma-tag) a3-5)
)
+2 -2
View File
@@ -33,7 +33,7 @@
(bucket-3 3) ;; blit displays
(tex-lcom-sky-pre 4) ;; tex
(sky-draw 5) ;; sky
(bucket-6 6) ;; ocean
(ocean-mid-far 6) ;; ocean
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; All levels with tfrag tpage
@@ -389,7 +389,7 @@
(tex-lcom-sky-post 309)
(bucket-310 310) ;; ocean
(ocean-near 310) ;; ocean
(bucket-311 311) ;; depth-cue
(tex-all-sprite 312)
+6 -2
View File
@@ -1485,7 +1485,7 @@
)
(dma-bucket-insert-tag
(-> *display* frames (-> *display* on-screen) bucket-group)
(bucket-id bucket-6)
(bucket-id ocean-mid-far)
s5-2
(the-as (pointer dma-tag) a3-3)
)
@@ -1511,7 +1511,7 @@
)
(dma-bucket-insert-tag
(-> *display* frames (-> *display* on-screen) bucket-group)
(bucket-id bucket-310)
(bucket-id ocean-near)
s5-3
(the-as (pointer dma-tag) a3-5)
)
@@ -1613,3 +1613,7 @@
;; definition (debug) for function test-to-from-spr
;; ERROR: function was not converted to expressions. Cannot decompile.