2018-02-06 17:31:23 +01:00
|
|
|
#include <algorithm>
|
|
|
|
|
2019-07-30 19:08:32 +02:00
|
|
|
#include "dxvk_device.h"
|
2017-10-10 23:32:13 +02:00
|
|
|
#include "dxvk_renderpass.h"
|
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
2019-07-30 13:04:13 +02:00
|
|
|
bool DxvkRenderPassFormat::eq(const DxvkRenderPassFormat& fmt) const {
|
2018-05-03 19:33:41 +02:00
|
|
|
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;
|
|
|
|
}
|
2019-07-30 13:04:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
size_t DxvkRenderPassFormat::hash() const {
|
|
|
|
DxvkHashState state;
|
|
|
|
state.add(uint32_t(sampleCount));
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
|
|
|
state.add(uint32_t(color[i].format));
|
|
|
|
state.add(uint32_t(color[i].layout));
|
|
|
|
}
|
|
|
|
|
|
|
|
state.add(uint32_t(depth.format));
|
|
|
|
state.add(uint32_t(depth.layout));
|
|
|
|
return state;
|
|
|
|
}
|
2018-05-03 19:33:41 +02:00
|
|
|
|
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-03 19:33:41 +02:00
|
|
|
bool DxvkRenderPass::hasCompatibleFormat(const DxvkRenderPassFormat& fmt) const {
|
2019-07-30 13:04:13 +02:00
|
|
|
return m_format.eq(fmt);
|
2018-04-30 13:12:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2018-02-06 17:31:23 +01:00
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
VkRenderPass handle = this->createRenderPass(ops);
|
|
|
|
m_instances.push_back({ ops, handle });
|
|
|
|
return handle;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
VkRenderPass DxvkRenderPass::createRenderPass(const DxvkRenderPassOps& ops) {
|
2017-10-10 23:32:13 +02:00
|
|
|
std::vector<VkAttachmentDescription> attachments;
|
|
|
|
|
2017-11-20 15:35:29 +01:00
|
|
|
VkAttachmentReference depthRef;
|
2017-10-14 13:37:40 +02:00
|
|
|
std::array<VkAttachmentReference, MaxNumRenderTargets> colorRef;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
// Render passes may not require the previous
|
|
|
|
// contents of the attachments to be preserved.
|
2017-10-14 13:37:40 +02:00
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
2018-04-30 13:12:28 +02:00
|
|
|
if (m_format.color[i].format != VK_FORMAT_UNDEFINED) {
|
2017-10-10 23:32:13 +02:00
|
|
|
VkAttachmentDescription desc;
|
2017-12-05 13:00:06 +01:00
|
|
|
desc.flags = 0;
|
2018-04-30 13:12:28 +02:00
|
|
|
desc.format = m_format.color[i].format;
|
|
|
|
desc.samples = m_format.sampleCount;
|
|
|
|
desc.loadOp = ops.colorOps[i].loadOp;
|
2020-05-01 22:05:07 +02:00
|
|
|
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
2017-12-05 13:00:06 +01:00
|
|
|
desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
|
|
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
2018-04-30 13:12:28 +02:00
|
|
|
desc.initialLayout = ops.colorOps[i].loadLayout;
|
|
|
|
desc.finalLayout = ops.colorOps[i].storeLayout;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2017-12-20 12:13:08 +01:00
|
|
|
colorRef[i].attachment = attachments.size();
|
2018-04-30 13:12:28 +02:00
|
|
|
colorRef[i].layout = m_format.color[i].layout;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
attachments.push_back(desc);
|
2019-10-26 23:37:46 +02:00
|
|
|
} else {
|
|
|
|
colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
|
|
|
|
colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
if (m_format.depth.format != VK_FORMAT_UNDEFINED) {
|
|
|
|
VkAttachmentDescription desc;
|
|
|
|
desc.flags = 0;
|
|
|
|
desc.format = m_format.depth.format;
|
|
|
|
desc.samples = m_format.sampleCount;
|
2018-04-30 21:42:16 +02:00
|
|
|
desc.loadOp = ops.depthOps.loadOpD;
|
2020-05-01 22:05:07 +02:00
|
|
|
desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
2018-04-30 21:42:16 +02:00
|
|
|
desc.stencilLoadOp = ops.depthOps.loadOpS;
|
2020-05-01 22:05:07 +02:00
|
|
|
desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
2018-04-30 13:12:28 +02:00
|
|
|
desc.initialLayout = ops.depthOps.loadLayout;
|
|
|
|
desc.finalLayout = ops.depthOps.storeLayout;
|
|
|
|
|
|
|
|
depthRef.attachment = attachments.size();
|
|
|
|
depthRef.layout = m_format.depth.layout;
|
|
|
|
|
|
|
|
attachments.push_back(desc);
|
2019-10-26 23:37:46 +02:00
|
|
|
} else {
|
|
|
|
depthRef.attachment = VK_ATTACHMENT_UNUSED;
|
|
|
|
depthRef.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
2018-04-30 13:12:28 +02:00
|
|
|
}
|
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
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;
|
2018-04-30 13:12:28 +02:00
|
|
|
subpass.pDepthStencilAttachment = &depthRef;
|
2017-10-10 23:32:13 +02:00
|
|
|
subpass.preserveAttachmentCount = 0;
|
|
|
|
subpass.pPreserveAttachments = nullptr;
|
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
if (m_format.depth.format == VK_FORMAT_UNDEFINED)
|
|
|
|
subpass.pDepthStencilAttachment = nullptr;
|
|
|
|
|
2020-05-01 21:10:31 +02:00
|
|
|
std::array<VkSubpassDependency, 4> subpassDeps;
|
2019-01-22 15:44:19 +01:00
|
|
|
uint32_t subpassDepCount = 0;
|
|
|
|
|
2020-05-01 21:10:31 +02:00
|
|
|
VkPipelineStageFlags renderStages = 0;
|
|
|
|
VkAccessFlags renderAccess = 0;
|
|
|
|
|
|
|
|
if (m_format.depth.format) {
|
|
|
|
renderStages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
|
|
|
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
|
|
|
|
|
|
|
VkImageAspectFlags loadAspects = 0;
|
|
|
|
|
|
|
|
if (ops.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
|
|
loadAspects = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
if (ops.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
|
|
loadAspects = VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
|
|
|
|
|
|
if (loadAspects & imageFormatInfo(m_format.depth.format)->aspectMask)
|
|
|
|
renderAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
|
|
|
|
|
|
|
if (m_format.depth.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)
|
|
|
|
renderAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
|
|
|
if (!m_format.color[i].format)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
renderStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
|
renderAccess |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
|
|
|
|
|
|
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
|
|
|
|
renderAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (renderStages) {
|
|
|
|
subpassDeps[subpassDepCount++] = {
|
|
|
|
VK_SUBPASS_EXTERNAL, 0,
|
|
|
|
renderStages, renderStages,
|
|
|
|
0, renderAccess };
|
|
|
|
}
|
|
|
|
|
2019-01-22 15:44:19 +01:00
|
|
|
if (ops.barrier.srcStages & (
|
|
|
|
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT |
|
|
|
|
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT |
|
|
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
|
|
|
|
subpassDeps[subpassDepCount++] = { 0, 0,
|
2018-09-13 10:43:30 +02:00
|
|
|
VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
|
|
|
|
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, /* XXX */
|
2018-10-30 14:11:27 +01:00
|
|
|
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
|
2019-01-22 15:44:19 +01:00
|
|
|
VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, 0 };
|
|
|
|
}
|
|
|
|
|
2019-10-13 02:00:10 +02:00
|
|
|
if (ops.barrier.srcStages & (
|
|
|
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
|
|
|
|
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT |
|
|
|
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
|
|
|
|
subpassDeps[subpassDepCount++] = { 0, 0,
|
|
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
|
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
|
|
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
|
|
VK_ACCESS_SHADER_READ_BIT,
|
|
|
|
VK_DEPENDENCY_BY_REGION_BIT };
|
|
|
|
}
|
|
|
|
|
2019-01-22 15:44:19 +01:00
|
|
|
if (ops.barrier.srcStages && ops.barrier.dstStages) {
|
|
|
|
subpassDeps[subpassDepCount++] = {
|
|
|
|
0, VK_SUBPASS_EXTERNAL,
|
|
|
|
ops.barrier.srcStages,
|
|
|
|
ops.barrier.dstStages,
|
|
|
|
ops.barrier.srcAccess,
|
|
|
|
ops.barrier.dstAccess, 0 };
|
|
|
|
}
|
2018-01-22 19:21:46 +01:00
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
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;
|
2019-01-22 15:44:19 +01:00
|
|
|
info.dependencyCount = subpassDepCount;
|
|
|
|
info.pDependencies = subpassDepCount ? subpassDeps.data() : nullptr;
|
2017-10-10 23:32:13 +02:00
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
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;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-30 13:12:28 +02:00
|
|
|
bool DxvkRenderPass::compareOps(
|
|
|
|
const DxvkRenderPassOps& a,
|
|
|
|
const DxvkRenderPassOps& b) {
|
2019-01-22 15:44:19 +01:00
|
|
|
bool eq = a.barrier.srcStages == b.barrier.srcStages
|
|
|
|
&& a.barrier.srcAccess == b.barrier.srcAccess
|
|
|
|
&& a.barrier.dstStages == b.barrier.dstStages
|
|
|
|
&& a.barrier.dstAccess == b.barrier.dstAccess;
|
|
|
|
|
|
|
|
if (eq) {
|
|
|
|
eq &= a.depthOps.loadOpD == b.depthOps.loadOpD
|
|
|
|
&& a.depthOps.loadOpS == b.depthOps.loadOpS
|
|
|
|
&& a.depthOps.loadLayout == b.depthOps.loadLayout
|
|
|
|
&& a.depthOps.storeLayout == b.depthOps.storeLayout;
|
|
|
|
}
|
2018-04-30 13:12:28 +02:00
|
|
|
|
|
|
|
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].storeLayout == b.colorOps[i].storeLayout;
|
|
|
|
}
|
|
|
|
|
|
|
|
return eq;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-30 19:08:32 +02:00
|
|
|
DxvkRenderPassPool::DxvkRenderPassPool(const DxvkDevice* device)
|
|
|
|
: m_vkd(device->vkd()) {
|
2017-11-26 14:01:41 +01:00
|
|
|
|
2017-10-11 00:27:33 +02:00
|
|
|
}
|
2017-10-10 23:32:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
DxvkRenderPassPool::~DxvkRenderPassPool() {
|
2017-11-26 14:01:41 +01:00
|
|
|
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-30 13:04:13 +02:00
|
|
|
DxvkRenderPass* DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) {
|
2017-10-10 23:32:13 +02:00
|
|
|
std::lock_guard<std::mutex> lock(m_mutex);
|
2019-07-30 13:04:13 +02:00
|
|
|
|
|
|
|
auto entry = m_renderPasses.find(fmt);
|
|
|
|
if (entry != m_renderPasses.end())
|
|
|
|
return &entry->second;
|
|
|
|
|
|
|
|
auto result = m_renderPasses.emplace(std::piecewise_construct,
|
|
|
|
std::tuple(fmt),
|
|
|
|
std::tuple(m_vkd, fmt));
|
|
|
|
return &result.first->second;
|
2017-10-10 23:32:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|