Add GEVulkanTextureDescriptor to avoid refilling every frame

This commit is contained in:
Benau 2022-07-15 14:09:57 +08:00
parent 3769c18288
commit 713ab53272
7 changed files with 369 additions and 16 deletions

View File

@ -38,6 +38,7 @@ set(GE_SOURCES
src/ge_vulkan_scene_manager.cpp
src/ge_vulkan_shader_manager.cpp
src/ge_vulkan_texture.cpp
src/ge_vulkan_texture_descriptor.cpp
src/ge_gl_texture.cpp
src/ge_spm.cpp
)

View File

@ -0,0 +1,104 @@
#ifndef HEADER_GE_VULKAN_TEXTURE_DESCRIPTOR_HPP
#define HEADER_GE_VULKAN_TEXTURE_DESCRIPTOR_HPP
#include "vulkan_wrapper.h"
#include "IrrCompileConfig.h"
namespace irr
{
namespace video { class ITexture; }
}
#include <array>
#include <map>
#include <memory>
#include <vector>
namespace GE
{
class GEVulkanDriver;
enum GEVulkanSampler : unsigned;
class GEVulkanTextureDescriptor
{
typedef std::array<std::shared_ptr<VkImageView>,
_IRR_MATERIAL_MAX_TEXTURES_> TextureList;
std::map<TextureList, int> m_texture_list;
std::shared_ptr<VkImageView> m_white_image, m_transparent_image;
VkDescriptorSetLayout m_descriptor_set_layout;
VkDescriptorPool m_descriptor_pool;
std::vector<VkDescriptorSet> m_descriptor_sets;
const unsigned m_max_texture_list;
const unsigned m_max_layer;
const unsigned m_binding;
GEVulkanSampler m_sampler_use;
GEVulkanDriver* m_vk;
bool m_recreate_next_frame;
bool m_needs_update_descriptor;
public:
// ------------------------------------------------------------------------
GEVulkanTextureDescriptor(unsigned max_texture_list, unsigned max_layer,
bool single_descriptor, unsigned binding = 0);
// ------------------------------------------------------------------------
~GEVulkanTextureDescriptor();
// ------------------------------------------------------------------------
void handleDeletedTextures()
{
bool has_deleted_image_view = false;
for (auto& p : m_texture_list)
{
for (auto& t : p.first)
{
if (*(t.get()) == VK_NULL_HANDLE)
{
has_deleted_image_view = true;
break;
}
}
}
if (has_deleted_image_view || m_recreate_next_frame)
{
m_texture_list.clear();
m_needs_update_descriptor = true;
m_recreate_next_frame = false;
}
}
// ------------------------------------------------------------------------
int getTextureID(const irr::video::ITexture** list);
// ------------------------------------------------------------------------
void setSamplerUse(GEVulkanSampler sampler)
{
if (m_sampler_use == sampler)
return;
m_sampler_use = sampler;
m_needs_update_descriptor = true;
}
// ------------------------------------------------------------------------
void updateDescriptor();
// ------------------------------------------------------------------------
unsigned getMaxTextureList() const { return m_max_texture_list; }
// ------------------------------------------------------------------------
unsigned getMaxLayer() const { return m_max_layer; }
// ------------------------------------------------------------------------
VkDescriptorSetLayout* getDescriptorSetLayout()
{ return &m_descriptor_set_layout; }
// ------------------------------------------------------------------------
VkDescriptorSet* getDescriptorSet()
{ return m_descriptor_sets.data(); }
}; // GEVulkanTextureDescriptor
}
#endif

View File

@ -13,7 +13,6 @@ GEVulkanDepthTexture::GEVulkanDepthTexture(GEVulkanDriver* vk,
m_vulkan_device = m_vk->getDevice();
m_image = VK_NULL_HANDLE;
m_vma_allocation = VK_NULL_HANDLE;
m_image_view = VK_NULL_HANDLE;
m_has_mipmaps = false;
m_locked_data = NULL;
m_size = m_orig_size = m_max_size = size;

View File

@ -38,7 +38,8 @@ public:
// ------------------------------------------------------------------------
virtual void regenerateMipMapLevels(void* mipmap_data = NULL) {}
// ------------------------------------------------------------------------
virtual u64 getTextureHandler() const { return (u64)m_image_view; }
virtual u64 getTextureHandler() const
{ return (u64)*(m_image_view.get()); }
// ------------------------------------------------------------------------
virtual unsigned int getTextureSize() const { return m_texture_size; }
// ------------------------------------------------------------------------
@ -46,6 +47,9 @@ public:
// ------------------------------------------------------------------------
virtual void updateTexture(void* data, irr::video::ECOLOR_FORMAT format,
u32 w, u32 h, u32 x, u32 y) {}
// ------------------------------------------------------------------------
virtual std::shared_ptr<VkImageView> getImageView() const
{ return m_image_view; }
}; // GEVulkanDepthTexture
}

