diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index b8a08e5f73..00309d7302 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -106,11 +106,8 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/Sprite3.cpp graphics/opengl_renderer/SpriteRenderer.cpp graphics/opengl_renderer/TextureUploadHandler.cpp - graphics/opengl_renderer/tfrag/BufferedRenderer.cpp - graphics/opengl_renderer/tfrag/program6_cpu.cpp graphics/opengl_renderer/tfrag/Tfrag3.cpp graphics/opengl_renderer/tfrag/tfrag_common.cpp - graphics/opengl_renderer/tfrag/tfrag_unpack.cpp graphics/opengl_renderer/tfrag/TFragment.cpp graphics/opengl_renderer/tfrag/Tie3.cpp graphics/texture/TextureConverter.cpp diff --git a/game/graphics/opengl_renderer/Loader.cpp b/game/graphics/opengl_renderer/Loader.cpp index 19c8bcc6ce..dca26f2fa1 100644 --- a/game/graphics/opengl_renderer/Loader.cpp +++ b/game/graphics/opengl_renderer/Loader.cpp @@ -13,11 +13,11 @@ std::string uppercase_string(const std::string& s) { } } // namespace -tfrag3::Level* Loader::get_tfrag3_level(const std::string& level_name) { +const Loader::LevelData* Loader::get_tfrag3_level(const std::string& level_name) { std::unique_lock lk(m_loader_mutex); - const auto& existing = m_tfrag3_levels.find(level_name); - if (existing == m_tfrag3_levels.end()) { - if (m_level_to_load.empty()) { + const auto& existing = m_loaded_tfrag3_levels.find(level_name); + if (existing == m_loaded_tfrag3_levels.end()) { + if (m_level_to_load.empty() && m_initializing_tfrag3_levels.count(level_name) == 0) { fmt::print("[pc loader] starting load for {}\n", level_name); m_level_to_load = level_name; lk.unlock(); @@ -28,7 +28,7 @@ tfrag3::Level* Loader::get_tfrag3_level(const std::string& level_name) { } } else { existing->second.frames_since_last_used = 0; - return existing->second.level.get(); + return &existing->second.data; } } @@ -60,8 +60,8 @@ void Loader::loader_thread() { disk_load_time, import_time, decomp_time); lk.lock(); + m_initializing_tfrag3_levels[lev].data.level = std::move(result); m_level_to_load = ""; - m_tfrag3_levels[lev].level = std::move(result); } } @@ -69,6 +69,79 @@ Loader::Loader() { m_loader_thread = std::thread(&Loader::loader_thread, this); } +void Loader::update() { + Timer loader_timer; + + // only main thread can touch this. + for (auto& lev : m_loaded_tfrag3_levels) { + lev.second.frames_since_last_used++; + } + + bool did_gpu_stuff = false; + + { + // try to move level from initializing to initialized: + std::unique_lock lk(m_loader_mutex); + const auto& it = m_initializing_tfrag3_levels.begin(); + if (it != m_initializing_tfrag3_levels.end()) { + did_gpu_stuff = true; + constexpr int MAX_TEX_BYTES_PER_FRAME = 1024 * 1024; + auto& data = it->second.data; + + int bytes_this_run = 0; + while (data.textures.size() < data.level->textures.size()) { + auto& tex = data.level->textures[data.textures.size()]; + GLuint gl_tex; + glGenTextures(1, &gl_tex); + glBindTexture(GL_TEXTURE_2D, gl_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.w, tex.h, 0, GL_RGBA, + GL_UNSIGNED_INT_8_8_8_8_REV, tex.data.data()); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, gl_tex); + glGenerateMipmap(GL_TEXTURE_2D); + + float aniso = 0.0f; + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &aniso); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso); + it->second.data.textures.push_back(gl_tex); + bytes_this_run += tex.w * tex.h * 4; + if (bytes_this_run > MAX_TEX_BYTES_PER_FRAME) { + break; + } + } + if (data.textures.size() == data.level->textures.size()) { + fmt::print("Loader texture complete: {}\n", it->first); + it->second.data.load_id = m_id++; + + m_loaded_tfrag3_levels[it->first] = std::move(it->second); + m_initializing_tfrag3_levels.erase(it); + } + } + } + + if (!did_gpu_stuff) { + // try to remove levels. + if (m_loaded_tfrag3_levels.size() >= 3) { + for (const auto& lev : m_loaded_tfrag3_levels) { + if (lev.second.frames_since_last_used > 180) { + fmt::print("------------------------- PC unloading {}\n", lev.first); + for (auto tex : lev.second.data.textures) { + glBindTexture(GL_TEXTURE_2D, tex); + glDeleteTextures(1, &tex); + } + m_loaded_tfrag3_levels.erase(lev.first); + break; + } + } + } + } + + if (loader_timer.getMs() > 5) { + fmt::print("Loader::update slow setup: {:.1f}ms\n", loader_timer.getMs()); + } +} + Loader::~Loader() { { std::lock_guard lk(m_loader_mutex); @@ -76,4 +149,15 @@ Loader::~Loader() { m_loader_cv.notify_all(); } m_loader_thread.join(); +} + +void Loader::hack_scramble_textures() { + for (auto& it : m_loaded_tfrag3_levels) { + int n = it.second.data.textures.size(); + for (int i = 0; i < n; i++) { + int a = rand() % n; + int b = rand() % n; + std::swap(it.second.data.textures[a], it.second.data.textures[b]); + } + } } \ No newline at end of file diff --git a/game/graphics/opengl_renderer/Loader.h b/game/graphics/opengl_renderer/Loader.h index b1f4d3e9d0..f9c273c209 100644 --- a/game/graphics/opengl_renderer/Loader.h +++ b/game/graphics/opengl_renderer/Loader.h @@ -4,27 +4,41 @@ #include #include +#include "game/graphics/pipelines/opengl.h" + #include "common/custom_data/Tfrag3Data.h" class Loader { public: Loader(); ~Loader(); - tfrag3::Level* get_tfrag3_level(const std::string& level_name); + void update(); + + struct LevelData { + std::unique_ptr level; + std::vector textures; + u64 load_id = 0; + }; + + const LevelData* get_tfrag3_level(const std::string& level_name); + void hack_scramble_textures(); private: struct Level { - std::unique_ptr level; + LevelData data; int frames_since_last_used = 0; }; void loader_thread(); - std::unordered_map m_tfrag3_levels; + std::unordered_map m_loaded_tfrag3_levels; + std::unordered_map m_initializing_tfrag3_levels; + std::string m_level_to_load; std::thread m_loader_thread; std::mutex m_loader_mutex; std::condition_variable m_loader_cv; bool m_want_shutdown = false; + uint64_t m_id = 0; }; diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index eefb8aa419..c8ab07e66e 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -165,6 +165,8 @@ void OpenGLRenderer::render(DmaFollower dma, const RenderOptions& settings) { finish_screenshot(settings.screenshot_path, settings.window_width_px, settings.window_height_px, settings.lbox_width_px, settings.lbox_height_px); } + + m_render_state.loader.update(); } void OpenGLRenderer::serialize(Serializer& ser) { diff --git a/game/graphics/opengl_renderer/tfrag/BufferedRenderer.cpp b/game/graphics/opengl_renderer/tfrag/BufferedRenderer.cpp deleted file mode 100644 index 794be878f5..0000000000 --- a/game/graphics/opengl_renderer/tfrag/BufferedRenderer.cpp +++ /dev/null @@ -1,664 +0,0 @@ -#include "BufferedRenderer.h" -#include "common/dma/gs.h" -#include "third-party/imgui/imgui.h" -#include "game/graphics/pipelines/opengl.h" - -namespace BufferedRenderer { - -Renderer::Renderer(BucketId my_id) : m_my_id(my_id) { - glGenBuffers(1, &m_ogl.vertex_buffer); - glGenBuffers(1, &m_ogl.index_buffer); - glGenVertexArrays(1, &m_ogl.vao); - - // these are some big buffers - glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - m_ogl.vertex_buffer_size = MAX_VERTS; - glBufferData(GL_ARRAY_BUFFER, m_ogl.vertex_buffer_size * sizeof(Vertex), nullptr, - GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer); - m_ogl.index_buffer_size = MAX_VERTS * 3; - glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer_size * sizeof(u32), nullptr, - GL_DYNAMIC_DRAW); -} - -Renderer::~Renderer() { - glDeleteBuffers(1, &m_ogl.vertex_buffer); - glDeleteBuffers(1, &m_ogl.index_buffer); - glDeleteVertexArrays(1, &m_ogl.vao); -} - -void Renderer::render_list(const DrawList& list, - SharedRenderState* render_state, - ScopedProfilerNode& prof, - const std::vector& vertices) { - // first, load primitive buffer - glBindVertexArray(m_ogl.vao); - u32 vert_count = std::min((int)vertices.size(), (int)m_ogl.vertex_buffer_size); - if (vertices.size() > m_ogl.vertex_buffer_size) { - fmt::print("TOO MANY VERTICES: {} / {}\n", vertices.size(), m_ogl.vertex_buffer_size); - assert(false); - } - - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - glEnableVertexAttribArray(3); - - glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - glBufferSubData(GL_ARRAY_BUFFER, 0, vert_count * sizeof(Vertex), vertices.data()); - - glVertexAttribPointer(0, // location 0 in the shader - 3, // 3 values per vert - GL_UNSIGNED_INT, // u32's - GL_TRUE, // normalized - sizeof(Vertex), // stride - (void*)offsetof(Vertex, xyz) // offset (0) - ); - - glVertexAttribPointer(1, // location 1 in the shader - 4, // 4 values per vert - GL_UNSIGNED_BYTE, // u8's - GL_TRUE, // normalized - sizeof(Vertex), // stride - (void*)offsetof(Vertex, rgba) // offset (0) - ); - - glVertexAttribPointer(2, // location 2 in the shader - 3, // 3 values per vert - GL_FLOAT, // u32's - GL_FALSE, // normalized - sizeof(Vertex), // stride - (void*)offsetof(Vertex, st) // offset (0) - ); - - glActiveTexture(GL_TEXTURE0); - - for (auto& group : list.groups) { - if (group.tbp != UINT16_MAX) { - render_group(group, render_state, prof, vertices); - } - } - - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(2); - - glBindVertexArray(0); -} - -void Renderer::setup_opengl_excluding_textures(SharedRenderState* render_state, DrawMode mode) { - if (mode.get_depth_write_enable()) { - glDepthMask(GL_TRUE); - } else { - glDepthMask(GL_FALSE); - } - - if (mode.get_zt_enable()) { - glEnable(GL_DEPTH_TEST); - switch (mode.get_depth_test()) { - case GsTest::ZTest::NEVER: - glDepthFunc(GL_NEVER); - break; - case GsTest::ZTest::ALWAYS: - glDepthFunc(GL_ALWAYS); - break; - case GsTest::ZTest::GEQUAL: - glDepthFunc(GL_GEQUAL); - break; - case GsTest::ZTest::GREATER: - glDepthFunc(GL_GREATER); - break; - default: - assert(false); - } - } else { - glDisable(GL_DEPTH_TEST); - } - - if (mode.get_ab_enable() && mode.get_alpha_blend() != DrawMode::AlphaBlend::DISABLED) { - glEnable(GL_BLEND); - switch (mode.get_alpha_blend()) { - case DrawMode::AlphaBlend::SRC_DST_SRC_DST: - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case DrawMode::AlphaBlend::SRC_0_SRC_DST: - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - default: - assert(false); - } - } else { - glDisable(GL_BLEND); - } - - if (mode.get_clamp_s_enable()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - } - - if (mode.get_clamp_t_enable()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - if (mode.get_filt_enable()) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - float alpha_reject = 0.; - if (mode.get_at_enable()) { - switch (mode.get_alpha_test()) { - case DrawMode::AlphaTest::ALWAYS: - break; - case DrawMode::AlphaTest::GEQUAL: - alpha_reject = mode.get_aref() / 127.f; - break; - case DrawMode::AlphaTest::NEVER: - break; - default: - assert(false); - } - } - - // todo check afail - - if (mode.get_tcc_enable()) { - render_state->shaders[ShaderId::BUFFERED_TCC1].activate(); - glUniform1f( - glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC1].id(), "alpha_reject"), - alpha_reject); - glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC1].id(), "T0"), 0); - } else { - fmt::print("tcc off!\n"); - render_state->shaders[ShaderId::BUFFERED_TCC0].activate(); - glUniform1f( - glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC0].id(), "alpha_reject"), - alpha_reject); - glUniform1i(glGetUniformLocation(render_state->shaders[ShaderId::BUFFERED_TCC0].id(), "T0"), 0); - } -} - -void Renderer::render_group(const DrawGroup& group, - SharedRenderState* render_state, - ScopedProfilerNode& prof, - const std::vector& /*vertices*/) { - TextureRecord* tex = nullptr; - - tex = render_state->texture_pool->lookup(group.tbp); - - if (!tex) { - fmt::print("Failed to find texture at {}, using random\n", group.tbp); - tex = render_state->texture_pool->get_random_texture(); - } - assert(tex); - - // first: do we need to load the texture? - if (!tex->on_gpu) { - render_state->texture_pool->upload_to_gpu(tex); - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, tex->gpu_texture); - - for (auto& draw : group.draws) { - if (draw.mode.is_valid()) { - m_stats.draw_calls++; - prof.add_draw_call(); - prof.add_tri(draw.triangles.size()); - render_state->shaders[ShaderId::DEBUG_BUFFERED].activate(); - setup_opengl_excluding_textures(render_state, draw.mode); - // check for overflows. - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ogl.index_buffer); - if (draw.triangles.size() * 3 > m_ogl.index_buffer_size) { - fmt::format("TOO MANY TRIS: {}/{}\n", draw.triangles.size() * 3, m_ogl.index_buffer_size); - assert(false); - } - - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, draw.triangles.size() * sizeof(u32) * 3, - draw.triangles.data()); - glDrawElements(GL_TRIANGLES, draw.triangles.size() * 3, GL_UNSIGNED_INT, (void*)0); - } - } -} - -void Renderer::draw_debug_window() { - // todo - ImGui::Text("draws: %d", m_stats.draw_calls); -} - -void Renderer::clear_stats() { - m_stats = {}; -} - -Builder::Builder(BucketId my_id) : m_my_id(my_id), m_renderer(my_id) {} - -void Builder::add_gif_data_sized(const void* data, u32 expected_size) { - if (expected_size != add_gif_data(data)) { - assert(false); // todo, might be too strict due to alignment crap - } -} - -void Builder::flush(SharedRenderState* render_state, ScopedProfilerNode& prof) { - m_renderer.render_list(m_list, render_state, prof, m_vertices); - m_list.clear(); - m_vertices.clear(); - m_cache = {}; -} - -void Builder::draw_debug_window() { - ImGui::Text("Builder: %d tri, %d vert", m_stats.m_tri, m_stats.m_dvert); - - ImGui::Text("Renderer:"); - ImGui::Separator(); - m_renderer.draw_debug_window(); -} - -void Builder::reset_state() { - m_current_mode.as_int() = 0; - m_stats = {}; - m_renderer.clear_stats(); - m_vertex_queue = {}; - m_current_mode.enable_depth_write(); - m_current_mode.enable_ab(); - m_current_mode.enable_at(); - m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST); -} - -u32 Builder::add_gif_data(const void* data_in) { - bool eop = false; - auto* data = (const u8*)data_in; - - u32 offset = 0; - while (!eop) { - GifTag tag(data + offset); - offset += 16; - - // unpack registers. - // faster to do it once outside of the nloop loop. - GifTag::RegisterDescriptor reg_desc[16]; - u32 nreg = tag.nreg(); - for (u32 i = 0; i < nreg; i++) { - reg_desc[i] = tag.reg(i); - } - - auto format = tag.flg(); - if (format == GifTag::Format::PACKED) { - if (tag.pre()) { - handle_prim(tag.prim()); - } - for (u32 loop = 0; loop < tag.nloop(); loop++) { - for (u32 reg = 0; reg < nreg; reg++) { - switch (reg_desc[reg]) { - case GifTag::RegisterDescriptor::AD: - handle_ad(data + offset); - break; - case GifTag::RegisterDescriptor::ST: - handle_st_packed(data + offset); - break; - case GifTag::RegisterDescriptor::RGBAQ: - handle_rgbaq_packed(data + offset); - break; - case GifTag::RegisterDescriptor::XYZF2: - handle_xyzf2_packed(data + offset); - break; - // case GifTag::RegisterDescriptor::PRIM: - // handle_prim_packed(data + offset, render_state, prof); - // break; - // case GifTag::RegisterDescriptor::TEX0_1: - // handle_tex0_1_packed(data + offset, render_state, prof); - // break; - default: - fmt::print("Register {} is not supported in packed mode of BufferedRenderer\n", - reg_descriptor_name(reg_desc[reg])); - assert(false); - } - offset += 16; // PACKED = quadwords - } - } - } else if (format == GifTag::Format::REGLIST) { - for (u32 loop = 0; loop < tag.nloop(); loop++) { - for (u32 reg = 0; reg < nreg; reg++) { - u64 register_data; - memcpy(®ister_data, data + offset, 8); - // fmt::print("loop: {} reg: {} {}\n", loop, reg, - // reg_descriptor_name(reg_desc[reg])); - switch (reg_desc[reg]) { - // case GifTag::RegisterDescriptor::PRIM: - // handle_prim(register_data, render_state, prof); - // break; - // case GifTag::RegisterDescriptor::RGBAQ: - // handle_rgbaq(register_data); - // break; - // case GifTag::RegisterDescriptor::XYZF2: - // handle_xyzf2(register_data, render_state, prof); - // break; - default: - fmt::print("Register {} is not supported in reglist mode of BufferedRenderer\n", - reg_descriptor_name(reg_desc[reg])); - assert(false); - } - offset += 8; // PACKED = quadwords - } - } - } else { - assert(false); // format not packed or reglist. - } - - eop = tag.eop(); - } - return offset; -} - -void Builder::handle_ad(const u8* data) { - u64 value; - GsRegisterAddress addr; - memcpy(&value, data, sizeof(u64)); - memcpy(&addr, data + 8, sizeof(GsRegisterAddress)); - - switch (addr) { - // case GsRegisterAddress::ZBUF_1: - // handle_zbuf1(value, render_state, prof); - // break; - case GsRegisterAddress::TEST_1: - handle_test1(value); - break; - case GsRegisterAddress::ALPHA_1: - handle_alpha1(value); - break; - // case GsRegisterAddress::PABE: - // handle_pabe(value); - break; - case GsRegisterAddress::CLAMP_1: - handle_clamp1(value); - break; - // case GsRegisterAddress::PRIM: - // handle_prim(value, render_state, prof); - // break; - // - case GsRegisterAddress::TEX1_1: - handle_tex1_1(value); - break; - // case GsRegisterAddress::TEXA: - // handle_texa(value); - // break; - // case GsRegisterAddress::TEXCLUT: - // // TODO - // // the only thing the direct renderer does with texture is font, which does no tricks - // with - // // CLUT. The texture upload process will do all of the lookups with the default CLUT. - // // So we'll just assume that the TEXCLUT is set properly and ignore this. - // break; - // case GsRegisterAddress::FOGCOL: - // // TODO - // break; - case GsRegisterAddress::TEX0_1: - handle_tex0_1(value); - break; - case GsRegisterAddress::MIPTBP1_1: - case GsRegisterAddress::MIPTBP2_1: - // this has the address of different mip levels, we can just ignore it. - break; - // case GsRegisterAddress::TEXFLUSH: - // break; - default: - fmt::print("Address {} is not supported in ad of BufferedRenderer\n", - register_address_name(addr)); - assert(false); - } -} - -void Builder::handle_test1(u64 val) { - // ate, atst, aref, afail, date, datm, zte, ztest - GsTest test(val); - - // ATE - m_current_mode.set_at(test.alpha_test_enable()); - - // ATST - switch (test.alpha_test()) { - case GsTest::AlphaTest::ALWAYS: - m_current_mode.set_alpha_test(DrawMode::AlphaTest::ALWAYS); - break; - case GsTest::AlphaTest::GEQUAL: - m_current_mode.set_alpha_test(DrawMode::AlphaTest::GEQUAL); - break; - case GsTest::AlphaTest::NEVER: - m_current_mode.set_alpha_test(DrawMode::AlphaTest::NEVER); - break; - default: - fmt::print("Alpha test: {} not supported\n", (int)test.alpha_test()); - assert(false); - } - - // AREF - m_current_mode.set_aref(test.aref()); - - // AFAIL - m_current_mode.set_alpha_fail(test.afail()); - - // DATE - assert(test.date() == false); - - // DATM - // who cares, if date is off - - // ZTE - m_current_mode.set_zt(test.zte()); - - // ZTST - m_current_mode.set_depth_test(test.ztest()); -} - -void Builder::handle_tex0_1(u64 val) { - GsTex0 reg(val); - - // TBP0 - m_current_tbp = reg.tbp0(); - - // TBW - // assume it's right - - // PSM - assert(reg.psm() != GsTex0::PSM::PSMT4HH); // not supported in buffered yet. - - // TW, TH - // assume it's right - - // TCC - m_current_mode.set_tcc(reg.tcc()); - - // TFX - assert(reg.tfx() == GsTex0::TextureFunction::MODULATE); - - // CBP, CPSM, CSM - // assume it's right -} - -void Builder::handle_tex1_1(u64 val) { - GsTex1 reg(val); - // ignoring these and doing our own thing! - // just need to pick between filtering and not filtering. - m_current_mode.set_filt_enable(reg.mmag()); -} - -void Builder::handle_clamp1(u64 val) { - // check that we got one of the expected ones - if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) { - fmt::print("clamp: 0x{:x}\n", val); - assert(false); - } - - m_current_mode.set_clamp_s_enable(val & 0b1); - m_current_mode.set_clamp_t_enable(val & 0b100); -} - -void Builder::handle_alpha1(u64 val) { - GsAlpha reg(val); - if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && reg.b_mode() == GsAlpha::BlendMode::DEST && - reg.c_mode() == GsAlpha::BlendMode::SOURCE && reg.d_mode() == GsAlpha::BlendMode::DEST) { - // (Cs - Cd) * As + Cd - // Cs * As + (1 - As) * Cd - m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_DST_SRC_DST); - - } else if (reg.a_mode() == GsAlpha::BlendMode::SOURCE && - reg.b_mode() == GsAlpha::BlendMode::ZERO_OR_FIXED && - reg.c_mode() == GsAlpha::BlendMode::SOURCE && - reg.d_mode() == GsAlpha::BlendMode::DEST) { - // (Cs - 0) * As + Cd - // Cs * As + (1) * CD - m_current_mode.set_alpha_blend(DrawMode::AlphaBlend::SRC_0_SRC_DST); - } else { - // unsupported blend: a 0 b 2 c 2 d 1 - fmt::print("unsupported blend: a {} b {} c {} d {}\n", (int)reg.a_mode(), (int)reg.b_mode(), - (int)reg.c_mode(), (int)reg.d_mode()); - assert(false); - } -} - -void Builder::handle_prim(u64 val) { - GsPrim prim(val); - - // PRIM - m_prim_kind = prim.kind(); - - // IIP - assert(prim.gouraud()); - - // TME - assert(prim.tme()); - - // FGE - // TODO fog - - // ABE - m_current_mode.set_ab(prim.abe()); - - // AA1 - assert(!prim.aa1()); - - // FST - assert(!prim.fst()); - - // CTXT - assert(!prim.ctxt()); - - // FIX - assert(!prim.fix()); - - if (m_vertex_queue.startup) { - m_vertex_queue.startup = 0; - m_vertex_queue.idx = 0; - } else { - // assert(false); - } -} - -void Builder::handle_st_packed(const u8* data) { - memcpy(m_st_pending_q, data, 3 * sizeof(float)); -} - -void Builder::handle_rgbaq_packed(const u8* data) { - m_q = m_st_pending_q[2]; - // memcpy(m_rgba.data(), data, 4); - m_rgba[0] = data[0]; - m_rgba[1] = data[4]; - m_rgba[2] = data[8]; - m_rgba[3] = data[12]; -} - -void Builder::handle_xyzf2_packed(const u8* data) { - u32 x, y; - memcpy(&x, data, 4); - memcpy(&y, data + 4, 4); - - u64 upper; - memcpy(&upper, data + 8, 8); - u32 z = (upper >> 4) & 0xffffff; - - u8 f = (upper >> 36); - bool adc = upper & (1ull << 47); - handle_xyzf2_common(x, y, z, f, !adc); -} - -void Builder::handle_xyzf2_common(u32 x, u32 y, u32 z, u8 /*f*/, bool advance) { - // first, create a vertex: - u32 new_vertex = create_vertex_now(x, y, z); - - // next, add that vertex. This will inform us if we actually draw a prim or not - bool new_prim = false; - switch (m_prim_kind) { - case GsPrim::Kind::TRI_STRIP: - new_prim = handle_tri_strip_add(new_vertex, advance); - break; - default: - assert(false); - } - - if (new_prim) { - // todo, winding order? - add_prim_now({m_vertex_queue.verts[0], m_vertex_queue.verts[1], m_vertex_queue.verts[2]}); - } -} - -void Builder::add_prim_now(Triangle tri) { - if (m_cache.last_tbp == m_current_tbp && m_cache.last_mode == m_current_mode.as_int()) { - m_cache.draw->triangles.push_back(tri); - } else { - auto group = m_list.get_group_for_tbp(m_current_tbp); - assert(group); - // todo flush and stats - - auto draw = group->get_draw_for_mode(m_current_mode); - assert(draw); - // todo flush and stats - draw->triangles.push_back(tri); - m_cache.last_mode = m_current_mode.as_int(); - m_cache.last_tbp = m_current_tbp; - m_cache.draw = draw; - } - - m_stats.m_tri++; -} - -u32 Builder::create_vertex_now(u32 x, u32 y, u32 z) { - m_stats.m_dvert++; - u32 idx = m_vertices.size(); - m_vertices.emplace_back(); - auto& vert = m_vertices.back(); - vert.xyz = math::Vector(x << 16, y << 16, z << 8); - vert.rgba = m_rgba; - vert.st = math::Vector(m_st_pending_q[0], m_st_pending_q[1]); - vert.q = m_q; - return idx; -} - -bool Builder::handle_tri_strip_add(u32 new_vertex, bool advance) { - m_vertex_queue.verts[m_vertex_queue.idx] = new_vertex; - m_vertex_queue.idx++; - - // wrap the index - if (m_vertex_queue.idx == 3) { - m_vertex_queue.idx = 0; - } - - // bump the startup - if (m_vertex_queue.startup < 3) { - m_vertex_queue.startup++; - } - - if (m_vertex_queue.startup >= 3) { - if (advance) { - return true; - } - } - return false; -} - -} // namespace BufferedRenderer diff --git a/game/graphics/opengl_renderer/tfrag/BufferedRenderer.h b/game/graphics/opengl_renderer/tfrag/BufferedRenderer.h deleted file mode 100644 index fc73012b47..0000000000 --- a/game/graphics/opengl_renderer/tfrag/BufferedRenderer.h +++ /dev/null @@ -1,219 +0,0 @@ -#pragma once -#include "common/math/Vector.h" -#include "common/common_types.h" -#include "game/graphics/opengl_renderer/BucketRenderer.h" -#include "common/dma/gs.h" -#include "game/graphics/pipelines/opengl.h" - -namespace BufferedRenderer { - -// The buffered renderer performs efficient sorting of primitives to reduce draw calls. - -// the settings: - -// this is the maximum number of draw "kinds" we can have per textures. -// a draw is a different "kind" if any opengl state changes happen (like z test, etc) -// if this is exceeded, this will return an error code. -// you must flush the group, then try adding it again. -// making this too large will slow down insertion and increase memory usage -constexpr int MAX_DRAW_KINDS_PER_TEX = 4; - -// this is the maximum number of textures. If this is exceeded, there will be an error like above. -constexpr int MAX_TEXTURES = 256; - -// this is the PS2 maximum TBP value. -constexpr int MAX_TBP = 16384; - -// 32-byte vertex. -// the xyz, rgba, and stq are aligned. we have a free 4-bytes at the end. -// there is a single big pool of vertices. -struct Vertex { - math::Vector xyz; // ps2 coords (0) - math::Vector rgba; // 0, 4 (1) - math::Vector st; // (2) - float q; // (3) - u32 pad; -}; -static_assert(sizeof(Vertex) == 32); - -// a triangle grabs three vertices from the pools. -struct Triangle { - u32 verts[3]; -}; - -struct Draw { - DrawMode mode; - std::vector triangles; // just indices - void clear() { - mode.set_invalid(); - triangles.clear(); - } -}; - -struct DrawGroup { - Draw draws[MAX_DRAW_KINDS_PER_TEX]; - u16 tbp = UINT16_MAX; - - // can fail, in which case you should flush the DrawGroup. - Draw* get_draw_for_mode(DrawMode mode) { - for (auto& draw : draws) { - if (draw.mode.is_invalid()) { - draw.mode = mode; - return &draw; - } else if (draw.mode == mode) { - return &draw; - } - } - return nullptr; - } - - void clear() { - for (auto& draw : draws) { - draw.clear(); - tbp = UINT16_MAX; - } - } -}; - -struct DrawList { - DrawGroup groups[MAX_TEXTURES]; - u16 tbp_to_tex_id[MAX_TBP]; - u16 current_tex_id = 0; - - DrawList() { - for (auto& x : tbp_to_tex_id) { - x = UINT16_MAX; - } - } - - void clear() { - for (auto& group : groups) { - group.clear(); - } - for (auto& x : tbp_to_tex_id) { - x = UINT16_MAX; - } - current_tex_id = 0; - } - - DrawGroup* get_group_for_tbp(u16 tbp) { - if (tbp_to_tex_id[tbp] != UINT16_MAX) { - // already have it - return &groups[tbp_to_tex_id[tbp]]; - } else { - if (current_tex_id == MAX_TEXTURES) { - // don't have it, and out of room - return nullptr; - } else { - // don't have it, but we can add it. - auto group = &groups[current_tex_id]; - group->tbp = tbp; - tbp_to_tex_id[tbp] = current_tex_id; - current_tex_id++; - return group; - } - } - } -}; - -class Renderer { - public: - Renderer(BucketId my_id); - ~Renderer(); - void render_list(const DrawList& list, - SharedRenderState* render_state, - ScopedProfilerNode& prof, - const std::vector& vertices); - void render_group(const DrawGroup& group, - SharedRenderState* render_state, - ScopedProfilerNode& prof, - const std::vector& vertices); - - void setup_opengl_excluding_textures(SharedRenderState* render_state, DrawMode mode); - - void draw_debug_window(); - void clear_stats(); - BucketId my_id() const { return m_my_id; } - - private: - static constexpr int MAX_VERTS = 400000; - BucketId m_my_id; - - struct { - int triangles = 0; - int draw_calls = 0; - int groups = 0; - } m_stats; - - struct { - GLuint vertex_buffer = -1; - u32 vertex_buffer_size = 0; - GLuint index_buffer = -1; - u32 index_buffer_size = 0; - GLuint vao = -1; - } m_ogl; -}; - -class Builder { - public: - Builder(BucketId my_id); - u32 add_gif_data(const void* data); - void add_gif_data_sized(const void* data, u32 expected_size); - void flush(SharedRenderState* render_state, ScopedProfilerNode& prof); - void draw_debug_window(); - void reset_state(); - - private: - void handle_ad(const u8* data); - void handle_test1(u64 val); - void handle_tex0_1(u64 val); - void handle_tex1_1(u64 val); - void handle_clamp1(u64 val); - void handle_prim(u64 val); - void handle_alpha1(u64 val); - - void handle_st_packed(const u8* data); - void handle_rgbaq_packed(const u8* data); - void handle_xyzf2_packed(const u8* data); - void handle_xyzf2_common(u32 x, u32 y, u32 z, u8 f, bool advance); - bool handle_tri_strip_add(u32 new_vertex, bool advance); - void add_prim_now(Triangle tri); - - u32 create_vertex_now(u32 x, u32 y, u32 z); - BucketId my_id() const { return m_my_id; } - - BucketId m_my_id; - - DrawList m_list; - Renderer m_renderer; - DrawMode m_current_mode; - u16 m_current_tbp = 0; - - GsPrim::Kind m_prim_kind = GsPrim::Kind::PRIM_7; - - std::vector m_vertices; - - float m_st_pending_q[3] = {0}; // q goes to real q on rgbaq packed - float m_q = 0; - math::Vector m_rgba; - - // todo maybe add a mode cache? - - struct { - u32 idx = 0; - u32 startup = 0; - u32 verts[3] = {0, 0, 0}; - } m_vertex_queue; - - struct { - u32 m_dvert = 0; - u32 m_tri = 0; - } m_stats; - - struct { - u32 last_tbp = UINT32_MAX; - u32 last_mode = UINT32_MAX; - Draw* draw = nullptr; - } m_cache; -}; -} // namespace BufferedRenderer diff --git a/game/graphics/opengl_renderer/tfrag/TFragment.cpp b/game/graphics/opengl_renderer/tfrag/TFragment.cpp index b6c6611668..15c25af4f3 100644 --- a/game/graphics/opengl_renderer/tfrag/TFragment.cpp +++ b/game/graphics/opengl_renderer/tfrag/TFragment.cpp @@ -22,8 +22,6 @@ TFragment::TFragment(const std::string& name, int level_id) : BucketRenderer(name, my_id), m_child_mode(child_mode), - m_direct_renderer(fmt::format("{}.direct", name), my_id, 1024, DirectRenderer::Mode::NORMAL), - m_buffered_renderer(my_id), m_tree_kinds(trees), m_level_id(level_id) { for (auto& buf : m_buffered_data) { @@ -31,10 +29,6 @@ TFragment::TFragment(const std::string& name, x = 0xff; } } - - for (auto& x : m_kick_data.pad) { - x = 0; - } } constexpr const char* level_names[] = {"bea", "cit", "dar", "fin", "int", "jub", "jun", "fic", @@ -45,14 +39,6 @@ void TFragment::render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) { m_debug_string.clear(); - m_frag_debug.clear(); - if (m_use_buffered_renderer) { - m_buffered_renderer.reset_state(); - } else { - m_direct_renderer.reset_state(); - } - - m_stats = {}; if (!m_enabled) { while (dma.current_tag_offset() != render_state->next_bucket) { @@ -110,30 +96,26 @@ void TFragment::render(DmaFollower& dma, return; } - if (m_extra_debug) { - ImGui::Begin(fmt::format("{} extra", m_name).c_str()); - } - - if (m_use_tfrag3) { - std::string level_name; - while (looks_like_tfrag_init(dma)) { - handle_initialization(dma, render_state, prof); - if (level_name.empty()) { - level_name = m_pc_port_data.level_name; - } else if (level_name != m_pc_port_data.level_name) { - assert(false); - } - - while (looks_like_tfragment_dma(dma)) { - dma.read_and_advance(); - } + std::string level_name; + while (looks_like_tfrag_init(dma)) { + handle_initialization(dma); + if (level_name.empty()) { + level_name = m_pc_port_data.level_name; + } else if (level_name != m_pc_port_data.level_name) { + assert(false); } - while (dma.current_tag_offset() != render_state->next_bucket) { + while (looks_like_tfragment_dma(dma)) { dma.read_and_advance(); } + } - assert(!level_name.empty()); + while (dma.current_tag_offset() != render_state->next_bucket) { + dma.read_and_advance(); + } + + assert(!level_name.empty()); + { m_tfrag3.setup_for_level(m_tree_kinds, level_name, render_state); TfragRenderSettings settings; settings.hvdf_offset = m_tfrag_data.hvdf_offset; @@ -164,50 +146,10 @@ void TFragment::render(DmaFollower& dma, auto t3prof = prof.make_scoped_child("t3"); m_tfrag3.render_matching_trees(m_tree_kinds, settings, render_state, t3prof); - - } else { - while (looks_like_tfrag_init(dma)) { - m_debug_string += "------------- START!\n"; - handle_initialization(dma, render_state, prof); - int count = 0; - // fmt::print("---------------------------------------START\n"); - - while (looks_like_tfragment_dma(dma)) { - m_stats.tfrag_dma_packets++; - auto frag = dma.read_and_advance(); - m_stats.tfrag_bytes += frag.size_bytes; - - if (m_extra_debug) { - handle_tfrag(frag, render_state, prof); - } else { - handle_tfrag(frag, render_state, prof); - } - if (m_max_draw >= 0 && count++ > m_max_draw) { - break; - } - } - - if (dma.current_tag().qwc == 3) { - dma.read_and_advance(); - } - if (dma.current_tag().qwc == 0) { - dma.read_and_advance(); - } - } - } - - if (m_extra_debug) { - ImGui::End(); } m_debug_string += fmt::format("fail: {}\n", dma.current_tag().print()); - if (m_use_buffered_renderer) { - m_buffered_renderer.flush(render_state, prof); - } else { - m_direct_renderer.flush_pending(render_state, prof); - } - while (dma.current_tag_offset() != render_state->next_bucket) { auto tag = dma.current_tag().print(); auto data = dma.read_and_advance(); @@ -250,15 +192,16 @@ void TFragment::render(DmaFollower& dma, } } } + + if (m_hack_scrambler) { + render_state->loader.hack_scramble_textures(); + m_hack_scrambler = false; + } } void TFragment::draw_debug_window() { - ImGui::Separator(); - ImGui::Checkbox("Extra Debug", &m_extra_debug); - ImGui::InputInt("Max Draw", &m_max_draw); - ImGui::SameLine(); - if (ImGui::Button("All")) { - m_max_draw = -1; + if (ImGui::Button("Scrambler")) { + m_hack_scrambler = true; } ImGui::Checkbox("Manual Time of Day", &m_override_time_of_day); if (m_override_time_of_day) { @@ -274,41 +217,12 @@ void TFragment::draw_debug_window() { } } - ImGui::Checkbox("Use TFRAG3", &m_use_tfrag3); - if (!m_use_tfrag3) { - ImGui::Checkbox("Use Buffered Renderer", &m_use_buffered_renderer); - ImGui::Checkbox("Skip MSCAL", &m_skip_mscals); - ImGui::Checkbox("Skip XGKICK", &m_skip_xgkick); - ImGui::Checkbox("Prog8 hack", &m_prog8_with_prog6); - ImGui::Checkbox("Prog10 hack", &m_prog10_with_prog6); - ImGui::Checkbox("Prog18 hack", &m_prog18_with_prog6); - ImGui::Checkbox("Others with prog6", &m_all_with_prog6); - ImGui::Text("packets: %d", m_stats.tfrag_dma_packets); - ImGui::Text("frag bytes: %d", m_stats.tfrag_bytes); - ImGui::Text("errors: %d", m_stats.error_packets); - for (int prog = 0; prog < 12; prog++) { - ImGui::Text(" prog %d: %d calls\n", prog, m_stats.per_program[prog].calls); - } - - if (!m_use_buffered_renderer && ImGui::TreeNode("direct")) { - m_direct_renderer.draw_debug_window(); - ImGui::TreePop(); - } - - if (m_use_buffered_renderer && ImGui::TreeNode("buffered")) { - m_buffered_renderer.draw_debug_window(); - ImGui::TreePop(); - } - } else { - m_tfrag3.draw_debug_window(); - } + m_tfrag3.draw_debug_window(); ImGui::TextUnformatted(m_debug_string.data()); } -void TFragment::handle_initialization(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { +void TFragment::handle_initialization(DmaFollower& dma) { // Set up test (different between different renderers) auto setup_test = dma.read_and_advance(); assert(setup_test.vif0() == 0); @@ -316,23 +230,16 @@ void TFragment::handle_initialization(DmaFollower& dma, assert(setup_test.vifcode1().immediate == 2); assert(setup_test.size_bytes == 32); memcpy(m_test_setup, setup_test.data, 32); - if (m_use_buffered_renderer) { - m_buffered_renderer.add_gif_data_sized(m_test_setup, 32); - } else { - m_direct_renderer.render_gif(m_test_setup, 32, render_state, prof); - } // matrix 0 auto mat0_upload = dma.read_and_advance(); unpack_to_stcycl(&m_buffered_data[0].pad[TFragDataMem::TFragMatrix0 * 16], mat0_upload, VifCode::Kind::UNPACK_V4_32, 4, 4, 64, TFragDataMem::TFragMatrix0, false, false); - m_debug_string += fmt::format("Matrix 0:\n {}\n", m_matrix_0.to_string_aligned()); // matrix 1 auto mat1_upload = dma.read_and_advance(); unpack_to_stcycl(&m_buffered_data[1].pad[TFragDataMem::TFragMatrix0 * 16], mat1_upload, VifCode::Kind::UNPACK_V4_32, 4, 4, 64, TFragDataMem::TFragMatrix1, false, false); - m_debug_string += fmt::format("Matrix 1:\n {}\n", m_matrix_1.to_string_aligned()); // data auto data_upload = dma.read_and_advance(); @@ -344,21 +251,6 @@ void TFragment::handle_initialization(DmaFollower& dma, auto mscal_setup = dma.read_and_advance(); verify_mscal(mscal_setup, TFragProgMem::TFragSetup); - // iaddiu vi14, vi00, 0x2a0 | nop - m_ptrs.vi14 = 0x2a0; // todo constant - // iaddiu vi01, vi00, 0x350 | nop - m_ptrs.vi01 = 0x350; // todo constant - // mfir.x vf03, vi14 | nop - m_ptrs.vf03_x = m_ptrs.vi14; - // mfir.y vf03, vi01 | nop - m_ptrs.vf03_y = m_ptrs.vi01; - // mfir.z vf03, vi14 | nop - m_ptrs.vf03_z = m_ptrs.vi14; - // mfir.w vf03, vi01 | nop :e - m_ptrs.vf03_w = m_ptrs.vi01; - // lq.xyzw vf04, 664(vi00) | nop - m_globals.vf04_ambient = m_tfrag_data.ambient; // TODO get rid? - auto pc_port_data = dma.read_and_advance(); assert(pc_port_data.size_bytes == sizeof(TfragPcPortData)); memcpy(&m_pc_port_data, pc_port_data.data, sizeof(TfragPcPortData)); @@ -386,220 +278,6 @@ void TFragment::handle_initialization(DmaFollower& dma, db_setup.vifcode1().immediate == (Buffer1_Start - Buffer0_Start)); } -template -void TFragment::handle_tfrag(const DmaTransfer& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - auto first_vif = dma.vifcode0(); - auto second_vif = dma.vifcode1(); - if (DEBUG) { - ImGui::Separator(); - ImGui::Text("tf: %d sz %d", m_stats.tfrag_dma_packets, dma.size_bytes); - ImGui::Text(" vif: %s", first_vif.print().c_str()); - ImGui::Text(" vif: %s", second_vif.print().c_str()); - } - - // first VIF should be a STCYCL - assert(first_vif.kind == VifCode::Kind::STCYCL); - VifCodeStcycl stcycl(first_vif.immediate); - - // this is our state for running through the DMA data - int cl = stcycl.cl; - int wl = stcycl.wl; - int offset_into_data = 0; - bool row_init = false; - u32 row[4]; - u8 stmod = 0; - - // next can be one of: - // - NOP, UNPACK, MSCAL - - // fmt::print("START vif -> {} (mod {})\n", second_vif.print(), stmod); - switch (second_vif.kind) { - case VifCode::Kind::NOP: - // do nothing! - break; - case VifCode::Kind::UNPACK_V4_8: - offset_into_data = handle_unpack_v4_8_mode0(second_vif, dma, offset_into_data, cl, wl); - break; - case VifCode::Kind::MSCAL: - if (!m_skip_mscals) { - handle_mscal(second_vif, render_state, prof); - } - break; - default: - fmt::print("unknown second vif in tfragment: {}\n", second_vif.print()); - assert(false); - } - - bool ok = true; - while (ok && offset_into_data < (int)dma.size_bytes) { - assert((offset_into_data % 4) == 0); - auto vif = dma.read_val(offset_into_data); - offset_into_data += 4; - - auto code = VifCode(vif); - // fmt::print("vif -> {} (mod {}) {}/{} #x{:x}\n", code.print(), stmod, offset_into_data, - // dma.size_bytes, dma.data_offset); - switch (code.kind) { - case VifCode::Kind::UNPACK_V4_16: - if (DEBUG) { - ImGui::Text(" vif: %s (m %d)", code.print().c_str(), stmod); - } - if (stmod == 0) { - offset_into_data = handle_unpack_v4_16_mode0(code, dma, offset_into_data, cl, wl); - } else if (stmod == 1) { - assert(row_init); - offset_into_data = handle_unpack_v4_16_mode1(code, dma, offset_into_data, cl, wl, row); - } else { - assert(false); - } - break; - case VifCode::Kind::UNPACK_V4_32: - if (DEBUG) { - ImGui::Text(" vif: %s", code.print().c_str()); - } - assert(stmod == 0); - offset_into_data = handle_unpack_v4_32(code, dma, offset_into_data, cl, wl); - break; - case VifCode::Kind::UNPACK_V4_8: - if (DEBUG) { - ImGui::Text(" vif: %s", code.print().c_str()); - } - if (stmod == 0) { - offset_into_data = handle_unpack_v4_8_mode0(code, dma, offset_into_data, cl, wl); - } else if (stmod == 1) { - assert(row_init); - offset_into_data = handle_unpack_v4_8_mode1(code, dma, offset_into_data, cl, wl, row); - } else { - assert(false); - } - - break; - case VifCode::Kind::UNPACK_V3_32: - if (DEBUG) { - ImGui::Text(" vif: %s", code.print().c_str()); - } - assert(stmod == 0); - offset_into_data = handle_unpack_v3_32(code, dma, offset_into_data, cl, wl); - break; - case VifCode::Kind::STROW: - row_init = true; - memcpy(row, dma.data + offset_into_data, 16); - offset_into_data += 16; - if (DEBUG) { - Vector4f vec; - memcpy(&vec, row, 16); - ImGui::Text(" row: %s", vec.to_string_aligned().c_str()); - // fmt::print(" row: {}\n", vec.to_string_aligned().c_str()); - } - break; - case VifCode::Kind::STMOD: - if (DEBUG) { - ImGui::Text(" stmod %d\n", code.immediate); - } - if (stmod == 0) { - assert(code.immediate == 1); - } else { - assert(stmod == 1); - assert(code.immediate == 0 || code.immediate == 1); // kinda weird. - } - stmod = code.immediate; - break; - case VifCode::Kind::STCYCL: - if (DEBUG) { - ImGui::Text(" vif: %s", code.print().c_str()); - } - { - VifCodeStcycl ss(code.immediate); - cl = ss.cl; - wl = ss.wl; - } - - break; - case VifCode::Kind::NOP: - if (DEBUG) { - ImGui::Text(" NOP"); - } - break; - default: - ok = false; - if (DEBUG) { - ImGui::TextColored(ImVec4(0.8, 0.3, 0.3, 1.0), "unhandled vif: %s", code.print().c_str()); - } - break; - } - } - if (!ok) { - m_stats.error_packets++; - } else { - if (DEBUG) { - ImGui::Text("END"); - } - - assert(stmod == 0); - } -} - -template -void TFragment::handle_mscal(const VifCode& code, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - if (DEBUG) { - ImGui::TextColored(ImVec4(0.3, 0.8, 0.3, 1.0), "MSCAL: %d", code.immediate); - } - - int prog_id = code.immediate / 2; - if (prog_id >= NUM_PROGRAMS) { - fmt::print("bad program: {}\n", prog_id); - assert(false); - } - m_stats.per_program[prog_id].calls++; - - switch (code.immediate) { - case 12: - case 6: - exec_program_6(render_state, prof); - break; - case 8: - if (m_prog8_with_prog6) { - exec_program_6(render_state, prof); - } else { - m_stats.error_mscals++; - } - break; - case 10: - if (m_prog10_with_prog6) { - exec_program_6(render_state, prof); - } else { - m_stats.error_mscals++; - } - break; - case 18: - if (m_prog18_with_prog6) { - exec_program_6(render_state, prof); - } else { - m_stats.error_mscals++; - } - break; - default: - if (m_all_with_prog6) { - exec_program_6(render_state, prof); - } else { - m_stats.error_mscals++; - if (DEBUG) { - ImGui::TextColored(ImVec4(0.8, 0.8, 0.3, 1.0), " UNHANDLED"); - } - } - - break; - } -} - -void TFragment::flip_buffers() { - m_uploading_buffer ^= 1; -} - std::string TFragData::print() const { std::string result; result += fmt::format("fog: {}\n", fog.to_string_aligned()); diff --git a/game/graphics/opengl_renderer/tfrag/TFragment.h b/game/graphics/opengl_renderer/tfrag/TFragment.h index 95aeb40de9..a3120f90b7 100644 --- a/game/graphics/opengl_renderer/tfrag/TFragment.h +++ b/game/graphics/opengl_renderer/tfrag/TFragment.h @@ -2,7 +2,6 @@ #include "game/graphics/opengl_renderer/BucketRenderer.h" #include "game/graphics/opengl_renderer/DirectRenderer.h" -#include "game/graphics/opengl_renderer/tfrag/BufferedRenderer.h" #include "game/graphics/opengl_renderer/tfrag/Tfrag3.h" #include "common/dma/gs.h" #include "common/math/Vector.h" @@ -10,8 +9,6 @@ using math::Matrix4f; using math::Vector4f; -constexpr int KICK_ZONE_END = 1024; - struct TFragData { Vector4f fog; // 0 656 (vf01) Vector4f val; // 1 657 (vf02) @@ -35,10 +32,6 @@ struct TFragBufferedData { }; static_assert(sizeof(TFragBufferedData) == 328 * 16); -struct TFragKickZone { - u8 pad[(KICK_ZONE_END - 670) * 16]; -}; - class TFragment : public BucketRenderer { public: TFragment(const std::string& name, @@ -50,186 +43,25 @@ class TFragment : public BucketRenderer { void draw_debug_window() override; private: - void handle_initialization(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - void handle_tfrag(const DmaTransfer& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - int handle_unpack_v4_8_mode0(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl); - int handle_unpack_v4_8_mode1(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl, - const u32 row[4]); - int handle_unpack_v4_16_mode0(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl); - int handle_unpack_v4_16_mode1(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl, - const u32 row[4]); - int handle_unpack_v4_32(const VifCode& code, const DmaTransfer& dma, int offset, int cl, int wl); - int handle_unpack_v3_32(const VifCode& code, const DmaTransfer& dma, int offset, int cl, int wl); - - template - void handle_mscal(const VifCode& code, SharedRenderState* render_state, ScopedProfilerNode& prof); - - template - void exec_program_6(SharedRenderState* render_state, ScopedProfilerNode& prof); - - template - void XGKICK(u32 addr, SharedRenderState* render_state, ScopedProfilerNode& prof); - - struct Prog6Inputs { - Vector4f vf04_cam_mat_x; - Vector4f vf07_cam_mat_y; - Vector4f vf08_cam_mat_z; - }; - - struct Prog6Vars { - // pre-set - u16 vi03; - u16 vi07; - u16 vi08; - u16 vi09; - u16 vi14; - Vector4f vf16_scaled_pos_0; - Vector4f vf17_scaled_pos_1; - Vector4f vf18_scaled_pos_2; - Vector4f vf19_scaled_pos_3; - - // uninit - u16 vi02; - u16 vi04; - u16 vi05; - u16 vi06_kick_zone_ptr; - u16 vi10; - u16 vi11; - u16 vi12; // seems to be gs loop count (dverts) - 0x80. - u16 vi13; - Vector4f vf09_cam_trans; - Vector4f vf12_root_pos_0; // position a, 0 - Vector4f vf13_root_pos_1; - Vector4f vf14_loop_pos_0; - Vector4f vf15_loop_pos_1; - Vector4f vf20; - Vector4f vf21; - Vector4f vf22; - Vector4f vf23; - Vector4f vf24; - Vector4f vf25; // position b, 0 - Vector4f vf26; - Vector4f vf27; - Vector4f vf28; - Vector4f vf29; - Vector4f vf30; - Vector4f vf31; - }; - - template - void exec_program_6_process_first(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - void exec_jumper_L128(const Prog6Inputs& in, Prog6Vars& vars); - - template - bool exec_jumper_L129(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - void exec_jumper_L6A1(const Prog6Inputs& in, Prog6Vars& vars); - - template - bool exec_jumper_L130(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - void exec_jumper_L6B0(const Prog6Inputs& in, Prog6Vars& vars); - - template - bool exec_jumper_L131(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - void exec_jumper_L6BF(const Prog6Inputs& in, Prog6Vars& vars); - - template - bool exec_jumper_L132(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - template - bool exec_jumper_L122(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof); + void handle_initialization(DmaFollower& dma); std::string m_debug_string; + bool m_hack_scrambler = false; bool m_child_mode = false; - bool m_extra_debug = false; - int m_max_draw = -1; - bool m_skip_mscals = false; - bool m_skip_xgkick = false; - bool m_prog8_with_prog6 = true; - bool m_prog10_with_prog6 = true; - bool m_prog18_with_prog6 = true; - bool m_all_with_prog6 = false; - bool m_use_buffered_renderer = true; - bool m_use_tfrag3 = true; bool m_hack_test_many_levels = false; bool m_override_time_of_day = false; - float m_time_of_days[8] = {0}; - std::string m_frag_debug; + float m_time_of_days[8] = {1, 0, 0, 0, 0, 0, 0, 0}; // GS setup data u8 m_test_setup[32]; // VU data - Matrix4f m_matrix_0; - Matrix4f m_matrix_1; TFragData m_tfrag_data; - TFragKickZone m_kick_data; TfragPcPortData m_pc_port_data; // buffers TFragBufferedData m_buffered_data[2]; - int m_uploading_buffer = 0; - - u8* get_upload_buffer() { return (u8*)&m_buffered_data[m_uploading_buffer].pad[0]; } - u8* get_processing_buffer() { return (u8*)&m_buffered_data[1 - m_uploading_buffer].pad[0]; } - - void flip_buffers(); - u16 ilw_data(int offset, int xyzw); - u16 ilw_kick_zone(int offset, int xyzw); - - Vector4f load_vector_data(int offset); - void store_vector_kick_zone(int offset, const Vector4f& vec); - void store_gif_kick_zone(int offset, const GifTag& tag); - void store_u32_kick_zone(u32 value, int qw, int xyzw); enum TFragDataMem { Buffer0_Start = 0, @@ -242,56 +74,10 @@ class TFragment : public BucketRenderer { TFragKickZoneData = 670, }; - enum TFragJumper { - L128_PART0_X = 0, - L129_PART1_X = 1, - L0x6A1_PART0_Y = 2, - L130_PART1_Y = 3, - L0x6B0_PART0_Z = 4, - L131_PART1_Z = 5, - L0x6BF_PART0_W = 6, - L132_PART1_W = 7, - L122_KICK = 8, - END_PROGRAM = 9, - INVALID = 10 - }; - - TFragJumper m_next_block = TFragJumper::INVALID; - TFragJumper m_ret_block = TFragJumper::INVALID; - bool m_clip_and_3ffff = false; - Vector4f m_acc; // todo, probably rearrange this so acc stays entirely in part0 or part1? - float m_q; // todo, probably regroup - enum TFragProgMem { TFragSetup = 0, }; - struct Ptrs { - int vi01; - int vi14; - int vf03_x, vf03_y, vf03_z, vf03_w; - } m_ptrs; - - struct Globals { - Vector4f vf04_ambient; - } m_globals; - - static constexpr int NUM_PROGRAMS = 13; - struct Stats { - int tfrag_dma_packets = 0; - int tfrag_bytes = 0; - int error_packets = 0; - int error_mscals = 0; - - struct PerProgram { - int calls = 0; - }; - - PerProgram per_program[NUM_PROGRAMS]; // addr / 2 - } m_stats; - - DirectRenderer m_direct_renderer; - BufferedRenderer::Builder m_buffered_renderer; Tfrag3 m_tfrag3; std::vector m_tree_kinds; int m_level_id; diff --git a/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp b/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp index c1b42b2011..0a44e28a75 100644 --- a/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp +++ b/game/graphics/opengl_renderer/tfrag/Tfrag3.cpp @@ -160,33 +160,9 @@ bool Tfrag3::update_load(const std::vector& tree_kind } m_load_state.vert++; if (!remaining) { - m_load_state.state = INIT_TEX; - m_load_state.tex_id = 0; + return true; } } break; - - case State::INIT_TEX: - for (size_t max_tex = - std::min((size_t)m_load_state.tex_id + MAX_TEX_PER_FRAME, lev_data->textures.size()); - m_load_state.tex_id < max_tex; m_load_state.tex_id++) { - auto& tex = lev_data->textures[m_load_state.tex_id]; - GLuint gl_tex; - glGenTextures(1, &gl_tex); - glBindTexture(GL_TEXTURE_2D, gl_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.w, tex.h, 0, GL_RGBA, - GL_UNSIGNED_INT_8_8_8_8_REV, tex.data.data()); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, gl_tex); - glGenerateMipmap(GL_TEXTURE_2D); - - float aniso = 0.0f; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &aniso); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso); - m_textures.push_back(gl_tex); - } - return m_load_state.tex_id == lev_data->textures.size(); - break; default: assert(false); } @@ -200,12 +176,18 @@ bool Tfrag3::setup_for_level(const std::vector& tree_ // first, get the level in memory Timer tfrag3_setup_timer; - auto lev_data = render_state->loader.get_tfrag3_level(level); - if (!lev_data) { + const auto* lev_data = render_state->loader.get_tfrag3_level(level); + if (!lev_data || (m_has_level && lev_data->load_id != m_load_id)) { m_has_level = false; + m_textures = nullptr; + m_level_name = ""; + + discard_tree_cache(); return false; } int init_load_state = m_load_state.state; + m_textures = &lev_data->textures; + m_load_id = lev_data->load_id; if (m_level_name != level) { m_has_level = false; @@ -213,7 +195,7 @@ bool Tfrag3::setup_for_level(const std::vector& tree_ m_load_state.loading = true; m_load_state.state = State::FIRST; } - if (update_load(tree_kinds, lev_data)) { + if (update_load(tree_kinds, lev_data->level.get())) { m_has_level = true; m_level_name = level; m_load_state.loading = false; @@ -277,7 +259,7 @@ void Tfrag3::render_tree(const TfragRenderSettings& settings, continue; } - glBindTexture(GL_TEXTURE_2D, m_textures.at(draw.tree_tex_id)); + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); auto double_draw = setup_tfrag_shader(render_state, draw.mode); tree.tris_this_frame += draw.num_triangles; tree.draws_this_frame++; @@ -393,12 +375,7 @@ void Tfrag3::draw_debug_window() { } void Tfrag3::discard_tree_cache() { - for (auto tex : m_textures) { - glBindTexture(GL_TEXTURE_2D, tex); - glDeleteTextures(1, &tex); - } - m_textures.clear(); - + m_textures = nullptr; for (auto& tree : m_cached_trees) { if (tree.kind != tfrag3::TFragmentTreeKind::INVALID) { glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture); @@ -408,6 +385,7 @@ void Tfrag3::discard_tree_cache() { glDeleteVertexArrays(1, &tree.vao); } } + m_cached_trees.clear(); } namespace { diff --git a/game/graphics/opengl_renderer/tfrag/Tfrag3.h b/game/graphics/opengl_renderer/tfrag/Tfrag3.h index 3f3135cc19..6cec242d87 100644 --- a/game/graphics/opengl_renderer/tfrag/Tfrag3.h +++ b/game/graphics/opengl_renderer/tfrag/Tfrag3.h @@ -81,7 +81,7 @@ class Tfrag3 { std::string m_level_name; - std::vector m_textures; + const std::vector* m_textures = nullptr; std::vector m_cached_trees; std::vector> m_color_result; @@ -89,6 +89,8 @@ class Tfrag3 { GLuint m_debug_vao = -1; GLuint m_debug_verts = -1; + u64 m_load_id = -1; + // in theory could be up to 4096, I think, but we don't see that many... // should be easy to increase (will require a shader change too for indexing) static constexpr int TIME_OF_DAY_COLOR_COUNT = 8192; @@ -105,13 +107,11 @@ class Tfrag3 { FREE_OLD_TREES = 1, INIT_NEW_TREES = 2, UPLOAD_VERTS = 3, - INIT_TEX = 4, }; struct { bool loading = false; State state; - u32 tex_id = 0; u32 vert = 0; } m_load_state; static constexpr int MAX_TEX_PER_FRAME = 4; diff --git a/game/graphics/opengl_renderer/tfrag/Tie3.cpp b/game/graphics/opengl_renderer/tfrag/Tie3.cpp index 680196ba18..d92d398ad6 100644 --- a/game/graphics/opengl_renderer/tfrag/Tie3.cpp +++ b/game/graphics/opengl_renderer/tfrag/Tie3.cpp @@ -167,32 +167,10 @@ bool Tie3::update_load(const tfrag3::Level* lev_data) { } m_load_state.vert++; if (!remaining) { - m_load_state.state = INIT_TEX; - m_load_state.tex = 0; + return true; } } break; - case State::INIT_TEX: - for (size_t max_tex = std::min((size_t)m_load_state.tex + 3, lev_data->textures.size()); - m_load_state.tex < max_tex; m_load_state.tex++) { - auto& tex = lev_data->textures[m_load_state.tex]; - GLuint gl_tex; - glGenTextures(1, &gl_tex); - glBindTexture(GL_TEXTURE_2D, gl_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.w, tex.h, 0, GL_RGBA, - GL_UNSIGNED_INT_8_8_8_8_REV, tex.data.data()); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, gl_tex); - glGenerateMipmap(GL_TEXTURE_2D); - - float aniso = 0.0f; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &aniso); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, aniso); - m_textures.push_back(gl_tex); - } - return m_load_state.tex == lev_data->textures.size(); - break; default: assert(false); } @@ -208,9 +186,15 @@ bool Tie3::setup_for_level(const std::string& level, SharedRenderState* render_s // TODO: right now this will wait to load from disk and unpack it. Timer tfrag3_setup_timer; auto lev_data = render_state->loader.get_tfrag3_level(level); - if (!lev_data) { + if (!lev_data || (m_has_level && lev_data->load_id != m_load_id)) { + m_has_level = false; + m_textures = nullptr; + m_level_name = ""; + discard_tree_cache(); return false; } + m_textures = &lev_data->textures; + m_load_id = lev_data->load_id; int init_load_state = m_load_state.state; if (m_level_name != level) { @@ -219,7 +203,7 @@ bool Tie3::setup_for_level(const std::string& level, SharedRenderState* render_s m_load_state.loading = true; m_load_state.state = State::FIRST; } - if (update_load(lev_data)) { + if (update_load(lev_data->level.get())) { m_has_level = true; m_level_name = level; m_load_state.loading = false; @@ -346,12 +330,6 @@ void do_wind_math(u16 wind_idx, } void Tie3::discard_tree_cache() { - for (auto tex : m_textures) { - glBindTexture(GL_TEXTURE_2D, tex); - glDeleteTextures(1, &tex); - } - m_textures.clear(); - for (auto& tree : m_trees) { glBindTexture(GL_TEXTURE_1D, tree.time_of_day_texture); glDeleteTextures(1, &tree.time_of_day_texture); @@ -528,7 +506,7 @@ void Tie3::render_tree_wind(int idx, const auto& draw = tree.wind_draws->operator[](draw_idx); if ((int)draw.tree_tex_id != last_texture) { - glBindTexture(GL_TEXTURE_2D, m_textures.at(draw.tree_tex_id)); + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); last_texture = draw.tree_tex_id; } auto double_draw = setup_tfrag_shader(render_state, draw.mode); @@ -659,7 +637,7 @@ void Tie3::render_tree(int idx, } if ((int)draw.tree_tex_id != last_texture) { - glBindTexture(GL_TEXTURE_2D, m_textures.at(draw.tree_tex_id)); + glBindTexture(GL_TEXTURE_2D, m_textures->at(draw.tree_tex_id)); last_texture = draw.tree_tex_id; } diff --git a/game/graphics/opengl_renderer/tfrag/Tie3.h b/game/graphics/opengl_renderer/tfrag/Tie3.h index 6dcfa88c8f..197c6ad863 100644 --- a/game/graphics/opengl_renderer/tfrag/Tie3.h +++ b/game/graphics/opengl_renderer/tfrag/Tie3.h @@ -78,7 +78,8 @@ class Tie3 : public BucketRenderer { std::vector m_trees; std::string m_level_name; - std::vector m_textures; // todo, can we share with tfrag in some cases? + const std::vector* m_textures; + u64 m_load_id = -1; struct Cache { std::vector vis_temp; diff --git a/game/graphics/opengl_renderer/tfrag/program6_cpu.cpp b/game/graphics/opengl_renderer/tfrag/program6_cpu.cpp deleted file mode 100644 index 58326c8960..0000000000 --- a/game/graphics/opengl_renderer/tfrag/program6_cpu.cpp +++ /dev/null @@ -1,1144 +0,0 @@ -#include "game/graphics/opengl_renderer/tfrag/TFragment.h" -#include "third-party/imgui/imgui.h" -// tfragment's program 6, implemented on the CPU (slow) - -u32 float_2_u32(float x) { - u32 y; - memcpy(&y, &x, 4); - return y; -} - -std::string int_vec_debug(const Vector4f& vec) { - return fmt::format("[{:x} {:x} {:x} {:x}]", float_2_u32(vec.x()), float_2_u32(vec.y()), - float_2_u32(vec.z()), float_2_u32(vec.w())); -} - -std::string debug_print_ad_vec(const Vector4f& val) { - u64 data; - u8 address; - memcpy(&data, val.data(), 8); - memcpy(&address, val.data() + 2, 1); - - return fmt::format("AD: 0x{:x} 0x{:x}\n", address, data); -} - -u16 TFragment::ilw_data(int offset, int xyzw) { - u16 result; - if (m_uploading_buffer == 0) { - offset -= Buffer1_Start; - } - assert(offset < Buffer1_Start); - assert(offset >= 0); - int mem_offset = (xyzw * 4) + (offset * 16); - memcpy(&result, get_processing_buffer() + mem_offset, 2); - return result; -} - -Vector4f TFragment::load_vector_data(int offset) { - Vector4f result; - if (m_uploading_buffer == 0) { - offset -= Buffer1_Start; - } - offset = offset & 0x3ff; // not super happy with this... - assert(offset < Buffer1_Start); - assert(offset >= 0); - memcpy(&result, get_processing_buffer() + (offset * 16), 16); - return result; -} - -void TFragment::store_vector_kick_zone(int offset, const Vector4f& vec) { - assert(offset >= TFragDataMem::TFragKickZoneData); - assert(offset < KICK_ZONE_END); // hack increased - memcpy(&m_kick_data.pad[(offset - TFragDataMem::TFragKickZoneData) * 16], &vec.data()[0], 16); -} - -u16 TFragment::ilw_kick_zone(int offset, int xyzw) { - assert(offset >= TFragDataMem::TFragKickZoneData); - assert(offset < KICK_ZONE_END); - u16 result; - int mem_offset = (xyzw * 4) + (offset * 16); - memcpy(&result, m_kick_data.pad + mem_offset - TFragDataMem::TFragKickZoneData * 16, 2); - return result; -} - -template -void TFragment::exec_program_6(SharedRenderState* render_state, ScopedProfilerNode& prof) { - // fmt::print("exec 6\n"); - flip_buffers(); - // VF02 is VAL always - // VF05 is ADGIF always - // VF06 is STRGIF always - // VF10 is HVDF offset always - // VF11 is hmge_scale always - // VF01 is fog always - - // SETUP - // first, load globals from TFragData (these never change, so we'll just use them from TFragData) - // lq.xyzw vf02, 657(vi00) | nop - // lq.xyzw vf05, 660(vi00) | addw.z vf28, vf00, vf00 (done later) - // lq.xyzw vf06, 658(vi00) | nop - // lq.xyzw vf10, 661(vi00) | nop - // lq.xyzw vf11, 662(vi00) | nop - // lq.xyzw vf01, 656(vi00) | addz.z vf28, vf28, vf02 (done later) - - // there are two main versions, one for each double-buffer. - // I'm not sure why these need to be different yet. - // but, just in case it actually matters and we actually need to swap addresses for some reason - // (like addresses baked in to the data) - // we're going to split into two functions. - // these inputs will be given to either. (these are const) - Prog6Inputs inputs; - - // non-const - Prog6Vars vars; - if (m_uploading_buffer == 1) { - vars.vi14 = 0; - } else { - vars.vi14 = Buffer1_Start; - } - - vars.vf28.z() = 1.f; - vars.vf28.z() += m_tfrag_data.val.z(); - - // ilw.w vi08, 4(vi14) | nop - vars.vi08 = ilw_data(4 + vars.vi14, 3); - // fmt::print("------------- VI08 init: {}\n", vars.vi08); - // ilw.z vi09, 4(vi14) | nop - vars.vi09 = ilw_data(4 + vars.vi14, 2); - // ilw.y vi03, 3(vi14) | nop - vars.vi03 = ilw_data(3 + vars.vi14, 1); - - // fmt::print("-------VI03 init: {}\n", vars.vi03); - - if (DEBUG) { - // small, like 9, 54, 66 - ImGui::Text("ints: %d %d %d", vars.vi08, vars.vi09, vars.vi03); - } - - // fmt::print("vi09: #x{:x} ({})\n", vars.vi09, vars.vi14); - - // fcset 0x0 | nop - // iaddi vi07, vi00, -0x1 | nop - vars.vi07 = -1; - - // lq.xyzw vf04, 5(vi14) | mulw.xyzw vf16, vf00, vf00 - inputs.vf04_cam_mat_x = load_vector_data(vars.vi14 + 5); - vars.vf16_scaled_pos_0 = Vector4f(0, 0, 0, 1); - - // lq.xyzw vf07, 6(vi14) | mulw.xyzw vf17, vf00, vf00 - inputs.vf07_cam_mat_y = load_vector_data(vars.vi14 + 6); - vars.vf17_scaled_pos_1 = Vector4f(0, 0, 0, 1); - - // ibne vi00, vi14, L136 | mulw.xyzw vf18, vf00, vf00 - vars.vf18_scaled_pos_2 = Vector4f(0, 0, 0, 1); - // lq.xyzw vf08, 7(vi14) | mulw.xyzw vf19, vf00, vf00 - vars.vf19_scaled_pos_3 = Vector4f(0, 0, 0, 1); - inputs.vf08_cam_mat_z = load_vector_data(vars.vi14 + 7); - - if (m_uploading_buffer == 1) { - // vi14 = 0 version - exec_program_6_process_first(inputs, vars, render_state, prof); - } else { - // L136 - assert(false); - } - - // because we're doing everything in-sync (no background kicking or uploading), - // I _think_ it's fine to just do - flip_buffers(); - // and now we only have to implement one half of program 6? -} - -namespace { - -float u32_2_float(u32 x) { - float y; - memcpy(&y, &x, 4); - return y; -} - -Vector4f itof0(const Vector4f& vec) { - Vector4f result; - for (int i = 0; i < 4; i++) { - s32 val; - memcpy(&val, vec.data() + i, 4); - result[i] = val; - } - return result; -} - -Vector4f ftoi4(const Vector4f& vec) { - Vector4f result; - for (int i = 0; i < 4; i++) { - s32 f = vec[i] * 16.f; - float val; - memcpy(&val, &f, 4); - result[i] = val; - } - return result; -} - -bool clip_xyz_plus_minus(const Vector4f& pt) { - float pw = std::abs(pt.w()); - float mw = -pw; - for (int i = 0; i < 3; i++) { - if (pt[i] > pw) { - return true; - } - if (pt[i] < mw) { - return true; - } - } - return false; -} -} // namespace - -void TFragment::store_gif_kick_zone(int offset, const GifTag& tag) { - assert(offset >= TFragDataMem::TFragKickZoneData); - assert(offset < KICK_ZONE_END); - memcpy(&m_kick_data.pad[(offset - TFragDataMem::TFragKickZoneData) * 16], &tag, 16); -} - -void TFragment::store_u32_kick_zone(u32 value, int qw, int xyzw) { - assert(qw >= TFragDataMem::TFragKickZoneData); - assert(qw < KICK_ZONE_END); - memcpy(&m_kick_data.pad[(xyzw * 4) + (qw - TFragDataMem::TFragKickZoneData) * 16], &value, 4); -} - -template -void TFragment::exec_program_6_process_first(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // SETUP BLOCK - - // ilwr.x vi02, vi03 | nop - assert(vars.vi03 < TFragDataMem::Buffer1_Start); // should be a buffer 0 addr - vars.vi02 = ilw_data(vars.vi03, 0); - // fmt::print("--------- initial vi02.x: {}\n", vars.vi02); - - // lq.xyzw vf09, 8(vi14) | nop - vars.vf09_cam_trans = load_vector_data(vars.vi14 + 8); - - // stupid, this is 0. - // iadd vi08, vi08, vi14 | nop - vars.vi08 += vars.vi14; - // iadd vi09, vi09, vi14 | nop - vars.vi09 += vars.vi14; - - // lq.xyw vf28, 0(vi02) | nop - if (DEBUG) { - ImGui::Text("vi02: %d", vars.vi02); - } - auto vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - vars.vf28.w() = vf28_load_temp.w(); - - // mtir vi06, vf03.x | nop - vars.vi06_kick_zone_ptr = m_ptrs.vf03_x; - - // ilwr.x vi12, vi09 | nop - vars.vi12 = ilw_data(vars.vi09, 0); - // fmt::print("--------- initial vi12: {}\n", vars.vi12); - - // ilwr.z vi13, vi09 | nop - vars.vi13 = ilw_data(vars.vi09, 2); - - // mtir vi04, vf28.w | subz.xyz vf24, vf28, vf02 - vars.vi04 = float_2_u32(vars.vf28.w()); - vars.vf24 = vars.vf28 - m_tfrag_data.val.z(); // only xyz, but what sets w?? - - // iaddiu vi11, vi00, 0x4000 | nop - vars.vi11 = 0x4000; - - // iaddiu vi11, vi11, 0x4000 | nop - vars.vi11 += 0x4000; - - // ilwr.y vi02, vi03 | nop - vars.vi02 = ilw_data(vars.vi03, 1); - // fmt::print("--------- initial vi02.y: {}\n", vars.vi02); - - // lq.xyzw vf12, 0(vi04) | nop - if (DEBUG) { - ImGui::Text("vi04: %d", vars.vi04); - } - vars.vf12_root_pos_0 = load_vector_data(vars.vi04); - - // lq.xyzw vf20, 1(vi04) | nop - vars.vf20 = load_vector_data(vars.vi04 + 1); - - // iaddiu vi12, vi12, 0x80 | nop - vars.vi12 += 0x80; - - // iadd vi13, vi13, vi08 | nop - vars.vi13 += vars.vi08; - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf12, vf12 - vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - vars.vf28.w() = vf28_load_temp.w(); - vars.vf12_root_pos_0 = itof0(vars.vf12_root_pos_0); - - // todo - // vars.vf12_root_pos_0 *= 0; - - // fmt::print("root 12 setup: {}\n", vars.vf12_root_pos_0.to_string_aligned()); - - // mfir.w vf24, vi06 | nop - vars.vf24.w() = u32_2_float(vars.vi06_kick_zone_ptr); - - // lqi.xyzw vf29, vi13 | nop - vars.vf29 = load_vector_data(vars.vi13); - vars.vi13++; - - // lqi.xyzw vf30, vi13 | nop - vars.vf30 = load_vector_data(vars.vi13); - vars.vi13++; - - // lqi.xyzw vf31, vi13 | nop - vars.vf31 = load_vector_data(vars.vi13); - vars.vi13++; - - // sqi.xyzw vf05, vi06 | subz.xyz vf25, vf28, vf02 - if (DEBUG) { - ImGui::Text("vi06: %d", vars.vi06_kick_zone_ptr); - } - store_gif_kick_zone(vars.vi06_kick_zone_ptr, m_tfrag_data.ad_gif); - vars.vi06_kick_zone_ptr++; - vars.vf25 = vars.vf28 - m_tfrag_data.val.z(); - - // sqi.xyzw vf29, vi06 | mulaw.xyzw ACC, vf09, vf00 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf29); - vars.vi06_kick_zone_ptr++; - if (DEBUG) { - fmt::print("@ {} ad (0): {}", vars.vi13, debug_print_ad_vec(vars.vf29)); - } - Vector4f acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | nop - vars.vi04 = float_2_u32(vars.vf28.w()); - - // sqi.xyzw vf30, vi06 | maddax.xyzw ACC, vf04, vf12 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf30); - vars.vi06_kick_zone_ptr++; - if (DEBUG) { - fmt::print("ad (1): {}", debug_print_ad_vec(vars.vf30)); - } - acc += in.vf04_cam_mat_x * vars.vf12_root_pos_0.x(); - - // sqi.xyzw vf31, vi06 | nop - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf31); - vars.vi06_kick_zone_ptr++; - if (DEBUG) { - fmt::print("ad (2): {}", debug_print_ad_vec(vars.vf31)); - } - - // ilwr.z vi02, vi03 | nop - vars.vi02 = ilw_data(vars.vi03, 2); - // fmt::print("--------- initial vi02.z: {}\n", vars.vi02); - - // lq.xyzw vf13, 0(vi04) | madday.xyzw ACC, vf07, vf12 - vars.vf13_root_pos_1 = load_vector_data(vars.vi04); - acc += in.vf07_cam_mat_y * vars.vf12_root_pos_0.y(); - - // lq.xyzw vf21, 1(vi04) | maddz.xyzw vf12, vf08, vf12 - vars.vf21 = load_vector_data(vars.vi04 + 1); - vars.vf12_root_pos_0 = acc + in.vf08_cam_mat_z * vars.vf12_root_pos_0.z(); - // fmt::print("root 12 setup cam: {}\n", in.vf08_cam_mat_z.to_string_aligned()); - - // lqi.xyzw vf29, vi13 | nop - vars.vf29 = load_vector_data(vars.vi13); - vars.vi13++; - - // lqi.xyzw vf30, vi13 | nop - vars.vf30 = load_vector_data(vars.vi13); - vars.vi13++; - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf13, vf13 - vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - vars.vf28.w() = vf28_load_temp.w(); - vars.vf13_root_pos_1 = itof0(vars.vf13_root_pos_1); - - // div Q, vf01.x, vf12.w | mul.xyzw vf16, vf12, vf11 - float q = m_tfrag_data.fog.x() / vars.vf12_root_pos_0.w(); - vars.vf16_scaled_pos_0 = vars.vf12_root_pos_0.elementwise_multiply(m_tfrag_data.hmge_scale); - - // sqi.xyzw vf29, vi06 | nop - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf29); - vars.vi06_kick_zone_ptr++; - if (DEBUG) { - fmt::print("ad (3): {}", debug_print_ad_vec(vars.vf29)); - } - - // sqi.xyzw vf30, vi06 | nop - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf30); - vars.vi06_kick_zone_ptr++; - if (DEBUG) { - fmt::print("ad (4): {}", debug_print_ad_vec(vars.vf30)); - } - - // iadd vi01, vi12, vi12 | subz.xyz vf26, vf28, vf02 - m_ptrs.vi01 = vars.vi12 + vars.vi12; - vars.vf26 = vars.vf28 - m_tfrag_data.val.z(); - - // iadd vi01, vi01, vi12 | mulaw.xyzw ACC, vf09, vf00 - m_ptrs.vi01 += vars.vi12; - acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | nop - vars.vi04 = float_2_u32(vars.vf28.w()); - - // iadd vi05, vi06, vi01 | maddax.xyzw ACC, vf04, vf13 - vars.vi05 = vars.vi06_kick_zone_ptr + m_ptrs.vi01; - // fmt::print("vert count: {}\n", vars.vi12); - acc += in.vf04_cam_mat_x * vars.vf13_root_pos_1.x(); - - // ior vi10, vi06, vi00 | mul.xyz vf12, vf12, Q - vars.vi10 = vars.vi06_kick_zone_ptr; - vars.vf12_root_pos_0.x() *= q; - vars.vf12_root_pos_0.y() *= q; - vars.vf12_root_pos_0.z() *= q; - - // ilwr.w vi02, vi03 | mul.xyz vf24, vf24, Q - vars.vi02 = ilw_data(vars.vi03, 3); - // fmt::print("--------- initial vi02.w: {}\n", vars.vi02); - vars.vf24.x() *= q; - vars.vf24.y() *= q; - vars.vf24.z() *= q; - - // lq.xyzw vf14, 0(vi04) | madday.xyzw ACC, vf07, vf13 - vars.vf14_loop_pos_0 = load_vector_data(vars.vi04); - acc += in.vf07_cam_mat_y * vars.vf13_root_pos_1.y(); - - // lq.xyzw vf22, 1(vi04) | maddz.xyzw vf13, vf08, vf13 - vars.vf22 = load_vector_data(vars.vi04 + 1); - vars.vf13_root_pos_1 = acc + in.vf08_cam_mat_z * vars.vf13_root_pos_1.z(); - - // sqi.xyzw vf06, vi06 | add.xyzw vf12, vf12, vf10 - store_gif_kick_zone(vars.vi06_kick_zone_ptr, m_tfrag_data.str_gif); - vars.vi06_kick_zone_ptr++; - vars.vf12_root_pos_0 += m_tfrag_data.hvdf_offset; - - // isw.x vi12, -1(vi06) | nop - store_u32_kick_zone(vars.vi12, vars.vi06_kick_zone_ptr - 1, 0); - if (DEBUG) { - ImGui::Text("strgif mod: %d", vars.vi12); // maybe number of tris or something? - } - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf14, vf14 - vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - vars.vf28.w() = vf28_load_temp.w(); - // fmt::print("ORIG VF28: {} {}\n", vars.vf28.x(), vars.vf28.y()); - vars.vf14_loop_pos_0 = itof0(vars.vf14_loop_pos_0); - - // div Q, vf01.x, vf13.w | mul.xyzw vf17, vf13, vf11 - m_q = m_tfrag_data.fog.x() / vars.vf13_root_pos_1.w(); - vars.vf17_scaled_pos_1 = vars.vf13_root_pos_1.elementwise_multiply(m_tfrag_data.hmge_scale); - - // iaddi vi09, vi09, 0x1 | miniz.w vf12, vf12, vf01 - vars.vi09++; - // fmt::print("VI09 INC (prestart): {}\n", vars.vi09); - vars.vf12_root_pos_0.w() = std::min(vars.vf12_root_pos_0.w(), m_tfrag_data.fog.z()); - - // ilwr.x vi12, vi09 | clipw.xyz vf16, vf16 - vars.vi12 = ilw_data(vars.vi09, 0); - m_clip_and_3ffff = clip_xyz_plus_minus(vars.vf16_scaled_pos_0); - - // starting here, the control flow does crazy stuff, so we have this weird state machine: - m_next_block = TFragJumper::L128_PART0_X; - - while (true) { - exec_jumper_L128(in, vars); - if (exec_jumper_L129(in, vars, render_state, prof)) { - break; - } - exec_jumper_L6A1(in, vars); - if (exec_jumper_L130(in, vars, render_state, prof)) { - break; - } - exec_jumper_L6B0(in, vars); - if (exec_jumper_L131(in, vars, render_state, prof)) { - break; - } - exec_jumper_L6BF(in, vars); - if (exec_jumper_L132(in, vars, render_state, prof)) { - break; - } - } -} - -template -void TFragment::exec_jumper_L128(const Prog6Inputs& in, Prog6Vars& vars) { - // Part 0 for X - // iaddi vi03, vi03, 0x1 | subz.xyz vf27, vf28, vf02 - vars.vi03++; - Vector4f vf27_temp = vars.vf28 - m_tfrag_data.val.z(); - vars.vf27.x() = vf27_temp.x(); - vars.vf27.y() = vf27_temp.y(); - vars.vf27.z() = vf27_temp.z(); - - // iaddi vi07, vi07, 0x1 | mulaw.xyzw ACC, vf09, vf00 - vars.vi07++; - m_acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | maxy.w vf12, vf12, vf01 - vars.vi04 = float_2_u32(vars.vf28.w()); - vars.vf12_root_pos_0.w() = std::max(vars.vf12_root_pos_0.w(), m_tfrag_data.fog.y()); - - // fcand vi01, 0x3ffff | maddax.xyzw ACC, vf04, vf14 - m_acc += in.vf04_cam_mat_x * vars.vf14_loop_pos_0.x(); - // fcand already calculated - - // ibeq vi00, vi01, L129 | mul.xyz vf13, vf13, Q - // branch made after next instr - vars.vf13_root_pos_1.x() *= m_q; - vars.vf13_root_pos_1.y() *= m_q; - vars.vf13_root_pos_1.z() *= m_q; - - // ilwr.x vi02, vi03 | mul.xyz vf25, vf25, Q - vars.vi02 = ilw_data(vars.vi03, 0); - vars.vf25.x() *= m_q; - vars.vf25.y() *= m_q; - vars.vf25.z() *= m_q; - - // skipped if we take the branch - // nop | addw.w vf12, vf12, vf01 - if (m_clip_and_3ffff) { - vars.vf12_root_pos_0.w() += m_tfrag_data.fog.w(); - } -} - -template -void TFragment::exec_jumper_L6A1(const Prog6Inputs& in, Prog6Vars& vars) { - // part 1 for 1 - // nop | subz.xyz vf24, vf28, vf02 - Vector4f vf24_temp = vars.vf28 - m_tfrag_data.val.z(); - vars.vf24.x() = vf24_temp.x(); - vars.vf24.y() = vf24_temp.y(); - vars.vf24.z() = vf24_temp.z(); - - // iaddi vi07, vi07, 0x1 | mulaw.xyzw ACC, vf09, vf00 - vars.vi07++; - m_acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | maxy.w vf13, vf13, vf01 - vars.vi04 = float_2_u32(vars.vf28.w()); - vars.vf13_root_pos_1.w() = std::max(vars.vf13_root_pos_1.w(), m_tfrag_data.fog.y()); - - // fcand vi01, 0x3ffff | maddax.xyzw ACC, vf04, vf15 - m_acc += in.vf04_cam_mat_x * vars.vf15_loop_pos_1.x(); - // fcand already calculated - - // ibeq vi00, vi01, L130 | mul.xyz vf14, vf14, Q - vars.vf14_loop_pos_0.x() *= m_q; - vars.vf14_loop_pos_0.y() *= m_q; - vars.vf14_loop_pos_0.z() *= m_q; - - // ilwr.y vi02, vi03 | mul.xyz vf26, vf26, Q - vars.vi02 = ilw_data(vars.vi03, 1); - vars.vf26.x() *= m_q; - vars.vf26.y() *= m_q; - vars.vf26.z() *= m_q; - - // nop | addw.w vf13, vf13, vf0 - if (m_clip_and_3ffff) { - vars.vf13_root_pos_1.w() += m_tfrag_data.fog.w(); - } -} - -template -void TFragment::exec_jumper_L6B0(const Prog6Inputs& in, Prog6Vars& vars) { - // nop | subz.xyz vf25, vf28, vf02 - Vector4f vf25_temp = vars.vf28 - m_tfrag_data.val.z(); - vars.vf25.x() = vf25_temp.x(); - vars.vf25.y() = vf25_temp.y(); - vars.vf25.z() = vf25_temp.z(); - - // iaddi vi07, vi07, 0x1 | mulaw.xyzw ACC, vf09, vf00 - vars.vi07++; - m_acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | maxy.w vf14, vf14, vf01 - vars.vi04 = float_2_u32(vars.vf28.w()); - vars.vf14_loop_pos_0.w() = std::max(vars.vf14_loop_pos_0.w(), m_tfrag_data.fog.y()); - - // fcand vi01, 0x3ffff | maddax.xyzw ACC, vf04, vf12 - m_acc += in.vf04_cam_mat_x * vars.vf12_root_pos_0.x(); - // fcand already calculated - - // ibeq vi00, vi01, L131 | mul.xyz vf15, vf15, Q - vars.vf15_loop_pos_1.x() *= m_q; - vars.vf15_loop_pos_1.y() *= m_q; - vars.vf15_loop_pos_1.z() *= m_q; - - // ilwr.z vi02, vi03 | mul.xyz vf27, vf27, Q - vars.vi02 = ilw_data(vars.vi03, 2); - vars.vf27.x() *= m_q; - vars.vf27.y() *= m_q; - vars.vf27.z() *= m_q; - - // nop | addw.w vf14, vf14, vf01 - if (m_clip_and_3ffff) { - vars.vf14_loop_pos_0.w() += m_tfrag_data.fog.w(); - } -} - -template -void TFragment::exec_jumper_L6BF(const Prog6Inputs& in, Prog6Vars& vars) { - // nop | subz.xyz vf26, vf28, vf02 - Vector4f vf26_temp = vars.vf28 - m_tfrag_data.val.z(); - vars.vf26.x() = vf26_temp.x(); - vars.vf26.y() = vf26_temp.y(); - vars.vf26.z() = vf26_temp.z(); - - // iaddi vi07, vi07, 0x1 | mulaw.xyzw ACC, vf09, vf00 - vars.vi07++; - m_acc = vars.vf09_cam_trans; - - // mtir vi04, vf28.w | maxy.w vf15, vf15, vf01 - vars.vi04 = float_2_u32(vars.vf28.w()); // L131 previously - assert(vars.vi04 != 0xbeef); // hit - vars.vf15_loop_pos_1.w() = std::max(vars.vf15_loop_pos_1.w(), m_tfrag_data.fog.y()); - - // fcand vi01, 0x3ffff | maddax.xyzw ACC, vf04, vf13 - m_acc += in.vf04_cam_mat_x * vars.vf13_root_pos_1.x(); - - // ibeq vi00, vi01, L132 | mul.xyz vf12, vf12, Q - vars.vf12_root_pos_0.x() *= m_q; - vars.vf12_root_pos_0.y() *= m_q; - vars.vf12_root_pos_0.z() *= m_q; - - // ilwr.w vi02, vi03 | mul.xyz vf24, vf24, Q - vars.vi02 = ilw_data(vars.vi03, 3); - vars.vf24.x() *= m_q; - vars.vf24.y() *= m_q; - vars.vf24.z() *= m_q; - - // nop | addw.w vf15, vf15, vf01 - if (m_clip_and_3ffff) { - vars.vf15_loop_pos_1.w() += m_tfrag_data.fog.w(); - } -} - -template -bool TFragment::exec_jumper_L129(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // Part 1 for X - // lq.xyzw vf15, 0(vi04) | madday.xyzw ACC, vf07, vf14 - vars.vf15_loop_pos_1 = load_vector_data(vars.vi04); - m_acc += in.vf07_cam_mat_y * vars.vf14_loop_pos_0.y(); - - // lq.xyzw vf23, 1(vi04) | maddz.xyzw vf14, vf08, vf14 - vars.vf23 = load_vector_data(vars.vi04 + 1); - vars.vf14_loop_pos_0 = m_acc + in.vf08_cam_mat_z * vars.vf14_loop_pos_0.z(); - - // sqi.xyz vf24, vi06 | add.xyzw vf13, vf13, vf10 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf24); - // fmt::print("A: vf24 store: {}\n", vars.vf24.to_string_aligned()); - vars.vi06_kick_zone_ptr++; - vars.vf13_root_pos_1 += m_tfrag_data.hvdf_offset; - - // sqi.xyzw vf20, vi06 | ftoi4.xyzw vf12, vf12 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf20); - // fmt::print("B: vf20 store: {}\n", int_vec_debug(vars.vf20)); - vars.vi06_kick_zone_ptr++; - vars.vf12_root_pos_0 = ftoi4(vars.vf12_root_pos_0); - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf15, vf15 - if (vars.vi02 < Buffer1_Start) { // HACK added - auto vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - if (float_2_u32(vf28_load_temp.w()) < Buffer1_Start) { - vars.vf28.w() = vf28_load_temp.w(); - } - } - vars.vf15_loop_pos_1 = itof0(vars.vf15_loop_pos_1); - - // div Q, vf01.x, vf14.w | mul.xyzw vf18, vf14, vf11 - m_q = m_tfrag_data.fog.x() / vars.vf14_loop_pos_0.w(); - vars.vf18_scaled_pos_2 = vars.vf14_loop_pos_0.elementwise_multiply(m_tfrag_data.hmge_scale); - - // ibeq vi05, vi06, L133 | miniz.w vf13, vf13, vf01 - bool take_branch = (vars.vi05 == vars.vi06_kick_zone_ptr); - // fmt::print("L129 prog: {} {}\n", vars.vi05, vars.vi06_kick_zone_ptr); - vars.vf13_root_pos_1.w() = std::min(vars.vf13_root_pos_1.w(), m_tfrag_data.fog.z()); - - // sqi.xyzw vf12, vi06 | clipw.xyz vf17, vf17 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf12_root_pos_0); - // fmt::print("C: vf12 store: {}\n", int_vec_debug(vars.vf12_root_pos_0)); - vars.vi06_kick_zone_ptr++; - m_clip_and_3ffff = clip_xyz_plus_minus(vars.vf17_scaled_pos_1); - - if (take_branch) { - // kick zone is full, time for another kick - return exec_jumper_L122(in, vars, render_state, prof); - } else { - return false; - } -} - -template -bool TFragment::exec_jumper_L130(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // lq.xyzw vf12, 0(vi04) | madday.xyzw ACC, vf07, vf15 - vars.vf12_root_pos_0 = load_vector_data(vars.vi04); - m_acc += in.vf07_cam_mat_y * vars.vf15_loop_pos_1.y(); - - // lq.xyzw vf20, 1(vi04) | maddz.xyzw vf15, vf08, vf15 - vars.vf20 = load_vector_data(vars.vi04 + 1); - // fmt::print("load vf20 from {}\n", vars.vi04 + 1); - vars.vf15_loop_pos_1 = m_acc + in.vf08_cam_mat_z * vars.vf15_loop_pos_1.z(); - - // sqi.xyzw vf25, vi06 | add.xyzw vf14, vf14, vf10 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf25); - // fmt::print("A: vf25 store: {}\n", vars.vf25.to_string_aligned()); - vars.vi06_kick_zone_ptr++; - vars.vf14_loop_pos_0 += m_tfrag_data.hvdf_offset; - - // sqi.xyzw vf21, vi06 | ftoi4.xyzw vf13, vf13 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf21); - // fmt::print("B: vf21 store: {}\n", int_vec_debug(vars.vf21)); - vars.vi06_kick_zone_ptr++; - vars.vf13_root_pos_1 = ftoi4(vars.vf13_root_pos_1); - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf12, vf12 - if (vars.vi02 < Buffer1_Start) { // HACK added - auto vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - if (float_2_u32(vf28_load_temp.w()) < Buffer1_Start) { - vars.vf28.w() = vf28_load_temp.w(); - } - } - - vars.vf12_root_pos_0 = itof0(vars.vf12_root_pos_0); - - // div Q, vf01.x, vf15.w | mul.xyzw vf19, vf15, vf11 - m_q = m_tfrag_data.fog.x() / vars.vf15_loop_pos_1.w(); - vars.vf19_scaled_pos_3 = vars.vf15_loop_pos_1.elementwise_multiply(m_tfrag_data.hmge_scale); - - // ibeq vi05, vi06, L134 | miniz.w vf14, vf14, vf01 - bool take_branch = (vars.vi05 == vars.vi06_kick_zone_ptr); - vars.vf14_loop_pos_0.w() = std::min(vars.vf14_loop_pos_0.w(), m_tfrag_data.fog.z()); - - // sqi.xyzw vf13, vi06 | clipw.xyz vf18, vf18 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf13_root_pos_1); - // fmt::print("C: vf13 store: {}\n", int_vec_debug(vars.vf13_root_pos_1)); - vars.vi06_kick_zone_ptr++; - m_clip_and_3ffff = clip_xyz_plus_minus(vars.vf18_scaled_pos_2); - - if (take_branch) { - // kick zone is full, time for another kick - return exec_jumper_L122(in, vars, render_state, prof); - } else { - return false; - } -} - -template -bool TFragment::exec_jumper_L131(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // lq.xyzw vf13, 0(vi04) | madday.xyzw ACC, vf07, vf12 - vars.vf13_root_pos_1 = load_vector_data(vars.vi04); - m_acc += in.vf07_cam_mat_y * vars.vf12_root_pos_0.y(); - - // lq.xyzw vf21, 1(vi04) | maddz.xyzw vf12, vf08, vf12 - vars.vf21 = load_vector_data(vars.vi04 + 1); - // fmt::print("vf21 load from: {}\n", vars.vi04 + 1); - vars.vf12_root_pos_0 = m_acc + in.vf08_cam_mat_z * vars.vf12_root_pos_0.z(); - - // sqi.xyzw vf26, vi06 | add.xyzw vf15, vf15, vf10 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf26); - // fmt::print("A: vf26 store: {}\n", vars.vf26.to_string_aligned()); - vars.vi06_kick_zone_ptr++; - vars.vf15_loop_pos_1 += m_tfrag_data.hvdf_offset; - - // sqi.xyzw vf22, vi06 | ftoi4.xyzw vf14, vf14 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf22); - // fmt::print("B: vf22 store: {}\n", int_vec_debug(vars.vf22)); - vars.vi06_kick_zone_ptr++; - vars.vf14_loop_pos_0 = ftoi4(vars.vf14_loop_pos_0); - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf13, vf13 - if (vars.vi02 < Buffer1_Start) { // HACK added - auto vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - if (float_2_u32(vf28_load_temp.w()) < Buffer1_Start) { - vars.vf28.w() = vf28_load_temp.w(); - } - } - vars.vf13_root_pos_1 = itof0(vars.vf13_root_pos_1); - - // div Q, vf01.x, vf12.w | mul.xyzw vf16, vf12, vf11 - m_q = m_tfrag_data.fog.x() / vars.vf12_root_pos_0.w(); - vars.vf16_scaled_pos_0 = vars.vf12_root_pos_0.elementwise_multiply(m_tfrag_data.hmge_scale); - - // ibeq vi05, vi06, L135 | miniz.w vf15, vf15, vf01 - bool take_branch = (vars.vi05 == vars.vi06_kick_zone_ptr); - vars.vf15_loop_pos_1.w() = std::min(vars.vf15_loop_pos_1.w(), m_tfrag_data.fog.z()); - - // sqi.xyzw vf14, vi06 | clipw.xyz vf19, vf19 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf14_loop_pos_0); - // fmt::print("C: vf14 store: {}\n", int_vec_debug(vars.vf14_loop_pos_0)); - vars.vi06_kick_zone_ptr++; - m_clip_and_3ffff = clip_xyz_plus_minus(vars.vf19_scaled_pos_3); - - if (take_branch) { - // kick zone is full, time for another kick - return exec_jumper_L122(in, vars, render_state, prof); - } else { - return false; - } -} - -template -bool TFragment::exec_jumper_L132(const Prog6Inputs& in, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // lq.xyzw vf14, 0(vi04) | madday.xyzw ACC, vf07, vf13 - vars.vf14_loop_pos_0 = load_vector_data(vars.vi04); // bad here, in L0x6BF_PART0_W prev - m_acc += in.vf07_cam_mat_y * vars.vf13_root_pos_1.y(); - - // lq.xyzw vf22, 1(vi04) | maddz.xyzw vf13, vf08, vf13 - vars.vf22 = load_vector_data(vars.vi04 + 1); - vars.vf13_root_pos_1 = m_acc + in.vf08_cam_mat_z * vars.vf13_root_pos_1.z(); - - // sqi.xyzw vf27, vi06 | add.xyzw vf12, vf12, vf10 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf27); - // fmt::print("A: vf27 store: {}\n", vars.vf27.to_string_aligned()); - vars.vi06_kick_zone_ptr++; - vars.vf12_root_pos_0 += m_tfrag_data.hvdf_offset; - - // sqi.xyzw vf23, vi06 | ftoi4.xyzw vf15, vf15 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf23); - // fmt::print("B: vf23 store: {}\n", int_vec_debug(vars.vf23)); - vars.vi06_kick_zone_ptr++; - vars.vf15_loop_pos_1 = ftoi4(vars.vf15_loop_pos_1); - - // lq.xyw vf28, 0(vi02) | itof0.xyzw vf14, vf14 - if (vars.vi02 < Buffer1_Start) { // HACK added - auto vf28_load_temp = load_vector_data(vars.vi02); - vars.vf28.x() = vf28_load_temp.x(); - vars.vf28.y() = vf28_load_temp.y(); - if (float_2_u32(vf28_load_temp.w()) < Buffer1_Start) { - vars.vf28.w() = vf28_load_temp.w(); - } - } - vars.vf14_loop_pos_0 = itof0(vars.vf14_loop_pos_0); - - // div Q, vf01.x, vf13.w | mul.xyzw vf17, vf13, vf11 - m_q = m_tfrag_data.fog.x() / vars.vf13_root_pos_1.w(); - vars.vf17_scaled_pos_1 = vars.vf13_root_pos_1.elementwise_multiply(m_tfrag_data.hmge_scale); - - // ibne vi05, vi06, L128 | miniz.w vf12, vf12, vf01 - bool take_branch = (vars.vi05 != vars.vi06_kick_zone_ptr); - // fmt::print("kick check: {} {}\n", vars.vi05, vars.vi06_kick_zone_ptr); - vars.vf12_root_pos_0.w() = std::min(vars.vf12_root_pos_0.w(), m_tfrag_data.fog.z()); - - // sqi.xyzw vf15, vi06 | clipw.xyz vf16, vf16 - store_vector_kick_zone(vars.vi06_kick_zone_ptr, vars.vf15_loop_pos_1); - vars.vi06_kick_zone_ptr++; - // fmt::print("C: vf15 store: {}\n", int_vec_debug(vars.vf15_loop_pos_1)); - m_clip_and_3ffff = clip_xyz_plus_minus(vars.vf16_scaled_pos_0); - - if (take_branch) { - return false; - } else { - // kick zone is full, kick then restart - return exec_jumper_L122(in, vars, render_state, prof); - } - - // b L122 | nop - // iaddiu vi15, vi00, 0x692 | nop ;; L128 -} - -template -bool TFragment::exec_jumper_L122(const Prog6Inputs& /*in*/, - Prog6Vars& vars, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // KICK ZONE! - // L122: - // fcset 0x0 - m_clip_and_3ffff = false; // ?? - // iaddi vi07, vi00, -0x1 - vars.vi07 = -1; - // fmt::print("KICK blocks: vi12 = 0x{:x}\n", vars.vi12); - // iblez vi12, L123 - // iaddi vi09, vi09, 0x1 - vars.vi09++; - // fmt::print("VI09 now {}\n", vars.vi09); - if (((s16)vars.vi12) > 0) { - // ior vi10, vi06, vi00 - vars.vi10 = vars.vi06_kick_zone_ptr; - // iadd vi01, vi12, vi12 - m_ptrs.vi01 = vars.vi12 + vars.vi12; - // iadd vi01, vi01, vi12 - m_ptrs.vi01 += vars.vi12; - // iadd vi05, vi06, vi01 - vars.vi05 = vars.vi06_kick_zone_ptr + m_ptrs.vi01; - // sqi.xyzw vf06, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr, m_tfrag_data.str_gif); - vars.vi06_kick_zone_ptr++; - // isw.x vi12, -1(vi06) - store_u32_kick_zone(vars.vi12, vars.vi06_kick_zone_ptr - 1, 0); - // jr vi15 - // ilwr.x vi12, vi09 - vars.vi12 = ilw_data(vars.vi09, 0); - // fmt::print("didn't kick, vi12 now {}\n", vars.vi12); - m_next_block = m_ret_block; - - return false; - } - - // L123: - // ilw.y vi01, -1(vi09) - m_ptrs.vi01 = ilw_data(vars.vi09 - 1, 1); - // ilw.z vi13, -1(vi09) - vars.vi13 = ilw_data(vars.vi09 - 1, 2); - // fmt::print("VI09 loads: {} {}\n", m_ptrs.vi01, vars.vi13); - // ibeq vi00, vi12, L126 - // ilwr.x vi14, vi10 - // fmt::print("val is {}: {}\n", vars.vi10, ilw_kick_zone(vars.vi10, 0)); - vars.vi14 = ilw_kick_zone(vars.vi10, 0); - if (vars.vi12 != 0) { - // ibltz vi01, L124 - // iaddiu vi12, vi12, 0x80 - vars.vi12 += 0x80; - if (((s16)m_ptrs.vi01) >= 0) { - // iadd vi13, vi13, vi08 - vars.vi13 += vars.vi08; - if (DEBUG) { - fmt::print("vi13 = {}, (after adding {})\n", vars.vi13, vars.vi08); - } - // lqi.xyzw vf29, vi13 - vars.vf29 = load_vector_data(vars.vi13++); - // lqi.xyzw vf30, vi13 - vars.vf30 = load_vector_data(vars.vi13++); - // lqi.xyzw vf31, vi13 - vars.vf31 = load_vector_data(vars.vi13++); - // sqi.xyzw vf05, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr++, m_tfrag_data.ad_gif); - // sqi.xyzw vf29, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf29); - if (DEBUG) { - fmt::print("ad (0): {}", debug_print_ad_vec(vars.vf29)); - } - // sqi.xyzw vf30, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf30); - if (DEBUG) { - fmt::print("ad (1): {}", debug_print_ad_vec(vars.vf30)); - } - // sqi.xyzw vf31, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf31); - if (DEBUG) { - fmt::print("ad (2): {}", debug_print_ad_vec(vars.vf31)); - } - // lqi.xyzw vf29, vi13 - vars.vf29 = load_vector_data(vars.vi13++); - // lqi.xyzw vf30, vi13 - vars.vf30 = load_vector_data(vars.vi13++); - // iadd vi01, vi12, vi12 - m_ptrs.vi01 = vars.vi12 + vars.vi12; - // iadd vi01, vi01, vi12 - m_ptrs.vi01 += vars.vi12; - // sqi.xyzw vf29, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf29); - if (DEBUG) { - fmt::print("ad (3): {}", debug_print_ad_vec(vars.vf29)); - } - // sqi.xyzw vf30, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf30); - if (DEBUG) { - fmt::print("ad (4): {}", debug_print_ad_vec(vars.vf30)); - } - // ior vi10, vi06, vi00 - vars.vi10 = vars.vi06_kick_zone_ptr; - // iadd vi05, vi06, vi01 - vars.vi05 = vars.vi06_kick_zone_ptr + m_ptrs.vi01; - // sqi.xyzw vf06, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr++, m_tfrag_data.str_gif); - // isw.x vi12, -1(vi06) - store_u32_kick_zone(vars.vi12, vars.vi06_kick_zone_ptr - 1, 0); - // jr vi15 - // ilwr.x vi12, vi09 - vars.vi12 = ilw_data(vars.vi09, 0); - // fmt::print("didn't kick 2, vi12 now {}\n", vars.vi12); - m_next_block = m_ret_block; - return false; - } - - // L124: - // mtir vi01, vf24.w - m_ptrs.vi01 = float_2_u32(vars.vf24.w()); - // mtir vi06, vf03.y - vars.vi06_kick_zone_ptr = m_ptrs.vf03_y; - // mr32.xyzw vf03, vf03 - auto temp = m_ptrs.vf03_x; - m_ptrs.vf03_x = m_ptrs.vf03_y; - m_ptrs.vf03_y = m_ptrs.vf03_z; - m_ptrs.vf03_z = m_ptrs.vf03_w; - m_ptrs.vf03_w = temp; - - // iadd vi14, vi14, vi11 - vars.vi14 += vars.vi11; - - // ibgez vi13, L125 - // iswr.x vi14, vi10 - // fmt::print("kick zone store: {}\n", vars.vi14); - store_u32_kick_zone(vars.vi14, vars.vi10, 0); - if (((s16)vars.vi13) < 0) { - // xgkick vi01 - XGKICK(m_ptrs.vi01, render_state, prof); - // ior vi10, vi06, vi00 - vars.vi10 = vars.vi06_kick_zone_ptr; // xgkick delay slots, doesn't seem to matter. - // mfir.w vf24, vi06 - vars.vf24.w() = u32_2_float(vars.vi06_kick_zone_ptr); - // iadd vi01, vi12, vi12 - m_ptrs.vi01 = vars.vi12 + vars.vi12; - // iadd vi01, vi01, vi12 - m_ptrs.vi01 += vars.vi12; - // iadd vi05, vi06, vi01 - vars.vi05 = vars.vi06_kick_zone_ptr + m_ptrs.vi01; - // sqi.xyzw vf06, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr++, m_tfrag_data.str_gif); - // isw.x vi12, -1(vi06) - store_u32_kick_zone(vars.vi12, vars.vi06_kick_zone_ptr - 1, 0); - // jr vi15 - // ilwr.x vi12, vi09 - vars.vi12 = ilw_data(vars.vi09, 0); - // fmt::print("didn't kick 3, vi12 now {}\n", vars.vi12); - m_next_block = m_ret_block; - return false; - } - - // L125: - // iadd vi13, vi13, vi08 - vars.vi13 += vars.vi08; - // xgkick vi01 - XGKICK(m_ptrs.vi01, render_state, prof); - // lqi.xyzw vf29, vi13 - vars.vf29 = load_vector_data(vars.vi13++); - // lqi.xyzw vf30, vi13 - vars.vf30 = load_vector_data(vars.vi13++); - // lqi.xyzw vf31, vi13 - vars.vf31 = load_vector_data(vars.vi13++); - // mfir.w vf24, vi06 - vars.vf24.w() = u32_2_float(vars.vi06_kick_zone_ptr); - // sqi.xyzw vf05, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr++, m_tfrag_data.ad_gif); - // sqi.xyzw vf29, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf29); - if (DEBUG) { - fmt::print("ad (0): {}", debug_print_ad_vec(vars.vf29)); - } - // sqi.xyzw vf30, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf30); - if (DEBUG) { - fmt::print("ad (1): {}", debug_print_ad_vec(vars.vf30)); - } - // sqi.xyzw vf31, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf31); - if (DEBUG) { - fmt::print("ad (2): {}", debug_print_ad_vec(vars.vf31)); - } - // lqi.xyzw vf29, vi13 - vars.vf29 = load_vector_data(vars.vi13++); - // lqi.xyzw vf30, vi13 - vars.vf30 = load_vector_data(vars.vi13++); - // iadd vi01, vi12, vi12 - m_ptrs.vi01 = vars.vi12 + vars.vi12; - // iadd vi01, vi01, vi12 - m_ptrs.vi01 += vars.vi12; - // sqi.xyzw vf29, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf29); - if (DEBUG) { - fmt::print("ad (3): {}", debug_print_ad_vec(vars.vf29)); - } - // sqi.xyzw vf30, vi06 - store_vector_kick_zone(vars.vi06_kick_zone_ptr++, vars.vf30); - if (DEBUG) { - fmt::print("ad (4): {}", debug_print_ad_vec(vars.vf30)); - } - // nop - // ior vi10, vi06, vi00 - vars.vi10 = vars.vi06_kick_zone_ptr; - // iadd vi05, vi06, vi01 - vars.vi05 = vars.vi06_kick_zone_ptr + m_ptrs.vi01; - // sqi.xyzw vf06, vi06 - store_gif_kick_zone(vars.vi06_kick_zone_ptr++, m_tfrag_data.str_gif); - // isw.x vi12, -1(vi06) - store_u32_kick_zone(vars.vi12, vars.vi06_kick_zone_ptr - 1, 0); - // jr vi15 - // ilwr.x vi12, vi09 - vars.vi12 = ilw_data(vars.vi09, 0); - // fmt::print("did kick, vi12 now {}\n", vars.vi12); - m_next_block = m_ret_block; - return false; - } - - // L126: - // mtir vi01, vf24.w - m_ptrs.vi01 = float_2_u32(vars.vf24.w()); - // mr32.xyzw vf03, vf03 - auto temp = m_ptrs.vf03_x; - m_ptrs.vf03_x = m_ptrs.vf03_y; - m_ptrs.vf03_y = m_ptrs.vf03_z; - m_ptrs.vf03_z = m_ptrs.vf03_w; - m_ptrs.vf03_w = temp; - // iadd vi14, vi14, vi11 - // fmt::print("before add: {}\n", vars.vi14); - vars.vi14 += vars.vi11; - // iswr.x vi14, vi10 - // fmt::print("kick zone store: {}\n", vars.vi14); - store_u32_kick_zone(vars.vi14, vars.vi10, 0); - // lq.xyzw vf04, 664(vi00) - // todo don't think I needed that load of ambient - XGKICK(m_ptrs.vi01, render_state, prof); - // xgkick vi01 - // nop | nop :e - m_next_block = END_PROGRAM; - return true; - - // nop | nop -} - -template -void TFragment::XGKICK(u32 addr, SharedRenderState* render_state, ScopedProfilerNode& prof) { - if (DEBUG) { - ImGui::Text("XGKICK: %d", addr); - } - - assert(addr >= TFragDataMem::TFragKickZoneData); - assert(addr < KICK_ZONE_END); - - if (!m_skip_xgkick) { - if (m_use_buffered_renderer) { - m_buffered_renderer.add_gif_data( - &m_kick_data.pad[(addr - TFragDataMem::TFragKickZoneData) * 16]); - } else { - m_direct_renderer.render_gif(&m_kick_data.pad[(addr - TFragDataMem::TFragKickZoneData) * 16], - UINT32_MAX, render_state, prof); - } - } -} - -template void TFragment::exec_program_6(SharedRenderState* render_state, - ScopedProfilerNode& prof); -template void TFragment::exec_program_6(SharedRenderState* render_state, - ScopedProfilerNode& prof); \ No newline at end of file diff --git a/game/graphics/opengl_renderer/tfrag/tfrag_unpack.cpp b/game/graphics/opengl_renderer/tfrag/tfrag_unpack.cpp deleted file mode 100644 index a6648f7817..0000000000 --- a/game/graphics/opengl_renderer/tfrag/tfrag_unpack.cpp +++ /dev/null @@ -1,240 +0,0 @@ -#include "game/graphics/opengl_renderer/tfrag/TFragment.h" - -// TFragment VIF unpack implementation - -int TFragment::handle_unpack_v4_8_mode0(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - - // CL x (num/WL)+(num%WL) - - u8* write_base = get_upload_buffer(); - - if (unpack.is_unsigned) { - // note: formulas below assume this! - assert(cl == 2); - assert(wl == 1); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + 2 * i; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = dma.read_val(offset++); - qw[1] = dma.read_val(offset++); - qw[2] = dma.read_val(offset++); - qw[3] = dma.read_val(offset++); - memcpy(write_base + (dest_qw * 16), qw, 16); - } - } else { - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - s32 qw[4]; - qw[0] = dma.read_val(offset++); - qw[1] = dma.read_val(offset++); - qw[2] = dma.read_val(offset++); - qw[3] = dma.read_val(offset++); - memcpy(write_base + (dest_qw * 16), qw, 16); - } - } - - return offset; -} - -int TFragment::handle_unpack_v4_8_mode1(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl, - const u32 row[4]) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - - // CL x (num/WL)+(num%WL) - - u8* write_base = get_upload_buffer(); - - if (unpack.is_unsigned) { - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = row[0] + dma.read_val(offset++); - qw[1] = row[1] + dma.read_val(offset++); - qw[2] = row[2] + dma.read_val(offset++); - qw[3] = row[3] + dma.read_val(offset++); - memcpy(write_base + (dest_qw * 16), qw, 16); - } - } else { - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - s32 qw[4]; - qw[0] = row[0] + dma.read_val(offset++); - qw[1] = row[1] + dma.read_val(offset++); - qw[2] = row[2] + dma.read_val(offset++); - qw[3] = row[3] + dma.read_val(offset++); - memcpy(write_base + (dest_qw * 16), qw, 16); - } - } - - return offset; -} - -int TFragment::handle_unpack_v4_16_mode0(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - assert(unpack.is_unsigned); - - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - - u8* write_base = get_upload_buffer(); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = dma.read_val(offset); - offset += 2; - qw[1] = dma.read_val(offset); - offset += 2; - qw[2] = dma.read_val(offset); - offset += 2; - qw[3] = dma.read_val(offset); - offset += 2; - memcpy(write_base + (dest_qw * 16), qw, 16); - } - return offset; -} - -int TFragment::handle_unpack_v4_16_mode1(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl, - const u32 row[4]) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - assert(unpack.is_unsigned); - - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - - assert(code.num); - u8* write_base = get_upload_buffer(); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = row[0] + (u32)dma.read_val(offset); - offset += 2; - qw[1] = row[1] + (u32)dma.read_val(offset); - offset += 2; - qw[2] = row[2] + (u32)dma.read_val(offset); - offset += 2; - qw[3] = row[3] + (u32)dma.read_val(offset); - offset += 2; - - // fmt::print(" unpack rgba?: {:x} {:x} {:x} {:x}\n", qw[0], qw[1], qw[2], qw[3]); - memcpy(write_base + (dest_qw * 16), qw, 16); - } - return offset; -} - -int TFragment::handle_unpack_v3_32(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - assert(!unpack.is_unsigned); - - // note: formulas below assume this! - assert(cl == 2); - assert(wl == 1); - - assert(code.num); - u8* write_base = get_upload_buffer(); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i * 2; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = dma.read_val(offset); - offset += 4; - qw[1] = dma.read_val(offset); - offset += 4; - qw[2] = dma.read_val(offset); - offset += 4; - qw[3] = 0x80; // this can be anything... but it seems like it tries to load from it sometimes? - memcpy(write_base + (dest_qw * 16), qw, 16); - } - return offset; -} - -int TFragment::handle_unpack_v4_32(const VifCode& code, - const DmaTransfer& dma, - int offset, - int cl, - int wl) { - VifCodeUnpack unpack(code); - assert(unpack.use_tops_flag); - assert(!unpack.is_unsigned); - - // note: formulas below assume this! - assert(cl == 4); - assert(wl == 4); - u8* write_base = get_upload_buffer(); - assert(code.num); - for (int i = 0; i < code.num; i++) { - // write every other qw - int dest_qw = unpack.addr_qw + i; - assert(dest_qw <= 328); - u32 qw[4]; - qw[0] = dma.read_val(offset); - offset += 4; - qw[1] = dma.read_val(offset); - offset += 4; - qw[2] = dma.read_val(offset); - offset += 4; - qw[3] = dma.read_val(offset); - offset += 4; - memcpy(write_base + (dest_qw * 16), qw, 16); - } - return offset; - - // u8* write_base = get_upload_buffer(); - // assert(code.num + unpack.addr_qw <= 328); - // memcpy(write_base + (unpack.addr_qw * 16), dma.data + offset, code.num * 16); - // return offset + code.num * 16; -}