vk_scheduler: Implement a scheduler
The scheduler abstracts command buffer and fence management with an interface that's able to do OpenGL-like operations on Vulkan command buffers. It returns by value a command buffer and fence that have to be used for subsequent operations until Flush or Finish is executed, after that the current execution context (the pair of command buffers and fences) gets invalidated a new one must be fetched. Thankfully validation layers will quickly detect if this is skipped throwing an error due to modifications to a sent command buffer.
This commit is contained in:
parent
94b27bb8a5
commit
f546fb35ed
|
@ -109,7 +109,9 @@ if (ENABLE_VULKAN)
|
|||
renderer_vulkan/vk_memory_manager.cpp
|
||||
renderer_vulkan/vk_memory_manager.h
|
||||
renderer_vulkan/vk_resource_manager.cpp
|
||||
renderer_vulkan/vk_resource_manager.h)
|
||||
renderer_vulkan/vk_resource_manager.h
|
||||
renderer_vulkan/vk_scheduler.cpp
|
||||
renderer_vulkan/vk_scheduler.h)
|
||||
|
||||
target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include)
|
||||
target_compile_definitions(video_core PRIVATE HAS_VULKAN)
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_vulkan/declarations.h"
|
||||
#include "video_core/renderer_vulkan/vk_device.h"
|
||||
#include "video_core/renderer_vulkan/vk_resource_manager.h"
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
VKScheduler::VKScheduler(const VKDevice& device, VKResourceManager& resource_manager)
|
||||
: device{device}, resource_manager{resource_manager} {
|
||||
next_fence = &resource_manager.CommitFence();
|
||||
AllocateNewContext();
|
||||
}
|
||||
|
||||
VKScheduler::~VKScheduler() = default;
|
||||
|
||||
VKExecutionContext VKScheduler::GetExecutionContext() const {
|
||||
return VKExecutionContext(current_fence, current_cmdbuf);
|
||||
}
|
||||
|
||||
VKExecutionContext VKScheduler::Flush(vk::Semaphore semaphore) {
|
||||
SubmitExecution(semaphore);
|
||||
current_fence->Release();
|
||||
AllocateNewContext();
|
||||
return GetExecutionContext();
|
||||
}
|
||||
|
||||
VKExecutionContext VKScheduler::Finish(vk::Semaphore semaphore) {
|
||||
SubmitExecution(semaphore);
|
||||
current_fence->Wait();
|
||||
current_fence->Release();
|
||||
AllocateNewContext();
|
||||
return GetExecutionContext();
|
||||
}
|
||||
|
||||
void VKScheduler::SubmitExecution(vk::Semaphore semaphore) {
|
||||
const auto& dld = device.GetDispatchLoader();
|
||||
current_cmdbuf.end(dld);
|
||||
|
||||
const auto queue = device.GetGraphicsQueue();
|
||||
const vk::SubmitInfo submit_info(0, nullptr, nullptr, 1, ¤t_cmdbuf, semaphore ? 1u : 0u,
|
||||
&semaphore);
|
||||
queue.submit({submit_info}, *current_fence, dld);
|
||||
}
|
||||
|
||||
void VKScheduler::AllocateNewContext() {
|
||||
current_fence = next_fence;
|
||||
current_cmdbuf = resource_manager.CommitCommandBuffer(*current_fence);
|
||||
next_fence = &resource_manager.CommitFence();
|
||||
|
||||
const auto& dld = device.GetDispatchLoader();
|
||||
current_cmdbuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}, dld);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/renderer_vulkan/declarations.h"
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
class VKDevice;
|
||||
class VKExecutionContext;
|
||||
class VKFence;
|
||||
class VKResourceManager;
|
||||
|
||||
/// The scheduler abstracts command buffer and fence management with an interface that's able to do
|
||||
/// OpenGL-like operations on Vulkan command buffers.
|
||||
class VKScheduler {
|
||||
public:
|
||||
explicit VKScheduler(const VKDevice& device, VKResourceManager& resource_manager);
|
||||
~VKScheduler();
|
||||
|
||||
/// Gets the current execution context.
|
||||
[[nodiscard]] VKExecutionContext GetExecutionContext() const;
|
||||
|
||||
/// Sends the current execution context to the GPU. It invalidates the current execution context
|
||||
/// and returns a new one.
|
||||
VKExecutionContext Flush(vk::Semaphore semaphore = nullptr);
|
||||
|
||||
/// Sends the current execution context to the GPU and waits for it to complete. It invalidates
|
||||
/// the current execution context and returns a new one.
|
||||
VKExecutionContext Finish(vk::Semaphore semaphore = nullptr);
|
||||
|
||||
private:
|
||||
void SubmitExecution(vk::Semaphore semaphore);
|
||||
|
||||
void AllocateNewContext();
|
||||
|
||||
const VKDevice& device;
|
||||
VKResourceManager& resource_manager;
|
||||
vk::CommandBuffer current_cmdbuf;
|
||||
VKFence* current_fence = nullptr;
|
||||
VKFence* next_fence = nullptr;
|
||||
};
|
||||
|
||||
class VKExecutionContext {
|
||||
friend class VKScheduler;
|
||||
|
||||
public:
|
||||
VKExecutionContext() = default;
|
||||
|
||||
VKFence& GetFence() const {
|
||||
return *fence;
|
||||
}
|
||||
|
||||
vk::CommandBuffer GetCommandBuffer() const {
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit VKExecutionContext(VKFence* fence, vk::CommandBuffer cmdbuf)
|
||||
: fence{fence}, cmdbuf{cmdbuf} {}
|
||||
|
||||
VKFence* fence{};
|
||||
vk::CommandBuffer cmdbuf;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
Reference in New Issue