mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 18:51:52 +01:00
Consolidate AddAttachment
Loops + Rename Renderpass
-> RenderPass
This commit is contained in:
parent
92a21ea616
commit
830a800d9e
@ -7,18 +7,18 @@
|
||||
namespace skyline::gpu::interconnect {
|
||||
CommandExecutor::CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {}
|
||||
|
||||
bool CommandExecutor::CreateRenderpass(vk::Rect2D renderArea) {
|
||||
if (renderpass && renderpass->renderArea != renderArea) {
|
||||
nodes.emplace_back(std::in_place_type_t<node::RenderpassEndNode>());
|
||||
renderpass = nullptr;
|
||||
bool CommandExecutor::CreateRenderPass(vk::Rect2D renderArea) {
|
||||
if (renderPass && renderPass->renderArea != renderArea) {
|
||||
nodes.emplace_back(std::in_place_type_t<node::RenderPassEndNode>());
|
||||
renderPass = nullptr;
|
||||
}
|
||||
|
||||
bool newRenderpass{renderpass == nullptr};
|
||||
if (newRenderpass)
|
||||
bool newRenderPass{renderPass == nullptr};
|
||||
if (newRenderPass)
|
||||
// We need to create a render pass if one doesn't already exist or the current one isn't compatible
|
||||
renderpass = &std::get<node::RenderpassNode>(nodes.emplace_back(std::in_place_type_t<node::RenderpassNode>(), renderArea));
|
||||
renderPass = &std::get<node::RenderPassNode>(nodes.emplace_back(std::in_place_type_t<node::RenderPassNode>(), renderArea));
|
||||
|
||||
return newRenderpass;
|
||||
return newRenderPass;
|
||||
}
|
||||
|
||||
void CommandExecutor::AddSubpass(const std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &)> &function, vk::Rect2D renderArea, std::vector<TextureView> inputAttachments, std::vector<TextureView> colorAttachments, std::optional<TextureView> depthStencilAttachment) {
|
||||
@ -28,22 +28,22 @@ namespace skyline::gpu::interconnect {
|
||||
if (depthStencilAttachment)
|
||||
syncTextures.emplace(depthStencilAttachment->backing.get());
|
||||
|
||||
bool newRenderpass{CreateRenderpass(renderArea)};
|
||||
renderpass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr);
|
||||
if (newRenderpass)
|
||||
bool newRenderPass{CreateRenderPass(renderArea)};
|
||||
renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr);
|
||||
if (newRenderPass)
|
||||
nodes.emplace_back(std::in_place_type_t<node::FunctionNode>(), function);
|
||||
else
|
||||
nodes.emplace_back(std::in_place_type_t<node::NextSubpassFunctionNode>(), function);
|
||||
}
|
||||
|
||||
void CommandExecutor::AddClearColorSubpass(TextureView attachment, const vk::ClearColorValue &value) {
|
||||
bool newRenderpass{CreateRenderpass(vk::Rect2D{
|
||||
bool newRenderPass{CreateRenderPass(vk::Rect2D{
|
||||
.extent = attachment.backing->dimensions,
|
||||
})};
|
||||
renderpass->AddSubpass({}, attachment, nullptr);
|
||||
renderPass->AddSubpass({}, attachment, nullptr);
|
||||
|
||||
if (renderpass->ClearColorAttachment(0, value)) {
|
||||
if (!newRenderpass)
|
||||
if (renderPass->ClearColorAttachment(0, value)) {
|
||||
if (!newRenderPass)
|
||||
nodes.emplace_back(std::in_place_type_t<node::NextSubpassNode>());
|
||||
} else {
|
||||
auto function{[scissor = attachment.backing->dimensions, value](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &, GPU &) {
|
||||
@ -58,7 +58,7 @@ namespace skyline::gpu::interconnect {
|
||||
});
|
||||
}};
|
||||
|
||||
if (newRenderpass)
|
||||
if (newRenderPass)
|
||||
nodes.emplace_back(std::in_place_type_t<node::FunctionNode>(), function);
|
||||
else
|
||||
nodes.emplace_back(std::in_place_type_t<node::NextSubpassFunctionNode>(), function);
|
||||
@ -69,9 +69,9 @@ namespace skyline::gpu::interconnect {
|
||||
if (!nodes.empty()) {
|
||||
TRACE_EVENT("gpu", "CommandExecutor::Execute");
|
||||
|
||||
if (renderpass) {
|
||||
nodes.emplace_back(std::in_place_type_t<node::RenderpassEndNode>());
|
||||
renderpass = nullptr;
|
||||
if (renderPass) {
|
||||
nodes.emplace_back(std::in_place_type_t<node::RenderPassEndNode>());
|
||||
renderPass = nullptr;
|
||||
}
|
||||
|
||||
gpu.scheduler.SubmitWithCycle([this](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle) {
|
||||
@ -83,10 +83,10 @@ namespace skyline::gpu::interconnect {
|
||||
#define NODE(name) [&](name& node) { node(commandBuffer, cycle, gpu); }
|
||||
std::visit(VariantVisitor{
|
||||
NODE(FunctionNode),
|
||||
NODE(RenderpassNode),
|
||||
NODE(RenderPassNode),
|
||||
NODE(NextSubpassNode),
|
||||
NODE(NextSubpassFunctionNode),
|
||||
NODE(RenderpassEndNode),
|
||||
NODE(RenderPassEndNode),
|
||||
}, node);
|
||||
#undef NODE
|
||||
}
|
||||
|
@ -16,13 +16,13 @@ namespace skyline::gpu::interconnect {
|
||||
private:
|
||||
GPU &gpu;
|
||||
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
|
||||
|
||||
/**
|
||||
* @return If a new renderpass 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
|
||||
*/
|
||||
bool CreateRenderpass(vk::Rect2D renderArea);
|
||||
bool CreateRenderPass(vk::Rect2D renderArea);
|
||||
|
||||
public:
|
||||
CommandExecutor(const DeviceState &state);
|
||||
|
@ -4,16 +4,16 @@
|
||||
#include "command_nodes.h"
|
||||
|
||||
namespace skyline::gpu::interconnect::node {
|
||||
RenderpassNode::Storage::~Storage() {
|
||||
RenderPassNode::Storage::~Storage() {
|
||||
if (device) {
|
||||
if (framebuffer)
|
||||
(**device).destroy(framebuffer, nullptr, *device->getDispatcher());
|
||||
if (renderpass)
|
||||
(**device).destroy(renderpass, nullptr, *device->getDispatcher());
|
||||
if (renderPass)
|
||||
(**device).destroy(renderPass, nullptr, *device->getDispatcher());
|
||||
}
|
||||
}
|
||||
|
||||
u32 RenderpassNode::AddAttachment(TextureView &view) {
|
||||
u32 RenderPassNode::AddAttachment(TextureView &view) {
|
||||
auto &textures{storage->textures};
|
||||
auto texture{std::find(textures.begin(), textures.end(), view.backing)};
|
||||
if (texture == textures.end())
|
||||
@ -29,43 +29,47 @@ namespace skyline::gpu::interconnect::node {
|
||||
.initialLayout = view.backing->layout,
|
||||
.finalLayout = view.backing->layout,
|
||||
});
|
||||
return attachments.size() - 1;
|
||||
return static_cast<u32>(attachments.size() - 1);
|
||||
} else {
|
||||
// If we've got a match from a previous subpass, we need to preserve the attachment till the current subpass
|
||||
auto attachmentIndex{std::distance(attachments.begin(), attachment)};
|
||||
|
||||
auto it{subpassDescriptions.begin()};
|
||||
for (; it != subpassDescriptions.end(); it++) {
|
||||
auto getSubpassAttachmentRange{[this] (const vk::SubpassDescription& subpassDescription) {
|
||||
// Find the bounds for the attachment references belonging to the current subpass
|
||||
auto referenceBeginIt{attachmentReferences.begin()};
|
||||
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
|
||||
referenceBeginIt += reinterpret_cast<uintptr_t>(subpassDescription.pInputAttachments) / sizeof(vk::AttachmentReference);
|
||||
|
||||
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount}; // We depend on all attachments being contiguous for a subpass, this will horribly break if that assumption is broken
|
||||
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != NoDepthStencil)
|
||||
auto referenceEndIt{referenceBeginIt + subpassDescription.inputAttachmentCount + subpassDescription.colorAttachmentCount}; // We depend on all attachments being contiguous for a subpass, this will horribly break if that assumption is broken
|
||||
if (reinterpret_cast<uintptr_t>(subpassDescription.pDepthStencilAttachment) != NoDepthStencil)
|
||||
referenceEndIt++;
|
||||
|
||||
return std::make_pair(referenceBeginIt, referenceEndIt);
|
||||
}};
|
||||
|
||||
// We want to find the first subpass that utilizes the attachment we want to preserve
|
||||
for (; it != subpassDescriptions.end(); it++) {
|
||||
auto [attachmentReferenceBegin, attachmentReferenceEnd]{getSubpassAttachmentRange(*it)};
|
||||
|
||||
// Iterate over all attachment references in the current subpass to see if they point to our target attachment
|
||||
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
|
||||
if (std::find_if(attachmentReferenceBegin, attachmentReferenceEnd, [&](const vk::AttachmentReference &reference) {
|
||||
return reference.attachment == attachmentIndex;
|
||||
}) != referenceEndIt)
|
||||
break; // The iterator should be set to the first subpass that utilizes the attachment we want to preserve
|
||||
}) != attachmentReferenceEnd)
|
||||
break;
|
||||
}
|
||||
|
||||
if (it == subpassDescriptions.end())
|
||||
// We should never have a case where an attachment is bound to the render pass but not utilized by any subpass
|
||||
throw exception("Cannot find corresponding subpass for attachment #{}", attachmentIndex);
|
||||
|
||||
// We want to preserve the attachment for all subpasses till the current subpass
|
||||
auto lastUsageIt{it}; //!< The last subpass that the attachment has been used in for creating a dependency
|
||||
for (; it != subpassDescriptions.end(); it++) {
|
||||
auto referenceBeginIt{attachmentReferences.begin()};
|
||||
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
|
||||
auto [attachmentReferenceBegin, attachmentReferenceEnd]{getSubpassAttachmentRange(*it)};
|
||||
|
||||
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount};
|
||||
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != NoDepthStencil)
|
||||
referenceEndIt++;
|
||||
|
||||
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
|
||||
if (std::find_if(attachmentReferenceBegin, attachmentReferenceEnd, [&](const vk::AttachmentReference &reference) {
|
||||
return reference.attachment == attachmentIndex;
|
||||
}) != referenceEndIt) {
|
||||
}) != attachmentReferenceEnd) {
|
||||
lastUsageIt = it;
|
||||
continue; // If a subpass uses an attachment then it doesn't need to be preserved
|
||||
}
|
||||
@ -75,6 +79,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
subpassPreserveAttachments.push_back(attachmentIndex);
|
||||
}
|
||||
|
||||
// We want to ensure writes to the attachment from the last subpass using it are complete prior to using it in the latest subpass
|
||||
vk::SubpassDependency dependency{
|
||||
.srcSubpass = static_cast<u32>(std::distance(subpassDescriptions.begin(), lastUsageIt)),
|
||||
.dstSubpass = static_cast<uint32_t>(subpassDescriptions.size()), // We assume that the next subpass is using the attachment
|
||||
@ -92,7 +97,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderpassNode::AddSubpass(span<TextureView> inputAttachments, span<TextureView> colorAttachments, TextureView *depthStencilAttachment) {
|
||||
void RenderPassNode::AddSubpass(span<TextureView> inputAttachments, span<TextureView> colorAttachments, TextureView *depthStencilAttachment) {
|
||||
attachmentReferences.reserve(attachmentReferences.size() + inputAttachments.size() + colorAttachments.size() + (depthStencilAttachment ? 1 : 0));
|
||||
|
||||
auto inputAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
|
||||
@ -132,7 +137,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
});
|
||||
}
|
||||
|
||||
bool RenderpassNode::ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value) {
|
||||
bool RenderPassNode::ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value) {
|
||||
auto attachmentReference{RebasePointer(attachmentReferences, subpassDescriptions.back().pColorAttachments) + colorAttachment};
|
||||
auto attachmentIndex{attachmentReference->attachment};
|
||||
|
||||
@ -155,7 +160,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderpassNode::operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
|
||||
void RenderPassNode::operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
|
||||
storage->device = &gpu.vkDevice;
|
||||
|
||||
auto preserveAttachmentIt{preserveAttachmentReferences.begin()};
|
||||
@ -181,7 +186,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
texture->WaitOnFence();
|
||||
}
|
||||
|
||||
auto renderpass{(*gpu.vkDevice).createRenderPass(vk::RenderPassCreateInfo{
|
||||
auto renderPass{(*gpu.vkDevice).createRenderPass(vk::RenderPassCreateInfo{
|
||||
.attachmentCount = static_cast<u32>(attachmentDescriptions.size()),
|
||||
.pAttachments = attachmentDescriptions.data(),
|
||||
.subpassCount = static_cast<u32>(subpassDescriptions.size()),
|
||||
@ -189,10 +194,10 @@ namespace skyline::gpu::interconnect::node {
|
||||
.dependencyCount = static_cast<u32>(subpassDependencies.size()),
|
||||
.pDependencies = subpassDependencies.data(),
|
||||
}, nullptr, *gpu.vkDevice.getDispatcher())};
|
||||
storage->renderpass = renderpass;
|
||||
storage->renderPass = renderPass;
|
||||
|
||||
auto framebuffer{(*gpu.vkDevice).createFramebuffer(vk::FramebufferCreateInfo{
|
||||
.renderPass = renderpass,
|
||||
.renderPass = renderPass,
|
||||
.attachmentCount = static_cast<u32>(attachments.size()),
|
||||
.pAttachments = attachments.data(),
|
||||
.width = renderArea.extent.width,
|
||||
@ -202,7 +207,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
storage->framebuffer = framebuffer;
|
||||
|
||||
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo{
|
||||
.renderPass = renderpass,
|
||||
.renderPass = renderPass,
|
||||
.framebuffer = framebuffer,
|
||||
.renderArea = renderArea,
|
||||
.clearValueCount = static_cast<u32>(clearValues.size()),
|
||||
|
@ -24,9 +24,9 @@ namespace skyline::gpu::interconnect::node {
|
||||
using FunctionNode = FunctionNodeBase<>;
|
||||
|
||||
/**
|
||||
* @brief Creates and begins a VkRenderpass alongside managing all resources bound to it and to the subpasses inside it
|
||||
* @brief Creates and begins a VkRenderPass alongside managing all resources bound to it and to the subpasses inside it
|
||||
*/
|
||||
struct RenderpassNode {
|
||||
struct RenderPassNode {
|
||||
private:
|
||||
/**
|
||||
* @brief Storage for all resources in the VkRenderPass that have their lifetimes bond to the completion fence
|
||||
@ -34,7 +34,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
struct Storage : public FenceCycleDependency {
|
||||
vk::raii::Device *device{};
|
||||
vk::Framebuffer framebuffer{};
|
||||
vk::RenderPass renderpass{};
|
||||
vk::RenderPass renderPass{};
|
||||
std::vector<std::shared_ptr<Texture>> textures;
|
||||
|
||||
~Storage();
|
||||
@ -65,7 +65,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
vk::Rect2D renderArea;
|
||||
std::vector<vk::ClearValue> clearValues;
|
||||
|
||||
RenderpassNode(vk::Rect2D renderArea) : storage(std::make_shared<Storage>()), renderArea(renderArea) {}
|
||||
RenderPassNode(vk::Rect2D renderArea) : storage(std::make_shared<Storage>()), renderArea(renderArea) {}
|
||||
|
||||
/**
|
||||
* @note Any preservation of attachments from previous subpasses is automatically handled by this
|
||||
@ -90,7 +90,7 @@ namespace skyline::gpu::interconnect::node {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A node which progresses to the next subpass during a renderpass
|
||||
* @brief A node which progresses to the next subpass during a render pass
|
||||
*/
|
||||
struct NextSubpassNode {
|
||||
void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
|
||||
@ -111,13 +111,13 @@ namespace skyline::gpu::interconnect::node {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Ends a VkRenderpass that would be created prior with RenderpassNode
|
||||
* @brief Ends a VkRenderPass that would be created prior with RenderPassNode
|
||||
*/
|
||||
struct RenderpassEndNode {
|
||||
struct RenderPassEndNode {
|
||||
void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
|
||||
commandBuffer.endRenderPass();
|
||||
}
|
||||
};
|
||||
|
||||
using NodeVariant = std::variant<FunctionNode, RenderpassNode, NextSubpassNode, NextSubpassFunctionNode, RenderpassEndNode>; //!< A variant encompassing all command nodes types
|
||||
using NodeVariant = std::variant<FunctionNode, RenderPassNode, NextSubpassNode, NextSubpassFunctionNode, RenderPassEndNode>; //!< A variant encompassing all command nodes types
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user