From 2c3674190aeea8f79eeadb17b1fe29fb2a1eadc8 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 15 Oct 2017 19:23:10 +0200 Subject: [PATCH] [dxvk] Implemented proper resource binding --- src/dxvk/dxvk_buffer.cpp | 4 ++ src/dxvk/dxvk_cmdlist.cpp | 38 ++++++++++- src/dxvk/dxvk_cmdlist.h | 11 ++++ src/dxvk/dxvk_compute.h | 11 ++++ src/dxvk/dxvk_context.cpp | 54 ++++++++++++++++ src/dxvk/dxvk_context.h | 7 ++- src/dxvk/dxvk_descriptor.cpp | 101 ++++++++++++++++++++++++++++++ src/dxvk/dxvk_descriptor.h | 62 ++++++++++++++++++ src/dxvk/dxvk_recorder.h | 8 +++ src/dxvk/dxvk_sampler.cpp | 0 src/dxvk/dxvk_sampler.h | 0 src/dxvk/meson.build | 1 + tests/dxvk/test_dxvk_triangle.cpp | 3 + 13 files changed, 296 insertions(+), 4 deletions(-) create mode 100644 src/dxvk/dxvk_descriptor.cpp create mode 100644 src/dxvk/dxvk_descriptor.h create mode 100644 src/dxvk/dxvk_sampler.cpp create mode 100644 src/dxvk/dxvk_sampler.h diff --git a/src/dxvk/dxvk_buffer.cpp b/src/dxvk/dxvk_buffer.cpp index 5f13f330..471b7fca 100644 --- a/src/dxvk/dxvk_buffer.cpp +++ b/src/dxvk/dxvk_buffer.cpp @@ -27,6 +27,10 @@ namespace dxvk { m_vkd->vkGetBufferMemoryRequirements( m_vkd->device(), m_buffer, &memReq); m_memory = memAlloc.alloc(memReq, memFlags); + + if (m_vkd->vkBindBufferMemory(m_vkd->device(), + m_buffer, m_memory.memory(), m_memory.offset()) != VK_SUCCESS) + throw DxvkError("DxvkBuffer::DxvkBuffer: Failed to bind device memory"); } diff --git a/src/dxvk/dxvk_cmdlist.cpp b/src/dxvk/dxvk_cmdlist.cpp index 34bf1d9a..8b68aefd 100644 --- a/src/dxvk/dxvk_cmdlist.cpp +++ b/src/dxvk/dxvk_cmdlist.cpp @@ -5,7 +5,7 @@ namespace dxvk { DxvkCommandList::DxvkCommandList( const Rc& vkd, uint32_t queueFamily) - : m_vkd(vkd) { + : m_vkd(vkd), m_descAlloc(vkd) { TRACE(this, queueFamily); VkCommandPoolCreateInfo poolInfo; @@ -71,10 +71,46 @@ namespace dxvk { void DxvkCommandList::reset() { TRACE(this); + + m_descAlloc.reset(); m_resources.reset(); } + void DxvkCommandList::bindShaderResources( + VkPipelineBindPoint pipeline, + VkPipelineLayout pipelineLayout, + VkDescriptorSetLayout descriptorLayout, + uint32_t bindingCount, + const DxvkResourceBinding* bindings) { + VkDescriptorSet dset = m_descAlloc.alloc(descriptorLayout); + + if (bindingCount > m_descriptorSetWrites.size()) + m_descriptorSetWrites.resize(bindingCount); + + for (uint32_t i = 0; i < bindingCount; i++) { + VkWriteDescriptorSet& info = m_descriptorSetWrites.at(i); + + info.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + info.pNext = nullptr; + info.dstSet = dset; + info.dstBinding = i; + info.dstArrayElement = 0; + info.descriptorCount = 1; + info.descriptorType = bindings[i].type; + info.pImageInfo = &bindings[i].image; + info.pBufferInfo = &bindings[i].buffer; + info.pTexelBufferView = nullptr; + } + + m_vkd->vkUpdateDescriptorSets(m_vkd->device(), + bindingCount, m_descriptorSetWrites.data(), 0, nullptr); + + m_vkd->vkCmdBindDescriptorSets(m_buffer, + pipeline, pipelineLayout, 0, 1, &dset, 0, nullptr); + } + + void DxvkCommandList::cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) { diff --git a/src/dxvk/dxvk_cmdlist.h b/src/dxvk/dxvk_cmdlist.h index 782d0a88..e5ca18a7 100644 --- a/src/dxvk/dxvk_cmdlist.h +++ b/src/dxvk/dxvk_cmdlist.h @@ -2,6 +2,7 @@ #include +#include "dxvk_descriptor.h" #include "dxvk_lifetime.h" #include "dxvk_recorder.h" @@ -70,6 +71,13 @@ namespace dxvk { */ void reset() final; + void bindShaderResources( + VkPipelineBindPoint pipeline, + VkPipelineLayout pipelineLayout, + VkDescriptorSetLayout descriptorLayout, + uint32_t bindingCount, + const DxvkResourceBinding* bindings) final; + void cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) final; @@ -123,6 +131,9 @@ namespace dxvk { VkCommandBuffer m_buffer; DxvkLifetimeTracker m_resources; + DxvkDescriptorAlloc m_descAlloc; + + std::vector m_descriptorSetWrites; }; diff --git a/src/dxvk/dxvk_compute.h b/src/dxvk/dxvk_compute.h index c6df6122..a2f210cf 100644 --- a/src/dxvk/dxvk_compute.h +++ b/src/dxvk/dxvk_compute.h @@ -33,6 +33,17 @@ namespace dxvk { return m_descriptorSetLayout; } + /** + * \brief Pipeline layout layout + * + * The pipeline layout for this pipeline. + * Use this to bind descriptor sets. + * \returns The descriptor set layout + */ + VkPipelineLayout pipelineLayout() const { + return m_pipelineLayout; + } + /** * \brief Pipeline handle * \returns Pipeline handle diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 0cf9562f..4dfb6c25 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -127,6 +127,8 @@ namespace dxvk { m_cmd->cmdDispatch( wgCountX, wgCountY, wgCountZ); + + // TODO resource barriers } @@ -173,6 +175,18 @@ namespace dxvk { } } + if (m_state.c.flags.test(DxvkComputePipelineBit::DirtyResources) + && m_state.c.pipeline != nullptr) { + std::vector bindings; + this->addResourceBindingInfo(bindings, m_state.c.cs); + + m_cmd->bindShaderResources( + VK_PIPELINE_BIND_POINT_COMPUTE, + m_state.c.pipeline->pipelineLayout(), + m_state.c.pipeline->descriptorSetLayout(), + bindings.size(), bindings.data()); + } + m_state.c.flags.clr( DxvkComputePipelineBit::PipelineDirty, DxvkComputePipelineBit::DirtyResources); @@ -259,4 +273,44 @@ namespace dxvk { } } + + uint32_t DxvkContext::addResourceBindingInfo( + std::vector& bindings, + const DxvkShaderState& stageInfo) const { + const uint32_t slotCount = stageInfo.shader->slotCount(); + + for (uint32_t i = 0; i < slotCount; i++) { + DxvkResourceSlot slot = stageInfo.shader->slot(i); + DxvkResourceBinding binding; + + switch (slot.type) { + case DxvkResourceType::ImageSampler: + binding.type = VK_DESCRIPTOR_TYPE_SAMPLER; + break; + + case DxvkResourceType::SampledImage: + binding.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + break; + + case DxvkResourceType::StorageImage: + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + break; + + case DxvkResourceType::UniformBuffer: + binding.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + binding.buffer = stageInfo.boundUniformBuffers.at(slot.slot).descriptorInfo(); + break; + + case DxvkResourceType::StorageBuffer: + binding.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + binding.buffer = stageInfo.boundStorageBuffers.at(slot.slot).descriptorInfo(); + break; + } + + bindings.push_back(binding); + } + + return slotCount; + } + } \ No newline at end of file diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 1a6cabba..af66e224 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -165,9 +165,10 @@ namespace dxvk { DxvkShaderState* getShaderState( VkShaderStageFlagBits stage); - - VkPipelineStageFlags pipelineStage( - VkShaderStageFlags shaderStage) const; + + uint32_t addResourceBindingInfo( + std::vector& bindings, + const DxvkShaderState& stageInfo) const; }; diff --git a/src/dxvk/dxvk_descriptor.cpp b/src/dxvk/dxvk_descriptor.cpp new file mode 100644 index 00000000..11eaa146 --- /dev/null +++ b/src/dxvk/dxvk_descriptor.cpp @@ -0,0 +1,101 @@ +#include "dxvk_descriptor.h" + +namespace dxvk { + + DxvkDescriptorAlloc::DxvkDescriptorAlloc( + const Rc& vkd) + : m_vkd(vkd) { + TRACE(this); + } + + + DxvkDescriptorAlloc::~DxvkDescriptorAlloc() { + TRACE(this); + + for (auto p : m_pools) { + m_vkd->vkDestroyDescriptorPool( + m_vkd->device(), p, nullptr); + } + } + + + VkDescriptorSet DxvkDescriptorAlloc::alloc(VkDescriptorSetLayout layout) { + TRACE(this, layout); + + VkDescriptorSet set = VK_NULL_HANDLE; + + if (m_poolId < m_pools.size()) + set = this->allocFrom(m_pools.at(m_poolId), layout); + + if (set == VK_NULL_HANDLE) { + VkDescriptorPool pool = this->createDescriptorPool(); + set = this->allocFrom(pool, layout); + + if (set == VK_NULL_HANDLE) + throw DxvkError("DxvkDescriptorAlloc::alloc: Failed to allocate descriptor set"); + + m_pools.push_back(pool); + m_poolId += 1; + } + + return set; + } + + + void DxvkDescriptorAlloc::reset() { + for (auto p : m_pools) { + m_vkd->vkResetDescriptorPool( + m_vkd->device(), p, 0); + } + + m_poolId = 0; + } + + + VkDescriptorPool DxvkDescriptorAlloc::createDescriptorPool() { + TRACE(this); + + // TODO tune these values, if necessary + constexpr uint32_t MaxSets = 256; + constexpr uint32_t MaxDesc = 256; + + std::array pools = {{ + { VK_DESCRIPTOR_TYPE_SAMPLER, MaxDesc }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, MaxDesc }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, MaxDesc }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, MaxDesc }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, MaxDesc } }}; + + VkDescriptorPoolCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.maxSets = MaxSets; + info.poolSizeCount = pools.size(); + info.pPoolSizes = pools.data(); + + VkDescriptorPool pool = VK_NULL_HANDLE; + if (m_vkd->vkCreateDescriptorPool(m_vkd->device(), + &info, nullptr, &pool) != VK_SUCCESS) + throw DxvkError("DxvkDescriptorAlloc::createDescriptorPool: Failed to create descriptor pool"); + return pool; + } + + + VkDescriptorSet DxvkDescriptorAlloc::allocFrom( + VkDescriptorPool pool, + VkDescriptorSetLayout layout) const { + VkDescriptorSetAllocateInfo info; + info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + info.pNext = nullptr; + info.descriptorPool = pool; + info.descriptorSetCount = 1; + info.pSetLayouts = &layout; + + VkDescriptorSet set = VK_NULL_HANDLE; + if (m_vkd->vkAllocateDescriptorSets(m_vkd->device(), &info, &set) != VK_SUCCESS) + return VK_NULL_HANDLE; + return set; + } + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_descriptor.h b/src/dxvk/dxvk_descriptor.h new file mode 100644 index 00000000..8c07c835 --- /dev/null +++ b/src/dxvk/dxvk_descriptor.h @@ -0,0 +1,62 @@ +#pragma once + +#include "dxvk_include.h" + +namespace dxvk { + + struct DxvkResourceBinding { + VkDescriptorType type; + VkDescriptorImageInfo image; + VkDescriptorBufferInfo buffer; + }; + + /** + * \brief Descriptor set allocator + * + * Creates descriptor pools on demand and + * allocates descriptor sets from those pools. + */ + class DxvkDescriptorAlloc { + + public: + + DxvkDescriptorAlloc( + const Rc& vkd); + ~DxvkDescriptorAlloc(); + + DxvkDescriptorAlloc (const DxvkDescriptorAlloc&) = delete; + DxvkDescriptorAlloc& operator = (const DxvkDescriptorAlloc&) = delete; + + /** + * \brief Allocates a descriptor set + * + * \param [in] layout Descriptor set layout + * \returns The descriptor set + */ + VkDescriptorSet alloc( + VkDescriptorSetLayout layout); + + /** + * \brief Resets descriptor set allocator + * + * Destroys all descriptor sets and + * resets the Vulkan descriptor pools. + */ + void reset(); + + private: + + Rc m_vkd; + + std::vector m_pools; + size_t m_poolId = 0; + + VkDescriptorPool createDescriptorPool(); + + VkDescriptorSet allocFrom( + VkDescriptorPool pool, + VkDescriptorSetLayout layout) const; + + }; + +} \ No newline at end of file diff --git a/src/dxvk/dxvk_recorder.h b/src/dxvk/dxvk_recorder.h index 73cd272c..e47d9513 100644 --- a/src/dxvk/dxvk_recorder.h +++ b/src/dxvk/dxvk_recorder.h @@ -1,5 +1,6 @@ #pragma once +#include "dxvk_descriptor.h" #include "dxvk_lifetime.h" namespace dxvk { @@ -27,6 +28,13 @@ namespace dxvk { virtual void reset() = 0; + virtual void bindShaderResources( + VkPipelineBindPoint pipeline, + VkPipelineLayout pipelineLayout, + VkDescriptorSetLayout descriptorLayout, + uint32_t bindingCount, + const DxvkResourceBinding* bindings) = 0; + virtual void cmdBeginRenderPass( const VkRenderPassBeginInfo* pRenderPassBegin, VkSubpassContents contents) = 0; diff --git a/src/dxvk/dxvk_sampler.cpp b/src/dxvk/dxvk_sampler.cpp new file mode 100644 index 00000000..e69de29b diff --git a/src/dxvk/dxvk_sampler.h b/src/dxvk/dxvk_sampler.h new file mode 100644 index 00000000..e69de29b diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 1ede34bb..86155f30 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -6,6 +6,7 @@ dxvk_src = files([ 'dxvk_compute.cpp', 'dxvk_context.cpp', 'dxvk_deferred.cpp', + 'dxvk_descriptor.cpp', 'dxvk_device.cpp', 'dxvk_framebuffer.cpp', 'dxvk_graphics.cpp', diff --git a/tests/dxvk/test_dxvk_triangle.cpp b/tests/dxvk/test_dxvk_triangle.cpp index 9e94134b..eab6ae15 100644 --- a/tests/dxvk/test_dxvk_triangle.cpp +++ b/tests/dxvk/test_dxvk_triangle.cpp @@ -105,6 +105,9 @@ public: m_dxvkCommandList, sync1, sync2); m_dxvkSwapchain->present(sync2); m_dxvkDevice->waitForIdle(); + + std::memcpy(m_testData, m_testBuffer->mapPtr(), sizeof(m_testData)); + std::cout << m_testData[0] << std::endl; } private: