From fad2e138827849caeece9362e17ad13c8cda9938 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 27 Sep 2018 11:30:39 +0200 Subject: [PATCH] [dxvk] Add meta copy code The current way of copying data between incompatible images is slow and does not work for multisampled images. This new code implements a render pass which performs an exact copy of the source data. --- src/dxvk/dxvk_meta_copy.cpp | 560 ++++++++++++++++++++++++++++++++++++ src/dxvk/dxvk_meta_copy.h | 182 ++++++++++++ src/dxvk/meson.build | 8 + 3 files changed, 750 insertions(+) create mode 100644 src/dxvk/dxvk_meta_copy.cpp create mode 100644 src/dxvk/dxvk_meta_copy.h diff --git a/src/dxvk/dxvk_meta_copy.cpp b/src/dxvk/dxvk_meta_copy.cpp new file mode 100644 index 00000000..d3e5a2d9 --- /dev/null +++ b/src/dxvk/dxvk_meta_copy.cpp @@ -0,0 +1,560 @@ +#include "dxvk_meta_copy.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace dxvk { + + DxvkMetaCopyRenderPass::DxvkMetaCopyRenderPass( + const Rc& vkd, + const Rc& dstImageView, + const Rc& srcImageView, + bool discardDst) + : m_vkd (vkd), + m_dstImageView(dstImageView), + m_srcImageView(srcImageView), + m_renderPass (createRenderPass(discardDst)), + m_framebuffer (createFramebuffer()) { + + } + + + DxvkMetaCopyRenderPass::~DxvkMetaCopyRenderPass() { + m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_framebuffer, nullptr); + m_vkd->vkDestroyRenderPass (m_vkd->device(), m_renderPass, nullptr); + } + + + VkRenderPass DxvkMetaCopyRenderPass::createRenderPass(bool discard) const { + auto aspect = m_dstImageView->info().aspect; + + std::array subpassDeps = {{ + { VK_SUBPASS_EXTERNAL, 0, + m_dstImageView->imageInfo().stages, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + 0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 0 }, + { 0, VK_SUBPASS_EXTERNAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + m_dstImageView->imageInfo().stages, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + m_dstImageView->imageInfo().access, 0 }, + }}; + + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_dstImageView->info().format; + attachment.samples = m_dstImageView->imageInfo().sampleCount; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = m_dstImageView->imageInfo().layout; + attachment.finalLayout = m_dstImageView->imageInfo().layout; + + if (discard) { + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } + + VkAttachmentReference attachmentRef; + attachmentRef.attachment = 0; + attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) + ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 0; + subpass.pColorAttachments = nullptr; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attachmentRef; + } else { + subpass.pDepthStencilAttachment = &attachmentRef; + } + + VkRenderPassCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.attachmentCount = 1; + info.pAttachments = &attachment; + info.subpassCount = 1; + info.pSubpasses = &subpass; + info.dependencyCount = subpassDeps.size(); + info.pDependencies = subpassDeps.data(); + + VkRenderPass result = VK_NULL_HANDLE; + if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyRenderPass: Failed to create render pass"); + return result; + } + + + VkFramebuffer DxvkMetaCopyRenderPass::createFramebuffer() const { + VkImageView dstViewHandle = m_dstImageView->handle(); + VkImageSubresourceRange dstSubresources = m_dstImageView->subresources(); + VkExtent3D dstExtent = m_dstImageView->mipLevelExtent(0); + + VkFramebufferCreateInfo fboInfo; + fboInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fboInfo.pNext = nullptr; + fboInfo.flags = 0; + fboInfo.renderPass = m_renderPass; + fboInfo.attachmentCount = 1; + fboInfo.pAttachments = &dstViewHandle; + fboInfo.width = dstExtent.width; + fboInfo.height = dstExtent.height; + fboInfo.layers = dstSubresources.layerCount; + + VkFramebuffer result = VK_NULL_HANDLE; + if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &fboInfo, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaMipGenRenderPass: Failed to create target framebuffer"); + return result; + } + + + DxvkMetaCopyObjects::DxvkMetaCopyObjects(const Rc& vkd) + : m_vkd (vkd), + m_sampler (createSampler()), + m_shaderVert (createShaderModule(dxvk_resolve_vert)), + m_shaderGeom (createShaderModule(dxvk_resolve_geom)), + m_color { + createShaderModule(dxvk_copy_color_1d), + createShaderModule(dxvk_copy_color_2d), + createShaderModule(dxvk_copy_color_ms) }, + m_depth { + createShaderModule(dxvk_copy_depth_1d), + createShaderModule(dxvk_copy_depth_2d), + createShaderModule(dxvk_copy_depth_ms) } { + + } + + + DxvkMetaCopyObjects::~DxvkMetaCopyObjects() { + for (const auto& pair : m_pipelines) { + m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr); + m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr); + m_vkd->vkDestroyDescriptorSetLayout (m_vkd->device(), pair.second.dsetLayout, nullptr); + m_vkd->vkDestroyRenderPass(m_vkd->device(), pair.second.renderPass, nullptr); + } + + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.fragMs, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag2D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag1D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.fragMs, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag2D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag1D, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderGeom, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderVert, nullptr); + + m_vkd->vkDestroySampler(m_vkd->device(), m_sampler, nullptr); + } + + + VkFormat DxvkMetaCopyObjects::getCopyDestinationFormat( + VkImageAspectFlags dstAspect, + VkImageAspectFlags srcAspect, + VkFormat srcFormat) const { + if (srcAspect == dstAspect) + return srcFormat; + + if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT + && srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) { + switch (srcFormat) { + case VK_FORMAT_D16_UNORM: return VK_FORMAT_R16_UNORM; + case VK_FORMAT_D32_SFLOAT: return VK_FORMAT_R32_SFLOAT; + default: return VK_FORMAT_UNDEFINED; + } + } + + if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT + && srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) { + switch (srcFormat) { + case VK_FORMAT_R16_UNORM: return VK_FORMAT_D16_UNORM; + case VK_FORMAT_R32_SFLOAT: return VK_FORMAT_D32_SFLOAT; + default: return VK_FORMAT_UNDEFINED; + } + } + + return VK_FORMAT_UNDEFINED; + } + + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::getPipeline( + VkImageViewType viewType, + VkFormat dstFormat, + VkSampleCountFlagBits dstSamples) { + std::lock_guard lock(m_mutex); + + DxvkMetaCopyPipelineKey key; + key.viewType = viewType; + key.format = dstFormat; + key.samples = dstSamples; + + auto entry = m_pipelines.find(key); + if (entry != m_pipelines.end()) + return entry->second; + + DxvkMetaCopyPipeline pipeline = createPipeline(key); + m_pipelines.insert({ key, pipeline }); + return pipeline; + } + + + VkSampler DxvkMetaCopyObjects::createSampler() const { + VkSamplerCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.magFilter = VK_FILTER_NEAREST; + info.minFilter = VK_FILTER_NEAREST; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.mipLodBias = 0.0f; + info.anisotropyEnable = VK_FALSE; + info.maxAnisotropy = 1.0f; + info.compareEnable = VK_FALSE; + info.compareOp = VK_COMPARE_OP_ALWAYS; + info.minLod = 0.0f; + info.maxLod = 0.0f; + info.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + info.unnormalizedCoordinates = VK_FALSE; + + VkSampler result = VK_NULL_HANDLE; + if (m_vkd->vkCreateSampler(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create sampler"); + return result; + } + + + VkShaderModule DxvkMetaCopyObjects::createShaderModule( + const SpirvCodeBuffer& code) const { + VkShaderModuleCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.codeSize = code.size(); + info.pCode = code.data(); + + VkShaderModule result = VK_NULL_HANDLE; + if (m_vkd->vkCreateShaderModule(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create shader module"); + return result; + } + + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::createPipeline( + const DxvkMetaCopyPipelineKey& key) { + DxvkMetaCopyPipeline pipeline; + pipeline.renderPass = this->createRenderPass(key); + pipeline.dsetLayout = this->createDescriptorSetLayout(); + pipeline.pipeLayout = this->createPipelineLayout(pipeline.dsetLayout); + pipeline.pipeHandle = this->createPipelineObject(key, pipeline.pipeLayout, pipeline.renderPass); + return pipeline; + } + + + VkRenderPass DxvkMetaCopyObjects::createRenderPass( + const DxvkMetaCopyPipelineKey& key) const { + auto aspect = imageFormatInfo(key.format)->aspectMask; + + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = key.format; + attachment.samples = key.samples; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL; + attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL; + + VkAttachmentReference attachmentRef; + attachmentRef.attachment = 0; + attachmentRef.layout = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) + ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL + : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = nullptr; + subpass.colorAttachmentCount = 0; + subpass.pColorAttachments = nullptr; + subpass.pResolveAttachments = nullptr; + subpass.pDepthStencilAttachment = nullptr; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = nullptr; + + if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &attachmentRef; + } else { + subpass.pDepthStencilAttachment = &attachmentRef; + } + + VkRenderPassCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.attachmentCount = 1; + info.pAttachments = &attachment; + info.subpassCount = 1; + info.pSubpasses = &subpass; + info.dependencyCount = 0; + info.pDependencies = nullptr; + + VkRenderPass result = VK_NULL_HANDLE; + if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create render pass"); + return result; + } + + + VkDescriptorSetLayout DxvkMetaCopyObjects::createDescriptorSetLayout() const { + VkDescriptorSetLayoutBinding binding; + binding.binding = 0; + binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding.pImmutableSamplers = &m_sampler; + + VkDescriptorSetLayoutCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.bindingCount = 1; + info.pBindings = &binding; + + VkDescriptorSetLayout result = VK_NULL_HANDLE; + if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout"); + return result; + } + + + VkPipelineLayout DxvkMetaCopyObjects::createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const { + VkPushConstantRange push; + push.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + push.offset = 0; + push.size = sizeof(VkOffset2D); + + VkPipelineLayoutCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.setLayoutCount = 1; + info.pSetLayouts = &descriptorSetLayout; + info.pushConstantRangeCount = 1; + info.pPushConstantRanges = &push; + + VkPipelineLayout result = VK_NULL_HANDLE; + if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create pipeline layout"); + return result; + } + + + VkPipeline DxvkMetaCopyObjects::createPipelineObject( + const DxvkMetaCopyPipelineKey& key, + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass) { + auto aspect = imageFormatInfo(key.format)->aspectMask; + + std::array stages; + + VkPipelineShaderStageCreateInfo& vsStage = stages[0]; + vsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vsStage.pNext = nullptr; + vsStage.flags = 0; + vsStage.stage = VK_SHADER_STAGE_VERTEX_BIT; + vsStage.module = m_shaderVert; + vsStage.pName = "main"; + vsStage.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo& gsStage = stages[1]; + gsStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + gsStage.pNext = nullptr; + gsStage.flags = 0; + gsStage.stage = VK_SHADER_STAGE_GEOMETRY_BIT; + gsStage.module = m_shaderGeom; + gsStage.pName = "main"; + gsStage.pSpecializationInfo = nullptr; + + VkPipelineShaderStageCreateInfo& psStage = stages[2]; + psStage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + psStage.pNext = nullptr; + psStage.flags = 0; + psStage.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + psStage.module = VK_NULL_HANDLE; + psStage.pName = "main"; + psStage.pSpecializationInfo = nullptr; + + auto shaderSet = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? &m_color : &m_depth; + + if (key.viewType == VK_IMAGE_VIEW_TYPE_1D) + psStage.module = shaderSet->frag1D; + else if (key.samples == VK_SAMPLE_COUNT_1_BIT) + psStage.module = shaderSet->frag2D; + else + psStage.module = shaderSet->fragMs; + + std::array dynStates = {{ + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }}; + + VkPipelineDynamicStateCreateInfo dynState; + dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynState.pNext = nullptr; + dynState.flags = 0; + dynState.dynamicStateCount = dynStates.size(); + dynState.pDynamicStates = dynStates.data(); + + VkPipelineVertexInputStateCreateInfo viState; + viState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + viState.pNext = nullptr; + viState.flags = 0; + viState.vertexBindingDescriptionCount = 0; + viState.pVertexBindingDescriptions = nullptr; + viState.vertexAttributeDescriptionCount = 0; + viState.pVertexAttributeDescriptions = nullptr; + + VkPipelineInputAssemblyStateCreateInfo iaState; + iaState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + iaState.pNext = nullptr; + iaState.flags = 0; + iaState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + iaState.primitiveRestartEnable = VK_FALSE; + + VkPipelineViewportStateCreateInfo vpState; + vpState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vpState.pNext = nullptr; + vpState.flags = 0; + vpState.viewportCount = 1; + vpState.pViewports = nullptr; + vpState.scissorCount = 1; + vpState.pScissors = nullptr; + + VkPipelineRasterizationStateCreateInfo rsState; + rsState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rsState.pNext = nullptr; + rsState.flags = 0; + rsState.depthClampEnable = VK_TRUE; + rsState.rasterizerDiscardEnable = VK_FALSE; + rsState.polygonMode = VK_POLYGON_MODE_FILL; + rsState.cullMode = VK_CULL_MODE_NONE; + rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rsState.depthBiasEnable = VK_FALSE; + rsState.depthBiasConstantFactor = 0.0f; + rsState.depthBiasClamp = 0.0f; + rsState.depthBiasSlopeFactor = 0.0f; + rsState.lineWidth = 1.0f; + + uint32_t msMask = 0xFFFFFFFF; + VkPipelineMultisampleStateCreateInfo msState; + msState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + msState.pNext = nullptr; + msState.flags = 0; + msState.rasterizationSamples = key.samples; + msState.sampleShadingEnable = key.samples != VK_SAMPLE_COUNT_1_BIT; + msState.minSampleShading = 1.0f; + msState.pSampleMask = &msMask; + msState.alphaToCoverageEnable = VK_FALSE; + msState.alphaToOneEnable = VK_FALSE; + + VkPipelineColorBlendAttachmentState cbAttachment; + cbAttachment.blendEnable = VK_FALSE; + cbAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + cbAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + cbAttachment.colorBlendOp = VK_BLEND_OP_ADD; + cbAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + cbAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + cbAttachment.alphaBlendOp = VK_BLEND_OP_ADD; + cbAttachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo cbState; + cbState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + cbState.pNext = nullptr; + cbState.flags = 0; + cbState.logicOpEnable = VK_FALSE; + cbState.logicOp = VK_LOGIC_OP_NO_OP; + cbState.attachmentCount = 1; + cbState.pAttachments = &cbAttachment; + + for (uint32_t i = 0; i < 4; i++) + cbState.blendConstants[i] = 0.0f; + + VkStencilOpState stencilOp; + stencilOp.failOp = VK_STENCIL_OP_KEEP; + stencilOp.passOp = VK_STENCIL_OP_KEEP; + stencilOp.depthFailOp = VK_STENCIL_OP_KEEP; + stencilOp.compareOp = VK_COMPARE_OP_ALWAYS; + stencilOp.compareMask = 0xFFFFFFFF; + stencilOp.writeMask = 0xFFFFFFFF; + stencilOp.compareMask = 0; + + VkPipelineDepthStencilStateCreateInfo dsState; + dsState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + dsState.pNext = nullptr; + dsState.flags = 0; + dsState.depthTestEnable = VK_TRUE; + dsState.depthWriteEnable = VK_TRUE; + dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS; + dsState.depthBoundsTestEnable = VK_FALSE; + dsState.stencilTestEnable = VK_FALSE; + dsState.front = stencilOp; + dsState.back = stencilOp; + dsState.minDepthBounds = 0.0f; + dsState.maxDepthBounds = 1.0f; + + VkGraphicsPipelineCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.stageCount = stages.size(); + info.pStages = stages.data(); + info.pVertexInputState = &viState; + info.pInputAssemblyState = &iaState; + info.pTessellationState = nullptr; + info.pViewportState = &vpState; + info.pRasterizationState = &rsState; + info.pMultisampleState = &msState; + info.pColorBlendState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? &cbState : nullptr; + info.pDepthStencilState = (aspect & VK_IMAGE_ASPECT_COLOR_BIT) ? nullptr : &dsState; + info.pDynamicState = &dynState; + info.layout = pipelineLayout; + info.renderPass = renderPass; + info.subpass = 0; + info.basePipelineHandle = VK_NULL_HANDLE; + info.basePipelineIndex = -1; + + VkPipeline result = VK_NULL_HANDLE; + if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), VK_NULL_HANDLE, 1, &info, nullptr, &result) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create graphics pipeline"); + return result; + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_meta_copy.h b/src/dxvk/dxvk_meta_copy.h new file mode 100644 index 00000000..de67bcab --- /dev/null +++ b/src/dxvk/dxvk_meta_copy.h @@ -0,0 +1,182 @@ +#pragma once + +#include +#include + +#include "../spirv/spirv_code_buffer.h" + +#include "dxvk_barrier.h" +#include "dxvk_cmdlist.h" +#include "dxvk_hash.h" +#include "dxvk_resource.h" + +namespace dxvk { + + /** + * \brief Copy pipeline + * + * Stores the objects for a single pipeline + * that is used for fragment shader copies. + */ + struct DxvkMetaCopyPipeline { + VkRenderPass renderPass; + VkDescriptorSetLayout dsetLayout; + VkPipelineLayout pipeLayout; + VkPipeline pipeHandle; + }; + + /** + * \brief Copy pipeline key + * + * Used to look up copy pipelines based + * on the copy operation they support. + */ + struct DxvkMetaCopyPipelineKey { + VkImageViewType viewType; + VkFormat format; + VkSampleCountFlagBits samples; + + bool eq(const DxvkMetaCopyPipelineKey& other) const { + return this->viewType == other.viewType + && this->format == other.format + && this->samples == other.samples; + } + + size_t hash() const { + return (uint32_t(format) << 8) + ^ (uint32_t(samples) << 4) + ^ (uint32_t(viewType)); + } + }; + + /** + * \brief Copy framebuffer and render pass + * + * Creates a framebuffer and render + * pass object for an image view. + */ + class DxvkMetaCopyRenderPass : public DxvkResource { + + public: + + DxvkMetaCopyRenderPass( + const Rc& vkd, + const Rc& dstImageView, + const Rc& srcImageView, + bool discardDst); + + ~DxvkMetaCopyRenderPass(); + + VkRenderPass renderPass() const { + return m_renderPass; + } + + VkFramebuffer framebuffer() const { + return m_framebuffer; + } + + private: + + const Rc m_vkd; + + const Rc m_dstImageView; + const Rc m_srcImageView; + + VkRenderPass m_renderPass = VK_NULL_HANDLE; + VkFramebuffer m_framebuffer = VK_NULL_HANDLE; + + VkRenderPass createRenderPass(bool discard) const; + + VkFramebuffer createFramebuffer() const; + + }; + + /** + * \brief Meta copy objects + * + * Meta copy operations are necessary in order + * to copy data between color and depth images. + */ + class DxvkMetaCopyObjects : public RcObject { + + public: + + DxvkMetaCopyObjects(const Rc& vkd); + ~DxvkMetaCopyObjects(); + + /** + * \brief Queries color format for d->c copies + * + * Returns the color format that we need to use + * as the destination image view format in case + * of depth to color image copies. + * \param [in] format Depth format + * \returns Corresponding color format + */ + VkFormat getCopyDestinationFormat( + VkImageAspectFlags dstAspect, + VkImageAspectFlags srcAspect, + VkFormat srcFormat) const; + + /** + * \brief Creates pipeline for meta copy operation + * + * \param [in] viewType Image view type + * \param [in] dstFormat Destination image format + * \param [in] dstSamples Destination sample count + * \returns Compatible pipeline for the operation + */ + DxvkMetaCopyPipeline getPipeline( + VkImageViewType viewType, + VkFormat dstFormat, + VkSampleCountFlagBits dstSamples); + + private: + + struct FragShaders { + VkShaderModule frag1D; + VkShaderModule frag2D; + VkShaderModule fragMs; + }; + + Rc m_vkd; + + VkSampler m_sampler; + + VkShaderModule m_shaderVert; + VkShaderModule m_shaderGeom; + + FragShaders m_color; + FragShaders m_depth; + + std::mutex m_mutex; + + std::unordered_map< + DxvkMetaCopyPipelineKey, + DxvkMetaCopyPipeline, + DxvkHash, DxvkEq> m_pipelines; + + VkSampler createSampler() const; + + VkShaderModule createShaderModule( + const SpirvCodeBuffer& code) const; + + DxvkMetaCopyPipeline createPipeline( + const DxvkMetaCopyPipelineKey& key); + + VkRenderPass createRenderPass( + const DxvkMetaCopyPipelineKey& key) const; + + VkDescriptorSetLayout createDescriptorSetLayout() const; + + VkPipelineLayout createPipelineLayout( + VkDescriptorSetLayout descriptorSetLayout) const; + + VkPipeline createPipelineObject( + const DxvkMetaCopyPipelineKey& key, + VkPipelineLayout pipelineLayout, + VkRenderPass renderPass); + + }; + +} \ No newline at end of file diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index c64f1d87..0dc911ac 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -12,6 +12,13 @@ dxvk_shaders = files([ 'shaders/dxvk_clear_image3d_u.comp', 'shaders/dxvk_clear_image3d_f.comp', + 'shaders/dxvk_copy_color_1d.frag', + 'shaders/dxvk_copy_color_2d.frag', + 'shaders/dxvk_copy_color_ms.frag', + 'shaders/dxvk_copy_depth_1d.frag', + 'shaders/dxvk_copy_depth_2d.frag', + 'shaders/dxvk_copy_depth_ms.frag', + 'shaders/dxvk_mipgen_vert.vert', 'shaders/dxvk_mipgen_geom.geom', 'shaders/dxvk_mipgen_frag_1d.frag', @@ -54,6 +61,7 @@ dxvk_src = files([ 'dxvk_main.cpp', 'dxvk_memory.cpp', 'dxvk_meta_clear.cpp', + 'dxvk_meta_copy.cpp', 'dxvk_meta_mipgen.cpp', 'dxvk_meta_resolve.cpp', 'dxvk_openvr.cpp',