aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/renderer_vulkan/vk_rasterizer.cpp
diff options
context:
space:
mode:
authorMako <137927095+Takoroka@users.noreply.github.com>2026-11-02 02:38:47 -0500
committerGitHub <noreply@github.com>2026-11-02 08:38:47 +0100
commite38b738b84eb671b7567a37b4932f11a58843dad (patch)
tree6b7ceef02e90971a052b79d9972994413d1ef46f /src/video_core/renderer_vulkan/vk_rasterizer.cpp
parente0f348ec127964762c81e1a4f77e290d0bfa8f96 (diff)
vulkan: repack 69-byte vertices to 72 bytes (#281)
Splatoon Raiders draws with a 69-byte vertex stride and a packed 4-byte attribute at byte 65. Those fetches are unaligned, which Vulkan leaves undefined: NVIDIA reads them as meant, the AMD Windows driver does not, and the outdoor scenes turn into a white haze with horizontal streaks. When a binding uses that layout, a compute pass copies it to a 72-byte stride with the tail moved to byte 68, and the vertex input offsets and stride follow. EGLANTINE_TEST_VERTEX_REPACK=0 turns it off; EGLANTINE_EXPERIMENTAL_STATIC_VERTEX_REPACK=1 also covers pipelines without dynamic vertex input. Based on an outside patch (02-portable-vertex-repacking). Changes from it: a range over the device limits skips the repack instead of throwing, and the pipeline cache version stays, so caches are kept.
Diffstat (limited to 'src/video_core/renderer_vulkan/vk_rasterizer.cpp')
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index c0e8825bac..bbb49d5432 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -282,6 +282,18 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
// update engine as channel may be different.
pipeline->SetEngine(maxwell3d, gpu_memory);
+ const u32 repack_dirty = buffer_cache_runtime.SetVertexRepackLayout(
+ maxwell3d->regs, pipeline->HasDynamicVertexInput());
+ if (repack_dirty) {
+ auto& flags = maxwell3d->dirty.flags;
+ flags[VideoCommon::Dirty::VertexBuffers] = true;
+ flags[Dirty::VertexInput] = true;
+ for (u32 binding = 0; binding < 32; ++binding) {
+ if (repack_dirty & (1U << binding)) {
+ flags[VideoCommon::Dirty::VertexBuffer0 + binding] = true;
+ }
+ }
+ }
if (Profile::Scope scope{Profile::Zone::Configure}; !pipeline->Configure(is_indexed)) {
report_failure("configure failed");
return;
@@ -2269,7 +2281,8 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
.location = index,
.binding = binding,
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
- .offset = attribute.offset,
+ .offset = attribute.offset +
+ (buffer_cache_runtime.IsVertexRepacked(binding) && attribute.offset >= 65 ? 3 : 0),
});
}
@@ -2280,7 +2293,7 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
.pNext = nullptr,
.binding = binding,
- .stride = input_binding.stride,
+ .stride = buffer_cache_runtime.IsVertexRepacked(binding) ? 72U : input_binding.stride.Value(),
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
.divisor = is_instanced ? input_binding.frequency : 1,
});