template_cache.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #pragma once
  2. #include "gl/humanoid/humanoid_types.h"
  3. #include "scene_renderer.h"
  4. #include <QMatrix4x4>
  5. #include <QVector3D>
  6. #include <cstdint>
  7. #include <functional>
  8. #include <limits>
  9. #include <list>
  10. #include <mutex>
  11. #include <string>
  12. #include <unordered_map>
  13. #include <vector>
  14. namespace Render::GL {
  15. inline constexpr std::uint8_t k_anim_frame_count = 16;
  16. inline constexpr std::uint8_t k_template_variant_count = 8;
  17. class Mesh;
  18. class Texture;
  19. class Shader;
  20. struct AnimationInputs;
  21. enum class AnimState : std::uint8_t {
  22. Idle = 0,
  23. Move = 1,
  24. Run = 2,
  25. AttackMelee = 3,
  26. AttackRanged = 4,
  27. Construct = 5,
  28. Heal = 6,
  29. Hit = 7
  30. };
  31. struct AnimKey {
  32. AnimState state{AnimState::Idle};
  33. CombatAnimPhase combat_phase{CombatAnimPhase::Idle};
  34. std::uint8_t frame{0};
  35. std::uint8_t attack_variant{0};
  36. };
  37. struct TemplateKey {
  38. std::string renderer_id;
  39. std::uint32_t owner_id{0};
  40. std::uint8_t lod{0};
  41. std::uint8_t mount_lod{0};
  42. std::uint8_t variant{0};
  43. std::uint8_t attack_variant{0};
  44. AnimState state{AnimState::Idle};
  45. CombatAnimPhase combat_phase{CombatAnimPhase::Idle};
  46. std::uint8_t frame{0};
  47. bool operator==(const TemplateKey &other) const {
  48. return renderer_id == other.renderer_id && owner_id == other.owner_id &&
  49. lod == other.lod && mount_lod == other.mount_lod &&
  50. variant == other.variant && attack_variant == other.attack_variant &&
  51. state == other.state && combat_phase == other.combat_phase &&
  52. frame == other.frame;
  53. }
  54. };
  55. struct TemplateKeyHash {
  56. std::size_t operator()(const TemplateKey &key) const noexcept;
  57. };
  58. struct RecordedMeshCmd {
  59. Mesh *mesh{nullptr};
  60. Texture *texture{nullptr};
  61. Shader *shader{nullptr};
  62. QMatrix4x4 local_model;
  63. QVector3D color{1.0F, 1.0F, 1.0F};
  64. float alpha{1.0F};
  65. int material_id{0};
  66. };
  67. struct PoseTemplate {
  68. std::vector<RecordedMeshCmd> commands;
  69. };
  70. class TemplateRecorder : public Renderer {
  71. public:
  72. TemplateRecorder() = default;
  73. void reset(std::size_t reserve_hint = 0);
  74. auto take_commands() -> std::vector<RecordedMeshCmd> {
  75. return std::move(m_commands);
  76. }
  77. [[nodiscard]] auto commands() const -> const std::vector<RecordedMeshCmd> & {
  78. return m_commands;
  79. }
  80. void mesh(Mesh *mesh, const QMatrix4x4 &model, const QVector3D &color,
  81. Texture *texture = nullptr, float alpha = 1.0F,
  82. int material_id = 0) override;
  83. void cylinder(const QVector3D &, const QVector3D &, float, const QVector3D &,
  84. float) override {}
  85. void selection_ring(const QMatrix4x4 &, float, float,
  86. const QVector3D &) override {}
  87. void grid(const QMatrix4x4 &, const QVector3D &, float, float,
  88. float) override {}
  89. void selection_smoke(const QMatrix4x4 &, const QVector3D &, float) override {}
  90. void healing_beam(const QVector3D &, const QVector3D &, const QVector3D &,
  91. float, float, float, float) override {}
  92. void healer_aura(const QVector3D &, const QVector3D &, float, float,
  93. float) override {}
  94. void combat_dust(const QVector3D &, const QVector3D &, float, float,
  95. float) override {}
  96. void stone_impact(const QVector3D &, const QVector3D &, float, float,
  97. float) override {}
  98. void mode_indicator(const QMatrix4x4 &, int, const QVector3D &,
  99. float) override {}
  100. private:
  101. std::vector<RecordedMeshCmd> m_commands;
  102. };
  103. class TemplateCache {
  104. public:
  105. static constexpr std::size_t k_default_max_entries = 500'000;
  106. static constexpr std::size_t k_dense_attack_variant_slots = 8;
  107. static constexpr std::size_t k_dense_variant_slots = k_template_variant_count;
  108. static constexpr std::size_t k_dense_anim_state_slots = 305;
  109. static constexpr std::size_t k_dense_anim_slot_count =
  110. k_dense_variant_slots * k_dense_attack_variant_slots *
  111. k_dense_anim_state_slots;
  112. struct DenseDomainHandle {
  113. static constexpr std::size_t k_invalid =
  114. std::numeric_limits<std::size_t>::max();
  115. std::size_t value{k_invalid};
  116. [[nodiscard]] auto is_valid() const -> bool { return value != k_invalid; }
  117. };
  118. static auto instance() noexcept -> TemplateCache & {
  119. static TemplateCache inst;
  120. return inst;
  121. }
  122. auto get_or_build(const TemplateKey &key,
  123. const std::function<PoseTemplate()> &builder)
  124. -> const PoseTemplate *;
  125. auto get_dense_domain_handle(const std::string &renderer_id,
  126. std::uint32_t owner_id, std::uint8_t lod,
  127. std::uint8_t mount_lod) -> DenseDomainHandle;
  128. auto get_or_build_dense(
  129. DenseDomainHandle domain, std::size_t dense_slot, const TemplateKey &key,
  130. const std::function<PoseTemplate()> &builder) -> const PoseTemplate *;
  131. static auto dense_slot_index(std::uint8_t variant,
  132. const AnimKey &anim_key) -> std::size_t;
  133. void clear();
  134. void set_max_entries(std::size_t max) {
  135. std::lock_guard<std::mutex> lock(m_mutex);
  136. m_max_entries = max;
  137. }
  138. [[nodiscard]] auto size() const -> std::size_t {
  139. std::lock_guard<std::mutex> lock(m_mutex);
  140. return m_cache.size();
  141. }
  142. private:
  143. TemplateCache() = default;
  144. void evict_lru();
  145. void clear_dense_slot_for_key(const TemplateKey &key);
  146. auto set_dense_slot(DenseDomainHandle domain, std::size_t dense_slot,
  147. const PoseTemplate *tpl) -> void;
  148. using LruList = std::list<TemplateKey>;
  149. struct CacheEntry {
  150. PoseTemplate tpl;
  151. LruList::iterator lru_it;
  152. };
  153. struct DenseDomainKey {
  154. std::string renderer_id;
  155. std::uint32_t owner_id{0};
  156. std::uint8_t lod{0};
  157. std::uint8_t mount_lod{0};
  158. bool operator==(const DenseDomainKey &other) const {
  159. return renderer_id == other.renderer_id && owner_id == other.owner_id &&
  160. lod == other.lod && mount_lod == other.mount_lod;
  161. }
  162. };
  163. struct DenseDomainKeyHash {
  164. std::size_t operator()(const DenseDomainKey &key) const noexcept;
  165. };
  166. struct DenseDomainEntry {
  167. DenseDomainKey key;
  168. std::vector<const PoseTemplate *> template_slots;
  169. };
  170. std::unordered_map<TemplateKey, CacheEntry, TemplateKeyHash> m_cache;
  171. LruList m_lru;
  172. std::unordered_map<DenseDomainKey, std::size_t, DenseDomainKeyHash>
  173. m_dense_domain_lookup;
  174. std::vector<DenseDomainEntry> m_dense_domains;
  175. std::size_t m_max_entries{k_default_max_entries};
  176. mutable std::mutex m_mutex;
  177. };
  178. auto make_anim_key(const AnimationInputs &anim, float phase_offset,
  179. std::uint8_t attack_variant) -> AnimKey;
  180. auto make_animation_inputs(const AnimKey &key) -> AnimationInputs;
  181. } // namespace Render::GL