Improve vulkan resource freeing

and some minor improvements to the Renderer, now taking in an
AssetRef<Pipeline> as parameter.
This commit is contained in:
Thraix
2024-10-11 20:06:22 +02:00
parent dc735c4df7
commit ecc11f07db
21 changed files with 151 additions and 58 deletions
+1 -1
View File
@@ -202,7 +202,6 @@
<ClCompile Include="src\copium\event\WindowResizeEvent.cpp" /> <ClCompile Include="src\copium\event\WindowResizeEvent.cpp" />
<ClCompile Include="src\copium\mesh\Mesh.cpp" /> <ClCompile Include="src\copium\mesh\Mesh.cpp" />
<ClCompile Include="src\copium\renderer\LineVertex.cpp" /> <ClCompile Include="src\copium\renderer\LineVertex.cpp" />
<ClCompile Include="src\copium\renderer\LineVertex.h" />
<ClCompile Include="src\copium\pipeline\ShaderBinding.cpp" /> <ClCompile Include="src\copium\pipeline\ShaderBinding.cpp" />
<ClCompile Include="src\copium\renderer\Batch.cpp" /> <ClCompile Include="src\copium\renderer\Batch.cpp" />
<ClCompile Include="src\copium\renderer\LineRenderer.cpp" /> <ClCompile Include="src\copium\renderer\LineRenderer.cpp" />
@@ -287,6 +286,7 @@
<ClInclude Include="src\copium\pipeline\ShaderBinding.h" /> <ClInclude Include="src\copium\pipeline\ShaderBinding.h" />
<ClInclude Include="src\copium\renderer\Batch.h" /> <ClInclude Include="src\copium\renderer\Batch.h" />
<ClInclude Include="src\copium\renderer\LineRenderer.h" /> <ClInclude Include="src\copium\renderer\LineRenderer.h" />
<ClInclude Include="src\copium\renderer\LineVertex.h" />
<ClInclude Include="src\copium\renderer\Renderer.h" /> <ClInclude Include="src\copium\renderer\Renderer.h" />
<ClInclude Include="src\copium\renderer\RendererVertex.h" /> <ClInclude Include="src\copium\renderer\RendererVertex.h" />
<ClInclude Include="src\copium\sampler\DepthAttachment.h" /> <ClInclude Include="src\copium\sampler\DepthAttachment.h" />
+3 -3
View File
@@ -216,9 +216,6 @@
<ClCompile Include="src\copium\event\ViewportResize.cpp"> <ClCompile Include="src\copium\event\ViewportResize.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\copium\renderer\LineVertex.h">
<Filter>Header Files</Filter>
</ClCompile>
<ClCompile Include="src\copium\renderer\LineRenderer.cpp"> <ClCompile Include="src\copium\renderer\LineRenderer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -479,5 +476,8 @@
<ClInclude Include="src\copium\renderer\LineRenderer.h"> <ClInclude Include="src\copium\renderer\LineRenderer.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\copium\renderer\LineVertex.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>
+6 -2
View File
@@ -30,8 +30,12 @@ namespace Copium
Buffer::~Buffer() Buffer::~Buffer()
{ {
vkFreeMemory(Vulkan::GetDevice(), memory, nullptr); VkDeviceMemory memoryCpy = memory;
vkDestroyBuffer(Vulkan::GetDevice(), handle, nullptr); VkBuffer handleCpy = handle;
Vulkan::GetDevice().QueueIdleCommand([memoryCpy, handleCpy]() {
vkFreeMemory(Vulkan::GetDevice(), memoryCpy, nullptr);
vkDestroyBuffer(Vulkan::GetDevice(), handleCpy, nullptr);
});
} }
void Buffer::Update(void* indexData, int index) void Buffer::Update(void* indexData, int index)
@@ -29,7 +29,10 @@ namespace Copium
CommandBuffer::~CommandBuffer() CommandBuffer::~CommandBuffer()
{ {
vkFreeCommandBuffers(Vulkan::GetDevice(), Vulkan::GetDevice().GetCommandPool(), commandBuffers.size(), commandBuffers.data()); std::vector<VkCommandBuffer> commandBuffersCpy = commandBuffers;
Vulkan::GetDevice().QueueIdleCommand([commandBuffersCpy]() {
vkFreeCommandBuffers(Vulkan::GetDevice(), Vulkan::GetDevice().GetCommandPool(), commandBuffersCpy.size(), commandBuffersCpy.data());
});
} }
// TODO: Test as constexpr function to see if it avoids the switch case // TODO: Test as constexpr function to see if it avoids the switch case
@@ -30,14 +30,18 @@ namespace Copium
Framebuffer::~Framebuffer() Framebuffer::~Framebuffer()
{ {
for (auto& framebuffer : framebuffers) std::vector<VkFramebuffer> framebuffersCpy = framebuffers;
vkDestroyFramebuffer(Vulkan::GetDevice(), framebuffer, nullptr); VkRenderPass renderPassCpy = renderPass;
vkDestroyRenderPass(Vulkan::GetDevice(), renderPass, nullptr); Vulkan::GetDevice().QueueIdleCommand([framebuffersCpy, renderPassCpy]() {
for (auto& framebuffer : framebuffersCpy)
vkDestroyFramebuffer(Vulkan::GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(Vulkan::GetDevice(), renderPassCpy, nullptr);
});
} }
void Framebuffer::Resize(uint32_t width, uint32_t height) void Framebuffer::Resize(uint32_t width, uint32_t height)
{ {
vkDeviceWaitIdle(Vulkan::GetDevice()); Vulkan::GetDevice().WaitIdle();
this->width = width; this->width = width;
this->height = height; this->height = height;
for (auto&& framebuffer : framebuffers) for (auto&& framebuffer : framebuffers)
@@ -23,7 +23,11 @@ namespace Copium
{ {
CP_ASSERT(binding.GetUniformType(str) == UniformType::Mat3, "Uniform type missmatch = %s", str.c_str()); CP_ASSERT(binding.GetUniformType(str) == UniformType::Mat3, "Uniform type missmatch = %s", str.c_str());
uint32_t offset = binding.GetUniformOffset(str); uint32_t offset = binding.GetUniformOffset(str);
memcpy(buffer.data() + offset, &data, sizeof(glm::mat3)); // memcpy(buffer.data() + offset, &data[0], sizeof(glm::vec3));
// memcpy(buffer.data() + offset + 16, &data[1], sizeof(glm::vec3));
// memcpy(buffer.data() + offset + 32, &data[2], sizeof(glm::vec3));
glm::mat4x3 mat43{data};
memcpy(buffer.data() + offset, &mat43, sizeof(glm::mat4x3));
} }
void UniformBuffer::Set(const std::string& str, const glm::mat4& data) void UniformBuffer::Set(const std::string& str, const glm::mat4& data)
+23
View File
@@ -65,6 +65,29 @@ namespace Copium
CP_ABORT("Failed to find suitable memory type"); CP_ABORT("Failed to find suitable memory type");
} }
void Device::WaitIdle()
{
vkDeviceWaitIdle(device);
while (!idleCommands.empty())
{
idleCommands.front()();
idleCommands.pop();
}
}
void Device::WaitIdleIfCommandQueued()
{
if (!idleCommands.empty())
{
WaitIdle();
}
}
void Device::QueueIdleCommand(std::function<void()> idleCommand)
{
idleCommands.emplace(idleCommand);
}
void Device::SelectPhysicalDevice() void Device::SelectPhysicalDevice()
{ {
uint32_t deviceCount; uint32_t deviceCount;
+19 -12
View File
@@ -4,6 +4,8 @@
#include "copium/util/Common.h" #include "copium/util/Common.h"
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <queue>
#include <functional>
namespace Copium namespace Copium
{ {
@@ -11,18 +13,6 @@ namespace Copium
class Device class Device
{ {
CP_DELETE_COPY_AND_MOVE_CTOR(Device); CP_DELETE_COPY_AND_MOVE_CTOR(Device);
private:
VkPhysicalDevice physicalDevice;
VkDevice device;
VkCommandPool commandPool;
// TODO: Move to SwapChain?
uint32_t graphicsQueueIndex;
uint32_t presentQueueIndex;
VkQueue graphicsQueue;
VkQueue presentQueue;
// TODO end
public: public:
Device(); Device();
~Device(); ~Device();
@@ -35,6 +25,23 @@ namespace Copium
VkPhysicalDevice GetPhysicalDevice() const; VkPhysicalDevice GetPhysicalDevice() const;
operator VkDevice() const; operator VkDevice() const;
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
void WaitIdle();
void WaitIdleIfCommandQueued();
void QueueIdleCommand(std::function<void()> idleCommand);
private:
VkPhysicalDevice physicalDevice;
VkDevice device;
VkCommandPool commandPool;
// TODO: Move to SwapChain?
uint32_t graphicsQueueIndex;
uint32_t presentQueueIndex;
VkQueue graphicsQueue;
VkQueue presentQueue;
std::queue<std::function<void()>> idleCommands;
// TODO end
private: private:
void SelectPhysicalDevice(); void SelectPhysicalDevice();
+1 -1
View File
@@ -179,7 +179,7 @@ namespace Copium
glfwWaitEvents(); glfwWaitEvents();
} }
vkDeviceWaitIdle(Vulkan::GetDevice()); Vulkan::GetDevice().WaitIdle();
Destroy(); Destroy();
+9
View File
@@ -16,6 +16,7 @@ namespace Copium
std::unique_ptr<SwapChain> Vulkan::swapChain; std::unique_ptr<SwapChain> Vulkan::swapChain;
std::unique_ptr<ImGuiInstance> Vulkan::imGuiInstance; std::unique_ptr<ImGuiInstance> Vulkan::imGuiInstance;
AssetHandle<Texture2D> Vulkan::emptyTexture2D; AssetHandle<Texture2D> Vulkan::emptyTexture2D;
AssetHandle<Texture2D> Vulkan::whiteTexture2D;
void Vulkan::Initialize() void Vulkan::Initialize()
{ {
@@ -39,16 +40,19 @@ namespace Copium
// By looking at where the executable is, since that should always be in the bin folder (it currently isn't though) // By looking at where the executable is, since that should always be in the bin folder (it currently isn't though)
AssetManager::RegisterAssetDir("assets/"); AssetManager::RegisterAssetDir("assets/");
emptyTexture2D = AssetHandle<Texture2D>{"empty_texture2d", std::make_unique<Texture2D>(std::vector<uint8_t>{255, 0, 255, 255}, 1, 1, SamplerCreator{})}; emptyTexture2D = AssetHandle<Texture2D>{"empty_texture2d", std::make_unique<Texture2D>(std::vector<uint8_t>{255, 0, 255, 255}, 1, 1, SamplerCreator{})};
whiteTexture2D = AssetHandle<Texture2D>{"white_texture2d", std::make_unique<Texture2D>(std::vector<uint8_t>{255, 255, 255, 255}, 1, 1, SamplerCreator{})};
CP_INFO("Initialized AssetManager in %f seconds", timer.Elapsed()); CP_INFO("Initialized AssetManager in %f seconds", timer.Elapsed());
} }
void Vulkan::Destroy() void Vulkan::Destroy()
{ {
emptyTexture2D.UnloadAsset(); emptyTexture2D.UnloadAsset();
whiteTexture2D.UnloadAsset();
AssetManager::UnregisterAssetDir("assets/"); AssetManager::UnregisterAssetDir("assets/");
AssetManager::Cleanup(); AssetManager::Cleanup();
imGuiInstance.reset(); imGuiInstance.reset();
swapChain.reset(); swapChain.reset();
device->WaitIdle();
device.reset(); device.reset();
window.reset(); window.reset();
instance.reset(); instance.reset();
@@ -79,6 +83,11 @@ namespace Copium
return *imGuiInstance; return *imGuiInstance;
} }
AssetHandle<Texture2D> Vulkan::GetWhiteTexture2D()
{
return whiteTexture2D;
}
AssetHandle<Texture2D> Vulkan::GetEmptyTexture2D() AssetHandle<Texture2D> Vulkan::GetEmptyTexture2D()
{ {
return emptyTexture2D; return emptyTexture2D;
+2
View File
@@ -24,6 +24,7 @@ namespace Copium
static std::unique_ptr<ImGuiInstance> imGuiInstance; static std::unique_ptr<ImGuiInstance> imGuiInstance;
static AssetHandle<Texture2D> emptyTexture2D; static AssetHandle<Texture2D> emptyTexture2D;
static AssetHandle<Texture2D> whiteTexture2D;
public: public:
static void Initialize(); static void Initialize();
static void Destroy(); static void Destroy();
@@ -33,6 +34,7 @@ namespace Copium
static SwapChain& GetSwapChain(); static SwapChain& GetSwapChain();
static ImGuiInstance& GetImGuiInstance(); static ImGuiInstance& GetImGuiInstance();
static bool Valid(); static bool Valid();
static AssetHandle<Texture2D> GetWhiteTexture2D();
static AssetHandle<Texture2D> GetEmptyTexture2D(); static AssetHandle<Texture2D> GetEmptyTexture2D();
}; };
} }
@@ -25,7 +25,10 @@ namespace Copium
DescriptorPool::~DescriptorPool() DescriptorPool::~DescriptorPool()
{ {
vkDestroyDescriptorPool(Vulkan::GetDevice(), descriptorPool, nullptr); VkDescriptorPool descriptorPoolCpy = descriptorPool;
Vulkan::GetDevice().QueueIdleCommand([descriptorPoolCpy]() {
vkDestroyDescriptorPool(Vulkan::GetDevice(), descriptorPoolCpy, nullptr);
});
} }
std::vector<VkDescriptorSet> DescriptorPool::AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout) std::vector<VkDescriptorSet> DescriptorPool::AllocateDescriptorSets(VkDescriptorSetLayout descriptorSetLayout)
@@ -45,7 +48,11 @@ namespace Copium
void DescriptorPool::FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets) void DescriptorPool::FreeDescriptorSets(const std::vector<VkDescriptorSet>& descriptorSets)
{ {
vkFreeDescriptorSets(Vulkan::GetDevice(), descriptorPool, descriptorSets.size(), descriptorSets.data()); VkDescriptorPool descriptorPoolCpy = descriptorPool;
std::vector<VkDescriptorSet> descriptorSetsCpy = descriptorSets;
Vulkan::GetDevice().QueueIdleCommand([descriptorPoolCpy, descriptorSetsCpy]() {
vkFreeDescriptorSets(Vulkan::GetDevice(), descriptorPoolCpy, descriptorSetsCpy.size(), descriptorSetsCpy.data());
});
} }
DescriptorPool::operator VkDescriptorPool() const DescriptorPool::operator VkDescriptorPool() const
+13 -6
View File
@@ -44,11 +44,13 @@ namespace Copium
{ {
creator.SetVertexDescriptor(Vertex::GetDescriptor()); creator.SetVertexDescriptor(Vertex::GetDescriptor());
creator.SetBlending(metaFileClass.GetValue("alpha-blending", "false") == "true" ? true : false); creator.SetBlending(metaFileClass.GetValue("alpha-blending", "false") == "true" ? true : false);
creator.SetDepthTest(metaFileClass.GetValue("depth-test", "true") == "true" ? true : false);
} }
else if (type == "LineRenderer") else if (type == "LineRenderer")
{ {
creator.SetVertexDescriptor(LineVertex::GetDescriptor()); creator.SetVertexDescriptor(LineVertex::GetDescriptor());
creator.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); creator.SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST);
creator.SetDepthTest(metaFileClass.GetValue("depth-test", "false") == "true" ? true : false);
} }
InitializeDescriptorSetLayout(creator); InitializeDescriptorSetLayout(creator);
InitializePipeline(creator); InitializePipeline(creator);
@@ -63,12 +65,17 @@ namespace Copium
Pipeline::~Pipeline() Pipeline::~Pipeline()
{ {
vkDestroyPipeline(Vulkan::GetDevice(), graphicsPipeline, nullptr); VkPipeline graphicsPipelineCpy = graphicsPipeline;
vkDestroyPipelineLayout(Vulkan::GetDevice(), pipelineLayout, nullptr); VkPipelineLayout pipelineLayoutCpy = pipelineLayout;
for (auto&& descriptorSetLayout : descriptorSetLayouts) std::vector<VkDescriptorSetLayout> descriptorSetLayoutsCpy = descriptorSetLayouts;
{ Vulkan::GetDevice().QueueIdleCommand([graphicsPipelineCpy, pipelineLayoutCpy, descriptorSetLayoutsCpy]() {
vkDestroyDescriptorSetLayout(Vulkan::GetDevice(), descriptorSetLayout, nullptr); vkDestroyPipeline(Vulkan::GetDevice(), graphicsPipelineCpy, nullptr);
} vkDestroyPipelineLayout(Vulkan::GetDevice(), pipelineLayoutCpy, nullptr);
for (auto&& descriptorSetLayout : descriptorSetLayoutsCpy)
{
vkDestroyDescriptorSetLayout(Vulkan::GetDevice(), descriptorSetLayout, nullptr);
}
});
} }
void Pipeline::Bind(const CommandBuffer& commandBuffer) void Pipeline::Bind(const CommandBuffer& commandBuffer)
+6 -2
View File
@@ -46,8 +46,12 @@ namespace Copium
Shader::~Shader() Shader::~Shader()
{ {
vkDestroyShaderModule(Vulkan::GetDevice(), vertShaderModule, nullptr); VkShaderModule vertShaderModuleCpy = vertShaderModule;
vkDestroyShaderModule(Vulkan::GetDevice(), fragShaderModule, nullptr); VkShaderModule fragShaderModuleCpy = fragShaderModule;
Vulkan::GetDevice().QueueIdleCommand([vertShaderModuleCpy, fragShaderModuleCpy]() {
vkDestroyShaderModule(Vulkan::GetDevice(), vertShaderModuleCpy, nullptr);
vkDestroyShaderModule(Vulkan::GetDevice(), fragShaderModuleCpy, nullptr);
});
} }
const std::vector<VkPipelineShaderStageCreateInfo> Shader::GetShaderStages() const const std::vector<VkPipelineShaderStageCreateInfo> Shader::GetShaderStages() const
@@ -12,10 +12,10 @@ namespace Copium
static constexpr int MAX_NUM_INDICES = 6 * MAX_NUM_QUADS; static constexpr int MAX_NUM_INDICES = 6 * MAX_NUM_QUADS;
static constexpr int MAX_NUM_TEXTURES = 32; static constexpr int MAX_NUM_TEXTURES = 32;
Renderer::Renderer() Renderer::Renderer(const AssetRef<Pipeline>& pipeline)
: descriptorPool{}, : descriptorPool{},
ibo{MAX_NUM_INDICES}, ibo{MAX_NUM_INDICES},
pipeline{"renderer.meta"}, // TODO: should be a runtime renderer pipeline or passed in constructor pipeline{pipeline},
samplers{MAX_NUM_TEXTURES, &Vulkan::GetEmptyTexture2D().GetAsset()} samplers{MAX_NUM_TEXTURES, &Vulkan::GetEmptyTexture2D().GetAsset()}
{ {
InitializeIndexBuffer(); InitializeIndexBuffer();
+1 -1
View File
@@ -33,7 +33,7 @@ namespace Copium
int textureCount; int textureCount;
void* mappedVertexBuffer; void* mappedVertexBuffer;
public: public:
Renderer(); Renderer(const AssetRef<Pipeline>& pipeline);
~Renderer(); ~Renderer();
void Quad(const glm::vec2& from, const glm::vec2& to, const glm::vec3& color = glm::vec3{1, 1, 1}); void Quad(const glm::vec2& from, const glm::vec2& to, const glm::vec3& color = glm::vec3{1, 1, 1});
@@ -39,12 +39,17 @@ namespace Copium
ColorAttachment::~ColorAttachment() ColorAttachment::~ColorAttachment()
{ {
for (auto&& image : images) std::vector<VkImage> imagesCpy = images;
vkDestroyImage(Vulkan::GetDevice(), image, nullptr); std::vector<VkDeviceMemory> imageMemoriesCpy = imageMemories;
for (auto&& imageMemory : imageMemories) std::vector<VkImageView> imageViewsCpy = imageViews;
vkFreeMemory(Vulkan::GetDevice(), imageMemory, nullptr); Vulkan::GetDevice().QueueIdleCommand([imagesCpy, imageMemoriesCpy, imageViewsCpy]() {
for (auto&& imageView : imageViews) for (auto&& image : imagesCpy)
vkDestroyImageView(Vulkan::GetDevice(), imageView, nullptr); vkDestroyImage(Vulkan::GetDevice(), image, nullptr);
for (auto&& imageMemory : imageMemoriesCpy)
vkFreeMemory(Vulkan::GetDevice(), imageMemory, nullptr);
for (auto&& imageView : imageViewsCpy)
vkDestroyImageView(Vulkan::GetDevice(), imageView, nullptr);
});
} }
void ColorAttachment::Resize(int width, int height) void ColorAttachment::Resize(int width, int height)
@@ -13,9 +13,14 @@ namespace Copium
DepthAttachment::~DepthAttachment() DepthAttachment::~DepthAttachment()
{ {
vkDestroyImage(Vulkan::GetDevice(), image, nullptr); VkImage imageCpy = image;
vkFreeMemory(Vulkan::GetDevice(), imageMemory, nullptr); VkDeviceMemory imageMemoryCpy = imageMemory;
vkDestroyImageView(Vulkan::GetDevice(), imageView, nullptr); VkImageView imageViewCpy = imageView;
Vulkan::GetDevice().QueueIdleCommand([imageCpy, imageMemoryCpy, imageViewCpy]() {
vkDestroyImage(Vulkan::GetDevice(), imageCpy, nullptr);
vkFreeMemory(Vulkan::GetDevice(), imageMemoryCpy, nullptr);
vkDestroyImageView(Vulkan::GetDevice(), imageViewCpy, nullptr);
});
} }
+8 -3
View File
@@ -75,9 +75,14 @@ namespace Copium
Font::~Font() Font::~Font()
{ {
vkDestroyImage(Vulkan::GetDevice(), image, nullptr); VkImage imageCpy = image;
vkFreeMemory(Vulkan::GetDevice(), imageMemory, nullptr); VkDeviceMemory imageMemoryCpy = imageMemory;
vkDestroyImageView(Vulkan::GetDevice(), imageView, nullptr); VkImageView imageViewCpy = imageView;
Vulkan::GetDevice().QueueIdleCommand([imageCpy, imageMemoryCpy, imageViewCpy]() {
vkDestroyImage(Vulkan::GetDevice(), imageCpy, nullptr);
vkFreeMemory(Vulkan::GetDevice(), imageMemoryCpy, nullptr);
vkDestroyImageView(Vulkan::GetDevice(), imageViewCpy, nullptr);
});
} }
VkDescriptorImageInfo Font::GetDescriptorImageInfo(int index) const VkDescriptorImageInfo Font::GetDescriptorImageInfo(int index) const
+4 -1
View File
@@ -11,7 +11,10 @@ namespace Copium
Sampler::~Sampler() Sampler::~Sampler()
{ {
vkDestroySampler(Vulkan::GetDevice(), sampler, nullptr); VkSampler samplerCpy = sampler;
Vulkan::GetDevice().QueueIdleCommand([samplerCpy]() {
vkDestroySampler(Vulkan::GetDevice(), samplerCpy, nullptr);
});
} }
void Sampler::InitializeSampler(const SamplerCreator& samplerCreator) void Sampler::InitializeSampler(const SamplerCreator& samplerCreator)
@@ -27,13 +27,14 @@ namespace Copium
Texture2D::~Texture2D() Texture2D::~Texture2D()
{ {
// TODO: Do we want to queue the deletion and have it wait for idle once every frame instead? VkImage imageCpy = image;
// Something like: VkDeviceMemory imageMemoryCpy = imageMemory;
// Vulkan::GetDevice().QueueIdleCommand([]() { Texture2D::Destroy(image, imageMemory, imageView); }); VkImageView imageViewCpy = imageView;
vkDeviceWaitIdle(Vulkan::GetDevice()); Vulkan::GetDevice().QueueIdleCommand([imageCpy, imageMemoryCpy, imageViewCpy]() {
vkDestroyImage(Vulkan::GetDevice(), image, nullptr); vkDestroyImage(Vulkan::GetDevice(), imageCpy, nullptr);
vkFreeMemory(Vulkan::GetDevice(), imageMemory, nullptr); vkFreeMemory(Vulkan::GetDevice(), imageMemoryCpy, nullptr);
vkDestroyImageView(Vulkan::GetDevice(), imageView, nullptr); vkDestroyImageView(Vulkan::GetDevice(), imageViewCpy, nullptr);
});
} }
VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const VkDescriptorImageInfo Texture2D::GetDescriptorImageInfo(int index) const