From d208ceddce0364cf74fca849dd9afdd81ec2e3f7 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 26 Mar 2023 15:41:10 -0400 Subject: [PATCH] [jak2] fix enter-state and sprite crash (#2428) Fixes https://github.com/open-goal/jak-project/issues/2426 and other sprite crashes with the `HUD` address assert. Doesn't fix the other sprite issues. Fixes https://github.com/open-goal/jak-project/issues/2427 Also removes the old sprite renderer, which doesn't work. --- game/CMakeLists.txt | 1 - .../opengl_renderer/OpenGLRenderer.cpp | 9 +- .../opengl_renderer/sprite/Sprite3.cpp | 12 +- .../opengl_renderer/sprite/SpriteRenderer.cpp | 727 ------------------ .../opengl_renderer/sprite/SpriteRenderer.h | 163 ---- .../opengl_renderer/sprite/sprite_common.h | 9 +- goal_src/jak2/kernel/gstate.gc | 1 + 7 files changed, 18 insertions(+), 904 deletions(-) delete mode 100644 game/graphics/opengl_renderer/sprite/SpriteRenderer.cpp delete mode 100644 game/graphics/opengl_renderer/sprite/SpriteRenderer.h diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 8cd000030b..2b46b552cb 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -137,7 +137,6 @@ set(RUNTIME_SOURCE graphics/opengl_renderer/sprite/Sprite3.cpp graphics/opengl_renderer/sprite/Sprite3_Distort.cpp graphics/opengl_renderer/sprite/Sprite3_Glow.cpp - graphics/opengl_renderer/sprite/SpriteRenderer.cpp graphics/opengl_renderer/ocean/CommonOceanRenderer.cpp graphics/opengl_renderer/ocean/OceanMid.cpp graphics/opengl_renderer/ocean/OceanMid_PS2.cpp diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 9b85168d32..b4bc6513e3 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -21,7 +21,6 @@ #include "game/graphics/opengl_renderer/ocean/OceanMidAndFar.h" #include "game/graphics/opengl_renderer/ocean/OceanNear.h" #include "game/graphics/opengl_renderer/sprite/Sprite3.h" -#include "game/graphics/opengl_renderer/sprite/SpriteRenderer.h" #include "game/graphics/pipelines/opengl.h" #include "third-party/imgui/imgui.h" @@ -445,13 +444,7 @@ void OpenGLRenderer::init_bucket_renderers_jak1() { init_bucket_renderer("common-tex", BucketCategory::TEX, BucketId::PRE_SPRITE_TEX); // 65 - std::vector> sprite_renderers; - // the first renderer added will be the default for sprite. - sprite_renderers.push_back(std::make_unique("sprite-3", (int)BucketId::SPRITE)); - sprite_renderers.push_back( - std::make_unique("sprite-renderer", (int)BucketId::SPRITE)); - init_bucket_renderer("sprite", BucketCategory::SPRITE, BucketId::SPRITE, - std::move(sprite_renderers)); // 66 + init_bucket_renderer("sprite", BucketCategory::SPRITE, BucketId::SPRITE); // 66 init_bucket_renderer("debug", BucketCategory::OTHER, BucketId::DEBUG, 0x20000); init_bucket_renderer("debug-no-zbuf", BucketCategory::OTHER, diff --git a/game/graphics/opengl_renderer/sprite/Sprite3.cpp b/game/graphics/opengl_renderer/sprite/Sprite3.cpp index 65ff18f8b1..a9bef12c16 100644 --- a/game/graphics/opengl_renderer/sprite/Sprite3.cpp +++ b/game/graphics/opengl_renderer/sprite/Sprite3.cpp @@ -337,7 +337,17 @@ void Sprite3::render_2d_group1(DmaFollower& dma, auto run = dma.read_and_advance(); ASSERT(run.vifcode0().kind == VifCode::Kind::NOP); ASSERT(run.vifcode1().kind == VifCode::Kind::MSCAL); - ASSERT(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud); + + switch (render_state->version) { + case GameVersion::Jak1: + ASSERT(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud_Jak1); + break; + case GameVersion::Jak2: + ASSERT(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud_Jak2); + break; + default: + ASSERT_NOT_REACHED(); + } if (m_enabled && m_2d_enable) { do_block_common(SpriteMode::ModeHUD, sprite_count, render_state, prof); } diff --git a/game/graphics/opengl_renderer/sprite/SpriteRenderer.cpp b/game/graphics/opengl_renderer/sprite/SpriteRenderer.cpp deleted file mode 100644 index 659bcf8049..0000000000 --- a/game/graphics/opengl_renderer/sprite/SpriteRenderer.cpp +++ /dev/null @@ -1,727 +0,0 @@ -#include "SpriteRenderer.h" - -#include "common/log/log.h" - -#include "game/graphics/opengl_renderer/background/background_common.h" -#include "game/graphics/opengl_renderer/dma_helpers.h" - -#include "third-party/fmt/core.h" -#include "third-party/imgui/imgui.h" - -namespace { - -/*! - * Does the next DMA transfer look like it could be the start of a 2D group? - */ -bool looks_like_2d_chunk_start(const DmaFollower& dma) { - return dma.current_tag().qwc == 1 && dma.current_tag().kind == DmaTag::Kind::CNT; -} - -/*! - * Read the header. Asserts if it's bad. - * Returns the number of sprites. - * Advances 1 dma transfer - */ -u32 process_sprite_chunk_header(DmaFollower& dma) { - auto transfer = dma.read_and_advance(); - // note that flg = true, this should use double buffering - bool ok = verify_unpack_with_stcycl(transfer, VifCode::Kind::UNPACK_V4_32, 4, 4, 1, - SpriteDataMem::Header, false, true); - ASSERT(ok); - u32 header[4]; - memcpy(header, transfer.data, 16); - ASSERT(header[0] <= SpriteRenderer::SPRITES_PER_CHUNK); - return header[0]; -} -} // namespace - -constexpr int SPRITE_RENDERER_MAX_SPRITES = 8000; - -SpriteRenderer::SpriteRenderer(const std::string& name, int my_id) : BucketRenderer(name, my_id) { - glGenBuffers(1, &m_ogl.vertex_buffer); - glGenVertexArrays(1, &m_ogl.vao); - glBindVertexArray(m_ogl.vao); - glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - auto verts = SPRITE_RENDERER_MAX_SPRITES * 3 * 2; - auto bytes = verts * sizeof(SpriteVertex3D); - glBufferData(GL_ARRAY_BUFFER, bytes, nullptr, GL_STREAM_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, // location 0 in the shader - 4, // 4 floats per vert (w unused) - GL_FLOAT, // floats - GL_TRUE, // normalized, ignored, - sizeof(SpriteVertex3D), // - (void*)offsetof(SpriteVertex3D, xyz_sx) // offset in array (why is this a pointer...) - ); - - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, // location 0 in the shader - 4, // 4 color components - GL_FLOAT, // floats - GL_TRUE, // normalized, ignored, - sizeof(SpriteVertex3D), // - (void*)offsetof(SpriteVertex3D, quat_sy) // offset in array (why is this a pointer...) - ); - - glEnableVertexAttribArray(2); - glVertexAttribPointer( - 2, // location 0 in the shader - 4, // 4 color components - GL_FLOAT, // floats - GL_TRUE, // normalized, ignored, - sizeof(SpriteVertex3D), // - (void*)offsetof(SpriteVertex3D, rgba) // offset in array (why is this a pointer...) - ); - - glEnableVertexAttribArray(3); - glVertexAttribIPointer( - 3, // location 0 in the shader - 2, // 4 color components - GL_UNSIGNED_SHORT, // floats - sizeof(SpriteVertex3D), // - (void*)offsetof(SpriteVertex3D, flags_matrix) // offset in array (why is this a pointer...) - ); - - glEnableVertexAttribArray(4); - glVertexAttribIPointer( - 4, // location 0 in the shader - 4, // 3 floats per vert - GL_UNSIGNED_SHORT, // floats - sizeof(SpriteVertex3D), // - (void*)offsetof(SpriteVertex3D, info) // offset in array (why is this a pointer...) - ); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - - m_vertices_3d.resize(verts); -} - -/*! - * Run the sprite distorter. Currently nothing uses sprite-distorter so this just skips through - * the table upload stuff that runs every frame, even if there are no sprites. - */ -void SpriteRenderer::render_distorter(DmaFollower& dma, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - // Next thing should be the sprite-distorter setup - // m_direct_renderer.reset_state(); - while (dma.current_tag().qwc != 7) { - dma.read_and_advance(); - // m_direct_renderer.render_vif(direct_data.vif0(), direct_data.vif1(), direct_data.data, - // direct_data.size_bytes, render_state, prof); - } - // m_direct_renderer.flush_pending(render_state, prof); - auto sprite_distorter_direct_setup = dma.read_and_advance(); - ASSERT(sprite_distorter_direct_setup.vifcode0().kind == VifCode::Kind::NOP); - ASSERT(sprite_distorter_direct_setup.vifcode1().kind == VifCode::Kind::DIRECT); - ASSERT(sprite_distorter_direct_setup.vifcode1().immediate == 7); - memcpy(m_sprite_distorter_setup, sprite_distorter_direct_setup.data, 7 * 16); - - // Next thing should be the sprite-distorter tables - auto sprite_distorter_tables = dma.read_and_advance(); - ASSERT(sprite_distorter_tables.size_bytes == 0x8b * 16); - ASSERT(sprite_distorter_tables.vifcode0().kind == VifCode::Kind::STCYCL); - VifCodeStcycl distorter_table_transfer(sprite_distorter_tables.vifcode0()); - ASSERT(distorter_table_transfer.cl == 4); - ASSERT(distorter_table_transfer.wl == 4); - // TODO: check unpack cmd (vif1) - - // TODO: do something with the table - - // next would be the program, but we don't have it. - - // TODO: next is the sprite-distorter (currently not used) -} - -/*! - * Handle DMA data that does the per-frame setup. - * This should get the dma chain immediately after the call to sprite-draw-distorters. - * It ends right before the sprite-add-matrix-data for the 3d's - */ -void SpriteRenderer::handle_sprite_frame_setup(DmaFollower& dma) { - // first is some direct data - auto direct_data = dma.read_and_advance(); - ASSERT(direct_data.size_bytes == 3 * 16); - memcpy(m_sprite_direct_setup, direct_data.data, 3 * 16); - - // next would be the program, but it's 0 size on the PC and isn't sent. - - // next is the "frame data" - auto frame_data = dma.read_and_advance(); - ASSERT(frame_data.size_bytes == (int)sizeof(SpriteFrameData)); // very cool - ASSERT(frame_data.vifcode0().kind == VifCode::Kind::STCYCL); - VifCodeStcycl frame_data_stcycl(frame_data.vifcode0()); - ASSERT(frame_data_stcycl.cl == 4); - ASSERT(frame_data_stcycl.wl == 4); - ASSERT(frame_data.vifcode1().kind == VifCode::Kind::UNPACK_V4_32); - VifCodeUnpack frame_data_unpack(frame_data.vifcode1()); - ASSERT(frame_data_unpack.addr_qw == SpriteDataMem::FrameData); - ASSERT(frame_data_unpack.use_tops_flag == false); - memcpy(&m_frame_data, frame_data.data, sizeof(SpriteFrameData)); - - // next, a MSCALF. - auto mscalf = dma.read_and_advance(); - ASSERT(mscalf.size_bytes == 0); - ASSERT(mscalf.vifcode0().kind == VifCode::Kind::MSCALF); - ASSERT(mscalf.vifcode0().immediate == SpriteProgMem::Init); - ASSERT(mscalf.vifcode1().kind == VifCode::Kind::FLUSHE); - - // next base and offset - auto base_offset = dma.read_and_advance(); - ASSERT(base_offset.size_bytes == 0); - ASSERT(base_offset.vifcode0().kind == VifCode::Kind::BASE); - ASSERT(base_offset.vifcode0().immediate == SpriteDataMem::Buffer0); - ASSERT(base_offset.vifcode1().kind == VifCode::Kind::OFFSET); - ASSERT(base_offset.vifcode1().immediate == SpriteDataMem::Buffer1); -} - -void SpriteRenderer::render_3d(DmaFollower& dma) { - // one time matrix data - auto matrix_data = dma.read_and_advance(); - ASSERT(matrix_data.size_bytes == sizeof(Sprite3DMatrixData)); - - bool unpack_ok = verify_unpack_with_stcycl(matrix_data, VifCode::Kind::UNPACK_V4_32, 4, 4, 5, - SpriteDataMem::Matrix, false, false); - ASSERT(unpack_ok); - static_assert(sizeof(m_3d_matrix_data) == 5 * 16); - memcpy(&m_3d_matrix_data, matrix_data.data, sizeof(m_3d_matrix_data)); - // TODO -} - -void SpriteRenderer::render_2d_group0(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // opengl sprite frame setup - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "hvdf_offset"), 1, - m_3d_matrix_data.hvdf_offset.data()); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "pfog0"), - m_frame_data.pfog0); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "min_scale"), - m_frame_data.min_scale); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "max_scale"), - m_frame_data.max_scale); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "fog_min"), - m_frame_data.fog_min); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "fog_max"), - m_frame_data.fog_max); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "bonus"), - m_frame_data.bonus); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "hmge_scale"), 1, - m_frame_data.hmge_scale.data()); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "deg_to_rad"), - m_frame_data.deg_to_rad); - glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "inv_area"), - m_frame_data.inv_area); - glUniformMatrix4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "camera"), - 1, GL_FALSE, m_3d_matrix_data.camera.data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "xy_array"), 8, - m_frame_data.xy_array[0].data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "xyz_array"), 4, - m_frame_data.xyz_array[0].data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "st_array"), 4, - m_frame_data.st_array[0].data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "basis_x"), 1, - m_frame_data.basis_x.data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "basis_y"), 1, - m_frame_data.basis_y.data()); - - u16 last_prog = -1; - - while (looks_like_2d_chunk_start(dma)) { - m_debug_stats.blocks_2d_grp0++; - // 4 packets per chunk - - // first is the header - u32 sprite_count = process_sprite_chunk_header(dma); - m_debug_stats.count_2d_grp0 += sprite_count; - - // second is the vector data - u32 expected_vec_size = sizeof(SpriteVecData2d) * sprite_count; - auto vec_data = dma.read_and_advance(); - ASSERT(expected_vec_size <= sizeof(m_vec_data_2d)); - unpack_to_no_stcycl(&m_vec_data_2d, vec_data, VifCode::Kind::UNPACK_V4_32, expected_vec_size, - SpriteDataMem::Vector, false, true); - - // third is the adgif data - u32 expected_adgif_size = sizeof(AdGifData) * sprite_count; - auto adgif_data = dma.read_and_advance(); - ASSERT(expected_adgif_size <= sizeof(m_adgif)); - unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size, - SpriteDataMem::Adgif, false, true); - - // fourth is the actual run!!!!! - auto run = dma.read_and_advance(); - ASSERT(run.vifcode0().kind == VifCode::Kind::NOP); - ASSERT(run.vifcode1().kind == VifCode::Kind::MSCAL); - - if (m_enabled) { - if (run.vifcode1().immediate != last_prog) { - // one-time setups and flushing - flush_sprites(render_state, prof); - if (run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0 && - m_prim_gl_state.current_register != m_frame_data.sprite_2d_giftag.prim()) { - m_prim_gl_state.from_register(m_frame_data.sprite_2d_giftag.prim()); - } else if (m_prim_gl_state.current_register != m_frame_data.sprite_3d_giftag.prim()) { - m_prim_gl_state.from_register(m_frame_data.sprite_3d_giftag.prim()); - } - } - - if (run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0) { - if (m_2d_enable) { - do_block_common(SpriteMode::Mode2D, sprite_count, render_state, prof); - } - } else { - if (m_3d_enable) { - do_block_common(SpriteMode::Mode3D, sprite_count, render_state, prof); - } - } - last_prog = run.vifcode1().immediate; - } - } -} - -void SpriteRenderer::render_fake_shadow(DmaFollower& dma) { - // TODO - // nop + flushe - auto nop_flushe = dma.read_and_advance(); - ASSERT(nop_flushe.vifcode0().kind == VifCode::Kind::NOP); - ASSERT(nop_flushe.vifcode1().kind == VifCode::Kind::FLUSHE); -} - -/*! - * Handle DMA data for group1 2d's (HUD) - */ -void SpriteRenderer::render_2d_group1(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - // one time matrix data upload - auto mat_upload = dma.read_and_advance(); - bool mat_ok = verify_unpack_with_stcycl(mat_upload, VifCode::Kind::UNPACK_V4_32, 4, 4, 80, - SpriteDataMem::Matrix, false, false); - ASSERT(mat_ok); - ASSERT(mat_upload.size_bytes == sizeof(m_hud_matrix_data)); - memcpy(&m_hud_matrix_data, mat_upload.data, sizeof(m_hud_matrix_data)); - - // opengl sprite frame setup - glUniform4fv( - glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "hud_hvdf_offset"), 1, - m_hud_matrix_data.hvdf_offset.data()); - glUniform4fv(glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "hud_hvdf_user"), - 75, m_hud_matrix_data.user_hvdf[0].data()); - glUniformMatrix4fv( - glGetUniformLocation(render_state->shaders[ShaderId::SPRITE].id(), "hud_matrix"), 1, GL_FALSE, - m_hud_matrix_data.matrix.data()); - - m_prim_gl_state.from_register(m_frame_data.sprite_2d_giftag2.prim()); - - // loop through chunks. - while (looks_like_2d_chunk_start(dma)) { - m_debug_stats.blocks_2d_grp1++; - // 4 packets per chunk - - // first is the header - u32 sprite_count = process_sprite_chunk_header(dma); - m_debug_stats.count_2d_grp1 += sprite_count; - - // second is the vector data - u32 expected_vec_size = sizeof(SpriteVecData2d) * sprite_count; - auto vec_data = dma.read_and_advance(); - ASSERT(expected_vec_size <= sizeof(m_vec_data_2d)); - unpack_to_no_stcycl(&m_vec_data_2d, vec_data, VifCode::Kind::UNPACK_V4_32, expected_vec_size, - SpriteDataMem::Vector, false, true); - - // third is the adgif data - u32 expected_adgif_size = sizeof(AdGifData) * sprite_count; - auto adgif_data = dma.read_and_advance(); - ASSERT(expected_adgif_size <= sizeof(m_adgif)); - unpack_to_no_stcycl(&m_adgif, adgif_data, VifCode::Kind::UNPACK_V4_32, expected_adgif_size, - SpriteDataMem::Adgif, false, true); - - // fourth is the actual run!!!!! - auto run = dma.read_and_advance(); - ASSERT(run.vifcode0().kind == VifCode::Kind::NOP); - ASSERT(run.vifcode1().kind == VifCode::Kind::MSCAL); - ASSERT(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud); - if (m_enabled && m_2d_enable) { - do_block_common(SpriteMode::ModeHUD, sprite_count, render_state, prof); - } - } -} - -void SpriteRenderer::render(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - m_debug_stats = {}; - // First thing should be a NEXT with two nops. this is a jump from buckets to sprite data - auto data0 = dma.read_and_advance(); - ASSERT(data0.vif1() == 0); - ASSERT(data0.vif0() == 0); - ASSERT(data0.size_bytes == 0); - - if (dma.current_tag().kind == DmaTag::Kind::CALL) { - // sprite renderer didn't run, let's just get out of here. - for (int i = 0; i < 4; i++) { - dma.read_and_advance(); - } - ASSERT(dma.current_tag_offset() == render_state->next_bucket); - return; - } - - render_state->shaders[ShaderId::SPRITE].activate(); - - // First is the distorter - { - auto child = prof.make_scoped_child("distorter"); - render_distorter(dma, render_state, child); - } - - // next, sprite frame setup. - handle_sprite_frame_setup(dma); - - // 3d sprites - render_3d(dma); - - // 2d draw - // m_sprite_renderer.reset_state(); - { - auto child = prof.make_scoped_child("2d-group0"); - render_2d_group0(dma, render_state, child); - flush_sprites(render_state, prof); - } - - // shadow draw - render_fake_shadow(dma); - - // 2d draw (HUD) - { - auto child = prof.make_scoped_child("2d-group1"); - render_2d_group1(dma, render_state, child); - flush_sprites(render_state, prof); - } - - // TODO finish this up. - // fmt::print("next bucket is 0x{}\n", render_state->next_bucket); - while (dma.current_tag_offset() != render_state->next_bucket) { - // auto tag = dma.current_tag(); - // fmt::print("@ 0x{:x} tag: {}", dma.current_tag_offset(), tag.print()); - auto data = dma.read_and_advance(); - VifCode code(data.vif0()); - // fmt::print(" vif: {}\n", code.print()); - if (code.kind == VifCode::Kind::NOP) { - // fmt::print(" vif: {}\n", VifCode(data.vif1()).print()); - } - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); -} - -void SpriteRenderer::draw_debug_window() { - ImGui::Separator(); - ImGui::Text("2D Group 0 (World) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp0, - m_debug_stats.count_2d_grp0); - ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1, - m_debug_stats.count_2d_grp1); - ImGui::Checkbox("Culling", &m_enable_culling); - ImGui::Checkbox("2d", &m_2d_enable); - ImGui::SameLine(); - ImGui::Checkbox("3d", &m_3d_enable); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Render (for real) - -void SpriteRenderer::flush_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof) { - for (int i = 0; i <= m_adgif_index; ++i) { - update_gl_texture(render_state, i); - } - - if (m_sprite_offset == 0) { - // nothing to render - m_adgif_index = 0; - return; - } - - update_gl_blend(m_adgif_state_stack[m_adgif_index]); - - if (m_adgif_state_stack[m_adgif_index].z_write) { - glDepthMask(GL_TRUE); - } else { - glDepthMask(GL_FALSE); - } - - glBindVertexArray(m_ogl.vao); - - // render! - // fmt::print("drawing {} sprites\n", m_sprite_offset); - glBindBuffer(GL_ARRAY_BUFFER, m_ogl.vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, m_sprite_offset * sizeof(SpriteVertex3D) * 6, m_vertices_3d.data(), - GL_STREAM_DRAW); - - glDrawArrays(GL_TRIANGLES, 0, m_sprite_offset * 6); - - glBindVertexArray(0); - int n_tris = m_sprite_offset * 6 / 3; - prof.add_tri(n_tris); - prof.add_draw_call(1); - - m_sprite_offset = 0; - m_adgif_index = 0; -} - -void SpriteRenderer::handle_tex0(u64 val, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - GsTex0 reg(val); - - // update tbp - - m_adgif_state.reg_tex0 = reg; - m_adgif_state.texture_base_ptr = reg.tbp0(); - m_adgif_state.using_mt4hh = reg.psm() == GsTex0::PSM::PSMT4HH; - m_adgif_state.tcc = reg.tcc(); - - // tbw: assume they got it right - // psm: assume they got it right - // tw: assume they got it right - // th: assume they got it right - - ASSERT(reg.tfx() == GsTex0::TextureFunction::MODULATE); - - // cbp: assume they got it right - // cpsm: assume they got it right - // csm: assume they got it right -} - -void SpriteRenderer::handle_tex1(u64 val, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - GsTex1 reg(val); - // for now, we aren't going to handle mipmapping. I don't think it's used with direct. - // ASSERT(reg.mxl() == 0); - // if that's true, we can ignore LCM, MTBA, L, K - - m_adgif_state.enable_tex_filt = reg.mmag(); - - // MMAG/MMIN specify texture filtering. For now, assume always linear - // ASSERT(reg.mmag() == true); - // if (!(reg.mmin() == 1 || reg.mmin() == 4)) { // with mipmap off, both of these are linear - // // lg::error("unsupported mmin"); - // } -} - -void SpriteRenderer::handle_zbuf(u64 val, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - // note: we can basically ignore this. There's a single z buffer that's always configured the same - // way - 24-bit, at offset 448. - GsZbuf x(val); - ASSERT(x.psm() == TextureFormat::PSMZ24); - ASSERT(x.zbp() == 448); - - m_adgif_state.z_write = !x.zmsk(); -} - -void SpriteRenderer::handle_clamp(u64 val, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - if (!(val == 0b101 || val == 0 || val == 1 || val == 0b100)) { - ASSERT_MSG(false, fmt::format("clamp: 0x{:x}", val)); - } - - m_adgif_state.reg_clamp = val; - m_adgif_state.clamp_s = val & 0b001; - m_adgif_state.clamp_t = val & 0b100; -} - -void SpriteRenderer::update_gl_blend(AdGifState& state) { - if (!m_prim_gl_state.alpha_blend_enable) { - glDisable(GL_BLEND); - } else { - glEnable(GL_BLEND); - if (state.a == GsAlpha::BlendMode::SOURCE && state.b == GsAlpha::BlendMode::DEST && - state.c == GsAlpha::BlendMode::SOURCE && state.d == GsAlpha::BlendMode::DEST) { - // (Cs - Cd) * As + Cd - // Cs * As + (1 - As) * Cd - // s, d - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - } else if (state.a == GsAlpha::BlendMode::SOURCE && - state.b == GsAlpha::BlendMode::ZERO_OR_FIXED && - state.c == GsAlpha::BlendMode::SOURCE && state.d == GsAlpha::BlendMode::DEST) { - // (Cs - 0) * As + Cd - // Cs * As + (1) * Cd - // s, d - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glBlendEquation(GL_FUNC_ADD); - } else if (state.a == GsAlpha::BlendMode::ZERO_OR_FIXED && - state.b == GsAlpha::BlendMode::SOURCE && state.c == GsAlpha::BlendMode::SOURCE && - state.d == GsAlpha::BlendMode::DEST) { - // (0 - Cs) * As + Cd - // Cd - Cs * As - // s, d - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - } else { - // unsupported blend: a 0 b 2 c 2 d 1 - lg::error("unsupported blend: a {} b {} c {} d {} NOTE THIS DOWN IMMEDIATELY!!", (int)state.a, - (int)state.b, (int)state.c, (int)state.d); - ASSERT(false); - } - } -} - -void SpriteRenderer::handle_alpha(u64 val, - SharedRenderState* /*render_state*/, - ScopedProfilerNode& /*prof*/) { - GsAlpha reg(val); - - m_adgif_state.from_register(reg); -} - -void SpriteRenderer::update_gl_prim(SharedRenderState* /*render_state*/) { - // currently gouraud is handled in setup. - const auto& state = m_prim_gl_state; - if (state.fogging_enable) { - // ASSERT(false); - } - if (state.aa_enable) { - ASSERT(false); - } - if (state.use_uv) { - ASSERT(false); - } - if (state.ctxt) { - ASSERT(false); - } - if (state.fix) { - ASSERT(false); - } -} - -void SpriteRenderer::update_gl_texture(SharedRenderState* render_state, int unit) { - std::optional tex; - auto& state = m_adgif_state_stack[unit]; - if (!state.used) { - // nothing used this state, don't bother binding the texture. - return; - } - if (state.using_mt4hh) { - tex = render_state->texture_pool->lookup_mt4hh(state.texture_base_ptr); - } else { - tex = render_state->texture_pool->lookup(state.texture_base_ptr); - } - - if (!tex) { - lg::warn("Failed to find texture at {}, using random", state.texture_base_ptr); - tex = render_state->texture_pool->get_placeholder_texture(); - } - ASSERT(tex); - - glActiveTexture(GL_TEXTURE20 + unit); - glBindTexture(GL_TEXTURE_2D, *tex); - // Note: CLAMP and CLAMP_TO_EDGE are different... - if (state.clamp_s) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - } - - if (state.clamp_t) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - if (state.enable_tex_filt) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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); - } - - state.used = false; -} - -void SpriteRenderer::do_block_common(SpriteMode mode, - u32 count, - SharedRenderState* render_state, - ScopedProfilerNode& prof) { - for (u32 sprite_idx = 0; sprite_idx < count; sprite_idx++) { - if (m_sprite_offset == SPRITE_RENDERER_MAX_SPRITES) { - flush_sprites(render_state, prof); - } - - if (mode == Mode2D && render_state->has_pc_data && m_enable_culling) { - // we can skip sprites that are out of view - // it's probably possible to do this for 3D as well. - auto bsphere = m_vec_data_2d[sprite_idx].xyz_sx; - bsphere.w() = std::max(bsphere.w(), m_vec_data_2d[sprite_idx].sy()); - if (bsphere.w() == 0 || !sphere_in_view_ref(bsphere, render_state->camera_planes)) { - continue; - } - } - - auto& adgif = m_adgif[sprite_idx]; - // fmt::print("adgif: {:X} {:X} {:X} {:X}\n", adgif.tex0_data, adgif.tex1_data, - // adgif.clamp_data, adgif.alpha_data); fmt::print("adgif regs: {} {} {} {} {}\n", - // register_address_name(adgif.tex0_addr), register_address_name(adgif.tex1_addr), - // register_address_name(adgif.mip_addr), register_address_name(adgif.clamp_addr), - // register_address_name(adgif.alpha_addr)); - handle_tex0(adgif.tex0_data, render_state, prof); - handle_tex1(adgif.tex1_data, render_state, prof); - // handle_mip(adgif.mip_data, render_state, prof); - if (GsRegisterAddress(adgif.clamp_addr) == GsRegisterAddress::ZBUF_1) { - handle_zbuf(adgif.clamp_data, render_state, prof); - } else { - handle_clamp(adgif.clamp_data, render_state, prof); - } - handle_alpha(adgif.alpha_data, render_state, prof); - - if (!m_adgif_state_stack[m_adgif_index].used) { - m_adgif_state_stack[m_adgif_index] = m_adgif_state; - m_adgif_state_stack[m_adgif_index].used = true; - } else if (m_adgif_state != m_adgif_state_stack[m_adgif_index]) { - if (m_adgif_index + 1 == ADGIF_STATE_COUNT || - !m_adgif_state.nontexture_equal(m_adgif_state_stack[m_adgif_index])) { - flush_sprites(render_state, prof); - } else { - m_adgif_index++; - } - m_adgif_state_stack[m_adgif_index] = m_adgif_state; - m_adgif_state_stack[m_adgif_index].used = true; - } - - int vert_idx = 6 * m_sprite_offset; - - auto& vert1 = m_vertices_3d.at(vert_idx + 0); - - vert1.xyz_sx = m_vec_data_2d[sprite_idx].xyz_sx; - vert1.quat_sy = m_vec_data_2d[sprite_idx].flag_rot_sy; - vert1.rgba = m_vec_data_2d[sprite_idx].rgba / 255; - vert1.flags_matrix[0] = m_vec_data_2d[sprite_idx].flag(); - vert1.flags_matrix[1] = m_vec_data_2d[sprite_idx].matrix(); - vert1.info[0] = m_adgif_index; - vert1.info[1] = m_adgif_state_stack[m_adgif_index].tcc; - vert1.info[2] = 0; - vert1.info[3] = mode; - - m_vertices_3d.at(vert_idx + 1) = vert1; - m_vertices_3d.at(vert_idx + 2) = vert1; - m_vertices_3d.at(vert_idx + 3) = vert1; - m_vertices_3d.at(vert_idx + 4) = vert1; - m_vertices_3d.at(vert_idx + 5) = vert1; - - m_vertices_3d.at(vert_idx + 1).info[2] = 1; - m_vertices_3d.at(vert_idx + 2).info[2] = 2; - m_vertices_3d.at(vert_idx + 3).info[2] = 2; - m_vertices_3d.at(vert_idx + 4).info[2] = 3; - m_vertices_3d.at(vert_idx + 5).info[2] = 0; - - ++m_sprite_offset; - } -} diff --git a/game/graphics/opengl_renderer/sprite/SpriteRenderer.h b/game/graphics/opengl_renderer/sprite/SpriteRenderer.h deleted file mode 100644 index 1fd12724be..0000000000 --- a/game/graphics/opengl_renderer/sprite/SpriteRenderer.h +++ /dev/null @@ -1,163 +0,0 @@ -#pragma once - -#include "common/dma/gs.h" -#include "common/math/Vector.h" - -#include "game/graphics/opengl_renderer/BucketRenderer.h" -#include "game/graphics/opengl_renderer/DirectRenderer.h" -#include "game/graphics/opengl_renderer/sprite/sprite_common.h" - -class SpriteRenderer : public BucketRenderer { - public: - SpriteRenderer(const std::string& name, int my_id); - void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode& prof) override; - void draw_debug_window() override; - static constexpr int SPRITES_PER_CHUNK = 48; - - private: - void render_distorter(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - void handle_sprite_frame_setup(DmaFollower& dma); - void render_3d(DmaFollower& dma); - void render_2d_group0(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - void render_fake_shadow(DmaFollower& dma); - void render_2d_group1(DmaFollower& dma, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - enum SpriteMode { Mode2D = 1, ModeHUD = 2, Mode3D = 3 }; - void do_block_common(SpriteMode mode, - u32 count, - SharedRenderState* render_state, - ScopedProfilerNode& prof); - - void handle_tex0(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - void handle_tex1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - // void handle_mip(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - void handle_zbuf(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - void handle_clamp(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - void handle_alpha(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof); - - void update_gl_prim(SharedRenderState* render_state); - void update_gl_texture(SharedRenderState* render_state, int unit); - void flush_sprites(SharedRenderState* render_state, ScopedProfilerNode& prof); - - u8 m_sprite_distorter_setup[7 * 16]; // direct data - u8 m_sprite_direct_setup[3 * 16]; - SpriteFrameData m_frame_data; // qwa: 980 - Sprite3DMatrixData m_3d_matrix_data; - SpriteHudMatrixData m_hud_matrix_data; - - SpriteVecData2d m_vec_data_2d[SPRITES_PER_CHUNK]; - AdGifData m_adgif[SPRITES_PER_CHUNK]; - - struct DebugStats { - int blocks_2d_grp0 = 0; - int count_2d_grp0 = 0; - int blocks_2d_grp1 = 0; - int count_2d_grp1 = 0; - } m_debug_stats; - - bool m_enable_culling = true; - - bool m_2d_enable = true; - bool m_3d_enable = true; - - struct SpriteVertex3D { - math::Vector4f xyz_sx; // position + x scale - math::Vector4f quat_sy; // quaternion + y scale - math::Vector4f rgba; // color - math::Vector flags_matrix; // flags + matrix... split - math::Vector info; - math::Vector pad; - }; - static_assert(sizeof(SpriteVertex3D) == 64); - - std::vector m_vertices_3d; - - struct { - GLuint vertex_buffer; - GLuint vao; - } m_ogl; - - int m_sprite_offset = 0; - - // state set through the prim register that requires changing GL stuff. - struct PrimGlState { - void from_register(GsPrim reg) { - current_register = reg; - gouraud_enable = reg.gouraud(); - texture_enable = reg.tme(); - fogging_enable = reg.fge(); - aa_enable = reg.aa1(); - use_uv = reg.fst(); - ctxt = reg.ctxt(); - fix = reg.fix(); - alpha_blend_enable = reg.abe(); - } - - GsPrim current_register; - bool gouraud_enable = false; - bool texture_enable = false; - bool fogging_enable = false; - bool alpha_blend_enable = false; - - bool aa_enable = false; - bool use_uv = false; // todo: might not require a gl state change - bool ctxt = false; // do they ever use ctxt2? - bool fix = false; // what does this even do? - } m_prim_gl_state; - - static constexpr int ADGIF_STATE_COUNT = 10; - - struct AdGifState { - GsTex0 reg_tex0; - u32 texture_base_ptr = 0; - bool using_mt4hh = false; - bool tcc = false; - - bool enable_tex_filt = false; - - u64 reg_clamp = 0b101; - bool clamp_s = true; - bool clamp_t = true; - - GsAlpha reg_alpha; - GsAlpha::BlendMode a = GsAlpha::BlendMode::SOURCE; - GsAlpha::BlendMode b = GsAlpha::BlendMode::DEST; - GsAlpha::BlendMode c = GsAlpha::BlendMode::SOURCE; - GsAlpha::BlendMode d = GsAlpha::BlendMode::DEST; - u8 fix = 0; - void from_register(GsAlpha reg) { - reg_alpha = reg; - a = reg.a_mode(); - b = reg.b_mode(); - c = reg.c_mode(); - d = reg.d_mode(); - fix = reg.fix(); - - ASSERT(fix == 0); - } - bool z_write = false; - - bool used = false; - - bool nontexture_equal(const AdGifState& other) const { - return reg_alpha == other.reg_alpha && z_write == other.z_write; - } - - bool operator==(const AdGifState& other) const { - return reg_tex0 == other.reg_tex0 && enable_tex_filt == other.enable_tex_filt && - reg_clamp == other.reg_clamp && nontexture_equal(other); - } - bool operator!=(const AdGifState& other) const { return !operator==(other); } - } m_adgif_state_stack[ADGIF_STATE_COUNT]; - - AdGifState m_adgif_state; // temp state - - int m_adgif_index = 0; - - void update_gl_blend(AdGifState& state); -}; diff --git a/game/graphics/opengl_renderer/sprite/sprite_common.h b/game/graphics/opengl_renderer/sprite/sprite_common.h index 5cd0d2d94b..5db39de2f6 100644 --- a/game/graphics/opengl_renderer/sprite/sprite_common.h +++ b/game/graphics/opengl_renderer/sprite/sprite_common.h @@ -201,10 +201,11 @@ struct SpriteHud2DPacket { * The layout of VU1 code memory */ enum SpriteProgMem { - Init = 0, // the sprite initialization program. runs once per frame. - Sprites2dGrp0 = 3, // world space 2d sprites - Sprites2dHud = 109, // hud sprites - Sprites3d = 211 // 3d sprites + Init = 0, // the sprite initialization program. runs once per frame. + Sprites2dGrp0 = 3, // world space 2d sprites + Sprites2dHud_Jak1 = 109, // hud sprites + Sprites2dHud_Jak2 = 115, + Sprites3d = 211 // 3d sprites }; static_assert(offsetof(SpriteFrameData, hmge_scale) == 256); diff --git a/goal_src/jak2/kernel/gstate.gc b/goal_src/jak2/kernel/gstate.gc index 54f8aea9b1..9ea7edf261 100644 --- a/goal_src/jak2/kernel/gstate.gc +++ b/goal_src/jak2/kernel/gstate.gc @@ -450,6 +450,7 @@ It type checks the arguments for the entry function. (abandon-thread) #f ;; can't get here ) + #t ) ) )