1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-31 14: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() { void DxvkContext::updateVertexBufferBindings() {
if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) { if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers); m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
if (unlikely(!m_state.gp.state.ilBindingCount))
return;
std::array<VkBuffer, MaxNumVertexBindings> buffers; std::array<VkBuffer, MaxNumVertexBindings> buffers;
std::array<VkDeviceSize, MaxNumVertexBindings> offsets; std::array<VkDeviceSize, MaxNumVertexBindings> offsets;
// Set buffer handles and offsets for active bindings // Set buffer handles and offsets for active bindings
uint32_t bindingMask = 0;
for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) { for (uint32_t i = 0; i < m_state.gp.state.ilBindingCount; i++) {
uint32_t binding = m_state.gp.state.ilBindings[i].binding; uint32_t binding = m_state.gp.state.ilBindings[i].binding;
bindingMask |= 1u << binding;
if (likely(m_state.vi.vertexBuffers[binding].defined())) { if (likely(m_state.vi.vertexBuffers[binding].defined())) {
auto vbo = m_state.vi.vertexBuffers[binding].getDescriptor(); auto vbo = m_state.vi.vertexBuffers[binding].getDescriptor();
buffers[binding] = vbo.buffer.buffer; buffers[i] = vbo.buffer.buffer;
offsets[binding] = vbo.buffer.offset; offsets[i] = vbo.buffer.offset;
m_cmd->trackResource(m_state.vi.vertexBuffers[binding].buffer()); m_cmd->trackResource(m_state.vi.vertexBuffers[binding].buffer());
} else { } else {
buffers[binding] = m_device->dummyBufferHandle(); buffers[i] = m_device->dummyBufferHandle();
offsets[binding] = 0; offsets[i] = 0;
} }
} }
// Actually bind all the vertex buffers. // Vertex bindigs get remapped when compiling the
uint32_t bindingIndex = 0; // pipeline, so this actually does the right thing
m_cmd->cmdBindVertexBuffers(
while (bindingMask) { 0, m_state.gp.state.ilBindingCount,
uint32_t shift = bit::tzcnt(bindingMask); buffers.data(), offsets.data());
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;
}
} }
} }

View File

@ -258,6 +258,22 @@ namespace dxvk {
int32_t rasterizedStream = m_gs != nullptr int32_t rasterizedStream = m_gs != nullptr
? m_gs->shaderOptions().rasterizedStream ? m_gs->shaderOptions().rasterizedStream
: 0; : 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; VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo;
viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
@ -270,9 +286,9 @@ namespace dxvk {
viInfo.pNext = &viDivisorInfo; viInfo.pNext = &viDivisorInfo;
viInfo.flags = 0; viInfo.flags = 0;
viInfo.vertexBindingDescriptionCount = state.ilBindingCount; viInfo.vertexBindingDescriptionCount = state.ilBindingCount;
viInfo.pVertexBindingDescriptions = state.ilBindings; viInfo.pVertexBindingDescriptions = viBindings.data();
viInfo.vertexAttributeDescriptionCount = state.ilAttributeCount; viInfo.vertexAttributeDescriptionCount = state.ilAttributeCount;
viInfo.pVertexAttributeDescriptions = state.ilAttributes; viInfo.pVertexAttributeDescriptions = viAttribs.data();
if (viDivisorCount == 0) if (viDivisorCount == 0)
viInfo.pNext = viDivisorInfo.pNext; viInfo.pNext = viDivisorInfo.pNext;