From 5d23d8d79014185d3cee8d70d558339679f95f25 Mon Sep 17 00:00:00 2001 From: Benau Date: Mon, 18 Apr 2022 12:16:27 +0800 Subject: [PATCH] Add multithreading GEVulkanTexture loading --- lib/graphics_engine/include/ge_spin_lock.hpp | 14 +++++ lib/graphics_engine/src/ge_vulkan_texture.cpp | 56 +++++++++++++++++-- lib/graphics_engine/src/ge_vulkan_texture.hpp | 41 +++++++++++--- 3 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 lib/graphics_engine/include/ge_spin_lock.hpp diff --git a/lib/graphics_engine/include/ge_spin_lock.hpp b/lib/graphics_engine/include/ge_spin_lock.hpp new file mode 100644 index 000000000..0561e282c --- /dev/null +++ b/lib/graphics_engine/include/ge_spin_lock.hpp @@ -0,0 +1,14 @@ +#ifndef HEADER_GE_SPIN_LOCK_HPP +#define HEADER_GE_SPIN_LOCK_HPP + +#include +class GESpinLock +{ + mutable std::atomic_flag m_locked = ATOMIC_FLAG_INIT; +public: + void lock() const + { while (m_locked.test_and_set(std::memory_order_acquire)); } + void unlock() const { m_locked.clear(std::memory_order_release); } +}; + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_texture.cpp b/lib/graphics_engine/src/ge_vulkan_texture.cpp index 4f2347d2c..7ce8f7ce1 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.cpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.cpp @@ -23,7 +23,17 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path, { m_max_size = getDriver()->getDriverAttributes() .getAttributeAsDimension2d("MAX_TEXTURE_SIZE"); - reloadInternal(); + m_full_path = getDriver()->getFileSystem()->getAbsolutePath(NamedPath); + if (!getDriver()->getFileSystem()->existFileOnly(m_full_path)) + { + LoadingFailed = true; + return; + } + + m_size_lock.lock(); + m_image_view_lock.lock(); + GEVulkanCommandLoader::addMultiThreadingCommand( + std::bind(&GEVulkanTexture::reloadInternal, this)); } // GEVulkanTexture // ---------------------------------------------------------------------------- @@ -69,6 +79,9 @@ GEVulkanTexture::GEVulkanTexture(const std::string& name, unsigned int size, // ---------------------------------------------------------------------------- GEVulkanTexture::~GEVulkanTexture() { + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + vkDeviceWaitIdle(m_vulkan_device); clearVulkanData(); } // ~GEVulkanTexture @@ -349,14 +362,21 @@ void GEVulkanTexture::reloadInternal() return; clearVulkanData(); - video::IImage* texture_image = getResizedImage(NamedPath.getPtr(), - m_max_size, &m_orig_size); - if (texture_image == NULL) + + io::IReadFile* file = io::createReadFile(m_full_path); + if (file == NULL) { - LoadingFailed = true; - return; + // We checked for file existence so we should always get a file + throw std::runtime_error("File missing in getResizedImage"); } + video::IImage* texture_image = getResizedImage(file, m_max_size, + &m_orig_size); + if (texture_image == NULL) + throw std::runtime_error("Missing texture_image in getResizedImage"); + file->drop(); + m_size = texture_image->getDimension(); + m_size_lock.unlock(); if (m_image_mani) m_image_mani(texture_image); @@ -364,6 +384,8 @@ void GEVulkanTexture::reloadInternal() uint8_t* data = (uint8_t*)texture_image->lock(); bgraConversion(data); upload(data); + m_image_view_lock.unlock(); + texture_image->unlock(); texture_image->drop(); } // reloadInternal @@ -404,6 +426,9 @@ void* GEVulkanTexture::lock(video::E_TEXTURE_LOCK_MODE mode, u32 mipmap_level) // ---------------------------------------------------------------------------- uint8_t* GEVulkanTexture::getTextureData() { + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + VkBuffer buffer; VkDeviceMemory buffer_memory; VkDeviceSize image_size = @@ -462,6 +487,9 @@ cleanup: void GEVulkanTexture::updateTexture(void* data, video::ECOLOR_FORMAT format, u32 w, u32 h, u32 x, u32 y) { + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + VkBuffer staging_buffer; VkDeviceMemory staging_buffer_memory; if (m_single_channel) @@ -555,4 +583,20 @@ void GEVulkanTexture::bgraConversion(uint8_t* img_data) } } // bgraConversion +//----------------------------------------------------------------------------- +void GEVulkanTexture::reload() +{ + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + + vkDeviceWaitIdle(m_vulkan_device); + if (!m_disable_reload) + { + m_size_lock.lock(); + m_image_view_lock.lock(); + GEVulkanCommandLoader::addMultiThreadingCommand( + std::bind(&GEVulkanTexture::reloadInternal, this)); + } +} // reload + } diff --git a/lib/graphics_engine/src/ge_vulkan_texture.hpp b/lib/graphics_engine/src/ge_vulkan_texture.hpp index a5f87db30..387db61f6 100644 --- a/lib/graphics_engine/src/ge_vulkan_texture.hpp +++ b/lib/graphics_engine/src/ge_vulkan_texture.hpp @@ -3,6 +3,8 @@ #include "vulkan_wrapper.h" +#include "ge_spin_lock.hpp" + #include #include #include @@ -34,6 +36,12 @@ private: const bool m_single_channel; + GESpinLock m_size_lock; + + GESpinLock m_image_view_lock; + + io::path m_full_path; + // ------------------------------------------------------------------------ bool createTextureImage(uint8_t* texture_data); // ------------------------------------------------------------------------ @@ -83,9 +91,18 @@ public: } // ------------------------------------------------------------------------ virtual const core::dimension2d& getOriginalSize() const - { return m_orig_size; } + { + m_size_lock.lock(); + m_size_lock.unlock(); + return m_orig_size; + } // ------------------------------------------------------------------------ - virtual const core::dimension2d& getSize() const { return m_size; } + virtual const core::dimension2d& getSize() const + { + m_size_lock.lock(); + m_size_lock.unlock(); + return m_size; + } // ------------------------------------------------------------------------ virtual video::E_DRIVER_TYPE getDriverType() const { return video::EDT_VULKAN; } @@ -99,16 +116,22 @@ public: // ------------------------------------------------------------------------ virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {} // ------------------------------------------------------------------------ - virtual u64 getTextureHandler() const { return (u64)m_image_view; } - // ------------------------------------------------------------------------ - virtual unsigned int getTextureSize() const { return m_texture_size; } - // ------------------------------------------------------------------------ - virtual void reload() + virtual u64 getTextureHandler() const { - vkDeviceWaitIdle(m_vulkan_device); - reloadInternal(); + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + return (u64)m_image_view; } // ------------------------------------------------------------------------ + virtual unsigned int getTextureSize() const + { + m_image_view_lock.lock(); + m_image_view_lock.unlock(); + return m_texture_size; + } + // ------------------------------------------------------------------------ + virtual void reload(); + // ------------------------------------------------------------------------ virtual void updateTexture(void* data, irr::video::ECOLOR_FORMAT format, u32 w, u32 h, u32 x, u32 y); }; // GEVulkanTexture