From 505e80e756bbc29e33c4c9bd7fdd0a45487f9662 Mon Sep 17 00:00:00 2001 From: squidbus <175574877+squidbus@users.noreply.github.com> Date: Tue, 30 Sep 2025 06:17:22 -0700 Subject: [PATCH] video_core: Fix some image copy and buffer offset validation errors. (#3673) --- .../renderer_vulkan/vk_rasterizer.cpp | 11 +++++------ src/video_core/texture_cache/image.cpp | 17 ++++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 33bec3083..7dfef59a8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -541,6 +541,8 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding const auto& [buffer_id, vsharp, size] = buffer_bindings[i]; const auto& desc = stage.buffers[i]; const bool is_storage = desc.IsStorage(vsharp, pipeline_cache.GetProfile()); + const u32 alignment = + is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment(); // Buffer is not from the cache, either a special buffer or unbound. if (!buffer_id) { if (desc.buffer_type == Shader::BufferType::GdsBuffer) { @@ -549,8 +551,8 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding } else if (desc.buffer_type == Shader::BufferType::Flatbuf) { auto& vk_buffer = buffer_cache.GetUtilityBuffer(VideoCore::MemoryUsage::Stream); const u32 ubo_size = stage.flattened_ud_buf.size() * sizeof(u32); - const u64 offset = vk_buffer.Copy(stage.flattened_ud_buf.data(), ubo_size, - instance.UniformMinAlignment()); + const u64 offset = + vk_buffer.Copy(stage.flattened_ud_buf.data(), ubo_size, alignment); buffer_infos.emplace_back(vk_buffer.Handle(), offset, ubo_size); } else if (desc.buffer_type == Shader::BufferType::BdaPagetable) { const auto* bda_buffer = buffer_cache.GetBdaPageTableBuffer(); @@ -562,8 +564,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding auto& lds_buffer = buffer_cache.GetUtilityBuffer(VideoCore::MemoryUsage::Stream); const auto& cs_program = liverpool->GetCsRegs(); const auto lds_size = cs_program.SharedMemSize() * cs_program.NumWorkgroups(); - const auto [data, offset] = - lds_buffer.Map(lds_size, instance.StorageMinAlignment()); + const auto [data, offset] = lds_buffer.Map(lds_size, alignment); std::memset(data, 0, lds_size); buffer_infos.emplace_back(lds_buffer.Handle(), offset, lds_size); } else if (instance.IsNullDescriptorSupported()) { @@ -575,8 +576,6 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding } else { const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer( vsharp.base_address, size, desc.is_written, desc.is_formatted, buffer_id); - const u32 alignment = - is_storage ? instance.StorageMinAlignment() : instance.UniformMinAlignment(); const u32 offset_aligned = Common::AlignDown(offset, alignment); const u32 adjust = offset - offset_aligned; ASSERT(adjust % 4 == 0); diff --git a/src/video_core/texture_cache/image.cpp b/src/video_core/texture_cache/image.cpp index 41a66503f..ab3f74892 100644 --- a/src/video_core/texture_cache/image.cpp +++ b/src/video_core/texture_cache/image.cpp @@ -416,6 +416,7 @@ void Image::Download(std::span download_copies, vk::B void Image::CopyImage(Image& src_image) { const auto& src_info = src_image.info; const u32 num_mips = std::min(src_info.resources.levels, info.resources.levels); + const u32 num_layers = std::min(src_info.resources.layers, info.resources.layers); ASSERT(src_info.resources.layers == info.resources.layers || num_mips == 1); const u32 width = src_info.size.width; @@ -437,13 +438,13 @@ void Image::CopyImage(Image& src_image) { .aspectMask = src_image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = mip, .baseArrayLayer = 0, - .layerCount = src_info.resources.layers, + .layerCount = num_layers, }, .dstSubresource{ .aspectMask = aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = mip, .baseArrayLayer = 0, - .layerCount = info.resources.layers, + .layerCount = num_layers, }, .extent = {mip_w, mip_h, mip_d}, }); @@ -464,6 +465,7 @@ void Image::CopyImage(Image& src_image) { void Image::CopyImageWithBuffer(Image& src_image, vk::Buffer buffer, u64 offset) { const auto& src_info = src_image.info; const u32 num_mips = std::min(src_info.resources.levels, info.resources.levels); + const u32 num_layers = std::min(src_info.resources.layers, info.resources.layers); ASSERT(src_info.resources.layers == info.resources.layers || num_mips == 1); SetBackingSamples(info.num_samples, false); @@ -483,7 +485,7 @@ void Image::CopyImageWithBuffer(Image& src_image, vk::Buffer buffer, u64 offset) .aspectMask = src_image.aspect_mask & ~vk::ImageAspectFlagBits::eStencil, .mipLevel = mip, .baseArrayLayer = 0, - .layerCount = src_info.resources.layers, + .layerCount = num_layers, }, .imageOffset = {0, 0, 0}, .imageExtent = {mip_w, mip_h, mip_d}, @@ -585,20 +587,21 @@ void Image::Resolve(Image& src_image, const VideoCore::SubresourceRange& mrt0_ra mrt0_range); Transit(vk::ImageLayout::eTransferDstOptimal, vk::AccessFlagBits2::eTransferWrite, mrt1_range); + const u32 num_layers = std::min(mrt0_range.extent.layers, mrt1_range.extent.layers); if (src_image.backing->num_samples == 1) { const vk::ImageCopy region = { .srcSubresource{ .aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = 0, .baseArrayLayer = mrt0_range.base.layer, - .layerCount = mrt0_range.extent.layers, + .layerCount = num_layers, }, .srcOffset = {0, 0, 0}, .dstSubresource{ .aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = 0, .baseArrayLayer = mrt1_range.base.layer, - .layerCount = mrt1_range.extent.layers, + .layerCount = num_layers, }, .dstOffset = {0, 0, 0}, .extent = {info.size.width, info.size.height, 1}, @@ -612,14 +615,14 @@ void Image::Resolve(Image& src_image, const VideoCore::SubresourceRange& mrt0_ra .aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = 0, .baseArrayLayer = mrt0_range.base.layer, - .layerCount = mrt0_range.extent.layers, + .layerCount = num_layers, }, .srcOffset = {0, 0, 0}, .dstSubresource{ .aspectMask = vk::ImageAspectFlagBits::eColor, .mipLevel = 0, .baseArrayLayer = mrt1_range.base.layer, - .layerCount = mrt1_range.extent.layers, + .layerCount = num_layers, }, .dstOffset = {0, 0, 0}, .extent = {info.size.width, info.size.height, 1},