From 2f556366268ec9273364521afd53afa68f07cb99 Mon Sep 17 00:00:00 2001 From: TheTurtle Date: Sat, 15 Nov 2025 07:44:25 +0200 Subject: [PATCH] vk_rasterizer: Attempt to optimize compute clears (#3795) --- src/video_core/buffer_cache/buffer_cache.cpp | 2 +- .../renderer_vulkan/vk_rasterizer.cpp | 63 ++++++++++++++++++- .../renderer_vulkan/vk_rasterizer.h | 1 + 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 04c473f1b..cb18bc190 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -889,7 +889,7 @@ bool BufferCache::SynchronizeBuffer(Buffer& buffer, VAddr device_addr, u32 size, }); TouchBuffer(buffer); } - if (is_texel_buffer) { + if (is_texel_buffer && !is_written) { return SynchronizeBufferFromImage(buffer, device_addr, size); } return false; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index a47c523e1..37b8051e8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -380,7 +380,8 @@ void Rasterizer::OnSubmit() { } bool Rasterizer::BindResources(const Pipeline* pipeline) { - if (IsComputeImageCopy(pipeline) || IsComputeMetaClear(pipeline)) { + if (IsComputeImageCopy(pipeline) || IsComputeMetaClear(pipeline) || + IsComputeImageClear(pipeline)) { return false; } @@ -520,6 +521,66 @@ bool Rasterizer::IsComputeImageCopy(const Pipeline* pipeline) { return true; } +bool Rasterizer::IsComputeImageClear(const Pipeline* pipeline) { + if (!pipeline->IsCompute()) { + return false; + } + + // Ensure shader only has 2 bound buffers + const auto& cs_pgm = liverpool->GetCsRegs(); + const auto& info = pipeline->GetStage(Shader::LogicalStage::Compute); + if (cs_pgm.num_thread_x.full != 64 || info.buffers.size() != 2 || !info.images.empty()) { + return false; + } + + // From those 2 buffers, first must hold the clear vector and second the image being cleared + const auto& desc0 = info.buffers[0]; + const auto& desc1 = info.buffers[1]; + if (desc0.is_formatted || !desc1.is_formatted || desc0.is_written || !desc1.is_written) { + return false; + } + + // First buffer must have size of vec4 and second the size of a single layer + const AmdGpu::Buffer buf0 = desc0.GetSharp(info); + const AmdGpu::Buffer buf1 = desc1.GetSharp(info); + const u32 buf1_bpp = AmdGpu::NumBitsPerBlock(buf1.GetDataFmt()); + if (buf0.GetSize() != 16 || (cs_pgm.dim_x * 128ULL * (buf1_bpp / 8)) != buf1.GetSize()) { + return false; + } + + // Find image the buffer alias + const auto image1_id = + texture_cache.FindImageFromRange(buf1.base_address, buf1.GetSize(), false); + if (!image1_id) { + return false; + } + + // Image clear must be valid + VideoCore::Image& image1 = texture_cache.GetImage(image1_id); + if (image1.info.guest_size != buf1.GetSize() || image1.info.num_bits != buf1_bpp || + image1.info.props.is_depth) { + return false; + } + + // Perform image clear + const float* values = reinterpret_cast(buf0.base_address); + const vk::ClearValue clear = { + .color = {.float32 = std::array{values[0], values[1], values[2], values[3]}}, + }; + const VideoCore::SubresourceRange range = { + .base = + { + .level = 0, + .layer = 0, + }, + .extent = image1.info.resources, + }; + image1.Clear(clear, range); + image1.flags |= VideoCore::ImageFlagBits::GpuModified; + image1.flags &= ~VideoCore::ImageFlagBits::Dirty; + return true; +} + void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Bindings& binding, Shader::PushData& push_data) { buffer_bindings.clear(); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 524a8f06d..96a3c95e8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -112,6 +112,7 @@ private: bool IsComputeMetaClear(const Pipeline* pipeline); bool IsComputeImageCopy(const Pipeline* pipeline); + bool IsComputeImageClear(const Pipeline* pipeline); private: friend class VideoCore::BufferCache;