mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
Spilling the render pass should make shader storage buffer/image writes visible due to how external subpass dependencies are defined. For UAV rendering, we need to do this when changing the UAVs, even if the render targets themselves do not change.
232 lines
8.3 KiB
C++
232 lines
8.3 KiB
C++
#include <algorithm>
|
|
|
|
#include "dxvk_renderpass.h"
|
|
|
|
namespace dxvk {
|
|
|
|
bool DxvkRenderPassFormat::matches(const DxvkRenderPassFormat& fmt) const {
|
|
bool eq = sampleCount == fmt.sampleCount;
|
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
|
|
eq &= color[i].format == fmt.color[i].format
|
|
&& color[i].layout == fmt.color[i].layout;
|
|
}
|
|
|
|
eq &= depth.format == fmt.depth.format
|
|
&& depth.layout == fmt.depth.layout;
|
|
|
|
return eq;
|
|
}
|
|
|
|
|
|
DxvkRenderPass::DxvkRenderPass(
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
const DxvkRenderPassFormat& fmt)
|
|
: m_vkd(vkd), m_format(fmt),
|
|
m_default(createRenderPass(DxvkRenderPassOps())) {
|
|
|
|
}
|
|
|
|
|
|
DxvkRenderPass::~DxvkRenderPass() {
|
|
m_vkd->vkDestroyRenderPass(m_vkd->device(), m_default, nullptr);
|
|
|
|
for (const auto& i : m_instances) {
|
|
m_vkd->vkDestroyRenderPass(
|
|
m_vkd->device(), i.handle, nullptr);
|
|
}
|
|
}
|
|
|
|
|
|
bool DxvkRenderPass::hasCompatibleFormat(const DxvkRenderPassFormat& fmt) const {
|
|
return m_format.matches(fmt);
|
|
}
|
|
|
|
|
|
VkRenderPass DxvkRenderPass::getHandle(const DxvkRenderPassOps& ops) {
|
|
std::lock_guard<sync::Spinlock> lock(m_mutex);
|
|
|
|
for (const auto& i : m_instances) {
|
|
if (compareOps(i.ops, ops))
|
|
return i.handle;
|
|
}
|
|
|
|
VkRenderPass handle = this->createRenderPass(ops);
|
|
m_instances.push_back({ ops, handle });
|
|
return handle;
|
|
}
|
|
|
|
|
|
VkRenderPass DxvkRenderPass::createRenderPass(const DxvkRenderPassOps& ops) {
|
|
std::vector<VkAttachmentDescription> attachments;
|
|
|
|
VkAttachmentReference depthRef;
|
|
std::array<VkAttachmentReference, MaxNumRenderTargets> colorRef;
|
|
|
|
// Render passes may not require the previous
|
|
// contents of the attachments to be preserved.
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
|
colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
|
|
colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
if (m_format.color[i].format != VK_FORMAT_UNDEFINED) {
|
|
VkAttachmentDescription desc;
|
|
desc.flags = 0;
|
|
desc.format = m_format.color[i].format;
|
|
desc.samples = m_format.sampleCount;
|
|
desc.loadOp = ops.colorOps[i].loadOp;
|
|
desc.storeOp = ops.colorOps[i].storeOp;
|
|
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
desc.initialLayout = ops.colorOps[i].loadLayout;
|
|
desc.finalLayout = ops.colorOps[i].storeLayout;
|
|
|
|
colorRef[i].attachment = attachments.size();
|
|
colorRef[i].layout = m_format.color[i].layout;
|
|
|
|
attachments.push_back(desc);
|
|
}
|
|
}
|
|
|
|
if (m_format.depth.format != VK_FORMAT_UNDEFINED) {
|
|
VkAttachmentDescription desc;
|
|
desc.flags = 0;
|
|
desc.format = m_format.depth.format;
|
|
desc.samples = m_format.sampleCount;
|
|
desc.loadOp = ops.depthOps.loadOpD;
|
|
desc.storeOp = ops.depthOps.storeOpD;
|
|
desc.stencilLoadOp = ops.depthOps.loadOpS;
|
|
desc.stencilStoreOp = ops.depthOps.storeOpS;
|
|
desc.initialLayout = ops.depthOps.loadLayout;
|
|
desc.finalLayout = ops.depthOps.storeLayout;
|
|
|
|
depthRef.attachment = attachments.size();
|
|
depthRef.layout = m_format.depth.layout;
|
|
|
|
attachments.push_back(desc);
|
|
}
|
|
|
|
VkSubpassDescription subpass;
|
|
subpass.flags = 0;
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
subpass.inputAttachmentCount = 0;
|
|
subpass.pInputAttachments = nullptr;
|
|
subpass.colorAttachmentCount = colorRef.size();
|
|
subpass.pColorAttachments = colorRef.data();
|
|
subpass.pResolveAttachments = nullptr;
|
|
subpass.pDepthStencilAttachment = &depthRef;
|
|
subpass.preserveAttachmentCount = 0;
|
|
subpass.pPreserveAttachments = nullptr;
|
|
|
|
if (m_format.depth.format == VK_FORMAT_UNDEFINED)
|
|
subpass.pDepthStencilAttachment = nullptr;
|
|
|
|
const std::array<VkSubpassDependency, 2> subpassDeps = {{
|
|
{ VK_SUBPASS_EXTERNAL, 0,
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT |
|
|
VK_ACCESS_SHADER_WRITE_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_TRANSFER_READ_BIT |
|
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT |
|
|
VK_ACCESS_SHADER_WRITE_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, 0 },
|
|
{ 0, VK_SUBPASS_EXTERNAL,
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
|
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT |
|
|
VK_ACCESS_SHADER_WRITE_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
VK_ACCESS_SHADER_READ_BIT |
|
|
VK_ACCESS_SHADER_WRITE_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_TRANSFER_READ_BIT |
|
|
VK_ACCESS_TRANSFER_WRITE_BIT, 0 },
|
|
}};
|
|
|
|
VkRenderPassCreateInfo info;
|
|
info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
info.pNext = nullptr;
|
|
info.flags = 0;
|
|
info.attachmentCount = attachments.size();
|
|
info.pAttachments = attachments.data();
|
|
info.subpassCount = 1;
|
|
info.pSubpasses = &subpass;
|
|
info.dependencyCount = subpassDeps.size();
|
|
info.pDependencies = subpassDeps.data();
|
|
|
|
VkRenderPass renderPass = VK_NULL_HANDLE;
|
|
|
|
if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &renderPass) != VK_SUCCESS) {
|
|
Logger::err("DxvkRenderPass: Failed to create render pass object");
|
|
return VK_NULL_HANDLE;
|
|
}
|
|
|
|
return renderPass;
|
|
}
|
|
|
|
|
|
bool DxvkRenderPass::compareOps(
|
|
const DxvkRenderPassOps& a,
|
|
const DxvkRenderPassOps& b) {
|
|
bool eq = a.depthOps.loadOpD == b.depthOps.loadOpD
|
|
&& a.depthOps.loadOpS == b.depthOps.loadOpS
|
|
&& a.depthOps.loadLayout == b.depthOps.loadLayout
|
|
&& a.depthOps.storeOpD == b.depthOps.storeOpD
|
|
&& a.depthOps.storeOpS == b.depthOps.storeOpS
|
|
&& a.depthOps.storeLayout == b.depthOps.storeLayout;
|
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) {
|
|
eq &= a.colorOps[i].loadOp == b.colorOps[i].loadOp
|
|
&& a.colorOps[i].loadLayout == b.colorOps[i].loadLayout
|
|
&& a.colorOps[i].storeOp == b.colorOps[i].storeOp
|
|
&& a.colorOps[i].storeLayout == b.colorOps[i].storeLayout;
|
|
}
|
|
|
|
return eq;
|
|
}
|
|
|
|
|
|
DxvkRenderPassPool::DxvkRenderPassPool(const Rc<vk::DeviceFn>& vkd)
|
|
: m_vkd(vkd) {
|
|
|
|
}
|
|
|
|
|
|
DxvkRenderPassPool::~DxvkRenderPassPool() {
|
|
|
|
}
|
|
|
|
|
|
Rc<DxvkRenderPass> DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) {
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
for (const auto& r : m_renderPasses) {
|
|
if (r->hasCompatibleFormat(fmt))
|
|
return r;
|
|
}
|
|
|
|
Rc<DxvkRenderPass> rp = new DxvkRenderPass(m_vkd, fmt);
|
|
m_renderPasses.push_back(rp);
|
|
return rp;
|
|
}
|
|
|
|
} |