diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h index 50631448..3a15443e 100644 --- a/src/dxvk/dxvk_buffer.h +++ b/src/dxvk/dxvk_buffer.h @@ -301,6 +301,19 @@ namespace dxvk { return m_physView->handle(); } + /** + * \brief Element cound + * + * Number of typed elements contained + * in the buffer view. Depends on the + * buffer view format. + * \returns Element count + */ + VkDeviceSize elementCount() const { + auto format = imageFormatInfo(m_info.format); + return m_info.rangeLength / format->elementSize; + } + /** * \brief Buffer view properties * \returns Buffer view properties diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index b0325f4d..1c870064 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -182,6 +182,15 @@ namespace dxvk { } + void updateDescriptorSets( + uint32_t descriptorWriteCount, + const VkWriteDescriptorSet* pDescriptorWrites) { + m_vkd->vkUpdateDescriptorSets(m_vkd->device(), + descriptorWriteCount, pDescriptorWrites, + 0, nullptr); + } + + void updateDescriptorSetWithTemplate( VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorTemplate, diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index cdf01c93..a66a3d1b 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -242,7 +242,66 @@ namespace dxvk { VkDeviceSize offset, VkDeviceSize length, VkClearColorValue value) { + this->renderPassEnd(); + this->unbindComputePipeline(); + // Query pipeline objects to use for this clear operation + DxvkMetaClearPipeline pipeInfo = m_metaClear->getClearBufferPipeline( + imageFormatInfo(bufferView->info().format)->flags); + + // Create a descriptor set pointing to the view + VkBufferView viewObject = bufferView->handle(); + + VkDescriptorSet descriptorSet = + m_cmd->allocateDescriptorSet(pipeInfo.dsetLayout); + + VkWriteDescriptorSet descriptorWrite; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.pNext = nullptr; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorCount = 1; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; + descriptorWrite.pImageInfo = nullptr; + descriptorWrite.pBufferInfo = nullptr; + descriptorWrite.pTexelBufferView = &viewObject; + m_cmd->updateDescriptorSets(1, &descriptorWrite); + + // Prepare shader arguments + DxvkMetaClearArgs pushArgs; + pushArgs.clearValue = value; + pushArgs.offset = VkOffset3D { int32_t(offset), 0, 0 }; + pushArgs.extent = VkExtent3D { uint32_t(length), 1, 1 }; + + VkExtent3D workgroups = util::computeBlockCount( + pushArgs.extent, pipeInfo.workgroupSize); + + m_cmd->cmdBindPipeline( + VK_PIPELINE_BIND_POINT_COMPUTE, + pipeInfo.pipeline); + m_cmd->cmdBindDescriptorSet( + VK_PIPELINE_BIND_POINT_COMPUTE, + pipeInfo.pipeLayout, descriptorSet); + m_cmd->cmdPushConstants( + pipeInfo.pipeLayout, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pushArgs), &pushArgs); + m_cmd->cmdDispatch( + workgroups.width, + workgroups.height, + workgroups.depth); + + m_barriers.accessBuffer( + bufferView->physicalSlice(), + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, + bufferView->bufferInfo().stages, + bufferView->bufferInfo().access); + m_barriers.recordCommands(m_cmd); + + m_cmd->trackResource(bufferView->viewResource()); + m_cmd->trackResource(bufferView->bufferResource()); } @@ -367,11 +426,81 @@ namespace dxvk { void DxvkContext::clearImageView( - const Rc& bufferView, + const Rc& imageView, VkOffset3D offset, VkExtent3D extent, VkClearColorValue value) { + this->renderPassEnd(); + this->unbindComputePipeline(); + // Query pipeline objects to use for this clear operation + DxvkMetaClearPipeline pipeInfo = m_metaClear->getClearImagePipeline( + imageView->type(), imageFormatInfo(imageView->info().format)->flags); + + // Create a descriptor set pointing to the view + VkDescriptorSet descriptorSet = + m_cmd->allocateDescriptorSet(pipeInfo.dsetLayout); + + VkDescriptorImageInfo viewInfo; + viewInfo.sampler = VK_NULL_HANDLE; + viewInfo.imageView = imageView->handle(); + viewInfo.imageLayout = imageView->imageInfo().layout; + + VkWriteDescriptorSet descriptorWrite; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.pNext = nullptr; + descriptorWrite.dstSet = descriptorSet; + descriptorWrite.dstBinding = 0; + descriptorWrite.dstArrayElement = 0; + descriptorWrite.descriptorCount = 1; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorWrite.pImageInfo = &viewInfo; + descriptorWrite.pBufferInfo = nullptr; + descriptorWrite.pTexelBufferView = nullptr; + m_cmd->updateDescriptorSets(1, &descriptorWrite); + + // Prepare shader arguments + DxvkMetaClearArgs pushArgs; + pushArgs.clearValue = value; + pushArgs.offset = offset; + pushArgs.extent = extent; + + VkExtent3D workgroups = util::computeBlockCount( + pushArgs.extent, pipeInfo.workgroupSize); + + if (imageView->type() == VK_IMAGE_VIEW_TYPE_1D_ARRAY) + workgroups.height = imageView->subresources().layerCount; + else if (imageView->type() == VK_IMAGE_VIEW_TYPE_2D_ARRAY) + workgroups.depth = imageView->subresources().layerCount; + + m_cmd->cmdBindPipeline( + VK_PIPELINE_BIND_POINT_COMPUTE, + pipeInfo.pipeline); + m_cmd->cmdBindDescriptorSet( + VK_PIPELINE_BIND_POINT_COMPUTE, + pipeInfo.pipeLayout, descriptorSet); + m_cmd->cmdPushConstants( + pipeInfo.pipeLayout, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, sizeof(pushArgs), &pushArgs); + m_cmd->cmdDispatch( + workgroups.width, + workgroups.height, + workgroups.depth); + + m_barriers.accessImage( + imageView->image(), + imageView->subresources(), + imageView->imageInfo().layout, + VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, + VK_ACCESS_SHADER_WRITE_BIT, + imageView->imageInfo().layout, + imageView->imageInfo().stages, + imageView->imageInfo().access); + m_barriers.recordCommands(m_cmd); + + m_cmd->trackResource(imageView); + m_cmd->trackResource(imageView->image()); } @@ -1402,6 +1531,16 @@ namespace dxvk { } + void DxvkContext::unbindComputePipeline() { + m_flags.set( + DxvkContextFlag::CpDirtyPipeline, + DxvkContextFlag::CpDirtyPipelineState, + DxvkContextFlag::CpDirtyResources); + + m_cpActivePipeline = VK_NULL_HANDLE; + } + + void DxvkContext::updateComputePipeline() { if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) { m_flags.clr(DxvkContextFlag::CpDirtyPipeline); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 8682f2f5..da9864cc 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -227,13 +227,13 @@ namespace dxvk { * Can be used to clear sub-regions of storage images * that are not going to be used as render targets. * Implicit format conversion will be applied. - * \param [in] bufferView The buffer view + * \param [in] imageView The image view * \param [in] offset Offset of the rect to clear * \param [in] extent Extent of the rect to clear * \param [in] value The clear value */ void clearImageView( - const Rc& bufferView, + const Rc& imageView, VkOffset3D offset, VkExtent3D extent, VkClearColorValue value); @@ -628,6 +628,8 @@ namespace dxvk { const Rc& framebuffer); void renderPassUnbindFramebuffer(); + void unbindComputePipeline(); + void updateComputePipeline(); void updateComputePipelineState(); diff --git a/src/dxvk/dxvk_meta_clear.cpp b/src/dxvk/dxvk_meta_clear.cpp index 25269bda..280f9d9f 100644 --- a/src/dxvk/dxvk_meta_clear.cpp +++ b/src/dxvk/dxvk_meta_clear.cpp @@ -70,6 +70,47 @@ namespace dxvk { } + DxvkMetaClearPipeline DxvkMetaClearObjects::getClearBufferPipeline( + DxvkFormatFlags formatFlags) const { + DxvkMetaClearPipeline result; + result.dsetLayout = m_clearBufDsetLayout; + result.pipeLayout = m_clearBufPipeLayout; + result.pipeline = formatFlags.test(DxvkFormatFlag::SampledInteger) + ? m_clearPipesU32.clearBuf + : m_clearPipesF32.clearBuf; + result.workgroupSize = VkExtent3D { 128, 1, 1 }; + return result; + } + + + DxvkMetaClearPipeline DxvkMetaClearObjects::getClearImagePipeline( + VkImageViewType viewType, + DxvkFormatFlags formatFlags) const { + const DxvkMetaClearPipelines& pipes + = formatFlags.test(DxvkFormatFlag::SampledInteger) + ? m_clearPipesU32 : m_clearPipesF32; + + DxvkMetaClearPipeline result; + result.dsetLayout = m_clearImgDsetLayout; + result.pipeLayout = m_clearImgPipeLayout; + + auto pipeInfo = [&pipes, viewType] () -> std::pair { + switch (viewType) { + case VK_IMAGE_VIEW_TYPE_1D: return { pipes.clearImg1D, VkExtent3D { 64, 1, 1 } }; + case VK_IMAGE_VIEW_TYPE_2D: return { pipes.clearImg2D, VkExtent3D { 8, 8, 1 } }; + case VK_IMAGE_VIEW_TYPE_3D: return { pipes.clearImg3D, VkExtent3D { 4, 4, 4 } }; + case VK_IMAGE_VIEW_TYPE_1D_ARRAY: return { pipes.clearImg1DArray, VkExtent3D { 64, 1, 1 } }; + case VK_IMAGE_VIEW_TYPE_2D_ARRAY: return { pipes.clearImg2DArray, VkExtent3D { 8, 8, 1 } }; + default: return { VkPipeline(VK_NULL_HANDLE), VkExtent3D { 0, 0, 0, } }; + } + }(); + + result.pipeline = pipeInfo.first; + result.workgroupSize = pipeInfo.second; + return result; + } + + VkDescriptorSetLayout DxvkMetaClearObjects::createDescriptorSetLayout( VkDescriptorType descriptorType) { VkDescriptorSetLayoutBinding bindInfo; diff --git a/src/dxvk/dxvk_meta_clear.h b/src/dxvk/dxvk_meta_clear.h index ba090096..da044f40 100644 --- a/src/dxvk/dxvk_meta_clear.h +++ b/src/dxvk/dxvk_meta_clear.h @@ -1,8 +1,7 @@ #pragma once -#include "dxvk_barrier.h" -#include "dxvk_cmdlist.h" -#include "dxvk_resource.h" +#include "dxvk_format.h" +#include "dxvk_include.h" #include "../spirv/spirv_code_buffer.h" @@ -22,6 +21,20 @@ namespace dxvk { }; + /** + * \brief Pipeline-related objects + * + * Use this to bind the pipeline + * and allocate a descriptor set. + */ + struct DxvkMetaClearPipeline { + VkDescriptorSetLayout dsetLayout; + VkPipelineLayout pipeLayout; + VkPipeline pipeline; + VkExtent3D workgroupSize; + }; + + /** * \brief Clear shaders and related objects * @@ -36,6 +49,30 @@ namespace dxvk { DxvkMetaClearObjects(const Rc& vkd); ~DxvkMetaClearObjects(); + /** + * \brief Retrieves objects to use for buffers + * + * Returns the pipeline, pipeline layout and descriptor + * set layout which are required to perform a meta clear + * operation on a buffer resource with the given format. + * \param [in] viewType The image virw type + */ + DxvkMetaClearPipeline getClearBufferPipeline( + DxvkFormatFlags formatFlags) const; + + /** + * \brief Retrieves objects for a given image view type + * + * Returns the pipeline, pipeline layout and descriptor + * set layout which are required to perform a meta clear + * operation on a resource with the given view type. + * \param [in] viewType The image virw type + * \returns The pipeline-related objects to use + */ + DxvkMetaClearPipeline getClearImagePipeline( + VkImageViewType viewType, + DxvkFormatFlags formatFlags) const; + private: struct DxvkMetaClearPipelines {