From 1962fbfb516aed458b62893c9c8166e05d60278d Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sun, 27 Oct 2024 09:21:44 -0400 Subject: [PATCH] [jak2,3] Support loading clut blender animated textures to the pool (#3735) Animated textures that use the clut blender can now upload them to the texture pool, so they can get read by the eye renderer. This will also fix darkjak's eyelids in jak 2. ![image](https://github.com/user-attachments/assets/5edbd20d-53c9-42c6-937d-6263823b8b45) Co-authored-by: water111 --- .../opengl_renderer/TextureAnimator.cpp | 66 ++++++++--- .../opengl_renderer/TextureAnimator.h | 11 +- .../opengl_renderer/TextureAnimatorDefs.cpp | 6 +- .../jak2/engine/gfx/texture/texture-anim.gc | 111 ++++++------------ .../jak3/engine/gfx/texture/texture-anim.gc | 57 +++++---- 5 files changed, 127 insertions(+), 124 deletions(-) diff --git a/game/graphics/opengl_renderer/TextureAnimator.cpp b/game/graphics/opengl_renderer/TextureAnimator.cpp index 0855f3e0fda..1146ae9b38f 100644 --- a/game/graphics/opengl_renderer/TextureAnimator.cpp +++ b/game/graphics/opengl_renderer/TextureAnimator.cpp @@ -736,10 +736,14 @@ void TextureAnimator::copy_private_to_public() { int TextureAnimator::create_clut_blender_group(const std::vector& textures, const std::string& suffix0, const std::string& suffix1, - const std::optional& dgo) { + const std::optional& dgo, + bool add_to_pool) { int ret = m_clut_blender_groups.size(); m_clut_blender_groups.emplace_back(); add_to_clut_blender_group(ret, textures, suffix0, suffix1, dgo); + if (add_to_pool) { + m_clut_blender_groups.back().move_to_pool = true; + } return ret; } @@ -1240,23 +1244,23 @@ void TextureAnimator::handle_texture_anim_data(DmaFollower& dma, break; case PcTextureAnimCodesJak2::DARKJAK: { auto p = scoped_prof("darkjak"); - run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak2::PRISON_JAK: { auto p = scoped_prof("prisonjak"); - run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_jakb_prison_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak2::ORACLE_JAK: { auto p = scoped_prof("oraclejak"); - run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_jakb_oracle_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak2::NEST_JAK: { auto p = scoped_prof("nestjak"); - run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_jakb_nest_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak2::KOR_TRANSFORM: { auto p = scoped_prof("kor"); - run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_kor_transform_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak2::SKULL_GEM: case PcTextureAnimCodesJak2::BOMB: @@ -1321,11 +1325,12 @@ void TextureAnimator::handle_texture_anim_data(DmaFollower& dma, break; case PcTextureAnimCodesJak3::DARKJAK: { auto p = scoped_prof("darkjak"); - run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_darkjak_clut_blender_idx, frame_idx, texture_pool); } break; case PcTextureAnimCodesJak3::DARKJAK_HIGHRES: { auto p = scoped_prof("darkjak-highres"); - run_clut_blender_group(tf, m_darkjak_highres_clut_blender_idx, frame_idx); + run_clut_blender_group(tf, m_darkjak_highres_clut_blender_idx, frame_idx, + texture_pool); } break; case PcTextureAnimCodesJak3::SKULL_GEM: case PcTextureAnimCodesJak3::DEFAULT_WATER: @@ -1579,15 +1584,48 @@ PcTextureId TextureAnimator::get_id_for_tbp(TexturePool* pool, u64 tbp, u64 othe } } -void TextureAnimator::run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx) { +void TextureAnimator::run_clut_blender_group(DmaTransfer& tf, + int idx, + u64 frame_idx, + TexturePool* texture_pool) { + auto& blenders = m_clut_blender_groups.at(idx); + const int tbps_size = sizeof(u32) * 4 * ((blenders.blenders.size() + 3) / 4); float f; - ASSERT(tf.size_bytes == 16); + ASSERT(tf.size_bytes == 16 + tbps_size); memcpy(&f, tf.data, sizeof(float)); float weights[2] = {1.f - f, f}; - auto& blender = m_clut_blender_groups.at(idx); - blender.last_updated_frame = frame_idx; - for (size_t i = 0; i < blender.blenders.size(); i++) { - m_private_output_slots[blender.outputs[i]] = blender.blenders[i].run(weights); + blenders.last_updated_frame = frame_idx; + for (size_t i = 0; i < blenders.blenders.size(); i++) { + m_private_output_slots[blenders.outputs[i]] = blenders.blenders[i].run(weights); + } + + const u32* tbps = (const u32*)(tf.data + 16); + + // give to the pool for renderers that don't know how to access this directly + if (blenders.move_to_pool) { + for (size_t i = 0; i < blenders.blenders.size(); i++) { + auto& blender = blenders.blenders[i]; + const u32 tbp = tbps[i]; + if (tbp == UINT32_MAX) { + continue; + } + ASSERT(tbp < 0x40000); + m_skip_tbps.push_back(tbp); // known to be an output texture. + if (blender.pool_gpu_tex) { + // TODO: handle debug checkbox. + texture_pool->move_existing_to_vram(blender.pool_gpu_tex, tbp); + ASSERT(texture_pool->lookup(tbp).value() == blender.texture()); + } else { + TextureInput in; + in.gpu_texture = blender.texture(); + in.w = blender.w(); + in.h = blender.h(); + in.debug_page_name = "PC-ANIM"; + in.debug_name = std::to_string(tbp); + in.id = get_id_for_tbp(texture_pool, tbp, idx); + blender.pool_gpu_tex = texture_pool->give_texture_and_load_to_vram(in, tbp); + } + } } } diff --git a/game/graphics/opengl_renderer/TextureAnimator.h b/game/graphics/opengl_renderer/TextureAnimator.h index 9f3e591b8ac..68d418f5af4 100644 --- a/game/graphics/opengl_renderer/TextureAnimator.h +++ b/game/graphics/opengl_renderer/TextureAnimator.h @@ -77,6 +77,10 @@ class ClutBlender { GLuint texture() const { return m_texture; } bool at_default() const { return m_current_weights[0] == 1.f && m_current_weights[1] == 0.f; } + int w() const { return m_dest->w; } + int h() const { return m_dest->h; } + GpuTexture* pool_gpu_tex = nullptr; + private: const tfrag3::IndexTexture* m_dest; std::array, 256>*, 2> m_cluts; @@ -220,7 +224,6 @@ struct FixedAnim { std::optional fbt; int dest_slot; std::vector src_textures; - GpuTexture* pool_gpu_tex = nullptr; }; @@ -397,6 +400,7 @@ class TextureAnimator { std::vector blenders; std::vector outputs; u64 last_updated_frame = 0; + bool move_to_pool = false; }; std::vector m_clut_blender_groups; @@ -409,13 +413,14 @@ class TextureAnimator { int create_clut_blender_group(const std::vector& textures, const std::string& suffix0, const std::string& suffix1, - const std::optional& dgo); + const std::optional& dgo, + bool send_to_pool = false); void add_to_clut_blender_group(int idx, const std::vector& textures, const std::string& suffix0, const std::string& suffix1, const std::optional& dgo); - void run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx); + void run_clut_blender_group(DmaTransfer& tf, int idx, u64 frame_idx, TexturePool* texture_pool); GLint run_clouds(const SkyInput& input, bool hires); void run_slime(const SlimeInput& input); diff --git a/game/graphics/opengl_renderer/TextureAnimatorDefs.cpp b/game/graphics/opengl_renderer/TextureAnimatorDefs.cpp index 071534a78cc..c0890f4e8fa 100644 --- a/game/graphics/opengl_renderer/TextureAnimatorDefs.cpp +++ b/game/graphics/opengl_renderer/TextureAnimatorDefs.cpp @@ -21,7 +21,7 @@ void TextureAnimator::setup_texture_anims_jak3() { "jakchires-facert", "jakchires-hair", }, - "-norm", "-dark", "MHCTYCST.DGO"); + "-norm", "-dark", "MHCTYCST.DGO", true); // default-water { @@ -1791,13 +1791,13 @@ void TextureAnimator::setup_texture_anims_jak2() { // MISSING FINGER m_jakb_oracle_clut_blender_idx = create_clut_blender_group( {"jakb-eyebrow", "jakb-eyelid", "jakb-facelft", "jakb-facert", "jakb-hairtrans"}, "-norm", - "-dark", "ORACLE.DGO"); + "-dark", "ORACLE.DGO", true); // NEST // MISSING FINGER m_jakb_nest_clut_blender_idx = create_clut_blender_group( {"jakb-eyebrow", "jakb-eyelid", "jakb-facelft", "jakb-facert", "jakb-hairtrans"}, "-norm", - "-dark", "NEB.DGO"); + "-dark", "NEB.DGO", true); // KOR (doesn't work??) m_kor_transform_clut_blender_idx = create_clut_blender_group( diff --git a/goal_src/jak2/engine/gfx/texture/texture-anim.gc b/goal_src/jak2/engine/gfx/texture/texture-anim.gc index 36498f729c6..0c60c0815e3 100644 --- a/goal_src/jak2/engine/gfx/texture/texture-anim.gc +++ b/goal_src/jak2/engine/gfx/texture/texture-anim.gc @@ -777,6 +777,34 @@ struct SlimeInput { (the int (-> *toxic-slime-texture-anim-array* array-data 8 tex dest 0))) ) +(defun pc-clut-blender ((bucket bucket-id) (id texture-anim-pc) (anim-array texture-anim-array)) + (let* ((sz (-> anim-array length)) + (qwc (+ 1 (/ (+ 3 sz) 4)))) + (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) + bucket + ) + (pc-texture-anim-flag start-anim-array dma-buf) + (pc-texture-anim-flag-id id dma-buf :qwc qwc) + (let ((morph (-> anim-array array-data 0 frame-time)) + (vec (the vector (-> dma-buf base))) + ) + (set! (-> vec x) morph) + ) + (&+! (-> dma-buf base) 16) + (dotimes (i sz) + (let ((tex (-> anim-array array-data i tex))) + (set! (-> (the (pointer uint32) (-> dma-buf base)) i) + (if tex (-> tex dest 0) + -1) + ) + ) + ) + (&+! (-> dma-buf base) (- (* 16 qwc) 16)) + (pc-texture-anim-flag finish-anim-array dma-buf) + ) + ) + (none) + ) (defun update-texture-anim ((bucket bucket-id) (anim-array texture-anim-array)) @@ -902,96 +930,23 @@ struct SlimeInput { (return #f) ) ((= anim-array *darkjak-texture-anim-array*) - ;; darkjak is simple, and we reimplemented it in C++. - ;; so we just have to send the frame-time value. - ;; (format *stdcon* "doing darkjak~%") - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag darkjak dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc darkjak) anim-array) (return #f) ) - ((= anim-array *jakb-prison-texture-anim-array*) - ;; prison is simple, and we reimplemented it in C++. - ;; so we just have to send the frame-time value. - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag prison-jak dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc prison-jak) anim-array) (return #f) ) - ((= anim-array *darkjak-hires-texture-anim-array*) - ;; oracle is simple, and we reimplemented it in C++. - ;; so we just have to send the frame-time value. - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag oracle-jak dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc oracle-jak) anim-array) (return #f) ) ((= anim-array *darkjak-hires-nest-texture-anim-array*) - ;; oracle is simple, and we reimplemented it in C++. - ;; so we just have to send the frame-time value. - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag nest-jak dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc nest-jak) anim-array) (return #f) ) ((= anim-array *kor-transform-texture-anim-array*) - ;; kor is simple, and we reimplemented it in C++. - ;; so we just have to send the frame-time value. - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag kor-transform dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc kor-transform) anim-array) (return #f) ) (else diff --git a/goal_src/jak3/engine/gfx/texture/texture-anim.gc b/goal_src/jak3/engine/gfx/texture/texture-anim.gc index 4f98a2b7b7a..63ac9d4792a 100644 --- a/goal_src/jak3/engine/gfx/texture/texture-anim.gc +++ b/goal_src/jak3/engine/gfx/texture/texture-anim.gc @@ -435,6 +435,35 @@ 0 ) +(defun pc-clut-blender ((bucket bucket-id) (id texture-anim-pc) (anim-array texture-anim-array)) + (let* ((sz (-> anim-array length)) + (qwc (+ 1 (/ (+ 3 sz) 4)))) + (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) + bucket + ) + (pc-texture-anim-flag start-anim-array dma-buf) + (pc-texture-anim-flag-id id dma-buf :qwc qwc) + (let ((morph (-> anim-array array-data 0 frame-time)) + (vec (the vector (-> dma-buf base))) + ) + (set! (-> vec x) morph) + ) + (&+! (-> dma-buf base) 16) + (dotimes (i sz) + (let ((tex (-> anim-array array-data i tex))) + (set! (-> (the (pointer uint32) (-> dma-buf base)) i) + (if tex (-> tex dest 0) + -1) + ) + ) + ) + (&+! (-> dma-buf base) (- (* 16 qwc) 16)) + (pc-texture-anim-flag finish-anim-array dma-buf) + ) + ) + (none) + ) + ;; WARN: Function update-texture-anim has a return type of none, but the expression builder found a return statement. (defun update-texture-anim ((bucket bucket-id) (anim-array texture-anim-array)) (let ((anim-idx 0)) @@ -471,35 +500,11 @@ ;; (return #f) ) ((*darkjak-texture-anim-array*) - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag darkjak dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc darkjak) anim-array) (return #f) ) ((*darkjak-highres-texture-anim-array*) - (with-dma-buffer-add-bucket ((dma-buf (-> *display* frames (-> *display* on-screen) global-buf)) - bucket - ) - (pc-texture-anim-flag start-anim-array dma-buf) - (pc-texture-anim-flag darkjak-highres dma-buf :qwc 1) - (let ((morph (-> anim-array array-data 0 frame-time)) - (vec (the vector (-> dma-buf base))) - ) - (set! (-> vec x) morph) - ) - (&+! (-> dma-buf base) 16) - (pc-texture-anim-flag finish-anim-array dma-buf) - ) + (pc-clut-blender bucket (texture-anim-pc darkjak-highres) anim-array) (return #f) ) ((*skull-gem-texture-anim-array*)