mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[dxvk] Compact vertex buffer bindings
This way, we can always update all vertex buffer bindings with one single API call, without having to deal with any gaps in binding IDs. The previous optimization triggers a bug in some drivers when no vertex buffer is ever bound to a given binding point, and may also trigger inefficient behaviour if the binding range is assumed to be contiguous.
This commit is contained in:
parent
644f33a82b
commit
0d40c20aef
@ -3673,45 +3673,34 @@ namespace dxvk {
|
||||
if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
|
||||
m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
|
||||
|
||||
if (unlikely(!m_state.gp.state.ilBindingCount))
|
||||
return;
|
||||
|
||||
std::array<VkBuffer, MaxNumVertexBindings> buffers;
|
||||
std::array<VkDeviceSize, MaxNumVertexBindings> 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;
|
||||
|
||||
// Vertex bindigs get remapped when compiling the
|
||||
// pipeline, so this actually does the right thing
|
||||
m_cmd->cmdBindVertexBuffers(
|
||||
index, count,
|
||||
&buffers[index],
|
||||
&offsets[index]);
|
||||
|
||||
bindingIndex += shift + count;
|
||||
bindingMask >>= shift + count;
|
||||
}
|
||||
0, m_state.gp.state.ilBindingCount,
|
||||
buffers.data(), offsets.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +259,22 @@ namespace dxvk {
|
||||
? m_gs->shaderOptions().rasterizedStream
|
||||
: 0;
|
||||
|
||||
// Compact vertex bindings so that we can more easily update vertex buffers
|
||||
std::array<VkVertexInputAttributeDescription, MaxNumVertexAttributes> viAttribs;
|
||||
std::array<VkVertexInputBindingDescription, MaxNumVertexBindings> viBindings;
|
||||
std::array<uint32_t, MaxNumVertexBindings> 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;
|
||||
viDivisorInfo.pNext = nullptr;
|
||||
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user