mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2026-04-22 02:11:43 +00:00
refactor(cleanup): fix a memory leak & optimize reuse
This commit is contained in:
parent
df6367cf2e
commit
a354150cba
7 changed files with 62 additions and 33 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
#include "lsfg-vk-common/vulkan/buffer.hpp"
|
||||
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
|
||||
#include "lsfg-vk-common/vulkan/fence.hpp"
|
||||
#include "lsfg-vk-common/vulkan/image.hpp"
|
||||
#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp"
|
||||
#include "lsfg-vk-common/vulkan/vulkan.hpp"
|
||||
|
|
@ -98,7 +99,7 @@ namespace lsfgvk {
|
|||
size_t fidx{0}; // real frame index
|
||||
|
||||
std::vector<vk::CommandBuffer> cmdbufs; // TODO: ponder reuse
|
||||
size_t cmdbuf_idx{0};
|
||||
vk::Fence cmdbufFence;
|
||||
|
||||
ls::Ctx ctx;
|
||||
|
||||
|
|
@ -377,7 +378,8 @@ ContextImpl::ContextImpl(const InstanceImpl& instance,
|
|||
blackImage(createBlackImage(instance.getVulkan())),
|
||||
syncSemaphore(importTimelineSemaphore(instance.getVulkan(), syncFd)),
|
||||
prepassSemaphore(createPrepassSemaphore(instance.getVulkan())),
|
||||
cmdbufs(createCommandBuffers(instance.getVulkan(), 16)),
|
||||
cmdbufs(createCommandBuffers(instance.getVulkan(), destFds.size() + 1)),
|
||||
cmdbufFence(instance.getVulkan()),
|
||||
ctx(createCtx(instance, extent, hdr, flow, perf, destFds.size())),
|
||||
mipmaps(ctx, sourceImages),
|
||||
alpha0{
|
||||
|
|
@ -517,8 +519,13 @@ void Instance::scheduleFrames(Context& context) {
|
|||
}
|
||||
|
||||
void Context::scheduleFrames() {
|
||||
// wait for previous pre-pass to complete
|
||||
if (this->fidx && !this->cmdbufFence.wait(this->ctx.vk))
|
||||
throw lsfgvk::error("Timeout waiting for previous frame to complete");
|
||||
this->cmdbufFence.reset(this->ctx.vk);
|
||||
|
||||
// schedule pre-pass
|
||||
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size());
|
||||
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(0);
|
||||
cmdbuf = vk::CommandBuffer(this->ctx.vk);
|
||||
|
||||
this->mipmaps.render(ctx.vk, cmdbuf, this->fidx);
|
||||
|
|
@ -538,7 +545,7 @@ void Context::scheduleFrames() {
|
|||
|
||||
// schedule main passes
|
||||
for (size_t i = 0; i < this->destImages.size(); i++) {
|
||||
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(this->cmdbuf_idx++ % this->cmdbufs.size());
|
||||
vk::CommandBuffer& cmdbuf = this->cmdbufs.at(i + 1);
|
||||
cmdbuf = vk::CommandBuffer(this->ctx.vk);
|
||||
|
||||
const auto& pass = this->passes.at(i);
|
||||
|
|
@ -554,7 +561,8 @@ void Context::scheduleFrames() {
|
|||
|
||||
cmdbuf.submit(this->ctx.vk,
|
||||
{}, this->prepassSemaphore.handle(), this->idx - 1,
|
||||
{}, this->syncSemaphore.handle(), this->idx + i
|
||||
{}, this->syncSemaphore.handle(), this->idx + i,
|
||||
i == this->destImages.size() - 1 ? this->cmdbufFence.handle() : nullptr
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ namespace ls {
|
|||
}
|
||||
owned_ptr& operator=(owned_ptr&& other) noexcept {
|
||||
if (this != &other) {
|
||||
if (this->ptr) {
|
||||
if (deleter) deleter(*this->ptr);
|
||||
delete this->ptr;
|
||||
}
|
||||
|
||||
ptr = other.ptr;
|
||||
other.ptr = nullptr;
|
||||
deleter = std::move(other.deleter);
|
||||
|
|
|
|||
|
|
@ -73,12 +73,14 @@ namespace vk {
|
|||
/// @param signalSemaphores the semaphores to signal
|
||||
/// @param signalTimelineSemaphore the timeline semaphore to signal
|
||||
/// @param signalValue the value to signal
|
||||
/// @param fence optional fence to signal on completion
|
||||
/// @throws ls::vulkan_error on failure
|
||||
void submit(const vk::Vulkan& vk,
|
||||
std::vector<VkSemaphore> waitSemaphores,
|
||||
VkSemaphore waitTimelineSemaphore, uint64_t waitValue,
|
||||
std::vector<VkSemaphore> signalSemaphores,
|
||||
VkSemaphore signalTimelineSemaphore, uint64_t signalValue) const;
|
||||
VkSemaphore signalTimelineSemaphore, uint64_t signalValue,
|
||||
VkFence fence = nullptr) const;
|
||||
|
||||
/// submit the command buffer instantly
|
||||
/// @param vk the vulkan instance
|
||||
|
|
|
|||
|
|
@ -215,7 +215,8 @@ void CommandBuffer::submit(const vk::Vulkan& vk,
|
|||
std::vector<VkSemaphore> waitSemaphores,
|
||||
VkSemaphore waitTimelineSemaphore, uint64_t waitValue,
|
||||
std::vector<VkSemaphore> signalSemaphores,
|
||||
VkSemaphore signalTimelineSemaphore, uint64_t signalValue) const {
|
||||
VkSemaphore signalTimelineSemaphore, uint64_t signalValue,
|
||||
VkFence fence) const {
|
||||
auto res = vk.df().EndCommandBuffer(*this->commandBuffer);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkEndCommandBuffer() failed");
|
||||
|
|
@ -254,7 +255,7 @@ void CommandBuffer::submit(const vk::Vulkan& vk,
|
|||
.signalSemaphoreCount = static_cast<uint32_t>(signalSemaphores.size()),
|
||||
.pSignalSemaphores = signalSemaphores.data()
|
||||
};
|
||||
res = vk.df().QueueSubmit(vk.queue(), 1, &submitInfo, VK_NULL_HANDLE);
|
||||
res = vk.df().QueueSubmit(vk.queue(), 1, &submitInfo, fence);
|
||||
if (res != VK_SUCCESS)
|
||||
throw ls::vulkan_error(res, "vkQueueSubmit() failed");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
|
|
|||
|
|
@ -101,17 +101,19 @@ Swapchain::Swapchain(const vk::Vulkan& vk, lsfgvk::Instance& backend,
|
|||
);
|
||||
|
||||
this->renderCommandBuffer.emplace(vk);
|
||||
this->renderSemaphore.emplace(vk, 0);
|
||||
this->renderFence.emplace(vk);
|
||||
for (size_t i = 0; i < this->destinationImages.size(); i++) {
|
||||
this->passes.emplace_back(RenderPass {
|
||||
.commandBuffer = vk::CommandBuffer(vk),
|
||||
.acquireSemaphore = vk::Semaphore(vk),
|
||||
.postCopySemaphore = {
|
||||
vk::Semaphore(vk),
|
||||
vk::Semaphore(vk)
|
||||
}
|
||||
.acquireSemaphore = vk::Semaphore(vk)
|
||||
});
|
||||
}
|
||||
for (size_t i = 0; i < this->info.images.size(); i++) {
|
||||
this->postCopySemaphores.emplace_back(
|
||||
vk::Semaphore(vk),
|
||||
vk::Semaphore(vk)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
VkResult Swapchain::present(const vk::Vulkan& vk,
|
||||
|
|
@ -119,7 +121,7 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
void* next_chain, uint32_t imageIdx,
|
||||
const std::vector<VkSemaphore>& semaphores) {
|
||||
const auto& swapchainImage = this->info.images.at(imageIdx);
|
||||
const auto& sourceImage = this->sourceImages.at(this->fidx++ % 2);
|
||||
const auto& sourceImage = this->sourceImages.at(this->fidx % 2);
|
||||
|
||||
// schedule frame generation
|
||||
this->instance.get().scheduleFrames(this->ctx.get());
|
||||
|
|
@ -142,8 +144,9 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
}
|
||||
|
||||
// wait for completion of previous frame
|
||||
auto no_timeout = this->renderSemaphore->wait(vk, this->idx - 1, 150UL * 1000 * 1000); // 150ms
|
||||
if (!no_timeout) throw ls::vulkan_error(VK_TIMEOUT, "vkWaitSemaphores() failed");
|
||||
if (this->fidx && !this->renderFence->wait(vk, 150UL * 1000 * 1000))
|
||||
throw ls::vulkan_error(VK_TIMEOUT, "vkWaitForFences() failed");
|
||||
this->renderFence->reset(vk);
|
||||
|
||||
// copy swapchain image into backend source image
|
||||
auto& cmdbuf = this->renderCommandBuffer.emplace(vk);
|
||||
|
|
@ -180,16 +183,13 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
{}, this->syncSemaphore->handle(), this->idx++
|
||||
);
|
||||
|
||||
uint32_t lastAqImageIdx{};
|
||||
for (size_t i = 0; i < this->destinationImages.size(); i++) {
|
||||
auto& destinationImage = this->destinationImages.at(i);
|
||||
auto& pass = this->passes.at(i);
|
||||
pass = RenderPass {
|
||||
.commandBuffer = vk::CommandBuffer(vk),
|
||||
.acquireSemaphore = vk::Semaphore(vk),
|
||||
.postCopySemaphore = {
|
||||
vk::Semaphore(vk),
|
||||
vk::Semaphore(vk)
|
||||
}
|
||||
.acquireSemaphore = vk::Semaphore(vk)
|
||||
};
|
||||
|
||||
// acquire swapchain image
|
||||
|
|
@ -204,6 +204,13 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
|
||||
const auto& aquiredSwapchainImage = this->info.images.at(aqImageIdx);
|
||||
|
||||
// create post-copy semaphores
|
||||
auto& postCopySemaphores = this->postCopySemaphores.at(aqImageIdx);
|
||||
postCopySemaphores = {
|
||||
vk::Semaphore(vk),
|
||||
vk::Semaphore(vk)
|
||||
};
|
||||
|
||||
// copy backend destination image into swapchain image
|
||||
auto& cmdbuf = pass.commandBuffer;
|
||||
|
||||
|
|
@ -236,18 +243,19 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
|
||||
std::vector<VkSemaphore> waitSemaphores{ pass.acquireSemaphore.handle() };
|
||||
if (i) { // non-first pass
|
||||
const auto& prevPass = this->passes.at(i - 1);
|
||||
waitSemaphores.push_back(prevPass.postCopySemaphore.second.handle());
|
||||
const auto& prevPCS = this->postCopySemaphores.at(lastAqImageIdx);
|
||||
waitSemaphores.push_back(prevPCS.second.handle());
|
||||
}
|
||||
|
||||
const std::vector<VkSemaphore> signalSemaphores{
|
||||
pass.postCopySemaphore.first.handle(),
|
||||
pass.postCopySemaphore.second.handle()
|
||||
postCopySemaphores.first.handle(),
|
||||
postCopySemaphores.second.handle()
|
||||
};
|
||||
|
||||
cmdbuf.submit(vk,
|
||||
waitSemaphores, this->syncSemaphore->handle(), this->idx,
|
||||
signalSemaphores, this->renderSemaphore->handle(), this->idx
|
||||
signalSemaphores, nullptr, 0,
|
||||
i == this->destinationImages.size() - 1 ? this->renderFence->handle() : nullptr
|
||||
);
|
||||
|
||||
// present swapchain image
|
||||
|
|
@ -255,7 +263,7 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = i ? nullptr : next_chain,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &pass.postCopySemaphore.first.handle(),
|
||||
.pWaitSemaphores = &postCopySemaphores.first.handle(),
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &aqImageIdx,
|
||||
|
|
@ -265,15 +273,16 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
throw ls::vulkan_error(res, "vkQueuePresentKHR() failed");
|
||||
|
||||
lastAqImageIdx = aqImageIdx;
|
||||
this->idx++;
|
||||
}
|
||||
|
||||
// present original swapchain image
|
||||
const auto& lastPass = this->passes.at(this->destinationImages.size() - 1);
|
||||
auto& lastPCS = this->postCopySemaphores.at(lastAqImageIdx);
|
||||
const VkPresentInfoKHR presentInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &lastPass.postCopySemaphore.second.handle(),
|
||||
.pWaitSemaphores = &lastPCS.second.handle(),
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &imageIdx,
|
||||
|
|
@ -282,5 +291,8 @@ VkResult Swapchain::present(const vk::Vulkan& vk,
|
|||
if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR)
|
||||
throw ls::vulkan_error(res, "vkQueuePresentKHR() failed");
|
||||
|
||||
this->postCopySemaphores.at(imageIdx).second = std::move(lastPCS.second);
|
||||
|
||||
this->fidx++;
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "lsfg-vk-backend/lsfgvk.hpp"
|
||||
#include "lsfg-vk-common/helpers/pointers.hpp"
|
||||
#include "lsfg-vk-common/vulkan/command_buffer.hpp"
|
||||
#include "lsfg-vk-common/vulkan/fence.hpp"
|
||||
#include "lsfg-vk-common/vulkan/image.hpp"
|
||||
#include "lsfg-vk-common/vulkan/semaphore.hpp"
|
||||
#include "lsfg-vk-common/vulkan/timeline_semaphore.hpp"
|
||||
|
|
@ -11,6 +12,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
|
@ -61,13 +63,13 @@ namespace lsfgvk::layer {
|
|||
ls::lazy<vk::TimelineSemaphore> syncSemaphore;
|
||||
|
||||
std::optional<vk::CommandBuffer> renderCommandBuffer;
|
||||
ls::lazy<vk::TimelineSemaphore> renderSemaphore;
|
||||
ls::lazy<vk::Fence> renderFence;
|
||||
struct RenderPass {
|
||||
vk::CommandBuffer commandBuffer;
|
||||
vk::Semaphore acquireSemaphore;
|
||||
std::pair<vk::Semaphore, vk::Semaphore> postCopySemaphore;
|
||||
};
|
||||
std::vector<RenderPass> passes;
|
||||
std::vector<std::pair<vk::Semaphore, vk::Semaphore>> postCopySemaphores;
|
||||
|
||||
ls::R<lsfgvk::Instance> instance;
|
||||
ls::owned_ptr<ls::R<lsfgvk::Context>> ctx;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue