From 7ae49cd06aa6466922c77026d3cbedfb30034b88 Mon Sep 17 00:00:00 2001 From: IndecisiveTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Tue, 15 Jul 2025 22:07:12 +0300 Subject: [PATCH] vk_rasterizer: Use xor as heuristic for HTILE clear --- src/shader_recompiler/frontend/instruction.h | 2 -- src/shader_recompiler/info.h | 1 + .../ir/passes/shader_info_collection_pass.cpp | 3 +++ .../renderer_vulkan/vk_rasterizer.cpp | 19 ++++++++++++++----- src/video_core/texture_cache/texture_cache.h | 4 ++++ 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/shader_recompiler/frontend/instruction.h b/src/shader_recompiler/frontend/instruction.h index 7c2e0bd1e..f4e7bc9f2 100644 --- a/src/shader_recompiler/frontend/instruction.h +++ b/src/shader_recompiler/frontend/instruction.h @@ -3,8 +3,6 @@ #pragma once -#include -#include "common/bit_field.h" #include "shader_recompiler/frontend/opcodes.h" namespace Shader::Gcn { diff --git a/src/shader_recompiler/info.h b/src/shader_recompiler/info.h index bb5c88584..11dd9c05e 100644 --- a/src/shader_recompiler/info.h +++ b/src/shader_recompiler/info.h @@ -222,6 +222,7 @@ struct Info { VAddr pgm_base; bool has_storage_images{}; bool has_discard{}; + bool has_bitwise_xor{}; bool has_image_gather{}; bool has_image_query{}; bool uses_buffer_atomic_float_min_max{}; diff --git a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp index 079827866..8f0e61da2 100644 --- a/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp +++ b/src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp @@ -95,6 +95,9 @@ void Visit(Info& info, const IR::Inst& inst) { case IR::Opcode::DiscardCond: info.has_discard = true; break; + case IR::Opcode::BitwiseXor32: + info.has_bitwise_xor = true; + break; case IR::Opcode::ImageGather: case IR::Opcode::ImageGatherDref: info.has_image_gather = true; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index b6130e873..c5f894b10 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -503,9 +503,13 @@ bool Rasterizer::IsComputeMetaClear(const Pipeline* pipeline) { return false; } + // Most of the time when a metadata is updated with a shader it gets cleared. It means + // we can skip the whole dispatch and update the tracked state instead. Also, it is not + // intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we + // will need its full emulation anyways. const auto& info = pipeline->GetStage(Shader::LogicalStage::Compute); - // Assume if a shader reads and writes metas at the same time, it is a copy shader. + // Assume if a shader reads metadata, it is a copy shader. for (const auto& desc : info.buffers) { const VAddr address = desc.GetSharp(info).base_address; if (!desc.IsSpecial() && !desc.is_written && texture_cache.IsMeta(address)) { @@ -513,10 +517,15 @@ bool Rasterizer::IsComputeMetaClear(const Pipeline* pipeline) { } } - // Most of the time when a metadata is updated with a shader it gets cleared. It means - // we can skip the whole dispatch and update the tracked state instead. Also, it is not - // intended to be consumed and in such rare cases (e.g. HTile introspection, CRAA) we - // will need its full emulation anyways. + // Metadata surfaces are tiled and thus need address calculation to be written properly. + // If a shader wants to encode HTILE, for example, from a depth image it will have to compute + // proper tile address from dispatch invocation id. This address calculation contains an xor + // operation so use it as a heuristic for metadata writes that are probably not clears. + if (info.has_bitwise_xor) { + return false; + } + + // Assume if a shader writes metadata without address calculation, it is a clear shader. for (const auto& desc : info.buffers) { const VAddr address = desc.GetSharp(info).base_address; if (!desc.IsSpecial() && desc.is_written && texture_cache.ClearMeta(address)) { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index ff8ffb61c..9a9679c0a 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -161,10 +161,12 @@ public: /// Registers an image view for provided image ImageView& RegisterImageView(ImageId image_id, const ImageViewInfo& view_info); + /// Returns true if the specified address is a metadata surface. bool IsMeta(VAddr address) const { return surface_metas.contains(address); } + /// Returns true if a slice of the specified metadata surface has been cleared. bool IsMetaCleared(VAddr address, u32 slice) const { const auto& it = surface_metas.find(address); if (it != surface_metas.end()) { @@ -173,6 +175,7 @@ public: return false; } + /// Clears all slices of the specified metadata surface. bool ClearMeta(VAddr address) { auto it = surface_metas.find(address); if (it != surface_metas.end()) { @@ -182,6 +185,7 @@ public: return false; } + /// Updates the state of a slice of the specified metadata surface. bool TouchMeta(VAddr address, u32 slice, bool is_clear) { auto it = surface_metas.find(address); if (it != surface_metas.end()) {