[Vulkan] Use vertex_fetch_bitmap instead of vertex_bindings()

Avoids using cached/stale vertex binding indices
This commit is contained in:
Herman S.
2025-11-03 00:29:25 +09:00
parent 16f842038b
commit ec5816a278

View File

@@ -2516,10 +2516,21 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
// Ensure vertex buffers are resident. // Ensure vertex buffers are resident.
// TODO(Triang3l): Cache residency for ranges in a way similar to how texture // TODO(Triang3l): Cache residency for ranges in a way similar to how texture
// validity is tracked. // validity is tracked.
//
// Use the vertex_fetch_bitmap instead of vertex_bindings() to avoid using
// cached/stale vertex binding indices. The bitmap is populated during shader
// translation and represents which fetch constant indices the shader actually
// references, allowing us to check the current register values at draw time.
const Shader::ConstantRegisterMap& constant_map_vertex =
vertex_shader->constant_register_map();
uint64_t vertex_buffers_resident[2] = {}; uint64_t vertex_buffers_resident[2] = {};
for (const Shader::VertexBinding& vertex_binding : for (uint32_t i = 0; i < xe::countof(constant_map_vertex.vertex_fetch_bitmap);
vertex_shader->vertex_bindings()) { ++i) {
uint32_t vfetch_index = vertex_binding.fetch_constant; uint32_t vfetch_bits_remaining = constant_map_vertex.vertex_fetch_bitmap[i];
uint32_t j;
while (xe::bit_scan_forward(vfetch_bits_remaining, &j)) {
vfetch_bits_remaining = xe::clear_lowest_bit(vfetch_bits_remaining);
uint32_t vfetch_index = i * 32 + j;
if (vertex_buffers_resident[vfetch_index >> 6] & if (vertex_buffers_resident[vfetch_index >> 6] &
(uint64_t(1) << (vfetch_index & 63))) { (uint64_t(1) << (vfetch_index & 63))) {
continue; continue;
@@ -2541,15 +2552,35 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1); vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false; return false;
default: default:
// Type is kTexture (2) or kInvalidTexture (3) - completely wrong for
// vertex data
if (cvars::gpu_allow_invalid_fetch_constants) {
XELOGW( XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) is completely invalid!", "Vertex fetch constant {} ({:08X} {:08X}) has wrong type {} "
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1); "(texture fetch constant in vertex slot) - allowing due to "
"--gpu_allow_invalid_fetch_constants=true. This will likely "
"crash "
"or produce garbage!",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1,
static_cast<uint32_t>(vfetch_constant.type));
break;
}
XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) is completely invalid! "
"Type={} - this slot contains a texture fetch constant (type 2), "
"not a "
"vertex fetch constant (type 0). This may indicate the shader is "
"reading "
"from the wrong fetch constant index, or the game has a bug.",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1,
static_cast<uint32_t>(vfetch_constant.type));
return false; return false;
} }
if (!shared_memory_->RequestRange(vfetch_constant.address << 2, if (!shared_memory_->RequestRange(vfetch_constant.address << 2,
vfetch_constant.size << 2)) { vfetch_constant.size << 2)) {
XELOGE( XELOGE(
"Failed to request vertex buffer at 0x{:08X} (size {}) in the shared " "Failed to request vertex buffer at 0x{:08X} (size {}) in the "
"shared "
"memory", "memory",
vfetch_constant.address << 2, vfetch_constant.size << 2); vfetch_constant.address << 2, vfetch_constant.size << 2);
return false; return false;
@@ -2557,6 +2588,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
vertex_buffers_resident[vfetch_index >> 6] |= uint64_t(1) vertex_buffers_resident[vfetch_index >> 6] |= uint64_t(1)
<< (vfetch_index & 63); << (vfetch_index & 63);
} }
}
// Synchronize the memory pages backing memory scatter export streams, and // Synchronize the memory pages backing memory scatter export streams, and
// calculate the range that includes the streams for the buffer barrier. // calculate the range that includes the streams for the buffer barrier.