mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
Apparently we need those to make sure that the initial layout transition itself is valid. We don't need to add shader access though, since we cannot access attachments inside shaders.
217 lines
7.4 KiB
C++
217 lines
7.4 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_ALL_GRAPHICS_BIT,
|
|
0,
|
|
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_ALL_GRAPHICS_BIT,
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
|
VK_ACCESS_SHADER_WRITE_BIT,
|
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
|
VK_ACCESS_HOST_READ_BIT |
|
|
VK_ACCESS_INDEX_READ_BIT |
|
|
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
|
|
VK_ACCESS_SHADER_READ_BIT |
|
|
VK_ACCESS_TRANSFER_READ_BIT |
|
|
VK_ACCESS_UNIFORM_READ_BIT |
|
|
VK_ACCESS_VERTEX_ATTRIBUTE_READ_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;
|
|
}
|
|
|
|
} |