From 4362a0cccc0616d2e77357adb20edfefb765cb9d Mon Sep 17 00:00:00 2001 From: Egor Orachyov Date: Sat, 3 Aug 2024 18:09:44 +0300 Subject: [PATCH] gh-59: setup texture manager for basic management of texture assets --- .../freetype/freetype_asset_loader.cpp | 4 +- .../freetype/freetype_asset_loader.hpp | 1 + engine/plugins/freetype/freetype_font.cpp | 27 ++- engine/plugins/freetype/freetype_font.hpp | 12 +- .../runtime/asset/texture_asset_loader.cpp | 48 +++-- engine/runtime/asset/_rtti.cpp | 1 + engine/runtime/asset/asset.hpp | 2 +- engine/runtime/asset/asset_loader.hpp | 21 ++- engine/runtime/asset/asset_manager.cpp | 50 ++++-- engine/runtime/asset/asset_manager.hpp | 32 ++-- engine/runtime/core/ref.hpp | 2 +- engine/runtime/core/weak_ref.hpp | 15 +- engine/runtime/gfx/gfx_sampler.hpp | 2 + engine/runtime/gfx/gfx_texture.cpp | 24 +++ engine/runtime/gfx/gfx_texture.hpp | 3 + engine/runtime/grc/texture.cpp | 122 ++++++++----- engine/runtime/grc/texture.hpp | 66 ++++--- engine/runtime/grc/texture_manager.cpp | 167 +++++++++++++++--- engine/runtime/grc/texture_manager.hpp | 51 +++++- engine/runtime/grc/texture_pool.cpp | 122 +++++++++++++ engine/runtime/grc/texture_pool.hpp | 78 ++++++++ engine/runtime/platform/application.cpp | 18 +- engine/runtime/render/aux_draw_manager.cpp | 9 +- engine/runtime/render/aux_draw_manager.hpp | 2 + engine/runtime/scene/scene.hpp | 2 +- engine/runtime/system/engine.cpp | 8 +- 26 files changed, 700 insertions(+), 189 deletions(-) create mode 100644 engine/runtime/grc/texture_pool.cpp create mode 100644 engine/runtime/grc/texture_pool.hpp diff --git a/engine/plugins/freetype/freetype_asset_loader.cpp b/engine/plugins/freetype/freetype_asset_loader.cpp index a931f59d9..f5442fe44 100644 --- a/engine/plugins/freetype/freetype_asset_loader.cpp +++ b/engine/plugins/freetype/freetype_asset_loader.cpp @@ -27,7 +27,6 @@ #include "freetype_asset_loader.hpp" -#include "freetype_font.hpp" #include "freetype_import_data.hpp" #include "grc/font.hpp" #include "profiler/profiler.hpp" @@ -57,7 +56,8 @@ namespace wmoge { asset->set_name(name); asset->set_import_data(meta.import_data); - return FreetypeFont::load(font, import_data->source_files[0].file, import_data->height, import_data->glyphs_in_row); + FreetypeFont loader; + return loader.load(font, import_data->source_files[0].file, import_data->height, import_data->glyphs_in_row); } }// namespace wmoge \ No newline at end of file diff --git a/engine/plugins/freetype/freetype_asset_loader.hpp b/engine/plugins/freetype/freetype_asset_loader.hpp index dae159223..26bdb93da 100644 --- a/engine/plugins/freetype/freetype_asset_loader.hpp +++ b/engine/plugins/freetype/freetype_asset_loader.hpp @@ -28,6 +28,7 @@ #pragma once #include "asset/asset_loader.hpp" +#include "freetype_font.hpp" namespace wmoge { diff --git a/engine/plugins/freetype/freetype_font.cpp b/engine/plugins/freetype/freetype_font.cpp index c57498bab..ac2e5a906 100644 --- a/engine/plugins/freetype/freetype_font.cpp +++ b/engine/plugins/freetype/freetype_font.cpp @@ -32,12 +32,18 @@ #include "grc/texture.hpp" #include "platform/file_system.hpp" #include "profiler/profiler.hpp" -#include "system/engine.hpp" +#include "system/ioc_container.hpp" #include namespace wmoge { + FreetypeFont::FreetypeFont() { + m_gfx_driver = IocContainer::iresolve_v(); + m_file_system = IocContainer::iresolve_v(); + m_texture_manager = IocContainer::iresolve_v(); + } + Status FreetypeFont::load(const Ref& font, const std::string& path, int height, int glyphs_in_row) { WG_AUTO_PROFILE_ASSET("FreetypeFont::load"); @@ -45,7 +51,7 @@ namespace wmoge { static const int GLYPHS_BITMAP_OFFSET = 2; std::vector ttf_data; - if (!Engine::instance()->file_system()->read_file(path, ttf_data)) { + if (!m_file_system->read_file(path, ttf_data)) { WG_LOG_ERROR("failed to load font data from asset pak " << path); return StatusCode::FailedRead; } @@ -153,15 +159,21 @@ namespace wmoge { sampler_desc.brd_clr = GfxSampBrdClr::Black; sampler_desc.mag_flt = GfxSampFlt::Linear; sampler_desc.min_flt = GfxSampFlt::LinearMipmapLinear; - sampler_desc.max_anisotropy = Engine::instance()->gfx_driver()->device_caps().max_anisotropy; + sampler_desc.max_anisotropy = m_gfx_driver->device_caps().max_anisotropy; sampler_desc.u = GfxSampAddress::ClampToBorder; sampler_desc.v = GfxSampAddress::ClampToBorder; TexCompressionParams compression_params{}; compression_params.format = TexCompressionFormat::BC4; - font_desc.texture = make_ref(GfxFormat::R8, bitmap_width, bitmap_height, GfxTexSwizz::RRRRtoRGBA); - font_desc.texture->set_name(SID(font->get_name().str() + "_texture")); + TextureFlags flags; + flags.set(TextureFlag::Pooled); + flags.set(TextureFlag::FromDisk); + flags.set(TextureFlag::Font); + flags.set(TextureFlag::Compressed); + + font_desc.texture = m_texture_manager->create_2d(flags, GfxFormat::R8, bitmap_width, bitmap_height, GfxTexSwizz::RRRRtoRGBA); + font_desc.texture->set_name(SID(font->get_name().str() + "_bitmap")); font_desc.texture->set_sampler_from_desc(sampler_desc); font_desc.texture->set_compression(compression_params); font_desc.texture->set_source_images({bitmap}); @@ -174,10 +186,7 @@ namespace wmoge { WG_LOG_ERROR("failed to compress font texture " << font->get_name()); return StatusCode::Error; } - if (!font_desc.texture->generate_gfx_resource()) { - WG_LOG_ERROR("failed to create gfx font texture " << font->get_name()); - return StatusCode::Error; - } + m_texture_manager->init(font_desc.texture.get()); return font->init(font_desc); } diff --git a/engine/plugins/freetype/freetype_font.hpp b/engine/plugins/freetype/freetype_font.hpp index 2b1650428..7a48c459d 100644 --- a/engine/plugins/freetype/freetype_font.hpp +++ b/engine/plugins/freetype/freetype_font.hpp @@ -29,7 +29,10 @@ #include "core/status.hpp" #include "core/string_utils.hpp" +#include "gfx/gfx_driver.hpp" #include "grc/font.hpp" +#include "grc/texture_manager.hpp" +#include "platform/file_system.hpp" namespace wmoge { @@ -39,6 +42,8 @@ namespace wmoge { */ class FreetypeFont { public: + FreetypeFont(); + /** * @brief Loads font from a .ttf file from file system using specified height in pixels * @@ -51,7 +56,12 @@ namespace wmoge { * * @return True if font loaded */ - static Status load(const Ref& font, const std::string& path, int height = 40, int glyphs_in_row = 16); + Status load(const Ref& font, const std::string& path, int height = 40, int glyphs_in_row = 16); + + private: + GfxDriver* m_gfx_driver; + FileSystem* m_file_system; + TextureManager* m_texture_manager; }; }// namespace wmoge \ No newline at end of file diff --git a/engine/plugins/runtime/asset/texture_asset_loader.cpp b/engine/plugins/runtime/asset/texture_asset_loader.cpp index 7817bd4a9..916be6e1a 100644 --- a/engine/plugins/runtime/asset/texture_asset_loader.cpp +++ b/engine/plugins/runtime/asset/texture_asset_loader.cpp @@ -32,9 +32,11 @@ #include "gfx/gfx_driver.hpp" #include "grc/image.hpp" #include "grc/texture.hpp" +#include "grc/texture_manager.hpp" #include "grc/texture_resize.hpp" #include "profiler/profiler.hpp" #include "system/engine.hpp" +#include "system/ioc_container.hpp" namespace wmoge { @@ -63,13 +65,21 @@ namespace wmoge { return StatusCode::FailedResize; } - Ref texture = make_ref( - import_data->format, - source_image->get_width(), - source_image->get_height()); + auto texture_manager = IocContainer::iresolve_v(); + + TextureFlags flags; + flags.set(TextureFlag::Pooled); + flags.set(TextureFlag::FromDisk); + flags.set(TextureFlag::Compressed, import_data->compression.format != TexCompressionFormat::Unknown); + + Ref texture = + texture_manager->create_2d(flags, + import_data->format, + source_image->get_width(), + source_image->get_height()); if (!texture) { - WG_LOG_ERROR("Failed to instantiate texture " << name); + WG_LOG_ERROR("failed to instantiate texture " << name); return StatusCode::FailedInstantiate; } @@ -93,10 +103,7 @@ namespace wmoge { return StatusCode::Error; } } - if (!texture->generate_gfx_resource()) { - WG_LOG_ERROR("failed create gfx asset for " << name); - return StatusCode::Error; - } + texture_manager->init(texture.get()); return WG_OK; } @@ -144,13 +151,21 @@ namespace wmoge { } } - Ref texture = make_ref( - import_data->format, - source_images.front()->get_width(), - source_images.front()->get_height()); + auto texture_manager = IocContainer::iresolve_v(); + + TextureFlags flags; + flags.set(TextureFlag::Pooled); + flags.set(TextureFlag::FromDisk); + flags.set(TextureFlag::Compressed, import_data->compression.format != TexCompressionFormat::Unknown); + + Ref texture = + texture_manager->create_cube(flags, + import_data->format, + source_images.front()->get_width(), + source_images.front()->get_height()); if (!texture) { - WG_LOG_ERROR("Failed to instantiate texture " << name); + WG_LOG_ERROR("failed to instantiate texture " << name); return StatusCode::Error; } @@ -174,10 +189,7 @@ namespace wmoge { return StatusCode::Error; } } - if (!texture->generate_gfx_resource()) { - WG_LOG_ERROR("failed create gfx asset for " << name); - return StatusCode::Error; - } + texture_manager->init(texture.get()); return WG_OK; } diff --git a/engine/runtime/asset/_rtti.cpp b/engine/runtime/asset/_rtti.cpp index 53a534231..a5407933f 100644 --- a/engine/runtime/asset/_rtti.cpp +++ b/engine/runtime/asset/_rtti.cpp @@ -39,6 +39,7 @@ namespace wmoge { rtti_type(); rtti_type(); rtti_type(); + rtti_type(); rtti_type(); } diff --git a/engine/runtime/asset/asset.hpp b/engine/runtime/asset/asset.hpp index e90e1bdc2..76a0a7e8f 100644 --- a/engine/runtime/asset/asset.hpp +++ b/engine/runtime/asset/asset.hpp @@ -92,7 +92,7 @@ namespace wmoge { * @class Asset * @brief Base class for any engine asset */ - class Asset : public WeakRefCnt { + class Asset : public WeakRefCnt { public: WG_RTTI_CLASS(Asset, RttiObject); diff --git a/engine/runtime/asset/asset_loader.hpp b/engine/runtime/asset/asset_loader.hpp index 50f1eb108..e0c3c7cad 100644 --- a/engine/runtime/asset/asset_loader.hpp +++ b/engine/runtime/asset/asset_loader.hpp @@ -50,7 +50,26 @@ namespace wmoge { WG_RTTI_CLASS_BEGIN(AssetLoader) { WG_RTTI_META_DATA(RttiUiHint("Interface for an asset loader to implement custom loading")); - // WG_RTTI_METHOD(load, {"name", "meta", "asset"}, {RttiUiHint("Instantiates and loads a particular asset type from meta info")}); + } + WG_RTTI_END; + + /** + * @class AssetUnloader + * @brief Class responsible for unloading assets(s) of a specific type + */ + class AssetUnloader : public RttiObject { + public: + WG_RTTI_CLASS(AssetUnloader, RttiObject); + + AssetUnloader() = default; + virtual ~AssetUnloader() = default; + + virtual Status unload(Asset* asset) { return StatusCode::NotImplemented; } + virtual RttiClass* get_asset_type() { return nullptr; } + }; + + WG_RTTI_CLASS_BEGIN(AssetUnloader) { + WG_RTTI_META_DATA(RttiUiHint("Interface for an asset unloader to implement custom unloading")); } WG_RTTI_END; diff --git a/engine/runtime/asset/asset_manager.cpp b/engine/runtime/asset/asset_manager.cpp index 803779d84..ff2695a3e 100644 --- a/engine/runtime/asset/asset_manager.cpp +++ b/engine/runtime/asset/asset_manager.cpp @@ -44,6 +44,20 @@ namespace wmoge { m_file_system = IocContainer::iresolve_v(); m_type_storage = IocContainer::iresolve_v(); m_event_manager = IocContainer::iresolve_v(); + + m_callback = std::make_shared([this](Asset* asset) { + std::lock_guard guard(m_mutex); + + auto* rtti = asset->get_class(); + auto unloader = find_unloader(rtti); + auto& id = asset->get_id(); + + if (unloader) { + (*unloader)->unload(asset); + } + + m_assets.erase(id); + }); } AsyncResult> AssetManager::load_async(const AssetId& name, AssetCallback callback) { @@ -113,6 +127,7 @@ namespace wmoge { m_event_manager->dispatch(event); std::lock_guard guard(m_mutex); + asset->set_release_callback(m_callback); m_assets[name] = WeakRef(asset); async_op->set_result(std::move(asset)); return 0; @@ -180,6 +195,11 @@ namespace wmoge { m_loaders[loader->get_class_name()] = std::move(loader); } + void AssetManager::add_unloader(Ref unloader) { + std::lock_guard guard(m_mutex); + m_unloaders[unloader->get_asset_type()] = std::move(unloader); + } + void AssetManager::add_pak(std::shared_ptr pak) { std::lock_guard guard(m_mutex); m_paks.push_back(std::move(pak)); @@ -191,6 +211,12 @@ namespace wmoge { return query != m_loaders.end() ? std::make_optional(query->second.get()) : std::nullopt; } + std::optional AssetManager::find_unloader(RttiClass* rtti) { + std::lock_guard guard(m_mutex); + auto query = m_unloaders.find(rtti); + return query != m_unloaders.end() ? std::make_optional(query->second.get()) : std::nullopt; + } + std::optional AssetManager::find_meta(const AssetId& asset) { std::lock_guard guard(m_mutex); @@ -215,20 +241,6 @@ namespace wmoge { return std::nullopt; } - void AssetManager::gc() { - WG_AUTO_PROFILE_ASSET("AssetManager::gc"); - - std::lock_guard guard(m_mutex); - int evicted = 0; - for (auto iter = m_assets.begin(); iter != m_assets.end(); ++iter) { - if (iter->second.acquire()->refs_count() == 1) { - iter = m_assets.erase(iter); - evicted += 1; - } - } - WG_LOG_INFO("gc " << evicted << " unreferenced assets"); - } - void AssetManager::clear() { WG_AUTO_PROFILE_ASSET("AssetManager::clear"); @@ -249,6 +261,16 @@ namespace wmoge { add_loader(loader->instantiate().cast()); } + std::vector unloaders = m_type_storage->find_classes([](const Ref& type) { + return type->is_subtype_of(AssetUnloader::get_class_static()) && type->can_instantiate(); + }); + + for (auto& unloader : unloaders) { + assert(unloader); + assert(unloader->can_instantiate()); + add_unloader(unloader->instantiate().cast()); + } + add_pak(std::make_shared()); } diff --git a/engine/runtime/asset/asset_manager.hpp b/engine/runtime/asset/asset_manager.hpp index ceb738c7b..0984d4aac 100644 --- a/engine/runtime/asset/asset_manager.hpp +++ b/engine/runtime/asset/asset_manager.hpp @@ -126,31 +126,21 @@ namespace wmoge { /** @brief Add specific format asset loader */ void add_loader(Ref loader); + /** @brief Add specific format asset loader */ + void add_unloader(Ref unloader); + /** @brief Add additional pak for assets loading */ void add_pak(std::shared_ptr pak); /** @brief Find asset loader by loader name */ std::optional find_loader(const Strid& loader); + /** @brief Find asset unloader by asset type */ + std::optional find_unloader(RttiClass* rtti); + /** @brief Find asset meta by asset name */ std::optional find_meta(const AssetId& asset); - /** - * @brief Clear from a cache only unused asset - * - * This is a costly operation, which traverses all cached - * assets in a asset system and evicts those entries, - * which are not used by the engine at this time. - * - * @note This operation allows to free some used memory and assets - * at cost of traversal plus potential loading of asset, - * if they requested in future. - * - * @note Call this operation with regular intervals in couple of frames - * or on scene changes or large streaming chunks updates. - */ - void gc(); - /** * @brief Evicts all loaded assets from a cache * @@ -180,10 +170,12 @@ namespace wmoge { }; private: - buffered_vector> m_paks; - flat_map> m_assets; - flat_map m_loading; - flat_map> m_loaders; + buffered_vector> m_paks; + flat_map> m_assets; + flat_map m_loading; + flat_map> m_loaders; + flat_map> m_unloaders; + std::shared_ptr> m_callback; class FileSystem* m_file_system = nullptr; class RttiTypeStorage* m_type_storage = nullptr; diff --git a/engine/runtime/core/ref.hpp b/engine/runtime/core/ref.hpp index 6255c041a..0f200a34f 100644 --- a/engine/runtime/core/ref.hpp +++ b/engine/runtime/core/ref.hpp @@ -77,7 +77,7 @@ namespace wmoge { public: Ref() = default; - Ref(std::nullptr_t){}; + Ref(std::nullptr_t) {}; explicit Ref(T* object) { m_ptr = ref(object); diff --git a/engine/runtime/core/weak_ref.hpp b/engine/runtime/core/weak_ref.hpp index cebfe884c..1fd6545b6 100644 --- a/engine/runtime/core/weak_ref.hpp +++ b/engine/runtime/core/weak_ref.hpp @@ -30,6 +30,8 @@ #include "core/ref.hpp" #include "core/synchronization.hpp" +#include +#include #include #include @@ -62,24 +64,33 @@ namespace wmoge { * @class WeakRefCnt * @brief Base class for any shared object which wants weak referencing support * + * @tparam Type of class to be declared weak referencable * @tparam BaseRefCntClass Base class which provides shared ref cnt mechanism */ - template + template class WeakRefCnt : public BaseRefCntClass { public: + using ReleaseCallback = std::function; + using ReleaseCallbackRef = std::shared_ptr; + ~WeakRefCnt() override = default; + void set_release_callback(ReleaseCallbackRef callback) { m_callback_ref = std::move(callback); } [[nodiscard]] const Ref& get_weak_access() const { return m_weak_access; } protected: void reach_zero() override { if (m_weak_access->try_release_object()) { + if (m_callback_ref) { + (*m_callback_ref)(dynamic_cast(this)); + } BaseRefCntClass::destroy(); } } private: Ref m_weak_access = make_ref(this); + ReleaseCallbackRef m_callback_ref; }; template @@ -96,7 +107,7 @@ namespace wmoge { public: WeakRef() = default; - WeakRef(std::nullptr_t){}; + WeakRef(std::nullptr_t) {}; explicit WeakRef(T* object) { m_ptr = std::move(weak_ref_access(object)); diff --git a/engine/runtime/gfx/gfx_sampler.hpp b/engine/runtime/gfx/gfx_sampler.hpp index 990943241..dc968f24f 100644 --- a/engine/runtime/gfx/gfx_sampler.hpp +++ b/engine/runtime/gfx/gfx_sampler.hpp @@ -84,6 +84,8 @@ namespace wmoge { virtual const GfxSamplerDesc& desc() const = 0; }; + using GfxSamplerRef = Ref; + }// namespace wmoge namespace std { diff --git a/engine/runtime/gfx/gfx_texture.cpp b/engine/runtime/gfx/gfx_texture.cpp index cfd438093..8ff30e235 100644 --- a/engine/runtime/gfx/gfx_texture.cpp +++ b/engine/runtime/gfx/gfx_texture.cpp @@ -46,4 +46,28 @@ namespace wmoge { return *this == other; } + GfxTextureDesc GfxTextureDesc::make_2d(GfxFormat format, int width, int height, GfxTexSwizz swizz) { + GfxTextureDesc desc; + desc.format = format; + desc.width = width; + desc.height = height; + desc.swizz = swizz; + desc.depth = 1; + desc.array_slices = 1; + desc.tex_type = GfxTex::Tex2d; + return desc; + } + + GfxTextureDesc GfxTextureDesc::make_cube(GfxFormat format, int width, int height, GfxTexSwizz swizz) { + GfxTextureDesc desc; + desc.format = format; + desc.width = width; + desc.height = height; + desc.swizz = swizz; + desc.depth = 1; + desc.array_slices = 6; + desc.tex_type = GfxTex::TexCube; + return desc; + } + }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/gfx/gfx_texture.hpp b/engine/runtime/gfx/gfx_texture.hpp index 2d953db1f..6d203997b 100644 --- a/engine/runtime/gfx/gfx_texture.hpp +++ b/engine/runtime/gfx/gfx_texture.hpp @@ -49,6 +49,9 @@ namespace wmoge { GfxFormat format = GfxFormat::RGBA8; GfxMemUsage mem_usage = GfxMemUsage::GpuLocal; GfxTexUsages usages; + + static GfxTextureDesc make_2d(GfxFormat format, int width, int height, GfxTexSwizz swizz = GfxTexSwizz::None); + static GfxTextureDesc make_cube(GfxFormat format, int width, int height, GfxTexSwizz swizz = GfxTexSwizz::None); }; /** diff --git a/engine/runtime/grc/texture.cpp b/engine/runtime/grc/texture.cpp index 3a7e185d1..9dc2f5203 100644 --- a/engine/runtime/grc/texture.cpp +++ b/engine/runtime/grc/texture.cpp @@ -33,20 +33,27 @@ #include "gfx/gfx_driver.hpp" #include "io/yaml.hpp" #include "profiler/profiler.hpp" -#include "system/engine.hpp" +#include "system/ioc_container.hpp" #include namespace wmoge { - Texture::Texture(GfxFormat format, int width, int height, int depth, int array_slices, GfxTexSwizz swizz) { - m_format = format; - m_width = width; - m_height = height; - m_depth = depth; - m_array_slices = array_slices; - m_mips = 1; - m_swizz = swizz; + Texture::~Texture() { + if (m_callback) { + (*m_callback)(this); + } + } + + Texture::Texture(TextureFlags flags, GfxTextureDesc desc) { + m_flags = flags; + m_format = desc.format; + m_width = desc.width; + m_height = desc.height; + m_depth = desc.depth; + m_array_slices = desc.array_slices; + m_mips = desc.mips_count; + m_swizz = desc.swizz; } void Texture::set_source_images(std::vector> images) { @@ -56,11 +63,17 @@ namespace wmoge { m_sampler = sampler; } void Texture::set_sampler_from_desc(const GfxSamplerDesc& desc) { - set_sampler(Engine::instance()->gfx_driver()->make_sampler(desc, SID(desc.to_string()))); + IocContainer::iresolve_v()->make_sampler(desc, SID(desc.to_string())); } void Texture::set_compression(const TexCompressionParams& params) { m_compression = params; } + void Texture::set_flags(const TextureFlags& flags) { + m_flags = flags; + } + void Texture::set_texture_callback(CallbackRef callback) { + m_callback = callback; + } Status Texture::generate_mips() { WG_AUTO_PROFILE_ASSET("Texture::generate_mips"); @@ -89,13 +102,17 @@ namespace wmoge { Status Texture::generate_compressed_data() { WG_AUTO_PROFILE_ASSET("Texture::generate_compressed_data"); + if (!m_flags.get(TextureFlag::Compressed)) { + WG_LOG_INFO("no compression flag on texutre " << get_name()); + return StatusCode::InvalidState; + } if (m_compression.format == TexCompressionFormat::Unknown) { WG_LOG_INFO("no compression setup for texture " << get_name()); - return WG_OK; + return StatusCode::InvalidState; } if (m_images.empty()) { WG_LOG_INFO("no source to compress " << get_name()); - return WG_OK; + return StatusCode::InvalidState; } std::vector source_data; @@ -145,44 +162,36 @@ namespace wmoge { return WG_OK; } - Status Texture::generate_gfx_resource() { - WG_AUTO_PROFILE_ASSET("Texture::generate_gfx_resource"); - if (!m_sampler) { - GfxSamplerDesc sampler_desc{}; - set_sampler_from_desc(sampler_desc); - } + Status Texture::create_gfx_resource(TexturePool& pool) { + WG_AUTO_PROFILE_ASSET("Texture::create_gfx_resource"); + assert(m_flags.get(TextureFlag::Pooled)); - GfxFormat format = m_format; - bool compressed = false; + const GfxTextureDesc desc = get_desc(); + m_texture = pool.allocate(desc, get_name()); - if (!m_compressed.empty() && m_compression.format != TexCompressionFormat::Unknown) { - format = m_format_compressed; - compressed = true; - } + return WG_OK; + } - Engine* engine = Engine::instance(); - GfxDriver* gfx_driver = engine->gfx_driver(); - - switch (m_tex_type) { - case GfxTex::Tex2d: - m_texture = gfx_driver->make_texture_2d(m_width, m_height, m_mips, format, m_usages, m_mem_usage, m_swizz, get_name()); - break; - case GfxTex::Tex2dArray: - m_texture = gfx_driver->make_texture_2d_array(m_width, m_height, m_mips, m_array_slices, format, m_usages, m_mem_usage, get_name()); - break; - case GfxTex::TexCube: - m_texture = gfx_driver->make_texture_cube(m_width, m_height, m_mips, format, m_usages, m_mem_usage, get_name()); - break; - default: - WG_LOG_ERROR("unknown texture gfx type " << get_name()); - return StatusCode::InvalidParameter; - } + Status Texture::delete_gfx_resource(TexturePool& pool) { + WG_AUTO_PROFILE_ASSET("Texture::delete_gfx_resource"); + assert(m_flags.get(TextureFlag::Pooled)); + + pool.release(m_texture); + m_texture.reset(); + + return Status(); + } + Status Texture::upload_gfx_data(GfxCmdListRef& cmd) { assert(m_depth == 1); assert(m_array_slices >= 1); assert(m_mips >= 1); + const bool is_compressed = m_flags.get(TextureFlag::Compressed); + assert(!is_compressed || m_format_compressed != GfxFormat::Unknown); + assert(is_compressed || m_format_compressed == GfxFormat::Unknown); + for (int array_slice = 0; array_slice < m_array_slices; array_slice++) { for (int mip = 0; mip < m_mips; mip++) { const int index = array_slice * m_mips + mip; @@ -190,20 +199,22 @@ namespace wmoge { Ref data = m_images[index]->get_pixel_data(); Rect2i rect = {0, 0, m_images[index]->get_width(), m_images[index]->get_height()}; - if (compressed) { + if (is_compressed) { data = m_compressed[index].data; rect = {0, 0, m_compressed[index].width, m_compressed[index].height}; } + array_view buffer(data->buffer(), data->size()); + switch (m_tex_type) { case GfxTex::Tex2d: - // gfx_ctx->update_texture_2d(m_texture, mip, rect, data); + cmd->update_texture_2d(m_texture, mip, rect, buffer); continue; case GfxTex::Tex2dArray: - // gfx_ctx->update_texture_2d_array(m_texture, mip, array_slice, rect, data); + cmd->update_texture_2d_array(m_texture, mip, array_slice, rect, buffer); continue; case GfxTex::TexCube: - // gfx_ctx->update_texture_cube(m_texture, mip, array_slice, rect, data); + cmd->update_texture_cube(m_texture, mip, array_slice, rect, buffer); continue; default: assert(false); @@ -214,12 +225,25 @@ namespace wmoge { return WG_OK; } - Texture2d::Texture2d(GfxFormat format, int width, int height, GfxTexSwizz swizz) : Texture(format, width, height, 1, 1, swizz) { - m_tex_type = GfxTex::Tex2d; + GfxTextureDesc Texture::get_desc() const { + GfxTextureDesc desc; + desc.width = m_width; + desc.height = m_height; + desc.depth = m_depth; + desc.array_slices = m_array_slices; + desc.mips_count = m_mips; + desc.mem_usage = m_mem_usage; + desc.usages = m_usages; + desc.swizz = m_swizz; + desc.format = m_format_compressed != GfxFormat::Unknown ? m_format_compressed : m_format; + desc.tex_type = m_tex_type; + return desc; + } + + Texture2d::Texture2d(TextureFlags flags, GfxTextureDesc desc) : Texture(flags, desc) { } - TextureCube::TextureCube(GfxFormat format, int width, int height) : Texture(format, width, height, 1, 6) { - m_tex_type = GfxTex::TexCube; + TextureCube::TextureCube(TextureFlags flags, GfxTextureDesc desc) : Texture(flags, desc) { } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/grc/texture.hpp b/engine/runtime/grc/texture.hpp index a8fefa1b8..a7829dc87 100644 --- a/engine/runtime/grc/texture.hpp +++ b/engine/runtime/grc/texture.hpp @@ -28,16 +28,32 @@ #pragma once #include "asset/asset.hpp" +#include "core/mask.hpp" +#include "gfx/gfx_cmd_list.hpp" #include "gfx/gfx_defs.hpp" #include "gfx/gfx_sampler.hpp" #include "gfx/gfx_texture.hpp" #include "grc/image.hpp" #include "grc/texture_compression.hpp" +#include "grc/texture_pool.hpp" #include "grc/texture_resize.hpp" #include "io/serialization.hpp" namespace wmoge { + /** @brief Flag assigned to texture asset */ + enum class TextureFlag { + Managed = 0,// Texture managed withing texture manager + Pooled, // Texture gpu memory allocated from pool + Streamed, // Texture can be streamed in-out from disk + Compressed, // Texture uses gpu compression to reduce footprint + FromDisk, // Texture loaded from disc as an asset + Font, // Texture created as a font glyph atlas + }; + + /** @brief Flags assigned to texture asset */ + using TextureFlags = Mask; + /** * @class Texture * @brief Base-class for any engine gpu texture asset which can be used for rendering @@ -46,32 +62,32 @@ namespace wmoge { public: WG_RTTI_CLASS(Texture, Asset); - Texture() = default; - ~Texture() override = default; + using Callback = std::function; + using CallbackRef = std::shared_ptr; + + Texture() = default; + ~Texture() override; /** - * @brief Create new texture of desired format and size - * - * @param format Base (with no compression) texture format - * @param width Width of the texture in pixels - * @param height Height of the texture in pixels - * @param depth Depth of the texture in pixels (in most cases 1) - * @param array_slices Number of slices for array or cube texture (in most cases 1) - * @param swizz Texture channels swizzling + * @brief Creates texture object from flags and gfx desc + * + * @brief flags Texture object usage flags + * @brief desc Gfx texture desc */ - Texture(GfxFormat format, int width, int height, int depth = 1, int array_slices = 1, GfxTexSwizz swizz = GfxTexSwizz::None); + Texture(TextureFlags flags, GfxTextureDesc desc); - virtual void set_source_images(std::vector> images); - virtual void set_sampler(const Ref& sampler); - virtual void set_sampler_from_desc(const GfxSamplerDesc& desc); - virtual void set_compression(const TexCompressionParams& params); + void set_source_images(std::vector> images); + void set_sampler(const Ref& sampler); + void set_sampler_from_desc(const GfxSamplerDesc& desc); + void set_compression(const TexCompressionParams& params); + void set_flags(const TextureFlags& flags); + void set_texture_callback(CallbackRef callback); - /** @brief Generate mip-chain for the image using source 0-mip faces data */ - virtual Status generate_mips(); - /** @brief Generate compressed texture data based on compression settings */ - virtual Status generate_compressed_data(); - /** @brief Create default gfx texture asset and sampler */ - virtual Status generate_gfx_resource(); + Status generate_mips(); + Status generate_compressed_data(); + Status create_gfx_resource(TexturePool& pool); + Status delete_gfx_resource(TexturePool& pool); + Status upload_gfx_data(GfxCmdListRef& cmd); [[nodiscard]] const std::vector>& get_images() const { return m_images; } [[nodiscard]] const std::vector& get_compressed() const { return m_compressed; } @@ -90,6 +106,8 @@ namespace wmoge { [[nodiscard]] GfxTexUsages get_usages() const { return m_usages; } [[nodiscard]] bool get_srgb() const { return m_srgb; } [[nodiscard]] const TexCompressionParams& get_compression() const { return m_compression; } + [[nodiscard]] const TextureFlags& get_flgas() const { return m_flags; } + [[nodiscard]] GfxTextureDesc get_desc() const; protected: std::vector> m_images; @@ -109,6 +127,8 @@ namespace wmoge { GfxTexUsages m_usages = {GfxTexUsageFlag::Sampling}; bool m_srgb = false; TexCompressionParams m_compression{}; + TextureFlags m_flags; + CallbackRef m_callback; }; WG_RTTI_CLASS_BEGIN(Texture) { @@ -128,7 +148,7 @@ namespace wmoge { Texture2d() = default; ~Texture2d() override = default; - Texture2d(GfxFormat format, int width, int height, GfxTexSwizz swizz = GfxTexSwizz::None); + Texture2d(TextureFlags flags, GfxTextureDesc desc); }; WG_RTTI_CLASS_BEGIN(Texture2d) { @@ -148,7 +168,7 @@ namespace wmoge { TextureCube() = default; ~TextureCube() override = default; - TextureCube(GfxFormat format, int width, int height); + TextureCube(TextureFlags flags, GfxTextureDesc desc); }; WG_RTTI_CLASS_BEGIN(TextureCube) { diff --git a/engine/runtime/grc/texture_manager.cpp b/engine/runtime/grc/texture_manager.cpp index 3c21f40c2..2a417942f 100644 --- a/engine/runtime/grc/texture_manager.cpp +++ b/engine/runtime/grc/texture_manager.cpp @@ -27,6 +27,7 @@ #include "texture_manager.hpp" +#include "core/array_view.hpp" #include "profiler/profiler.hpp" #include "system/ioc_container.hpp" @@ -38,11 +39,76 @@ namespace wmoge { WG_AUTO_PROFILE_GRC("TextureManager::TextureManager"); m_gfx_driver = IocContainer::iresolve_v(); + m_pool = std::make_unique(*m_gfx_driver); + m_callback = std::make_shared>([this](Texture* texture) { + remove(texture); + }); init_default_textures(); init_default_samplers(); } + void TextureManager::update() { + WG_AUTO_PROFILE_GRC("TextureManager::update"); + + std::lock_guard guard(m_mutex); + init_default_textures(); + init_textures(); + } + + Ref TextureManager::create_2d(TextureFlags flags, GfxFormat format, int width, int height, GfxTexSwizz swizz) { + flags.set(TextureFlag::Managed); + + auto texture = make_ref(flags, GfxTextureDesc::make_2d(format, width, height, swizz)); + texture->set_sampler(get_sampler(DefaultSampler::Default)); + add(texture); + return texture; + } + + Ref TextureManager::create_cube(TextureFlags flags, GfxFormat format, int width, int height) { + flags.set(TextureFlag::Managed); + + auto texture = make_ref(flags, GfxTextureDesc::make_cube(format, width, height)); + texture->set_sampler(get_sampler(DefaultSampler::Default)); + add(texture); + return texture; + } + + void TextureManager::add(const Ref& texture) { + assert(texture); + assert(!has(texture.get())); + + std::lock_guard guard(m_mutex); + texture->set_texture_callback(m_callback); + m_textures[texture.get()].weak_ref = texture; + } + + void TextureManager::remove(Texture* texture) { + assert(texture); + assert(has(texture)); + + std::lock_guard guard(m_mutex); + + auto entry = m_textures.find(texture); + if (entry->second.state.get(TextureState::Inited)) { + texture->delete_gfx_resource(*m_pool); + } + m_textures.erase(entry); + } + + void TextureManager::init(Texture* texture) { + assert(texture); + assert(has(texture)); + + std::lock_guard guard(m_mutex); + m_textures[texture].state.set(TextureState::PendingInit); + } + + bool TextureManager::has(Texture* texture) const { + std::lock_guard guard(m_mutex); + return m_textures.find(texture) != m_textures.end(); + } + const Ref& TextureManager::get_texture(DefaultTexture texture) { assert(int(texture) < int(DefaultTexture::Total)); return m_default_textures[int(texture)]; @@ -53,18 +119,29 @@ namespace wmoge { return m_default_samplers[int(sampler)]; } - void TextureManager::init_default_textures() { - WG_AUTO_PROFILE_GRC("TextureManager::init_default_textures"); + void TextureManager::init_default_samplers() { + WG_AUTO_PROFILE_GRC("TextureManager::init_default_samplers"); - const std::array tex_colors[int(DefaultTexture::Total)] = { - {0xff, 0xff, 0xff, 0xff},// - {0x00, 0x00, 0x00, 0xff},// - {0xff, 0x00, 0x00, 0xff},// - {0x00, 0xff, 0x00, 0xff},// - {0x00, 0x00, 0xff, 0xff},// - {0x7f, 0x7f, 0x7f, 0xff},// + const GfxSamplerDesc samp_descs[int(DefaultSampler::Total)] = { + GfxSamplerDesc(), + GfxSamplerDesc::make(GfxSampFlt::Linear, m_gfx_driver->device_caps().max_anisotropy, GfxSampAddress::Repeat), + GfxSamplerDesc::make(GfxSampFlt::Nearest, 0.0f, GfxSampAddress::Repeat), }; + const char* samp_names[int(DefaultSampler::Total)] = { + "default", + "linear", + "nearest", + }; + + for (int i = 0; i < int(DefaultSampler::Total); i++) { + m_default_samplers[i] = m_gfx_driver->make_sampler(samp_descs[i], SID(samp_names[i])); + } + } + + void TextureManager::init_default_textures() { + WG_AUTO_PROFILE_GRC("TextureManager::init_default_textures"); + const char* tex_names[int(DefaultTexture::Total)] = { "white", "black", @@ -77,30 +154,72 @@ namespace wmoge { for (int i = 0; i < int(DefaultTexture::Total); i++) { m_default_textures[i] = m_gfx_driver->make_texture_2d(1, 1, 1, GfxFormat::RGBA8, {GfxTexUsageFlag::Sampling}, GfxMemUsage::GpuLocal, GfxTexSwizz::None, SID(tex_names[i])); } + } + + void TextureManager::upload_default_textures() { + WG_AUTO_PROFILE_GRC("TextureManager::upload_default_textures"); + + if (!m_need_upload_default) { + return; + } + + const std::array tex_colors[int(DefaultTexture::Total)] = { + {0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0xff}, + {0xff, 0x00, 0x00, 0xff}, + {0x00, 0xff, 0x00, 0xff}, + {0x00, 0x00, 0xff, 0xff}, + {0x7f, 0x7f, 0x7f, 0xff}, + }; + + auto cmd = m_gfx_driver->acquire_cmd_list(GfxQueueType::Graphics); for (int i = 0; i < int(DefaultTexture::Total); i++) { - // m_gfx_ctx->update_texture_2d(m_default_textures[i], 0, Rect2i(0, 0, 1, 1), make_ref(tex_colors[i].data(), sizeof(std::uint8_t[4]))); + cmd->barrier_image(m_default_textures[i], GfxTexBarrierType::Undefined, GfxTexBarrierType::CopyDestination); + cmd->update_texture_2d(m_default_textures[i], 0, Rect2i(0, 0, 1, 1), array_view(tex_colors[i].data(), sizeof(std::uint8_t[4]))); + cmd->barrier_image(m_default_textures[i], GfxTexBarrierType::CopyDestination, GfxTexBarrierType::Sampling); } + + m_gfx_driver->submit_cmd_list(cmd); + m_need_upload_default = false; } - void TextureManager::init_default_samplers() { - WG_AUTO_PROFILE_GRC("TextureManager::init_default_samplers"); + void TextureManager::init_textures() { + std::vector for_upload; + for (auto& iter : m_textures) { + auto texture = iter.first; + auto& entry = iter.second; + + if (!entry.state.get(TextureState::PendingInit)) { + continue; + } + if (!texture->create_gfx_resource(*m_pool)) { + continue; + } + + entry.state.set(TextureState::PendingInit, false); + entry.state.set(TextureState::Inited, true); + for_upload.push_back(texture); + } - const GfxSamplerDesc samp_descs[int(DefaultSampler::Total)] = { - GfxSamplerDesc(), - GfxSamplerDesc::make(GfxSampFlt::Linear, m_gfx_driver->device_caps().max_anisotropy, GfxSampAddress::Repeat), - GfxSamplerDesc::make(GfxSampFlt::Nearest, 0.0f, GfxSampAddress::Repeat), - }; + if (for_upload.empty()) { + return; + } - const char* samp_names[int(DefaultSampler::Total)] = { - "default", - "linear", - "nearest", - }; + std::vector for_barrier; + for (Texture* texture : for_upload) { + for_barrier.push_back(texture->get_texture().get()); + } - for (int i = 0; i < int(DefaultSampler::Total); i++) { - m_default_samplers[i] = m_gfx_driver->make_sampler(samp_descs[i], SID(samp_names[i])); + auto cmd = m_gfx_driver->acquire_cmd_list(GfxQueueType::Graphics); + cmd->barrier_images(for_barrier, GfxTexBarrierType::Undefined, GfxTexBarrierType::CopyDestination); + for (Texture* texture : for_upload) { + texture->upload_gfx_data(cmd); } + cmd->barrier_images(for_barrier, GfxTexBarrierType::CopyDestination, GfxTexBarrierType::Sampling); + m_gfx_driver->submit_cmd_list(cmd); + + WG_LOG_INFO("uploaded " << for_upload.size() << " textures to gpu"); } }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/grc/texture_manager.hpp b/engine/runtime/grc/texture_manager.hpp index 90a373908..5179e3f9c 100644 --- a/engine/runtime/grc/texture_manager.hpp +++ b/engine/runtime/grc/texture_manager.hpp @@ -27,15 +27,19 @@ #pragma once +#include "core/flat_set.hpp" #include "gfx/gfx_cmd_list.hpp" #include "gfx/gfx_driver.hpp" #include "gfx/gfx_texture.hpp" +#include "grc/texture.hpp" +#include "grc/texture_pool.hpp" + +#include +#include namespace wmoge { - /** - * @brief Built-in default textures - */ + /** @brief Built-in default textures */ enum class DefaultTexture { White = 0, Black, @@ -46,9 +50,7 @@ namespace wmoge { Total }; - /** - * @brief Built-in default samplers - */ + /** @brief Built-in default samplers */ enum class DefaultSampler { Default = 0, Linear, @@ -56,26 +58,57 @@ namespace wmoge { Total }; + /** @brief Managed texture state */ + enum class TextureState { + PendingInit = 0, + Inited + }; + /** * @class TextureManager - * @brief Render core manager for gfx texture assets + * @brief Manager for memory, gfx and streaming of texture assets */ class TextureManager { public: TextureManager(); + ~TextureManager() = default; + + void update(); + + Ref create_2d(TextureFlags flags, GfxFormat format, int width, int height, GfxTexSwizz swizz = GfxTexSwizz::None); + Ref create_cube(TextureFlags flags, GfxFormat format, int width, int height); + void add(const Ref& texture); + void remove(Texture* texture); + void init(Texture* texture); + bool has(Texture* texture) const; [[nodiscard]] const Ref& get_texture(DefaultTexture texture); [[nodiscard]] const Ref& get_sampler(DefaultSampler sampler); private: - void init_default_textures(); void init_default_samplers(); + void init_default_textures(); + void upload_default_textures(); + void init_textures(); private: - GfxDriver* m_gfx_driver; + struct Entry { + WeakRef weak_ref; + Mask state; + }; + + flat_map m_textures; + + std::shared_ptr> m_callback; + std::unique_ptr m_pool; + bool m_need_upload_default = true; Ref m_default_textures[int(DefaultTexture::Total)]; Ref m_default_samplers[int(DefaultSampler::Total)]; + + GfxDriver* m_gfx_driver; + + mutable std::mutex m_mutex; }; }// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/grc/texture_pool.cpp b/engine/runtime/grc/texture_pool.cpp new file mode 100644 index 000000000..193f04e5c --- /dev/null +++ b/engine/runtime/grc/texture_pool.cpp @@ -0,0 +1,122 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#include "texture_pool.hpp" + +#include + +namespace wmoge { + + TexturePool::TexturePool(GfxDriver& driver) : m_driver(driver) { + } + + TexturePool::~TexturePool() { + for (const PoolKeyVal& entry : m_pools) { + assert(entry.second.n_items_used == 0); + } + } + + GfxTextureRef TexturePool::allocate(const GfxTextureDesc& desc, const Strid& name) { + std::lock_guard guard(m_mutex); + + PoolList* pool = get_or_create_pool(desc); + + std::optional item_slot; + + if (pool->n_items_used < pool->n_items) { + for (std::size_t i = 0; i < pool->n_items; i++) { + if (!pool->items_used[i]) { + item_slot = i; + break; + } + } + } + + if (!item_slot) { + item_slot = pool->n_items; + + GfxTextureRef new_texture = m_driver.make_texture(desc); + pool->items.push_back(PoolItem{new_texture}); + pool->items_used.push_back(false); + pool->n_items++; + } + + pool->items_used[*item_slot] = true; + pool->n_items_used++; + + return pool->items[*item_slot].texture; + } + + void TexturePool::release(const GfxTextureRef& handle) { + std::lock_guard guard(m_mutex); + + assert(handle); + + PoolList* pool = get_pool(handle->desc()); + + for (std::size_t i = 0; i < pool->n_items; i++) { + if (pool->items[i].texture == handle) { + assert(pool->items_used[i]); + assert(pool->n_items_used > 0); + pool->items_used[i] = false; + pool->n_items_used--; + return; + } + } + + assert(false); + } + + TexturePool::PoolList* TexturePool::get_or_create_pool(const GfxTextureDesc& desc) { + PoolList* pool = nullptr; + + for (PoolKeyVal& entry : m_pools) { + if (entry.first == desc) { + pool = &entry.second; + } + } + + if (!pool) { + m_pools.emplace_back(desc, PoolList()); + pool = &m_pools.back().second; + } + + return pool; + } + + TexturePool::PoolList* TexturePool::get_pool(const GfxTextureDesc& desc) { + for (PoolKeyVal& entry : m_pools) { + if (entry.first == desc) { + return &entry.second; + } + } + + assert(false); + return nullptr; + } + +}// namespace wmoge diff --git a/engine/runtime/grc/texture_pool.hpp b/engine/runtime/grc/texture_pool.hpp new file mode 100644 index 000000000..4e4ca628a --- /dev/null +++ b/engine/runtime/grc/texture_pool.hpp @@ -0,0 +1,78 @@ +/**********************************************************************************/ +/* Wmoge game engine */ +/* Available at github https://github.com/EgorOrachyov/wmoge */ +/**********************************************************************************/ +/* MIT License */ +/* */ +/* Copyright (c) 2023 Egor Orachyov */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining a copy */ +/* of this software and associated documentation files (the "Software"), to deal */ +/* in the Software without restriction, including without limitation the rights */ +/* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell */ +/* copies of the Software, and to permit persons to whom the Software is */ +/* furnished to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be included in all */ +/* copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR */ +/* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, */ +/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE */ +/* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER */ +/* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */ +/* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE */ +/* SOFTWARE. */ +/**********************************************************************************/ + +#pragma once + +#include "gfx/gfx_driver.hpp" +#include "gfx/gfx_texture.hpp" + +#include +#include +#include + +namespace wmoge { + + /** + * @class TexturePool + * @brief Pool of preallocated gfx textures (for mem management) + */ + class TexturePool { + public: + TexturePool(GfxDriver& driver); + ~TexturePool(); + + GfxTextureRef allocate(const GfxTextureDesc& desc, const Strid& name = Strid()); + void release(const GfxTextureRef& handle); + + private: + // Single item allocated from pool + struct PoolItem { + GfxTextureRef texture; + }; + + // Pool configured for a specific type of textures + struct PoolList { + std::vector items; + std::vector items_used; + std::size_t n_items = 0; + std::size_t n_items_used = 0; + }; + + PoolList* get_or_create_pool(const GfxTextureDesc& desc); + PoolList* get_pool(const GfxTextureDesc& desc); + + private: + using PoolKeyVal = std::pair; + using PoolMap = std::vector; + + PoolMap m_pools; + std::mutex m_mutex; + + GfxDriver& m_driver; + }; + +}// namespace wmoge \ No newline at end of file diff --git a/engine/runtime/platform/application.cpp b/engine/runtime/platform/application.cpp index 76f0b1125..ab90893b3 100644 --- a/engine/runtime/platform/application.cpp +++ b/engine/runtime/platform/application.cpp @@ -192,10 +192,11 @@ namespace wmoge { } static void unbind_globals(IocContainer* ioc) { + ioc->unbind(); + ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); - ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); @@ -203,12 +204,11 @@ namespace wmoge { ioc->unbind(); ioc->unbind(); ioc->unbind(); - ioc->unbind(); - ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); + ioc->unbind(); ioc->unbind(); ioc->unbind(); ioc->unbind(); @@ -308,15 +308,15 @@ namespace wmoge { signal_after_init.emit(); signal_before_loop.emit(); + { + while (!should_close()) { + WG_AUTO_PROFILE_PLATFORM("Application::iteration"); - while (!should_close()) { - WG_AUTO_PROFILE_PLATFORM("Application::iteration"); - - if (!on_loop()) { - return 1; + if (!on_loop()) { + return 1; + } } } - signal_after_loop.emit(); signal_before_shutdown.emit(); diff --git a/engine/runtime/render/aux_draw_manager.cpp b/engine/runtime/render/aux_draw_manager.cpp index 38113baf1..1a8cc8ce6 100644 --- a/engine/runtime/render/aux_draw_manager.cpp +++ b/engine/runtime/render/aux_draw_manager.cpp @@ -456,8 +456,11 @@ namespace wmoge { } }; - AuxDrawManager::AuxDrawManager() { - WG_AUTO_PROFILE_RENDER("AuxDrawManager::AuxDrawManager"); + AuxDrawManager::AuxDrawManager() = default; + AuxDrawManager::~AuxDrawManager() = default; + + void AuxDrawManager::init() { + WG_AUTO_PROFILE_RENDER("AuxDrawManager::init"); Config* config = IocContainer::iresolve_v(); AssetManager* asset_manager = IocContainer::iresolve_v(); @@ -474,8 +477,6 @@ namespace wmoge { m_text.set_name(SID("aux_text")); } - AuxDrawManager::~AuxDrawManager() = default; - void AuxDrawManager::draw_line(const Vec3f& from, const Vec3f& to, const Color4f& color, float lifetime) { std::lock_guard guard(m_mutex); diff --git a/engine/runtime/render/aux_draw_manager.hpp b/engine/runtime/render/aux_draw_manager.hpp index 03d5eab77..c88774728 100644 --- a/engine/runtime/render/aux_draw_manager.hpp +++ b/engine/runtime/render/aux_draw_manager.hpp @@ -62,6 +62,8 @@ namespace wmoge { AuxDrawManager(); ~AuxDrawManager(); + void init(); + void draw_line(const Vec3f& from, const Vec3f& to, const Color4f& color, float lifetime = LIFETIME_ONE_FRAME); void draw_triangle(const Vec3f& p0, const Vec3f& p1, const Vec3f& p2, const Color4f& color, bool solid = true, float lifetime = LIFETIME_ONE_FRAME); void draw_sphere(const Vec3f& pos, float radius, const Color4f& color, bool solid = true, float lifetime = LIFETIME_ONE_FRAME); diff --git a/engine/runtime/scene/scene.hpp b/engine/runtime/scene/scene.hpp index 84e1ce76e..8f49b930a 100644 --- a/engine/runtime/scene/scene.hpp +++ b/engine/runtime/scene/scene.hpp @@ -73,7 +73,7 @@ namespace wmoge { * @see SceneNode * @see SceneTree */ - class Scene final : public WeakRefCnt { + class Scene final : public WeakRefCnt { public: Scene(Strid name = Strid()); ~Scene() override = default; diff --git a/engine/runtime/system/engine.cpp b/engine/runtime/system/engine.cpp index 602f68447..28b3b9a79 100644 --- a/engine/runtime/system/engine.cpp +++ b/engine/runtime/system/engine.cpp @@ -116,7 +116,6 @@ namespace wmoge { m_input = ioc->resolve_v(); m_asset_manager = ioc->resolve_v(); - m_asset_manager->load_loaders(); WindowInfo window_info; window_info.width = m_config->get_int_or_default(SID("window.width"), 1280); @@ -135,6 +134,8 @@ namespace wmoge { m_shader_manager = ioc->resolve_v(); m_shader_manager->load_compilers(); + m_asset_manager->load_loaders(); + m_shader_library = ioc->resolve_v(); m_pso_cache = ioc->resolve_v(); m_texture_manager = ioc->resolve_v(); @@ -146,6 +147,7 @@ namespace wmoge { m_canvas_debug = ioc->resolve_v(); m_view_manager = ioc->resolve_v(); + m_aux_draw_manager->init(); m_console->init(); m_layer_stack->attach(std::make_shared()); @@ -188,6 +190,10 @@ namespace wmoge { m_scene_manager->update(); } + if (m_texture_manager) { + m_texture_manager->update(); + } + m_layer_stack->each_up([](LayerStack::LayerPtr& layer) { layer->on_iter(); });