From 450472b51fbc53c504be2e738a8f2d5660ea7029 Mon Sep 17 00:00:00 2001 From: rainmakerv2 <30595646+rainmakerv3@users.noreply.github.com> Date: Sat, 4 Apr 2026 13:38:51 +0800 Subject: [PATCH 1/4] Update serdes.h (#4214) --- src/common/serdes.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/serdes.h b/src/common/serdes.h index f91a0ace8..a8152e95a 100644 --- a/src/common/serdes.h +++ b/src/common/serdes.h @@ -42,7 +42,8 @@ struct Archive { } void Advance(size_t size) { - ASSERT(offset + size <= container.size()); + ASSERT_MSG(offset + size <= container.size(), + "Invalid or corrupted deserialization container/shader cache"); offset += size; } @@ -104,7 +105,8 @@ struct Writer { struct Reader { template void Read(T* ptr, size_t size) { - ASSERT(ar.offset + size <= ar.container.size()); + ASSERT_MSG(ar.offset + size <= ar.container.size(), + "Invalid or corrupted deserialization container/shader cache"); std::memcpy(reinterpret_cast(ptr), ar.CurrPtr(), size); ar.Advance(size); } From 73520ae094a502d2d3992b627ea0f17eb8b17900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Miko=C5=82ajczyk?= Date: Sat, 4 Apr 2026 12:02:44 +0200 Subject: [PATCH 2/4] GS fixes (#4213) * Handle S_BFM_I32 in a copy shader * GS: set dwords_per_vertex based on the number of buffer loads if different from VERT_ITEMSIZE --- src/shader_recompiler/frontend/copy_shader.cpp | 9 +++++++++ src/shader_recompiler/frontend/copy_shader.h | 1 + .../ir/passes/ring_access_elimination.cpp | 9 ++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/shader_recompiler/frontend/copy_shader.cpp b/src/shader_recompiler/frontend/copy_shader.cpp index 795003e43..ff3045b86 100644 --- a/src/shader_recompiler/frontend/copy_shader.cpp +++ b/src/shader_recompiler/frontend/copy_shader.cpp @@ -45,6 +45,14 @@ CopyShaderData ParseCopyShader(std::span code) { sources[inst.dst[0].code] += inst.control.sopk.simm; break; } + case Gcn::Opcode::S_BFM_B32: { + ASSERT(inst.src[0].field == Gcn::OperandField::SignedConstIntPos && + inst.src[1].field == Gcn::OperandField::SignedConstIntPos); + const auto src0 = inst.src[0].code - Gcn::OperandFieldRange::SignedConstIntPosMin + 1; + const auto src1 = inst.src[1].code - Gcn::OperandFieldRange::SignedConstIntPosMin + 1; + sources[inst.dst[0].code] = ((1 << src0) - 1) << src1; + break; + } case Gcn::Opcode::EXP: { const auto& exp = inst.control.exp; const IR::Attribute semantic = static_cast(exp.target); @@ -71,6 +79,7 @@ CopyShaderData ParseCopyShader(std::span code) { ASSERT(sources[index] != -1); offsets[inst.src[1].code] += sources[index]; } + data.num_comps++; break; } default: diff --git a/src/shader_recompiler/frontend/copy_shader.h b/src/shader_recompiler/frontend/copy_shader.h index 24c7060ed..c416bde99 100644 --- a/src/shader_recompiler/frontend/copy_shader.h +++ b/src/shader_recompiler/frontend/copy_shader.h @@ -15,6 +15,7 @@ struct CopyShaderData { std::map> attr_map; u32 num_attrs{0}; u32 output_vertices{0}; + u32 num_comps{0}; }; CopyShaderData ParseCopyShader(std::span code); diff --git a/src/shader_recompiler/ir/passes/ring_access_elimination.cpp b/src/shader_recompiler/ir/passes/ring_access_elimination.cpp index f8818b622..a7a23a726 100644 --- a/src/shader_recompiler/ir/passes/ring_access_elimination.cpp +++ b/src/shader_recompiler/ir/passes/ring_access_elimination.cpp @@ -104,6 +104,13 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim output_vertices, info.gs_copy_data.output_vertices); output_vertices = info.gs_copy_data.output_vertices; } + u32 dwords_per_vertex = gs_info.out_vertex_data_size; + if (info.gs_copy_data.num_comps && info.gs_copy_data.num_comps != dwords_per_vertex) { + LOG_WARNING(Render_Vulkan, + "VERT_ITEMSIZE {} is different than actual number of dwords per vertex {}", + dwords_per_vertex, info.gs_copy_data.num_comps); + dwords_per_vertex = info.gs_copy_data.num_comps; + } ForEachInstruction([&](IR::IREmitter& ir, IR::Inst& inst) { const auto opcode = inst.GetOpcode(); @@ -139,7 +146,7 @@ void RingAccessElimination(const IR::Program& program, const RuntimeInfo& runtim const auto offset = inst.Flags().inst_offset.Value(); const auto data = ir.BitCast(IR::U32{inst.Arg(2)}); const auto comp_ofs = output_vertices * 4u; - const auto output_size = comp_ofs * gs_info.out_vertex_data_size; + const auto output_size = comp_ofs * dwords_per_vertex; const auto vc_read_ofs = (((offset / comp_ofs) * comp_ofs) % output_size) * 16u; const auto& it = info.gs_copy_data.attr_map.find(vc_read_ofs); From b365d5fe7819d4d0231fb74561e725e136090a28 Mon Sep 17 00:00:00 2001 From: Niram7777 Date: Sat, 4 Apr 2026 20:57:22 +0200 Subject: [PATCH 3/4] Vulkan device destroy DescriptorPool on Shutdown (#4217) Validation Error: [ VUID-vkDestroyDevice-device-05137 ] | MessageID = 0x4872eaa0 vkDestroyDevice(): Object Tracking - For VkDevice 0x55ac6bd22670, VkDescriptorPool 0x300000000030 has not been destroyed. The Vulkan spec states: All child objects created on device that can be destroyed or freed must have been destroyed or freed prior to destroying device (https://docs.vulkan.org/spec/latest/chapters/devsandqueues.html#VUID-vkDestroyDevice-device-05137) Objects: 1 [0] VkDescriptorPool 0x300000000030 --- src/imgui/renderer/imgui_impl_vulkan.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/imgui/renderer/imgui_impl_vulkan.cpp b/src/imgui/renderer/imgui_impl_vulkan.cpp index 97f44c318..0ef1d263d 100644 --- a/src/imgui/renderer/imgui_impl_vulkan.cpp +++ b/src/imgui/renderer/imgui_impl_vulkan.cpp @@ -1219,6 +1219,10 @@ void ImGuiImplVulkanDestroyDeviceObjects() { v.device.destroyDescriptorSetLayout(bd->descriptor_set_layout, v.allocator); bd->descriptor_set_layout = VK_NULL_HANDLE; } + if (bd->descriptor_pool) { + v.device.destroyDescriptorPool(bd->descriptor_pool, v.allocator); + bd->descriptor_pool = VK_NULL_HANDLE; + } if (bd->pipeline_layout) { v.device.destroyPipelineLayout(bd->pipeline_layout, v.allocator); bd->pipeline_layout = VK_NULL_HANDLE; From fb067bc43fbf69e39c708129c3a753f82d0b5c78 Mon Sep 17 00:00:00 2001 From: Niram7777 Date: Sat, 4 Apr 2026 21:30:28 +0200 Subject: [PATCH 4/4] Vulkan device destroy images_view on Swapchain::Destroy (#4218) --- src/video_core/renderer_vulkan/vk_swapchain.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 04f9d8504..4904319bd 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -261,6 +261,12 @@ void Swapchain::Destroy() { LOG_WARNING(Render_Vulkan, "Failed to wait for device to become idle: {}", vk::to_string(wait_result)); } + + for (auto& image_view : images_view) { + device.destroyImageView(image_view); + } + images_view.clear(); + if (swapchain) { device.destroySwapchainKHR(swapchain); }