mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-13 16:08:50 +01:00
[dxvk] Introduce DxvkBindingLayout and related classes
This is intended to replace the legacy DxvkPipelineLayout, and can support multiple descriptor sets.
This commit is contained in:
parent
67d03aabd0
commit
3751edbe0c
@ -1,11 +1,344 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "dxvk_device.h"
|
||||||
#include "dxvk_descriptor.h"
|
#include "dxvk_descriptor.h"
|
||||||
#include "dxvk_limits.h"
|
#include "dxvk_limits.h"
|
||||||
#include "dxvk_pipelayout.h"
|
#include "dxvk_pipelayout.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
|
uint32_t DxvkBindingInfo::computeSetIndex() const {
|
||||||
|
if (stages & (VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT)) {
|
||||||
|
// For fragment shaders, create a separate set for UBOs
|
||||||
|
if (descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
|
||||||
|
|| descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
|
||||||
|
return DxvkDescriptorSets::FsBuffers;
|
||||||
|
|
||||||
|
return DxvkDescriptorSets::FsViews;
|
||||||
|
} else {
|
||||||
|
// Put all vertex shader resources into the last set.
|
||||||
|
// Vertex shader UBOs are usually updated every draw,
|
||||||
|
// and other resource types are rarely used.
|
||||||
|
return DxvkDescriptorSets::VsAll;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkBindingInfo::canMerge(const DxvkBindingInfo& binding) const {
|
||||||
|
if ((stages & VK_SHADER_STAGE_FRAGMENT_BIT) != (binding.stages & VK_SHADER_STAGE_FRAGMENT_BIT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return descriptorType == binding.descriptorType
|
||||||
|
&& resourceBinding == binding.resourceBinding
|
||||||
|
&& viewType == binding.viewType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingInfo::merge(const DxvkBindingInfo& binding) {
|
||||||
|
stages |= binding.stages;
|
||||||
|
access |= binding.access;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkBindingInfo::eq(const DxvkBindingInfo& other) const {
|
||||||
|
return descriptorType == other.descriptorType
|
||||||
|
&& resourceBinding == other.resourceBinding
|
||||||
|
&& viewType == other.viewType
|
||||||
|
&& stages == other.stages
|
||||||
|
&& access == other.access;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DxvkBindingInfo::hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
hash.add(descriptorType);
|
||||||
|
hash.add(resourceBinding);
|
||||||
|
hash.add(viewType);
|
||||||
|
hash.add(stages);
|
||||||
|
hash.add(access);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingList::DxvkBindingList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingList::~DxvkBindingList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingList::addBinding(const DxvkBindingInfo& binding) {
|
||||||
|
for (auto& b : m_bindings) {
|
||||||
|
if (b.canMerge(binding)) {
|
||||||
|
b.merge(binding);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bindings.push_back(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingList::merge(const DxvkBindingList& list) {
|
||||||
|
for (const auto& binding : list.m_bindings)
|
||||||
|
addBinding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkBindingList::eq(const DxvkBindingList& other) const {
|
||||||
|
if (getBindingCount() != other.getBindingCount())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < getBindingCount(); i++) {
|
||||||
|
if (!getBinding(i).eq(other.getBinding(i)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DxvkBindingList::hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
|
||||||
|
for (const auto& binding : m_bindings)
|
||||||
|
hash.add(binding.hash());
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingSetLayoutKey::DxvkBindingSetLayoutKey(const DxvkBindingList& list) {
|
||||||
|
m_bindings.resize(list.getBindingCount());
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < list.getBindingCount(); i++) {
|
||||||
|
m_bindings[i].descriptorType = list.getBinding(i).descriptorType;
|
||||||
|
m_bindings[i].stages = list.getBinding(i).stages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingSetLayoutKey::~DxvkBindingSetLayoutKey() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkBindingSetLayoutKey::eq(const DxvkBindingSetLayoutKey& other) const {
|
||||||
|
if (m_bindings.size() != other.m_bindings.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_bindings.size(); i++) {
|
||||||
|
if (m_bindings[i].descriptorType != other.m_bindings[i].descriptorType
|
||||||
|
|| m_bindings[i].stages != other.m_bindings[i].stages)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DxvkBindingSetLayoutKey::hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_bindings.size(); i++) {
|
||||||
|
hash.add(m_bindings[i].descriptorType);
|
||||||
|
hash.add(m_bindings[i].stages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingSetLayout::DxvkBindingSetLayout(
|
||||||
|
DxvkDevice* device,
|
||||||
|
const DxvkBindingSetLayoutKey& key)
|
||||||
|
: m_device(device) {
|
||||||
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
std::array<VkDescriptorSetLayoutBinding, MaxNumActiveBindings> bindingInfos;
|
||||||
|
std::array<VkDescriptorUpdateTemplateEntry, MaxNumActiveBindings> templateInfos;
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutCreateInfo layoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
||||||
|
layoutInfo.bindingCount = key.getBindingCount();
|
||||||
|
layoutInfo.pBindings = bindingInfos.data();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < key.getBindingCount(); i++) {
|
||||||
|
auto entry = key.getBinding(i);
|
||||||
|
|
||||||
|
VkDescriptorSetLayoutBinding& bindingInfo = bindingInfos[i];
|
||||||
|
bindingInfo.binding = i;
|
||||||
|
bindingInfo.descriptorType = entry.descriptorType;
|
||||||
|
bindingInfo.descriptorCount = 1;
|
||||||
|
bindingInfo.stageFlags = entry.stages;
|
||||||
|
bindingInfo.pImmutableSamplers = nullptr;
|
||||||
|
|
||||||
|
VkDescriptorUpdateTemplateEntry& templateInfo = templateInfos[i];
|
||||||
|
templateInfo.dstBinding = i;
|
||||||
|
templateInfo.dstArrayElement = 0;
|
||||||
|
templateInfo.descriptorCount = 1;
|
||||||
|
templateInfo.descriptorType = entry.descriptorType;
|
||||||
|
templateInfo.offset = sizeof(DxvkDescriptorInfo) * i;
|
||||||
|
templateInfo.stride = sizeof(DxvkDescriptorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vk->vkCreateDescriptorSetLayout(vk->device(), &layoutInfo, nullptr, &m_layout) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkBindingSetLayoutKey: Failed to create descriptor set layout");
|
||||||
|
|
||||||
|
if (layoutInfo.bindingCount) {
|
||||||
|
VkDescriptorUpdateTemplateCreateInfo templateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO };
|
||||||
|
templateInfo.descriptorUpdateEntryCount = layoutInfo.bindingCount;
|
||||||
|
templateInfo.pDescriptorUpdateEntries = templateInfos.data();
|
||||||
|
templateInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET;
|
||||||
|
templateInfo.descriptorSetLayout = m_layout;
|
||||||
|
|
||||||
|
if (vk->vkCreateDescriptorUpdateTemplate(vk->device(), &templateInfo, nullptr, &m_template) != VK_SUCCESS)
|
||||||
|
throw DxvkError("DxvkBindingLayoutObjects: Failed to create descriptor update template");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingSetLayout::~DxvkBindingSetLayout() {
|
||||||
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
vk->vkDestroyDescriptorSetLayout(vk->device(), m_layout, nullptr);
|
||||||
|
vk->vkDestroyDescriptorUpdateTemplate(vk->device(), m_template, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingLayout::DxvkBindingLayout()
|
||||||
|
: m_pushConst { 0, 0, 0 } {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingLayout::~DxvkBindingLayout() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingLayout::addBinding(const DxvkBindingInfo& binding) {
|
||||||
|
uint32_t set = binding.computeSetIndex();
|
||||||
|
m_bindings[set].addBinding(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingLayout::addPushConstantRange(VkPushConstantRange range) {
|
||||||
|
uint32_t oldEnd = m_pushConst.offset + m_pushConst.size;
|
||||||
|
uint32_t newEnd = range.offset + range.size;
|
||||||
|
|
||||||
|
m_pushConst.stageFlags |= range.stageFlags;
|
||||||
|
m_pushConst.offset = std::min(m_pushConst.offset, range.offset);
|
||||||
|
m_pushConst.size = std::max(oldEnd, newEnd) - m_pushConst.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DxvkBindingLayout::merge(const DxvkBindingLayout& layout) {
|
||||||
|
for (uint32_t i = 0; i < layout.m_bindings.size(); i++)
|
||||||
|
m_bindings[i].merge(layout.m_bindings[i]);
|
||||||
|
|
||||||
|
addPushConstantRange(layout.m_pushConst);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DxvkBindingLayout::eq(const DxvkBindingLayout& other) const {
|
||||||
|
for (uint32_t i = 0; i < m_bindings.size(); i++) {
|
||||||
|
if (!m_bindings[i].eq(other.m_bindings[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pushConst.stageFlags != other.m_pushConst.stageFlags
|
||||||
|
|| m_pushConst.offset != other.m_pushConst.offset
|
||||||
|
|| m_pushConst.size != other.m_pushConst.size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t DxvkBindingLayout::hash() const {
|
||||||
|
DxvkHashState hash;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < m_bindings.size(); i++)
|
||||||
|
hash.add(m_bindings[i].hash());
|
||||||
|
|
||||||
|
hash.add(m_pushConst.stageFlags);
|
||||||
|
hash.add(m_pushConst.offset);
|
||||||
|
hash.add(m_pushConst.size);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingLayoutObjects::DxvkBindingLayoutObjects(
|
||||||
|
DxvkDevice* device,
|
||||||
|
const DxvkBindingLayout& layout,
|
||||||
|
const DxvkBindingSetLayout** setObjects)
|
||||||
|
: m_device(device), m_layout(layout) {
|
||||||
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
uint32_t constId = 0;
|
||||||
|
|
||||||
|
std::array<VkDescriptorSetLayout, DxvkDescriptorSets::SetCount> setLayouts;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < DxvkDescriptorSets::SetCount; i++) {
|
||||||
|
m_bindingOffsets[i] = constId;
|
||||||
|
m_bindingObjects[i] = setObjects[i];
|
||||||
|
setLayouts[i] = setObjects[i]->getSetLayout();
|
||||||
|
|
||||||
|
uint32_t bindingCount = m_layout.getBindingCount(i);
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < bindingCount; j++) {
|
||||||
|
const DxvkBindingInfo& binding = m_layout.getBinding(i, j);
|
||||||
|
|
||||||
|
DxvkBindingMapping mapping;
|
||||||
|
mapping.set = i;
|
||||||
|
mapping.binding = j;
|
||||||
|
mapping.constId = constId++;
|
||||||
|
|
||||||
|
m_mapping.insert({ binding.resourceBinding, mapping });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindingCount)
|
||||||
|
m_setMask |= 1u << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPushConstantRange pushConst = m_layout.getPushConstantRange();
|
||||||
|
|
||||||
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
||||||
|
pipelineLayoutInfo.setLayoutCount = setLayouts.size();
|
||||||
|
pipelineLayoutInfo.pSetLayouts = setLayouts.data();
|
||||||
|
|
||||||
|
if (pushConst.stageFlags && pushConst.size) {
|
||||||
|
pipelineLayoutInfo.pushConstantRangeCount = 1;
|
||||||
|
pipelineLayoutInfo.pPushConstantRanges = &pushConst;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vk->vkCreatePipelineLayout(vk->device(), &pipelineLayoutInfo, nullptr, &m_pipelineLayout))
|
||||||
|
throw DxvkError("DxvkBindingLayoutObjects: Failed to create pipeline layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DxvkBindingLayoutObjects::~DxvkBindingLayoutObjects() {
|
||||||
|
auto vk = m_device->vkd();
|
||||||
|
|
||||||
|
vk->vkDestroyPipelineLayout(vk->device(), m_pipelineLayout, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VkAccessFlags DxvkBindingLayoutObjects::getAccessFlags() const {
|
||||||
|
VkAccessFlags flags = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < DxvkDescriptorSets::SetCount; i++) {
|
||||||
|
for (uint32_t j = 0; j < m_layout.getBindingCount(i); j++)
|
||||||
|
flags |= m_layout.getBinding(i, j).access;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DxvkDescriptorSlotMapping:: DxvkDescriptorSlotMapping() { }
|
DxvkDescriptorSlotMapping:: DxvkDescriptorSlotMapping() { }
|
||||||
DxvkDescriptorSlotMapping::~DxvkDescriptorSlotMapping() { }
|
DxvkDescriptorSlotMapping::~DxvkDescriptorSlotMapping() { }
|
||||||
|
|
||||||
|
@ -1,11 +1,475 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "dxvk_hash.h"
|
||||||
#include "dxvk_include.h"
|
#include "dxvk_include.h"
|
||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
|
class DxvkDevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Descriptor set indices
|
||||||
|
*/
|
||||||
|
struct DxvkDescriptorSets {
|
||||||
|
static constexpr uint32_t FsViews = 0;
|
||||||
|
static constexpr uint32_t FsBuffers = 1;
|
||||||
|
static constexpr uint32_t VsAll = 2;
|
||||||
|
static constexpr uint32_t SetCount = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding info
|
||||||
|
*
|
||||||
|
* Stores metadata for a single binding in
|
||||||
|
* a given shader, or for the whole pipeline.
|
||||||
|
*/
|
||||||
|
struct DxvkBindingInfo {
|
||||||
|
VkDescriptorType descriptorType; ///< Vulkan descriptor type
|
||||||
|
uint32_t resourceBinding; ///< API binding slot for the resource
|
||||||
|
VkImageViewType viewType; ///< Image view type
|
||||||
|
VkShaderStageFlags stages; ///< Shader stage mask
|
||||||
|
VkAccessFlags access; ///< Access mask for the resource
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Computes descriptor set index for the given binding
|
||||||
|
*
|
||||||
|
* This is determines based on the shader stages that use the binding.
|
||||||
|
* \returns Descriptor set index
|
||||||
|
*/
|
||||||
|
uint32_t computeSetIndex() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks whether bindings can be merged
|
||||||
|
*
|
||||||
|
* Bindings can be merged if they access the same resource with
|
||||||
|
* the same view and descriptor type and are part of the same
|
||||||
|
* descriptor set.
|
||||||
|
* \param [in] binding The binding to probe
|
||||||
|
* \returns \c true if the bindings can be merged
|
||||||
|
*/
|
||||||
|
bool canMerge(const DxvkBindingInfo& binding) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Merges bindings
|
||||||
|
*
|
||||||
|
* Merges the stage and access flags of two
|
||||||
|
* otherwise identical binding declarations.
|
||||||
|
* \param [in] binding The binding to merge
|
||||||
|
*/
|
||||||
|
void merge(const DxvkBindingInfo& binding);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks for equality
|
||||||
|
*
|
||||||
|
* \param [in] other Binding to compare to
|
||||||
|
* \returns \c true if both bindings are equal
|
||||||
|
*/
|
||||||
|
bool eq(const DxvkBindingInfo& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Hashes binding info
|
||||||
|
* \returns Binding hash
|
||||||
|
*/
|
||||||
|
size_t hash() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding list
|
||||||
|
*
|
||||||
|
* Linear structure that can be used to look
|
||||||
|
* up descriptor set objects.
|
||||||
|
*/
|
||||||
|
class DxvkBindingList {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBindingList();
|
||||||
|
~DxvkBindingList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of Vulkan bindings
|
||||||
|
* \returns Binding count
|
||||||
|
*/
|
||||||
|
uint32_t getBindingCount() const {
|
||||||
|
return uint32_t(m_bindings.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves binding info
|
||||||
|
*
|
||||||
|
* \param [in] idx Binding index
|
||||||
|
* \returns Binding info
|
||||||
|
*/
|
||||||
|
const DxvkBindingInfo& getBinding(uint32_t index) const {
|
||||||
|
return m_bindings[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds a binding to the list
|
||||||
|
* \param [in] binding Binding info
|
||||||
|
*/
|
||||||
|
void addBinding(const DxvkBindingInfo& binding);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Merges binding lists
|
||||||
|
*
|
||||||
|
* Adds bindings from another list to the current list. Useful
|
||||||
|
* when creating descriptor set layouts for pipelines consisting
|
||||||
|
* of multiple shader stages.
|
||||||
|
* \param [in] layout Binding list to merge
|
||||||
|
*/
|
||||||
|
void merge(const DxvkBindingList& list);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks for equality
|
||||||
|
*
|
||||||
|
* \param [in] other Binding layout to compare to
|
||||||
|
* \returns \c true if both binding layouts are equal
|
||||||
|
*/
|
||||||
|
bool eq(const DxvkBindingList& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Hashes binding layout
|
||||||
|
* \returns Binding layout hash
|
||||||
|
*/
|
||||||
|
size_t hash() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<DxvkBindingInfo> m_bindings;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding set layout key entry
|
||||||
|
*
|
||||||
|
* Stores unique info for a single binding.
|
||||||
|
*/
|
||||||
|
struct DxvkBindingSetLayoutKeyEntry {
|
||||||
|
VkDescriptorType descriptorType;
|
||||||
|
VkShaderStageFlags stages;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding set layout key
|
||||||
|
*
|
||||||
|
* Stores relevant information to look
|
||||||
|
* up unique descriptor set layouts.
|
||||||
|
*/
|
||||||
|
class DxvkBindingSetLayoutKey {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBindingSetLayoutKey(const DxvkBindingList& list);
|
||||||
|
~DxvkBindingSetLayoutKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves binding count
|
||||||
|
* \returns Binding count
|
||||||
|
*/
|
||||||
|
uint32_t getBindingCount() const {
|
||||||
|
return uint32_t(m_bindings.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves binding info
|
||||||
|
*
|
||||||
|
* \param [in] index Binding index
|
||||||
|
* \returns Binding info
|
||||||
|
*/
|
||||||
|
DxvkBindingSetLayoutKeyEntry getBinding(uint32_t index) const {
|
||||||
|
return m_bindings[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks for equality
|
||||||
|
*
|
||||||
|
* \param [in] other Binding layout to compare to
|
||||||
|
* \returns \c true if both binding layouts are equal
|
||||||
|
*/
|
||||||
|
bool eq(const DxvkBindingSetLayoutKey& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Hashes binding layout
|
||||||
|
* \returns Binding layout hash
|
||||||
|
*/
|
||||||
|
size_t hash() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<DxvkBindingSetLayoutKeyEntry> m_bindings;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding list objects
|
||||||
|
*
|
||||||
|
* Manages a Vulkan descriptor set layout
|
||||||
|
* object for a given binding list.
|
||||||
|
*/
|
||||||
|
class DxvkBindingSetLayout {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBindingSetLayout(
|
||||||
|
DxvkDevice* device,
|
||||||
|
const DxvkBindingSetLayoutKey& key);
|
||||||
|
|
||||||
|
~DxvkBindingSetLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries descriptor set layout
|
||||||
|
* \returns Descriptor set layout
|
||||||
|
*/
|
||||||
|
VkDescriptorSetLayout getSetLayout() const {
|
||||||
|
return m_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries descriptor template
|
||||||
|
* \returns Descriptor set template
|
||||||
|
*/
|
||||||
|
VkDescriptorUpdateTemplate getSetUpdateTemplate() const {
|
||||||
|
return m_template;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DxvkDevice* m_device;
|
||||||
|
VkDescriptorSetLayout m_layout = VK_NULL_HANDLE;
|
||||||
|
VkDescriptorUpdateTemplate m_template = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding layout
|
||||||
|
*
|
||||||
|
* Convenience class to map out shader bindings for use in
|
||||||
|
* descriptor set layouts and pipeline layouts. If possible,
|
||||||
|
* bindings that only differ in stage will be merged.
|
||||||
|
*/
|
||||||
|
class DxvkBindingLayout {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBindingLayout();
|
||||||
|
~DxvkBindingLayout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of Vulkan bindings per set
|
||||||
|
*
|
||||||
|
* \param [in] set Descriptor set index
|
||||||
|
* \returns Binding count for the given set
|
||||||
|
*/
|
||||||
|
uint32_t getBindingCount(uint32_t set) const {
|
||||||
|
return m_bindings[set].getBindingCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves binding info
|
||||||
|
*
|
||||||
|
* \param [in] set Descriptor set index
|
||||||
|
* \param [in] idx Binding index
|
||||||
|
* \returns Binding info
|
||||||
|
*/
|
||||||
|
const DxvkBindingInfo& getBinding(uint32_t set, uint32_t idx) const {
|
||||||
|
return m_bindings[set].getBinding(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves binding list for a given set
|
||||||
|
*
|
||||||
|
* Use convenience methods above to gather info about
|
||||||
|
* individual descriptors. This is intended to be used
|
||||||
|
* for descriptor set lookup primarily.
|
||||||
|
*/
|
||||||
|
const DxvkBindingList& getBindingList(uint32_t set) const {
|
||||||
|
return m_bindings[set];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves push constant range
|
||||||
|
* \returns Push constant range
|
||||||
|
*/
|
||||||
|
VkPushConstantRange getPushConstantRange() const {
|
||||||
|
return m_pushConst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds a binding to the layout
|
||||||
|
* \param [in] binding Binding info
|
||||||
|
*/
|
||||||
|
void addBinding(const DxvkBindingInfo& binding);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Adds push constant range
|
||||||
|
* \param [in] range Push constant range
|
||||||
|
*/
|
||||||
|
void addPushConstantRange(VkPushConstantRange range);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Merges binding layouts
|
||||||
|
*
|
||||||
|
* Adds bindings and push constant range from another layout to
|
||||||
|
* the current layout. Useful when creating pipeline layouts and
|
||||||
|
* descriptor set layouts for pipelines consisting of multiple
|
||||||
|
* shader stages.
|
||||||
|
* \param [in] layout Binding layout to merge
|
||||||
|
*/
|
||||||
|
void merge(const DxvkBindingLayout& layout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Checks for equality
|
||||||
|
*
|
||||||
|
* \param [in] other Binding layout to compare to
|
||||||
|
* \returns \c true if both binding layouts are equal
|
||||||
|
*/
|
||||||
|
bool eq(const DxvkBindingLayout& other) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Hashes binding layout
|
||||||
|
* \returns Binding layout hash
|
||||||
|
*/
|
||||||
|
size_t hash() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::array<DxvkBindingList, DxvkDescriptorSets::SetCount> m_bindings;
|
||||||
|
VkPushConstantRange m_pushConst;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Descriptor set and binding number
|
||||||
|
*/
|
||||||
|
struct DxvkBindingMapping {
|
||||||
|
uint32_t set;
|
||||||
|
uint32_t binding;
|
||||||
|
uint32_t constId;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pipeline and descriptor set layouts for a given binding layout
|
||||||
|
*
|
||||||
|
* Creates the following Vulkan objects for a given binding layout:
|
||||||
|
* - A descriptor set layout for each required descriptor set
|
||||||
|
* - A descriptor update template for each set with non-zero binding count
|
||||||
|
* - A pipeline layout referencing all descriptor sets and the push constant ranges
|
||||||
|
*/
|
||||||
|
class DxvkBindingLayoutObjects {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DxvkBindingLayoutObjects(
|
||||||
|
DxvkDevice* device,
|
||||||
|
const DxvkBindingLayout& layout,
|
||||||
|
const DxvkBindingSetLayout** setObjects);
|
||||||
|
|
||||||
|
~DxvkBindingLayoutObjects();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Binding layout
|
||||||
|
* \returns Binding layout
|
||||||
|
*/
|
||||||
|
const DxvkBindingLayout& layout() const {
|
||||||
|
return m_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries active descriptor set mask
|
||||||
|
* \returns Bit mask of non-empty descriptor sets
|
||||||
|
*/
|
||||||
|
uint32_t getSetMask() const {
|
||||||
|
return m_setMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries first binding number for a given set
|
||||||
|
*
|
||||||
|
* This is relevant for generating binding masks.
|
||||||
|
* \param [in] set Descriptor set index
|
||||||
|
* \returns First binding in the given set
|
||||||
|
*/
|
||||||
|
uint32_t getFirstBinding(uint32_t set) const {
|
||||||
|
return m_bindingOffsets[set];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves descriptor set layout for a given set
|
||||||
|
*
|
||||||
|
* \param [in] set Descriptor set index
|
||||||
|
* \returns Vulkan descriptor set layout
|
||||||
|
*/
|
||||||
|
VkDescriptorSetLayout getSetLayout(uint32_t set) const {
|
||||||
|
return m_bindingObjects[set]->getSetLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves descriptor update template for a given set
|
||||||
|
*
|
||||||
|
* \param [in] set Descriptor set index
|
||||||
|
* \returns Vulkan descriptor update template
|
||||||
|
*/
|
||||||
|
VkDescriptorUpdateTemplate getSetUpdateTemplate(uint32_t set) const {
|
||||||
|
return m_bindingObjects[set]->getSetUpdateTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Retrieves pipeline layout
|
||||||
|
* \returns Pipeline layout
|
||||||
|
*/
|
||||||
|
VkPipelineLayout getPipelineLayout() const {
|
||||||
|
return m_pipelineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Looks up set and binding number by resource binding
|
||||||
|
*
|
||||||
|
* \param [in] index Resource binding index
|
||||||
|
* \returns Descriptor set and binding number
|
||||||
|
*/
|
||||||
|
std::optional<DxvkBindingMapping> lookupBinding(uint32_t index) const {
|
||||||
|
auto entry = m_mapping.find(index);
|
||||||
|
|
||||||
|
if (entry != m_mapping.end())
|
||||||
|
return entry->second;
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Queries accumulated resource access flags
|
||||||
|
*
|
||||||
|
* Can be used to determine whether the pipeline
|
||||||
|
* reads or writes any resources.
|
||||||
|
*/
|
||||||
|
VkAccessFlags getAccessFlags() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
DxvkDevice* m_device;
|
||||||
|
DxvkBindingLayout m_layout;
|
||||||
|
VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
uint32_t m_setMask = 0;
|
||||||
|
|
||||||
|
std::array<const DxvkBindingSetLayout*, DxvkDescriptorSets::SetCount> m_bindingObjects = { };
|
||||||
|
std::array<uint32_t, DxvkDescriptorSets::SetCount> m_bindingOffsets = { };
|
||||||
|
|
||||||
|
std::unordered_map<uint32_t, DxvkBindingMapping> m_mapping;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Resource slot
|
* \brief Resource slot
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user