From 34de4ea3925b028537209efec276ee83b6458329 Mon Sep 17 00:00:00 2001 From: Irastris Date: Tue, 14 Apr 2026 16:11:15 -0400 Subject: [PATCH] Frame interp: Stable keying for simple shadows --- include/dusk/frame_interpolation.h | 2 + src/d/d_drawlist.cpp | 31 +++++++++------ src/dusk/frame_interpolation.cpp | 64 ++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/include/dusk/frame_interpolation.h b/include/dusk/frame_interpolation.h index 423ac9af37..3aadfe8520 100644 --- a/include/dusk/frame_interpolation.h +++ b/include/dusk/frame_interpolation.h @@ -34,6 +34,7 @@ void open_child(const void* key, int32_t id); void close_child(); void record_camera(::camera_process_class* cam, int camera_id); void record_final_mtx_raw(const Mtx* dest, const Mtx src); +void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag); bool lookup_replacement(const void* source, Mtx out); bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out); @@ -41,6 +42,7 @@ bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out); void camera_eye_from_view_mtx(MtxP view_mtx, cXyz* o_eye); bool build_star_view(Mtx o_view, Mtx o_cam_billboard_base, cXyz* o_anchor_eye, float* o_fovy); +uint64_t alloc_simple_shadow_pair_base(); } // namespace frame_interp } // namespace dusk #endif diff --git a/src/d/d_drawlist.cpp b/src/d/d_drawlist.cpp index 24798f4482..e903e39ce4 100644 --- a/src/d/d_drawlist.cpp +++ b/src/d/d_drawlist.cpp @@ -1,28 +1,29 @@ #include "d/dolzel.h" // IWYU pragma: keep -#include #include "JSystem/J2DGraph/J2DAnimation.h" #include "JSystem/J2DGraph/J2DGrafContext.h" #include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J3DGraphBase/J3DDrawBuffer.h" -#include "JSystem/JKernel/JKRHeap.h" #include "SSystem/SComponent/c_bg_s_shdw_draw.h" #include "SSystem/SComponent/c_math.h" #include "d/d_com_inf_game.h" #include "d/d_drawlist.h" - -#include - -#include "absl/container/flat_hash_map.h" -#include "client/TracyScoped.hpp" #include "d/d_s_play.h" -#include "dusk/frame_interpolation.h" -#include "dusk/gx_helper.h" -#include "dusk/logging.h" #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_lib.h" #include "m_Do/m_Do_mtx.h" +#if TARGET_PC +#include +#include +#include "JSystem/JKernel/JKRHeap.h" +#include "absl/container/flat_hash_map.h" +#include "client/TracyScoped.hpp" +#include "dusk/frame_interpolation.h" +#include "dusk/gx_helper.h" +#include "dusk/logging.h" +#endif + class dDlst_2Dm_c { public: virtual void draw(); @@ -1432,8 +1433,14 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa mDoMtx_stack_c::scaleM(param_2, 1.0f, param_2 * param_5); cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx); #ifdef TARGET_PC - dusk::frame_interp::record_final_mtx_raw(&mVolumeMtx, mVolumeMtx); - dusk::frame_interp::record_final_mtx_raw(&mMtx, mMtx); + const uint64_t shadow_tag_base = dusk::frame_interp::alloc_simple_shadow_pair_base(); + if (shadow_tag_base != 0) { + dusk::frame_interp::record_final_mtx_raw_tagged(&mVolumeMtx, mVolumeMtx, shadow_tag_base); + dusk::frame_interp::record_final_mtx_raw_tagged(&mMtx, mMtx, shadow_tag_base + 1u); + } else { + dusk::frame_interp::record_final_mtx_raw(&mVolumeMtx, mVolumeMtx); + dusk::frame_interp::record_final_mtx_raw(&mMtx, mMtx); + } #endif mpTexObj = param_6; } diff --git a/src/dusk/frame_interpolation.cpp b/src/dusk/frame_interpolation.cpp index ced68b6be5..0fa7d036e0 100644 --- a/src/dusk/frame_interpolation.cpp +++ b/src/dusk/frame_interpolation.cpp @@ -28,6 +28,7 @@ struct Data { size_t child_index = 0; Mtx matrix{}; const Mtx* dest = nullptr; + uint64_t stable_tag = 0; }; struct Path; @@ -46,6 +47,8 @@ struct Path { std::vector children; std::vector ops; std::vector> items; + Label draw_scope{}; + uint32_t simple_shadow_pair_seq = 0; }; struct Recording { @@ -57,6 +60,7 @@ struct MatrixValue { }; using FinalMtxLookup = std::unordered_map; +using FinalMtxLookupTagged = std::unordered_map; bool s_initialized = false; @@ -142,8 +146,9 @@ const OpBucket* find_op_bucket(const Path& path, Op op) { return &*it; } -void build_final_mtx_lookup(const Path& path, FinalMtxLookup& lookup) { - lookup.clear(); +void build_final_mtx_lookups(const Path& path, FinalMtxLookup& dest_lookup, FinalMtxLookupTagged& tag_lookup) { + dest_lookup.clear(); + tag_lookup.clear(); const OpBucket* bucket = find_op_bucket(path, Op::FinalMtx); if (bucket == nullptr) { @@ -151,10 +156,12 @@ void build_final_mtx_lookup(const Path& path, FinalMtxLookup& lookup) { } for (const Data& data : bucket->values) { - if (data.dest == nullptr) { - continue; + if (data.dest != nullptr) { + dest_lookup[data.dest] = &data; + } + if (data.stable_tag != 0) { + tag_lookup[data.stable_tag] = &data; } - lookup[data.dest] = &data; } } @@ -201,7 +208,8 @@ void store_replacement(const Data& old_data, const Data& new_data, float step) { void interpolate_branch(const Path& old_path, const Path& new_path, float step) { FinalMtxLookup old_final_mtx_lookup; - build_final_mtx_lookup(old_path, old_final_mtx_lookup); + FinalMtxLookupTagged old_final_mtx_lookup_tagged; + build_final_mtx_lookups(old_path, old_final_mtx_lookup, old_final_mtx_lookup_tagged); for (const auto& item : new_path.items) { const Op op = item.first; @@ -230,7 +238,17 @@ void interpolate_branch(const Path& old_path, const Path& new_path, float step) } const Data* indexed_old_data = find_matching_data(old_path, op, index); - const Data* old_data = op == Op::FinalMtx ? find_matching_final_mtx(old_final_mtx_lookup, *new_data) : indexed_old_data; + const Data* old_data = nullptr; + if (op == Op::FinalMtx) { + if (new_data->stable_tag != 0) { + const auto it = old_final_mtx_lookup_tagged.find(new_data->stable_tag); + old_data = it != old_final_mtx_lookup_tagged.end() ? it->second : nullptr; + } else { + old_data = find_matching_final_mtx(old_final_mtx_lookup, *new_data); + } + } else { + old_data = indexed_old_data; + } if (op == Op::FinalMtx) { store_replacement(old_data != nullptr ? *old_data : *new_data, *new_data, step); } @@ -370,7 +388,9 @@ void open_child(const void* key, int32_t id) { data.child_label = label; data.child_index = siblings.size(); siblings.emplace_back(std::make_unique()); - g_current_path.push_back(siblings.back().get()); + Path* const child = siblings.back().get(); + child->draw_scope = label; + g_current_path.push_back(child); } void close_child() { @@ -388,6 +408,18 @@ void record_final_mtx_raw(const Mtx* dest, const Mtx src) { Data& data = append_op(Op::FinalMtx); data.dest = dest; + data.stable_tag = 0; + copy_matrix(src, data.matrix); +} + +void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag) { + if (!s_initialized || !g_recording || dest == nullptr) { + return; + } + + Data& data = append_op(Op::FinalMtx); + data.dest = dest; + data.stable_tag = stable_tag; copy_matrix(src, data.matrix); } @@ -501,4 +533,20 @@ bool build_star_view(Mtx o_view, Mtx o_cam_billboard_base, cXyz* o_anchor_eye, f *o_fovy = s_star_prev.fovy + (s_star_curr.fovy - s_star_prev.fovy) * step; return true; } + +uint64_t alloc_simple_shadow_pair_base() { + if (!s_initialized || !g_recording || g_current_path.size() <= 1) { + return 0; + } + + Path* const scope = g_current_path.back(); + const uint64_t h = static_cast(reinterpret_cast(scope->draw_scope.key)); + const uint32_t lo = scope->simple_shadow_pair_seq; + scope->simple_shadow_pair_seq += 2; + uint64_t tag0 = (h << 17) ^ (static_cast(lo) << 1u); + if (tag0 == 0) { + tag0 = 2; + } + return tag0; +} } // namespace dusk::frame_interp