diff --git a/src/dxvk/dxvk_meta_copy.cpp b/src/dxvk/dxvk_meta_copy.cpp index fa4fd36ee..fdd7b658f 100644 --- a/src/dxvk/dxvk_meta_copy.cpp +++ b/src/dxvk/dxvk_meta_copy.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -179,6 +180,10 @@ namespace dxvk { DxvkMetaCopyObjects::~DxvkMetaCopyObjects() { + 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); m_vkd->vkDestroyPipelineLayout(m_vkd->device(), pair.second.pipeLayout, nullptr); @@ -250,6 +255,16 @@ namespace dxvk { m_pipelines.insert({ key, pipeline }); return pipeline; } + + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::getCopyBufferImagePipeline() { + std::lock_guard lock(m_mutex); + + if (!m_copyBufferImagePipeline.pipeHandle) + m_copyBufferImagePipeline = createCopyBufferImagePipeline(); + + return m_copyBufferImagePipeline; + } VkSampler DxvkMetaCopyObjects::createSampler() const { @@ -296,6 +311,65 @@ namespace dxvk { } + DxvkMetaCopyPipeline DxvkMetaCopyObjects::createCopyBufferImagePipeline() { + DxvkMetaCopyPipeline pipeline; + pipeline.renderPass = VK_NULL_HANDLE; + + std::array bindings = {{ + { 0, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + { 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_COMPUTE_BIT, nullptr }, + }}; + + VkDescriptorSetLayoutCreateInfo setLayoutInfo; + setLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + setLayoutInfo.pNext = nullptr; + setLayoutInfo.flags = 0; + setLayoutInfo.bindingCount = bindings.size(); + setLayoutInfo.pBindings = bindings.data(); + + if (m_vkd->vkCreateDescriptorSetLayout(m_vkd->device(), &setLayoutInfo, nullptr, &pipeline.dsetLayout) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create descriptor set layout"); + + VkPushConstantRange pushRange = { VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(DxvkCopyBufferImageArgs) }; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pNext = nullptr; + pipelineLayoutInfo.flags = 0; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &pipeline.dsetLayout; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushRange; + + if (m_vkd->vkCreatePipelineLayout(m_vkd->device(), &pipelineLayoutInfo, nullptr, &pipeline.pipeLayout) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create pipeline layout"); + + VkShaderModule shaderModule = createShaderModule(dxvk_copy_buffer_image); + + VkComputePipelineCreateInfo pipelineInfo; + pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + pipelineInfo.pNext = nullptr; + pipelineInfo.flags = 0; + pipelineInfo.layout = pipeline.pipeLayout; + pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + pipelineInfo.stage.pNext = nullptr; + pipelineInfo.stage.flags = 0; + pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; + pipelineInfo.stage.module = shaderModule; + pipelineInfo.stage.pName = "main"; + pipelineInfo.stage.pSpecializationInfo = nullptr; + pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + pipelineInfo.basePipelineIndex = -1; + + if (m_vkd->vkCreateComputePipelines(m_vkd->device(), VK_NULL_HANDLE, + 1, &pipelineInfo, nullptr, &pipeline.pipeHandle) != VK_SUCCESS) + throw DxvkError("DxvkMetaCopyObjects: Failed to create compute pipeline"); + + m_vkd->vkDestroyShaderModule(m_vkd->device(), shaderModule, nullptr); + return pipeline; + } + + DxvkMetaCopyPipeline DxvkMetaCopyObjects::createPipeline( const DxvkMetaCopyPipelineKey& key) { DxvkMetaCopyPipeline pipeline; diff --git a/src/dxvk/dxvk_meta_copy.h b/src/dxvk/dxvk_meta_copy.h index 43d908968..90285b905 100644 --- a/src/dxvk/dxvk_meta_copy.h +++ b/src/dxvk/dxvk_meta_copy.h @@ -14,6 +14,17 @@ namespace dxvk { class DxvkDevice; + /** + * \brief Push constants for buffer image copies + */ + struct DxvkCopyBufferImageArgs { + VkOffset3D dstOffset; uint32_t pad0; + VkOffset3D srcOffset; uint32_t pad1; + VkExtent3D extent; uint32_t pad2; + VkExtent2D dstSize; + VkExtent2D srcSize; + }; + /** * \brief Copy pipeline * @@ -135,6 +146,12 @@ namespace dxvk { VkFormat dstFormat, VkSampleCountFlagBits dstSamples); + /** + * \brief Creates pipeline for buffer image copy + * \returns Compute pipeline for buffer image copies + */ + DxvkMetaCopyPipeline getCopyBufferImagePipeline(); + private: struct FragShaders { @@ -160,12 +177,16 @@ namespace dxvk { DxvkMetaCopyPipelineKey, DxvkMetaCopyPipeline, DxvkHash, DxvkEq> m_pipelines; - + + DxvkMetaCopyPipeline m_copyBufferImagePipeline = { }; + VkSampler createSampler() const; VkShaderModule createShaderModule( const SpirvCodeBuffer& code) const; + DxvkMetaCopyPipeline createCopyBufferImagePipeline(); + DxvkMetaCopyPipeline createPipeline( const DxvkMetaCopyPipelineKey& key); diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index d4c24ce28..ec63ff485 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -16,6 +16,7 @@ dxvk_shaders = files([ 'shaders/dxvk_clear_image3d_u.comp', 'shaders/dxvk_clear_image3d_f.comp', + 'shaders/dxvk_copy_buffer_image.comp', 'shaders/dxvk_copy_color_1d.frag', 'shaders/dxvk_copy_color_2d.frag', 'shaders/dxvk_copy_color_ms.frag', diff --git a/src/dxvk/shaders/dxvk_copy_buffer_image.comp b/src/dxvk/shaders/dxvk_copy_buffer_image.comp new file mode 100644 index 000000000..7407285e3 --- /dev/null +++ b/src/dxvk/shaders/dxvk_copy_buffer_image.comp @@ -0,0 +1,30 @@ +#version 450 + +layout( + local_size_x = 8, + local_size_y = 8, + local_size_z = 1) in; + +layout(binding = 0) writeonly uniform uimageBuffer u_dst; +layout(binding = 1) uniform usamplerBuffer u_src; + +layout(push_constant) +uniform u_info_t { + uvec3 dst_offset; + uvec3 src_offset; + uvec3 extent; + uvec2 dst_size; + uvec2 src_size; +} u_info; + +void main() { + if (all(lessThan(gl_GlobalInvocationID, u_info.extent))) { + uvec3 dst_coord = u_info.dst_offset + gl_GlobalInvocationID; + uvec3 src_coord = u_info.src_offset + gl_GlobalInvocationID; + + uint dst_index = dst_coord.x + u_info.dst_size.x * (dst_coord.y + u_info.dst_size.y * dst_coord.z); + uint src_index = src_coord.x + u_info.src_size.x * (src_coord.y + u_info.src_size.y * src_coord.z); + + imageStore(u_dst, int(dst_index), texelFetch(u_src, int(src_index))); + } +} \ No newline at end of file