mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-26 18:34:15 +01:00
Fix Command Buffer Allocation & FenceCycle
This commit fixes a major issue with command buffer allocation which would result in only being able to utilize a command buffer slot on the 2nd attempt to use it after it's freed, this would lead to a significantly larger amount of command buffers being created than necessary. It also fixes an issue with the command buffers not being reset after they were utilized which results in UB eventually. Another issue was fixed with `FenceCycle` where all dependencies are only destroyed on destruction of the `FenceCycle` itself rather than the function where the `VkFence` was found to be signalled.
This commit is contained in:
parent
bee28aaf0d
commit
3879d573d5
@ -8,8 +8,9 @@ namespace skyline::gpu {
|
|||||||
CommandScheduler::CommandBufferSlot::CommandBufferSlot(vk::raii::Device &device, vk::CommandBuffer commandBuffer, vk::raii::CommandPool &pool) : device(device), commandBuffer(device, commandBuffer, pool), fence(device, vk::FenceCreateInfo{}), cycle(std::make_shared<FenceCycle>(device, *fence)) {}
|
CommandScheduler::CommandBufferSlot::CommandBufferSlot(vk::raii::Device &device, vk::CommandBuffer commandBuffer, vk::raii::CommandPool &pool) : device(device), commandBuffer(device, commandBuffer, pool), fence(device, vk::FenceCreateInfo{}), cycle(std::make_shared<FenceCycle>(device, *fence)) {}
|
||||||
|
|
||||||
bool CommandScheduler::CommandBufferSlot::AllocateIfFree(CommandScheduler::CommandBufferSlot &slot) {
|
bool CommandScheduler::CommandBufferSlot::AllocateIfFree(CommandScheduler::CommandBufferSlot &slot) {
|
||||||
if (slot.active.test_and_set(std::memory_order_acq_rel)) {
|
if (!slot.active.test_and_set(std::memory_order_acq_rel)) {
|
||||||
if (slot.cycle->Poll()) {
|
if (slot.cycle->Poll()) {
|
||||||
|
slot.commandBuffer.reset();
|
||||||
slot.cycle = std::make_shared<FenceCycle>(slot.device, *slot.fence);
|
slot.cycle = std::make_shared<FenceCycle>(slot.device, *slot.fence);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -25,11 +26,12 @@ namespace skyline::gpu {
|
|||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
CommandScheduler::ActiveCommandBuffer CommandScheduler::AllocateCommandBuffer() {
|
CommandScheduler::ActiveCommandBuffer CommandScheduler::AllocateCommandBuffer() {
|
||||||
|
std::scoped_lock lock(mutex);
|
||||||
auto slot{std::find_if(commandBuffers.begin(), commandBuffers.end(), CommandBufferSlot::AllocateIfFree)};
|
auto slot{std::find_if(commandBuffers.begin(), commandBuffers.end(), CommandBufferSlot::AllocateIfFree)};
|
||||||
|
auto slotId{std::distance(commandBuffers.begin(), slot)};
|
||||||
if (slot != commandBuffers.end())
|
if (slot != commandBuffers.end())
|
||||||
return ActiveCommandBuffer(*slot);
|
return ActiveCommandBuffer(*slot);
|
||||||
|
|
||||||
std::scoped_lock lock(mutex);
|
|
||||||
vk::CommandBuffer commandBuffer;
|
vk::CommandBuffer commandBuffer;
|
||||||
vk::CommandBufferAllocateInfo commandBufferAllocateInfo{
|
vk::CommandBufferAllocateInfo commandBufferAllocateInfo{
|
||||||
.commandPool = *vkCommandPool,
|
.commandPool = *vkCommandPool,
|
||||||
|
@ -41,7 +41,7 @@ namespace skyline::gpu {
|
|||||||
constexpr ActiveCommandBuffer(CommandBufferSlot &slot) : slot(slot) {}
|
constexpr ActiveCommandBuffer(CommandBufferSlot &slot) : slot(slot) {}
|
||||||
|
|
||||||
~ActiveCommandBuffer() {
|
~ActiveCommandBuffer() {
|
||||||
slot.active.clear();
|
slot.active.clear(std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Fence GetFence() {
|
vk::Fence GetFence() {
|
||||||
@ -93,5 +93,19 @@ namespace skyline::gpu {
|
|||||||
SubmitCommandBuffer(*commandBuffer, commandBuffer.GetFence());
|
SubmitCommandBuffer(*commandBuffer, commandBuffer.GetFence());
|
||||||
return commandBuffer.GetFenceCycle();
|
return commandBuffer.GetFenceCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note Same as Submit but with FenceCycle as an argument rather than return value
|
||||||
|
*/
|
||||||
|
template<typename RecordFunction>
|
||||||
|
void SubmitWithCycle(RecordFunction recordFunction) {
|
||||||
|
auto commandBuffer{AllocateCommandBuffer()};
|
||||||
|
commandBuffer->begin(vk::CommandBufferBeginInfo{
|
||||||
|
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit,
|
||||||
|
});
|
||||||
|
recordFunction(*commandBuffer, commandBuffer.GetFenceCycle());
|
||||||
|
commandBuffer->end();
|
||||||
|
SubmitCommandBuffer(*commandBuffer, commandBuffer.GetFence());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ namespace skyline::gpu {
|
|||||||
if (signalled.test(std::memory_order_consume))
|
if (signalled.test(std::memory_order_consume))
|
||||||
return;
|
return;
|
||||||
while (device.waitForFences(fence, false, std::numeric_limits<u64>::max()) != vk::Result::eSuccess);
|
while (device.waitForFences(fence, false, std::numeric_limits<u64>::max()) != vk::Result::eSuccess);
|
||||||
if (signalled.test_and_set(std::memory_order_release))
|
if (!signalled.test_and_set(std::memory_order_release))
|
||||||
DestroyDependencies();
|
DestroyDependencies();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ namespace skyline::gpu {
|
|||||||
if (signalled.test(std::memory_order_consume))
|
if (signalled.test(std::memory_order_consume))
|
||||||
return true;
|
return true;
|
||||||
if (device.waitForFences(fence, false, timeout.count()) == vk::Result::eSuccess) {
|
if (device.waitForFences(fence, false, timeout.count()) == vk::Result::eSuccess) {
|
||||||
if (signalled.test_and_set(std::memory_order_release))
|
if (!signalled.test_and_set(std::memory_order_release))
|
||||||
DestroyDependencies();
|
DestroyDependencies();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -86,8 +86,9 @@ namespace skyline::gpu {
|
|||||||
bool Poll() {
|
bool Poll() {
|
||||||
if (signalled.test(std::memory_order_consume))
|
if (signalled.test(std::memory_order_consume))
|
||||||
return true;
|
return true;
|
||||||
if ((*device).getFenceStatus(fence, *device.getDispatcher()) == vk::Result::eSuccess) {
|
auto status{(*device).getFenceStatus(fence, *device.getDispatcher())};
|
||||||
if (signalled.test_and_set(std::memory_order_release))
|
if (status == vk::Result::eSuccess) {
|
||||||
|
if (!signalled.test_and_set(std::memory_order_release))
|
||||||
DestroyDependencies();
|
DestroyDependencies();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user