diff --git a/lib/graphics_engine/CMakeLists.txt b/lib/graphics_engine/CMakeLists.txt index d02199712..a884f936a 100644 --- a/lib/graphics_engine/CMakeLists.txt +++ b/lib/graphics_engine/CMakeLists.txt @@ -31,6 +31,7 @@ set(GE_SOURCES src/ge_vulkan_driver.cpp src/ge_vulkan_dynamic_buffer.cpp src/ge_vulkan_features.cpp + src/ge_vulkan_mesh_cache.cpp src/ge_vulkan_shader_manager.cpp src/ge_vulkan_texture.cpp src/ge_gl_texture.cpp diff --git a/lib/graphics_engine/include/ge_spm_buffer.hpp b/lib/graphics_engine/include/ge_spm_buffer.hpp index 378d0f893..d988c11bb 100644 --- a/lib/graphics_engine/include/ge_spm_buffer.hpp +++ b/lib/graphics_engine/include/ge_spm_buffer.hpp @@ -1,6 +1,7 @@ #ifndef HEADER_GE_SPM_BUFFER_HPP #define HEADER_GE_SPM_BUFFER_HPP +#include #include #include "IMeshBuffer.h" @@ -21,7 +22,17 @@ private: std::vector m_indices; irr::core::aabbox3d m_bounding_box; + + size_t m_vbo_offset; + + size_t m_ibo_offset; public: + // ------------------------------------------------------------------------ + GESPMBuffer() + { + m_vbo_offset = 0; + m_ibo_offset = 0; + } // ------------------------------------------------------------------------ virtual const irr::video::SMaterial& getMaterial() const { return m_material; } @@ -33,7 +44,6 @@ public: { return m_vertices.data(); } // ------------------------------------------------------------------------ virtual void* getVertices() { return m_vertices.data(); } - // ------------------------------------------------------------------------ virtual irr::u32 getVertexCount() const { return m_vertices.size(); } // ------------------------------------------------------------------------ @@ -139,7 +149,14 @@ public: virtual irr::u32 getChangedID_Vertex() const { return 0; } // ------------------------------------------------------------------------ virtual irr::u32 getChangedID_Index() const { return 0; } - + // ------------------------------------------------------------------------ + void setVBOOffset(size_t offset) { m_vbo_offset = offset; } + // ------------------------------------------------------------------------ + size_t getVBOOffset() const { return m_vbo_offset; } + // ------------------------------------------------------------------------ + void setIBOOffset(size_t offset) { m_ibo_offset = offset; } + // ------------------------------------------------------------------------ + size_t getIBOOffset() const { return m_ibo_offset; } }; } // end namespace irr diff --git a/lib/graphics_engine/include/ge_vulkan_mesh_cache.hpp b/lib/graphics_engine/include/ge_vulkan_mesh_cache.hpp new file mode 100644 index 000000000..3c5de2ffc --- /dev/null +++ b/lib/graphics_engine/include/ge_vulkan_mesh_cache.hpp @@ -0,0 +1,27 @@ +#ifndef HEADER_GE_VULKAN_MESH_CACHE_HPP +#define HEADER_GE_VULKAN_MESH_CACHE_HPP + +#include "vulkan_wrapper.h" + +namespace GE +{ +class GEVulkanDriver; +namespace GEVulkanMeshCache +{ +// ---------------------------------------------------------------------------- +void init(GEVulkanDriver*); +// ---------------------------------------------------------------------------- +void irrlichtMeshChanged(); +// ---------------------------------------------------------------------------- +void updateCache(); +// ---------------------------------------------------------------------------- +void destroy(); +// ---------------------------------------------------------------------------- +VkBuffer getVBO(); +// ---------------------------------------------------------------------------- +VkBuffer getIBO(); +}; // GEVulkanMeshCache + +} + +#endif diff --git a/lib/graphics_engine/src/ge_vulkan_driver.cpp b/lib/graphics_engine/src/ge_vulkan_driver.cpp index 037ae3af3..e2a9bcfab 100644 --- a/lib/graphics_engine/src/ge_vulkan_driver.cpp +++ b/lib/graphics_engine/src/ge_vulkan_driver.cpp @@ -4,6 +4,7 @@ #include "ge_vulkan_2d_renderer.hpp" #include "ge_vulkan_features.hpp" +#include "ge_vulkan_mesh_cache.hpp" #include "ge_vulkan_shader_manager.hpp" #include "ge_vulkan_texture.hpp" #include "ge_vulkan_command_loader.hpp" @@ -551,6 +552,7 @@ GEVulkanDriver::GEVulkanDriver(const SIrrlichtCreationParameters& params, // For GEVulkanDynamicBuffer GE::setVideoDriver(this); GEVulkan2dRenderer::init(this); + GEVulkanMeshCache::init(this); createUnicolorTextures(); GEVulkanFeatures::printStats(); } @@ -581,6 +583,7 @@ void GEVulkanDriver::destroyVulkan() m_transparent_texture = NULL; } + GEVulkanMeshCache::destroy(); GEVulkan2dRenderer::destroy(); GEVulkanShaderManager::destroy(); diff --git a/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp b/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp new file mode 100644 index 000000000..36f6d5d11 --- /dev/null +++ b/lib/graphics_engine/src/ge_vulkan_mesh_cache.cpp @@ -0,0 +1,175 @@ +#include "ge_vulkan_mesh_cache.hpp" + +#include "ge_main.hpp" +#include "ge_spm_buffer.hpp" +#include "ge_vulkan_driver.hpp" + +#include "IAnimatedMesh.h" +#include "IMeshCache.h" +#include "ISceneManager.h" +#include "IrrlichtDevice.h" + +#include + +namespace GE +{ +namespace GEVulkanMeshCache +{ +// ============================================================================ +GEVulkanDriver* g_vk; +uint64_t g_irrlicht_cache_time; +uint64_t g_ge_cache_time; +VkBuffer g_vbo_buffer; +VkDeviceMemory g_vbo_memory; +VkBuffer g_ibo_buffer; +VkDeviceMemory g_ibo_memory; +// ---------------------------------------------------------------------------- +void init(GEVulkanDriver* vk) +{ + g_vk = vk; + g_irrlicht_cache_time = getMonoTimeMs(); + g_ge_cache_time = 0; + g_vbo_buffer = VK_NULL_HANDLE; + g_vbo_memory = VK_NULL_HANDLE; + g_ibo_buffer = VK_NULL_HANDLE; + g_ibo_memory = VK_NULL_HANDLE; +} // init + +// ---------------------------------------------------------------------------- +void irrlichtMeshChanged() +{ + g_irrlicht_cache_time = getMonoTimeMs(); +} // irrlichtMeshChanged + +// ---------------------------------------------------------------------------- +void updateCache() +{ + if (g_irrlicht_cache_time <= g_ge_cache_time) + return; + g_ge_cache_time = g_irrlicht_cache_time; + + destroy(); + size_t vbo_size, ibo_size; + vbo_size = 0; + ibo_size = 0; + scene::IMeshCache* cache = g_vk->getIrrlichtDevice()->getSceneManager() + ->getMeshCache(); + std::vector buffers; + for (unsigned i = 0; i < cache->getMeshCount(); i++) + { + scene::IAnimatedMesh* mesh = cache->getMeshByIndex(i); + if (mesh->getMeshType() != scene::EAMT_SPM) + continue; + for (unsigned j = 0; j < mesh->getMeshBufferCount(); j++) + { + scene::IMeshBuffer* mb = mesh->getMeshBuffer(j); + vbo_size += mesh->getMeshBuffer(j)->getVertexCount(); + ibo_size += mesh->getMeshBuffer(j)->getIndexCount(); + buffers.push_back(static_cast(mb)); + } + } + vbo_size *= getVertexPitchFromType(video::EVT_SKINNED_MESH); + ibo_size *= sizeof(uint16_t); + + VkBuffer staging_buffer = VK_NULL_HANDLE; + VkDeviceMemory staging_memory = VK_NULL_HANDLE; + + if (!g_vk->createBuffer(vbo_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + staging_buffer, staging_memory)) + throw std::runtime_error("updateCache create staging vbo failed"); + + uint8_t* mapped; + if (vkMapMemory(g_vk->getDevice(), staging_memory, 0, + vbo_size, 0, (void**)&mapped) != VK_SUCCESS) + throw std::runtime_error("updateCache vkMapMemory failed"); + size_t offset = 0; + for (GESPMBuffer* spm_buffer : buffers) + { + size_t copy_size = spm_buffer->getVertexCount() * + getVertexPitchFromType(video::EVT_SKINNED_MESH); + memcpy(&mapped[offset], spm_buffer->getVertices(), copy_size); + spm_buffer->setVBOOffset( + offset / getVertexPitchFromType(video::EVT_SKINNED_MESH)); + offset += copy_size; + } + + if (!g_vk->createBuffer(vbo_size, + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + g_vbo_buffer, g_vbo_memory)) + throw std::runtime_error("updateCache create vbo failed"); + + g_vk->copyBuffer(staging_buffer, g_vbo_buffer, vbo_size); + vkUnmapMemory(g_vk->getDevice(), staging_memory); + vkFreeMemory(g_vk->getDevice(), staging_memory, NULL); + vkDestroyBuffer(g_vk->getDevice(), staging_buffer, NULL); + + if (!g_vk->createBuffer(ibo_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + staging_buffer, staging_memory)) + throw std::runtime_error("updateCache create staging ibo failed"); + + if (vkMapMemory(g_vk->getDevice(), staging_memory, 0, + ibo_size, 0, (void**)&mapped) != VK_SUCCESS) + throw std::runtime_error("updateCache vkMapMemory failed"); + offset = 0; + for (GESPMBuffer* spm_buffer : buffers) + { + size_t copy_size = spm_buffer->getIndexCount() * sizeof(uint16_t); + memcpy(&mapped[offset], spm_buffer->getIndices(), copy_size); + spm_buffer->setIBOOffset(offset / sizeof(uint16_t)); + offset += copy_size; + } + + if (!g_vk->createBuffer(ibo_size, + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + g_ibo_buffer, g_ibo_memory)) + throw std::runtime_error("updateCache create ibo failed"); + + g_vk->copyBuffer(staging_buffer, g_ibo_buffer, ibo_size); + vkUnmapMemory(g_vk->getDevice(), staging_memory); + vkFreeMemory(g_vk->getDevice(), staging_memory, NULL); + vkDestroyBuffer(g_vk->getDevice(), staging_buffer, NULL); +} // updateCache + +// ---------------------------------------------------------------------------- +void destroy() +{ + g_vk->waitIdle(); + + if (g_vbo_memory != VK_NULL_HANDLE) + vkFreeMemory(g_vk->getDevice(), g_vbo_memory, NULL); + g_vbo_memory = VK_NULL_HANDLE; + if (g_vbo_buffer != VK_NULL_HANDLE) + vkDestroyBuffer(g_vk->getDevice(), g_vbo_buffer, NULL); + g_vbo_buffer = VK_NULL_HANDLE; + + if (g_ibo_memory != VK_NULL_HANDLE) + vkFreeMemory(g_vk->getDevice(), g_ibo_memory, NULL); + g_ibo_memory = VK_NULL_HANDLE; + if (g_ibo_buffer != VK_NULL_HANDLE) + vkDestroyBuffer(g_vk->getDevice(), g_ibo_buffer, NULL); + g_ibo_buffer = VK_NULL_HANDLE; +} // destroy + +// ---------------------------------------------------------------------------- +VkBuffer getVBO() +{ + return g_vbo_buffer; +} // getVBO + +// ---------------------------------------------------------------------------- +VkBuffer getIBO() +{ + return g_ibo_buffer; +} // getIBO + +} + +} diff --git a/lib/irrlicht/source/Irrlicht/CMeshCache.cpp b/lib/irrlicht/source/Irrlicht/CMeshCache.cpp index 5bcce1936..c48d4ffeb 100644 --- a/lib/irrlicht/source/Irrlicht/CMeshCache.cpp +++ b/lib/irrlicht/source/Irrlicht/CMeshCache.cpp @@ -6,6 +6,10 @@ #include "IAnimatedMesh.h" #include "IMesh.h" +#ifndef SERVER_ONLY +#include +#endif + namespace irr { namespace scene @@ -29,6 +33,9 @@ void CMeshCache::addMesh(const io::path& filename, IAnimatedMesh* mesh) e.Mesh = mesh; Meshes.push_back(e); +#ifndef SERVER_ONLY + GE::GEVulkanMeshCache::irrlichtMeshChanged(); +#endif } @@ -43,6 +50,9 @@ void CMeshCache::removeMesh(const IMesh* const mesh) { Meshes[i].Mesh->drop(); Meshes.erase(i); +#ifndef SERVER_ONLY + GE::GEVulkanMeshCache::irrlichtMeshChanged(); +#endif return; } } @@ -156,6 +166,9 @@ void CMeshCache::clear() Meshes[i].Mesh->drop(); Meshes.clear(); +#ifndef SERVER_ONLY + GE::GEVulkanMeshCache::irrlichtMeshChanged(); +#endif } //! Clears all meshes that are held in the mesh cache but not used anywhere else. @@ -168,6 +181,9 @@ void CMeshCache::clearUnusedMeshes() Meshes[i].Mesh->drop(); Meshes.erase(i); --i; +#ifndef SERVER_ONLY + GE::GEVulkanMeshCache::irrlichtMeshChanged(); +#endif } } }