mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-24 03:41:52 +01:00
Allow Attaching Texture/Buffers to CommandExecutor
Switch from `SubmitWithCycle` to manually allocating the active command buffer to tag dependencies with the `FenceCycle` that prevents them from being mutated prior to execution. This new paradigm could also allow eager recording of commands with only submission being deferred.
This commit is contained in:
parent
aeea3e6f66
commit
cb7f68b98d
@ -5,7 +5,11 @@
|
|||||||
#include "command_executor.h"
|
#include "command_executor.h"
|
||||||
|
|
||||||
namespace skyline::gpu::interconnect {
|
namespace skyline::gpu::interconnect {
|
||||||
CommandExecutor::CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {}
|
CommandExecutor::CommandExecutor(const DeviceState &state) : gpu(*state.gpu), activeCommandBuffer(gpu.scheduler.AllocateCommandBuffer()), cycle(activeCommandBuffer.GetFenceCycle()) {}
|
||||||
|
|
||||||
|
CommandExecutor::~CommandExecutor() {
|
||||||
|
cycle->Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
bool CommandExecutor::CreateRenderPass(vk::Rect2D renderArea) {
|
bool CommandExecutor::CreateRenderPass(vk::Rect2D renderArea) {
|
||||||
if (renderPass && renderPass->renderArea != renderArea) {
|
if (renderPass && renderPass->renderArea != renderArea) {
|
||||||
@ -21,12 +25,30 @@ namespace skyline::gpu::interconnect {
|
|||||||
return newRenderPass;
|
return newRenderPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CommandExecutor::AttachTexture(const std::shared_ptr<Texture> &texture) {
|
||||||
|
if (!syncTextures.contains(texture.get())) {
|
||||||
|
texture->WaitOnFence();
|
||||||
|
texture->cycle = cycle;
|
||||||
|
cycle->AttachObject(texture);
|
||||||
|
syncTextures.emplace(texture.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandExecutor::AttachBuffer(const std::shared_ptr<Buffer> &buffer) {
|
||||||
|
if (!syncBuffers.contains(buffer.get())) {
|
||||||
|
buffer->WaitOnFence();
|
||||||
|
buffer->cycle = cycle;
|
||||||
|
cycle->AttachObject(buffer);
|
||||||
|
syncBuffers.emplace(buffer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CommandExecutor::AddSubpass(const std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &)> &function, vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment) {
|
void CommandExecutor::AddSubpass(const std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &)> &function, vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment) {
|
||||||
for (const auto &attachments : {inputAttachments, colorAttachments})
|
for (const auto &attachments : {inputAttachments, colorAttachments})
|
||||||
for (const auto &attachment : attachments)
|
for (const auto &attachment : attachments)
|
||||||
syncTextures.emplace(attachment->texture.get());
|
AttachTexture(attachment->texture);
|
||||||
if (depthStencilAttachment)
|
if (depthStencilAttachment)
|
||||||
syncTextures.emplace(depthStencilAttachment->texture.get());
|
AttachTexture(depthStencilAttachment->texture);
|
||||||
|
|
||||||
bool newRenderPass{CreateRenderPass(renderArea)};
|
bool newRenderPass{CreateRenderPass(renderArea)};
|
||||||
renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr);
|
renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr);
|
||||||
@ -37,6 +59,8 @@ namespace skyline::gpu::interconnect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CommandExecutor::AddClearColorSubpass(TextureView *attachment, const vk::ClearColorValue &value) {
|
void CommandExecutor::AddClearColorSubpass(TextureView *attachment, const vk::ClearColorValue &value) {
|
||||||
|
AttachTexture(attachment->texture);
|
||||||
|
|
||||||
bool newRenderPass{CreateRenderPass(vk::Rect2D{
|
bool newRenderPass{CreateRenderPass(vk::Rect2D{
|
||||||
.extent = attachment->texture->dimensions,
|
.extent = attachment->texture->dimensions,
|
||||||
})};
|
})};
|
||||||
@ -74,10 +98,18 @@ namespace skyline::gpu::interconnect {
|
|||||||
renderPass = nullptr;
|
renderPass = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu.scheduler.SubmitWithCycle([this](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle) {
|
{
|
||||||
|
auto &commandBuffer{*activeCommandBuffer};
|
||||||
|
commandBuffer.begin(vk::CommandBufferBeginInfo{
|
||||||
|
.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit,
|
||||||
|
});
|
||||||
|
|
||||||
for (auto texture : syncTextures)
|
for (auto texture : syncTextures)
|
||||||
texture->SynchronizeHostWithBuffer(commandBuffer, cycle);
|
texture->SynchronizeHostWithBuffer(commandBuffer, cycle);
|
||||||
|
|
||||||
|
for (auto buffer : syncBuffers)
|
||||||
|
buffer->SynchronizeHostWithCycle(cycle);
|
||||||
|
|
||||||
using namespace node;
|
using namespace node;
|
||||||
for (NodeVariant &node : nodes) {
|
for (NodeVariant &node : nodes) {
|
||||||
#define NODE(name) [&](name& node) { node(commandBuffer, cycle, gpu); }
|
#define NODE(name) [&](name& node) { node(commandBuffer, cycle, gpu); }
|
||||||
@ -93,7 +125,15 @@ namespace skyline::gpu::interconnect {
|
|||||||
|
|
||||||
for (auto texture : syncTextures)
|
for (auto texture : syncTextures)
|
||||||
texture->SynchronizeGuestWithBuffer(commandBuffer, cycle);
|
texture->SynchronizeGuestWithBuffer(commandBuffer, cycle);
|
||||||
})->Wait();
|
|
||||||
|
for (auto buffer : syncBuffers)
|
||||||
|
buffer->SynchronizeGuestWithCycle(cycle);
|
||||||
|
|
||||||
|
commandBuffer.end();
|
||||||
|
|
||||||
|
gpu.scheduler.SubmitCommandBuffer(commandBuffer, activeCommandBuffer.GetFence());
|
||||||
|
cycle = activeCommandBuffer.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
nodes.clear();
|
nodes.clear();
|
||||||
syncTextures.clear();
|
syncTextures.clear();
|
||||||
|
@ -10,14 +10,17 @@
|
|||||||
namespace skyline::gpu::interconnect {
|
namespace skyline::gpu::interconnect {
|
||||||
/**
|
/**
|
||||||
* @brief Assembles a Vulkan command stream with various nodes and manages execution of the produced graph
|
* @brief Assembles a Vulkan command stream with various nodes and manages execution of the produced graph
|
||||||
* @note This class is **NOT** thread-safe and should not be utilized by multiple threads concurrently
|
* @note This class is **NOT** thread-safe and should **ONLY** be utilized by a single thread
|
||||||
*/
|
*/
|
||||||
class CommandExecutor {
|
class CommandExecutor {
|
||||||
private:
|
private:
|
||||||
GPU &gpu;
|
GPU &gpu;
|
||||||
|
CommandScheduler::ActiveCommandBuffer activeCommandBuffer;
|
||||||
|
std::shared_ptr<FenceCycle> cycle;
|
||||||
boost::container::stable_vector<node::NodeVariant> nodes;
|
boost::container::stable_vector<node::NodeVariant> nodes;
|
||||||
node::RenderPassNode *renderPass{};
|
node::RenderPassNode *renderPass{};
|
||||||
std::unordered_set<Texture*> syncTextures; //!< All textures that need to be synced prior to and after execution
|
std::unordered_set<Texture *> syncTextures; //!< All textures that need to be synced prior to and after execution
|
||||||
|
std::unordered_set<Buffer *> syncBuffers; //!< All buffers that need to be synced prior to and after execution
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If a new render pass was created by the function or the current one was reused as it was compatible
|
* @return If a new render pass was created by the function or the current one was reused as it was compatible
|
||||||
@ -27,9 +30,24 @@ namespace skyline::gpu::interconnect {
|
|||||||
public:
|
public:
|
||||||
CommandExecutor(const DeviceState &state);
|
CommandExecutor(const DeviceState &state);
|
||||||
|
|
||||||
|
~CommandExecutor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attach the lifetime of the texture to the command buffer
|
||||||
|
* @note This'll automatically handle syncing of the texture in the most optimal way possible
|
||||||
|
*/
|
||||||
|
void AttachTexture(const std::shared_ptr<Texture> &texture);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Attach the lifetime of a buffer to the command buffer
|
||||||
|
* @note This'll automatically handle syncing of the buffer in the most optimal way possible
|
||||||
|
*/
|
||||||
|
void AttachBuffer(const std::shared_ptr<Buffer> &buffer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a command that needs to be executed inside a subpass configured with certain attachments
|
* @brief Adds a command that needs to be executed inside a subpass configured with certain attachments
|
||||||
* @note Any texture supplied to this **must** be locked by the calling thread, it should also undergo no persistent layout transitions till execution
|
* @note Any texture supplied to this **must** be locked by the calling thread, it should also undergo no persistent layout transitions till execution
|
||||||
|
* @note All attachments will automatically be attached and aren't required to be attached prior
|
||||||
*/
|
*/
|
||||||
void AddSubpass(const std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &)> &&function, vk::Rect2D renderArea, span<TextureView *> inputAttachments = {}, span<TextureView *> colorAttachments = {}, TextureView *depthStencilAttachment = {});
|
void AddSubpass(const std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &)> &&function, vk::Rect2D renderArea, span<TextureView *> inputAttachments = {}, span<TextureView *> colorAttachments = {}, TextureView *depthStencilAttachment = {});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user