Consolidate AddAttachment Loops + Rename Renderpass -> RenderPass

This commit is contained in:
PixelyIon 2021-10-24 02:31:22 +05:30
parent 92a21ea616
commit 830a800d9e
4 changed files with 64 additions and 59 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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()),

View File

@ -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
}