From 2fac69b7f928d4f3793fab64d5e066d854cea136 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 5 Oct 2024 14:27:09 +0200 Subject: [PATCH] [dxvk] Add pipelines for buffer-to-image and image-to-buffer copies --- src/dxvk/dxvk_meta_copy.cpp | 357 +++++++++++++++++++++++++++++++++++- src/dxvk/dxvk_meta_copy.h | 100 +++++++++- 2 files changed, 451 insertions(+), 6 deletions(-) diff --git a/src/dxvk/dxvk_meta_copy.cpp b/src/dxvk/dxvk_meta_copy.cpp index f11019f2..79e23825 100644 --- a/src/dxvk/dxvk_meta_copy.cpp +++ b/src/dxvk/dxvk_meta_copy.cpp @@ -5,6 +5,13 @@ #include #include +#include +#include +#include + +#include +#include + #include #include #include @@ -88,14 +95,41 @@ namespace dxvk { createShaderModule(dxvk_copy_depth_stencil_1d), createShaderModule(dxvk_copy_depth_stencil_2d), createShaderModule(dxvk_copy_depth_stencil_ms) }; + + m_shaderBufferToImageDSExport = createShaderModule(dxvk_buffer_to_image_ds_export); + } else { + m_shaderBufferToImageD = createShaderModule(dxvk_buffer_to_image_d); + m_shaderBufferToImageS = createShaderModule(dxvk_buffer_to_image_s_discard); } + + m_shaderImageToBufferDS = createShaderModule(dxvk_image_to_buffer_ds); + m_shaderImageToBufferF = createShaderModule(dxvk_image_to_buffer_f); } DxvkMetaCopyObjects::~DxvkMetaCopyObjects() { + for (const auto& p : m_bufferToImagePipelines) + m_vkd->vkDestroyPipeline(m_vkd->device(), p.second, nullptr); + + for (const auto& p : m_imageToBufferPipelines) + m_vkd->vkDestroyPipeline(m_vkd->device(), p.second, nullptr); + + m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_bufferToImageCopySetLayout, nullptr); + m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_imageToBufferCopySetLayout, nullptr); + + m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_bufferToImageCopyPipelineLayout, nullptr); + m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_imageToBufferCopyPipelineLayout, nullptr); + + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderBufferToImageD, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderBufferToImageS, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderBufferToImageDSExport, nullptr); + + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderImageToBufferF, nullptr); + m_vkd->vkDestroyShaderModule(m_vkd->device(), m_shaderImageToBufferDS, nullptr); + + m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_copyBufferImagePipeline.dsetLayout, nullptr); m_vkd->vkDestroyPipeline(m_vkd->device(), m_copyBufferImagePipeline.pipeHandle, nullptr); m_vkd->vkDestroyPipelineLayout(m_vkd->device(), m_copyBufferImagePipeline.pipeLayout, nullptr); - m_vkd->vkDestroyDescriptorSetLayout(m_vkd->device(), m_copyBufferImagePipeline.dsetLayout, nullptr); for (const auto& pair : m_pipelines) { m_vkd->vkDestroyPipeline(m_vkd->device(), pair.second.pipeHandle, nullptr); @@ -140,6 +174,70 @@ namespace dxvk { } + DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyBufferToImagePipeline( + VkImageViewType viewType, + VkFormat dstFormat, + VkFormat srcFormat, + VkImageAspectFlags aspects) { + std::lock_guard lock(m_mutex); + + DxvkMetaBufferImageCopyPipelineKey key; + key.imageViewType = viewType; + key.imageFormat = dstFormat; + key.bufferFormat = srcFormat; + key.imageAspects = aspects; + + auto entry = m_bufferToImagePipelines.find(key); + if (entry != m_bufferToImagePipelines.end()) { + DxvkMetaCopyPipeline result = { }; + result.dsetLayout = m_bufferToImageCopySetLayout; + result.pipeLayout = m_bufferToImageCopyPipelineLayout; + result.pipeHandle = entry->second; + return result; + } + + VkPipeline pipeline = createCopyBufferToImagePipeline(key); + m_bufferToImagePipelines.insert({ key, pipeline }); + + DxvkMetaCopyPipeline result = { }; + result.dsetLayout = m_bufferToImageCopySetLayout; + result.pipeLayout = m_bufferToImageCopyPipelineLayout; + result.pipeHandle = pipeline; + return result; + } + + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyImageToBufferPipeline( + VkImageViewType viewType, + VkFormat dstFormat) { + std::lock_guard lock(m_mutex); + + DxvkMetaBufferImageCopyPipelineKey key; + key.imageViewType = viewType; + key.imageFormat = VK_FORMAT_UNDEFINED; + key.bufferFormat = dstFormat; + key.imageAspects = lookupFormatInfo(dstFormat)->aspectMask; + + auto entry = m_bufferToImagePipelines.find(key); + if (entry != m_bufferToImagePipelines.end()) { + DxvkMetaCopyPipeline result = { }; + result.dsetLayout = m_imageToBufferCopySetLayout; + result.pipeLayout = m_imageToBufferCopyPipelineLayout; + result.pipeHandle = entry->second; + return result; + } + + VkPipeline pipeline = createCopyImageToBufferPipeline(key); + m_bufferToImagePipelines.insert({ key, pipeline }); + + DxvkMetaCopyPipeline result = { }; + result.dsetLayout = m_imageToBufferCopySetLayout; + result.pipeLayout = m_imageToBufferCopyPipelineLayout; + result.pipeHandle = pipeline; + return result; + } + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyImagePipeline( VkImageViewType viewType, VkFormat dstFormat, @@ -239,6 +337,263 @@ namespace dxvk { } + VkPipeline DxvkMetaCopyObjects::createCopyBufferToImagePipeline( + const DxvkMetaBufferImageCopyPipelineKey& key) { + if (!m_bufferToImageCopySetLayout) { + std::array bindings = {{ + { 0, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT } + }}; + + VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + info.bindingCount = bindings.size(); + info.pBindings = bindings.data(); + + VkResult vr = m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), + &info, nullptr, &m_bufferToImageCopySetLayout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create descriptor set layout: ", vr)); + } + + if (!m_bufferToImageCopyPipelineLayout) { + VkPushConstantRange pushConstants = { }; + pushConstants.offset = 0; + pushConstants.size = sizeof(DxvkBufferImageCopyArgs); + pushConstants.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + info.setLayoutCount = 1; + info.pSetLayouts = &m_bufferToImageCopySetLayout; + info.pushConstantRangeCount = 1; + info.pPushConstantRanges = &pushConstants; + + VkResult vr = m_vkd->vkCreatePipelineLayout(m_vkd->device(), + &info, nullptr, &m_bufferToImageCopyPipelineLayout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create pipeline layout: ", vr)); + } + + std::array stages = { }; + uint32_t stageCount = 0; + + stages[stageCount++] = VkPipelineShaderStageCreateInfo { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_VERTEX_BIT, m_shaderVert, "main" }; + + if (m_shaderGeom) { + stages[stageCount++] = VkPipelineShaderStageCreateInfo { + VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, nullptr, 0, + VK_SHADER_STAGE_GEOMETRY_BIT, m_shaderGeom, "main" }; + } + + // We don't support color right now + if (!(key.imageAspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) { + Logger::err(str::format("DxvkMetaCopyObjects: Color images not unsupported")); + return VK_NULL_HANDLE; + } + + VkSpecializationMapEntry specMap = { }; + specMap.size = sizeof(VkFormat); + + VkSpecializationInfo specInfo = { }; + specInfo.mapEntryCount = 1; + specInfo.pMapEntries = &specMap; + specInfo.dataSize = sizeof(VkFormat); + specInfo.pData = &key.bufferFormat; + + // Always use the DS export shader if possible, it can + // support writing to one aspect exclusively. + auto& stage = stages[stageCount++]; + stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + stage.module = m_shaderBufferToImageDSExport; + stage.pName = "main"; + stage.pSpecializationInfo = &specInfo; + + if (!m_shaderBufferToImageDSExport) { + stage.module = key.imageAspects == VK_IMAGE_ASPECT_STENCIL_BIT + ? m_shaderBufferToImageS + : m_shaderBufferToImageD; + } + + std::array dynStates = {{ + VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT, + VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + }}; + + VkPipelineDynamicStateCreateInfo dynState = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; + dynState.dynamicStateCount = dynStates.size(); + dynState.pDynamicStates = dynStates.data(); + + if (stage.module != m_shaderBufferToImageS) + dynState.dynamicStateCount -= 1; + + VkPipelineVertexInputStateCreateInfo viState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + + VkPipelineInputAssemblyStateCreateInfo iaState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + iaState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo vpState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; + + VkPipelineRasterizationStateCreateInfo rsState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; + rsState.depthClampEnable = VK_TRUE; + rsState.polygonMode = VK_POLYGON_MODE_FILL; + rsState.cullMode = VK_CULL_MODE_NONE; + rsState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rsState.lineWidth = 1.0f; + + uint32_t msMask = 0x1; + VkPipelineMultisampleStateCreateInfo msState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; + msState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + msState.pSampleMask = &msMask; + + VkPipelineColorBlendAttachmentState cbAttachment = { }; + cbAttachment.colorWriteMask = + VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo cbState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; + cbState.attachmentCount = 1; + cbState.pAttachments = &cbAttachment; + + VkStencilOpState stencilOp = { }; + stencilOp.failOp = VK_STENCIL_OP_REPLACE; + stencilOp.passOp = VK_STENCIL_OP_REPLACE; + stencilOp.depthFailOp = VK_STENCIL_OP_REPLACE; + stencilOp.compareOp = VK_COMPARE_OP_ALWAYS; + stencilOp.compareMask = 0xff; + stencilOp.writeMask = 0xff; + stencilOp.reference = 0xff; + + // Clear stencil for depth-only aspect + if (stage.module == m_shaderBufferToImageD) + stencilOp.reference = 0x00; + + VkPipelineDepthStencilStateCreateInfo dsState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; + dsState.depthTestEnable = !!(key.imageAspects & VK_IMAGE_ASPECT_DEPTH_BIT); + dsState.depthWriteEnable = dsState.depthTestEnable; + dsState.depthCompareOp = VK_COMPARE_OP_ALWAYS; + dsState.stencilTestEnable = !!(key.imageAspects & VK_IMAGE_ASPECT_STENCIL_BIT); + dsState.front = stencilOp; + dsState.back = stencilOp; + + VkPipelineRenderingCreateInfo rtState = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; + + if (key.imageAspects & VK_IMAGE_ASPECT_COLOR_BIT) { + rtState.colorAttachmentCount = 1; + rtState.pColorAttachmentFormats = &key.imageFormat; + } else { + auto formatAspects = lookupFormatInfo(key.imageFormat)->aspectMask; + + if (formatAspects & VK_IMAGE_ASPECT_DEPTH_BIT) + rtState.depthAttachmentFormat = key.imageFormat; + if (formatAspects & VK_IMAGE_ASPECT_STENCIL_BIT) + rtState.stencilAttachmentFormat = key.imageFormat; + } + + VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &rtState }; + info.stageCount = stageCount; + info.pStages = stages.data(); + info.pVertexInputState = &viState; + info.pInputAssemblyState = &iaState; + info.pViewportState = &vpState; + info.pRasterizationState = &rsState; + info.pMultisampleState = &msState; + info.pColorBlendState = (key.imageAspects & VK_IMAGE_ASPECT_COLOR_BIT) ? &cbState : nullptr; + info.pDepthStencilState = (key.imageAspects & VK_IMAGE_ASPECT_COLOR_BIT) ? nullptr : &dsState; + info.pDynamicState = &dynState; + info.layout = m_bufferToImageCopyPipelineLayout; + info.basePipelineIndex = -1; + + VkPipeline pipeline = VK_NULL_HANDLE; + VkResult vr = m_vkd->vkCreateGraphicsPipelines(m_vkd->device(), + VK_NULL_HANDLE, 1, &info, nullptr, &pipeline); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create graphics pipeline: ", vr)); + + return pipeline; + } + + + VkPipeline DxvkMetaCopyObjects::createCopyImageToBufferPipeline( + const DxvkMetaBufferImageCopyPipelineKey& key) { + if (!m_imageToBufferCopySetLayout) { + std::array bindings = {{ + { 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT }, + { 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }, + { 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT }, + }}; + + VkDescriptorSetLayoutCreateInfo info = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO }; + info.bindingCount = bindings.size(); + info.pBindings = bindings.data(); + + VkResult vr = m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), + &info, nullptr, &m_imageToBufferCopySetLayout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create descriptor set layout: ", vr)); + } + + if (!m_imageToBufferCopyPipelineLayout) { + VkPushConstantRange pushConstants = { }; + pushConstants.offset = 0; + pushConstants.size = sizeof(DxvkBufferImageCopyArgs); + pushConstants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + + VkPipelineLayoutCreateInfo info = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; + info.setLayoutCount = 1; + info.pSetLayouts = &m_imageToBufferCopySetLayout; + info.pushConstantRangeCount = 1; + info.pPushConstantRanges = &pushConstants; + + VkResult vr = m_vkd->vkCreatePipelineLayout(m_vkd->device(), + &info, nullptr, &m_imageToBufferCopyPipelineLayout); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create pipeline layout: ", vr)); + } + + if (key.imageViewType != VK_IMAGE_VIEW_TYPE_2D_ARRAY) { + Logger::err(str::format("DxvkMetaCopyObjects: Unsupported view type: ", key.imageViewType)); + return VK_NULL_HANDLE; + } + + VkSpecializationMapEntry specMap = { }; + specMap.size = sizeof(VkFormat); + + VkSpecializationInfo specInfo = { }; + specInfo.mapEntryCount = 1; + specInfo.pMapEntries = &specMap; + specInfo.dataSize = sizeof(VkFormat); + specInfo.pData = &key.bufferFormat; + + VkComputePipelineCreateInfo info = { VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO }; + info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + info.stage.pName = "main"; + info.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + info.stage.pSpecializationInfo = &specInfo; + info.layout = m_imageToBufferCopyPipelineLayout; + info.basePipelineIndex = -1; + + info.stage.module = key.imageAspects & VK_IMAGE_ASPECT_STENCIL_BIT + ? m_shaderImageToBufferDS + : m_shaderImageToBufferF; + + VkPipeline pipeline = VK_NULL_HANDLE; + VkResult vr = m_vkd->vkCreateComputePipelines(m_vkd->device(), + VK_NULL_HANDLE, 1, &info, nullptr, &pipeline); + + if (vr != VK_SUCCESS) + throw DxvkError(str::format("DxvkMetaCopyObjects: Failed to create compute pipeline", vr)); + + return pipeline; + } + + VkDescriptorSetLayout DxvkMetaCopyObjects::createDescriptorSetLayout( const DxvkMetaCopyPipelineKey& key) const { std::array bindings = {{ diff --git a/src/dxvk/dxvk_meta_copy.h b/src/dxvk/dxvk_meta_copy.h index d73e26bc..e9c3b379 100644 --- a/src/dxvk/dxvk_meta_copy.h +++ b/src/dxvk/dxvk_meta_copy.h @@ -15,7 +15,7 @@ namespace dxvk { class DxvkDevice; /** - * \brief Push constants for buffer image copies + * \brief Push constants for formatted buffer copies */ struct DxvkFormattedBufferCopyArgs { VkOffset3D dstOffset; uint32_t pad0; @@ -45,6 +45,19 @@ namespace dxvk { VkPipeline pipeHandle = VK_NULL_HANDLE; }; + + /** + * \brief Push constants for buffer <-> image copies + */ + struct DxvkBufferImageCopyArgs { + VkOffset3D imageOffset; + uint32_t bufferOffset; + VkExtent3D imageExtent; + uint32_t bufferImageWidth; + uint32_t bufferImageHeight; + uint32_t stencilBitIndex; + }; + /** * \brief Copy pipeline key * @@ -52,9 +65,9 @@ namespace dxvk { * on the copy operation they support. */ struct DxvkMetaCopyPipelineKey { - VkImageViewType viewType; - VkFormat format; - VkSampleCountFlagBits samples; + VkImageViewType viewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM; + VkFormat format = VK_FORMAT_UNDEFINED; + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM; bool eq(const DxvkMetaCopyPipelineKey& other) const { return this->viewType == other.viewType @@ -69,6 +82,31 @@ namespace dxvk { } }; + /** + * \brief Buffer to image copy pipeline key + */ + struct DxvkMetaBufferImageCopyPipelineKey { + VkImageViewType imageViewType = VK_IMAGE_VIEW_TYPE_MAX_ENUM; + VkFormat imageFormat = VK_FORMAT_UNDEFINED; + VkFormat bufferFormat = VK_FORMAT_UNDEFINED; + VkImageAspectFlags imageAspects = 0u; + + bool eq(const DxvkMetaBufferImageCopyPipelineKey& other) const { + return this->imageViewType == other.imageViewType + && this->imageFormat == other.imageFormat + && this->imageAspects == other.imageAspects + && this->bufferFormat == other.bufferFormat; + } + + size_t hash() const { + return (uint32_t(imageViewType)) + ^ (uint32_t(imageAspects) << 4) + ^ (uint32_t(imageFormat) << 8) + ^ (uint32_t(bufferFormat) << 16); + } + }; + + /** * \brief Copy view objects * @@ -126,6 +164,33 @@ namespace dxvk { VkFormat srcFormat, VkImageAspectFlags srcAspect) const; + /** + * \brief Creates pipeline for buffer to image copy + * + * Note that setting both depth and stencil aspects + * requires device support for depth-stencil export. + * \param [in] viewType Image view type + * \param [in] dstFormat Destionation image format + * \param [in] srcFormat Source buffer data format + * \param [in] aspects Aspect mask to copy + */ + DxvkMetaCopyPipeline getCopyBufferToImagePipeline( + VkImageViewType viewType, + VkFormat dstFormat, + VkFormat srcFormat, + VkImageAspectFlags aspects); + + /** + * \brief Creates pipeline for image to buffer copy + * + * This method always returns a compute pipeline. + * \param [in] viewType Image view type + * \param [in] dstFormat Destionation buffer format + */ + DxvkMetaCopyPipeline getCopyImageToBufferPipeline( + VkImageViewType viewType, + VkFormat dstFormat); + /** * \brief Creates pipeline for meta copy operation * @@ -158,6 +223,19 @@ namespace dxvk { VkShaderModule m_shaderVert = VK_NULL_HANDLE; VkShaderModule m_shaderGeom = VK_NULL_HANDLE; + VkDescriptorSetLayout m_bufferToImageCopySetLayout = VK_NULL_HANDLE; + VkPipelineLayout m_bufferToImageCopyPipelineLayout = VK_NULL_HANDLE; + + VkShaderModule m_shaderBufferToImageD = VK_NULL_HANDLE; + VkShaderModule m_shaderBufferToImageS = VK_NULL_HANDLE; + VkShaderModule m_shaderBufferToImageDSExport = VK_NULL_HANDLE; + + VkDescriptorSetLayout m_imageToBufferCopySetLayout = VK_NULL_HANDLE; + VkPipelineLayout m_imageToBufferCopyPipelineLayout = VK_NULL_HANDLE; + + VkShaderModule m_shaderImageToBufferF = VK_NULL_HANDLE; + VkShaderModule m_shaderImageToBufferDS = VK_NULL_HANDLE; + FragShaders m_color; FragShaders m_depth; FragShaders m_depthStencil; @@ -169,16 +247,28 @@ namespace dxvk { DxvkMetaCopyPipeline, DxvkHash, DxvkEq> m_pipelines; + std::unordered_map m_bufferToImagePipelines; + + std::unordered_map m_imageToBufferPipelines; + DxvkMetaCopyPipeline m_copyBufferImagePipeline = { }; VkShaderModule createShaderModule( const SpirvCodeBuffer& code) const; - + DxvkMetaCopyPipeline createCopyFormattedBufferPipeline(); DxvkMetaCopyPipeline createPipeline( const DxvkMetaCopyPipelineKey& key); + VkPipeline createCopyBufferToImagePipeline( + const DxvkMetaBufferImageCopyPipelineKey& key); + + VkPipeline createCopyImageToBufferPipeline( + const DxvkMetaBufferImageCopyPipelineKey& key); + VkDescriptorSetLayout createDescriptorSetLayout( const DxvkMetaCopyPipelineKey& key) const;