diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 164f4c397..73cd9b0e6 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -56,6 +56,22 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1 total_flexible_size, total_direct_size); } +u64 MemoryManager::ClampRangeSize(VAddr virtual_addr, u64 size) { + static constexpr u64 MinSizeToClamp = 1_GB; + // Dont bother with clamping if the size is small so we dont pay a map lookup on every buffer. + if (size < MinSizeToClamp) { + return size; + } + const auto vma = FindVMA(virtual_addr); + ASSERT_MSG(vma != vma_map.end(), "Attempted to access invalid GPU address {:#x}", virtual_addr); + const u64 clamped_size = std::min(size, vma->second.base + vma->second.size - virtual_addr); + if (size != clamped_size) { + LOG_WARNING(Kernel_Vmm, "Clamped requested buffer range addr={:#x}, size={:#x} to {:#x}", + virtual_addr, size, clamped_size); + } + return clamped_size; +} + bool MemoryManager::TryWriteBacking(void* address, const void* data, u32 num_bytes) { const VAddr virtual_addr = std::bit_cast(address); const auto& vma = FindVMA(virtual_addr)->second; diff --git a/src/core/memory.h b/src/core/memory.h index 59e48b248..ff7b82c10 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -164,6 +164,8 @@ public: return virtual_addr >= vma_map.begin()->first && virtual_addr < end_addr; } + u64 ClampRangeSize(VAddr virtual_addr, u64 size); + bool TryWriteBacking(void* address, const void* data, u32 num_bytes); void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 816f149b0..177fd07fa 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -503,16 +503,17 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding for (const auto& desc : stage.buffers) { const auto vsharp = desc.GetSharp(stage); if (!desc.IsSpecial() && vsharp.base_address != 0 && vsharp.GetSize() > 0) { - const auto buffer_id = buffer_cache.FindBuffer(vsharp.base_address, vsharp.GetSize()); - buffer_bindings.emplace_back(buffer_id, vsharp); + const u64 size = memory->ClampRangeSize(vsharp.base_address, vsharp.GetSize()); + const auto buffer_id = buffer_cache.FindBuffer(vsharp.base_address, size); + buffer_bindings.emplace_back(buffer_id, vsharp, size); } else { - buffer_bindings.emplace_back(VideoCore::BufferId{}, vsharp); + buffer_bindings.emplace_back(VideoCore::BufferId{}, vsharp, 0); } } // Second pass to re-bind buffers that were updated after binding for (u32 i = 0; i < buffer_bindings.size(); i++) { - const auto& [buffer_id, vsharp] = buffer_bindings[i]; + 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()); // Buffer is not from the cache, either a special buffer or unbound. @@ -541,17 +542,15 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding buffer_infos.emplace_back(null_buffer.Handle(), 0, VK_WHOLE_SIZE); } } else { - const auto [vk_buffer, offset] = - buffer_cache.ObtainBuffer(vsharp.base_address, vsharp.GetSize(), desc.is_written, - desc.is_formatted, buffer_id); + 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); push_data.AddOffset(binding.buffer, adjust); - buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, - vsharp.GetSize() + adjust); + buffer_infos.emplace_back(vk_buffer->Handle(), offset_aligned, size + adjust); if (auto barrier = vk_buffer->GetBarrier(desc.is_written ? vk::AccessFlagBits2::eShaderWrite : vk::AccessFlagBits2::eShaderRead, @@ -559,7 +558,7 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding buffer_barriers.emplace_back(*barrier); } if (desc.is_written && desc.is_formatted) { - texture_cache.InvalidateMemoryFromGPU(vsharp.base_address, vsharp.GetSize()); + texture_cache.InvalidateMemoryFromGPU(vsharp.base_address, size); } } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 292944a10..fb409eaf8 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -118,7 +118,7 @@ private: Pipeline::DescriptorWrites set_writes; Pipeline::BufferBarriers buffer_barriers; - using BufferBindingInfo = std::pair; + using BufferBindingInfo = std::tuple; boost::container::static_vector buffer_bindings; using ImageBindingInfo = std::pair; boost::container::static_vector image_bindings;