1
0
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:
Philip Rebohle 2019-05-08 03:37:49 +02:00
parent 644f33a82b
commit 0d40c20aef
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 30 additions and 25 deletions

View File

@ -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<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;
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());
}
}

View File

@ -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<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;
@ -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;