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*)