From 3b558e093e90c89c8307c33705f0df9081a55099 Mon Sep 17 00:00:00 2001 From: Ethan Lafrenais <6609531+Francessco121@users.noreply.github.com> Date: Fri, 15 Jul 2022 18:16:46 -0400 Subject: [PATCH] Fix instanced sprite distort renderer not always using the most recent sine table (#1646) * Fix instanced sprite distort renderer not always using the most recent sine table Sometimes the game won't update the sine table on the same frame the aspect ratio changes (for example if the player is in a cutscene), but the renderer assumed that it was always up-to-date on the next frame. This caused it to occasionally use outdated vertex/tex coord data that usually made the distort sprites a little too small/big. * Same fix, but better --- game/graphics/opengl_renderer/Sprite3.cpp | 31 ++++++++++++------- game/graphics/opengl_renderer/Sprite3.h | 7 +++-- .../jak1/engine/gfx/sprite/sprite-distort.gc | 18 +++++++++++ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/game/graphics/opengl_renderer/Sprite3.cpp b/game/graphics/opengl_renderer/Sprite3.cpp index 61eeb842f0..7ca1912d0d 100644 --- a/game/graphics/opengl_renderer/Sprite3.cpp +++ b/game/graphics/opengl_renderer/Sprite3.cpp @@ -314,11 +314,11 @@ void Sprite3::render_distorter(DmaFollower& dma, return; } - // Setup vertex data + // Set up vertex data { auto prof_node = prof.make_scoped_child("setup"); if (m_enable_distort_instancing) { - distort_setup_instanced(render_state, prof_node); + distort_setup_instanced(prof_node); } else { distort_setup(prof_node); } @@ -372,6 +372,18 @@ void Sprite3::distort_dma(DmaFollower& dma, ScopedProfilerNode& /*prof*/) { ASSERT(alpha.c_mode() == GsAlpha::BlendMode::SOURCE); ASSERT(alpha.d_mode() == GsAlpha::BlendMode::DEST); + // Next is the aspect used by the sine tables (PC only) + // + // This was added to let the renderer reliably detect when the sine tables changed, + // which is whenever the aspect ratio changed. However, the tables aren't always + // updated on the same frame that the aspect changed, so this just lets the game + // easily notify the renderer when it finally does get updated. + auto sprite_distort_tables_aspect = dma.read_and_advance(); + ASSERT(sprite_distort_tables_aspect.size_bytes == 16); + ASSERT(sprite_distort_tables_aspect.vifcode1().kind == VifCode::Kind::PC_PORT); + memcpy(&m_sprite_distorter_sine_tables_aspect, sprite_distort_tables_aspect.data, + sizeof(math::Vector4f)); + // Next thing should be the sine tables auto sprite_distorter_tables = dma.read_and_advance(); unpack_to_stcycl(&m_sprite_distorter_sine_tables, sprite_distorter_tables, @@ -517,15 +529,12 @@ void Sprite3::distort_setup(ScopedProfilerNode& /*prof*/) { * * Required sprite-specific frame data is kept as is and is grouped by resolution. */ -void Sprite3::distort_setup_instanced(SharedRenderState* render_state, - ScopedProfilerNode& /*prof*/) { - if (m_distort_instanced_ogl.last_width != render_state->fbo_state.width || - m_distort_instanced_ogl.last_height != render_state->fbo_state.height) { - m_distort_instanced_ogl.last_width = render_state->fbo_state.width; - m_distort_instanced_ogl.last_height = render_state->fbo_state.height; - - // Window dimensions changed, which means the aspect ratio may have changed, which means we have - // a new sine table +void Sprite3::distort_setup_instanced(ScopedProfilerNode& /*prof*/) { + if (m_distort_instanced_ogl.last_aspect_x != m_sprite_distorter_sine_tables_aspect.x() || + m_distort_instanced_ogl.last_aspect_y != m_sprite_distorter_sine_tables_aspect.y()) { + m_distort_instanced_ogl.last_aspect_x = m_sprite_distorter_sine_tables_aspect.x(); + m_distort_instanced_ogl.last_aspect_y = m_sprite_distorter_sine_tables_aspect.y(); + // Aspect ratio changed, which means we have a new sine table m_sprite_distorter_vertices_instanced.clear(); // Build a mesh for every possible distort sprite resolution diff --git a/game/graphics/opengl_renderer/Sprite3.h b/game/graphics/opengl_renderer/Sprite3.h index 72423a9a24..6aba7c4b9f 100644 --- a/game/graphics/opengl_renderer/Sprite3.h +++ b/game/graphics/opengl_renderer/Sprite3.h @@ -28,7 +28,7 @@ class Sprite3 : public BucketRenderer { ScopedProfilerNode& prof); void distort_dma(DmaFollower& dma, ScopedProfilerNode& prof); void distort_setup(ScopedProfilerNode& prof); - void distort_setup_instanced(SharedRenderState* render_state, ScopedProfilerNode& prof); + void distort_setup_instanced(ScopedProfilerNode& prof); void distort_draw(SharedRenderState* render_state, ScopedProfilerNode& prof); void distort_draw_instanced(SharedRenderState* render_state, ScopedProfilerNode& prof); void distort_draw_common(SharedRenderState* render_state, ScopedProfilerNode& prof); @@ -117,8 +117,8 @@ class Sprite3 : public BucketRenderer { GLuint vao; GLuint vertex_buffer; // contains vertex data for each possible sprite resolution (3-11) GLuint instance_buffer; // contains all instance specific data for each sprite per frame - int last_width = -1; - int last_height = -1; + float last_aspect_x = -1.0; + float last_aspect_y = -1.0; bool vertex_data_changed = false; } m_distort_instanced_ogl; @@ -130,6 +130,7 @@ class Sprite3 : public BucketRenderer { std::vector m_sprite_distorter_vertices; std::vector m_sprite_distorter_indices; SpriteDistorterSetup m_sprite_distorter_setup; // direct data + math::Vector4f m_sprite_distorter_sine_tables_aspect; SpriteDistorterSineTables m_sprite_distorter_sine_tables; std::vector m_sprite_distorter_frame_data; std::vector m_sprite_distorter_vertices_instanced; diff --git a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc index 8706e1aff3..be5516b94b 100644 --- a/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc +++ b/goal_src/jak1/engine/gfx/sprite/sprite-distort.gc @@ -143,6 +143,24 @@ ;; blend source and framebuffer RGB (alpha-1 (new 'static 'gs-alpha :b 1 :d 1)) ) + ;; send current aspect used by the sine tables (PC only) + (#when PC_PORT + (let ((packet (the-as dma-packet (-> dma-buff base)))) + (set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id cnt) :qwc 1)) + (set! (-> packet vif0) (new 'static 'vif-tag)) + (set! (-> packet vif1) (new 'static 'vif-tag :cmd (vif-cmd pc-port))) + (&+! (-> dma-buff base) 16) + ) + (let ((aspect-vec (the-as vector (-> dma-buff base)))) + (set-vector! aspect-vec + (-> *sprite-distorter-sine-tables* aspx) + (-> *sprite-distorter-sine-tables* aspy) + 0.0 + 0.0 + ) + (&+! (-> dma-buff base) 16) + ) + ) ;; send distorter sine tables (dma-buffer-add-ref-vif2 dma-buff #x8b (-> *sprite-distorter-sine-tables* entry)