View File

@ -24,8 +24,8 @@ GEVulkanTexture::GEVulkanTexture(const std::string& path,
m_locked_data(NULL),
m_vulkan_device(getVKDriver()->getDevice()),
m_image(VK_NULL_HANDLE), m_vma_allocation(VK_NULL_HANDLE),
m_image_view(VK_NULL_HANDLE), m_texture_size(0),
m_disable_reload(false), m_has_mipmaps(true),
m_texture_size(0), m_disable_reload(false),
m_has_mipmaps(true),
m_internal_format(VK_FORMAT_R8G8B8A8_UNORM),
m_vk(getVKDriver())
{
@ -50,8 +50,8 @@ GEVulkanTexture::GEVulkanTexture(video::IImage* img, const std::string& name)
m_locked_data(NULL),
m_vulkan_device(getVKDriver()->getDevice()),
m_image(VK_NULL_HANDLE), m_vma_allocation(VK_NULL_HANDLE),
m_image_view(VK_NULL_HANDLE), m_texture_size(0),
m_disable_reload(true), m_has_mipmaps(true),
m_texture_size(0), m_disable_reload(true),
m_has_mipmaps(true),
m_internal_format(VK_FORMAT_R8G8B8A8_UNORM),
m_vk(getVKDriver())
{
@ -76,8 +76,7 @@ GEVulkanTexture::GEVulkanTexture(const std::string& name, unsigned int size,
: video::ITexture(name.c_str()), m_image_mani(nullptr),
m_locked_data(NULL), m_vulkan_device(getVKDriver()->getDevice()),
m_image(VK_NULL_HANDLE), m_vma_allocation(VK_NULL_HANDLE),
m_image_view(VK_NULL_HANDLE), m_texture_size(0),
m_disable_reload(true), m_has_mipmaps(true),
m_texture_size(0), m_disable_reload(true), m_has_mipmaps(true),
m_internal_format(single_channel ?
VK_FORMAT_R8_UNORM : VK_FORMAT_R8G8B8A8_UNORM),
m_vk(getVKDriver())
@ -102,7 +101,7 @@ GEVulkanTexture::~GEVulkanTexture()
m_image_view_lock.lock();
m_image_view_lock.unlock();
if (m_image_view != VK_NULL_HANDLE || m_image != VK_NULL_HANDLE ||
if (m_image_view || m_image != VK_NULL_HANDLE ||
m_vma_allocation != VK_NULL_HANDLE)
m_vk->waitIdle();
@ -364,16 +363,26 @@ bool GEVulkanTexture::createImageView(VkImageAspectFlags aspect_flags)
view_info.components.a = VK_COMPONENT_SWIZZLE_R;
}
std::shared_ptr<VkImageView> image_view = std::make_shared<VkImageView>();
VkResult result = vkCreateImageView(m_vulkan_device, &view_info, NULL,
&m_image_view);
return (result == VK_SUCCESS);
image_view.get());
if (result == VK_SUCCESS)
{
m_image_view = image_view;
return true;
}
return false;
} // createImageView
// ----------------------------------------------------------------------------
void GEVulkanTexture::clearVulkanData()
{
if (m_image_view != VK_NULL_HANDLE)
vkDestroyImageView(m_vulkan_device, m_image_view, NULL);
if (m_image_view)
{
vkDestroyImageView(m_vulkan_device, *m_image_view.get(), NULL);
*(m_image_view.get()) = VK_NULL_HANDLE;
m_image_view.reset();
}
if (m_image != VK_NULL_HANDLE)
vmaDestroyImage(m_vk->getVmaAllocator(), m_image, m_vma_allocation);
} // clearVulkanData
@ -696,7 +705,7 @@ void GEVulkanTexture::reload()
m_image_view_lock.lock();
m_image_view_lock.unlock();
if (m_image_view != VK_NULL_HANDLE || m_image != VK_NULL_HANDLE ||
if (m_image_view || m_image != VK_NULL_HANDLE ||
m_vma_allocation != VK_NULL_HANDLE)
m_vk->waitIdle();

View File

@ -9,6 +9,7 @@
#include <algorithm>
#include <cmath>
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include <ITexture.h>
@ -33,7 +34,7 @@ protected:
VmaAllocation m_vma_allocation;
VkImageView m_image_view;
std::shared_ptr<VkImageView> m_image_view;
unsigned int m_texture_size;
@ -165,7 +166,7 @@ public:
{
m_image_view_lock.lock();
m_image_view_lock.unlock();
return (u64)m_image_view;
return m_image_view ? (u64)*(m_image_view.get()) : 0;
}
// ------------------------------------------------------------------------
virtual unsigned int getTextureSize() const
@ -180,6 +181,13 @@ public:
virtual void updateTexture(void* data, irr::video::ECOLOR_FORMAT format,
u32 w, u32 h, u32 x, u32 y);
// ------------------------------------------------------------------------
virtual std::shared_ptr<VkImageView> getImageView() const
{
m_image_view_lock.lock();
m_image_view_lock.unlock();
return m_image_view;
}
// ------------------------------------------------------------------------
VkFormat getInternalFormat() const { return m_internal_format; }
}; // GEVulkanTexture

View File

@ -0,0 +1,228 @@
#include "ge_vulkan_texture_descriptor.hpp"
#include "ge_main.hpp"
#include "ge_vulkan_driver.hpp"
#include "ge_vulkan_texture.hpp"
#include <algorithm>
#include <exception>
namespace GE
{
// ----------------------------------------------------------------------------
GEVulkanTextureDescriptor::GEVulkanTextureDescriptor(unsigned max_texture_list,
unsigned max_layer,
bool single_descriptor,
unsigned binding)
: m_max_texture_list(max_texture_list),
m_max_layer(max_layer), m_binding(binding)
{
if (m_max_layer > _IRR_MATERIAL_MAX_TEXTURES_)
{
throw std::runtime_error(
"Too large max_layer for GEVulkanTextureDescriptor");
}
m_vk = getVKDriver();
// m_descriptor_set_layout
VkDescriptorSetLayoutBinding texture_layout_binding = {};
texture_layout_binding.binding = m_binding;
texture_layout_binding.descriptorCount =
single_descriptor ? m_max_texture_list * m_max_layer : m_max_layer;
texture_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
texture_layout_binding.pImmutableSamplers = NULL;
texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
VkDescriptorSetLayoutCreateInfo setinfo = {};
setinfo.flags = 0;
setinfo.pNext = NULL;
setinfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
setinfo.pBindings = &texture_layout_binding;
setinfo.bindingCount = 1;
if (vkCreateDescriptorSetLayout(m_vk->getDevice(), &setinfo,
NULL, &m_descriptor_set_layout) != VK_SUCCESS)
{
throw std::runtime_error("vkCreateDescriptorSetLayout failed for "
"GEVulkanTextureDescriptor");
}
// m_descriptor_pool
VkDescriptorPoolSize pool_size;
pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
pool_size.descriptorCount = m_max_texture_list * m_max_layer;
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.flags = 0;
pool_info.maxSets = single_descriptor ? 1 : m_max_texture_list;
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &pool_size;
if (vkCreateDescriptorPool(m_vk->getDevice(), &pool_info, NULL,
&m_descriptor_pool) != VK_SUCCESS)
{
throw std::runtime_error("vkCreateDescriptorPool failed for "
"GEVulkanTextureDescriptor");
}
// m_descriptor_sets
if (single_descriptor)
m_descriptor_sets.resize(1);
else
m_descriptor_sets.resize(m_max_texture_list);
std::vector<VkDescriptorSetLayout> layouts(m_descriptor_sets.size(),
m_descriptor_set_layout);
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = m_descriptor_pool;
alloc_info.descriptorSetCount = layouts.size();
alloc_info.pSetLayouts = layouts.data();
if (vkAllocateDescriptorSets(m_vk->getDevice(), &alloc_info,
m_descriptor_sets.data()) != VK_SUCCESS)
{
throw std::runtime_error("vkAllocateDescriptorSets failed for "
"GEVulkanTextureDescriptor");
}
m_sampler_use = GVS_NEAREST;
m_recreate_next_frame = false;
m_needs_update_descriptor = false;
GEVulkanTexture* tex = static_cast<GEVulkanTexture*>(
m_vk->getWhiteTexture());
m_white_image = tex->getImageView();
tex = static_cast<GEVulkanTexture*>(m_vk->getTransparentTexture());
m_transparent_image = tex->getImageView();
} // GEVulkanTextureDescriptor
// ----------------------------------------------------------------------------
GEVulkanTextureDescriptor::~GEVulkanTextureDescriptor()
{
vkDestroyDescriptorSetLayout(m_vk->getDevice(), m_descriptor_set_layout,
NULL);
vkDestroyDescriptorPool(m_vk->getDevice(), m_descriptor_pool, NULL);
} // ~GEVulkanTextureDescriptor
// ----------------------------------------------------------------------------
void GEVulkanTextureDescriptor::updateDescriptor()
{
if (!m_needs_update_descriptor)
return;
m_needs_update_descriptor = false;
if (m_texture_list.empty())
return;
std::vector<VkDescriptorImageInfo> image_infos;
image_infos.resize(m_texture_list.size() * m_max_layer);
for (auto& p : m_texture_list)
{
const size_t max_size = std::min((size_t)m_max_layer, p.first.size());
for (unsigned i = 0; i < max_size; i++)
{
VkDescriptorImageInfo info;
info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
info.sampler = m_vk->getSampler(m_sampler_use);
info.imageView = *(p.first[i].get());
if (info.imageView == VK_NULL_HANDLE)
info.imageView = *m_transparent_image.get();
image_infos[p.second * m_max_layer + i] = info;
}
}
bool single_descriptor = (m_descriptor_sets.size() == 1);
if (single_descriptor)
{
VkDescriptorImageInfo dummy_info;
dummy_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
dummy_info.imageView = *m_transparent_image.get();
dummy_info.sampler = m_vk->getSampler(m_sampler_use);
image_infos.resize(m_max_texture_list * m_max_layer, dummy_info);
}
m_vk->waitIdle();
if (single_descriptor)
{
VkWriteDescriptorSet write_descriptor_set = {};
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_set.dstBinding = m_binding;
write_descriptor_set.dstArrayElement = 0;
write_descriptor_set.descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_descriptor_set.descriptorCount = m_max_texture_list * m_max_layer;
write_descriptor_set.pBufferInfo = 0;
write_descriptor_set.dstSet = m_descriptor_sets[0];
write_descriptor_set.pImageInfo = image_infos.data();
vkUpdateDescriptorSets(m_vk->getDevice(), 1, &write_descriptor_set, 0,
NULL);
}
else
{
std::vector<VkWriteDescriptorSet> all_sets;
for (unsigned i = 0; i < image_infos.size(); i += m_max_layer)
{
const unsigned set_idx = i / m_max_layer;
VkWriteDescriptorSet write_descriptor_set = {};
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_set.dstBinding = m_binding;
write_descriptor_set.dstArrayElement = 0;
write_descriptor_set.descriptorType =
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_descriptor_set.descriptorCount = m_max_layer;
write_descriptor_set.pBufferInfo = 0;
write_descriptor_set.dstSet = m_descriptor_sets[set_idx];
write_descriptor_set.pImageInfo = &image_infos[i];
all_sets.push_back(write_descriptor_set);
}
vkUpdateDescriptorSets(m_vk->getDevice(), all_sets.size(),
all_sets.data(), 0, NULL);
}
} // updateDescriptor
// ----------------------------------------------------------------------------
int GEVulkanTextureDescriptor::getTextureID(const irr::video::ITexture** list)
{
TextureList key =
{{
m_white_image,
m_transparent_image,
m_transparent_image,
m_transparent_image,
m_transparent_image,
m_transparent_image,
m_transparent_image,
m_transparent_image
}};
for (unsigned i = 0; i < m_max_layer; i++)
{
if (list[i])
{
key[i] = static_cast<const GEVulkanTexture*>(
list[i])->getImageView();
}
}
auto it = m_texture_list.find(key);
if (it != m_texture_list.end())
return it->second;
else
{
int cur_id = m_texture_list.size();
if (cur_id >= m_max_texture_list)
{
printf("Too many texture used in current frames\n");
m_recreate_next_frame = true;
return m_max_texture_list - 1;
}
m_texture_list[key] = cur_id;
m_needs_update_descriptor = true;
// Reset the list earlier if almost full
if (cur_id > int((float)m_max_texture_list * 0.8f))
m_recreate_next_frame = true;
return cur_id;
}
} // getTextureID
}