From e03ec6a9dc4def4598186b7cf02a9c25465cf8d3 Mon Sep 17 00:00:00 2001
From: Alyssa Rosenzweig <alyssa@rosenzweig.io>
Date: Tue, 11 Mar 2025 12:18:14 -0400
Subject: [PATCH] hk: fix unaligned copies

Fixes regression in Deus Ex: Human Revolution (DX11) via DXVK reported by James
Calligeros.

Pending CTS coverage: https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/5640

Only the alignment check here is load bearing but I clarified the logic while at
it.

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
---
 src/asahi/vulkan/hk_cmd_meta.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/asahi/vulkan/hk_cmd_meta.c b/src/asahi/vulkan/hk_cmd_meta.c
index 96e91f37117ef..c9bb25ea1f86b 100644
--- a/src/asahi/vulkan/hk_cmd_meta.c
+++ b/src/asahi/vulkan/hk_cmd_meta.c
@@ -1382,13 +1382,23 @@ hk_meta_resolve_rendering(struct hk_cmd_buffer *cmd,
 static void
 hk_cmd_copy(struct hk_cmd_buffer *cmd, uint64_t dst, uint64_t src, size_t size)
 {
-   if (size / 16) {
-      libagx_copy_uint4(cmd, agx_1d(size / 16), AGX_BARRIER_ALL, dst, src);
+   /* Use vectorized copies for as much of the buffer as possible. This requires
+    * that dst, src, and size are all properly aligned. Failing to check for
+    * alignment on the buffers causes subtle and hard-to-debug issues!
+    */
+   if (size >= 16 && (dst & 0xf) == 0 && (src & 0xf) == 0) {
+      unsigned uint4s = size / 16;
+      unsigned bytes = uint4s * 16;
+
+      libagx_copy_uint4(cmd, agx_1d(uint4s), AGX_BARRIER_ALL, dst, src);
+
+      dst += bytes;
+      src += bytes;
+      size -= bytes;
    }
 
-   if (size % 16) {
-      libagx_copy_uchar(cmd, agx_1d(size % 16), AGX_BARRIER_ALL,
-                        dst + (size & ~15), src + (size & ~15));
+   if (size) {
+      libagx_copy_uchar(cmd, agx_1d(size), AGX_BARRIER_ALL, dst, src);
    }
 }
 
-- 
GitLab