From 47b9fd8b197146cee0ff3045413f0f1652c5f76f Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 9 May 2018 13:01:52 +0200 Subject: [PATCH] [dxvk] Reimplement vertex buffer bindings Reduces the number of Vulkan calls for vertex buffer bindings and works around incorrect validation errors emitted when applications do not use a consecutive range of vertex bindings. No performance impact is expected in most games. --- src/dxvk/dxvk_context.cpp | 42 +++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 7ff4b378..0d50a325 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1945,29 +1945,51 @@ namespace dxvk { if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) { m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers); - uint32_t bindingMask = 0; + std::array buffers; + std::array offsets; + + // Set buffer handles and offsets for active bindings + uint32_t bindingCount = 0; + uint32_t bindingMask = 0; for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { const uint32_t binding = m_state.gp.state.ilBindings[i].binding; + bindingCount = std::max(bindingCount, binding + 1); if (m_state.vi.vertexBuffers[binding].defined()) { auto vbo = m_state.vi.vertexBuffers[binding].physicalSlice(); - const VkBuffer handle = vbo.handle(); - const VkDeviceSize offset = vbo.offset(); - - m_cmd->cmdBindVertexBuffers(binding, 1, &handle, &offset); - m_cmd->trackResource(vbo.resource()); + buffers[binding] = vbo.handle(); + offsets[binding] = vbo.offset(); bindingMask |= 1u << binding; - } else { - const VkBuffer handle = m_device->dummyBufferHandle(); - const VkDeviceSize offset = 0; - m_cmd->cmdBindVertexBuffers(binding, 1, &handle, &offset); + m_cmd->trackResource(vbo.resource()); } } + // Bind a dummy buffer to the remaining bindings + uint32_t bindingsUsed = (1u << bindingCount) - 1u; + uint32_t bindingsSet = bindingMask; + + while (bindingsSet != bindingsUsed) { + uint32_t binding = tzcnt(~bindingsSet); + + buffers[binding] = m_device->dummyBufferHandle(); + offsets[binding] = 0; + + bindingsSet |= 1u << binding; + } + + // Bind all vertex buffers at once + if (bindingCount != 0) { + m_cmd->cmdBindVertexBuffers(0, bindingCount, + buffers.data(), offsets.data()); + } + + // If the set of active bindings has changed, we'll + // need to adjust the strides of the inactive ones + // and compile a new pipeline if (m_state.vi.bindingMask != bindingMask) { m_flags.set(DxvkContextFlag::GpDirtyPipelineState); m_state.vi.bindingMask = bindingMask;