From 1e56f2b7a0dc039c1992fefa52e79970fc6aefba Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 5 Jul 2022 01:57:22 +0200 Subject: [PATCH] [dxvk] Factor out vertex input state setup --- src/dxvk/dxvk_graphics.cpp | 182 ++++++++++++++++++++++++++----------- src/dxvk/dxvk_graphics.h | 32 ++++++- 2 files changed, 160 insertions(+), 54 deletions(-) diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 597cfd19c..a45b16a9e 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -8,6 +8,131 @@ namespace dxvk { + DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState() { + + } + + + DxvkGraphicsPipelineVertexInputState::DxvkGraphicsPipelineVertexInputState( + const DxvkDevice* device, + const DxvkGraphicsPipelineStateInfo& state) { + std::array viBindingMap = { }; + + iaInfo.topology = state.ia.primitiveTopology(); + iaInfo.primitiveRestartEnable = state.ia.primitiveRestart(); + + viInfo.vertexBindingDescriptionCount = state.il.bindingCount(); + viInfo.vertexAttributeDescriptionCount = state.il.attributeCount(); + + // Process vertex bindings. We will compact binding numbers on + // the fly so that vertex buffers can be updated more easily. + for (uint32_t i = 0; i < state.il.bindingCount(); i++) { + viBindingMap[state.ilBindings[i].binding()] = i; + + viBindings[i].binding = i; + viBindings[i].stride = state.ilBindings[i].stride(); + viBindings[i].inputRate = state.ilBindings[i].inputRate(); + + if (state.ilBindings[i].inputRate() == VK_VERTEX_INPUT_RATE_INSTANCE + && state.ilBindings[i].divisor() != 1) { + uint32_t index = viDivisorInfo.vertexBindingDivisorCount++; + + viDivisors[index].binding = i; + viDivisors[index].divisor = state.ilBindings[i].divisor(); + } + } + + if (viInfo.vertexBindingDescriptionCount) + viInfo.pVertexBindingDescriptions = viBindings.data(); + + if (viDivisorInfo.vertexBindingDivisorCount) { + viDivisorInfo.pVertexBindingDivisors = viDivisors.data(); + + if (device->features().extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor) + viInfo.pNext = &viDivisorInfo; + } + + // Process vertex attributes, using binding map generated above + for (uint32_t i = 0; i < state.il.attributeCount(); i++) { + viAttributes[i].location = state.ilAttributes[i].location(); + viAttributes[i].binding = viBindingMap[state.ilAttributes[i].binding()]; + viAttributes[i].format = state.ilAttributes[i].format(); + viAttributes[i].offset = state.ilAttributes[i].offset(); + } + + if (viInfo.vertexAttributeDescriptionCount) + viInfo.pVertexAttributeDescriptions = viAttributes.data(); + } + + + bool DxvkGraphicsPipelineVertexInputState::eq(const DxvkGraphicsPipelineVertexInputState& other) const { + bool eq = iaInfo.topology == other.iaInfo.topology + && iaInfo.primitiveRestartEnable == other.iaInfo.primitiveRestartEnable + && viInfo.vertexBindingDescriptionCount == other.viInfo.vertexBindingDescriptionCount + && viInfo.vertexAttributeDescriptionCount == other.viInfo.vertexAttributeDescriptionCount + && viDivisorInfo.vertexBindingDivisorCount == other.viDivisorInfo.vertexBindingDivisorCount; + + for (uint32_t i = 0; i < viInfo.vertexBindingDescriptionCount && eq; i++) { + const auto& a = viBindings[i]; + const auto& b = other.viBindings[i]; + + eq = a.binding == b.binding + && a.stride == b.stride + && a.inputRate == b.inputRate; + } + + for (uint32_t i = 0; i < viInfo.vertexAttributeDescriptionCount && eq; i++) { + const auto& a = viAttributes[i]; + const auto& b = other.viAttributes[i]; + + eq = a.location == b.location + && a.binding == b.binding + && a.format == b.format + && a.offset == b.offset; + } + + for (uint32_t i = 0; i < viDivisorInfo.vertexBindingDivisorCount; i++) { + const auto& a = viDivisors[i]; + const auto& b = other.viDivisors[i]; + + eq = a.binding == b.binding + && a.divisor == b.divisor; + } + + return eq; + } + + + size_t DxvkGraphicsPipelineVertexInputState::hash() const { + DxvkHashState hash; + hash.add(uint32_t(iaInfo.topology)); + hash.add(uint32_t(iaInfo.primitiveRestartEnable)); + hash.add(uint32_t(viInfo.vertexBindingDescriptionCount)); + hash.add(uint32_t(viInfo.vertexAttributeDescriptionCount)); + hash.add(uint32_t(viDivisorInfo.vertexBindingDivisorCount)); + + for (uint32_t i = 0; i < viInfo.vertexBindingDescriptionCount; i++) { + hash.add(uint32_t(viBindings[i].binding)); + hash.add(uint32_t(viBindings[i].stride)); + hash.add(uint32_t(viBindings[i].inputRate)); + } + + for (uint32_t i = 0; i < viInfo.vertexAttributeDescriptionCount; i++) { + hash.add(uint32_t(viAttributes[i].location)); + hash.add(uint32_t(viAttributes[i].binding)); + hash.add(uint32_t(viAttributes[i].format)); + hash.add(uint32_t(viAttributes[i].offset)); + } + + for (uint32_t i = 0; i < viDivisorInfo.vertexBindingDivisorCount; i++) { + hash.add(uint32_t(viDivisors[i].binding)); + hash.add(uint32_t(viDivisors[i].divisor)); + } + + return hash; + } + + DxvkGraphicsPipeline::DxvkGraphicsPipeline( DxvkPipelineManager* pipeMgr, DxvkGraphicsPipelineShaders shaders, @@ -131,6 +256,8 @@ namespace dxvk { VkPipeline DxvkGraphicsPipeline::createPipeline( const DxvkGraphicsPipelineStateInfo& state) const { + const DxvkDevice* device = m_pipeMgr->m_device; + if (Logger::logLevel() <= LogLevel::Debug) { Logger::debug("Compiling graphics pipeline..."); this->logPipelineState(LogLevel::Debug, state); @@ -232,61 +359,12 @@ namespace dxvk { } } - // Generate per-instance attribute divisors - std::array viDivisorDesc; - uint32_t viDivisorCount = 0; - - for (uint32_t i = 0; i < state.il.bindingCount(); i++) { - if (state.ilBindings[i].inputRate() == VK_VERTEX_INPUT_RATE_INSTANCE - && state.ilBindings[i].divisor() != 1) { - const uint32_t id = viDivisorCount++; - - viDivisorDesc[id].binding = i; /* see below */ - viDivisorDesc[id].divisor = state.ilBindings[i].divisor(); - } - } - int32_t rasterizedStream = m_shaders.gs != nullptr ? m_shaders.gs->info().xfbRasterizedStream : 0; - - // Compact vertex bindings so that we can more easily update vertex buffers - std::array viAttribs; - std::array viBindings; - std::array viBindingMap = { }; - for (uint32_t i = 0; i < state.il.bindingCount(); i++) { - viBindings[i] = state.ilBindings[i].description(); - viBindings[i].binding = i; - viBindingMap[state.ilBindings[i].binding()] = i; - } + DxvkGraphicsPipelineVertexInputState viState(device, state); - for (uint32_t i = 0; i < state.il.attributeCount(); i++) { - viAttribs[i] = state.ilAttributes[i].description(); - viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding()]; - } - - VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT }; - viDivisorInfo.vertexBindingDivisorCount = viDivisorCount; - viDivisorInfo.pVertexBindingDivisors = viDivisorDesc.data(); - - VkPipelineVertexInputStateCreateInfo viInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, &viDivisorInfo }; - viInfo.vertexBindingDescriptionCount = state.il.bindingCount(); - viInfo.pVertexBindingDescriptions = viBindings.data(); - viInfo.vertexAttributeDescriptionCount = state.il.attributeCount(); - viInfo.pVertexAttributeDescriptions = viAttribs.data(); - - if (viDivisorCount == 0) - viInfo.pNext = viDivisorInfo.pNext; - - // TODO remove this once the extension is widely supported - if (!m_pipeMgr->m_device->features().extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor) - viInfo.pNext = viDivisorInfo.pNext; - - VkPipelineInputAssemblyStateCreateInfo iaInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; - iaInfo.topology = state.ia.primitiveTopology(); - iaInfo.primitiveRestartEnable = state.ia.primitiveRestart(); - VkPipelineTessellationStateCreateInfo tsInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; tsInfo.patchControlPoints = state.ia.patchVertexCount(); @@ -369,8 +447,8 @@ namespace dxvk { VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &rtInfo }; info.stageCount = stages.size(); info.pStages = stages.data(); - info.pVertexInputState = &viInfo; - info.pInputAssemblyState = &iaInfo; + info.pVertexInputState = &viState.viInfo; + info.pInputAssemblyState = &viState.iaInfo; info.pTessellationState = &tsInfo; info.pViewportState = &vpInfo; info.pRasterizationState = &rsInfo; diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 651c63dd2..9b106575a 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -19,6 +19,34 @@ namespace dxvk { class DxvkDevice; class DxvkPipelineManager; + /** + * \brief Vertex input info for graphics pipelines + * + * Can be used to compile dedicated vertex input pipelines for + * use in a graphics pipeline library, or as part of the data + * required to compile a full graphics pipeline. + */ + struct DxvkGraphicsPipelineVertexInputState { + DxvkGraphicsPipelineVertexInputState(); + + DxvkGraphicsPipelineVertexInputState( + const DxvkDevice* device, + const DxvkGraphicsPipelineStateInfo& state); + + VkPipelineInputAssemblyStateCreateInfo iaInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; + VkPipelineVertexInputStateCreateInfo viInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO }; + VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT }; + + std::array viBindings = { }; + std::array viDivisors = { }; + std::array viAttributes = { }; + + bool eq(const DxvkGraphicsPipelineVertexInputState& other) const; + + size_t hash() const; + }; + + /** * \brief Flags that describe pipeline properties */ @@ -68,8 +96,8 @@ namespace dxvk { return shader == nullptr || shader->info().stage == stage; } }; - - + + /** * \brief Common graphics pipeline state *