diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 1c91992ab..9f9a4c251 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -3672,46 +3672,35 @@ namespace dxvk { void DxvkContext::updateVertexBufferBindings() { if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) { m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers); + + if (unlikely(!m_state.gp.state.ilBindingCount)) + return; std::array buffers; std::array offsets; // Set buffer handles and offsets for active bindings - uint32_t bindingMask = 0; - for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { uint32_t binding = m_state.gp.state.ilBindings[i].binding; - bindingMask |= 1u << binding; if (likely(m_state.vi.vertexBuffers[binding].defined())) { auto vbo = m_state.vi.vertexBuffers[binding].getDescriptor(); - buffers[binding] = vbo.buffer.buffer; - offsets[binding] = vbo.buffer.offset; + buffers[i] = vbo.buffer.buffer; + offsets[i] = vbo.buffer.offset; m_cmd->trackResource(m_state.vi.vertexBuffers[binding].buffer()); } else { - buffers[binding] = m_device->dummyBufferHandle(); - offsets[binding] = 0; + buffers[i] = m_device->dummyBufferHandle(); + offsets[i] = 0; } } - // Actually bind all the vertex buffers. - uint32_t bindingIndex = 0; - - while (bindingMask) { - uint32_t shift = bit::tzcnt(bindingMask); - uint32_t count = bit::tzcnt(~bindingMask >> shift); - uint32_t index = bindingIndex + shift; - - m_cmd->cmdBindVertexBuffers( - index, count, - &buffers[index], - &offsets[index]); - - bindingIndex += shift + count; - bindingMask >>= shift + count; - } + // Vertex bindigs get remapped when compiling the + // pipeline, so this actually does the right thing + m_cmd->cmdBindVertexBuffers( + 0, m_state.gp.state.ilBindingCount, + buffers.data(), offsets.data()); } } diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 23784a65f..d50fb209f 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -258,6 +258,22 @@ namespace dxvk { int32_t rasterizedStream = m_gs != nullptr ? m_gs->shaderOptions().rasterizedStream : 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.ilBindingCount; i++) { + viBindings[i] = state.ilBindings[i]; + viBindings[i].binding = i; + viBindingMap[state.ilBindings[i].binding] = i; + } + + for (uint32_t i = 0; i < state.ilAttributeCount; i++) { + viAttribs[i] = state.ilAttributes[i]; + viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding]; + } VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo; viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; @@ -270,9 +286,9 @@ namespace dxvk { viInfo.pNext = &viDivisorInfo; viInfo.flags = 0; viInfo.vertexBindingDescriptionCount = state.ilBindingCount; - viInfo.pVertexBindingDescriptions = state.ilBindings; + viInfo.pVertexBindingDescriptions = viBindings.data(); viInfo.vertexAttributeDescriptionCount = state.ilAttributeCount; - viInfo.pVertexAttributeDescriptions = state.ilAttributes; + viInfo.pVertexAttributeDescriptions = viAttribs.data(); if (viDivisorCount == 0) viInfo.pNext = viDivisorInfo.pNext;